本文 AI 產出,尚未審核

LangChain 課程 – Prompts:提示工程

Few‑Shot Prompting 與範例注入


簡介

在 LLM(大型語言模型)日益普及的今天,提示工程(Prompt Engineering) 成為讓模型發揮最大效能的關鍵技巧。
其中 Few‑Shot Prompting(少量示例提示)與 範例注入(Example Injection)是最常見、也最實用的兩種手法。透過在提示中加入少量具代表性的範例,我們可以在不調整模型參數的情況下,引導模型產出更符合需求的回應,提升準確度與一致性。

本單元將說明 Few‑Shot Prompting 的原理、在 LangChain 中的實作方式,並提供多個 實用範例,協助讀者快速在自己的應用中加入範例注入的技巧。


核心概念

1. Few‑Shot Prompting 是什麼?

Few‑Shot Prompting 指的是在一次請求(single API call)中,於提示文字(prompt)裡 示範 幾個輸入與期望輸出的配對,讓模型「從示例中學習」如何回應新問題。
相較於 Zero‑Shot(完全不給範例)或 One‑Shot(只給一個範例),Few‑Shot 能在保持請求成本不變的前提下,顯著提升模型的正確率與穩定性。

關鍵要點

  • 範例越具代表性,模型的表現通常越好。
  • 範例數量不宜過多(一般 2~5 個),過長的提示會消耗更多 token,增加成本與回應延遲。

2. 範例注入(Example Injection)的實作方式

在 LangChain(包括 Python 與 JavaScript 版)中,我們可以透過 PromptTemplateFewShotPromptTemplate 或自訂的 PromptTemplate 來完成範例注入。
下面以 LangChainJS(JavaScript)為例,說明三種常見寫法:

寫法 說明
PromptTemplate + 手動拼接範例 最直接的方式,適合範例數量固定且簡單的情況。
FewShotPromptTemplate(內建) LangChain 已提供的類別,會自動把範例插入 example_prompt 中。
DynamicFewShotPromptTemplate(自訂) 需要根據不同任務動態產生範例時使用。

程式碼範例

以下範例均使用 Node.js + LangChainJS@langchain/core@langchain/openai),請先確保已安裝相關套件:

npm install @langchain/core @langchain/openai

範例 1️⃣:使用 PromptTemplate 手動拼接 Few‑Shot

import { PromptTemplate } from "@langchain/core/prompts";
import { OpenAI } from "@langchain/openai";

// 1. 定義少量範例(每個範例都是「問題 + 回答」的配對)
const examples = [
  {
    q: "台北的天氣如何?",
    a: "今天台北的天氣是晴,最高溫 28°C,最低溫 20°C。"
  },
  {
    q: "今天台北有雨嗎?",
    a: "今天台北局部有短暫陣雨,請隨身攜帶雨具。"
  }
];

// 2. 把範例拼成字串,使用「---」作為分隔線,方便模型辨識
const exampleString = examples
  .map(e => `Q: ${e.q}\nA: ${e.a}`)
  .join("\n---\n");

// 3. 建立 PromptTemplate,將範例字串與使用者問題結合
const template = `以下是一些天氣查詢的範例:
${exampleString}

現在請根據上述範例回答以下問題:
Q: {question}
A:`;

// 4. 建立 PromptTemplate 物件
const prompt = new PromptTemplate({
  template,
  inputVariables: ["question"]
});

// 5. 呼叫 LLM
const llm = new OpenAI({ temperature: 0 });
const chain = prompt.pipe(llm);

const response = await chain.invoke({ question: "明天台北會下雨嗎?" });
console.log(response);

說明

  • exampleString 把範例直接寫入提示,適合範例不變的情境。
  • 使用 temperature: 0 可以讓回應更 deterministic(確定性),減少雜訊。

範例 2️⃣:使用內建 FewShotPromptTemplate

import { FewShotPromptTemplate, PromptTemplate } from "@langchain/core/prompts";
import { OpenAI } from "@langchain/openai";

// 1. 單一範例的格式(example_prompt)
//   這裡只定義「問」與「答」的樣式,實際內容會在 later 注入
const examplePrompt = PromptTemplate.fromTemplate("Q: {input}\nA: {output}");

// 2. Few‑Shot PromptTemplate 本體
const fewShotPrompt = new FewShotPromptTemplate({
  // 範例資料(可自行增減)
  examples: [
    { input: "台北今天的最高溫是多少?", output: "最高溫 28°C。" },
    { input: "台北今天會下雨嗎?", output: "會有局部短暫陣雨。" }
  ],
  examplePrompt, // 前面定義的樣式
  prefix: "以下是關於台北天氣的問答範例:",
  suffix: "\n現在請回答以下問題:\nQ: {question}\nA:",
  inputVariables: ["question"]
});

// 3. 建立 LLM
const llm = new OpenAI({ temperature: 0 });
const chain = fewShotPrompt.pipe(llm);

// 4. 呼叫
const answer = await chain.invoke({ question: "今天台北的最低溫是多少?" });
console.log(answer);

說明

  • FewShotPromptTemplate 會自動把 examplesexamplePrompt 產生的格式插入 prefixsuffix 中。
  • 只要調整 examples 陣列,即可快速重用此模板。

範例 3️⃣:動態產生範例(Dynamic Few‑Shot)

有時候範例需要根據使用者的上下文動態生成,例如「法律文件」或「程式碼補全」的情境。下面示範如何在每次呼叫前自行組合範例:

import { PromptTemplate } from "@langchain/core/prompts";
import { OpenAI } from "@langchain/openai";

/**
 * 依據使用者的需求,從資料庫或 API 抓取最近的 3 個相似案例
 */
async function fetchRelevantExamples(query) {
  // 這裡僅示意,實務上會呼叫向量搜尋或資料庫
  const mockDB = [
    { q: "如何在 Python 中讀取 CSV?", a: "使用 pandas.read_csv('file.csv')。" },
    { q: "Node.js 如何寫入檔案?", a: "使用 fs.writeFileSync('path', data)。" },
    { q: "JavaScript 如何去除陣列重複值?", a: "使用 [...new Set(arr)]。" }
  ];
  // 假設簡單回傳全部(實際可根據 query 排序)
  return mockDB;
}

// 主函式
async function runDynamicFewShot(userQuestion) {
  const examples = await fetchRelevantExamples(userQuestion);
  const exampleString = examples
    .map(e => `Q: ${e.q}\nA: ${e.a}`)
    .join("\n---\n");

  const template = `以下是程式相關的問答範例:
${exampleString}

請依照上述範例回答下列問題:
Q: {question}
A:`;

  const prompt = new PromptTemplate({
    template,
    inputVariables: ["question"]
  });

  const llm = new OpenAI({ temperature: 0 });
  const chain = prompt.pipe(llm);

  const result = await chain.invoke({ question: userQuestion });
  console.log(result);
}

// 測試
runDynamicFewShot("JavaScript 如何將字串轉成日期?");

說明

  • fetchRelevantExamples 可以換成向量搜尋(如 Pinecone、FAISS)或資料庫查詢,讓範例更貼近使用者需求。
  • 每次呼叫都會重新組裝提示,保持 動態性彈性

範例 4️⃣:結合系統訊息(System Prompt)與 Few‑Shot

在 ChatML(OpenAI Chat Completion)中,我們可以同時提供 systemassistantuser 訊息。以下示範如何把 Few‑Shot 範例放在 system 中,以建立「角色」與「風格」:

import { ChatOpenAI } from "@langchain/openai";
import { ChatPromptTemplate, SystemMessagePromptTemplate, HumanMessagePromptTemplate } from "@langchain/core/prompts";

const examples = [
  { q: "請說明什麼是機器學習?", a: "機器學習是讓電腦透過資料自動學習模式的技術。" },
  { q: "什麼是深度學習?", a: "深度學習是機器學習的分支,使用多層神經網路。" }
];

// 產生系統訊息內的 Few‑Shot
const systemTemplate = `你是一位友善的 AI 老師,以下是你過往的回答範例:
${examples.map(e => `Q: ${e.q}\nA: ${e.a}`).join("\n---\n")}

請依照上述風格回答使用者的問題。`;

const systemMessage = SystemMessagePromptTemplate.fromTemplate(systemTemplate);
const humanMessage = HumanMessagePromptTemplate.fromTemplate("Q: {question}\nA:");

// 建立 Chat Prompt
const chatPrompt = ChatPromptTemplate.fromPromptMessages([systemMessage, humanMessage]);

const llm = new ChatOpenAI({ temperature: 0 });
const chain = chatPrompt.pipe(llm);

// 呼叫
const answer = await chain.invoke({ question: "什麼是自然語言處理?" });
console.log(answer.content);

說明

  • 把範例放在 system 訊息中,可讓模型將範例視為「角色設定」的一部份,對於需要維持固定語氣或風格的應用非常有用。

常見陷阱與最佳實踐

陷阱 可能的影響 解決方式 / 最佳實踐
範例過長 消耗過多 token,導致成本上升、回應被截斷 只保留 2~4 個最具代表性 的範例;使用 --- 或空行分隔,讓模型易於辨識
範例與目標任務不匹配 模型可能「學錯」樣式,產生錯誤答案 確保範例與最終問題在 領域、語氣、格式 上高度相似
忽略溫度參數 高溫度會讓模型產生多樣化但不一致的回應 在 Few‑Shot 場景通常使用 temperature = 00.2,提升可預測性
忘記加入換行或分隔符 模型無法辨識「範例」與「新問題」的邊界 使用 \n---\n、空行或明確的 Q:/A: 標記
一次塞入過多範例(尤其在 Chat API) 超過模型的上下文窗口(如 4k token) 若需要大量範例,考慮 分批向量檢索 先找最相關的幾筆再注入
範例中包含錯誤資訊 模型會直接複製錯誤答案 驗證範例正確性,必要時加入註解說明「此為示範」而非事實

最佳實踐總結

  1. 範例選擇:挑選最具代表性的 2~4 個,且盡量涵蓋不同變體(正向、負向、邏輯變化)。
  2. 格式統一:使用 Q: / A: 或類似的結構化標記,讓模型辨識更簡單。
  3. 控制溫度:在需要精確答案時將 temperature 設為 0,若想要創意產出可適度提升。
  4. 動態範例:結合向量搜尋或資料庫,根據使用者查詢自動挑選最相似的範例,提高相關性。
  5. 測試與迭代:透過 A/B 測試比較不同範例組合的效果,持續優化 Prompt。

實際應用場景

場景 為何適合使用 Few‑Shot 範例實作概念
客服聊天機器人 需要保持語氣一致、快速回答常見問題 把常見問答作為 Few‑Shot,系統訊息中加入角色設定
程式碼補全 / 語法說明 開發者問法多樣,示例能指導模型產生正確語法 從程式碼庫抓取相似片段,動態注入作為範例
醫療諮詢(非診斷) 輸出需要專業且一致的健康資訊 用醫學問答範例建立安全的回應框架
教育平台 需要模型以教師口吻解釋概念,且提供範例答案 在 system prompt 中放入教學範例,確保風格一致
商業報告自動生成 報告格式固定,範例能指導模型產出標準化段落 透過 Few‑Shot 範例示範「摘要 → 結論 → 建議」的結構

案例:在一個線上程式教學平台,我們使用 FewShotPromptTemplate 搭配向量搜尋,每次使用者請求「如何在 JavaScript 中實作 debounce?」時,系統會先從過去的教學內容中找出 3 個最相似的 debounce 範例,注入 Prompt,最終產生的答案不僅正確,且使用了與過往教學相同的語氣與格式,大幅提升使用者的閱讀體驗與信任感。


總結

Few‑Shot Prompting範例注入 是提升 LLM 準確性與一致性的 低成本、易實作 方法。透過 LangChain 的 PromptTemplateFewShotPromptTemplate,開發者只需要:

  1. 挑選 2~4 個高品質範例,保持格式統一。
  2. 組合 範例與使用者問題,注意分隔符與換行。
  3. 控制 溫度與 token 使用,避免超出模型窗口。
  4. 測試 不同範例組合,持續迭代 Prompt。

掌握這些技巧後,無論是客服機器人、程式碼輔助、教育平台或是企業報告自動化,都能快速建置出 高品質、可控 的 AI 服務。未來隨著向量資料庫與自動範例擷取技術的成熟,Few‑Shot Prompting 的效能將更加提升,成為 AI 應用開發者不可或缺的核心能力。祝你在 LangChain 的旅程中玩得開心、寫得順利!