从“你是谁?”到“xx喜欢白兰地”,看 LangChain 如何让大模型拥有“金鱼记忆”之外的超能力!
🤖 开场白:LLM 的“失忆症”
你有没有试过这样和大模型聊天?
你:我叫xx,喜欢喝白兰地。
AI:好的,xx!
你(5秒后) :我叫什么名字?
AI:……抱歉,我不知道。
是不是有种被“渣AI”抛弃的感觉?明明上一秒还在深情对视,下一秒它就一脸茫然:“这位朋友,我们认识吗?”
原因很简单——大模型的 API 调用是无状态的,就像每次 HTTP 请求都是一次全新的邂逅。它没有记忆,也没有感情(至少目前没有 😢)。
但别急!今天我们就来聊聊:如何给大模型装上“记忆外挂”?
答案就是——LangChain 的 RunnableWithMessageHistory!
🧠 为什么需要“记忆”?
在真实应用场景中,用户可不会只问一个问题就走人。他们可能会:
- 先自我介绍
- 然后问天气
- 接着让你推荐白兰地
- 最后再问:“我刚才说喜欢什么酒来着?”
如果 AI 每次都从零开始,用户体验会像坐过山车——刺激,但晕。
所以,我们需要一种机制:把对话历史“喂”给模型,让它知道上下文。
最朴素的做法?把所有历史消息拼成一个超长数组,每次调用都带上。
const messages = [
{ role: 'user', content: '我叫xx,喜欢喝白兰地' },
{ role: 'assistant', content: '好的,xx!' },
{ role: 'user', content: '你知道我是谁吗?' }
]
听起来不错?但问题来了——
滚雪球式增长的 Token,钱包扛得住吗?
一次对话还好,十轮、二十轮之后,光历史就占了 3000 个 token,模型还没回答正事,账单先爆了 💸。
于是,聪明的开发者们开始思考:能不能只记住“有用”的信息?能不能自动管理历史?
LangChain 说:交给我!
🛠️ LangChain 登场:让记忆变得优雅
LangChain 不仅是一个工具链,更像是一位贴心的“对话管家”。它提供了 RunnableWithMessageHistory 这个神器,帮你自动管理对话历史,还能无缝集成到你的 LLM 调用流程中。
来看一段魔法代码(基于 DeepSeek + LangChain):
import { ChatDeepSeek } from '@langchain/deepseek';
import { ChatPromptTemplate } from '@langchain/core/prompts';
import { RunnableWithMessageHistory } from '@langchain/core/runnables';
import { InMemoryChatMessageHistory } from '@langchain/core/chat_history';
// 1. 初始化模型
const model = new ChatDeepSeek({ model: 'deepseek-chat', temperature: 0 });
// 2. 定义 Prompt 模板(注意 placeholder)
const prompt = ChatPromptTemplate.fromMessages([
['system', "你是一个有记忆的助手"],
['placeholder', "{history}"], // ← 历史将在这里插入
['human', "{input}"]
]);
// 3. 构建可运行链
const runnable = prompt.pipe(model);
// 4. 创建内存中的历史存储
const messageHistory = new InMemoryChatMessageHistory();
// 5. 包装成带记忆的链
const chain = new RunnableWithMessageHistory({
runnable,
getMessageHistory: async () => messageHistory,
inputMessagesKey: 'input',
historyMessagesKey: 'history',
});
然后,你就可以愉快地对话了:
await chain.invoke({ input: '我叫xx,喜欢喝白兰地' }, { configurable: { sessionId: 'makefriend' } });
await chain.invoke({ input: '我叫什么名字?' }, { configurable: { sessionId: 'makefriend' } });
结果?
“你叫xx,喜欢喝白兰地。”
🎉 成功!AI 终于记得你了!
🔍 背后发生了什么?
LangChain 在背后做了三件关键事:
- 自动记录:每次调用后,自动把用户的输入和 AI 的回复存入
messageHistory。 - 智能注入:在下一次调用时,把历史消息作为
{history}插入到 Prompt 中。 - 会话隔离:通过
sessionId(比如'makefriend'),支持多用户、多会话并行,互不干扰。
就像给每个用户配了一个专属“记忆笔记本”,AI 随时翻阅,绝不混淆。
⚠️ 但…Token 问题解决了吗?
老实说,InMemoryChatMessageHistory 只是把问题“封装”了,并未彻底解决。如果你不做限制,历史还是会无限增长。
不过 LangChain 提供了更多高级方案:
- 窗口记忆(Window Memory) :只保留最近 N 轮对话。
- 摘要记忆(Summary Memory) :用 LLM 自己总结历史,压缩成一句话。
- 向量数据库记忆:把关键信息存入向量库,按需检索(适合长期记忆)。
这些,我们下次再聊!(挖个坑,敬请期待 🕳️)
💡 总结:AI 的“记忆”,其实是工程的艺术
- LLM 本身无状态 → 需要外部维护上下文。
- 简单拼接历史 → 可行但低效,Token 成本高。
- LangChain 的
RunnableWithMessageHistory→ 让记忆管理变得模块化、可扩展、易维护。 - 真正的“有记忆 AI” = 合理的历史策略 + 巧妙的 Prompt 设计 + 成本控制。
🎁 彩蛋:对比实验
看看“裸调 API” vs “LangChain 带记忆”的区别:
// 裸调:AI 失忆
const res1 = await model.invoke('我叫xx');
const res2 = await model.invoke('我叫什么?'); // ❌ 不知道!
// LangChain:AI 记得你
await chain.invoke({ input: '我叫xx' });
await chain.invoke({ input: '我叫什么?' }); // ✅ xx!
是不是瞬间觉得 AI 有人情味了?😉
📣 结语
在这个人人都想打造“个性化 AI 助手”的时代,记忆不是奢侈品,而是必需品。而 LangChain,正是那个帮你把“一次性聊天机器人”升级为“懂你的数字伙伴”的桥梁。
下次当你听到 AI 说“我记得你说过……”,请默默感谢背后的工程师——以及 LangChain。