在昨天的實作中,我們已經學會如何使用 LangChain 建立基本的 LLM 應用程式,並將原本基於 OpenAI SDK 實作的 CLI 聊天機器人,重構為以 LangChain 為基礎的版本。今天,我們要更進一步,介紹 LangChain 提供的 提示模板(Prompt Templates) 功能。
提示模板是 LangChain 的核心概念之一。它能將動態輸入參數與靜態提示內容分開管理,使提示的設計更乾淨、可重複利用且更容易維護,並幫助我們開發 LLM 應用程式更具靈活性與延展性。
在與大型語言模型互動的過程中,提示詞(Prompt)扮演了關鍵的角色。你可以把它想像成我們對 AI 下的一段「指令腳本」,用來明確告訴模型:
在最單純的情況下,我們可能會這樣撰寫一個 prompt:
const prompt = `請扮演一位 AI 助理,回答使用者問題:${userInput}`;
這樣的寫法雖然能正常運作,但隨著應用逐漸複雜,就會出現一些問題:
為了解決這些痛點,LangChain 提供了 提示模板(Prompt Templates)。這個功能內建於 @langchain/core
套件,可以將提示「函式化」:先定義好模板結構,再透過變數控制內容。
使用提示模板的好處包括:
提示模板是 LangChain 應用中非常重要的基礎工具之一。接下來,我們會實際操作這個工具,幫助你快速上手。
PromptTemplate
:文字提示模板在開發 LLM 應用時,提示詞(Prompt)的設計往往決定了模型回應的品質。我們經常需要針對不同情境調整提示內容,例如帶入使用者的問題、指定回答的語氣,或替換成特定的產品名稱。若僅依賴手動字串拼接,不但容易出錯,也會讓程式碼顯得冗長難維護。
這時候就能善用 LangChain 提供的 PromptTemplate
。它是一種直觀的字串模板工具,可以將提示定義成帶有變數欄位的樣板,並在執行階段自動填入實際值。這樣不僅讓提示設計更結構化,也能在不同場景下重複使用,特別適合用在聊天格式的需求,例如單句任務指令、文字生成,或需要輸出為純文字提示的情境。
首先,從 @langchain/core/prompts
匯入 PromptTemplate
:
import { PromptTemplate } from '@langchain/core/prompts';
接著,我們可以使用 new PromptTemplate()
明確定義提示的結構與需要帶入的變數:
const prompt = new PromptTemplate({
template: '請以 {tone} 的語氣,幫我寫一篇推薦 {product} 的文案。',
inputVariables: ['tone', 'product'],
});
在這個例子中:
template
代表提示的文字內容,並透過 {tone}
和 {product}
定義可替換的變數位置。inputVariables
用來宣告模板中有哪些變數必須在執行階段提供。PromptTemplate.fromTemplate()
如果模板內已經明確標示出 {}
裡的變數名稱,LangChain 也提供了更簡潔的靜態方法 fromTemplate()
。它會自動解析出變數名稱,不需要再手動列出 inputVariables
:
const prompt = PromptTemplate.fromTemplate(
'請用 {tone} 的語氣,幫我寫一篇推薦 {product} 的文案。'
);
在這個例子中,fromTemplate()
會自動偵測到需要的變數為 tone
與 product
。對於簡單場景來說,這種寫法更直觀,也能讓程式碼更簡潔。
建立好模板後,我們可以使用 format()
方法來填入變數,產生完整的提示語:
const formatted = await prompt.format({
tone: '幽默',
product: '全自動咖啡機',
});
console.log(formatted);
// 輸出:請用 幽默 的語氣,幫我寫一篇推薦 全自動咖啡機 的文案。
這樣,我們就能根據不同輸入,動態產生格式一致的提示語,讓 AI 回應更穩定、指令更一致。
ChatPromptTemplate
:聊天訊息模板當我們與聊天模型(Chat Models)互動時,模型接收的並不是單一長字串,而是結構化的多段訊息,常見角色包含:
為了方便管理這些訊息並支援動態變數插入,LangChain 提供了專門用於聊天場景的模板工具 ChatPromptTemplate
。它能幫助我們建立「多段式提示語」,依照不同情境填入內容,最後產生格式正確的輸入給聊天模型使用。
LangChain 提供了不同類型的 MessagePromptTemplate
類別,可以用來組合聊天內容:
SystemMessagePromptTemplate
:用來設定 AI 的角色與行為規則。HumanMessagePromptTemplate
:表示使用者的輸入。AIMessagePromptTemplate
:表示 AI 過去的回覆。你可以使用這些元件組合出一個有結構的聊天提示。例如:
import {
ChatPromptTemplate,
SystemMessagePromptTemplate,
HumanMessagePromptTemplate,
AIMessagePromptTemplate,
} from '@langchain/core/prompts';
const chatPrompt = new ChatPromptTemplate({
promptMessages: [
SystemMessagePromptTemplate.fromTemplate('你是一位 {role},請用 {style} 的語氣回答。'),
HumanMessagePromptTemplate.fromTemplate('{question}'),
AIMessagePromptTemplate.fromTemplate('好的,我了解了,我會依照你的需求回答。'),
],
inputVariables: ['role', 'style', 'question'],
});
在這個例子中,我們建立了一組聊天訊息模板,裡面包含三個角色的訊息,並保留 role
、style
、question
這三個變數,讓我們在執行時再填入實際值。
ChatPromptTemplate.fromMessages()
除了使用建構式明確指定變數外,LangChain 也提供 ChatPromptTemplate.fromMessages()
這個簡化方式,讓你直接以陣列方式建立多段訊息模板:
import {
ChatPromptTemplate,
SystemMessagePromptTemplate,
HumanMessagePromptTemplate,
AIMessagePromptTemplate,
} from '@langchain/core/prompts';
const chatPrompt = ChatPromptTemplate.fromMessages([
SystemMessagePromptTemplate.fromTemplate('你是一位 {role},請用 {style} 的語氣回答。'),
HumanMessagePromptTemplate.fromTemplate('{question}'),
AIMessagePromptTemplate.fromTemplate('好的,我了解了,我會依照你的需求回答。'),
]);
這種寫法不需要手動列出 inputVariables
,LangChain 會自動解析模板中 {}
內的變數名稱。
如果想進一步縮短程式碼,也可以直接使用角色名稱搭配字串的形式:
const chatPrompt = ChatPromptTemplate.fromMessages([
['system', '你是一位 {role},請用 {style} 的語氣回答。'],
['human', '{question}'],
['ai', '好的,我了解了,我會依照你的需求回答。'],
]);
這種寫法直接用陣列表示角色與內容,不需要額外建立訊息模板物件,語法更精簡,也容易閱讀。
當模板定義完成後,就能透過 formatMessages()
方法填入變數,產生符合聊天模型需求的訊息陣列:
const messages = await chatPrompt.formatMessages({
role: '資深講師',
style: '條列清楚',
question: '請解釋 event loop 的運作方式',
});
接著,這個 messages
陣列就可以直接傳入像 ChatOpenAI
這樣的聊天模型:
const response = await model.invoke(messages);
console.log(response.content);
透過 ChatPromptTemplate
,我們可以清楚定義每個角色的對話內容,並靈活插入變數。這不僅讓提示語更模組化、易於維護,也能確保對話結構始終符合模型的輸入格式。
MessagesPlaceholder
在多輪對話或需要延續記憶的應用場景中,往往需要保留前幾輪的訊息,並與當前的輸入一併傳給模型。為了支援這種情境,LangChain 提供了 MessagesPlaceholder
,可以在模板中預留一個插槽,用來動態插入歷史訊息。
以下是一個範例:
import {
ChatPromptTemplate,
MessagesPlaceholder,
HumanMessagePromptTemplate,
} from '@langchain/core/prompts';
const chatPrompt = new ChatPromptTemplate({
promptMessages: [
new MessagesPlaceholder('context'),
HumanMessagePromptTemplate.fromTemplate('{question}'),
],
inputVariables: ['context', 'question'],
});
在這裡,我們透過 context
變數作為上下文訊息的插槽,並在後面接上使用者目前的提問。
在執行時,只需要提供一組符合 BaseMessage[]
格式的訊息陣列,就能填入這段上下文:
import { SystemMessage, HumanMessage, AIMessage } from '@langchain/core/messages';
const messages = await chatPrompt.formatMessages({
context: [
new SystemMessage('你是一位技術助理。'),
new HumanMessage('什麼是 HTTP?'),
new AIMessage('HTTP 是一種網頁通訊協定。'),
],
question: '那 HTTPS 呢?',
});
然後一樣將這組訊息傳給聊天模型推論:
const response = await model.invoke(messages);
console.log(response.content);
透過這樣的設計,我們可以更有條理地插入並管理對話歷史,讓提示語保持乾淨且具彈性。特別是在需要處理記憶或多輪聊天的情境中,它能協助我們打造結構清晰、容易維護且可持續擴充的對話流程。
今天我們認識了 LangChain 的 提示模板(Prompt Templates),學會如何把動態輸入與靜態提示分離管理,讓設計更清晰可維護:
PromptTemplate
能將提示拆分為模板與變數,並透過 format()
動態生成完整內容。PromptTemplate.fromTemplate()
會自動解析變數名稱,讓程式更直觀簡潔。ChatPromptTemplate
專為聊天模型設計,支援系統訊息、使用者訊息、AI 訊息等結構化角色管理。ChatPromptTemplate.fromMessages()
可用簡寫形式快速建立訊息模板,並透過 formatMessages()
輸出結構化訊息陣列,直接交給模型使用。MessagesPlaceholder
可插入歷史訊息,方便處理多輪對話與上下文記憶。透過提示模板,我們能將提示邏輯與程式邏輯有效分離,打造更易維護且可擴展的 LLM 應用。