Sdílet prostřednictvím


Kurz: Vytvoření agenta LangChain.js pomocí služby Azure AI Search

V tomto kurzu použijete LangChain.js k vytvoření agenta LangChain.js, který zaměstnancům společnosti NorthWind umožní klást otázky týkající se lidských zdrojů. Pomocí architektury se vyhnete často používanému kódu, který se obvykle vyžaduje pro LangChain.js agenty a integraci služeb Azure, což vám umožní soustředit se na vaše obchodní potřeby.

V tomto kurzu se naučíte:

  • Nastavte agenta LangChain.js
  • Integrace prostředků Azure do agenta LangChain.js
  • Volitelně otestujte agenta LangChain.js v jazyce LangSmith Studio.

NorthWind spoléhá na dva zdroje dat: veřejná dokumentace personálního oddělení přístupná všem zaměstnancům a důvěrná databáze personálního oddělení obsahující citlivá data zaměstnanců. Tento kurz se zaměřuje na vytvoření LangChain.js agenta, který určuje, jestli je možné odpovědět na otázku zaměstnance pomocí veřejných dokumentů personálního oddělení. Pokud ano, LangChain.js agent poskytne odpověď přímo.

Diagram znázorňující pracovní postup agenta LangChain.js a jeho rozhodovací větev pro odpovědi na otázky s využitím HR dokumentace.

Výstraha

Tento článek používá klíče pro přístup k prostředkům. Doporučeným postupem v produkčním prostředí je použití Azure RBAC a spravované identity. Tento přístup eliminuje potřebu správy nebo obměny klíčů, zvýšení zabezpečení a zjednodušení řízení přístupu.

Požadavky

  • Aktivní účet Azure. Pokud ho nemáte, vytvořte si účet zdarma .
  • Node.js LTS nainstalované ve vašem systému.
  • TypeScript pro psaní a kompilaci kódu TypeScript.
  • LangChain.js knihovna k sestavení agenta.
  • Volitelné: LangSmith pro monitorování využití AI. Potřebujete název projektu, klíč a koncový bod.
  • Volitelné: LangGraph Studio pro ladění řetězů LangGraph a agentů LangChain.js.
  • Prostředek Azure AI Search: Ujistěte se, že máte koncový bod prostředku, klíč správce (pro vložení dokumentu), klíč dotazu (pro čtení dokumentů) a název indexu.
  • Prostředek Azure OpenAI: Potřebujete název instance prostředku, klíč a dva modely s jejich verzemi rozhraní API:
    • Vložený model, jako text-embedding-ada-002je .
    • Velký jazykový model, jako je gpt-4o.

Architektura agentů

Architektura LangChain.js poskytuje rozhodovací tok pro vytváření inteligentních agentů jako LangGraph. V tomto kurzu vytvoříte agenta LangChain.js, který se integruje se službou Azure AI Search a Azure OpenAI pro odpovědi na otázky související s lidskými zdroji. Architektura agenta je navržená tak, aby:

  • Určete, jestli je otázka relevantní pro dokumentaci k personálnímu oddělení.
  • Načtěte relevantní dokumenty ze služby Azure AI Search.
  • Pomocí Azure OpenAI vygenerujte odpověď na základě načtených dokumentů a modelu LLM.

Klíčové komponenty:

  • Struktura grafu: Agent LangChain.js je reprezentován jako graf, kde:

    • Uzly provádějí konkrétní úlohy, jako je rozhodování nebo načítání dat.
    • Hrany definují tok mezi uzly a určují posloupnost operací.
  • Integrace služby Azure AI Search:

    • Vloží dokumenty personálního oddělení do vektorového úložiště jako vnoření.
    • K vytvoření těchto vložených objektů používá model vkládání (text-embedding-ada-002).
    • Načte relevantní dokumenty na základě výzvy uživatele.
  • Integrace Azure OpenAI:

    • Používá velký jazykový model (gpt-4o) k:
      • Určuje, jestli je otázka zodpovězená z obecných dokumentů lidských zdrojů.
      • Vygeneruje odpověď s výzvou pomocí kontextu z dokumentů a uživatelských otázek.

Následující tabulka obsahuje příklady uživatelských otázek, které jsou i nejsou relevantní a odpověditelné z obecných dokumentů lidských zdrojů.

Otázka Relevance k dokumentům personálního oddělení
Does the NorthWind Health Plus plan cover eye exams? Relevantní. Dokumenty personálního oddělení, jako je například příručka pro zaměstnance, by měly poskytnout odpověď.
How much of my perks + benefits have I spent? Není relevantní. Tato otázka vyžaduje přístup k důvěrným datům zaměstnanců, která jsou mimo rozsah tohoto agenta.

Pomocí architektury se vyhnete často používanému kódu, který se obvykle vyžaduje pro LangChain.js agenty a integraci služeb Azure, což vám umožní soustředit se na vaše obchodní potřeby.

Inicializace projektu Node.js

V novém adresáři inicializujete projekt Node.js pro vašeho agenta TypeScriptu. Spusťte následující příkazy:

npm init -y
npm pkg set type=module
npx tsc --init

Vytvoření souboru prostředí

Vytvořte .env soubor pro místní vývoj pro ukládání proměnných prostředí pro prostředky Azure a LangGraph. Ujistěte se, že jméno instance prostředku pro embedding a LLM je pouze jméno prostředku, nikoli koncový bod.

Volitelné: Pokud používáte LangSmith, nastavte LANGSMITH_TRACING na true pro místní vývoj. Zakažte ho (false) nebo ho odeberte v produkčním prostředí.

Nainstalujte závislosti

  1. Nainstalujte závislosti Azure pro Azure AI Search:

    npm install @azure/search-documents
    
  2. Nainstalujte závislosti LangChain.js pro vytváření a používání agenta:

    npm install @langchain/community @langchain/core @langchain/langgraph @langchain/openai langchain
    
  3. Instalujte vývojové závislosti pro lokální vývoj

    npm install --save-dev dotenv
    

Vytvořte konfigurační soubory prostředků Azure AI Search

Pokud chcete spravovat různé prostředky a modely Azure používané v tomto kurzu, vytvořte pro každý prostředek konkrétní konfigurační soubory. Tento přístup zajišťuje přehlednost a oddělení obav, což usnadňuje správu a údržbu konfigurací.

Konfigurace pro nahrání dokumentů do úložiště vektorů

Konfigurační soubor služby Azure AI Search používá klíč správce k vložení dokumentů do úložiště vektorů. Tento klíč je nezbytný pro správu příjmu dat do služby Azure AI Search.

const endpoint = process.env.AZURE_AISEARCH_ENDPOINT;
const adminKey = process.env.AZURE_AISEARCH_ADMIN_KEY;
const indexName = process.env.AZURE_AISEARCH_INDEX_NAME;

export const VECTOR_STORE_ADMIN = {
  endpoint,
  key: adminKey,
  indexName,
};

LangChain.js abstrahuje potřebu definovat schéma pro příjem dat do služby Azure AI Search a poskytuje výchozí schéma vhodné pro většinu scénářů. Tato abstrakce zjednodušuje proces a snižuje potřebu vlastních definic schématu.

Konfigurace pro dotazování na úložiště vektorů

Pro dotazování na vektorové úložiště vytvořte samostatný konfigurační soubor:

import {
  AzureAISearchConfig,
  AzureAISearchQueryType,
} from "@langchain/community/vectorstores/azure_aisearch";
const endpoint = process.env.AZURE_AISEARCH_ENDPOINT;
const queryKey = process.env.AZURE_AISEARCH_QUERY_KEY;
const indexName = process.env.AZURE_AISEARCH_INDEX_NAME;

export const DOC_COUNT = 3;

export const VECTOR_STORE_QUERY: AzureAISearchConfig = {
  endpoint,
  key: queryKey,
  indexName,
  search: {
    type: AzureAISearchQueryType.Similarity,
  },
};

Při dotazování na vektorové úložiště použijte místo toho klíč dotazu. Toto oddělení klíčů zajišťuje zabezpečený a efektivní přístup k prostředku.

Vytvoření konfiguračních souborů prostředků Azure OpenAI

Pokud chcete spravovat dva různé modely, vkládání a LLM, vytvořte samostatné konfigurační soubory. Tento přístup zajišťuje přehlednost a oddělení obav, což usnadňuje správu a údržbu konfigurací.

Konfigurace embeddingů pro vektorové úložiště

Pokud chcete vytvořit vkládání pro vkládání dokumentů do úložiště vektorů Azure AI Search, vytvořte konfigurační soubor:

const key = process.env.AZURE_OPENAI_EMBEDDING_KEY;
const instance = process.env.AZURE_OPENAI_EMBEDDING_INSTANCE;
const apiVersion =
  process.env.AZURE_OPENAI_EMBEDDING_API_VERSION || "2023-05-15";
const model =
  process.env.AZURE_OPENAI_EMBEDDING_MODEL || "text-embedding-ada-002";

export const EMBEDDINGS_CONFIG = {
  azureOpenAIApiKey: key,
  azureOpenAIApiInstanceName: instance,
  azureOpenAIApiEmbeddingsDeploymentName: model,
  azureOpenAIApiVersion: apiVersion,
  maxRetries: 1,
};

Konfigurace pro LLM pro generování odpovědí

Pokud chcete vytvořit odpovědi z velkého jazykového modelu, vytvořte konfigurační soubor:

const key = process.env.AZURE_OPENAI_COMPLETE_KEY;
const instance = process.env.AZURE_OPENAI_COMPLETE_INSTANCE;
const apiVersion =
  process.env.AZURE_OPENAI_COMPLETE_API_VERSION || "2024-10-21";
const model = process.env.AZURE_OPENAI_COMPLETE_MODEL || "gpt-4o";
const maxTokens = process.env.AZURE_OPENAI_COMPLETE_MAX_TOKENS;

export const LLM_CONFIG = {
  model,
  azureOpenAIApiKey: key,
  azureOpenAIApiInstanceName: instance,
  azureOpenAIApiDeploymentName: model,
  azureOpenAIApiVersion: apiVersion,
  maxTokens: maxTokens ? parseInt(maxTokens, 10) : 100,
  maxRetries: 1,
  timeout: 60000,
};

Konstanty a výzvy

Aplikace umělé inteligence se často spoléhají na konstantní řetězce a výzvy. Tyto konstanty můžete spravovat pomocí samostatných souborů.

Vytvořte příkazový řádek systému:

export const SYSTEM_PROMPT = `Answer the query with a complete paragraph based on the following context:`;

Vytvořte konstanty uzlů:

export const ANSWER_NODE = "vector_store_retrieval";
export const DECISION_NODE = "requires_hr_documents";
export const START = "__start__";
export const END = "__end__";

Vytvoření ukázkových uživatelských dotazů:

export const USER_QUERIES = [
  "Does the NorthWind Health plus plan cover eye exams?",
  "What is included in the NorthWind Health plus plan that is not included in the standard?",
  "What happens in a performance review?",
];

Pokud chcete načíst dokumenty do služby Azure AI Search, použijte k zjednodušení procesu LangChain.js. Dokumenty uložené jako soubory PDF se převedou na embeddingové reprezentace a vloží se do úložiště vektorů. Tento proces zajišťuje, že jsou dokumenty připravené k efektivnímu načítání a dotazování.

Klíčové aspekty:

  • LangChain.js abstrakce: LangChain.js zpracovává většinu složitosti, jako jsou definice schématu a vytváření klientů, což usnadňuje proces.
  • Omezování a logika opakování: Zatímco vzorový kód obsahuje minimální funkci čekání, produkční aplikace by měly implementovat komplexní zpracování chyb a logiku opakování pro správu omezování a přechodných chyb.

Postup načtení dokumentů

  1. Vyhledejte dokumenty PDF: Dokumenty jsou uloženy v datovém adresáři.

  2. Načtěte soubory PDF do LangChain.js: Pomocí loadPdfsFromDirectory funkce načtěte dokumenty. Tato funkce využívá metodu LangChain.js komunity PDFLoader.load ke čtení každého souboru a vrácení Document[] pole. Toto uspořádání je standardní formát dokumentu LangChain.js.

    import { PDFLoader } from "@langchain/community/document_loaders/fs/pdf";
    import { waiter } from "../utils/waiter.js";
    import { loadDocsIntoAiSearchVector } from "./load_vector_store.js";
    import fs from "fs/promises";
    import path from "path";
    
    export async function loadPdfsFromDirectory(
      embeddings: any,
      dirPath: string,
    ): Promise<void> {
      try {
        const files = await fs.readdir(dirPath);
        console.log(
          `PDF: Loading directory ${dirPath}, ${files.length} files found`,
        );
        for (const file of files) {
          if (file.toLowerCase().endsWith(".pdf")) {
            const fullPath = path.join(dirPath, file);
            console.log(`PDF: Found ${fullPath}`);
    
            const pdfLoader = new PDFLoader(fullPath);
            console.log(`PDF: Loading ${fullPath}`);
            const docs = await pdfLoader.load();
    
            console.log(`PDF: Sending ${fullPath} to index`);
            const storeResult = await loadDocsIntoAiSearchVector(embeddings, docs);
            console.log(`PDF: Indexing result: ${JSON.stringify(storeResult)}`);
    
            await waiter(1000 * 60); // waits for 1 minute between files
          }
        }
      } catch (err) {
        console.error("Error loading PDFs:", err);
      }
    }
    
  3. Vložení dokumentů do služby Azure AI Search: Pomocí loadDocsIntoAiSearchVector funkce odešlete pole dokumentu do úložiště vektorů Azure AI Search. Tato funkce používá klienta vkládání ke zpracování dokumentů a obsahuje základní funkci čekání, která zpracovává omezování. Pro produkční účely implementujte robustní mechanismus opakovaného pokusu/zpoždění.

    import { AzureAISearchVectorStore } from "@langchain/community/vectorstores/azure_aisearch";
    
    import type { Document } from "@langchain/core/documents";
    import type { EmbeddingsInterface } from "@langchain/core/embeddings";
    import { VECTOR_STORE_ADMIN } from "../config/vector_store_admin.js";
    
    export async function loadDocsIntoAiSearchVector(
      embeddings: EmbeddingsInterface,
      documents: Document[],
    ): Promise<AzureAISearchVectorStore> {
      const vectorStore = await AzureAISearchVectorStore.fromDocuments(
        documents,
        embeddings,
        VECTOR_STORE_ADMIN,
      );
      return vectorStore;
    }
    

Vytvoření pracovního postupu agenta

V LangChain.jssestavte agenta LangChain.js pomocí jazyka LangGraph. LangGraph umožňuje definovat uzly a hrany:

  • Uzel: kde se provádí práce.
  • Edge: definuje připojení mezi uzly.

Součásti pracovního postupu

V této aplikaci jsou tyto dva pracovní uzly:

  • requiresHrResources: určuje, jestli je otázka relevantní pro dokumentaci k personálnímu oddělení pomocí Azure OpenAI LLM.
  • getAnswer: načte odpověď. Odpověď pochází z řetězce LangChain.js retrieveru, který používá vkládání dokumentů z Azure AI Search a odesílá je do Azure OpenAI LLM. Toto je podstata generování rozšířeného vyhledáváním.

Hrany definují, kde se má začít, končit a podmínka potřebná k volání uzlu getAnswer .

Export grafu

Pokud chcete ke spuštění a ladění grafu použít LangGraph Studio, exportujte ho jako vlastní objekt.

import { StateGraph } from "@langchain/langgraph";
import { StateAnnotation } from "./langchain/state.js";
import { route as endRoute } from "./langchain/check_route_end.js";
import { getAnswer } from "./azure/get_answer.js";
import { START, ANSWER_NODE, DECISION_NODE } from "./config/nodes.js";
import {
  requiresHrResources,
  routeRequiresHrResources,
} from "./azure/requires_hr_documents.js";

const builder = new StateGraph(StateAnnotation)
  .addNode(DECISION_NODE, requiresHrResources)
  .addNode(ANSWER_NODE, getAnswer)
  .addEdge(START, DECISION_NODE)
  .addConditionalEdges(DECISION_NODE, routeRequiresHrResources)
  .addConditionalEdges(ANSWER_NODE, endRoute);

export const hr_documents_answer_graph = builder.compile();
hr_documents_answer_graph.name = "Azure AI Search + Azure OpenAI";

V addNode, addEdge a addConditionalEdges metody, první parametr je název, jako řetězec, který identifikuje objekt v grafu. Druhým parametrem je funkce, která by měla být volána v daném kroku, nebo název uzlu, který se má volat.

Pro metodu addEdge je jeho název START ("start" definovaný v souboru ./src/config/nodes.ts) a vždy volá DECISION_NODE. Tento uzel je definován pomocí dvou parametrů: první je jeho název, DECISION_NODE a druhý je funkce, která se nazývá requiresHrResources.

Běžné funkce

Tato aplikace poskytuje běžné funkce jazyka LangChain:

  • Správa stavu:

    import { BaseMessage, BaseMessageLike } from "@langchain/core/messages";
    import { Annotation, messagesStateReducer } from "@langchain/langgraph";
    
    export const StateAnnotation = Annotation.Root({
      messages: Annotation<BaseMessage[], BaseMessageLike[]>({
        reducer: messagesStateReducer,
        default: () => [],
      }),
    });
    
  • Ukončení trasy:

    import { StateAnnotation } from "./state.js";
    import { END, ANSWER_NODE } from "../config/nodes.js";
    
    export const route = (
      state: typeof StateAnnotation.State,
    ): typeof END | typeof ANSWER_NODE => {
      if (state.messages.length > 0) {
        return END;
      }
      return ANSWER_NODE;
    };
    

Jedinou vlastní trasou pro tuto aplikaci je routeRequiresHrResources. Tato trasa se používá k určení, jestli odpověď z uzlu requiresHrResources indikuje, že otázka uživatele by měla pokračovat na ANSWER_NODE uzlu. Vzhledem k tomu, že tato trasa přijímá výstup requiresHrResources, je ve stejném souboru.

Integrace prostředků Azure OpenAI

Integrace Azure OpenAI používá dva různé modely:

  • Vkládání: Slouží k vložení dokumentů do vektorového úložiště.
  • LLM: Používá se k zodpovězení otázek dotazováním úložiště vektorů a generováním odpovědí.

Klient pro vkládání a klient LLM slouží k různým účelům. Nezmenšujte je na jeden model nebo klienta.

Model vkládání

Klient vkládání je vyžadován při každém načtení dokumentů z úložiště vektorů. Zahrnuje konfiguraci pro maxRetries pro zpracování přechodných chyb.

import { AzureOpenAIEmbeddings } from "@langchain/openai";
import { EMBEDDINGS_CONFIG } from "../config/embeddings.js";

export function getEmbeddingClient(): AzureOpenAIEmbeddings {
  return new AzureOpenAIEmbeddings({ ...EMBEDDINGS_CONFIG, maxRetries: 1 });
}

Model LLM

Model LLM slouží k zodpovězení dvou typů otázek:

  • Relevance pro personální oddělení: Určuje, jestli je otázka uživatele relevantní pro dokumentaci k personálnímu oddělení.
  • Generování odpovědí: Poskytuje odpověď na otázku uživatele rozšířenou o dokumenty z Azure AI Search.

Klient LLM se vytvoří a vyvolá, když je vyžadována odpověď.

import { RunnableConfig } from "@langchain/core/runnables";
import { StateAnnotation } from "../langchain/state.js";
import { AzureChatOpenAI } from "@langchain/openai";
import { LLM_CONFIG } from "../config/llm.js";

export const getLlmChatClient = (): AzureChatOpenAI => {
  return new AzureChatOpenAI({
    ...LLM_CONFIG,
    temperature: 0,
  });
};

export const callChatCompletionModel = async (
  state: typeof StateAnnotation.State,
  _config: RunnableConfig,
): Promise<typeof StateAnnotation.Update> => {
  const llm = new AzureChatOpenAI({
    ...LLM_CONFIG,
    temperature: 0,
  });

  const completion = await llm.invoke(state.messages);
  completion;

  return {
    messages: [
      ...state.messages,
      {
        role: "assistant",
        content: completion.content,
      },
    ],
  };
};

Agent LangChain.js používá LLM k rozhodnutí, jestli je otázka relevantní pro dokumentaci personálního oddělení, nebo jestli má pracovní postup směrovat na konec grafu.

// @ts-nocheck
import { getLlmChatClient } from "./llm.js";
import { StateAnnotation } from "../langchain/state.js";
import { RunnableConfig } from "@langchain/core/runnables";
import { BaseMessage } from "@langchain/core/messages";
import { ANSWER_NODE, END } from "../config/nodes.js";

const PDF_DOCS_REQUIRED = "Answer requires HR PDF docs.";

export async function requiresHrResources(
  state: typeof StateAnnotation.State,
  _config: RunnableConfig,
): Promise<typeof StateAnnotation.Update> {
  const lastUserMessage: BaseMessage = [...state.messages].reverse()[0];

  let pdfDocsRequired = false;

  if (lastUserMessage && typeof lastUserMessage.content === "string") {
    const question = `Does the following question require general company policy information that could be found in HR documents like employee handbooks, benefits overviews, or company-wide policies, then answer yes. Answer no if this requires personal employee-specific information that would require access to an individual's private data, employment records, or personalized benefits details: '${lastUserMessage.content}'. Answer with only "yes" or "no".`;

    const llm = getLlmChatClient();
    const response = await llm.invoke(question);
    const answer = response.content.toLocaleLowerCase().trim();
    console.log(`LLM question (is HR PDF documents required): ${question}`);
    console.log(`LLM answer (is HR PDF documents required): ${answer}`);
    pdfDocsRequired = answer === "yes";
  }

  // If HR documents (aka vector store) are required, append an assistant message to signal this.
  if (!pdfDocsRequired) {
    const updatedState = {
      messages: [
        ...state.messages,
        {
          role: "assistant",
          content:
            "Not a question for our HR PDF resources. This requires data specific to the asker.",
        },
      ],
    };

    return updatedState;
  } else {
    const updatedState = {
      messages: [
        ...state.messages,
        {
          role: "assistant",
          content: `${PDF_DOCS_REQUIRED} You asked: ${lastUserMessage.content}. Let me check.`,
        },
      ],
    };

    return updatedState;
  }
}

export const routeRequiresHrResources = (
  state: typeof StateAnnotation.State,
): typeof END | typeof ANSWER_NODE => {
  const lastMessage: BaseMessage = [...state.messages].reverse()[0];

  if (lastMessage && !lastMessage.content.includes(PDF_DOCS_REQUIRED)) {
    console.log("go to end");
    return END;
  }
  console.log("go to llm");
  return ANSWER_NODE;
};

Funkce requiresHrResources nastaví zprávu v aktualizovaném stavu s obsahem HR resources required detected . Směrovač routeRequiresHrResources hledá tento obsah, který určuje, kam se mají zprávy odesílat.

Integrace prostředku Azure AI Search pro úložiště vektorů

Integrace služby Azure AI Search poskytuje dokumenty úložiště vektorů, aby LLM mohl odpověď rozšířit pro uzel getAnswer. LangChain.js opět poskytuje většinu abstrakce, takže požadovaný kód je minimální. Mezi funkce patří:

  • getReadOnlyVectorStore: Načte klienta pomocí klíče dotazu.
  • getDocsFromVectorStore: Vyhledá relevantní dokumenty pro otázku uživatele.
import { AzureAISearchVectorStore } from "@langchain/community/vectorstores/azure_aisearch";
import { VECTOR_STORE_QUERY, DOC_COUNT } from "../config/vector_store_query.js";
import { getEmbeddingClient } from "./embeddings.js";

export function getReadOnlyVectorStore(): AzureAISearchVectorStore {
  const embeddings = getEmbeddingClient();
  return new AzureAISearchVectorStore(embeddings, VECTOR_STORE_QUERY);
}

export async function getDocsFromVectorStore(
  query: string,
): Promise<Document[]> {
  const store = getReadOnlyVectorStore();

  // @ts-ignore
  //return store.similaritySearchWithScore(query, DOC_COUNT);
  return store.similaritySearch(query, DOC_COUNT);
}

Kód integrace LangChain.js umožňuje neuvěřitelně snadno načíst relevantní dokumenty z úložiště vektorů.

Napište kód pro získání odpovědi z LLM

Teď, když jsou integrační komponenty vytvořené, vytvořte funkci getAnswer pro načtení relevantních dokumentů úložiště vektorů a vygenerujte odpověď pomocí LLM.

import { ChatPromptTemplate } from "@langchain/core/prompts";
import { createStuffDocumentsChain } from "langchain/chains/combine_documents";
import { createRetrievalChain } from "langchain/chains/retrieval";
import { getLlmChatClient } from "./llm.js";
import { StateAnnotation } from "../langchain/state.js";
import { AIMessage } from "@langchain/core/messages";
import { getReadOnlyVectorStore } from "./vector_store.js";

const EMPTY_STATE = { messages: [] };

export async function getAnswer(
  state: typeof StateAnnotation.State = EMPTY_STATE,
): Promise<typeof StateAnnotation.Update> {
  const vectorStore = getReadOnlyVectorStore();

  // Extract the last user message's content from the state as input
  const lastMessage = state.messages[state.messages.length - 1];

  const userInput =
    lastMessage && typeof lastMessage.content === "string"
      ? lastMessage.content
      : "";

  const questionAnsweringPrompt = ChatPromptTemplate.fromMessages([
    [
      "system",
      "Answer the user's questions based on the below context:\n\n{context}",
    ],
    ["human", "{input}"],
  ]);

  const combineDocsChain = await createStuffDocumentsChain({
    llm: getLlmChatClient(),
    prompt: questionAnsweringPrompt,
  });

  const retrievalChain = await createRetrievalChain({
    retriever: vectorStore.asRetriever(2),
    combineDocsChain,
  });
  const result = await retrievalChain.invoke({ input: userInput });
  const assistantMessage = new AIMessage(result.answer);

  return {
    messages: [...state.messages, assistantMessage],
  };
}

Tato funkce poskytuje výzvu se dvěma zástupnými symboly: jedním pro otázku uživatele a jedním pro kontext. Kontext tvoří všechny relevantní dokumenty z vektorového úložiště pro vyhledávání AI. Předejte výzvu a klienta LLM do funkce createStuffDocumentsChain pro vytvoření řetězce LLM. Předejte řetězec LLM do funkce createRetrievalChain, která vytvoří řetěz, zahrnující výzvu, relevantní dokumenty a LLM.

Spusťte řetězy s retrievalChain.invoke s dotazem uživatele jako vstupem, abyste získali odpověď. Ve stavu zpráv vraťte odpověď.

Sestavení balíčku agenta

  1. Přidejte skript pro package.json pro sestavení aplikace TypeScript:

    "build": "tsc",
    
  2. Postavte agenta LangChain.js.

    npm run build
    

Volitelné – spuštění agenta LangChain.js v místním vývoji pomocí nástroje LangChain Studio

Volitelně můžete pro místní vývoj použít LangChain Studio pro práci s vaším agentem LangChain.js.

  1. Vytvořte langgraph.json soubor pro definování grafu.

    {
        "dependencies": [],
        "graphs": {
          "agent": "./src/graph.ts:hr_documents_answer_graph"
        },
        "env": "../.env"
      }
    
  2. Nainstalujte rozhraní příkazového řádku LangGraph.

    npm install @langchain/langgraph-cli --save-dev
    
  3. Vytvořte skript v package.json pro předání .env souboru do rozhraní příkazového řádku LangGraph.

    "studio": "npx @langchain/langgraph-cli dev",
    
  4. Rozhraní příkazového řádku se spustí v terminálu a otevře prohlížeč pro LangGraph Studio.

              Welcome to
    
    ╦  ┌─┐┌┐┌┌─┐╔═╗┬─┐┌─┐┌─┐┬ ┬
    ║  ├─┤││││ ┬║ ╦├┬┘├─┤├─┘├─┤
    ╩═╝┴ ┴┘└┘└─┘╚═╝┴└─┴ ┴┴  ┴ ┴.js
    
    - 🚀 API: http://localhost:2024
    - 🎨 Studio UI: https://smith.langchain.com/studio?baseUrl=http://localhost:2024
    
    This in-memory server is designed for development and testing.
    For production use, please use LangGraph Cloud.
    
    info:    ▪ Starting server...
    info:    ▪ Initializing storage...
    info:    ▪ Registering graphs from C:\Users\myusername\azure-typescript-langchainjs\packages\langgraph-agent
    info:    ┏ Registering graph with id 'agent'
    info:    ┗ [1] { graph_id: 'agent' }
    info:    ▪ Starting 10 workers
    info:    ▪ Server running at ::1:2024
    
  5. Zobrazte agenta LangChain.js v nástroji LangGraph Studio.

    Snímek obrazovky nástroje LangSmith Studio s načteným grafem

  6. Pokud chcete přidat otázku uživatele, vyberte + Zpráva a pak vyberte Odeslat.

    Otázka Relevance k dokumentům personálního oddělení
    Does the NorthWind Health plus plan cover eye exams? Tato otázka je relevantní pro personální oddělení a dostatečně obecné, že dokumenty personálního oddělení, jako je příručka zaměstnanců, příručka výhod a knihovna rolí zaměstnanců, by na ni měly být schopny odpovědět.
    What is included in the NorthWind Health plus plan that is not included in the standard? Tato otázka je relevantní pro personální oddělení a dostatečně obecné, že dokumenty personálního oddělení, jako je příručka zaměstnanců, příručka výhod a knihovna rolí zaměstnanců, by na ni měly být schopny odpovědět.
    How much of my perks + benefit have I spent Tato otázka není relevantní pro obecné, neosobní dokumenty personálního oddělení. Tato otázka by se měla odeslat agentovi, který má přístup k datům zaměstnanců.
  7. Pokud je otázka relevantní pro dokumenty HR, měla by projít DECISION_NODE a dále do ANSWER_NODE.

    Podívejte se na výstup terminálu, abyste viděli, jaká je otázka k LLM a odpověď od LLM.

  8. Pokud otázka není relevantní pro personální dokumenty, tok přejde přímo na konec.

Když agent LangChain.js provede nesprávné rozhodnutí, může být problém následující:

  • Použitý model LLM
  • Počet dokumentů z úložiště vektorů
  • Výzva použitá v rozhodovacím uzlu

Spuštění agenta LangChain.js z aplikace

Pokud chcete volat LangChain.js agenta z nadřazené aplikace, jako je webové API, musíte zadat volání agenta LangChain.js.

import { HumanMessage } from "@langchain/core/messages";
import { hr_documents_answer_graph as app } from "./graph.js";

const AIMESSAGE = "aimessage";

export async function ask_agent(question: string) {
  const initialState = { messages: [new HumanMessage(question)], iteration: 0 };
  const finalState = await app.invoke(initialState);

  return finalState;
}
export async function get_answer(question: string) {
  try {
    const answerResponse = await ask_agent(question);

    const answer = answerResponse.messages
      .filter(
        (m: any) =>
          m &&
          m.constructor?.name?.toLowerCase() === AIMESSAGE.toLocaleLowerCase(),
      )
      .map((m: any) => m.content)
      .join("\n");

    return answer;
  } catch (e) {
    console.error("Error in get_answer:", e);
    throw e;
  }
}

Mezi dvě funkce patří:

  • ask_agent: Tato funkce vrátí stav, takže umožňuje přidat agenta LangChain.js do pracovního postupu více agentů LangChain.
  • get_answer: Tato funkce vrátí pouze text odpovědi. Tuto funkci lze volat z rozhraní API.

Řešení problémů

Vyčistěte zdroje

Odstraňte skupinu prostředků, která obsahuje prostředek Azure AI Search a prostředek Azure OpenAI.