本文 AI 產出,尚未審核

LangChain 教學:Chains 中的 Sequential ChainPipeline


簡介

在 LLM(大型語言模型)應用中,單一模型往往只能完成一小段任務,例如產生文字、回答問題或做簡單的資料轉換。Chain 的概念則是把多個模型或工具「串接」起來,形成一條完整的工作流程,讓複雜的需求可以一步步被拆解與執行。

本單元聚焦於 Sequential Chain(順序鏈)與 Pipeline(管線)兩種最常見的串接方式。它們不僅能讓程式碼結構更清晰,也方便在不同階段加入自訂邏輯、錯誤處理或快取機制。對於想要把 LLM 融入實務系統的開發者來說,掌握這兩種模式是邁向可維護、可擴充 AI 服務的第一步。


核心概念

1. Sequential Chain(順序鏈)

Sequential Chain 是最直觀的「先 A 後 B」流程。每一個子鏈(Chain)會接收前一個子鏈的輸出,作為自己的輸入,依序執行下去。

  • 特點

    • 線性:執行順序固定,除非手動跳過或提前終止。
    • 資料流明確:前後鏈的輸入/輸出都是字典({key: value}),易於追蹤。
    • 可組合:任意 ChainToolLLM 都可以放進同一條序列。
  • 適用情境

    • 需要先產生問題 → 再檢索相關文件 → 最後生成答案的情境。
    • 多步驟的資料清理 → 轉換 → 生成流程。

程式碼範例 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 提供 SimpleSequentialChainTransformChainRouterChain 等多種管線工具,讓開發者可以:

  • 在每個階段加入自訂的資料處理函式(如正則表達式過濾、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 在實務系統中的威力。

常見陷阱與最佳實踐

常見問題 可能原因 解決方式 / 最佳實踐
輸入/輸出鍵名稱不一致 子鏈的 inputKeyoutputKey 沒對齊,導致找不到變數。 - 在設計每個子鏈時,明確列出 inputVariablesoutputKey
- 使用 console.logdebugChain 觀察中間結果。
LLM 呼叫次數過多 每一步都直接呼叫 LLM,成本高、延遲大。 - 盡可能 合併 Prompt(把多個步驟合成一個 Prompt)。
- 只在需要 外部工具(檢索、計算)時分段。
錯誤未傳遞 子鏈拋出例外卻未被捕獲,導致整條 Chain 中斷。 - 使用 try/catch 包住每個子鏈,或在 SequentialChain 中提供 errorHandler
- 設計 回退(fallback) 策略,例如返回預設回應。
資料量過大 某一步把整個文件傳給 LLM,超過 token 上限。 - 在 前置處理 階段加入 摘要切片(chunking)機制。
- 使用向量檢索挑選最相關的片段。
路由條件過於簡單 RouterChain 的判斷邏輯漏掉某些情況,導致錯誤分流。 - 建立 測試用例,覆蓋常見關鍵字與語意變體。
- 若條件複雜,可考慮使用 小型分類模型 代替正則表達式。

最佳實踐小結

  1. 統一鍵名:所有子鏈的 inputVariablesoutputKey 必須明確、前後一致。
  2. 最小化 LLM 呼叫:把可以在本地完成的前處理(正則、JSON 解析)放在 TransformChain
  3. 加入快取:對於相同的查詢或檔案檢索結果,使用 MemoryCache 或 Redis 快取,降低重複呼叫。
  4. 錯誤容忍:每個子鏈都應該提供 預設回應重試機制,避免單點失效。
  5. 監控與日誌:在每一步加入 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 ChainPipeline,並能依照不同的業務需求,快速構建出可擴充、可靠的 LLM 工作流。祝你在 AI 應用開發的路上越走越順! 🚀