Megosztás a következőn keresztül:


Oktatóanyag: LangChain.js-ügynök létrehozása az Azure AI Search használatával

Ebben az oktatóanyagban LangChain.js használ egy LangChain.js ügynököt, amely lehetővé teszi a NorthWind vállalat alkalmazottai számára, hogy emberi erőforrásokkal kapcsolatos kérdéseket tegyenek fel. A keretrendszer használatával elkerülheti a LangChain.js ügynökökhöz és az Azure-szolgáltatások integrációjához általában szükséges sablonkódot, így az üzleti igényekre összpontosíthat.

Ebben az útmutatóban Ön:

  • LangChain.js-ügynök beállítása
  • Azure-erőforrások integrálása az LangChain.js-ügynökbe
  • Igény szerint tesztelje LangChain.js ügynökét a LangSmith Studióban

A NorthWind két adatforrásra támaszkodik: az összes alkalmazott számára elérhető nyilvános HR-dokumentációra és egy bizalmas alkalmazottak adatait tartalmazó bizalmas HR-adatbázisra. Ez az oktatóanyag egy LangChain.js ügynök létrehozására összpontosít, amely meghatározza, hogy egy alkalmazott kérdése megválaszolható-e a nyilvános HR-dokumentumok használatával. Ha igen, a LangChain.js ügynök közvetlenül adja meg a választ.

Az LangChain.js-ügynök munkafolyamatát és döntési ágát szemléltető ábra, amely hr-dokumentációt használ a kérdések megválaszolásához.

Figyelmeztetés

Ez a cikk kulcsokat használ az erőforrások eléréséhez. Éles környezetben a javasolt legjobb gyakorlat az Azure RBAC és a felügyelt identitás használata. Ez a megközelítés szükségtelenné teszi a kulcsok kezelését vagy elforgatását, a biztonság növelését és a hozzáférés-vezérlés egyszerűsítését.

Előfeltételek

  • Aktív Azure-fiók. Ha nincs fiókja, hozzon létre ingyenes fiókot .
  • Telepítve van a rendszerén a Node.js LTS.
  • TypeScript TypeScript-kód írásához és fordításához.
  • LangChain.js könyvtár az ügynök felépítéséhez.
  • Nem kötelező: LangSmith az AI-használat monitorozásához. Szüksége van a projekt nevére, kulcsára és végpontjára.
  • Nem kötelező: LangGraph Studio a LangGraph-láncok és LangChain.js ügynökök hibakereséséhez.
  • Azure AI Search-erőforrás: Győződjön meg arról, hogy rendelkezik az erőforrásvégpont, a rendszergazdai kulccsal (a dokumentum beszúrásához), a lekérdezési kulccsal (a dokumentumok olvasásához) és az index nevével.
  • Azure OpenAI-erőforrás: Szüksége lesz az erőforráspéldány nevére, kulcsára és két modellre az API-verziókkal:
    • Egy beágyazási modell, például text-embedding-ada-002.
    • Egy nagy nyelvi modell, például gpt-4o.

Ügynökarchitektúra

A LangChain.js keretrendszer döntési folyamatot biztosít az intelligens ügynökök LangGraphként való létrehozásához. Ebben az oktatóanyagban egy LangChain.js ügynököt hoz létre, amely integrálható az Azure AI Search és az Azure OpenAI szolgáltatással a HR-sel kapcsolatos kérdések megválaszolásához. Az ügynök architektúrája a következőkre lett tervezve:

  • Állapítsa meg, hogy egy kérdés releváns-e a HR-dokumentáció szempontjából.
  • A vonatkozó dokumentumok lekérése az Azure AI Search szolgáltatásból.
  • Az Azure OpenAI használatával választ hozhat létre a lekért dokumentumok és az LLM-modell alapján.

Fő összetevők:

  • Gráfstruktúra: A LangChain.js ügynök gráfként jelenik meg, ahol:

    • A csomópontok konkrét feladatokat hajtanak végre, például döntéshozatalt vagy adatok beolvasását.
    • Az élek határozzák meg a csomópontok közötti folyamatot, meghatározva a műveletek sorrendjét.
  • Azure AI Search-integráció:

    • Beágyazásként HR-dokumentumokat szúr be a vektortárolóba.
    • Beágyazási modell (text-embedding-ada-002) használatával hozza létre ezeket a beágyazásokat.
    • A vonatkozó dokumentumokat a felhasználói kérés alapján kéri le.
  • Azure OpenAI-integráció:

    • Nagy nyelvi modellt (gpt-4o) használ a következő célokra:
      • Meghatározza, hogy egy kérdés megválaszolható-e az általános HR-dokumentumokból.
      • A dokumentumokból és a felhasználói kérdésekből származó környezet használatával válasz generál.

Az alábbi táblázat olyan felhasználói kérdésekre mutat be példákat, amelyek általános emberierőforrás-dokumentumokból nem relevánsak és megválaszolhatók:

Kérdés A HR-dokumentumok relevanciája
Does the NorthWind Health Plus plan cover eye exams? Idevágó. A HR-dokumentumoknak, például az alkalmazotti kézikönyvnek választ kell adniuk.
How much of my perks + benefits have I spent? Nem releváns. Ehhez a kérdéshez hozzá kell férni a bizalmas alkalmazottak adataihoz, amelyek nem tartoznak az ügynök hatókörébe.

A keretrendszer használatával elkerülheti a LangChain.js ügynökökhöz és az Azure-szolgáltatások integrációjához általában szükséges sablonkódot, így az üzleti igényekre összpontosíthat.

A Node.js projekt inicializálása

Inicializálja a TypeScript-ügynökhöz tartozó Node.js projektet egy új könyvtárban. Futtassa az alábbi parancsot:

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

Környezeti fájl létrehozása

Hozzon létre egy .env fájlt a helyi fejlesztéshez az Azure-erőforrások és a LangGraph környezeti változóinak tárolásához. Győződjön meg arról, hogy a beágyazás és az LLM erőforráspéldányának neve csak az erőforrás neve legyen, nem pedig a végpont.

Nem kötelező: Ha a LangSmith-et használja, állítsa a LANGSMITH_TRACING értéket true-re a helyi fejlesztéshez. Tiltsa le (false) vagy távolítsa el a termelési környezetben.

Függőségek telepítése

  1. Azure-függőségek telepítése az Azure AI Search szolgáltatáshoz:

    npm install @azure/search-documents
    
  2. Ügynök létrehozásához és használatához telepítse LangChain.js függőségeket:

    npm install @langchain/community @langchain/core @langchain/langgraph @langchain/openai langchain
    
  3. Helyi fejlesztéshez szükséges függőségek telepítése.

    npm install --save-dev dotenv
    

Azure AI keresési erőforrás konfigurációs fájljainak létrehozása

Az oktatóanyagban használt különböző Azure-erőforrások és modellek kezeléséhez hozzon létre konkrét konfigurációs fájlokat az egyes erőforrásokhoz. Ez a megközelítés biztosítja az aggodalmak egyértelműségét és elkülönítését, így egyszerűbbé válik a konfigurációk kezelése és karbantartása.

Dokumentumok vektortárolóba való feltöltésének konfigurálása

Az Azure AI Search konfigurációs fájlja a rendszergazdai kulccsal szúr be dokumentumokat a vektortárolóba. Ez a kulcs elengedhetetlen az adatok Azure AI Searchbe való betöltésének kezeléséhez.

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 absztrakciót végez az azure AI Searchbe történő adatbetöltés sémájának definiálására, amely a legtöbb forgatókönyvhöz megfelelő alapértelmezett sémát biztosít. Ez az absztrakció leegyszerűsíti a folyamatot, és csökkenti az egyéni sémadefiníciók szükségességét.

Konfiguráció a vektortároló lekérdezéséhez

A vektortároló lekérdezéséhez hozzon létre egy külön konfigurációs fájlt:

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,
  },
};

A vektortároló lekérdezéséhez használja inkább a lekérdezési kulcsot. A kulcsok elkülönítése biztonságos és hatékony hozzáférést biztosít az erőforráshoz.

Azure OpenAI-erőforráskonfigurációs fájlok létrehozása

A két különböző modell, a beágyazások és az LLM kezeléséhez hozzon létre külön konfigurációs fájlokat. Ez a megközelítés biztosítja az aggodalmak egyértelműségét és elkülönítését, így egyszerűbbé válik a konfigurációk kezelése és karbantartása.

A vektortároló beágyazásának konfigurálása

Ha beágyazásokat szeretne létrehozni a dokumentumok Azure AI Search-vektortárolóba való beszúrásához, hozzon létre egy konfigurációs fájlt:

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,
};

Az LLM konfigurálása válaszok létrehozásához

Ha a nagy nyelvi modellből szeretne válaszokat létrehozni, hozzon létre egy konfigurációs fájlt:

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,
};

Állandók és utasítások

Az AI-alkalmazások gyakran állandó sztringekre és kérésekre támaszkodnak. Ezeket az állandókat külön fájlokkal kezelheti.

Hozza létre a rendszerutasítást.

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

Hozza létre a csomópontok állandóit:

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

Példa felhasználói lekérdezések létrehozása:

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?",
];

A dokumentumok Azure AI Searchbe való betöltéséhez a LangChain.js használatával egyszerűsítheti a folyamatot. A PDF-fájlként tárolt dokumentumok beágyazásokká alakulnak, és beszúródnak a vektortárolóba. Ez a folyamat biztosítja, hogy a dokumentumok készen állnak a hatékony lekérésre és lekérdezésre.

Fő szempontok:

  • LangChain.js absztrakció: LangChain.js kezeli az összetettség nagy részét, például a sémadefiníciókat és az ügyféllétrehozást, így a folyamat egyszerűvé válik.
  • Szabályozás és újrapróbálkozási logika: Bár a mintakód minimális várakozási függvényt tartalmaz, az éles alkalmazásoknak átfogó hibakezelési és újrapróbálkozási logikát kell alkalmazniuk a szabályozás és az átmeneti hibák kezeléséhez.

Dokumentumok betöltésének lépései

  1. Keresse meg a PDF-dokumentumokat: A dokumentumok az adatkönyvtárban vannak tárolva.

  2. PDF-fájlok betöltése a LangChain.js: Használja a loadPdfsFromDirectory funkciót a dokumentumok betöltéséhez. Ez a függvény a LangChain.js közösség metódusát PDFLoader.load használja az egyes fájlok beolvasására és tömbök Document[] visszaadására. Ez a tömb egy szabványos LangChain.js dokumentumformátum.

    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. Dokumentumok beszúrása az loadDocsIntoAiSearchVector: A függvény használatával küldje el a dokumentumtömböt az Azure AI Search vektortárolójába. Ez a függvény a beágyazások ügyfelével dolgozza fel a dokumentumokat, és egy egyszerű várakozási függvényt tartalmaz az adatfolyam korlátozás kezelésére. Implementáljon egy robusztus újrapróbálkozási/hátratolt mechanizmust.

    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;
    }
    

Ügynök munkafolyamatának létrehozása

A LangChain.js-ban építsd meg a LangChain.js ügynököt egy LangGraph használatával. A LangGraph lehetővé teszi a csomópontok és élek meghatározását:

  • Csomópont: ahol a munka történik.
  • Edge: a csomópontok közötti kapcsolatot határozza meg.

Munkafolyamat-összetevők

Ebben az alkalmazásban a két munkacsomópont a következő:

  • requiresHrResources: meghatározza, hogy a kérdés releváns-e az Azure OpenAI LLM használatával végzett HR-dokumentáció szempontjából.
  • getAnswer: lekéri a választ. A válasz egy LangChain.js retriever-láncból származik, amely az Azure AI Search dokumentumbeágyazását használja, és elküldi őket az Azure OpenAI LLM-nek. Ez a visszakereséssel bővített generáció lényege.

Az élek határozzák meg a getAnswer csomópont meghívásához szükséges kezdő, záró és feltételt.

A gráf exportálása

Ha a LangGraph Studiót szeretné használni a gráf futtatására és hibakeresésére, exportálja azt saját objektumként.

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";

Az addNode, addEdge és addConditionalEdges metódusokban az első paraméter egy név, sztringként, amely azonosítja az objektumot a gráfon belül. A második paraméter vagy az a függvény, amelyet az adott lépésben meg kell hívni, vagy a meghívni kívánt csomópont neve.

Az addEdge metódus esetében a neve START ("start" a ./src/config/nodes.ts fájlban definiálva), és mindig meghívja a DECISION_NODE. Ez a csomópont két paraméterrel van definiálva: az első a neve, DECISION_NODE, a második pedig a requiresHrResources nevű függvény.

Gyakori funkciók

Ez az alkalmazás általános LangChain-funkciókat biztosít:

  • Állapotkezelés:

    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: () => [],
      }),
    });
    
  • Útvonalvégzítés:

    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;
    };
    

Az alkalmazás egyetlen egyéni útvonala a routeRequiresHrResources. Ezzel az útvonalsal állapítható meg, hogy a requiresHrResources csomópont válasza azt jelzi-e, hogy a felhasználó kérdésének tovább kell-e folytatódnia a ANSWER_NODE csomóponton. Mivel ez az útvonal a requiresHrResources kimenetét kapja, ugyanabban a fájlban található.

Azure OpenAI-erőforrások integrálása

Az Azure OpenAI-integráció két különböző modellt használ:

  • Beágyazások: A dokumentumok vektortárolóba való beszúrására szolgál.
  • LLM: A vektortároló lekérdezésével és a válaszok generálásával válaszol a kérdésekre.

A beágyazási ügyfél és az LLM-ügyfél különböző célokat szolgálnak. Ne csökkentse őket egyetlen modellre vagy ügyfélre.

Beágyazási modell

A beágyazási ügyfélre minden alkalommal szükség van, amikor dokumentumokat kér le a vektortárolóból. A maxRetries konfigurációját tartalmazza az átmeneti hibák kezeléséhez.

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

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

LLM-modell

Az LLM-modell kétféle kérdésre ad választ:

  • A HR-hez kapcsolódó relevancia: Meghatározza, hogy a felhasználó kérdése releváns-e a HR-dokumentáció szempontjából.
  • Válaszgenerálás: Választ ad a felhasználó kérdésére, kiegészítve az Azure AI Search dokumentumaival.

A rendszer létrehozza és meghívja az LLM-ügyfelet, amikor válaszra van szükség.

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,
      },
    ],
  };
};

A LangChain.js ügynök az LLM használatával dönti el, hogy a kérdés releváns-e a HR-dokumentáció szempontjából, vagy a munkafolyamatnak a gráf végéhez kell-e irányítania.

// @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;
};

A requiresHrResources függvény egy frissített állapotban lévő üzenetet állít be tartalommal HR resources required detected . A routeRequiresHrResources útválasztó ezt a tartalmat keresi annak meghatározásához, hogy hová küldje az üzeneteket.

Az Azure AI Search-erőforrás integrálása vektortárolóhoz

Az Azure AI Search integrációja biztosítja a vektortár dokumentumait, hogy az LLM bővítse a getAnswer csomópont válaszát. LangChain.js ismét biztosítja az absztrakció nagy részét, így a szükséges kód minimális. A függvények a következők:

  • getReadOnlyVectorStore: Lekéri a klienst a lekérdezési kulcs alapján.
  • getDocsFromVectorStore: Megkeresi a felhasználó kérdésére vonatkozó dokumentumokat.
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);
}

A LangChain.js integrációs kód rendkívül egyszerűvé teszi a releváns dokumentumok beolvasását a vektortárolóból.

Írj kódot, hogy válaszokat kapj az LLM-től

Most, hogy elkészültek az integrációs összetevők, hozza létre a getAnswer függvényt a releváns vektortár-dokumentumok lekéréséhez, és hozzon létre egy választ az LLM használatával.

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],
  };
}

Ez a függvény két helyőrzőt tartalmaz: egyet a felhasználó kérdéséhez, egyet pedig a környezethez. A környezet az AI Search vektortárolójának összes releváns dokumentuma. Az LLM-lánc létrehozásához adja át a parancssort és az LLM-ügyfelet a createStuffDocumentsChainnek . Adja át az LLM-láncot a createRetrievalChain függvénynek, hogy olyan láncot hozzon létre, amely tartalmazza a felhívást, a releváns dokumentumokat és az LLM-et.

Futtassa a láncokat a retrievalChain.invoke használatával, és adja meg a felhasználó kérdését bemenetként a válasz megszerzéséhez. Adja vissza a választ az üzenetek állapotában.

Az ügynökcsomag létrehozása

  1. Adjon egy scriptet a package.json helyhez a TypeScript-alkalmazás felépítéséhez:

    "build": "tsc",
    
  2. Hozza létre a LangChain.js ügynököt.

    npm run build
    

Opcionális – futtassa a LangChain.js ügynököt helyi fejlesztési környezetben LangChain Studioval

Helyi fejlesztéshez használhatja a LangChain Studiót a LangChain.js-ügynökkel való együttműködéshez.

  1. Hozzon létre egy langgraph.json fájlt a gráf definiálásához.

    {
        "dependencies": [],
        "graphs": {
          "agent": "./src/graph.ts:hr_documents_answer_graph"
        },
        "env": "../.env"
      }
    
  2. Telepítse a LangGraph parancssori felületet.

    npm install @langchain/langgraph-cli --save-dev
    
  3. Hozzon létre egy szkriptet package.json a .env fájl LangGraph parancssori felületre való továbbításához.

    "studio": "npx @langchain/langgraph-cli dev",
    
  4. A parancssori felület a terminálon fut, és megnyit egy böngészőt a LangGraph Studióban.

              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. Tekintse meg a LangChain.js ügynököt a LangGraph Studióban.

    Képernyőkép a LangSmith Studióról egy betöltött gráfmal.

  6. Válassza az + Üzenet lehetőséget egy felhasználói kérdés hozzáadásához, majd válassza a Küldés lehetőséget.

    Kérdés A HR-dokumentumok relevanciája
    Does the NorthWind Health plus plan cover eye exams? Ez a kérdés a HR szempontjából releváns, és elég általános ahhoz, hogy a HR-dokumentumoknak, például az alkalmazotti kézikönyvnek, a juttatási kézikönyvnek és az alkalmazotti szerepkör-kódtárnak képesnek kell lennie arra, hogy megválaszolja azt.
    What is included in the NorthWind Health plus plan that is not included in the standard? Ez a kérdés a HR szempontjából releváns, és elég általános ahhoz, hogy a HR-dokumentumoknak, például az alkalmazotti kézikönyvnek, a juttatási kézikönyvnek és az alkalmazotti szerepkör-kódtárnak képesnek kell lennie arra, hogy megválaszolja azt.
    How much of my perks + benefit have I spent Ez a kérdés nem vonatkozik az általános, személytelen HR-dokumentumokra. Ezt a kérdést egy olyan ügynöknek kell elküldeni, aki hozzáfér az alkalmazottak adataihoz.
  7. Ha a kérdés a HR-dokumentumok szempontjából releváns, akkor át kell haladnia a DECISION_NODE és a ANSWER_NODE.

    Tekintse meg a terminálkimenetet az LLM kérdésének és az LLM válaszának megtekintéséhez.

  8. Ha a kérdés nem releváns a HR-dokumentumok szempontjából, a folyamat közvetlenül a végéhez ér.

Ha az LangChain.js ügynök helytelen döntést hoz, a probléma a következő lehet:

  • Használt LLM-modell
  • A vektortárolóból származó dokumentumok száma
  • A döntési csomópontban használt parancssor.

Az LangChain.js-ügynök futtatása egy alkalmazásból

Ha a LangChain.js-ügynököt egy szülőalkalmazásból, például egy webes API-ból szeretné meghívni, meg kell adnia a LangChain.js ügynök meghívását.

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;
  }
}

A két függvény a következő:

  • ask_agent: Ez a függvény az állapotot adja vissza, így lehetővé teszi a LangChain.js ügynök hozzáadását egy LangChain többügynök-munkafolyamathoz.
  • get_answer: Ez a függvény csak a válasz szövegét adja vissza. Ez a függvény egy API-ból hívható meg.

Hibaelhárítás

  • Az eljárással kapcsolatos problémák esetén hozzon létre egy hibát a mintakódtárban

Erőforrások tisztítása

Törölje az Azure AI Search-erőforrást és az Azure OpenAI-erőforrást tartalmazó erőforráscsoportot.