本文 AI 產出,尚未審核

LangChain 基礎概念 ─ 核心組件介紹:Models、Prompts、Output Parsers、Chains


簡介

LLM(大型語言模型)生成式 AI 越來越普及的今天,如何把模型、提示詞、輸出解析與工作流程有條不紊地串接起來,成為開發者必備的技能。
LangChain 正是一個 以組件化方式 讓開發者快速構建、測試、部署 LLM 應用的框架,它把「模型呼叫」與「業務邏輯」分離,讓程式碼更易維護、測試與重用。

本篇文章聚焦於 LangChain 四大核心組件

  1. Models – 與 LLM(如 OpenAI、Azure、Anthropic 等)互動的抽象層。
  2. Prompts – 系統化管理提示詞的工具,支援模板、變數與動態組合。
  3. Output Parsers – 把模型的文字回應轉成結構化資料(JSON、類別實例等)。
  4. Chains – 把上述組件串成 工作流,支援同步、非同步與條件分支。

掌握這四個概念,就能在 聊天機器人、文件摘要、資料擷取、程式碼生成 等多種場景中,快速組出可運行的原型,甚至直接投入生產環境。


核心概念

1️⃣ Models:統一的模型介面

LangChain 為各大 LLM 提供 統一的介面BaseLanguageModel),開發者只需要換一個模型實例,即可在同一套程式碼上測試不同供應商的效能與成本。

供應商 主要類別 (JS) 特色
OpenAI OpenAI 支援 gpt-3.5-turbogpt-4,可設定 temperaturemaxTokens 等參數。
Azure AzureOpenAI 同步 Azure 訂閱、資源管理,適合企業級部署。
Anthropic ChatAnthropic Claude 系列模型為主,注重安全性與指令遵守。

程式碼範例 1:建立模型實例

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

// 建立一個 OpenAI GPT‑4 的模型物件
const llm = new OpenAI({
  modelName: "gpt-4",          // 使用的模型名稱
  temperature: 0.2,            // 較低的 temperature 讓回應更具確定性
  maxTokens: 1024,             // 單次呼叫最大回傳 token 數
  openAIApiKey: process.env.OPENAI_API_KEY, // 從環境變數讀取金鑰
});

小技巧:在開發階段,把 temperature 設為 00.2,可以減少隨機性,方便除錯;正式上線時再根據需求調高。


2️⃣ Prompts:模板化的提示詞管理

LLM 的表現很大程度上取決於 提示詞(Prompt) 的設計。LangChain 把提示詞抽象成 PromptTemplate,支援變數插值、條件分支與多輪對話。

2️⃣.1 PromptTemplate 基礎

import { PromptTemplate } from "langchain/prompts";

// 建立一個簡單的「問答」模板
const qaPrompt = new PromptTemplate({
  inputVariables: ["question"],          // 需要外部提供的變數名稱
  template: `以下是一段中文說明,請直接回答使用者的問題。
  
說明:
{question}
  
答案:`,
});

使用時只要傳入一個 JavaScript 物件,即可得到完整的提示字串:

const prompt = await qaPrompt.format({ question: "什麼是 LangChain?" });
console.log(prompt);

2️⃣.2 Few‑Shot Prompt(示例提示)

Few‑Shot 能讓模型學習「格式」或「風格」:

import { FewShotPromptTemplate } from "langchain/prompts";

const examples = [
  { input: "台北101的高度?", output: "台北101高 508 公尺。" },
  { input: "什麼是區塊鏈?", output: "區塊鏈是一種去中心化的分散式帳本技術。" },
];

const fewShotPrompt = new FewShotPromptTemplate({
  examplePrompt: new PromptTemplate({
    inputVariables: ["input", "output"],
    template: `問題:{input}\n答案:{output}\n`,
  }),
  prefix: "以下是幾個問題與答案範例,請依照相同格式回答接下來的問題:",
  suffix: "問題:{question}\n答案:",
  inputVariables: ["question"],
  examples,
});

這樣的 Prompt 常用於 資訊抽取、格式化回覆 等需求。


3️⃣ Output Parsers:把文字變成結構化資料

LLM 預設回傳純文字,若要在程式中直接使用結果,往往需要 解析。LangChain 提供多種 BaseOutputParser,最常用的是 StructuredOutputParser(基於 JSON Schema)以及 RegexParser

程式碼範例 2:使用 StructuredOutputParser 產生 JSON

import { StructuredOutputParser } from "langchain/output_parsers";
import { z } from "zod";

// 定義回傳結構(使用 zod 建立 schema)
const weatherSchema = z.object({
  location: z.string().describe("城市或地點名稱"),
  temperature: z.number().describe("攝氏溫度"),
  condition: z.enum(["晴", "雨", "雲", "雪"]).describe("天氣狀況"),
});

// 產生對應的 parser
const parser = StructuredOutputParser.fromZodSchema(weatherSchema);

// 把 parser 的格式說明注入 Prompt
const weatherPrompt = new PromptTemplate({
  inputVariables: ["city"],
  template: `請根據以下城市提供天氣資訊,回傳 JSON,格式必須符合:
{format_instructions}
城市:{city}`,
  partialVariables: {
    format_instructions: parser.getFormatInstructions(),
  },
});

呼叫模型後,直接用 parser 解析:

const prompt = await weatherPrompt.format({ city: "台北" });
const rawResponse = await llm.invoke(prompt);   // rawResponse 為文字
const parsed = await parser.parse(rawResponse); // parsed 為 JavaScript 物件

console.log(parsed);
// => { location: "台北", temperature: 28, condition: "晴" }

注意:若模型回傳的 JSON 有語法錯誤,parse 會拋出例外,建議使用 try / catch 包起來,或在 Prompt 中加入「請勿加入額外說明」的指示。


4️⃣ Chains:把模型、提示、解析串成工作流

單一模型呼叫只能解決「一次性」的需求。實務上,我們常需要 先產生問題、再根據回覆做後續處理,這時 Chain 就派上用場。LangChain 提供 LLMChainSimpleSequentialChainRouterChain 等多種組合方式。

程式碼範例 3:LLMChain + OutputParser

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

// 1. 建立 LLM(同前面的 llm 變數)
const llm = new OpenAI({ modelName: "gpt-3.5-turbo", temperature: 0 });

// 2. 建立 Prompt(使用前面的 weatherPrompt)
const chain = new LLMChain({
  llm,
  prompt: weatherPrompt,
  outputParser: parser, // 直接把 parser 注入 chain
});

// 執行 chain
async function getWeather(city) {
  const result = await chain.run({ city });
  // result 已經是解析後的 JavaScript 物件
  return result;
}

getWeather("高雄").then(console.log);
// => { location: "高雄", temperature: 30, condition: "雨" }

程式碼範例 4:SimpleSequentialChain(多步驟)

假設要先 產生摘要,再 根據摘要產生關鍵字

import { SimpleSequentialChain } from "langchain/chains";
import { PromptTemplate } from "langchain/prompts";

// 步驟 1:摘要 Prompt
const summaryPrompt = new PromptTemplate({
  inputVariables: ["text"],
  template: `請將以下文字摘要成 3 行以內:
{text}`,
});

// 步驟 2:關鍵字 Prompt
const keywordPrompt = new PromptTemplate({
  inputVariables: ["summary"],
  template: `根據以下摘要,列出 5 個關鍵字(以逗號分隔):
{summary}`,
});

// 建立兩個 LLMChain
const summaryChain = new LLMChain({ llm, prompt: summaryPrompt });
const keywordChain = new LLMChain({ llm, prompt: keywordPrompt });

// 用 SimpleSequentialChain 把兩個 Chain 串起來
const workflow = new SimpleSequentialChain({
  chains: [summaryChain, keywordChain],
  verbose: true, // 顯示每一步的輸入/輸出,方便除錯
});

// 執行
const article = `LangChain 是一個 ... (略)`;
workflow.run({ text: article }).then(console.log);
// 輸出範例:關鍵字 => "LangChain, LLM, Prompt, Chain, AI"

程式碼範例 5:RouterChain(條件分支)

如果想根據使用者的意圖切換不同的處理流程,可使用 RouterChain

import { RouterChain } from "langchain/chains";
import { ChatPromptTemplate } from "langchain/prompts";

// 定義意圖判斷 Prompt
const intentPrompt = new ChatPromptTemplate({
  inputVariables: ["query"],
  template: `請判斷以下使用者問題的意圖,回傳一個關鍵字:
1. 天氣查詢
2. 文章摘要
3. 其他

問題:{query}
意圖:`,
});

// 建立三個子 Chain(同前面的 chain)
const weatherChain = /* 前面建立的 LLMChain */;
const summaryChain = /* 前面建立的 LLMChain */;
const fallbackChain = new LLMChain({ llm, prompt: new PromptTemplate({
  inputVariables: ["query"],
  template: `抱歉,我無法理解您的需求。請重新描述。`,
})});

// RouterChain 設定
const router = new RouterChain({
  llm,
  prompt: intentPrompt,
  routes: {
    天氣查詢: weatherChain,
    文章摘要: summaryChain,
    其他: fallbackChain,
  },
});

// 測試
router.run({ query: "台北今天的天氣如何?" }).then(console.log);
// => 會自動走 weatherChain,回傳天氣 JSON

常見陷阱與最佳實踐

常見陷阱 為什麼會發生 建議的解法
Prompt 太長或缺少指示 LLM 可能忽略關鍵資訊,或產生雜訊 使用 PromptTemplate 把變數明確列在 inputVariables,並在模板中加入「請勿加入額外說明」的指示。
Output Parser 失敗 模型回傳不符合 JSON 格式或語法錯誤 在 Prompt 中加入 format_instructions,並使用 try / catch 包住 parser.parse,必要時 重試(可加 temperature=0)。
模型成本失控 maxTokenstemperature 設定不當,導致大量 token 消耗 先在開發環境 限制 maxTokens,使用 streaming 只取需要的部分;部署前再根據需求調整。
Chain 內部錯誤被吞掉 verbose 預設關閉,除錯資訊不顯示 在測試階段開啟 verbose: true,或自行在每個 Chain 前後加 console.log
多模型混用時參數不一致 各模型支援的參數不同(如 stoplogprobs 把模型相關參數抽象成 自訂的設定物件,在建立模型時統一注入。

最佳實踐

  1. 先寫 Prompt 再寫程式:先在 Playground(OpenAI、Claude)驗證提示詞的效果,再搬到 LangChain。
  2. 結構化輸出優先:盡量使用 StructuredOutputParser,避免事後手動正則表達式切割。
  3. 模組化 Chain:把每個功能(摘要、關鍵字、翻譯)封裝成獨立的 LLMChain,再用 SimpleSequentialChainRouterChain 組合。
  4. 測試與 CI:使用 jestmocha 撰寫 單元測試,特別是 parser.parse 的 edge case。
  5. 安全與隱私:在 Prompt 中避免直接輸入機密資訊,必要時先做 脫敏 或使用 Azure OpenAI 的 Private Endpoint

實際應用場景

場景 核心組件組合 範例說明
客服聊天機器人 OpenAI + PromptTemplate + RouterChain + StructuredOutputParser 先判斷使用者是「查訂單」還是「常見問題」,再分別呼叫不同的子 Chain,回傳 JSON 給前端渲染。
文件自動摘要與關鍵字產出 LLMChain(摘要 Prompt) → LLMChain(關鍵字 Prompt) 透過 SimpleSequentialChain 把 PDF 文字先摘要,再產生 SEO 關鍵字,直接寫入資料庫。
程式碼自動生成與測試 OpenAI + FewShotPromptTemplate + RegexParser + Chain 用 Few‑Shot 示範「輸入需求 → 輸出 TypeScript 函式」;用 RegexParser 抓出 function 標頭,並自動寫入測試檔。
金融報表分析 AzureOpenAI + PromptTemplate + StructuredOutputParser + RouterChain 根據使用者查詢的「報表類型」切換不同的分析 Prompt,回傳結構化的數據(如盈虧、成長率)供前端圖表使用。
教育平台自動批改 ChatAnthropic + PromptTemplate + OutputParser + Chain 給學生的答案與評分標準,模型產生「分數」與「改進建議」的 JSON,直接寫回 LMS。

總結

LangChain 以 模型、提示詞、輸出解析、工作流 四大模組化概念,為 LLM 應用提供了 可組合、可測試、可擴充 的開發體驗。

  • Models 讓你輕鬆切換不同供應商;
  • Prompts 把提示詞變成可重用的模板;
  • Output Parsers 把文字變成程式可直接操作的結構化資料;
  • Chains 則把上述所有元件串成完整的業務流程。

在實務開發時,建議先 設計 Prompt、定義輸出 Schema,再逐步把模型、解析器、Chain 組起來,最後加入 錯誤處理與日誌,即可打造出 穩定、可維護、成本可控 的生成式 AI 服務。

掌握這四個核心組件,你就能在 聊天機器人、文件處理、程式碼生成、數據分析 等多元領域,快速驗證概念、迭代產品,並將 AI 能力無縫嵌入現有系統。祝你玩得開心、寫得順利! 🚀