本文 AI 產出,尚未審核

LangChain 實戰專案:Chatbot – 加入工具與查詢能力


簡介

在現代 AI 應用中,Chatbot 已不只是單純的對話機器人**,更需要具備即時查詢、資料擷取與外部工具整合的能力**。只有這樣的 Chatbot 才能在真實業務場景中提供有價值的回應,例如即時查詢庫存、呼叫第三方 API、或在對話中執行簡單計算。

LangChain 作為一套 「語言模型 + 工具」 的框架,讓開發者可以輕鬆把 LLM(大型語言模型)與外部資源串接。透過 Tool(工具)與 Retriever(檢索器),Chatbot 能在對話過程中自動決定何時呼叫外部服務、何時從知識庫取得資訊,從而大幅提升回應的正確性與實用性。

本篇文章將從 核心概念程式碼範例常見陷阱與最佳實踐,一步步帶你在 LangChainJS 中為 Chatbot 加入工具與查詢能力,並說明這些功能在實務上的應用場景。


核心概念

1. Tool(工具)

Tool 是一個 可被 LLM 呼叫的函式,通常用來執行以下任務:

類型 範例
API 呼叫 查詢天氣、股票、航班資訊
資料庫操作 讀寫 MySQL、MongoDB
計算 數學運算、文字統計
系統指令 執行 Shell、產生檔案

LangChainJS 中的 Tool 必須符合以下介面:

interface Tool {
  name: string;               // 工具名稱,LLM 會使用這個名稱呼叫
  description: string;        // 工具說明,提供給 LLM 作為參考
  func: (input: string) => Promise<string>; // 執行函式,接受字串輸入回傳字串
}

2. Retriever(檢索器)

Retriever 用來 從向量資料庫或全文檢索系統中取得相關文件,並把結果提供給 LLM 作為上下文。常見的實作有:

  • PineconeWeaviate:雲端向量資料庫
  • FAISS:本機向量索引
  • ElasticSearch:全文檢索

LangChainJS 提供 VectorStoreRetrieverElasticSearchRetriever 等抽象類別,讓開發者只要提供向量化模型與資料來源,即可快速建立檢索器。

3. Agent(代理人)

Agent 是 組合 LLM、Tool、Retriever 的核心,它會根據對話內容自行決策:

  1. 判斷是否需要工具(例如:「請幫我查一下今天台北的天氣」)
  2. 呼叫相應工具,取得結果
  3. 將結果與原始問題一起送回 LLM,產生最終回應

LangChainJS 中的 ChatAgent 只需要提供 LLM、tool list、retriever(可選)即可完成。


程式碼範例

以下範例均使用 LangChainJS(v0.2+) 搭配 OpenAI 的 ChatGPT,語言為 TypeScript/JavaScript。若使用 Python,概念相同,只是語法會略有差異。

範例 1:建立一個簡易的「天氣查詢」Tool

import { OpenAI } from "langchain/llms/openai";
import { Tool } from "langchain/tools";

// 假設有一個第三方天氣 API
async function fetchWeather(city: string): Promise<string> {
  const response = await fetch(`https://api.weatherapi.com/v1/current.json?key=YOUR_KEY&q=${city}`);
  const data = await response.json();
  return `🌤 ${city} 現在 ${data.current.temp_c}°C,${data.current.condition.text}`;
}

// 包裝成 LangChain 的 Tool
const weatherTool: Tool = {
  name: "weather",
  description: "查詢指定城市的即時天氣。輸入格式:城市名稱,例如「台北」",
  func: async (input: string) => {
    const city = input.trim();
    if (!city) return "請提供城市名稱。";
    try {
      return await fetchWeather(city);
    } catch (e) {
      return "呼叫天氣服務失敗,請稍後再試。";
    }
  },
};

重點:Tool 的 description 必須寫得 清楚且具體,讓 LLM 能正確判斷何時使用此工具。

範例 2:使用 FAISS 建立本機向量檢索器

import { OpenAIEmbeddings } from "langchain/embeddings/openai";
import { FAISS } from "langchain/vectorstores/faiss";
import { Document } from "langchain/document";

// 假設有一批產品說明文件
const docs: Document[] = [
  new Document({ pageContent: "iPhone 15 採用 A17 仿生晶片,支援 5G。" }),
  new Document({ pageContent: "MacBook Pro 2023 搭載 M2 Pro 晶片,配備 14 吋 Retina 螢幕。" }),
  // …更多文件
];

// 建立向量化模型與 FAISS 索引
const embeddings = new OpenAIEmbeddings({ openAIApiKey: process.env.OPENAI_API_KEY });
const vectorStore = await FAISS.fromDocuments(docs, embeddings);

// 產生 Retriever(取前 3 個最相似的文件)
const retriever = vectorStore.asRetriever({ k: 3 });

提示:在正式環境中,向量資料庫建置只需一次,之後只要呼叫 vectorStore.asRetriever() 即可重複使用。

範例 3:組合 LLM、Tool 與 Retriever 成為 ChatAgent

import { ChatOpenAI } from "langchain/chat_models/openai";
import { initializeAgentExecutorWithOptions } from "langchain/agents";
import { ConversationalRetrievalQAChain } from "langchain/chains";

// 1. LLM
const llm = new ChatOpenAI({
  temperature: 0, // 為了可預測性,設定為 0
  openAIApiKey: process.env.OPENAI_API_KEY,
});

// 2. Tool 列表(加入 weatherTool)
const tools = [weatherTool];

// 3. 建立 Agent
const agentExecutor = await initializeAgentExecutorWithOptions(tools, llm, {
  agentType: "chat-zero-shot-react-description",
  // 可選:加入檢索器,使 Agent 能在需要時查詢文件
  retriever,
});

// 測試對話
async function ask(question: string) {
  const result = await agentExecutor.run(question);
  console.log(`❓ ${question}\n🤖 ${result}\n`);
}

// 範例對話
await ask("今天台北的天氣如何?");
await ask("請告訴我 iPhone 15 的處理器規格。");

執行結果示例

❓ 今天台北的天氣如何?
🤖 🌤 台北現在 26°C,晴時多雲

❓ 請告訴我 iPhone 15 的處理器規格。
🤖 iPhone 15 採用 A17 仿生晶片,具備更高效能與更低功耗。

範例 4:自訂「數學計算」Tool,結合 LLM 的推理

import { Tool } from "langchain/tools";

const mathTool: Tool = {
  name: "calculator",
  description: "執行簡單的算術運算,支援 + - * / 以及括號。例如:2 * (3 + 4)",
  func: async (input: string) => {
    try {
      // 使用 Function constructor 只允許數學表達式
      const result = Function(`"use strict"; return (${input})`)();
      return `計算結果:${result}`;
    } catch {
      return "無效的算式,請重新輸入。";
    }
  },
};

// 把 mathTool 加入 Agent
const agentWithMath = await initializeAgentExecutorWithOptions(
  [weatherTool, mathTool],
  llm,
  { agentType: "chat-zero-shot-react-description", retriever }
);

// 測試
await agentWithMath.run("請幫我算一下 12 / (2 + 4) * 3 的結果。");

範例 5:從外部資料庫查詢庫存(MongoDB 示例)

import { MongoClient } from "mongodb";

const client = new MongoClient(process.env.MONGODB_URI!);
await client.connect();
const collection = client.db("shop").collection("products");

// Tool:查詢商品庫存
const stockTool: Tool = {
  name: "stock_lookup",
  description: "根據商品名稱查詢即時庫存。輸入格式:商品名稱,例如「MacBook Pro」",
  func: async (input: string) => {
    const product = await collection.findOne({ name: { $regex: input, $options: "i" } });
    if (!product) return `找不到「${input}」的商品。`;
    return `商品「${product.name}」目前庫存 ${product.stock} 件。`;
  },
};

// 加入 Agent
const agentFull = await initializeAgentExecutorWithOptions(
  [weatherTool, mathTool, stockTool],
  llm,
  { agentType: "chat-zero-shot-react-description", retriever }
);

// 測試查詢庫存
await agentFull.run("我想知道 MacBook Pro 的庫存情況。");

常見陷阱與最佳實踐

陷阱 說明 解決方案
Tool 說明不清楚 LLM 依賴 description 判斷何時使用工具,描述過於模糊會導致錯誤呼叫或不呼叫。 使用具體範例(例如「輸入格式:城市名稱」),並在說明中列出可接受的參數類型。
工具回傳非字串 LangChain 預期 func 回傳 string,若回傳物件會拋錯。 func 內先 JSON.stringify,或自行格式化為文字。
向量檢索成本過高 每次對話都重新建立向量索引會非常慢。 一次性建立索引,並持久化(FAISS.save、Pinecone)後直接載入。
LLM Hallucination(幻覺) 即使加入檢索器,LLM 仍可能產生未根據文件的回應。 使用 RAG with source grounding:在 Prompt 中加入「只使用檢索結果」的指示,或使用 ConversationalRetrievalQAChain 強制引用來源。
安全性問題 允許工具執行任意程式碼(如 eval)可能導致注入攻擊。 嚴格限制工具的執行環境,僅允許白名單函式,並在 func 中加入驗證。
上下文窗口限制 LLM 的 token 上限會被檢索結果與工具回傳佔滿。 摘要檢索結果,或只取最相關的 k 個文件(k 建議 2~5)。

最佳實踐清單

  1. 先定義需求:明確列出 Chatbot 必須支援的外部服務(天氣、庫存、計算等)。
  2. 分離層級:Tool 只負責「資料取得/運算」,LLM 僅負責「自然語言生成」。
  3. 使用 Zero‑Shot‑React Prompt:LangChain 提供的 chat-zero-shot-react-description 已內建「思考 → 決策 → 呼叫工具」的流程,除非有特殊需求,建議直接使用。
  4. 測試每個 Tool:單元測試確保工具在各種輸入下都有正確回傳,避免 LLM 因錯誤結果產生錯誤對話。
  5. 監控與日誌:記錄每次工具呼叫的輸入、輸出與 LLM 回答,方便日後除錯與性能分析。

實際應用場景

場景 需求 可能的 Tool 組合
客服中心 查詢訂單狀態、退貨流程、常見問題 order_lookup(資料庫)、faq_retriever(向量檢索)
行銷助理 產生活動文案、即時分析社群情緒 text_generator(LLM)+ sentiment_analysis(API)
內部知識庫 員工問答、文件搜尋、程式碼範例 doc_retriever(ElasticSearch)+ code_snippet_tool
金融諮詢 股價查詢、風險評估、計算投資回報率 stock_apicalculatorrisk_model
智慧家庭 控制 IoT 裝置、查詢天氣、設定提醒 iot_control(MQTT)、weatherreminder

範例:在客服中心中,使用 order_lookup 直接從 MySQL 取得訂單進度,若找不到則讓 LLM 回覆「抱歉,未找到相關訂單,請確認訂單號碼」;同時結合 faq_retriever,讓 Chatbot 能在同一回應中提供常見問題的參考連結,提升客戶滿意度。


總結

  • LangChain 為 LLM 加上「工具」與「檢索」的雙重能力,讓 Chatbot 從單純的文字生成,變成能即時查詢、執行計算、存取資料的多功能助理。
  • 透過 Tool(明確的 namedescriptionfunc)以及 Retriever(向量或全文檢索),開發者可以快速構建具備 RAG(Retrieval‑Augmented Generation) 的對話系統。
  • 本文提供了 5 個實作範例:天氣查詢、FAISS 檢索、ChatAgent 組合、數學計算、MongoDB 庫存查詢,涵蓋從 API 呼叫到資料庫操作的常見需求。
  • 為避免 Hallucination、上下文爆炸與安全風險,建議遵守 最佳實踐:清晰描述 Tool、一次性建立索引、限制工具執行環境、加入來源引用指示。

掌握了這些概念與技巧後,你就能在 LangChain 上打造 實務導向、可靠且可擴充的 Chatbot,不論是客服、金融、行銷或內部知識庫,都能快速上線,為使用者提供即時、正確且具備行動力的回應。祝開發順利,期待看到你在實戰中發揮創意! 🚀