Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
In diesem Lernprogramm verwenden Sie LangChain.js, um einen LangChain.js Agent zu erstellen, mit dem mitarbeiter des Unternehmens NorthWind personalbezogene Fragen stellen können. Mithilfe des Frameworks vermeiden Sie in der Regel Codebausteine, die für LangChain.js Agents und die Azure-Dienstintegration erforderlich sind, sodass Sie sich auf Ihre Geschäftsanforderungen konzentrieren können.
In diesem Tutorial erfahren Sie:
- Einrichten eines LangChain.js-Agenten
- Integrieren von Azure-Ressourcen in Ihren LangChain.js-Agent
- Testen Sie optional Ihren LangChain.js Agent in LangSmith Studio
NorthWind basiert auf zwei Datenquellen: öffentliche Personaldokumentation, die für alle Mitarbeiter zugänglich ist, und einer vertraulichen HR-Datenbank, die vertrauliche Mitarbeiterdaten enthält. Dieses Lernprogramm konzentriert sich auf die Erstellung eines LangChain.js Agenten, der bestimmt, ob die Frage eines Mitarbeiters mithilfe der öffentlichen HR-Dokumenten beantwortet werden kann. Wenn ja, stellt der LangChain.js Agent die Antwort direkt bereit.
Warnung
In diesem Artikel werden Schlüssel für den Zugriff auf Ressourcen verwendet. In einer Produktionsumgebung empfiehlt es sich, Azure RBAC und verwaltete Identität zu verwenden. Dieser Ansatz beseitigt die Notwendigkeit, Schlüssel zu verwalten oder zu drehen, die Sicherheit zu verbessern und die Zugriffssteuerung zu vereinfachen.
Voraussetzungen
- Ein aktives Azure-Konto. Erstellen Sie ein kostenloses Konto , wenn Sie kein Konto haben.
- Node.js LTS auf Ihrem System installiert.
- TypeScript zum Schreiben und Kompilieren von TypeScript-Code.
- LangChain.js Bibliothek zum Erstellen des Agents.
- Optional: LangSmith zur Überwachung der KI-Nutzung. Sie benötigen den Projektnamen, den Schlüssel und den Endpunkt.
- Optional: LangGraph Studio zum Debuggen von LangGraph-Ketten und LangChain.js-Agents.
- Azure AI Search-Ressource: Stellen Sie sicher, dass Sie über den Ressourcenendpunkt, den Administratorschlüssel (zum Einfügen von Dokumenten), den Abfrageschlüssel (zum Lesen von Dokumenten) und den Indexnamen verfügen.
-
Azure OpenAI-Ressource: Sie benötigen den Ressourceninstanznamen, den Schlüssel und zwei Modelle mit ihren API-Versionen:
- Ein Einbettungsmodell wie
text-embedding-ada-002
. - Ein großes Sprachmodell wie
gpt-4o
.
- Ein Einbettungsmodell wie
Agentarchitektur
Das LangChain.js Framework bietet einen Entscheidungsfluss für die Erstellung intelligenter Agenten als LangGraph. In diesem Lernprogramm erstellen Sie einen LangChain.js Agent, der in Azure AI Search und Azure OpenAI integriert ist, um HR-bezogene Fragen zu beantworten. Die Architektur des Agents ist dafür konzipiert, um die folgenden Aufgaben zu erfüllen:
- Ermitteln Sie, ob eine Frage für die Personaldokumentation relevant ist.
- Rufen Sie relevante Dokumente aus Azure AI Search ab.
- Verwenden Sie Azure OpenAI, um eine Antwort basierend auf den abgerufenen Dokumenten und dem LLM-Modell zu generieren.
Schlüsselkomponenten:
Diagrammstruktur: Der LangChain.js Agent wird als Diagramm dargestellt, wobei:
- Knoten führen bestimmte Aufgaben aus, z. B. Entscheidungsfindung oder Abrufen von Daten.
- Edges definieren den Fluss zwischen Knoten und bestimmen die Abfolge von Vorgängen.
Azure AI Search Integration:
- Fügt HR-Dokumente als Einbettungen in den Vektorspeicher ein.
- Verwendet ein Einbettungsmodell (
text-embedding-ada-002
), um diese Einbettungen zu erstellen. - Ruft relevante Dokumente basierend auf der Benutzeraufforderung ab.
Azure OpenAI-Integration:
- Verwendet ein großes Sprachmodell (
gpt-4o
) für:- Bestimmt, ob eine Frage aus allgemeinen HR-Dokumenten beantwortet werden kann.
- Erstellt eine Antwort basierend auf einer Aufforderung, mithilfe des Kontexts aus Dokumenten und der Benutzerfrage.
- Verwendet ein großes Sprachmodell (
Die folgende Tabelle enthält Beispiele für Benutzerfragen, die sowohl relevant und beantwortbar sind, als auch solche, die nicht aus allgemeinen Personaldokumenten beantwortet werden können.
Frage | Relevanz für HR-Dokumente |
---|---|
Does the NorthWind Health Plus plan cover eye exams? |
Einschlägig. Die Hr-Dokumente, z. B. das Mitarbeiterhandbuch, sollten eine Antwort geben. |
How much of my perks + benefits have I spent? |
Nicht relevant. Diese Frage erfordert Zugriff auf vertrauliche Mitarbeiterdaten, die sich außerhalb des Umfangs dieses Agents befinden. |
Mithilfe des Frameworks vermeiden Sie in der Regel Codebausteine, die für LangChain.js Agents und die Azure-Dienstintegration erforderlich sind, sodass Sie sich auf Ihre Geschäftsanforderungen konzentrieren können.
Initialisieren des Node.js-Projekts
Initialisieren Sie in einem neuen Verzeichnis Ihr Node.js Projekt für Ihren TypeScript-Agent. Führen Sie die folgenden Befehle aus:
npm init -y
npm pkg set type=module
npx tsc --init
Erstellen einer Umgebungsdatei
Erstellen Sie eine .env
Datei für die lokale Entwicklung, um Umgebungsvariablen für Azure-Ressourcen und LangGraph zu speichern. Stellen Sie sicher, dass der Ressourcenname für die Einbettung und das LLM nur der Ressourcenname und nicht der Endpunkt ist.
Optional: Wenn Sie LangSmith verwenden, setzen Sie LANGSMITH_TRACING
auf true
für die lokale Entwicklung. Deaktivieren Sie sie (false
) oder entfernen Sie sie in der Produktion.
Installieren von Abhängigkeiten
Installieren von Azure-Abhängigkeiten für Azure AI Search:
npm install @azure/search-documents
Installieren Sie LangChain.js Abhängigkeiten zum Erstellen und Verwenden eines Agents:
npm install @langchain/community @langchain/core @langchain/langgraph @langchain/openai langchain
Entwicklungsabhängigkeiten für die lokale Entwicklung installieren
npm install --save-dev dotenv
Erstellen von Azure AI-Suchressourcenkonfigurationsdateien
Um die verschiedenen Azure-Ressourcen und -Modelle zu verwalten, die in diesem Lernprogramm verwendet werden, erstellen Sie bestimmte Konfigurationsdateien für jede Ressource. Dieser Ansatz sorgt für Klarheit und Trennung von Verantwortlichkeiten und erleichtert das Verwalten und Pflegen der Konfigurationen.
Konfiguration zum Hochladen von Dokumenten in den Vektorspeicher
Die Azure AI Search-Konfigurationsdatei verwendet den Administratorschlüssel, um Dokumente in den Vektorspeicher einzufügen. Dieser Schlüssel ist für die Verwaltung der Erfassung von Daten in Azure AI Search unerlässlich.
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 abstrahiert die Notwendigkeit, ein Schema für die Datenaufnahme in Azure AI Search zu definieren und ein Standardschema bereitzustellen, das für die meisten Szenarien geeignet ist. Diese Abstraktion vereinfacht den Prozess und reduziert die Notwendigkeit benutzerdefinierter Schemadefinitionen.
Konfiguration zum Abfragen des Vektorspeichers
Erstellen Sie zum Abfragen des Vektorspeichers eine separate Konfigurationsdatei:
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,
},
};
Verwenden Sie beim Abfragen des Vektorspeichers stattdessen den Abfrageschlüssel. Diese Trennung von Schlüsseln gewährleistet einen sicheren und effizienten Zugriff auf die Ressource.
Erstellen von Azure OpenAI-Ressourcenkonfigurationsdateien
Zum Verwalten der beiden verschiedenen Modelle erstellen Einbettungen und LLM separate Konfigurationsdateien. Dieser Ansatz sorgt für Klarheit und Trennung von Verantwortlichkeiten und erleichtert das Verwalten und Pflegen der Konfigurationen.
Konfiguration von Einbettungen für Vektorspeicher
Um Einbettungen zum Einfügen von Dokumenten in den Azure AI Search-Vektorspeicher zu erstellen, erstellen Sie eine Konfigurationsdatei:
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,
};
Konfiguration für LLM zum Generieren von Antworten
Um Antworten aus dem großen Sprachmodell zu erstellen, erstellen Sie eine Konfigurationsdatei:
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,
};
Konstanten und Aufforderungen
KI-Anwendungen basieren häufig auf konstanten Zeichenfolgen und Eingabeaufforderungen. Verwalten Sie diese Konstanten mit separaten Dateien.
Erstellen Sie die Systemaufforderung:
export const SYSTEM_PROMPT = `Answer the query with a complete paragraph based on the following context:`;
Erstellen Sie die Knotenkonstanten:
export const ANSWER_NODE = "vector_store_retrieval";
export const DECISION_NODE = "requires_hr_documents";
export const START = "__start__";
export const END = "__end__";
Beispielbenutzerabfragen erstellen:
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?",
];
Laden von Dokumenten in Azure AI Search
Um Dokumente in Azure AI Search zu laden, verwenden Sie LangChain.js, um den Prozess zu vereinfachen. Die Dokumente, die als PDF-Dateien gespeichert sind, werden in Einbettungen konvertiert und in den Vektorspeicher eingefügt. Dieser Prozess stellt sicher, dass die Dokumente für effizientes Abrufen und Abfragen bereit sind.
Wichtige Aspekte:
- LangChain.js Abstraktion: LangChain.js behandelt einen Großteil der Komplexität, z. B. Schemadefinitionen und Clienterstellung, wodurch der Prozess einfach wird.
- Drosselungs- und Wiederholungslogik: Während der Beispielcode eine minimale Wartefunktion enthält, sollten Produktionsanwendungen umfassende Fehlerbehandlungs- und Wiederholungslogik implementieren, um Drosselungen und vorübergehende Fehler effektiv zu handhaben.
Schritte zum Laden von Dokumenten
Suchen Sie die PDF-Dokumente: Die Dokumente werden im Datenverzeichnis gespeichert.
Laden Sie PDFs in LangChain.js: Verwenden Sie die
loadPdfsFromDirectory
Funktion, um die Dokumente zu laden. Diese Funktion verwendet die Methode der LangChain.js CommunityPDFLoader.load
, um jede Datei zu lesen und einDocument[]
Array zurückzugeben. Dieses Array ist ein Standarddokumentformat 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); } }
Einfügen von Dokumenten in Azure AI Search: Verwenden Sie die
loadDocsIntoAiSearchVector
Funktion, um das Dokumentarray an den Azure AI Search-Vektorspeicher zu senden. Diese Funktion verwendet den Einbettungsclient, um die Dokumente zu verarbeiten und enthält eine einfache Wartefunktion zum Behandeln der Drosselung. Implementieren Sie in der Produktion einen robusten Wiederholungs- und Backoff-Mechanismus.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; }
Agent-Workflow erstellen
Erstellen Sie in LangChain.jsden LangChain.js-Agenten mit einem LangGraph. Mit LangGraph können Sie die Knoten und Kanten definieren:
- Knoten: wo Tätigkeiten ausgeführt werden.
- Edge: definiert die Verbindung zwischen Knoten.
Workflowkomponenten
In dieser Anwendung sind die beiden Arbeitsknoten:
- requiresHrResources: bestimmt, ob die Frage für die HR-Dokumentation unter Verwendung von Azure OpenAI LLM relevant ist.
- getAnswer: Ruft die Antwort ab. Die Antwort stammt aus einer LangChain.js Retrieverchain, die die Dokumenteinbettungen aus Azure AI Search verwendet und sie an die Azure OpenAI LLM sendet. Das ist der Kern der abrufgestützten Generierung.
Die Kanten definieren, wo begonnen und geendet wird, sowie die Bedingung, die zum Aufrufen des Knotens getAnswer erforderlich ist.
Exportieren des Diagramms
Um LangGraph Studio zum Ausführen und Debuggen des Diagramms zu verwenden, exportieren Sie es als eigenes 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";
In den Methoden "addNode", "addEdge" und "addConditionalEdges " ist der erste Parameter ein Name( als Zeichenfolge), um das Objekt innerhalb des Diagramms zu identifizieren. Der zweite Parameter ist entweder die Funktion, die an diesem Schritt aufgerufen werden soll, oder der Name des zu aufrufenden Knotens.
Für die addEdge-Methode ist der Name START ("start" definiert in der Datei ./src/config/nodes.ts) und ruft immer die DECISION_NODE auf. Dieser Knoten wird mit seinen beiden Parametern definiert: der erste ist sein Name, DECISION_NODE, und der zweite ist die Funktion requiresHrResources, die aufgerufen wird.
Allgemeine Funktionalität
Diese App bietet allgemeine LangChain-Funktionen:
Zustandsverwaltung:
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: () => [], }), });
Routenbeendigung:
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; };
Die einzige benutzerdefinierte Route für diese Anwendung ist die routeRequiresHrResources. Diese Route wird verwendet, um festzustellen, ob die Antwort des Knotens "requiresHrResources " angibt, dass die Frage des Benutzers mit dem knoten ANSWER_NODE fortgesetzt werden soll. Da diese Route die Ausgabe von "requiresHrResources" empfängt, befindet sie sich in derselben Datei.
Integrieren von Azure OpenAI-Ressourcen
Die Azure OpenAI-Integration verwendet zwei verschiedene Modelle:
- Einbettungen: Wird verwendet, um die Dokumente in den Vektorspeicher einzufügen.
- LLM: Wird verwendet, um Fragen zu beantworten, indem sie den Vektorspeicher abfragen und Antworten generieren.
Der Einbettungsclient und der LLM-Client dienen verschiedenen Zwecken. Reduzieren Sie sie nicht auf ein einzelnes Modell oder Client.
Einbettungsmodell
Der Einbettungsclient ist erforderlich, wenn Dokumente aus dem Vektorspeicher abgerufen werden. Es enthält eine Konfiguration für maxRetries zur Behandlung vorübergehender Fehler.
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
Das LLM-Modell wird verwendet, um zwei Arten von Fragen zu beantworten:
- Relevanz für HR: Bestimmt, ob die Frage des Benutzers für die Personaldokumentation relevant ist.
- Antwortgenerierung: Bietet eine Antwort auf die Frage des Benutzers, ergänzt mit Dokumenten aus Azure AI Search.
Der LLM-Client wird erstellt und aufgerufen, wenn eine Antwort erforderlich ist.
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,
},
],
};
};
Der LangChain.js Agent verwendet die LLM, um zu entscheiden, ob die Frage für die Personaldokumentation relevant ist oder ob der Workflow an das Ende des Diagramms weitergeleitet werden soll.
// @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;
};
Die requiresHrResources-Funktion legt eine Nachricht im aktualisierten Zustand mit HR resources required detected
Inhalt fest. Der Router, routeRequiresHrResources, sucht nach diesem Inhalt, um zu bestimmen, wo die Nachrichten gesendet werden sollen.
Integrieren der Azure AI Search-Ressource für den Vektorspeicher
Die Azure AI Search-Integration stellt die Vektorspeicherdokumente bereit, damit die LLM die Antwort für den getAnswer-Knoten erweitern kann. LangChain.js bietet wieder einen Großteil der Abstraktion, sodass der erforderliche Code minimal ist. Die Funktionen sind:
- getReadOnlyVectorStore: Ruft den Client mit dem Abfrageschlüssel ab.
- getDocsFromVectorStore: Sucht relevante Dokumente für die Frage des Benutzers.
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);
}
Der LangChain.js Integrationscode erleichtert das Abrufen der relevanten Dokumente aus dem Vektorspeicher unglaublich einfach.
Schreiben von Code zum Abrufen der Antwort von LLM
Nachdem die Integrationskomponenten erstellt wurden, erstellen Sie die getAnswer-Funktion , um relevante Vektorspeicherdokumente abzurufen und mithilfe der LLM eine Antwort zu generieren.
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],
};
}
Diese Funktion stellt eine Eingabeaufforderung mit zwei Platzhaltern bereit: eine für die Frage des Benutzers und eine für den Kontext. Der Kontext ist alle relevanten Dokumente aus dem AI Search-Vektorspeicher. Übergeben Sie die Eingabeaufforderung und den LLM-Client an die createStuffDocumentsChain , um eine LLM-Kette zu erstellen. Geben Sie die LLM-Kette an createRetrievalChain weiter, um eine Kette zu erstellen, die die Eingabeaufforderung, relevante Dokumente und die LLM umfasst.
Führen Sie die Ketten mit "retrievalChain.invoke " und der Frage des Benutzers als Eingabe aus, um die Antwort zu erhalten. Gibt die Antwort im Status "Nachrichten" zurück.
Erstellen des Agent-Pakets
Fügen Sie ein Skript zu package.json hinzu, um die TypeScript-Anwendung zu erstellen:
"build": "tsc",
Erstellen Sie den Agenten LangChain.js.
npm run build
Optional : Führen Sie den LangChain.js-Agent in der lokalen Entwicklung mit LangChain Studio aus.
Optional können Sie für die lokale Entwicklung LangChain Studio verwenden, um mit Ihrem LangChain.js-Agent zu arbeiten.
Erstellen Sie eine
langgraph.json
Datei, um das Diagramm zu definieren.{ "dependencies": [], "graphs": { "agent": "./src/graph.ts:hr_documents_answer_graph" }, "env": "../.env" }
Installieren Sie die LangGraph CLI.
npm install @langchain/langgraph-cli --save-dev
Erstellen Sie ein Skript in package.json , um die
.env
Datei an die LangGraph CLI zu übergeben."studio": "npx @langchain/langgraph-cli dev",
Die CLI wird in Ihrem Terminal ausgeführt und öffnet einen Browser im 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
Zeigen Sie den LangChain.js-Agenten im LangGraph-Studio an.
Wählen Sie +Nachricht aus, um eine Benutzerfrage hinzuzufügen, und wählen Sie dann "Absenden" aus.
Frage Relevanz für HR-Dokumente Does the NorthWind Health plus plan cover eye exams?
Diese Frage ist für hr relevant und allgemein genug, dass die HR-Dokumente wie das Mitarbeiterhandbuch, das Leistungshandbuch und die Mitarbeiterrollenbibliothek sie beantworten können sollten. What is included in the NorthWind Health plus plan that is not included in the standard?
Diese Frage ist für hr relevant und allgemein genug, dass die HR-Dokumente wie das Mitarbeiterhandbuch, das Leistungshandbuch und die Mitarbeiterrollenbibliothek sie beantworten können sollten. How much of my perks + benefit have I spent
Diese Frage ist für die allgemeinen, unpersönlichen HR-Dokumente nicht relevant. Diese Frage sollte an einen Agenten gesendet werden, der Zugriff auf Mitarbeiterdaten hat. Wenn die Frage für die HR-Dokumente relevant ist, sollte sie den DECISION_NODE durchlaufen und weiter zum ANSWER_NODE gelangen.
Schauen Sie sich die Terminalausgabe an, um die Frage an die LLM und die Antwort von der LLM zu sehen.
Wenn die Frage für die HR-Dokumente nicht relevant ist, geht der Ablauf direkt ans Ende.
Wenn der LangChain.js Agent eine falsche Entscheidung trifft, kann das Problem folgendes sein:
- VERWENDETE LLM-Modell
- Anzahl der Dokumente aus dem Vektorspeicher
- Aufforderung, die im Entscheidungsknoten verwendet wird.
Ausführen des LangChain.js-Agents aus einer App
Um den LangChain.js-Agent aus einer übergeordneten Anwendung, z. B. einer Web-API, aufzurufen, müssen Sie den Aufruf des LangChain.js-Agents angeben.
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;
}
}
Die beiden Funktionen sind:
- ask_agent: Diese Funktion gibt den Zustand zurück, sodass Sie den LangChain.js-Agent einem LangChain-Multi-Agent-Workflow hinzufügen können.
- get_answer: Diese Funktion gibt nur den Text der Antwort zurück. Diese Funktion kann über eine API aufgerufen werden.
Problembehandlung
- Erstellen Sie bei Problemen mit der Prozedur ein Problem im Beispielcode-Repository.
Bereinigen von Ressourcen
Löschen Sie die Ressourcengruppe, die die Azure AI Search-Ressource und die Azure OpenAI-Ressource enthält.