# Context 管理方案对比分析 > 对比 OpenCode、Codex 和 Gemini-cli 三个项目的 context 管理方案 --- ## 一、整体架构对比 | 维度 | **OpenCode** | **Codex** | **Gemini-cli** | |------|-------------|-----------|---------------| | **核心数据结构** | 线性 Message List | ContextManager (Vec) | Content[] (双版本) | | **消息历史版本** | 单一版本 | 单一版本 + GhostSnapshot | 精选版本 + 完整版本 | | **分层设计** | 无 | 无 | **✓ 三层**: Global → Environment → JIT | | **Plan 管理** | goal.json (计划中) + plan.md (参考) | SQLite + TodoListItem | 无 Plan 机制 | | **存储格式** | Storage Key-Value | JSONL + SQLite 混合 | JSON + 文本文件 | | **并发控制** | 未明确 | Arc + 文件锁 | Promise并发限制 | --- ## 二、Token 限制处理策略 ### 2.1 Token 估算方法 | 项目 | 估算策略 | 精度 | 实现位置 | |------|---------|------|---------| | **OpenCode** | 未详细说明,引用 Prune 阈值 | 中 | - | | **Codex** | **字节估算**: `bytes / 4` (1 token ≈ 4 bytes) | 低 | `truncate.rs::approx_token_count()` | | **Gemini-cli** | **启发式**: ASCII (0.25), 非ASCII (1.3), 图片 (3000), PDF (25800) | 高 | `tokenCalculation.ts::estimateTokenCountSync()` | **关键差异**: - **Codex**: 简单但快速,适合实时估算 - **Gemini-cli**: 更精确,区分字符类型和媒体,牺牲少量性能 ### 2.2 Token 限制阈值 | 项目 | 限制类型 | 阈值定义 | |------|---------|---------| | **OpenCode** | 删除阈值 | `PRUNE_MINIMUM = 20,000`, `PRUNE_PROTECT = 40,000` | | **Codex** | 模型限制 | 依赖模型配置,无固定值 | | **Gemini-cli** | 压缩阈值 | 默认 **50%** 模型限制 (`DEFAULT_COMPRESSION_TOKEN_THRESHOLD = 0.5`) | ### 2.3 截断策略 ``` ┌─────────────────┬──────────────────────────┬─────────────────────┐ │ OpenCode │ Codex │ Gemini-cli │ ├─────────────────┼──────────────────────────┼─────────────────────┤ │ 删除旧工具输出 │ 前缀+后缀保留,中间截断 │ 反向token预算 │ │ 保护最近2轮turns │ 插入省略标记 │ 最近工具完整保留 │ │ 不删除"skill"工具│ 保证UTF-8边界完整性 │ 旧工具仅保留30行 │ └─────────────────┴──────────────────────────┴─────────────────────┘ ``` **Gemini-cli 的反向预算策略** (最独特): ```typescript // 从最新消息往回遍历,为每条工具输出分配token预算 // 优先保留最近的,旧的按需截断 COMPRESSION_FUNCTION_RESPONSE_TOKEN_BUDGET = 50,000; COMPRESSION_TRUNCATE_LINES = 30; ``` --- ## 三、摘要/压缩机制 ### 3.1 压缩触发时机 | 项目 | 触发时机 | 方式 | |------|---------|------| | **OpenCode** | 事后 (context满时) | 被动压缩 | | **Codex** | 超过模型窗口时 | 自动压缩 | | **Gemini-cli** | **主动** (达到50%阈值) + **手动** (/compress) | 混合方式 | ### 3.2 压缩策略对比 #### OpenCode: 两阶段压缩 ``` 阶段1: Prune (清理旧工具输出) ├─ 从后向前遍历 ├─ 跳过最后2轮 ├─ 跳过已有summary的消息 └─ 删除量 > PRUNE_MINIMUM 时执行 阶段2: Full Compaction (上下文总结) ├─ 创建summary=true的assistant消息 ├─ 调用"compaction"专用agent └─ 提示词: "Provide a detailed prompt for continuing..." ``` #### Codex: 内联自动压缩 ``` 触发: run_inline_auto_compact_task() ├─ 生成摘要前缀 (SUMMARY_PREFIX) ├─ 使用SUMMARIZATION_PROMPT ├─ 保留GhostSnapshot (幽灵快照) └─ 替换历史记录为CompactedItem ``` **GhostSnapshot** (Codex独有): - 保留被压缩部分的"幽灵"引用 - 用户可查看但不会发送给模型 - 在UI中显示为折叠项 #### Gemini-cli: 三相智能压缩 ``` Phase 1: 历史分割 ├─ 保留最后30% (COMPRESSION_PRESERVE_THRESHOLD) └─ 压缩前70% Phase 2: 双重总结验证 ⭐ (独特) ├─ 第1次: 生成 ├─ 第2次: 自我批评 ("Did you omit any...") └─ 生成改进版本或确认原版本 Phase 3: 输出验证 ├─ 检查压缩后token数 < 原token数 └─ 失败则保持原历史 ``` **双重验证的价值**: ```typescript // 第一次生成 "Generate a state snapshot of the conversation..." // 第二次自我批评 "Did you omit any specific file content, code snippets, or context that might be needed later? If yes, provide an improved version. If no, confirm the original." ``` ### 3.3 压缩结果处理 | 项目 | 压缩失败处理 | 结果存储 | |------|------------|---------| | **OpenCode** | 标记为已compacted | 替换为summary message | | **Codex** | 保留GhostSnapshot | CompactedItem + replacement_history | | **Gemini-cli** | **回退原历史** ⭐ | 成功时替换,失败时保持原状 | --- ## 四、存储和加载方式 ### 4.1 存储架构 #### OpenCode (计划中) ``` .trace/{trace_id}/ ├── goal.json # Goal Tree (结构化plan) ├── messages.jsonl # 消息记录 (含 goal_id) └── meta.json # Trace 元数据 ``` #### Codex ``` ~/.codex/ ├── history.jsonl # 全局消息历史 ├── sessions/ │ ├── rollout-{timestamp}-{uuid}.jsonl # 会话回滚文件 │ └── ... └── state.db # SQLite状态数据库 ``` **关键特性**: - **原子写入**: 使用 `O_APPEND` 标志 - **并发安全**: Advisory文件锁 - **自动清理**: 超过限制时删除旧条目 (软限制80%) #### Gemini-cli ``` ~/.gemini/ ├── GEMINI.md # 全局内存 ├── tmp/{project_hash}/ │ └── chats/{session-ID}.json # 会话记录 └── config.json # 配置 项目根目录/ ├── GEMINI.md # 环境内存 └── subdirs/ └── GEMINI.md # JIT内存 (按需加载) ``` **独特的三层内存系统**: ``` Tier 1: Global Memory ├─ ~/.gemini/GEMINI.md └─ 用户级别,所有会话共享 Tier 2: Environment Memory ├─ 项目根目录的GEMINI.md ├─ 扩展提供的上下文文件 └─ MCP客户端指令 Tier 3: JIT Subdirectory Memory ⭐ ├─ 访问路径时动态发现 ├─ 向上遍历到项目根 ├─ 向下BFS搜索 (最多200目录) └─ 避免加载不相关上下文 ``` ### 4.2 加载策略对比 | 项目 | 加载时机 | 策略 | 并发控制 | |------|---------|------|---------| | **OpenCode** | 会话启动/恢复 | 按需加载 | 未明确 | | **Codex** | 启动时 | lookup(log_id, offset) | Arc + 文件锁 | | **Gemini-cli** | **分层+JIT** ⭐ | 全局(启动) + 环境(会话) + JIT(访问) | Promise并发限制 (10/20) | --- ## 五、Plan/Todo 机制 ### 5.1 数据结构对比 #### OpenCode (参考方案) ```typescript // plan.md (文本) - [ ] 分析代码 - [x] 实现功能 - [ ] 测试 // Todo.Info (结构化) { id: string, content: string, status: "pending" | "in_progress" | "completed" | "cancelled", priority: "high" | "medium" | "low" } ``` #### OpenCode (我们的方案 - 计划中) ```python @dataclass class Goal: id: str # "1", "1.1", "2" description: str status: Status # pending | in_progress | completed | abandoned summary: Optional[str] # done/abandon 时的总结 children: List["Goal"] @dataclass class GoalTree: mission: str current_id: Optional[str] goals: List[Goal] ``` **关键特性**: - **goal_id 关联**: 每条 message 记录它属于哪个 goal - **增量压缩**: goal 完成/放弃时压缩相关 messages - **精确回溯**: 基于 goal 的状态流转 #### Codex ```rust // TodoListItem in ResponseItem pub struct TodoListItem { todo_list: Vec, } pub struct TodoItem { task: String, completed: bool, } ``` **存储**: 作为 ResponseItem 的一部分,随对话历史一起管理 #### Gemini-cli **无专门 Plan 机制**,但有: - **会话记录**: 完整的 `ConversationRecord` - **目录跟踪**: `directories?: string[]` (会话中添加的目录) ### 5.2 执行与 Plan 的关联 | 项目 | 关联方式 | 可编辑性 | 可视化 | |------|---------|---------|--------| | **OpenCode (参考)** | 无结构化关联 | plan.md 可直接编辑 | 基础 | | **OpenCode (计划)** | message.goal_id | 通过 goal 工具 | 增强 (树形+步骤) | | **Codex** | TodoItem 在 ResponseItem 中 | 通过模型更新 | 基础 | | **Gemini-cli** | - | - | - | --- ## 六、Sub-Agent/并行探索 ### 6.1 Sub-Agent 支持 #### OpenCode (参考方案) ```typescript // Agent Mode - primary: 主代理,执行工具 - subagent: 子代理,独立context // 内置 Sub-Agents - general: 通用代理,可并行执行 - explore: 代码探索,仅查询工具 - compaction: 上下文总结 ``` **执行流程**: ``` 1. 创建 SubtaskPart 2. 子代理独立处理 (独立 message list) 3. 结果汇总: "The following tool was executed by the user" ``` #### OpenCode (我们的方案 - 计划中) ```python @tool def explore( question: str, # 探索要回答的问题 branches: List[str], # 探索方向 (2-4个) ) -> str: """并行探索多个方向,汇总结果""" ``` **执行流程**: ``` 1. 为每个探索方向创建独立的 Sub-Trace(完整的 Trace 结构) 2. 并行执行所有 Sub-Traces(使用 asyncio.gather) 3. 收集每个 Sub-Trace 的结论 4. 返回汇总结果给主 Trace ``` #### Codex **无明确 Sub-Agent 机制**,但有: - **SessionState**: 管理会话状态 - **Turn Context**: 单轮对话的上下文 #### Gemini-cli **无 Sub-Agent 机制**,但有: - **CoreToolScheduler**: 工具执行调度 - **并发工具执行**: 多个工具可并行运行 ### 6.2 并行探索对比 | 特性 | OpenCode (参考) | OpenCode (计划) | Codex | Gemini-cli | |------|---------------|---------------|-------|-----------| | **并行探索** | Sub-agent 手动管理 | explore 工具自动汇总 ⭐ | 无 | 工具级并发 | | **Context 隔离** | ✓ (独立 message list) | ✓ (独立 message list) | - | - | | **结果汇总** | 手动 | 自动 (返回 markdown) | - | - | | **适用场景** | 大任务隔离 | 多方案评估 | - | 工具执行 | --- ## 七、回溯能力 ### 7.1 回溯机制对比 #### OpenCode (参考方案) ``` 限制: 有限的回溯能力 - 无精确状态保存 - 依赖压缩后的摘要 ``` #### OpenCode (我们的方案 - 计划中) ```python goal(abandon="方案A需要Redis,环境没有", add="实现方案B") ``` **回溯流程**: ``` Before: Messages: [分析代码的 20 条 message...] [实现方案 A 的 30 条 message...] ← 这些要压缩 [测试失败的 message...] After: Messages: [分析代码的 20 条 message...] [Summary: "尝试方案A,因依赖问题失败"] ← 压缩为1条 [开始方案B的 message...] Plan: [✓] 1. 分析代码 [✗] 2. 实现方案A (abandoned: 依赖问题) [→] 2'. 实现方案B ``` **优势**: - **精确回溯**: 基于 goal 的状态标记 - **保留失败原因**: summary 包含 abandon 原因 - **压缩旧路径**: 失败尝试不占用大量 context #### Codex ```rust // GhostSnapshot: 保留被压缩部分的引用 pub struct CompactedItem { message: String, replacement_history: Option>, } ``` **回溯能力**: - **GhostSnapshot**: 用户可查看历史,但不发送给模型 - **Rollout 记录**: 完整的会话记录保存在 JSONL - **用户转换检测**: 可定位到特定用户消息 #### Gemini-cli ```typescript enum CompressionStatus { COMPRESSED, COMPRESSION_FAILED_INFLATED_TOKEN_COUNT, // 压缩反而增加 COMPRESSION_FAILED_EMPTY_SUMMARY, // 摘要为空 NOOP, } ``` **回溯能力**: - **会话记录**: 完整的 `ConversationRecord` 保存所有消息 - **压缩失败回退**: 自动回退到原历史 - **无结构化回溯**: 缺乏基于任务的回溯机制 ### 7.2 回溯对比表 | 项目 | 回溯粒度 | 状态保存 | 失败处理 | 历史查看 | |------|---------|---------|---------|---------| | **OpenCode (参考)** | 粗粒度 | 摘要 | 有限 | 基础 | | **OpenCode (计划)** | **goal级别** ⭐ | goal.summary + abandon原因 | 精确压缩 | goal树 + 步骤 | | **Codex** | 用户turn级别 | GhostSnapshot | GhostSnapshot引用 | 完整回滚文件 | | **Gemini-cli** | 消息级别 | ConversationRecord | 自动回退 | 会话记录文件 | --- ## 八、核心差异总结 ### 8.1 设计哲学 | 项目 | 核心理念 | 优势场景 | |------|---------|---------| | **OpenCode** | **结构化计划驱动** | 复杂任务,需要回溯和探索 | | **Codex** | **简单高效,成熟稳定** | 通用编码助手,快速响应 | | **Gemini-cli** | **分层智能,高保真保留** | 多项目管理,长期会话 | ### 8.2 独特创新点 #### OpenCode (我们的方案) 1. **goal 工具**: 结构化 Plan + 执行关联 2. **explore 工具**: 并行探索自动汇总 3. **增量压缩**: goal 完成/放弃时压缩,而非事后被动 4. **精确回溯**: abandon + 状态流转 #### Codex 1. **GhostSnapshot**: 压缩历史仍可查看 2. **原子写入**: O_APPEND + 并发安全 3. **字节估算**: 简单快速 (bytes/4) 4. **历史规范化**: 确保调用-输出对完整性 #### Gemini-cli 1. **三层内存**: Global → Environment → JIT ⭐ 2. **双重验证**: 自我批评式压缩 3. **反向token预算**: 优先保留最近工具输出 4. **启发式token估算**: 区分字符类型和媒体 5. **JIT Context发现**: 按需加载相关GEMINI.md ### 8.3 技术选型对比 | 技术点 | OpenCode | Codex | Gemini-cli | |--------|---------|-------|-----------| | **语言** | TypeScript | Rust | TypeScript | | **存储** | Storage KV | JSONL + SQLite | JSON + 文本 | | **并发** | 未明确 | Arc + 文件锁 | Promise限制 | | **token估算** | 未详述 | bytes/4 | 启发式 (区分类型) | | **压缩策略** | 两阶段 | 内联自动 | 三相智能 | --- ## 九、与 OpenCode 方案的详细对比 ### 9.1 OpenCode vs Codex | 方面 | OpenCode (参考) | Codex | 评估 | |------|---------------|-------|------| | **Plan格式** | 纯文本 (plan.md) | TodoItem (结构化) | Codex更结构化,但OpenCode计划中的goal.json更强 | | **Plan与执行关联** | 无 | TodoItem在ResponseItem中 | Codex有关联,但OpenCode计划中的goal_id更精确 | | **压缩时机** | 事后 (满时) | 事后 (超过窗口) | 相同 (被动) | | **并行探索** | Sub-agent (手动) | 无 | OpenCode参考方案更强,计划方案的explore更自动化 | | **回溯能力** | 有限 | GhostSnapshot | Codex的GhostSnapshot有价值,但OpenCode计划的goal-based更精确 | | **存储可靠性** | 未明确 | 原子写入+并发安全 | **Codex胜** ⭐ | | **工具复杂度** | todoread/todowrite | 无专门工具 | OpenCode参考方案更复杂,计划的goal/explore更简洁 | **可借鉴**: - ✓ Codex的原子写入和并发安全机制 - ✓ GhostSnapshot的用户友好性 (可查看但不发送) - ✓ 历史规范化 (ensure_call_outputs_present) ### 9.2 OpenCode vs Gemini-cli | 方面 | OpenCode (参考) | Gemini-cli | 评估 | |------|---------------|-----------|------| | **Plan格式** | plan.md + Todo.Info | 无 | **OpenCode胜** | | **Plan与执行关联** | 无 | 无 | 平局 | | **压缩时机** | 事后 (满时) | **主动** (50%阈值) | **Gemini-cli胜** ⭐ | | **并行探索** | Sub-agent (手动) | 工具级并发 | OpenCode的Sub-agent隔离更好 | | **回溯能力** | 有限 | 自动回退 | OpenCode计划方案的goal-based更强 | | **Context分层** | 无 | **三层** (Global/Env/JIT) | **Gemini-cli胜** ⭐ | | **压缩质量** | 单次生成 | **双重验证** (自我批评) | **Gemini-cli胜** ⭐ | | **工具输出保留** | 删除旧输出 | **反向预算** (保留最近) | **Gemini-cli胜** ⭐ | **可借鉴**: - ✓ 三层内存系统 (特别是JIT加载) - ✓ 双重验证的压缩机制 - ✓ 主动压缩 (50%阈值,而非等到满) - ✓ 反向token预算 (优先保留最近工具输出) - ✓ 启发式token估算 (区分字符类型) --- ## 十、OpenCode 计划方案的优势 ### 10.1 创新点 1. **结构化 Plan (goal.json)** - 比纯文本更精确 - 支持树形结构 (goal.children) - 状态流转清晰 2. **执行与 Plan 的强关联 (goal_id)** - 每条 message 知道它属于哪个 goal - 支持基于 goal 的压缩和回溯 - 可视化时能展示 goal + 对应步骤 3. **增量压缩 (goal 完成/放弃时)** - 比事后被动压缩更主动 - 压缩粒度可控 (按 goal) - 保留失败原因 (abandon summary) 4. **explore 工具 (并行探索自动汇总)** - 比手动管理 Sub-agent 更简单 - 适合多方案评估场景 - 自动生成汇总报告 5. **精确回溯 (abandon + 状态流转)** - 比 GhostSnapshot 更结构化 - 支持从失败尝试中学习 - Plan 树中保留失败路径 ### 10.2 待改进点 (可借鉴其他方案) 1. **存储可靠性** (借鉴 Codex) - 原子写入 - 并发安全 (文件锁) - 自动清理旧数据 2. **Context 分层** (借鉴 Gemini-cli) - 全局 context (用户级别) - 项目 context (项目级别) - JIT context (按需加载) 3. **压缩质量** (借鉴 Gemini-cli) - 双重验证 (自我批评) - 压缩失败自动回退 - 验证压缩后 token 数真的减少 4. **主动压缩** (借鉴 Gemini-cli) - 达到阈值 (如 50%) 时主动压缩 - 而非等到 context 满 5. **工具输出管理** (借鉴 Gemini-cli) - 反向 token 预算 - 优先保留最近工具输出的完整性 - 旧输出智能截断 (保留最后N行) 6. **Token 估算** (借鉴 Gemini-cli) - 启发式估算 (区分 ASCII/非ASCII/媒体) - 提高估算精度 7. **用户友好性** (借鉴 Codex) - GhostSnapshot 机制 (可查看但不发送) - 历史规范化 (保证调用-输出对完整性) --- ## 十一、实现建议 ### 11.1 Phase 1: 核心 goal 工具 (保留计划) - Goal 数据结构 - goal 工具 (add, done, focus) - Plan 注入到 system prompt - 基础可视化 ### 11.2 Phase 2: 增强存储和压缩 (借鉴) - **存储增强** (借鉴 Codex): - 原子写入和并发安全 - 自动清理机制 - **压缩增强** (借鉴 Gemini-cli): - 双重验证机制 - 主动压缩 (50%阈值) - 反向token预算 ### 11.3 Phase 3: 回溯和 Context 分层 - **回溯支持** (计划): - abandon 操作 - Message 关联 goal_id - 基于 goal 的 context 压缩 - **Context 分层** (借鉴 Gemini-cli): - 全局 context 文件 - 项目 context 文件 - JIT 子目录 context 发现 ### 11.4 Phase 4: 并行探索和优化 - **explore 工具** (计划): - 独立 message list 管理 - 结果汇总机制 - **优化** (借鉴): - GhostSnapshot (用户友好) - 启发式 token 估算 - 历史规范化 --- ## 十二、总结 ### 12.1 三方案对比矩阵 | 能力维度 | OpenCode (计划) | Codex | Gemini-cli | 最佳方案 | |---------|---------------|-------|-----------|---------| | **结构化 Plan** | ⭐⭐⭐ goal.json | ⭐⭐ TodoItem | ⭐ 无 | OpenCode | | **执行关联** | ⭐⭐⭐ goal_id | ⭐⭐ 弱关联 | ⭐ 无 | OpenCode | | **压缩策略** | ⭐⭐ 增量 | ⭐⭐ 自动 | ⭐⭐⭐ 三相智能 | Gemini-cli | | **压缩时机** | ⭐⭐ goal完成时 | ⭐ 被动 | ⭐⭐⭐ 主动50% | Gemini-cli | | **并行探索** | ⭐⭐⭐ explore工具 | ⭐ 无 | ⭐⭐ 工具级 | OpenCode | | **回溯能力** | ⭐⭐⭐ goal-based | ⭐⭐ GhostSnapshot | ⭐⭐ 会话记录 | OpenCode | | **存储可靠性** | ⭐⭐ 未明确 | ⭐⭐⭐ 原子+锁 | ⭐⭐ Promise限制 | Codex | | **Context分层** | ⭐ 无 | ⭐ 无 | ⭐⭐⭐ 三层JIT | Gemini-cli | | **工具输出管理** | ⭐ 删除旧的 | ⭐⭐ 截断 | ⭐⭐⭐ 反向预算 | Gemini-cli | | **Token估算** | ⭐⭐ 基础 | ⭐ bytes/4 | ⭐⭐⭐ 启发式 | Gemini-cli | **评分说明**: ⭐ 基础, ⭐⭐ 良好, ⭐⭐⭐ 优秀 ### 12.2 最终建议 **OpenCode 的核心优势** (保留并强化): - ✅ 结构化 goal.json - ✅ goal_id 关联 - ✅ explore 工具 - ✅ 精确回溯 **应借鉴的关键特性**: 1. **Gemini-cli 的压缩机制**: 双重验证 + 主动压缩 + 反向预算 2. **Gemini-cli 的分层 Context**: 特别是 JIT 加载 3. **Codex 的存储可靠性**: 原子写入 + 并发安全 4. **Codex 的 GhostSnapshot**: 提升用户体验 **综合方案** (OpenCode + 借鉴): ``` OpenCode 计划方案 ├─ 保留: goal.json, explore工具, goal-based回溯 ├─ 增强压缩: Gemini-cli的双重验证 + 主动压缩 ├─ 增强存储: Codex的原子写入 + 并发安全 ├─ 增强Context: Gemini-cli的三层分层 + JIT加载 └─ 增强UX: Codex的GhostSnapshot ``` 这将是一个**结构化驱动 + 智能压缩 + 可靠存储 + 分层Context**的综合方案,集三家之长! 🎯