LangChain 實戰專案:Chatbot
建構聊天機器人流程
簡介
在當前的 AI 風潮中,聊天機器人已成為企業與開發者最常見的應用之一。它不只可以提供即時客服、產品諮詢,甚至能成為內部知識庫的自動化助理。傳統上,開發一個功能完整且具彈性的聊天機器人,需要自行撰寫大量的 Prompt 設計、對話管理、上下文記憶 以及 工具整合 程式碼,工作量相當龐大。
LangChain 以「鏈」的概念將大型語言模型(LLM)與各式工具、記憶體、資料來源串接起來,讓開發者能以模組化的方式快速組裝出具備複雜功能的聊天機器人。本文將從 概念說明、程式碼範例、常見陷阱與最佳實踐,一步步帶你完成一個基本但可擴充的 Chatbot。
核心概念
1. LangChain 基礎架構
LangChain 的核心是 Chain(鏈)與 Component(元件):
| 元件 | 功能說明 |
|---|---|
| LLM | 直接呼叫 OpenAI、Anthropic、Azure 等大型語言模型。 |
| PromptTemplate | 統一管理 Prompt,支援變數插入與範本重用。 |
| Memory | 保存對話上下文(ConversationBufferMemory、ConversationSummaryMemory 等)。 |
| Tool | 將外部 API、資料庫、搜尋引擎等功能封裝成可被 LLM 呼叫的工具。 |
| Chain | 把上述元件按順序或條件組合,形成完整的工作流程。 |
重點:在設計聊天機器人時,我們通常會先建立 LLM + Prompt + Memory 的基礎對話鏈,然後根據需求加入 Tool(如搜尋、計算)形成 Agent。
2. PromptTemplate 與變數插入
使用 PromptTemplate 可以避免硬編碼 Prompt,讓 Prompt 更具可讀性與可維護性。
import { PromptTemplate } from "langchain/prompts";
// 建立一個簡單的問答 Prompt
const qaPrompt = new PromptTemplate({
template: `以下是一段使用者的問題與系統的回答。請根據問題給出最適切的答案。
問題: {question}
答案:`,
inputVariables: ["question"],
});
註解:
{question}會在執行時被實際的使用者問題取代。
3. 記憶體(Memory)保持對話上下文
對話型聊天機器人最重要的是 上下文連貫性。LangChain 提供多種 Memory,最常用的是 ConversationBufferMemory。
import { ConversationBufferMemory } from "langchain/memory";
const memory = new ConversationBufferMemory({
memoryKey: "chat_history", // 在 Prompt 中的變數名稱
returnMessages: true, // 返回完整訊息物件,方便後續處理
});
在 Chain 中加入 memory,每次呼叫都會自動把前面的對話加入 Prompt。
4. 基礎 LLM 呼叫與 Chain 組合
以下示範如何把 LLM + Prompt + Memory 組成最簡單的聊天鏈。
import { OpenAI } from "langchain/llms/openai";
import { LLMChain } from "langchain/chains";
const llm = new OpenAI({ temperature: 0.7, modelName: "gpt-4o-mini" });
const qaChain = new LLMChain({
llm,
prompt: qaPrompt,
memory, // 加入前面建立的記憶體
verbose: true, // 顯示執行細節,除錯時很有幫助
});
使用方式:
async function chat(question) {
const response = await qaChain.call({ question });
console.log("機器人回覆:", response.text);
}
// 範例對話
await chat("LangChain 是什麼?");
await chat("它可以用來做什麼?");
執行結果會自動把第一次的問題與回答保存到 memory,第二次呼叫時會把整段對話帶入 Prompt,提升連貫度。
5. 加入工具(Tool)打造 Agent
單純的 LLM 回答適合簡單問答,但若需要 即時搜尋、資料庫查詢、或 計算,就必須透過 Tool。LangChain 提供 Tool 介面,配合 AgentExecutor 可讓 LLM 主動決定何時呼叫外部工具。
5.1 建立自訂搜尋工具
import { Tool } from "langchain/tools";
class WebSearchTool extends Tool {
name = "WebSearch";
description = "使用關鍵字在網路上搜尋資訊,返回最相關的結果。";
async _call(input) {
// 這裡以 mock 為例,實務上接入真正的搜尋 API(如 SerpAPI)
const mockResult = `搜尋關鍵字「${input}」的結果:LangChain 是一個用於構建 LLM 應用的框架。`;
return mockResult;
}
}
5.2 建立 Agent 並註冊工具
import { initializeAgentExecutorWithOptions } from "langchain/agents";
const tools = [new WebSearchTool()];
const executor = await initializeAgentExecutorWithOptions(tools, llm, {
agentType: "zero-shot-react-description", // LLM 會根據描述自行決策
verbose: true,
});
5.3 使用 Agent 進行對話
async function agentChat(question) {
const result = await executor.call({ input: question });
console.log("Agent 回覆:", result.output);
}
// 讓 Agent 自行決定是否需要搜尋
await agentChat("請告訴我 2023 年最熱門的 AI 框架有哪些?");
在這個範例中,LLM 會先判斷「需要即時資訊」後呼叫 WebSearchTool,再把搜尋結果回饋給使用者,實現 知識更新 的能力。
6. 多模組組合:從簡單聊天到企業級助理
以下示範如何把 文件檢索(VectorStore) 與 工具 結合,打造一個能查詢公司內部文件的 Chatbot。
import { OpenAIEmbeddings } from "langchain/embeddings/openai";
import { MemoryVectorStore } from "langchain/vectorstores/memory";
import { RetrievalQAChain } from "langchain/chains";
// 1. 建立向量資料庫(此處使用記憶體版,實務上可換成 Pinecone、Weaviate 等)
const embeddings = new OpenAIEmbeddings();
const vectorStore = await MemoryVectorStore.fromTexts(
[
"公司治理手冊第 3 章說明了董事會的職責與權限。",
"2023 年財務報告顯示營收成長 12%。",
"產品使用說明書裡提到 API 認證方式為 OAuth2。",
],
embeddings
);
// 2. 建立檢索鏈
const retriever = vectorStore.asRetriever();
const qaRetrievalChain = RetrievalQAChain.fromLLM(llm, retriever, {
returnSourceDocuments: true, // 回傳來源文件,方便除錯
});
// 3. 把檢索鏈包進 Agent 的工具中
class DocumentSearchTool extends Tool {
name = "DocumentSearch";
description = "在公司內部文件中搜尋相關資訊,輸入關鍵字即可。";
async _call(input) {
const result = await qaRetrievalChain.call({ query: input });
return result.text; // 只回傳答案文字
}
}
const corpTools = [new DocumentSearchTool(), new WebSearchTool()];
const corpAgent = await initializeAgentExecutorWithOptions(corpTools, llm, {
agentType: "zero-shot-react-description",
verbose: true,
});
使用方式:
await corpAgent.call({ input: "請說明董事會的主要職責是什麼?" });
await corpAgent.call({ input: "2023 年的營收成長多少?" });
透過向量檢索,我們可以在 毫秒內 從大量文件中找到相關段落,讓聊天機器人具備 企業知識庫 的能力。
常見陷阱與最佳實踐
| 陷阱 | 說明 | 解決方案 |
|---|---|---|
| Prompt 過長 | 把全部歷史訊息直接塞入 Prompt,會超過模型的 token 限制。 | 使用 Memory(如 ConversationSummaryMemory)把舊訊息摘要,或設定 maxTokens。 |
| 工具呼叫無限制 | Agent 若沒有適當的 stop criteria,可能無限迭代呼叫工具。 | 設定 maxIterations(如 maxIterations: 5)或在 Prompt 中加入「如果無法解決,直接回覆」的指示。 |
| 向量資料庫未同步 | 新增或更新文件後忘記重新嵌入,導致檢索結果過時。 | 建立 自動化 pipeline:文件變更 → 重建向量 → 更新 VectorStore。 |
| 資訊安全 | 把機密資料直接傳給第三方 LLM,可能違反合規。 | 使用 本地 LLM(如 Llama 3)或在 Prompt 中過濾敏感資訊;同時利用 OpenAI 的 data control 功能。 |
| 溫度(temperature)設置不當 | 溫度過高會產生不穩定或不正確的答案。 | 對於事實性問答,建議 temperature: 0;對於創意寫作,可適度調高。 |
最佳實踐:
- 分層記憶:近期對話使用
ConversationBufferMemory,較早的對話使用ConversationSummaryMemory,減少 token 消耗。 - 工具優先:先嘗試資料庫或搜尋工具,只有在找不到答案時才交給 LLM 產生回覆,提升正確率。
- 日誌與監控:開啟
verbose: true,將每次呼叫的 Prompt、工具參數、回傳結果寫入日誌,有助於除錯與模型調校。 - 測試 Prompt:使用 PromptLayer 或 OpenAI Playground 先驗證 Prompt 效果,再寫入程式碼。
- 安全審核:對所有外部工具的輸入/輸出做 sanitization,防止 Prompt Injection 攻擊。
實際應用場景
| 場景 | 功能需求 | LangChain 解法 |
|---|---|---|
| 客服聊天機器人 | 常見問題解答、即時訂單查詢、跨系統資料整合 | 使用 ConversationBufferMemory + WebSearchTool(訂單 API)+ LLMChain |
| 內部知識庫助理 | 文件搜尋、政策說明、程式碼範例 | 向量檢索 (MemoryVectorStore) + DocumentSearchTool + Agent |
| 產品諮詢 AI | 根據使用者需求產生客製化方案、計算報價 | LLMChain + CalculatorTool(計算)+ WebSearchTool(市場資訊) |
| 教育輔助聊天機器人 | 解釋概念、提供練習題、即時批改 | ConversationSummaryMemory + LLMChain(解說)+ Tool(題庫 API) |
| 多語言客服 | 同時支援中文、英文、日文等語言 | 在 OpenAI 設定 modelName 為支援多語言的模型,搭配 PromptTemplate 中的語言變數。 |
案例說明:假設一家金融公司想要一個「投資顧問」聊天機器人,除了回答基本的投資概念外,還需要即時查詢 ETF 價格。開發者可先把 ETF 價格 API 包裝成
Tool,再把WebSearchTool用於宏觀經濟資訊,最後把所有工具交給AgentExecutor,即可在一次對話中完成 概念說明 + 即時數據 的需求。
總結
LangChain 讓 LLM 從單純的文字生成器,變成 可組合、可擴充、可控制 的應用平台。透過 PromptTemplate、Memory、Tool 與 Agent,我們可以在短時間內構建出:
- 具備上下文連貫性的聊天對話
- 能即時抓取外部資訊的智慧回覆
- 能在企業內部文件、資料庫中快速檢索的知識助理
在實作時,請特別注意 Prompt 長度、記憶體管理、工具呼叫限制 以及 資訊安全,並遵循 分層記憶、工具優先、日誌監控 的最佳實踐。只要掌握這些核心概念與設計模式,即可將 LangChain 應用於客服、內部助理、教育輔導、產品諮詢等多種場景,快速提升開發效率與使用者體驗。
祝你在 LangChain 的旅程中玩得開心、玩得順利! 🚀