context-comparison.md 21 KB

Context 管理方案对比分析

对比 OpenCode、Codex 和 Gemini-cli 三个项目的 context 管理方案


一、整体架构对比


二、Token 限制处理策略

2.1 Token 估算方法

维度 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并发限制
项目 估算策略 精度 实现位置
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 的反向预算策略 (最独特):

// 从最新消息往回遍历,为每条工具输出分配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次: 生成 <state_snapshot>
  ├─ 第2次: 自我批评 ("Did you omit any...")
  └─ 生成改进版本或确认原版本

Phase 3: 输出验证
  ├─ 检查压缩后token数 < 原token数
  └─ 失败则保持原历史

双重验证的价值:

// 第一次生成
"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 加载策略对比


五、Plan/Todo 机制

5.1 数据结构对比

OpenCode (参考方案)

// plan.md (文本)
- [ ] 分析代码
- [x] 实现功能
- [ ] 测试

// Todo.Info (结构化)
{
  id: string,
  content: string,
  status: "pending" | "in_progress" | "completed" | "cancelled",
  priority: "high" | "medium" | "low"
}

OpenCode (我们的方案 - 计划中)

@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

// TodoListItem in ResponseItem
pub struct TodoListItem {
    todo_list: Vec<TodoItem>,
}

pub struct TodoItem {
    task: String,
    completed: bool,
}

存储: 作为 ResponseItem 的一部分,随对话历史一起管理

Gemini-cli

无专门 Plan 机制,但有:

  • 会话记录: 完整的 ConversationRecord
  • 目录跟踪: directories?: string[] (会话中添加的目录)

5.2 执行与 Plan 的关联

项目 加载时机 策略 并发控制
OpenCode 会话启动/恢复 按需加载 未明确
Codex 启动时 lookup(log_id, offset) Arc + 文件锁
Gemini-cli 分层+JIT 全局(启动) + 环境(会话) + JIT(访问) Promise并发限制 (10/20)
项目 关联方式 可编辑性 可视化
OpenCode (参考) 无结构化关联 plan.md 可直接编辑 基础
OpenCode (计划) message.goal_id 通过 goal 工具 增强 (树形+步骤)
Codex TodoItem 在 ResponseItem 中 通过模型更新 基础
Gemini-cli - - -

六、Sub-Agent/并行探索

6.1 Sub-Agent 支持

OpenCode (参考方案)

// 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 (我们的方案 - 计划中)

@tool
def explore(
    question: str,           # 探索要回答的问题
    branches: List[str],     # 探索方向 (2-4个)
) -> str:
    """并行探索多个方向,汇总结果"""

执行流程:

1. 为每个 branch 创建独立 message list
2. 串行执行每个 branch (各自调用 LLM + 工具)
3. 收集每个 branch 的结论
4. 返回汇总结果给主会话

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 (我们的方案 - 计划中)

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

// GhostSnapshot: 保留被压缩部分的引用
pub struct CompactedItem {
    message: String,
    replacement_history: Option<Vec<ResponseItem>>,
}

回溯能力:

  • GhostSnapshot: 用户可查看历史,但不发送给模型
  • Rollout 记录: 完整的会话记录保存在 JSONL
  • 用户转换检测: 可定位到特定用户消息

Gemini-cli

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 方案的详细对比

9.1 OpenCode vs Codex

技术点 OpenCode Codex Gemini-cli
语言 TypeScript Rust TypeScript
存储 Storage KV JSONL + SQLite JSON + 文本
并发 未明确 Arc + 文件锁 Promise限制
token估算 未详述 bytes/4 启发式 (区分类型)
压缩策略 两阶段 内联自动 三相智能
方面 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的综合方案,集三家之长! 🎯