背景
使用 OpenCode + STDD 开发脚本做长任务对话时,上下文从 2 万 token 不断增长到 40 万 token,处理越来越慢。这是 LLM 无状态架构的固有问题——模型本身不记住任何东西,每次调用都是独立请求,"记忆"靠把历史塞进 prompt 实现。
核心约束
LLM 本质上是 无状态的——每次调用都是独立请求。让模型"记住"之前说过什么,唯一可靠的方式就是把历史塞进 prompt。在这个物理约束下,各框架的策略分化为几个流派。
主流 AI 编码框架的上下文管理策略
| 框架 | 策略 | 有效上限 | 优点 | 缺点 |
|---|---|---|---|---|
| OpenCode | 完整积累 | 模型窗口上限 | 无信息丢失 | 线性增长,20K→400K |
| Claude Code (boot mode) | 滑动窗口 + 内容压缩 | ~200K(自动压缩) | 中后期明显更快 | 早期决策信息可能丢失 |
| Claude Code (normal) | 完整积累 + 文件内容按需注入 | 模型窗口 | 文件内容不计入对话开销 | 对话本身仍增长 |
| Cursor | 完整积累 + @文件引用 | 模型窗口 | 用户控制上下文内容 | @引用越多越重 |
| Aider | repo-map + 完整对话历史 | 模型窗口 | repo-map 压缩了项目结构 | 对话历史仍然完整积累 |
| GitHub Copilot Chat | 激进截断(~8K tokens) | 很小 | 永远快 | 经常"失忆" |
| Continue.dev | 聊天历史完整 + 检索增强 | 模型窗口 | @-mention 精准引用 | 对话本身无压缩 |
| LangChain Agent | 可配置 Memory 类型 | 自定义 | 灵活(滑动窗口/摘要/向量检索) | 配置复杂,需自己维护 |
| Hermes Agent | compressor 引擎 + 外部记忆工具 | 模型窗口(压缩后 ~10%) | 可配阈值/压缩比;外加 memory/session_search/fact_store | 压缩用辅助模型(额外 token 开销) |
为什么大多数框架选择"完整积累"?
这是最安全的默认值:
- 信息完整:任何一条历史消息都可能包含决策依据、用户偏好、代码上下文。丢失它 = 模型做出错误决定的概率上升
- 实现简单:append message → call API,没有复杂的压缩/检索逻辑
- LLM 对位置不敏感(相对而言):现代模型(尤其是 128K+ 窗口)对处于中间的内容仍然能有效利用
代价就是——40 万 token 的对话,推理延迟 = 预填充时间爆炸 + 采样步数不变,两者叠加导致感受上的"越来越慢"。
少数有智能上下文管理的框架
1. Claude Code(Anthropic)
是目前主流编码代理中上下文管理最成熟的。
- 有 token budget:接近窗口上限时自动压缩/删除低优先级消息
- 区分"对话历史"和"工作文件":文件的当前状态单独追踪,不计入对话积累
- 内部使用重要性评分决定哪些消息可被丢弃(用户指令 > 工具输出 > 确认消息)
- 支持分叉/恢复会话:用
-r从摘要恢复对话
2. LangChain Memory Types(概念参考)
ConversationBufferMemory— 完整保留(基础模式)ConversationSummaryMemory— 定期摘要ConversationSummaryBufferMemory— 混合:近 N 条完整 + 之前摘要ConversationTokenBufferMemory— token 超过预算时丢弃最旧VectorStoreRetrieverMemory— 每次查询检索最相关的历史
3. Hermes Agent(当前环境)
Hermes 内置了 compressor 上下文压缩引擎,通过辅助模型对早期对话进行智能摘要,而非简单截断。关键参数:
compression.enabled: true— 压缩功能已启用compression.threshold: 0.9— 上下文达到模型窗口 90% 时触发压缩compression.target_ratio: 0.1— 压缩后只保留原上下文量的 10%compression.protect_last_n: 20— 保护最近 20 条消息不被压缩(保留即时交互上下文)compression.protect_first_n: 3— 保护前 3 条消息(system prompt 等)compression.hygiene_hard_message_limit: 400— 硬性消息数上限context.engine: compressor— 明确使用 compressor 引擎
压缩模型独立配置(当前使用本地 V100 + Qwen3.5-27B),不占用主模型的推理资源。
此外还提供了外部记忆工具来减轻积累压力:
memory— 跨会话持久偏好fact_store— 结构化实体记忆(实体解析 + 信任评分)session_search— FTS5 全文检索历史会话skill_manage— 过程性知识独立存储
这意味着 Hermes 在三层维度管理上下文:① compressor 主动压缩当前对话;② memory/fact_store 持久化跨会话知识;③ skill 解除过程性知识对对话窗口的依赖。
对 OpenCode + STDD 工作流的实用建议
A. 分阶段执行(最有效的武器)
STDD 的 Gate(阶段门禁)天然适合分阶段:
Spec 阶段 → 存档/reset → 下一阶段
每个阶段开新 session,参考前一阶段的产出文件。不需要把整个项目的对话历史背在身上。
B. 利用文件系统作为状态载体
OpenCode 能看到文件系统上的文件——把决策写进 .md 文件,读它比从对话历史里回溯更高效:
决策记录 → specs/decision-log.md
接口契约 → specs/api-contract.md
当前状态 → specs/current-phase.md
C. delegate_task 子代理
Hermes 的 delegate_task 机制就是为此设计的——子代理在独立上下文中完成任务,不污染主会话上下文。OpenCode 是否有类似能力取决于它的实现。
D. 检查 OpenCode 的配置选项
如果 OpenCode fork 有 max_tokens 或 context_window 相关配置项,可以尝试设置上限。部分 fork 支持自动裁剪超出的历史。
结论
| 你的预期 | 现实 |
|---|---|
| 框架应有智能上下文管理 | 绝大多数框架不做,因为完整 = 安全 |
| 对话越长应该越智能 | 相反,长→慢→质量不稳定 |
| 有框架能自动管理 | Claude Code 做得最好,其次 Hermes(compressor 引擎 + 外部记忆),LangChain 可配但需自己维护 |
Claude Code 是目前唯一在"智能上下文管理"上花了真功夫的编码代理。Hermes 的 compressor 引擎加上三层管理维度(压缩 + 持久记忆 + 技能)是另一个完整的解决方案。其他框架(包括 OpenCode、Cursor、Aider)基本都采用完整积累策略,差异主要在文件上下文的管理方式上。
对于 STDD + OpenCode 工作流,最有效的策略是分阶段执行 + 用文件系统做状态持久化,而不是依赖框架自动管理上下文。这不是工具选错了——这是整个行业的现状。