上下文管理
你正在用 AI 重构一个大模块。Agent 已经读了十几个文件、执行了一堆 shell 命令、搜索了几十个符号引用。半小时之后,它开始变得“迟钝”——回答开始跑偏、重复犯之前的错误、忘了你早就告诉过它的关键信息。
模型并没有变笨。是上下文窗口不堪重负。
Helix 用两种互补的策略来解决这个问题:Cache(存储并按需召回)与 Compact(压缩为结构化摘要)。
为什么上下文管理至关重要
工具密集型的 AI 工程任务,token 消耗增长远比普通对话快得多:
- 读一个 500 行的文件 → ~2,000 tokens
- 执行一次
find命令 → 可能输出几千行 - 搜索代码引用 → 几十个文件中的匹配结果
- 每次工具调用的参数和返回都计入上下文
10 次工具调用之后,你可能已经消耗了 50K+ tokens。而大多数模型对最近内容的注意力更集中——早期的重要决策与上下文正在被遗忘。
没有上下文管理,你只有两种选择:
- 开新对话——丢失所有进度
- 硬撑下去——输出质量持续下降,成本持续上升
Helix 提供了第三种方式。
Cache:存储大型输出,按需召回
Cache 解决的问题是:工具输出太大,但并不是每次都需要。
工作原理
- 当对话轮次超过阈值后,Helix 会自动用轻量的 cache 标记替换早期消息中的大型工具输出
- 原始内容存入本地 KV cache(Pebble 存储引擎,使用 SHA256 内容寻址去重)
- Cache 标记保留在对话历史里,形如
[CACHED] recall_cached_content("sha256hash") - 当 Agent 需要重新查看历史的工具输出时,通过
recall_cached_content工具按需召回原始内容
关键设计选择
- 内容寻址去重 —— 相同内容只存储一次,SHA256 哈希保证唯一性
- 高可逆性 —— 任意被缓存的内容都可以完整召回,没有信息损失
- 自动触发 —— 无需用户介入,系统按对话轮次自行处理
- Workspace 级隔离 —— 每个 Workspace 拥有独立的 cache 实例,由
builtin_context_cacheMCP server 管理
实际效果
设想一个有 80 次工具调用的会话,前 60 次的工具输出已经不在“活跃工作区”里。Cache 用几十字节的标记替换它们,释放出大量上下文空间,而 Agent 任何时候都依然可以“回看”任意历史输出。
Compact:把旧对话压缩为结构化摘要
Compact 解决的问题是:对话历史太长,但又不能直接全部丢掉。
触发条件
当 token 使用量达到上下文窗口的 85% 时(默认窗口大小:128K tokens),Compact 自动触发。还需满足额外条件:
- 当前没有正在进行的压缩操作
- 距上次压缩至少经过 60 秒(冷却期)
- 有足够多的历史消息可被压缩
压缩方式:“交接文档”格式
Compact 不是简单地截断或删除旧消息。它会调用 AI 生成结构化的交接文档摘要,包含六个章节:
| 摘要章节 | 内容 |
|---|---|
| 项目背景 | 项目类型、技术栈、关键架构信息 |
| 技术细节 | 已发现的重要技术事实与约束 |
| 已完成工作 | 至今完成的内容、关键决策与理由 |
| 当前问题 | 阻塞点和未解决的问题 |
| TODO 事项 | 接下来要做什么,并按优先级排列 |
| 用户偏好 | 用户表达过的风格、约束与特殊要求 |
这份摘要会作为一条 [Conversation History Summary] 消息注入对话历史,替换被压缩的旧消息。
三阶段加锁策略
为了避免压缩过程与正在进行的对话冲突,Compact 使用三阶段加锁策略:
- 加锁,读取数据 —— 获取锁,读取要压缩的消息
- 释放锁,调用 AI —— 释放锁,调用 AI 生成摘要(这一步耗时较长,不阻塞对话)
- 重新加锁,写回结果 —— 再次加锁,把摘要写入对话历史
这意味着用户在 Compact 生成摘要的同时可以继续正常对话——不会被阻塞。
Cache 与 Compact:何时用哪一个
| 维度 | Cache | Compact |
|---|---|---|
| 优化对象 | 大型工具输出的重复传输 | 过长的对话历史 |
| 可逆性 | ✅ 高——任何时候都可恢复完整原文 | ⚠️ 低——压缩为摘要后细节丢失 |
| 触发时机 | 基于对话轮次阈值 | token 用量达到窗口 85% |
| 存储方式 | 本地 KV cache(Pebble + SHA256) | 替换为摘要消息 |
| 用户感知 | 几乎不可见——Agent 自行决定何时召回 | 可能可见——早期细节会被摘要化 |
| 适用对象 | 文件内容、命令输出、搜索结果 | 已完成的讨论段落、早期推理 |
双策略协同的完整生命周期
会话开始
│
▼ 正常对话(所有内容都在上下文中)
│
├─ 工具输出不断累积...
│
▼ 轮次超过阈值 → Cache 启动
│ 早期工具输出 → cache 标记
│ 需要时 → recall_cached_content 取回
│
├─ 对话继续增长...
│
▼ token 达到窗口 85% → Compact 触发
│ 旧对话 → “交接文档”摘要
│ 最近对话保持完整
│
├─ 工作继续...
│
▼ 再次接近上限 → Compact 再次触发(60s 冷却之后)
│
└─ 会话可运行数小时 / 跨天
真实场景
场景:跨天的大规模重构任务
- 第 1 小时:理解代码结构,读了十几个文件 → Cache 开始存储早期工具输出
- 第 2 小时:形成方案,开始改动代码 → 上下文接近 85% → Compact 生成第一份交接摘要
- 第 3 小时:继续改动,遇到问题需要回看早期文件 → Agent 通过 Cache 召回
- 第二天:再次 Compact → 摘要更新 → 工作继续,关键上下文不丢失
整个过程中,用户无需手动管理任何东西。系统自动平衡上下文容量、信息保留与成本。
与其他能力的协同
与 SubAgent
SubAgent 在隔离的上下文中运行,拥有独立的 Cache/Compact 策略。子任务的中间工具输出永远不会进入主会话上下文——主会话只接收提炼后的摘要结果。这是另一种形式的“上下文保护”。
与 Workspace
Cache 与 Compact 都在 Workspace 级别运行——每个 Workspace 拥有独立的缓存存储与压缩策略。不同项目之间的上下文管理互不干扰。
相关文档
- 多 Agent 架构 —— SubAgent 如何与上下文管理协同
- Workspace 架构 —— Workspace 级的上下文隔离
- 功能总览 —— 返回核心能力总览