第 05 课:记忆与流式传输

第 05 课:记忆与流式传输

配套代码仓库:https://gitee.com/wang-zeyong111/lang-chain-lecture

本课定位

第 05 课关注交互体验。一个能用的 LLM 应用,通常不仅要能回答,还要能记住当前会话,并在任务较慢时持续给用户反馈。记忆解决上下文连续性,流式传输解决等待体验和可观察性。

学习目标

  • 理解短期记忆的本质。
  • 使用 thread_id 隔离不同会话。
  • 理解 checkpointer 的作用。
  • 掌握流式传输的常见模式。
  • 学会控制上下文长度。

一、记忆不是模型永久记住

很多初学者会误以为“模型记住了用户”。实际情况是:模型每次调用都是基于当前输入上下文生成结果。所谓记忆,是应用把之前的重要消息重新传给模型。

短期记忆通常保存:

  • 用户之前说过的话;
  • 模型之前的回答;
  • 工具调用结果;
  • 当前任务状态;
  • 用户偏好。

二、线程级记忆

LangChain v1 中,Agent 的短期记忆通常通过 checkpointer 管理,并用thread_id区分会话。

同一个用户可以有多个线程:

  • thread_id="support-ticket-1001";
  • thread_id="support-ticket-1002";
  • thread_id="student-001-langchain";

不同线程的消息应该隔离,避免 A 用户看到 B 用户的上下文。

三、checkpointer 的作用

checkpointer 负责保存和恢复 Agent 状态。

开发阶段可以用:

fromlanggraph.checkpoint.memoryimportInMemorySaver

生产阶段应使用数据库型 checkpointer,例如 Postgres。原因:

  • 进程重启后内存会丢失;
  • 多实例部署需要共享状态;
  • 需要审计和回放;
  • 需要长期保存关键会话。

四、短期记忆的风险

记忆不是越多越好。长历史会带来:

  • token 成本增加;
  • 响应变慢;
  • 模型被旧信息干扰;
  • 命中上下文窗口限制;
  • 隐私和合规风险。

因此需要上下文管理策略。

五、上下文裁剪策略

常见策略:

  1. 只保留最近 N 轮;
  2. 保留系统消息和最近消息;
  3. 把旧对话总结成摘要;
  4. 删除无关工具结果;
  5. 对长文档只保留引用 ID;
  6. 根据任务动态选择相关历史。

简单聊天可以先用“最近 N 条消息”。复杂任务再引入摘要记忆和长期记忆。

六、流式传输的价值

LLM 应用常常有延迟。用户看着空白页面等待 10 秒,体验很差。流式传输可以:

  • 逐步显示模型生成文本;
  • 显示 Agent 正在调用哪个工具;
  • 显示检索进度;
  • 显示自定义状态;
  • 方便开发者调试。

七、常见 stream mode

updates

用于观察 Agent 每个步骤。例如:

  • 模型节点输出工具调用;
  • 工具节点返回结果;
  • 模型节点输出最终答案。

适合调试 Agent 进度,也适合前端展示“正在检索”“正在计算”。

messages

用于流式输出模型消息或 token。适合聊天 UI 逐字显示。

custom

用于业务自定义事件。例如:

  • 已检索 3 个文档;
  • 正在调用订单系统;
  • 已完成 70%。

八、记忆与流式的组合

真实聊天应用通常同时需要:

  • 用户打开同一个会话时能恢复上下文;
  • 模型回答时逐步输出;
  • Agent 调工具时展示进度;
  • 工具失败时给友好提示;
  • 会话结束后保存最终状态。

这时你需要把 checkpointer、thread_id 和 stream 一起设计。

九、常见坑

  1. 忘记传thread_id,导致记忆无法正确隔离。
  2. 使用内存 checkpointer 上生产,重启就丢状态。
  3. 历史消息无限增长,成本和效果同时变差。
  4. 流式输出只展示 token,不展示 Agent 步骤,用户不知道系统在做什么。
  5. 工具结果太长,污染后续上下文。

十、自测清单

  • 我能解释短期记忆为什么需要应用层保存。
  • 我知道thread_id的作用。
  • 我知道 checkpointer 在开发和生产中的不同选择。
  • 我能说出updatesmessages两种流式模式的区别。
  • 我知道至少三种控制上下文长度的方法。

十一、课后练习

  1. 用两个 thread_id 模拟两个学生,一个喜欢类比,一个喜欢代码。
  2. 对同一个问题分别调用 Agent,观察是否保留各自偏好。
  3. 写一个trim_messages函数,只保留最近 6 条消息。
  4. 如果有真实模型,使用stream_mode="updates"观察工具调用过程。