LangChain 教學:Memory - ConversationBufferMemory
簡介
在對話型 AI 應用中,記憶(Memory)是讓模型能夠「保持上下文」的關鍵機制。沒有記憶,ChatGPT 只能根據單一輪提問回應,無法在多輪對話中保持前後關聯,使用者體驗會大打折扣。
LangChain 作為一套用於構建 LLM 應用的框架,提供了多種 Memory 類別,其中最直觀、最常用的就是 ConversationBufferMemory。它會把每一次使用者的輸入與模型的回覆都串接成一段文字,形成「對話緩衝區」,讓後續的 Prompt 能自動攜帶完整的對話歷史。
本篇文章將從概念說明、程式碼範例、常見陷阱與最佳實踐,最後列出實務應用場景,帶你一步步掌握 ConversationBufferMemory 的使用方式,適合剛入門到已有一定開發經驗的讀者。
核心概念
1. ConversationBufferMemory 是什麼?
ConversationBufferMemory 簡單來說就是一個 文字緩衝,它會把每一次的 human(使用者)與 ai(模型)訊息依序累加,形成類似:
Human: 你好
AI: 你好!有什麼可以幫忙的嗎?
Human: 請介紹一下台北101
AI: 台北101是...
在每次呼叫 LLM 時,框架會自動把這段緩衝文字插入 Prompt,讓模型知道「先前已說過什麼」。
2. 為什麼選擇 Buffer 而不是其他 Memory?
- 簡單直觀:不需要自行設計資料結構,框架自動管理。
- 適合短對話:對於對話輪數在 10~20 輪以內的情境,效能與成本都相當友好。
- 易於除錯:緩衝內容直接以文字呈現,開發者可以輕鬆印出檢查。
若對話過長或需要更細粒度的記憶(例如只記住關鍵資訊),可以考慮 ConversationSummaryMemory、VectorStoreRetrieverMemory 等進階方案。
3. 主要屬性與方法
| 屬性/方法 | 說明 |
|---|---|
memoryKey |
在 Prompt 中使用的變數名稱,預設為 "history"。 |
returnMessages |
設為 true 時,返回 Message 物件陣列;false(預設)則返回純文字。 |
clear() |
清空緩衝區,常用於重新開始新對話。 |
loadMemoryVariables(values) |
取得目前的緩衝內容,供 Prompt 使用。 |
程式碼範例
以下範例採用 LangChainJS(JavaScript / TypeScript)撰寫,請先安裝相關套件:
npm install langchain openai
註:本教學使用 OpenAI 的
gpt-3.5-turbo,請自行設定OPENAI_API_KEY環境變數。
範例 1:最簡單的 ConversationBufferMemory
import { OpenAI } from "langchain/llms/openai";
import { ConversationChain } from "langchain/chains";
import { ConversationBufferMemory } from "langchain/memory";
// 建立 LLM
const llm = new OpenAI({ temperature: 0 });
// 建立 Memory
const memory = new ConversationBufferMemory();
// 建立 Chain,將 LLM 與 Memory 綁定
const chain = new ConversationChain({ llm, memory });
async function chat() {
console.log(await chain.call({ input: "你好!" }));
console.log(await chain.call({ input: "今天台北天氣如何?" }));
}
chat();
說明
ConversationChain會自動把memory中的history文字插入 Prompt。- 每次
chain.call後,Memory 都會自動更新緩衝區。
範例 2:自訂 memoryKey 與 returnMessages
import { OpenAI } from "langchain/llms/openai";
import { ConversationChain } from "langchain/chains";
import { ConversationBufferMemory } from "langchain/memory";
const llm = new OpenAI({ temperature: 0 });
const memory = new ConversationBufferMemory({
memoryKey: "chat_history", // 在 Prompt 中使用的變數名稱
returnMessages: true // 回傳 Message 物件,方便後續處理
});
const chain = new ConversationChain({ llm, memory });
async function chat() {
const res1 = await chain.call({ input: "請告訴我什麼是區塊鏈?" });
console.log(res1.response);
// 直接取得緩衝的 Message 陣列
const messages = await memory.loadMemoryVariables({});
console.log("緩衝內容(Message 物件):", messages.chat_history);
}
chat();
說明
- 設定
memoryKey為chat_history,在 Prompt 中會變成{{chat_history}}。 returnMessages: true讓我們可以取得更結構化的訊息(含 role、content),適合要做訊息過濾或摘要的情況。
範例 3:在自訂 Prompt 中使用 ConversationBufferMemory
import { OpenAI } from "langchain/llms/openai";
import { LLMChain, PromptTemplate } from "langchain/chains";
import { ConversationBufferMemory } from "langchain/memory";
const llm = new OpenAI({ temperature: 0 });
const prompt = PromptTemplate.fromTemplate(
`以下是一段對話歷史,請根據內容回答使用者的問題。
{history}
使用者: {input}
AI:`
);
const memory = new ConversationBufferMemory({});
const chain = new LLMChain({ llm, prompt, memory });
async function chat() {
console.log(await chain.call({ input: "什麼是深度學習?" }));
console.log(await chain.call({ input: "它跟機器學習有什麼差別?" }));
}
chat();
說明
- 這裡使用
LLMChain搭配自訂PromptTemplate,在 Prompt 中手動插入{history}(即memoryKey的預設值)。 - 這種寫法適合想要在 Prompt 中加入額外說明或格式化的情況。
範例 4:清除記憶並重新開始對話
import { OpenAI } from "langchain/llms/openai";
import { ConversationChain } from "langchain/chains";
import { ConversationBufferMemory } from "langchain/memory";
const llm = new OpenAI({ temperature: 0 });
const memory = new ConversationBufferMemory();
const chain = new ConversationChain({ llm, memory });
async function chat() {
await chain.call({ input: "先說個笑話。" });
console.log("第一輪結束,緩衝內容:", await memory.loadMemoryVariables({}));
// 清除記憶
memory.clear();
console.log("已清除緩衝,重新開始:");
await chain.call({ input: "現在請告訴我 Python 的基礎語法。" });
}
chat();
說明
memory.clear()會把緩衝區全部清空,適合在使用者要求「重新開始」或切換主題時使用。
範例 5:結合檔案儲存持久化(簡易版)
import fs from "fs";
import { OpenAI } from "langchain/llms/openai";
import { ConversationChain } from "langchain/chains";
import { ConversationBufferMemory } from "langchain/memory";
const llm = new OpenAI({ temperature: 0 });
const memoryFile = "./chat_memory.json";
// 從檔案載入過去的緩衝(若不存在則建立空緩衝)
let initHistory = "";
if (fs.existsSync(memoryFile)) {
initHistory = fs.readFileSync(memoryFile, "utf-8");
}
const memory = new ConversationBufferMemory({ memoryKey: "history" });
memory.chatHistory = initHistory; // 手動設定初始內容
const chain = new ConversationChain({ llm, memory });
async function chat() {
const res = await chain.call({ input: "今天的新聞有什麼值得關注的?" });
console.log(res.response);
// 把最新的緩衝寫回檔案
const { history } = await memory.loadMemoryVariables({});
fs.writeFileSync(memoryFile, history);
}
chat();
說明
- 這個範例示範如何把緩衝內容寫入本地檔案,讓聊天紀錄在程式重啟後仍能保留。
- 在正式產品中,建議改用資料庫或雲端儲存,以確保安全與擴充性。
常見陷阱與最佳實踐
| 陷阱 | 可能的後果 | 解決方案或最佳實踐 |
|---|---|---|
| 緩衝過長 | Prompt 超過 LLM 的 token 限制,導致錯誤或成本激增。 | - 設定 maxTokenLimit(自行截斷)- 定期使用 ConversationSummaryMemory 產生摘要- 只保留最近 N 輪對話 |
| 忘記清除記憶 | 使用者切換話題時仍會帶入舊有上下文,產生不相關回覆。 | - 在 UI 中提供「重新開始」按鈕,呼叫 memory.clear()- 根據關鍵字或意圖自動清除 |
returnMessages 與 Prompt 不匹配 |
若 Prompt 期待純文字但 returnMessages:true,會出現型別錯誤。 |
- 確認 memoryKey 與 Prompt 中的變數型別一致- 若使用 Message 陣列,需自行組合成文字 |
| 多使用者環境共用同一 Memory 實例 | 不同使用者的對話互相污染,隱私風險。 | - 為每位使用者建立獨立的 Memory 物件(或使用 Session ID 做映射) |
| 未處理 API 錯誤 | 網路或金鑰失效時,整個對話流程卡住。 | - 包裝 chain.call 為 try/catch,並回傳友善錯誤訊息 |
小技巧
- 限制緩衝字元數:
const MAX_CHAR = 2000; const trimmed = history.slice(-MAX_CHAR); memory.chatHistory = trimmed; - 結合摘要:在第 N 輪自動把過往對話摘要後重寫緩衝,降低 token 數。
- 使用 Session ID:在多使用者聊天室中,將
memory放入Map<sessionId, Memory>,確保隔離。
實際應用場景
| 場景 | 為何選 ConversationBufferMemory | 示範功能 |
|---|---|---|
| 客服聊天機器人 | 客服對話往往在 10~15 輪內,完整保留上下文能提升解答正確率。 | 使用者提問「訂單編號 1234 為何未出貨?」 → 機器人根據前一次的「請提供訂單編號」回覆自動帶入。 |
| 教育輔助教練 | 教學對話需要累積學生的提問與教師的回覆,以便後續檢視學習進度。 | 學生問「什麼是二次函數?」 → 教練回覆後,後續問題「請舉例說明」仍能參考先前的解釋。 |
| 旅遊行程規劃 | 使用者會分步驟提供需求(日期、景點、預算),需要把每一步的資訊串接起來。 | 第一步:「我想去東京 3 天」 → 第二步:「預算 2 萬」 → 第三步:「請安排住宿」 |
| 程式除錯助手 | 開發者在多輪對話中提供錯誤訊息與程式碼片段,模型需要持續追蹤上下文。 | 開發者:「這段程式拋出 TypeError」 → 模型回問「是哪一行?」 → 記憶保持前後訊息,最終給出修正建議。 |
| 個人助理(日程管理) | 使用者會先說「提醒我明天 9 點開會」再說「請把會議議程加入」——需要把時間與議程串在一起。 | 透過緩衝,助理能一次性產出完整的日程條目。 |
總結
- ConversationBufferMemory 是 LangChain 中最易上手、最直觀的記憶機制,適合大多數短對話應用。
- 它的核心概念是把每一次的
Human與AI訊息串接成文字緩衝,並在每次呼叫 LLM 時自動注入 Prompt。 - 使用時要注意 緩衝長度、多使用者隔離、以及 何時清除,以避免 token 超限或上下文污染。
- 透過簡單的 API(
memoryKey、returnMessages、clear())即可客製化行為,配合自訂 Prompt、摘要或持久化儲存,可打造從客服機器人到程式除錯助手的完整對話系統。
掌握好 ConversationBufferMemory,你就能在開發 LLM 應用時,快速為模型提供「記憶」這個關鍵能力,提升使用者體驗與系統效能。祝你玩得開心、開發順利! 🚀