本文 AI 產出,尚未審核

LangChain 課程 – Prompts:提示工程

主題:PromptTemplate 使用方法


簡介

在使用大型語言模型(LLM)時,Prompt(提示) 的寫法直接決定了模型輸出的品質與一致性。隨著應用日益複雜,單純的字串拼接已難以維護,這時 PromptTemplate 便成為 LangChain 中最常用且最強大的工具。

本篇文章將說明什麼是 PromptTemplate、如何在程式碼中建立與管理模板,並提供多個實務範例,讓你能快速上手、避免常見陷阱,進而在聊天機器人、文件摘要、資料擷取等場景中發揮最大效能。


核心概念

1. PromptTemplate 是什麼?

  • PromptTemplate 是一個 可參數化的文字模板,允許你在執行時動態填入變數。
  • 它把 固定的指令文字(系統訊息、格式要求)與 變動的內容(使用者輸入、文件片段)分離,提升 可讀性可維護性重用性
  • LangChain 提供了多種模板類型:PromptTemplate(最基本)、ChatPromptTemplate(適用於多輪對話)以及 FewShotPromptTemplate(支援示例提示)。

2. 基本語法

import { PromptTemplate } from "langchain/prompts";

const template = `你是一位專業的旅遊導遊,請根據以下資訊為使用者規劃三天兩夜的行程。  
地點: {location}  
旅遊偏好: {preference}  
預算: {budget}元`;

const prompt = new PromptTemplate({
  inputVariables: ["location", "preference", "budget"],
  template,
});
  • inputVariables:列出模板中所有 占位變數,LangChain 會在呼叫 format 時檢查是否提供完整。
  • template:實際的文字模板,使用 {variable} 方式標示變數位置。

3. 使用 format 產生最終 Prompt

const filledPrompt = await prompt.format({
  location: "台北",
  preference: "美食與文化",
  budget: 8000,
});
console.log(filledPrompt);

輸出:

你是一位專業的旅遊導遊,請根據以下資訊為使用者規劃三天兩夜的行程。  
地點: 台北  
旅遊偏好: 美食與文化  
預算: 8000元

4. 進階功能

功能 說明 範例
Partial Variables 事先固定某些變數,只在執行時提供其餘部分。 new PromptTemplate({ template, inputVariables, partialVariables: {budget: 5000} })
Template Format 支援 f-stringjinja2 等不同語法。 templateFormat: "jinja2"
Output Parser 結合 BaseOutputParser,直接解析模型回傳的結構化資料。 outputParser: new JsonOutputParser()

程式碼範例

以下提供 五個 常見且實用的範例,涵蓋不同情境與技巧。每段程式碼均附有說明註解,方便初學者快速理解。

範例 1:基本的問答 Prompt

import { PromptTemplate } from "langchain/prompts";

const qaTemplate = new PromptTemplate({
  inputVariables: ["question"],
  template: `以下是一段簡短的說明,請根據說明回答使用者的問題。  
說明: {context}  
問題: {question}
請直接給出答案,避免冗長解釋。`,
});

async function ask(question, context) {
  const prompt = await qaTemplate.format({ question, context });
  // 假設已有 LLM 實例 llm
  const answer = await llm.invoke(prompt);
  return answer;
}

重點:把「說明」與「問題」分開,讓 LLM 能聚焦在核心資訊上。


範例 2:使用 Partial Variables 固定系統角色

import { PromptTemplate } from "langchain/prompts";

const systemPrompt = new PromptTemplate({
  inputVariables: ["user_input"],
  partialVariables: { role: "你是一位友善的程式設計教練" },
  template: `{role}  
使用者: {user_input}
教練:`,
});

const prompt = await systemPrompt.format({ user_input: "什麼是 closure?" });
console.log(prompt);

輸出:

你是一位友善的程式設計教練  
使用者: 什麼是 closure?
教練:

技巧:當角色資訊不會變動時,用 partialVariables 省去每次填入的麻煩。


範例 3:結合 Jinja2 語法的複雜模板

import { PromptTemplate } from "langchain/prompts";

const jinjaTemplate = new PromptTemplate({
  inputVariables: ["items"],
  template: `
{% for item in items %}
- {{item.name}} (價格: {{item.price}}元)
{% endfor %}
請根據上述商品清單,推薦三件最適合預算 1500 元的商品。`,
  templateFormat: "jinja2",
});

const prompt = await jinjaTemplate.format({
  items: [
    { name: "筆記型電腦", price: 30000 },
    { name: "藍牙耳機", price: 1200 },
    { name: "行動電源", price: 800 },
    { name: "鍵盤", price: 1500 },
  ],
});
console.log(prompt);

說明:利用 for 迴圈動態產生清單,適合處理 多筆資料


範例 4:Few‑Shot Prompt(示例提示)

import { FewShotPromptTemplate, PromptTemplate } from "langchain/prompts";

const examplePrompt = new PromptTemplate({
  inputVariables: ["question", "answer"],
  template: `Q: {question}
A: {answer}`,
});

const fewShot = new FewShotPromptTemplate({
  examplePrompt,
  examples: [
    { question: "台北 101 的高度?", answer: "508 公尺" },
    { question: "Python 的創始人是誰?", answer: "Guido van Rossum" },
  ],
  prefix: "以下是一些問答示例,請根據示例回答新問題。",
  suffix: "Q: {input}\nA:",
  inputVariables: ["input"],
});

const prompt = await fewShot.format({ input: "JavaScript 的發明者是誰?" });
console.log(prompt);

產生的 Prompt:

以下是一些問答示例,請根據示例回答新問題。
Q: 台北 101 的高度?
A: 508 公尺
Q: Python 的創始人是誰?
A: Guido van Rossum
Q: JavaScript 的發明者是誰?
A:

效益:提供 示例 能顯著提升模型的正確率,特別是對於 特定格式領域知識


範例 5:結合 Output Parser 直接得到 JSON

import { PromptTemplate } from "langchain/prompts";
import { JsonOutputParser } from "langchain/output_parsers";

const jsonParser = new JsonOutputParser();

const weatherTemplate = new PromptTemplate({
  inputVariables: ["city"],
  template: `請提供 {city} 未來 3 天的天氣預報,回傳格式必須是 JSON,欄位包括 date、high、low、description。`,
  outputParser: jsonParser,
});

async function getWeather(city) {
  const prompt = await weatherTemplate.format({ city });
  const rawResponse = await llm.invoke(prompt); // LLM 回傳文字
  const parsed = await jsonParser.parse(rawResponse);
  return parsed; // 直接得到 JavaScript 物件
}

亮點OutputParser 讓你在取得 LLM 輸出後,立即得到結構化資料,省去自行正則表達式或 JSON.parse 的麻煩。


常見陷阱與最佳實踐

陷阱 說明 解決方案
忘記列出所有變數 inputVariables 與模板不一致時會拋出錯誤。 使用 IDE 或 TypeScript 型別檢查,確保變數名一致。
模板過長導致 token 超限 大型上下文一次性塞入會觸發 token 超過模型上限。 分段 送入模型或使用 Retriever 先篩選相關段落。
變數值未經清理 使用者輸入可能包含特殊字符或換行,導致 Prompt 結構被破壞。 formatsanitize(例如移除多餘的換行、轉義引號)。
示例過多 Few‑Shot Prompt 中示例太多會佔用大量 token,反而降低效能。 僅保留 關鍵 2–3 個 最具代表性的示例。
忽略 Output Parser 直接使用文字回應,需要自行解析,容易出錯。 配合 Parser,讓 LangChain 自動把文字轉成結構化資料。

最佳實踐

  1. 模組化:將常用模板抽成獨立檔案,使用 export const 共享。
  2. 使用 Partial Variables 來固定不變的系統訊息或角色設定。
  3. 加入註解:在模板內使用 #/* */ 標註說明,方便日後維護。
  4. 測試 Prompt:在正式部署前,用單元測試驗證 format 後的字串是否符合預期。
  5. 結合 Retriever:若需要大量文件作為上下文,先用向量搜尋找出最相關的段落,再填入 Prompt。

實際應用場景

場景 PromptTemplate 如何發揮作用
客服聊天機器人 使用 ChatPromptTemplate 搭配 partialVariables 設定「客服角色」與「公司政策」;動態填入使用者問題。
文件摘要 先透過向量檢索取得關鍵段落,然後用 PromptTemplate 把段落與「請摘要」指令組合。
程式碼生成 利用 FewShotPromptTemplate 提供幾個範例函式,讓模型學習風格,再根據使用者需求產生新程式碼。
市場分析報告 結合 JsonOutputParser,讓模型直接回傳結構化的 KPI 數據,省去後續資料清洗。
多語言翻譯 把「目標語言」作為變數,模板固定「請將以下文字翻譯成 {target_lang}」;適用於批次翻譯。

總結

PromptTemplateLangChain 中最基礎且最強大的組件之一,它讓我們能以 結構化、可維護 的方式編寫提示,從而提升大型語言模型的效能與可靠性。透過本文的五個實作範例,你已掌握:

  • 如何建立基本與進階的 PromptTemplate
  • 使用 Partial VariablesJinja2Few‑ShotOutput Parser 等進階功能
  • 常見的錯誤與最佳實踐

只要把 模板化思維 融入日常開發流程,無論是聊天機器人、文件摘要或是自動化報告,都能快速產出高品質的 LLM 輸出。現在就把這些技巧套用到你的專案中,體驗 PromptTemplate 帶來的效能提升吧!祝開發順利 🚀