本文 AI 產出,尚未審核

LangChain 教學:自訂 Chain 與組合

簡介

在 LLM(大型語言模型)應用開發中,Chain 是將多個模型、工具或提示(Prompt)串連起來,形成一條完整工作流程的核心概念。單一模型往往只能完成「問答」或「文字生成」等簡單任務;而真實商業需求常常需要 前置資料處理 → 多步推理 → 後置結果格式化 等多階段操作。

本單元聚焦於 自訂 Chain(自己寫的流程)以及 Chain 的組合(把已有的 Chain 拼湊成更複雜的管線)。掌握這些技巧,你就能把 LangChain 變成「可程式化的 AI 工作流引擎」,快速構建客服機器人、文件摘要系統、資料清洗管線等實務應用。


核心概念

1. Chain 的基本結構

在 LangChain 中,Chain 本質上是一個 invoke(input) 方法的物件,接受輸入、呼叫一或多個 LLM 或工具,最後回傳結果。最簡單的 Chain 只包住一個 LLM:

import { LLMChain } from "langchain/chains";
import { OpenAI } from "langchain/llms/openai";

const llm = new OpenAI({ temperature: 0 });
const chain = new LLMChain({ llm, prompt: "請把以下文字翻成英文:\n{input}" });

const res = await chain.invoke({ input: "今天天氣很好" });
console.log(res);   // "The weather is nice today."
  • LLMChain 只負責 單一次呼叫 LLM,而 prompt 中的 {input} 會在執行時自動被替換。
  • invoke 的回傳值通常是 字串,但也可以自訂返回結構(如 JSON)。

2. 自訂 Chain:繼承 Chain 類別

若需要在 LLM 前後加入額外邏輯(例如資料庫查詢、正則表達式清理),可以自行 繼承 Chain,實作 _call 方法:

import { Chain } from "langchain/chains";

class CleanAndTranslateChain extends Chain {
  constructor({ llm }) {
    super();
    this.llm = llm;
  }

  /** 取得此 Chain 所需的輸入欄位名稱 */
  get inputKeys() {
    return ["rawText"];
  }

  /** 取得此 Chain 輸出的欄位名稱 */
  get outputKeys() {
    return ["translated"];
  }

  /** 真正的執行邏輯 */
  async _call(values) {
    // 1️⃣ 前置清理:移除多餘空白、換行
    const cleaned = values.rawText.replace(/\s+/g, " ").trim();

    // 2️⃣ 呼叫 LLM 產生翻譯
    const prompt = `請把以下中文翻成英文:\n${cleaned}`;
    const response = await this.llm.call(prompt);

    // 3️⃣ 後置處理:確保回傳為單行文字
    const translated = response.trim().replace(/\n/g, " ");

    return { translated };
  }
}

// 使用範例
import { OpenAI } from "langchain/llms/openai";
const llm = new OpenAI({ temperature: 0 });
const myChain = new CleanAndTranslateChain({ llm });

const out = await myChain.invoke({ rawText: "  今   天   \n\n 很   好  " });
console.log(out.translated);   // "Today is great."

重點:自訂 Chain 必須明確宣告 inputKeysoutputKeys,讓 LangChain 在組合時能自動對齊資料流。

3. 組合 Chain:SequentialChain & RouterChain

LangChain 提供兩種常見的組合方式:

組合方式 說明 典型使用情境
SequentialChain 依序執行多個 Chain,前一個的輸出會自動成為下一個的輸入 多步問答、先摘要再翻譯
RouterChain 根據條件(如關鍵字)選擇不同的子 Chain 執行 客服路由、不同領域的專家模型

3.1 SequentialChain 範例

把「摘要 → 翻譯」兩個步驟串成一條流程:

import { SequentialChain } from "langchain/chains";
import { PromptTemplate } from "langchain/prompts";
import { OpenAI } from "langchain/llms/openai";

const llm = new OpenAI({ temperature: 0 });

// Step 1: 摘要
const summaryPrompt = new PromptTemplate({
  template: "請幫我將以下內容做 3 點重點摘要:\n{input}",
  inputVariables: ["input"],
});
const summaryChain = new LLMChain({ llm, prompt: summaryPrompt });

// Step 2: 翻譯
const translatePrompt = new PromptTemplate({
  template: "請把以下中文摘要翻成英文:\n{summary}",
  inputVariables: ["summary"],
});
const translateChain = new LLMChain({ llm, prompt: translatePrompt });

// 串接
const workflow = new SequentialChain({
  chains: [summaryChain, translateChain],
  inputVariables: ["input"],
  // 最後的輸出鍵會自動合併成 { summary, translated }
  outputVariables: ["summary", "translated"],
});

const result = await workflow.invoke({
  input: "LangChain 是一個用於建構 LLM 應用的框架,提供 Chain、Agent、Tool 等概念。..."
});
console.log(result.translated);

3.2 RouterChain 範例

根據使用者輸入的主題自動切換不同的專家模型:

import { RouterChain } from "langchain/chains";
import { OpenAI } from "langchain/llms/openai";

const llm = new OpenAI({ temperature: 0 });

const financeChain = new LLMChain({
  llm,
  prompt: "你是金融專家,請回答以下問題:\n{question}",
});
const techChain = new LLMChain({
  llm,
  prompt: "你是科技專家,請回答以下問題:\n{question}",
});

// 路由條件函式:回傳欲使用的 chain 名稱
function routeFn(values) {
  const q = values.question.toLowerCase();
  if (q.includes("股票") || q.includes("投資")) return "finance";
  if (q.includes("程式") || q.includes("AI")) return "tech";
  return "default";
}

const router = new RouterChain({
  routes: {
    finance: financeChain,
    tech: techChain,
    default: new LLMChain({
      llm,
      prompt: "請一般性回答以下問題:\n{question}",
    }),
  },
  defaultRoute: "default",
  routeFn,
});

const ans = await router.invoke({
  question: "請問近期 AI 產業的趨勢如何?",
});
console.log(ans.text);

4. 讓 Chain 可重用:RunnableSerializable

LangChain 2.x 引入 Runnable 概念,使 Chain 更像「函式」可直接 pipemapbatch。以下示範如何把自訂 Chain 包裝成 Runnable,並在批次任務中使用:

import { RunnableSequence } from "langchain/schema/runnable";
import { OpenAI } from "langchain/llms/openai";

const llm = new OpenAI({ temperature: 0 });

// 先建立兩個 Runnable:清理 + LLM
const clean = RunnableSequence.from(async (input) => {
  return input.replace(/\s+/g, " ").trim();
});
const translate = RunnableSequence.from(async (text) => {
  const prompt = `請把以下中文翻成英文:\n${text}`;
  return await llm.call(prompt);
});

// 組合成完整流水線
const pipeline = clean.pipe(translate);

// 批次執行
const inputs = [
  "  今   天   \n很好  ",
  "  明天  \n會下雨  ",
];
const outputs = await Promise.all(inputs.map(pipeline.invoke));
console.log(outputs);

常見陷阱與最佳實踐

陷阱 為什麼會發生 解決方式
忘記宣告 inputKeys / outputKeys 自訂 Chain 無法與其他 Chain 自動對接 必寫 兩個 getter,或直接繼承 BaseChain 使用 BaseChain.inputKeys
LLM 呼叫過於頻繁 SequentialChain 中每一步都呼叫 LLM,成本飆升 把可以在本地完成的前置處理(正則、分詞)搬到 Python/Node 前端
回傳結構不一致 後續 Chain 期待 {summary} 卻收到 {text} 統一使用 JSON Schema,或在自訂 Chain 中 return { key: value }
Prompt 複雜度過高 長 Prompt 會導致 token 超限或回應不穩定 使用 Few‑Shot 範例、PromptTemplate 變數化,必要時分段呼叫
未設定 timeout LLM 服務偶爾卡住導致整條流程卡死 為每個 llm.call 加上 timeout、重試機制(retry

最佳實踐

  1. 最小化 LLM 次數:先在程式內完成清理、抽取,再交給 LLM。
  2. 使用 PromptTemplate:把變數抽離,讓 Prompt 可重用、易維護。
  3. 加入日誌(logging):在每個 Chain 前後打印 inputoutput,方便除錯。
  4. 測試每個子 Chain:利用 Jest / Mocha 為自訂 Chain 撰寫單元測試,確保資料流正確。
  5. 設定 maxTokenstemperature:根據需求調整,避免產生過長或過於隨機的回應。

實際應用場景

場景 需要的 Chain 為什麼適合自訂/組合
客服自動回覆 RouterChain(根據問題類別切換) + SequentialChain(先搜尋 FAQ → 再生成回覆) 可快速擴充新領域,只要新增對應子 Chain 即可
法律文件摘要與關鍵條款抽取 SequentialChain(摘要 → 關鍵詞抽取 → JSON 格式化) 多步驟必須保持上下文,Chain 保證資料流不遺失
多語言商品說明產生 CleanAndTranslateChain(清理) → LLMChain(生成) → RouterChain(依語言路由) 前置清理提升翻譯品質,路由讓不同語言使用不同模型或 prompt
資料科學報告自動化 SequentialChain(資料前處理 → 圖表生成工具 → LLM 報告撰寫) 結合外部工具(如 matplotlib)與 LLM,Chain 把非 AI 步驟包起來

總結

自訂 Chain 與 Chain 組合是 LangChain 中最具彈性、最能發揮 LLM 潛力的功能。透過 繼承 Chain、明確宣告輸入/輸出鍵,我們可以把任何前置或後置邏輯封裝成可重用的模組;再利用 SequentialChainRouterChainRunnable 等組合工具,將這些模組拼湊成完整的 AI 工作流。

在實務開發時,記得 減少不必要的 LLM 呼叫、保持 Prompt 可維護、加入日誌與測試,即可建立高效、可靠且易於擴充的 AI 服務。未來隨著模型與工具的演進,這套「Chain 思維」將成為打造智慧應用的基礎建築,值得每位開發者深入掌握。祝你玩得開心,打造出令人驚豔的 LangChain 應用!