Skip to content

OpenCode 解决上下文问题的核心技术手段 #7

@phantom5099

Description

@phantom5099

OpenCode 解决上下文问题的核心技术手段

1. 动态会话压缩与剪枝 (Session Compaction & Pruning)

这是 OpenCode 最具工业级特色的方案,位于 session/compaction.ts 。

  • 自动溢出检测 :通过 isOverflow 函数实时监控当前 Token 消耗。它预留了一个 COMPACTION_BUFFER (20,000 Token),一旦总消耗接近模型限制,就会触发压缩。
  • 工具调用剪枝 (Pruning) :
    • 逆向回溯策略 :从最新的消息往回扫描,保留最近的 40,000 Token。
    • 非破坏性擦除 :对于较早的、不再关键的工具输出(如之前的 ls 或 grep 结果),系统会将 part.state.time.compacted 标记为当前时间,并在发送给 LLM 时剔除这些冗长的输出内容。
    • 特权保护 :特定的工具(如 skill )会被保护,其输出不会被剪枝,以保证 Agent 的核心能力不丢失。

2. 响应截断与分流策略 (Truncation Strategy)

位于 tool/truncation.ts ,解决单次工具调用输出过大的问题。

  • 硬限阈值 :单次输出严格限制在 2,000 行 或 50 KB 。
  • 本地缓存分流 :如果工具输出(如执行测试的结果)超过阈值,系统会将完整内容写入本地磁盘( tool-output 目录),仅在上下文中返回一个“摘要+预览”。
  • 引导式感知 :在截断后的提示词中,系统会显式引导 Agent:“输出已截断,完整内容已存至 X 路径。请使用 grep 或 read (带有 offset/limit) 来分段查看”。

3. 结构化代码感知 (Semantic Context via LSP)

不同于 SWE-agent 这种主要依赖 shell 读文件的项目,OpenCode 深度集成了 LSP。

  • 符号替代文本 :当 Agent 需要了解某个类或函数时,OpenCode 优先提供符号定义和类型签名,而不是把整个源文件塞进上下文。
  • 按需读取 : tool/read.ts 默认带有 limit 参数(2000行),并支持 offset 。Agent 习惯于“翻页式”阅读,极大地节省了 Token。

4. 智能过滤与忽略 (Smart Filtering)

  • 全链路忽略 :在 file/ignore.ts 中定义了工业级通用的 FOLDERS 和 FILES 黑名单(如 node_modules 、 .git 、 dist 、 target 等)。
  • 搜索限额 :在 tool/ls.ts 中,文件列表被硬限制在 100 个 。如果目录太深,Agent 必须通过多次、具体的 ls 来探索,避免一次性加载数万个文件路径。

5. 任务聚焦机制 (Task/Todo Focused)

  • Todo 维持 : session/todo.ts 让 Agent 始终维护一份“待办清单”。
  • 作用 :即使历史消息被剪枝,Agent 只要看到最新的 Todo 列表,就能找回执行状态,避免因上下文丢失而导致的“原地打转”。

如何平衡记忆

1. 工业级持久化存储 (Structured Persistence)

OpenCode 没有将对话存在内存中,而是使用了 SQLite (Drizzle ORM) 进行物理持久化(见 session.sql.ts )。

  • 多级表结构 :分为 SessionTable (会话)、 MessageTable (单条消息)和 PartTable (消息内部的片段,如 Tool Call 或文本)。
  • 作用 :这意味着即使你关闭 IDE 再打开,甚至 Agent 进程崩溃,它也能从数据库中精准恢复每一条对话历史。

2. 动态摘要机制 (Session Summarization)

为了防止历史对话太长占用过多 Token,OpenCode 引入了 Summary 机制 (见 session/summary.ts )。

  • 关键差异化记忆 :它不仅仅是总结文本,还会计算 Diffs (代码变更摘要)。系统会记录该 Session 期间修改了哪些文件、增加了多少行、删除了多少行。
  • 快照关联 :摘要会与 Git 的 Snapshot 关联。当对话太长被剪枝(Pruning)时,Agent 仍然能通过 summary_diffs 字段知道之前“做了什么”,而不需要重读整个对话过程。

3. 跨会话的“元记忆”:Todo 机制

这是 OpenCode 保持长期任务记忆的神技。

  • Todo 表 (TodoTable) :在数据库中独立维护一个任务清单(见 session.sql.ts#L86 )。
  • 逻辑闭环 :每轮对话开始时,System Prompt 会注入当前的 Todo 列表。
  • 解决的问题 :如果对话历史因为太长被剪枝了,Agent 可能会忘记“接下来该干嘛”。但 Todo 列表是持久化且每轮必读的,它充当了 Agent 的 “工作记忆(Working Memory)” ,确保任务目标不漂移。

4. 环境感知的 System Prompt (Environment Awareness)

在 session/system.ts 中,每一轮对话都会动态构建一个环境块:

  • 实时注入 :包括当前工作目录、Git 仓库状态、甚至当前的日期。
  • 作用 :这让 Agent 始终记得自己“身处何处”,避免因为对话太久而忘记了自己是在 Windows 还是 Linux 下工作,或者忘记了当前项目的根目录。

5. 自动重试与回滚 (Retry & Revert)

记忆不仅包括“说了什么”,还包括“做错了什么”。

  • Revert 记录 : SessionTable 中有一个 revert 字段,记录了回滚的信息。
  • 记忆逻辑 :当 Agent 的一次尝试失败并回滚时,这个动作会被记录。在下一轮对话中,Agent 会“记得”之前的路径行不通,从而尝试新的方案

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions