本文 AI 產出,尚未審核
LangChain 教學:Chains 中的 Sequential Chain 與 Pipeline
簡介
在 LLM(大型語言模型)應用中,單一模型往往只能完成一小段任務,例如產生文字、回答問題或做簡單的資料轉換。Chain 的概念則是把多個模型或工具「串接」起來,形成一條完整的工作流程,讓複雜的需求可以一步步被拆解與執行。
本單元聚焦於 Sequential Chain(順序鏈)與 Pipeline(管線)兩種最常見的串接方式。它們不僅能讓程式碼結構更清晰,也方便在不同階段加入自訂邏輯、錯誤處理或快取機制。對於想要把 LLM 融入實務系統的開發者來說,掌握這兩種模式是邁向可維護、可擴充 AI 服務的第一步。
核心概念
1. Sequential Chain(順序鏈)
Sequential Chain 是最直觀的「先 A 後 B」流程。每一個子鏈(Chain)會接收前一個子鏈的輸出,作為自己的輸入,依序執行下去。
特點
- 線性:執行順序固定,除非手動跳過或提前終止。
- 資料流明確:前後鏈的輸入/輸出都是字典(
{key: value}),易於追蹤。 - 可組合:任意
Chain、Tool、LLM都可以放進同一條序列。
適用情境
- 需要先產生問題 → 再檢索相關文件 → 最後生成答案的情境。
- 多步驟的資料清理 → 轉換 → 生成流程。
程式碼範例 1:簡單的兩步驟問答
import { OpenAI } from "langchain/llms/openai";
import { LLMChain } from "langchain/chains";
import { PromptTemplate } from "langchain/prompts";
import { SequentialChain } from "langchain/chains/sequential";
// 1. 產生搜尋關鍵字的 Prompt
const keywordPrompt = PromptTemplate.fromTemplate(
"請從以下問題中抽取最關鍵的搜尋關鍵字:\n問題:{question}"
);
const keywordChain = new LLMChain({
llm: new OpenAI({ temperature: 0 }),
prompt: keywordPrompt,
outputKey: "keyword",
});
// 2. 用關鍵字產生答案的 Prompt
const answerPrompt = PromptTemplate.fromTemplate(
"根據關鍵字 {keyword},請提供一段簡潔的答案。"
);
const answerChain = new LLMChain({
llm: new OpenAI({ temperature: 0.7 }),
prompt: answerPrompt,
outputKey: "answer",
});
// 3. 組成 SequentialChain
const qaChain = new SequentialChain({
chains: [keywordChain, answerChain],
inputVariables: ["question"],
// 最終輸出會包含兩個 key
// { keyword: "...", answer: "..." }
});
const result = await qaChain.run({ question: "什麼是量子糾纏?" });
console.log(result);
說明:
keywordChain先把使用者問題轉成關鍵字,輸出 key 為keyword。answerChain直接使用前一步的keyword產生答案。SequentialChain把兩個子鏈串起來,最終一次呼叫即可完成完整流程。
2. Pipeline(管線)
Pipeline 與 Sequential Chain 的概念相近,但更強調「資料在不同階段的轉換」與平行處理的可能性。LangChain 提供 SimpleSequentialChain、TransformChain、RouterChain 等多種管線工具,讓開發者可以:
- 在每個階段加入自訂的資料處理函式(如正則表達式過濾、JSON 解析)。
- 動態決定下一步要走哪條路(Router)。
- 在同一層級同時執行多個子鏈(ParallelChain,雖然在 JavaScript SDK 中較少使用,但概念相同)。
程式碼範例 2:使用 TransformChain 進行前處理與後處理
import { OpenAI } from "langchain/llms/openai";
import { LLMChain } from "langchain/chains";
import { PromptTemplate } from "langchain/prompts";
import { TransformChain } from "langchain/chains/transform";
// 1. 前處理:把使用者輸入的繁體中文轉成簡體中文(示範用)
const toSimplified = async (input) => {
// 假設有一個簡易的轉換函式
const map = { "繁": "繁", "體": "体", "中": "中", "文": "文" };
const simplified = input.replace(/[繁體中文]/g, (c) => map[c] || c);
return { simplified };
};
// 2. LLM 產生回應(仍使用繁體提示)
const prompt = PromptTemplate.fromTemplate(
"請用繁體中文回答以下問題:\n{question}"
);
const llmChain = new LLMChain({
llm: new OpenAI({ temperature: 0.6 }),
prompt,
outputKey: "response",
});
// 3. 後處理:把 LLM 回傳的文字再轉回繁體(示範用)
const toTraditional = async ({ response }) => {
const map = { "繁": "繁", "体": "體", "中": "中", "文": "文" };
const traditional = response.replace(/[繁體中文]/g, (c) => map[c] || c);
return { finalAnswer: traditional };
};
// 4. 組成 Pipeline
const pipeline = new TransformChain({
inputVariables: ["question"],
// 前處理 → LLM → 後處理
transforms: [
{ chain: toSimplified }, // 會把 {question} 轉成 {simplified}
{ chain: llmChain, inputKey: "simplified", outputKey: "response" },
{ chain: toTraditional },
],
});
const out = await pipeline.run({ question: "請說明什麼是機器學習。" });
console.log(out.finalAnswer);
說明:
TransformChain允許在每一步自行定義 同步或非同步 的轉換函式。- 這種寫法適合需要 資料清理、格式轉換 或 多語言切換 的情境。
程式碼範例 3:RouterChain 依條件分流
import { OpenAI } from "langchain/llms/openai";
import { LLMChain } from "langchain/chains";
import { PromptTemplate } from "langchain/prompts";
import { RouterChain } from "langchain/chains/router";
// 兩個不同的 LLMChain:一個負責一般問答,一個負責程式碼生成
const qaPrompt = PromptTemplate.fromTemplate(
"請用簡潔的中文回答:\n{question}"
);
const codePrompt = PromptTemplate.fromTemplate(
"請產生符合以下需求的 Python 程式碼:\n{question}"
);
const qaChain = new LLMChain({ llm: new OpenAI({ temperature: 0 }), prompt: qaPrompt });
const codeChain = new LLMChain({ llm: new OpenAI({ temperature: 0.3 }), prompt: codePrompt });
// Router 的判斷邏輯(簡易版):如果問題含有「寫程式」字樣就走 codeChain
const router = new RouterChain({
router: async ({ question }) => {
if (/寫程式|程式碼|Python/.test(question)) {
return { destination: "code", nextInputs: { question } };
}
return { destination: "qa", nextInputs: { question } };
},
destinations: {
qa: qaChain,
code: codeChain,
},
});
const result1 = await router.run({ question: "什麼是深度學習?" });
console.log("QA:", result1);
const result2 = await router.run({ question: "寫程式,幫我產生一段讀檔的 Python 代碼。" });
console.log("CODE:", result2);
說明:
RouterChain先根據自訂的條件判斷要走哪條路線,然後把輸入傳給對應的子鏈。- 這樣的設計讓 單一入口 能夠處理多種需求,提升使用者體驗。
程式碼範例 4:結合檔案檢索與 LLM 的完整管線
import { OpenAI } from "langchain/llms/openai";
import { LLMChain } from "langchain/chains";
import { PromptTemplate } from "langchain/prompts";
import { SequentialChain } from "langchain/chains/sequential";
import { VectorStoreRetriever } from "langchain/vectorstores";
// 假設已經有一個向量資料庫:
const retriever = new VectorStoreRetriever({ /* 初始化參數 */ });
// 1. 從使用者問題取得相關文件
const retrievalPrompt = PromptTemplate.fromTemplate(
"請根據以下文件摘要回答問題:\n文件:{documents}\n問題:{question}"
);
const retrievalChain = new LLMChain({
llm: new OpenAI({ temperature: 0 }),
prompt: retrievalPrompt,
outputKey: "answer",
});
// 2. 主流程:檢索 → 產生答案
const qaPipeline = new SequentialChain({
chains: [
// 先執行檢索,回傳 documents
{
// 這裡直接用 async function 包裝檢索步驟
async run({ question }) {
const docs = await retriever.getRelevantDocuments(question);
const docTexts = docs.map(d => d.pageContent).join("\n---\n");
return { documents: docTexts };
},
},
retrievalChain,
],
inputVariables: ["question"],
});
const final = await qaPipeline.run({ question: "什麼是 LangChain 的 Chains?" });
console.log(final.answer);
說明:
- 先用向量檢索取得相關文件,再把文件與問題一起交給 LLM。
- 這是一個 典型的 RAG(Retrieval Augmented Generation) 工作流,展示了 Sequential Chain 在實務系統中的威力。
常見陷阱與最佳實踐
| 常見問題 | 可能原因 | 解決方式 / 最佳實踐 |
|---|---|---|
| 輸入/輸出鍵名稱不一致 | 子鏈的 inputKey、outputKey 沒對齊,導致找不到變數。 |
- 在設計每個子鏈時,明確列出 inputVariables 與 outputKey。- 使用 console.log 或 debugChain 觀察中間結果。 |
| LLM 呼叫次數過多 | 每一步都直接呼叫 LLM,成本高、延遲大。 | - 盡可能 合併 Prompt(把多個步驟合成一個 Prompt)。 - 只在需要 外部工具(檢索、計算)時分段。 |
| 錯誤未傳遞 | 子鏈拋出例外卻未被捕獲,導致整條 Chain 中斷。 | - 使用 try/catch 包住每個子鏈,或在 SequentialChain 中提供 errorHandler。- 設計 回退(fallback) 策略,例如返回預設回應。 |
| 資料量過大 | 某一步把整個文件傳給 LLM,超過 token 上限。 | - 在 前置處理 階段加入 摘要 或 切片(chunking)機制。 - 使用向量檢索挑選最相關的片段。 |
| 路由條件過於簡單 | RouterChain 的判斷邏輯漏掉某些情況,導致錯誤分流。 | - 建立 測試用例,覆蓋常見關鍵字與語意變體。 - 若條件複雜,可考慮使用 小型分類模型 代替正則表達式。 |
最佳實踐小結
- 統一鍵名:所有子鏈的
inputVariables與outputKey必須明確、前後一致。 - 最小化 LLM 呼叫:把可以在本地完成的前處理(正則、JSON 解析)放在
TransformChain。 - 加入快取:對於相同的查詢或檔案檢索結果,使用
MemoryCache或 Redis 快取,降低重複呼叫。 - 錯誤容忍:每個子鏈都應該提供 預設回應 或 重試機制,避免單點失效。
- 監控與日誌:在每一步加入
console.log或自訂 logger,方便事後排查與效能分析。
實際應用場景
| 場景 | 使用哪種 Chain | 為什麼適合 |
|---|---|---|
| 客服機器人:先辨識意圖 → 從知識庫檢索 → 產生回覆 | SequentialChain + Retrieval | 需求明確且線性,前置檢索能減少 LLM 負擔。 |
| 程式碼輔助 IDE:偵測語言 → 呼叫不同模型(自然語言 vs 程式碼) → 回傳建議 | RouterChain | 根據使用者輸入自動分流,提升正確率。 |
| 多語言文件翻譯:檢測語言 → 前置清理 → LLM 翻譯 → 後置校對 | TransformChain + SequentialChain | 每一步都有明確的資料轉換需求。 |
| 金融報告自動生成:抓取財務數據 → 數據正規化 → LLM 撰寫報告 → 加入圖表說明 | Pipeline(多階段) | 需要大量前處理與後處理,且每階段可獨立測試。 |
| 教育平台的自適應測驗:根據學生答題結果 → 選擇難度 → 產生新題目 → 給予即時回饋 | RouterChain + SequentialChain | 動態決策與連續生成的結合。 |
總結
- Sequential Chain 為最基礎的「一步接一步」流程,適合 線性、可預測 的任務。
- Pipeline(Transform / Router / Parallel) 提供更彈性的資料轉換與路由能力,讓開發者可以在同一條工作流中混合 前處理、檢索、模型呼叫、後處理 等多種操作。
- 在實務開發時,先規劃好資料鍵名、錯誤處理與快取策略,再根據需求選擇最合適的 Chain 組合,能顯著降低成本、提升效能與維護性。
透過本篇教學,你已掌握如何在 LangChain 中使用 Sequential Chain 與 Pipeline,並能依照不同的業務需求,快速構建出可擴充、可靠的 LLM 工作流。祝你在 AI 應用開發的路上越走越順! 🚀