普通视图

发现新文章,点击刷新页面。
昨天以前首页

让大模型“记住你”:LangChain 中的对话记忆机制实战

作者 Zyx2007
2026年1月4日 22:21

大语言模型(LLM)本质上是无状态的——每一次 API 调用都像一次全新的对话,模型对之前的交互一无所知。这种设计虽保证了接口的简洁与可扩展性,却也带来了明显的局限:无法支持多轮连贯的对话体验。用户说“我叫张三”,下一句问“我叫什么名字?”,若不传递上下文,模型只能回答“我不知道”。要让 AI 真正具备“记忆”,开发者必须主动维护对话历史,并将其作为输入的一部分传给模型。而 LangChain 提供的 RunnableWithMessageHistory 机制,正是解决这一问题的工程化方案。

无状态调用的局限

最基础的 LLM 调用方式如下:

const res1 = await model.invoke('我叫张三,喜欢喝白兰地');
const res2 = await model.invoke('我叫什么名字?');
console.log(res2.content); // 模型无法回答,因无上下文

两次调用彼此独立,模型无法建立关联。这就像每次见面都忘记对方是谁,显然无法支撑真实的对话场景。要实现连贯交互,必须将之前的对话记录(messages)一并传入。

手动维护消息历史:可行但繁琐

一种朴素的做法是手动维护一个消息数组:

const messages = [
  { role: 'user', content: '我叫张三,喜欢喝白兰地' },
  { role: 'assistant', content: '好的,张三!' },
  { role: 'user', content: '我叫什么名字?' }
];
// 将 messages 作为 prompt 的一部分传给模型

然而,这种方式存在明显问题:随着对话轮次增加,消息长度呈“滚雪球”式增长,迅速消耗大量 token,不仅增加成本,还可能超出模型上下文窗口限制。更关键的是,开发者需自行管理存储、截断、会话隔离等逻辑,极易出错。

LangChain 的解决方案:内置记忆模块

LangChain 通过 RunnableWithMessageHistory 抽象,将“带记忆的对话”封装为一个可复用的运行单元。配合 InMemoryChatMessageHistory,可轻松实现会话级记忆:

const messageHistory = new InMemoryChatMessageHistory();
const chain = new RunnableWithMessageHistory({
  runnable,
  getMessageHistory: async () => messageHistory,
  inputMessagesKey: 'input',
  historyMessagesKey: 'history',
});

这里,runnable 是原始的提示词+模型链,而 RunnableWithMessageHistory 在其前后自动注入和更新对话历史。开发者只需关注当前输入,历史管理由框架自动完成。

构建带记忆的对话链

完整的流程包含系统提示、历史占位符和用户输入三部分:

const prompt = ChatPromptTemplate.fromMessages([  ['system', "你是一个有记忆的助手"],
  ['placeholder', "{history}"],
  ['human', "{input}"]
]);
  • system 消息设定角色;
  • {history} 占位符由 LangChain 自动替换为过往对话;
  • {input} 接收当前用户提问。

当调用 chain.invoke() 时,框架会:

  1. messageHistory 读取已有消息;
  2. 将其插入 prompt{history} 位置;
  3. 调用模型生成回复;
  4. 将新对话(用户输入 + 模型回复)存回 messageHistory

会话隔离与实际效果

通过 sessionId 可区分不同用户的对话上下文:

await chain.invoke({ input: '我叫张三...' }, { configurable: { sessionId: 'user123' } });
await chain.invoke({ input: '我叫什么名字?' }, { configurable: { sessionId: 'user123' } });

第二次调用时,模型能准确回答“你叫张三”,因为它接收到了完整的对话历史。整个过程对开发者透明,无需手动拼接消息。

内存存储的权衡与扩展

示例中使用 InMemoryChatMessageHistory 将对话暂存于内存,适合演示或短期会话。但在生产环境中,通常需替换为持久化存储(如 Redis、数据库),并通过自定义 getMessageHistory 函数按 sessionId 加载历史。LangChain 的设计允许无缝切换底层存储,保持上层逻辑不变。

此外,为避免 token 耗尽,还可结合摘要记忆(Summary Memory)或滑动窗口策略:当历史过长时,自动压缩旧对话或仅保留最近 N 轮。这些高级功能同样可通过 LangChain 的 memory 模块实现。

工程价值:从“问答机”到“智能体”

引入记忆机制后,AI 应用的能力边界显著拓展:

  • 个性化服务:记住用户偏好、身份信息;
  • 任务延续:在多步骤操作中保持上下文(如订票、调试);
  • 情感连贯:维持语气与风格的一致性。

更重要的是,这种能力以声明式、模块化的方式集成,不破坏原有代码结构。开发者无需重写整个调用逻辑,只需将普通链包装为 RunnableWithMessageHistory,即可获得记忆能力。

结语

让大模型“记住”用户,不是魔法,而是工程。LangChain 通过抽象对话历史的管理,将复杂的上下文维护转化为简单的配置选项。这不仅降低了多轮对话的实现门槛,也为构建真正智能、连贯、个性化的 AI 应用铺平了道路。在 AI 从工具走向伙伴的进程中,记忆,正是建立信任与深度交互的第一步。

❌
❌