Nota
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
En este tutorial, usará LangChain.js para crear un agente de LangChain.js que permita a los empleados de la empresa NorthWind formular preguntas relacionadas con los recursos humanos. Mediante el uso del marco, se evita el código reutilizable que normalmente se requiere para LangChain.js agentes y la integración de servicios de Azure, lo que le permite centrarse en sus necesidades empresariales.
En este tutorial, usted hará lo siguiente:
- Configure un agente LangChain.js
- Integración de recursos de Azure en el agente de LangChain.js
- Opcionalmente, pruebe el agente de LangChain.js en LangSmith Studio
NorthWind se basa en dos orígenes de datos: documentación pública de RR. HH. accesible para todos los empleados y una base de datos confidencial de RR. HH. que contiene datos confidenciales de los empleados. Este tutorial se centra en la creación de un agente de LangChain.js que determina si se puede responder a la pregunta de un empleado mediante los documentos públicos de RR. HH. Si es así, el agente de LangChain.js proporciona la respuesta directamente.
Advertencia
En este artículo se usan claves para acceder a los recursos. En un entorno de producción, el procedimiento recomendado es usar RBAC de Azure e identidad administrada. Este enfoque elimina la necesidad de administrar o girar claves, lo que mejora la seguridad y simplifica el control de acceso.
Prerrequisitos
- Una cuenta de Azure activa. Cree una cuenta gratuita si no tiene una.
- Node.js LTS instalado en el sistema.
- TypeScript para escribir y compilar código TypeScript.
- LangChain.js biblioteca para construir el agente.
- Opcional: LangSmith para supervisar el uso de la inteligencia artificial. Necesita el nombre del proyecto, la clave y el punto de conexión.
- Opcional: LangGraph Studio para depurar las cadenas de LangGraph y los agentes LangChain.js.
- Recurso de Azure AI Search: asegúrese de que tiene el punto de conexión de recursos, la clave de administrador (para la inserción de documentos), la clave de consulta (para leer documentos) y el nombre del índice.
-
Recurso de Azure OpenAI: necesita el nombre de la instancia de recurso, la clave y dos modelos con sus versiones de API:
- Un modelo de incrustaciones como
text-embedding-ada-002
. - Un modelo de lenguaje grande como
gpt-4o
.
- Un modelo de incrustaciones como
Arquitectura del agente
El marco de LangChain.js proporciona un flujo de decisión para crear agentes inteligentes como langGraph. En este tutorial, creará un agente de LangChain.js que se integra con Azure AI Search y Azure OpenAI para responder a preguntas relacionadas con los recursos humanos. La arquitectura del agente está diseñada para:
- Determine si una pregunta es relevante para la documentación de RR. HH.
- Recupere documentos relevantes de Azure AI Search.
- Use Azure OpenAI para generar una respuesta basada en los documentos recuperados y el modelo LLM.
Componentes clave:
Estructura del grafo: el agente de LangChain.js se representa como un grafo, donde:
- Los nodos realizan tareas específicas, como la toma de decisiones o la recuperación de datos.
- Los bordes definen el flujo entre nodos y determinan la secuencia de operaciones.
Integración de Azure AI Search:
- Inserta documentos de RR. HH. en el almacén de vectores como incrustaciones.
- Usa un modelo de incrustaciones (
text-embedding-ada-002
) para crear estas incrustaciones. - Recupera los documentos pertinentes en función de la solicitud del usuario.
Integración de Azure OpenAI:
- Usa un modelo de lenguaje grande (
gpt-4o
) para:- Determina si una pregunta es respondible a partir de documentos generales de RR. HH.
- Genera una respuesta con una instrucción utilizando el contexto de documentos y la pregunta del usuario.
- Usa un modelo de lenguaje grande (
En la tabla siguiente se muestran ejemplos de preguntas de usuario que son y no son relevantes y respondibles de documentos generales de recursos humanos:
Pregunta | Relevancia para los documentos de RR. HH. |
---|---|
Does the NorthWind Health Plus plan cover eye exams? |
Pertinente. Los documentos de recursos humanos, como el manual del empleado, deben proporcionar una respuesta. |
How much of my perks + benefits have I spent? |
No es relevante. Esta pregunta requiere acceso a los datos confidenciales de los empleados, que están fuera del ámbito de este agente. |
Mediante el uso del marco, se evita el código reutilizable que normalmente se requiere para LangChain.js agentes y la integración de servicios de Azure, lo que le permite centrarse en sus necesidades empresariales.
Inicia tu proyecto de Node.js
En un nuevo directorio, inicialice el proyecto de Node.js para el agente de TypeScript. Ejecute los comandos siguientes:
npm init -y
npm pkg set type=module
npx tsc --init
Creación de un archivo de entorno
Cree un .env
archivo para el desarrollo local para almacenar variables de entorno para recursos de Azure y LangGraph. Asegúrese de que el nombre de la instancia de recurso para embedding y LLM sea solo el nombre del recurso, no el punto de conexión.
Opcional: si usa LangSmith, establezca LANGSMITH_TRACING
en true
para el desarrollo local. Deshabilite (false
) o quítelo en producción.
Instalación de dependencias
Instale las dependencias de Azure para Azure AI Search:
npm install @azure/search-documents
Instale LangChain.js dependencias para crear y usar un agente:
npm install @langchain/community @langchain/core @langchain/langgraph @langchain/openai langchain
Instale las dependencias de desarrollo en el entorno local.
npm install --save-dev dotenv
Creación de archivos de configuración de recursos de Azure AI Search
Para administrar los distintos recursos y modelos de Azure que se usan en este tutorial, cree archivos de configuración específicos para cada recurso. Este enfoque garantiza la claridad y separación de las preocupaciones, lo que facilita la administración y el mantenimiento de las configuraciones.
Configuración para cargar documentos en el almacén de vectores
El archivo de configuración de Azure AI Search usa la clave de administrador para insertar documentos en el almacén de vectores. Esta clave es esencial para administrar la ingesta de datos en 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 abstrae la necesidad de definir un esquema para la ingesta de datos en Azure AI Search, lo que proporciona un esquema predeterminado adecuado para la mayoría de los escenarios. Esta abstracción simplifica el proceso y reduce la necesidad de definiciones de esquema personalizadas.
Configuración para consultar el almacén de vectores
Para consultar el almacén de vectores, cree un archivo de configuración independiente:
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,
},
};
Al consultar el almacén de vectores, use la clave de consulta en su lugar. Esta separación de claves garantiza un acceso seguro y eficaz al recurso.
Creación de archivos de configuración de recursos de Azure OpenAI
Para administrar los dos modelos diferentes, embeddings y LLM, cree archivos de configuración independientes. Este enfoque garantiza la claridad y separación de las preocupaciones, lo que facilita la administración y el mantenimiento de las configuraciones.
Configuración para incrustaciones para el almacén de vectores
Para crear incrustaciones para insertar documentos en el almacén de vectores de Azure AI Search, cree un archivo de configuración:
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,
};
Configuración de LLM para generar respuestas
Para crear respuestas del modelo de lenguaje grande, cree un archivo de configuración:
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,
};
Constantes e indicaciones
Las aplicaciones de inteligencia artificial a menudo se basan en cadenas y mensajes constantes. Administre estas constantes con archivos independientes.
Cree el aviso del sistema.
export const SYSTEM_PROMPT = `Answer the query with a complete paragraph based on the following context:`;
Cree las constantes de nodos:
export const ANSWER_NODE = "vector_store_retrieval";
export const DECISION_NODE = "requires_hr_documents";
export const START = "__start__";
export const END = "__end__";
Cree consultas de usuario de ejemplo:
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?",
];
Carga de documentos en Azure AI Search
Para cargar documentos en Azure AI Search, use LangChain.js para simplificar el proceso. Los documentos, almacenados como ARCHIVOS PDF, se convierten en incrustaciones e insertan en el almacén de vectores. Este proceso garantiza que los documentos estén listos para una recuperación y consulta eficaces.
Principales consideraciones:
- LangChain.js abstracción: LangChain.js controla gran parte de la complejidad, como las definiciones de esquema y la creación de clientes, lo que facilita el proceso.
- Lógica de estrangulamiento y reintento: aunque el código de ejemplo incluye una función de espera mínima, las aplicaciones de producción deben implementar un manejo completo de errores y lógica de reintento para administrar errores transitorios y estrangulamiento.
Pasos para cargar documentos
Busque los documentos PDF: los documentos se almacenan en el directorio de datos.
Cargar archivos PDF en LangChain.js: use la
loadPdfsFromDirectory
función para cargar los documentos. Esta función utiliza el método de la comunidad LangChain.jsPDFLoader.load
para leer cada archivo y devolver unDocument[]
array. Esta matriz es un formato de documento estándar 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); } }
Insertar documentos en Azure AI Search: use la función para enviar la
loadDocsIntoAiSearchVector
matriz de documentos al almacén de vectores de Azure AI Search. Esta función usa el cliente de inserciones para procesar los documentos e incluye una función de espera básica para controlar la limitación. En el caso de la producción, implemente un mecanismo sólido de reintento/retroceso.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; }
Creación de un flujo de trabajo del agente
En LangChain.js, construye el agente de LangChain.js con un LangGraph. LangGraph permite definir los nodos y los bordes:
- Nodo: donde se realiza el trabajo.
- Edge: define la conexión entre nodos.
Componentes de flujo de trabajo
En esta aplicación, los dos nodos de trabajo son:
- requireHrResources: determina si la pregunta es relevante para la documentación de RR. HH. mediante azure OpenAI LLM.
- getAnswer: recupera la respuesta. La respuesta viene de una cadena de recuperación LangChain.js, que utiliza los embeddings de documentos de Azure AI Search y los envía a Azure OpenAI LLM. Esta es la esencia de la generación aumentada por recuperación.
Los bordes definen dónde empezar, finalizar y la condición necesaria para llamar al nodo getAnswer .
Exportación del gráfico
Para usar LangGraph Studio para ejecutar y depurar el gráfico, expórtelo como su propio objeto.
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";
En los métodos addNode, addEdge y addConditionalEdges , el primer parámetro es un nombre, como una cadena, para identificar el objeto dentro del grafo. El segundo parámetro es la función a la que se debe llamar en ese paso o el nombre del nodo al que se va a llamar.
Para el método addEdge , su nombre es START ("start" definido en el archivo ./src/config/nodes.ts) y siempre llama al DECISION_NODE. Ese nodo se define con sus dos parámetros: el primero es su nombre, DECISION_NODE y el segundo es la función denominada requireHrResources.
Funcionalidad común
Esta aplicación proporciona funcionalidad de LangChain común:
Administración de estados:
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: () => [], }), });
Terminación de ruta:
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; };
La única ruta personalizada para esta aplicación es routeRequiresHrResources. Esta ruta se usa para determinar si la respuesta del nodo requireHrResources indica que la pregunta del usuario debe continuar con el nodo ANSWER_NODE . Dado que esta ruta recibe la salida de requireHrResources, se encuentra en el mismo archivo.
Integración de recursos de Azure OpenAI
La integración de Azure OpenAI usa dos modelos diferentes:
- Incrustaciones: se usa para insertar los documentos en el almacén de vectores.
- LLM: se usa para responder a preguntas consultando el almacén de vectores y generando respuestas.
El cliente de incrustaciones y el cliente LLM sirven para diferentes propósitos. No los reduzca a un solo modelo o cliente.
Modelo de inserción
El cliente de embeddings es necesario cada vez que se recuperan documentos del almacén de vectores. Incluye una configuración para maxRetries para controlar errores transitorios.
import { AzureOpenAIEmbeddings } from "@langchain/openai";
import { EMBEDDINGS_CONFIG } from "../config/embeddings.js";
export function getEmbeddingClient(): AzureOpenAIEmbeddings {
return new AzureOpenAIEmbeddings({ ...EMBEDDINGS_CONFIG, maxRetries: 1 });
}
Modelo LLM
El modelo LLM se usa para responder a dos tipos de preguntas:
- Relevancia para recursos humanos: determina si la pregunta del usuario es relevante para la documentación de RR. HH.
- Generación de respuestas: proporciona una respuesta a la pregunta del usuario, aumentada con documentos de Azure AI Search.
El cliente LLM se crea e invoca cuando se requiere una respuesta.
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,
},
],
};
};
El agente de LangChain.js usa el LLM para decidir si la pregunta es relevante para la documentación de RR. HH. o si el flujo de trabajo debe enrutarse al final del gráfico.
// @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;
};
La función requireHrResources establece un mensaje en el estado actualizado con HR resources required detected
contenido. El enrutador, routeRequiresHrResources, busca ese contenido para determinar dónde enviar los mensajes.
Integración del recurso de Azure AI Search para el almacén de vectores
La integración de Azure AI Search proporciona los documentos del almacén de vectores para que el LLM pueda complementar la respuesta del nodo getAnswer. LangChain.js de nuevo proporciona gran parte de la abstracción, por lo que el código necesario es mínimo. Las funciones son:
- getReadOnlyVectorStore: recupera el cliente con la clave de consulta.
- getDocsFromVectorStore: busca documentos relevantes para la pregunta del usuario.
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);
}
El código de integración de LangChain.js hace que recuperar los documentos pertinentes del almacén de vectores sea increíblemente fácil.
Escribir código para obtener la respuesta de LLM
Ahora que se compilan los componentes de integración, cree la función getAnswer para recuperar los documentos de almacén de vectores pertinentes y genere una respuesta mediante 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],
};
}
Esta función proporciona un aviso con dos marcadores de posición: uno para la pregunta del usuario y otro para el contexto. El contexto son todos los documentos pertinentes del almacén vectorial de búsqueda de IA. Pase el aviso y el cliente LLM a createStuffDocumentsChain para crear una cadena LLM. Pase la cadena LLM para crearRetrievalChain para crear una cadena que incluya el mensaje, los documentos pertinentes y el LLM.
Ejecute las cadenas con retrievalChain.invoke y la pregunta del usuario como entrada para obtener la respuesta. Devuelve la respuesta en el estado de los mensajes.
Construir el paquete del agente
Agregue un script a package.json para compilar la aplicación TypeScript:
"build": "tsc",
Compila el agente LangChain.js.
npm run build
Opcional: ejecute el agente de LangChain.js en desarrollo local con LangChain Studio.
Opcionalmente, para el desarrollo local, use LangChain Studio para trabajar con el agente de LangChain.js.
Cree un
langgraph.json
archivo para definir el grafo.{ "dependencies": [], "graphs": { "agent": "./src/graph.ts:hr_documents_answer_graph" }, "env": "../.env" }
Instale la CLI de LangGraph.
npm install @langchain/langgraph-cli --save-dev
Cree un script en package.json para pasar el
.env
archivo a la CLI de LangGraph."studio": "npx @langchain/langgraph-cli dev",
La CLI se ejecuta en el terminal y abre un explorador en 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
Vea el agente de LangChain.js en LangGraph Studio.
Seleccione + Mensaje para agregar una pregunta de usuario y, a continuación, seleccione Enviar.
Pregunta Relevancia para los documentos de RR. HH. Does the NorthWind Health plus plan cover eye exams?
Esta pregunta es relevante para los recursos humanos y lo suficientemente general como para que los documentos de RR. HH. como el manual de empleados, el manual de beneficios y la biblioteca de roles de los empleados puedan responderlo. What is included in the NorthWind Health plus plan that is not included in the standard?
Esta pregunta es relevante para los recursos humanos y lo suficientemente general como para que los documentos de RR. HH. como el manual de empleados, el manual de beneficios y la biblioteca de roles de los empleados puedan responderlo. How much of my perks + benefit have I spent
Esta pregunta no es relevante para los documentos generales e impersonales de RR. HH. Esta pregunta debe enviarse a un agente que tenga acceso a los datos de los empleados. Si la pregunta es relevante para los documentos de recursos humanos, debe pasar a través del DECISION_NODE y hacia el ANSWER_NODE.
Vea la salida del terminal para ver la pregunta al LLM y la respuesta del LLM.
Si la pregunta no es relevante para los documentos de RR. HH., el flujo va directamente al final.
Cuando el agente de LangChain.js toma una decisión incorrecta, el problema puede ser:
- Modelo LLM usado
- Número de documentos del almacén de vectores
- Indicación usada en el nodo de decisión.
Ejecuta el agente LangChain.js desde una aplicación
Para llamar al agente de LangChain.js desde una aplicación primaria, como una API web, debe proporcionar la invocación del agente de 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;
}
}
Las dos funciones son:
- ask_agent: esta función devuelve el estado para que le permita agregar el agente de LangChain.js a un flujo de trabajo de varios agentes LangChain.
- get_answer: esta función devuelve solo el texto de la respuesta. Se puede llamar a esta función desde una API.
Solución de problemas
- Para cualquier problema con el procedimiento, cree un problema en el repositorio de código de ejemplo.
Limpieza de recursos
Elimine el grupo de recursos que contiene el recurso de Azure AI Search y el recurso de Azure OpenAI.