AI记不住你?别慌,LangChain 来当你的“人形备忘录”!

47 阅读4分钟

从“你是谁?”到“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 在背后做了三件关键事:

  1. 自动记录:每次调用后,自动把用户的输入和 AI 的回复存入 messageHistory
  2. 智能注入:在下一次调用时,把历史消息作为 {history} 插入到 Prompt 中。
  3. 会话隔离:通过 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。