工程进阶 · 可靠 Agent 的工程模式

Session ≠ Context Window

会话日志是持久的事件流、上下文窗口是临时的工作记忆,两者必须分离

本页解决的问题

先给结论

「Session ≠ Context Window」要解决的关键问题是什么?

会话日志是持久的事件流、上下文窗口是临时的工作记忆,两者必须分离

判断标准

让这个结论先证明自己值得留下。 把这一页当成决策工具,而不是需要背下来的定义。把概念连到一个真实任务、一个可观察结果,以及一个能改变你判断的失败上。

下一步

写下一个问题:试完这个方法后,你能用什么证据回答它?

常见误区

结论听起来很完整,却没有检查最关键的假设。

两个容易混淆的概念
临时 / 有限
Context Window
Claude 当前能看到的 Token。就像人的工作记忆:容量有限,过了就忘。每次对话开始时构建,用完就丢。
当前推理所需的精选内容
永久 / 可回溯
Session
所有发生过的事件的持久日志。就像完整的录像:从头到尾什么都记着,永远可以倒回去看。Append-only,只增不减。
所有原始事件的完整记录
为什么必须分离
上下文管理的不可逆性
  • 1 Compaction(压缩)和 Trimming(裁剪)都是不可逆操作,一旦压缩,原始细节就丢了
  • 2 压缩时很难知道未来哪些 Token 重要,今天看似无关的信息,可能是明天关键决策的依据
  • 3 如果压缩后原始信息丢了,就永远回不来了,这是信息论的基本约束

所以正确的做法是:原始事件永久保存在 Session 里,Context Window 只是从 Session 中临时取景的一个视角。丢了 Context 没关系,因为 Session 还在,随时可以重建。

Session 作为持久上下文对象
getEvents() 接口
Session 提供一个类似数据库的查询接口:Brain 可以按需读取任意范围的事件,摆脱固定上下文窗口的限制。
// Brain 可以灵活查询 Session const recentEvents = session.getEvents({ from: position - 100, // 从某个位置开始读 to: position // 读到当前位置 }); // 可以倒回到某个时间点 const beforeDecision = session.getEvents({ from: decisionPoint - 20, to: decisionPoint + 5 }); // 可以过滤特定类型的事件 const toolCalls = session.getEvents({ filter: "tool_use" });

这就像 REPL 中的对象一样,LLM 可以写代码来查询和过滤 Session 中的事件。Brain 从任意位置开始读、倒回到某个时间点、重读某个决策前后的上下文。

Harness 的灵活性
从 Session 取出的事件可以做任意变换
  • 优化 Prompt Cache 命中率:保持前缀稳定,减少重复计算的 Token 开销
  • 做上下文工程:根据当前任务类型,选择性地放入最相关的历史事件
  • Harness 是可换的:不同模型可能需要不同的上下文策略,换 Harness 不影响 Session
核心对比
维度 Context Window Session
持久性 临时,用完即丢 永久,持久化存储
内容 精选后的 Token 所有原始事件
操作 只读(对 Claude 来说) 可追加(append-only)
大小 有限(模型上限) 无限制
用途 当前推理 历史回溯、状态恢复
硬件类比
内存 (RAM)
Context Window
速度快、容量小、断电即失。CPU 正在用的数据必须在内存里,但内存不是用来长期存储的。
硬盘 (Disk)
Session
速度慢、容量大、断电不失。所有数据最终都存在硬盘上,需要时再加载到内存。

你不会把所有文件同时加载到内存里,那样内存会爆。同样的道理,你不应该把所有历史事件都塞进 Context Window,那样 Token 会爆。正确的做法是按需加载:Session 存全量,Context 取子集。

Session 是 Agent 的硬盘,Context Window 是内存,不要把内存当硬盘用。把所有原始事件存进 Session,让 Harness 按需组装 Context。这样即使上下文压缩了、模型换了,历史永远不会丢。

「两个容易混淆的概念」为什么要看操作

「所以正确的做法是: 原始事件永久保存在 Session 里 ,Context Window 只是从 Session 中临时取景的一个视角。丢了 Context 没关系,因为 Session 还在,随时可以重建」把结构落到了一个具体动作。这里真正要比较的不是名词谁更高级,而是数据如何被放置,以及最常发生的操作需要走多远。

读懂结构,要同时看访问方式和变化方式

「这就像 REPL 中的对象一样,LLM 可以写代码来查询和过滤 Session 中的事件。Brain 从任意位置开始读、倒回到某个时间点、重读某个决策前后的上下文」揭示了一个容易被忽略的取舍:按位置读取、按键查找、从两端进出、插入新元素和遍历关系,适合的组织方式并不相同。一个结构在某个操作上很快,不代表它在所有操作上都快。

  • 1 Compaction(压缩)和 Trimming(裁剪)都是 不可逆操作 ,一旦压缩,原始细节就丢了
  • 2 压缩时 很难知道未来哪些 Token 重要 ,今天看似无关的信息,可能是明天关键决策的依据
  • 3 如果压缩后原始信息丢了,就 永远回不来了 ,这是信息论的基本约束

把规模和更新频率一起算进去

实践时可以把「你不会把所有文件同时加载到内存里,那样内存会爆。同样的道理,你不应该把所有历史事件都塞进 Context Window,那样 Token 会爆。正确的做法是 按需加载 :Session 存全量,Context 取子集」当作边界提醒:先写下数据量、最常用的操作和允许的延迟,再看 AI 给出的结构是否真的匹配。

从「两个容易混淆的概念」走到「为什么必须分离」

「两个容易混淆的概念」先把问题落在「临时 / 有限 Context Window Claude 当前能看到的 Token。就像人的 工作记忆 :容量有限,过了就忘。每次对话开始时构建,用完就丢。 当前推理所需的精选内容 永久 / 可回溯 Session 所有发生过的事件的持久日志。就像 完整的录像 :从头到尾什么都记着,永远可以倒回去看。Append-only,只增不减。 所有原始事件的完整记录」上;到了「为什么必须分离」,讨论继续推进到「所以正确的做法是: 原始事件永久保存在 Session 里 ,Context Window 只是从 Session 中临时取景的一个视角。丢了 Context 没关系,因为 Session 还在,随时可以重建」。两段连起来,重点就不只是记住一个结论,而是看清它成立所依赖的条件。

把这条判断带到下一个场景

遇到一个新的数据结构时,不要从定义开始背。先写出最频繁的操作,再估计数据量和更新方式,最后检查结构是否让这三个条件同时成立。

  • 「两个容易混淆的概念」:临时 / 有限 Context Window Claude 当前能看到的 Token。就像人的 工作记忆 :容量有限,过了就忘。每次对话开始时构建,用完就丢。 当前推理所需的精选内容 永久 / 可回溯 Session 所有发生过的事件的持久日志。就像 完整的录像 :从头到尾什么都记着,永远可以倒回去看。Append-only,只增不减。 所有原始事件的完整记录
  • 「为什么必须分离」:所以正确的做法是: 原始事件永久保存在 Session 里 ,Context Window 只是从 Session 中临时取景的一个视角。丢了 Context 没关系,因为 Session 还在,随时可以重建
  • 「最后的要点」:做上下文工程 :根据当前任务类型,选择性地放入最相关的历史事件

最后的「最后的要点」把讨论落到「做上下文工程 :根据当前任务类型,选择性地放入最相关的历史事件」。回看这条线索时,最值得保留的是:当输入、规模或风险改变,哪些判断需要重新做一遍。

标记为已学完 阅读进度会自动记录
← 上一篇下一篇 →

继续阅读

同一条线上的下一篇。

文章讨论

读到这里,留下一个判断。

把刚想明白的地方、还没想通的问题,留给下一位一起学习的人。

正在讨论 Session ≠ Context Window 可靠 Agent 的工程模式
3条讨论文章讨论 · 与共学社区同步
在共学社区查看
AM
Asha Morgan内容编辑
观点实践记录

我把这篇文章里的一个判断改写成了今天可以验证的小实验。比记住结论更有用的是,知道下一步要观察什么。

文章讨论7 有帮助
LH
Lin Harper独立开发者
观点观点

读完以后我先回头找它成立的条件,而不是直接把方法搬进项目。这个顺序让后面的取舍清楚很多。

文章讨论5 有帮助
KM
Kiki Moore产品运营
问题问题

如果把这个判断放到真实工作里,最先需要补的约束是什么?我想知道从阅读到第一次实践之间,哪一步最值得先做。

文章讨论4 有帮助