共用方式為


教學課程:使用 Azure AI 搜尋建置 LangChain.js 代理程式

在本教學課程中,您會使用 LangChain.js 建置可讓 NorthWind 公司員工詢問人力資源相關問題的 LangChain.js 代理程式。 藉由使用架構,您可以避免 LangChain.js 代理程式和 Azure 服務整合通常需要重複使用的程式代碼,讓您專注於業務需求。

在本教學課程中,您會:

  • 設定 LangChain.js 代理程式
  • 將 Azure 資源整合到您的 LangChain.js 代理程式
  • 選擇性地在 LangSmith Studio 中測試您的 LangChain.js 代理程式

NorthWind 依賴兩個數據源:可供所有員工存取的公用 HR 檔,以及包含敏感性員工數據的機密 HR 資料庫。 本教學課程著重於建置 LangChain.js 代理程式,以判斷員工的問題是否可以使用公用 HR 檔來回答。 如果是,LangChain.js 代理程式會直接提供答案。

圖表說明 LangChain.js 代理程式工作流程及其決策分支,以使用 HR 檔來回答問題。

警告

本文使用金鑰來存取資源。 在生產環境中,建議的最佳做法是使用 Azure RBAC 和受控識別。 這種方法不需要管理或輪替密鑰、增強安全性及簡化存取控制。

先決條件

  • 作用中的 Azure 帳戶。 如果您沒有帳戶,請免費建立帳戶
  • Node.js LTS 安裝在你的系統上。
  • 用於撰寫和編譯 TypeScript 程式代碼的 TypeScript
  • LangChain.js程式庫 用於建置代理程式。
  • 可選用 LangSmith 來監控 AI 的使用。 您需要項目名稱、金鑰和端點。
  • 選用:用於偵錯 LangGraph 鏈結和 LangChain.js 代理程式的 LangGraph Studio
  • Azure AI 搜尋資源:請確定您擁有資源端點、系統管理密鑰(用於檔插入)、查詢金鑰(用於讀取檔案),以及索引名稱。
  • Azure OpenAI 資源:您需要具有其 API 版本的資源實例名稱、金鑰和兩個模型:
    • 內嵌模型,例如 text-embedding-ada-002
    • 大型語言模型,例如 gpt-4o

代理程序架構

LangChain.js 架構提供建置智慧代理為 LangGraph 的決策流程。 在本教學課程中,您會建立 LangChain.js 代理程式,與 Azure AI 搜尋服務與 Azure OpenAI 整合,以回答 HR 相關問題。 代理程式的架構設計為:

  • 判斷問題是否與 HR 檔有關。
  • 從 Azure AI 搜尋擷取相關文件。
  • 使用 Azure OpenAI 根據擷取的檔和 LLM 模型產生答案。

重要元件

  • 圖表結構:LangChain.js 代理程式會以圖形表示,其中:

    • 節點會 執行特定工作,例如決策或擷取數據。
    • 邊界 定義節點間的流動,決定作業的順序。
  • Azure AI 搜尋服務整合

    • 將 HR 檔插入向量存放區作為內嵌。
    • 使用內嵌模型 (text-embedding-ada-002) 來建立這些內嵌。
    • 根據使用者提示擷取相關文件。
  • Azure OpenAI 整合

    • 使用大型語言模型 (gpt-4o) 來:
      • 判斷問題是否可從一般 HR 檔回答。
      • 使用文件和用戶問題的內容產生提示的解答。

下表提供用戶問題的範例,這些問題與一般人力資源文件無關且無法回答:

問題 與 HR 文件的相關性
Does the NorthWind Health Plus plan cover eye exams? 相關。 人力資源檔,如員工手冊,應該提供答案。
How much of my perks + benefits have I spent? 不相關。 這個問題需要存取此代理程式範圍之外的機密員工數據。

藉由使用架構,您可以避免 LangChain.js 代理程式和 Azure 服務整合通常需要重複使用的程式代碼,讓您專注於業務需求。

初始化您的 Node.js 專案

在新目錄中,初始化 TypeScript 代理程式 Node.js 專案。 執行以下命令:

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

建立環境檔案

建立一個 .env 檔案,用於本機開發,以儲存 Azure 資源和 LangGraph 的環境變數。 請確保內嵌和 LLM 的資源實例名稱僅為資源名稱,而不是端點。

選擇性:如果使用 LangSmith,請將 LANGSMITH_TRACING 設定為 true 以進行本機開發。 在生產環境中停用它(false)或移除它。

安裝依賴項

  1. 為 Azure AI Search 安裝 Azure 依賴項:

    npm install @azure/search-documents
    
  2. 請安裝 LangChain.js 依賴項,以用來建立和使用代理程式:

    npm install @langchain/community @langchain/core @langchain/langgraph @langchain/openai langchain
    
  3. 安裝用於本地開發的相依性:

    npm install --save-dev dotenv
    

建立 Azure AI 搜尋資源組態檔

若要管理本教學課程中使用的各種 Azure 資源和模型,請為每個資源建立特定的組態檔。 這種方法可確保考慮的明確性與區隔,讓您更輕鬆地管理和維護設定。

將檔上傳至向量存放區的設定

Azure AI 搜尋服務設定檔會使用系統管理金鑰,將檔插入向量存放區。 此金鑰對於管理將數據擷取至 Azure AI 搜尋服務至關重要。

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 抽象化需要定義將數據擷取至 Azure AI 搜尋的架構,並提供適用於大部分案例的默認架構。 此抽象概念可簡化程式,並減少自定義架構定義的需求。

查詢向量存放區的組態

若要查詢向量存放區,請建立個別的組態檔:

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

查詢向量存放區時,請改用查詢索引鍵。 此金鑰區隔可確保資源的安全且有效率的存取。

建立 Azure OpenAI 資源組態檔

若要管理兩個不同的模型,內嵌和 LLM,請建立個別的組態檔。 這種方法可確保考慮的明確性與區隔,讓您更輕鬆地管理和維護設定。

向量存儲區嵌入配置設定

若要建立將檔插入 Azure AI 搜尋向量存放區的內嵌專案,請建立組態檔:

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

LLM 產生答案的設定

若要從大型語言模型建立答案,請建立組態檔:

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

常數和提示

AI 應用程式通常會依賴常數位符串和提示。 使用個別檔案管理這些常數。

建立系統提示:

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

建立節點常數:

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

建立範例使用者查詢:

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

若要將檔載入 Azure AI 搜尋,請使用 LangChain.js 來簡化程式。 儲存為 PDF 的檔案會轉換成內嵌,並插入向量存放區。 此程式可確保檔已準備好進行有效率的擷取和查詢。

主要考量:

  • LangChain.js 抽象概念:LangChain.js 處理許多複雜度,例如架構定義和用戶端建立,讓程式變得簡單明瞭。
  • 節流和重試邏輯:雖然範例程式代碼包含最少的等候函式,但生產應用程式應該實作完整的錯誤處理,並重試邏輯來管理節流和暫時性錯誤。

載入檔的步驟

  1. 找出 PDF 檔:檔案會儲存在 資料目錄中

  2. 將 PDF 載入 LangChain.js:使用 loadPdfsFromDirectory 函數載入文件。 此函式會利用 LangChain.js 社群的 PDFLoader.load 方法來讀取每個檔案並傳回 Document[] 陣列。 此陣列是標準 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. 將文件插入 Azure AI 搜尋:使用loadDocsIntoAiSearchVector函數將文件陣列傳送至 Azure AI 搜尋向量存放區。 此函式會使用內嵌客戶端來處理檔,並包含處理節流的基本等候函式。 針對生產環境,實作健全的重試/退避機制。

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

建立代理程式工作流程

在 LangChain.js中,使用 LangGraph 建置 LangChain.js 代理程式。 LangGraph 可讓您定義節點和邊緣:

  • 節點:執行工作的位置。
  • Edge:定義節點之間的連線。

工作流程元件

在此應用程式中,這兩個工作節點為:

  • requiresHrResources:判斷問題是否與使用 Azure OpenAI LLM 的 HR 文件有關。
  • getAnswer:擷取答案。 答案來自 LangChain.js 擷取器鏈結,它會使用來自 Azure AI 搜尋的檔內嵌,並將其傳送至 Azure OpenAI LLM。 這是檢索增強生成的精髓。

邊緣會定義呼叫 getAnswer 節點所需的開始、結束位置及條件。

匯出圖形

若要使用 LangGraph Studio 執行和偵錯圖形,請將它匯出為自己的物件。

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

addNodeaddEdgeaddConditionalEdges 方法中,第一個參數是名稱,做為字串,用來識別圖形中的物件。 第二個參數是應該在該步驟呼叫的函式或要呼叫之節點的名稱。

針對 addEdge 方法,其名稱為 START (./src/config/nodes.ts 檔案中定義的 “start”),且一律會呼叫 DECISION_NODE。 該節點是以其兩個參數所定義:第一個是其名稱,DECISION_NODE,第二個是呼叫 requiresHrResources 的函式。

一般功能

此應用程式提供常見的 LangChain 功能:

  • 狀態管理:

    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: () => [],
      }),
    });
    
  • 路由終止:

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

此應用程式的唯一自定義路由是 routeRequiresHrResources。 此路由可用來判斷 requiresHrResources 節點的答案是否表示使用者的問題應該繼續到 ANSWER_NODE 節點。 因為此路由會接收 requiresHrResources 的輸出,所以它位於相同的檔案中。

整合 Azure OpenAI 資源

Azure OpenAI 整合使用兩個不同的模型:

  • 內嵌:用來將檔插入向量存放區。
  • LLM:用來藉由查詢向量存放區和產生回應來回答問題。

內嵌用戶端和 LLM 用戶端有不同的用途。 請勿將它們縮減為單一模型或用戶端。

嵌入模型

每當從向量存放區擷取檔時,都需要內嵌用戶端。 它包含一個用於處理暫時性錯誤的maxRetries組態設定。

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

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

LLM 模型

LLM 模型可用來回答兩種類型的問題:

  • 與 HR 相關:判斷用戶的問題是否與 HR 文件有關。
  • 答案產生:提供用戶問題的解答,並透過 Azure AI 搜尋中的文件來增強。

需要回應時,會建立並叫用 LLM 用戶端。

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

LangChain.js 代理程式會使用 LLM 來決定問題是否與 HR 檔有關,或工作流程是否應該路由至圖形結尾。

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

requiresHrResources 函數會將訊息與HR resources required detected內容一起設置在更新狀態中。 路由器 routeRequiresHrResources 會尋找該內容,以判斷要傳送訊息的位置。

整合向量存放區的 Azure AI 搜尋資源

Azure AI 搜尋整合提供向量存放區檔,讓 LLM 可以增強 getAnswer 節點的答案。 LangChain.js 再次提供大部分抽象概念,因此所需的程序代碼最少。 功能包括:

  • getReadOnlyVectorStore:使用查詢密鑰擷取用戶端。
  • getDocsFromVectorStore:尋找用戶問題的相關文件。
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);
}

LangChain.js 整合程式代碼可讓從向量存放區擷取相關文件變得非常容易。

撰寫程式代碼以從 LLM 取得答案

現在已建置整合元件,請建立 getAnswer 函式來擷取相關的向量存放區檔,並使用 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],
  };
}

此函式提供一個提示訊息,其中包含兩個佔位元:一個用於用戶的問題,另一個用於背景資訊。 內容是 AI 搜尋向量存放區中的所有相關文件。 將提示和 LLM 用戶端傳遞至 createStuffDocumentsChain ,以建立 LLM 鏈結。 將 LLM 鏈結傳遞至createRetrievalChain來建立一個包含提示、相關文件及 LLM 的鏈結。

檢索Chain.invoke 和用戶的問題作為輸入來運行鏈,並得到答案。 傳回訊息狀態中的答案。

建置代理程式套件

  1. 將腳本新增至 package.json ,以建置 TypeScript 應用程式:

    "build": "tsc",
    
  2. 建置 LangChain.js 代理程式。

    npm run build
    

選擇性 - 使用 LangChain Studio 在本機開發中執行 LangChain.js 代理程式

可選擇用於本地開發時,使用 LangChain Studio 搭配您的 LangChain.js 代理程式。

  1. 建立檔案 langgraph.json 以定義圖形。

    {
        "dependencies": [],
        "graphs": {
          "agent": "./src/graph.ts:hr_documents_answer_graph"
        },
        "env": "../.env"
      }
    
  2. 安裝 LangGraph CLI。

    npm install @langchain/langgraph-cli --save-dev
    
  3. package.json 中建立腳本,以將檔案傳遞 .env 至 LangGraph CLI。

    "studio": "npx @langchain/langgraph-cli dev",
    
  4. CLI 會在終端機中執行,並開啟瀏覽器至 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. 在 LangGraph Studio 中檢視 LangChain.js 代理程式。

    LangSmith Studio 螢幕快照,載有圖形。

  6. 選取 [+ 訊息 ] 以新增使用者問題,然後選取 [ 提交]。

    問題 與 HR 文件的相關性
    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? 這個問題與人力資源有關,而且一般足以讓員工手冊、福利手冊和員工角色連結庫等人力資源文件能夠回答。
    How much of my perks + benefit have I spent 這個問題與一般、非個人人力資源文件無關。 這個問題應該傳送給可存取員工數據的代理程式。
  7. 如果問題與 HR 檔有關,它應該通過 DECISION_NODE ,然後傳遞至 ANSWER_NODE

    通過觀察終端機輸出來查看 LLM 提出的問題和 LLM 的回答。

  8. 如果問題與 HR 文件無關,流程會直接 結束

當 LangChain.js 代理程式做出不正確的決策時,問題可能是:

  • 使用的 LLM 模型
  • 向量庫的文件數量
  • 決策節點中使用的提示。

從應用程式執行 LangChain.js 代理程式

若要從父應用程式呼叫 LangChain.js 代理程式,例如 Web API,您必須提供 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;
  }
}

這兩個函數分別是:

  • ask_agent:此函式會傳回狀態,因此可讓您將 LangChain.js 代理程式新增至 LangChain 多代理程式工作流程。
  • get_answer:此函式只會傳回答案的文字。 您可以從 API 呼叫此函式。

故障排除

清理資源

刪除保留 Azure AI 搜尋資源和 Azure OpenAI 資源的資源群組。