From 83f7f4193c72b460e2501709161f79794f75b323 Mon Sep 17 00:00:00 2001 From: wenshao Date: Mon, 30 Mar 2026 04:28:52 +0800 Subject: [PATCH 1/7] =?UTF-8?q?=E9=9B=86=E4=B8=AD=E7=AE=A1=E7=90=86?= =?UTF-8?q?=E5=8A=A8=E6=80=81=E6=96=87=E6=A1=A3=E5=85=83=E6=95=B0=E6=8D=AE?= =?UTF-8?q?=E5=B9=B6=E8=A1=A5=E5=85=85=E6=A0=A1=E9=AA=8C=E5=B7=A5=E4=BD=9C?= =?UTF-8?q?=E6=B5=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Qwen-Coder --- CONTRIBUTING.md | 12 + README.md | 71 +++-- docs/SUMMARY.md | 11 +- docs/comparison/features.md | 2 +- docs/comparison/pricing.md | 32 +- docs/comparison/privacy-telemetry.md | 34 +- docs/comparison/system-requirements.md | 26 +- docs/data/CHANGELOG.md | 27 ++ docs/data/README.md | 77 +++++ docs/data/SCHEMA.md | 155 +++++++++ docs/data/agents-metadata.json | 415 +++++++++++++++++++++++++ docs/data/agents-metadata.schema.json | 166 ++++++++++ docs/evidence-index.md | 83 +++++ docs/guides/getting-started.md | 2 +- docs/tools/README.md | 4 +- scripts/check_all.py | 32 ++ scripts/check_data_schema.py | 161 ++++++++++ scripts/check_repo_consistency.py | 125 ++++++++ scripts/check_stale_data.py | 157 ++++++++++ 19 files changed, 1505 insertions(+), 87 deletions(-) create mode 100644 docs/data/CHANGELOG.md create mode 100644 docs/data/README.md create mode 100644 docs/data/SCHEMA.md create mode 100644 docs/data/agents-metadata.json create mode 100644 docs/data/agents-metadata.schema.json create mode 100644 docs/evidence-index.md create mode 100644 scripts/check_all.py create mode 100644 scripts/check_data_schema.py create mode 100644 scripts/check_repo_consistency.py create mode 100644 scripts/check_stale_data.py diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 187b9fc7..10079678 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -28,6 +28,12 @@ - 用新数据更新基准测试 - 修正不准确之处 - 提高清晰度 +- 如果涉及动态指标(Stars、下载量、价格、验证日期),优先更新 `docs/data/agents-metadata.json` +- 修改数据层前,先核对 `docs/data/SCHEMA.md` +- 如果动态数据发生变更,同步更新 `docs/data/CHANGELOG.md` +- 如果涉及证据完备度变化,同步更新 `docs/evidence-index.md` +- 提交前优先运行统一检查:`python3 scripts/check_all.py` +- 如需单独执行,可运行:`python3 scripts/check_data_schema.py`、`python3 scripts/check_repo_consistency.py` 和 `python3 scripts/check_stale_data.py` ### 3. 添加示例 @@ -160,6 +166,12 @@ - [ ] 信息准确 - [ ] 写作清晰中立 - [ ] 无不必要的格式更改 +- [ ] 动态数据已同步到 `docs/data/agents-metadata.json`(如适用) +- [ ] 已核对 `docs/data/SCHEMA.md`(如适用) +- [ ] 动态数据变更已记录到 `docs/data/CHANGELOG.md`(如适用) +- [ ] 证据状态已同步到 `docs/evidence-index.md`(如适用) +- [ ] 已运行 `python3 scripts/check_all.py` +- [ ] 如有需要,已分别运行 `python3 scripts/check_data_schema.py`、`python3 scripts/check_repo_consistency.py` 和 `python3 scripts/check_stale_data.py` ## 我们希望覆盖的领域 diff --git a/README.md b/README.md index 2a7f3533..95839772 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,8 @@ **👉 [一页总结(选型速查)](./docs/SUMMARY.md)** — 给没时间看全部文档的人 +> **维护说明**:高频变化的数据(Stars、下载量、价格、验证日期)开始统一沉淀到 [`docs/data/`](./docs/data/README.md)。证据完备度与验证状态见 [`docs/evidence-index.md`](./docs/evidence-index.md)。 + ## 核心发现 ### 源码分析纠正的"常识" @@ -29,26 +31,21 @@ > Rust 二进制(50ms)比 Node.js SEA(72ms)快 30%,比 npm 包(1.5s)快 **30 倍**。Qwen Code 作为 Gemini CLI 分叉,安装仅 48MB(上游 509MB 的 9%),启动快 2.5 倍。 -### 实际采用量(2026-03-26 API 实时查询) - -| Agent | npm 周下载 | 4 周趋势 | Stars | 版本数 | 首发 | -|-------|-----------|---------|-------|-------|------| -| **Claude Code** | **1,020 万** | 934→951→987→1,020 万 ↑ | 83k | 359 | 2025-02 | -| **Codex CLI** | **368 万** | 214→275→356→368 万 ↑↑ | 68k | 1,543 | 2025-04 | -| **Gemini CLI** | 74 万 | 76→66→73→74 万 → | **99k** | 539 | 2025-06 | -| **Copilot CLI** | 64 万 | 19→25→42→64 万 **↑↑↑** | 10k | 588 | 2025-09 | -| **Qwen Code** | 8.4 万 | 6→16→11→8.4 万 ↑ | 21k | 353 | 2025-07 | +### 实际采用量(汇总入口) -| Agent | PyPI 月下载 | Stars | -|-------|-----------|-------| -| **OpenHands** | **125 万** | 70k | -| **Aider** | 78 万 | 42k | -| **Kimi CLI** | 45 万 | 7k | -| **OpenCode** | — | **130k** | +> 高频变化数据已集中维护在 [`docs/data/agents-metadata.json`](./docs/data/agents-metadata.json)。 +> +> 当前 README 仅保留结论性摘要,详细数字、验证日期和证据状态请查看: +> - [`docs/data/agents-metadata.json`](./docs/data/agents-metadata.json) +> - [`docs/evidence-index.md`](./docs/evidence-index.md) +> - [`docs/comparison/evolution-community.md`](./docs/comparison/evolution-community.md) -> **Stars ≠ 采用**:Gemini CLI Stars(99k)是 Claude Code(83k)的 1.2 倍,但 npm 下载仅其 **7%**。Copilot CLI 增长最猛(4 周 ↑240%)。 +- Claude Code、Codex CLI 在 npm 生态采用量领先 +- Gemini CLI 社区热度高,但采用量与 Claude Code 不完全同步 +- Qwen Code、Kimi CLI 在中文开发者语境下增长明显 +- OpenHands、Aider 在 Python / research-oriented 场景保持稳定关注度 -*数据来源:[npm Registry API](https://api.npmjs.org/)、[PyPI Stats](https://pypistats.org/)、`gh api`* +*数据来源:[npm Registry API](https://api.npmjs.org/)、[PyPI Stats](https://pypistats.org/)、`gh api`;具体数值请以 `docs/data/agents-metadata.json` 为准。* --- @@ -59,7 +56,7 @@ | **日常编码** | Claude Code 或 Aider | 最强推理 / 最好 Git 集成 | | **免费使用** | Qwen Code 或 Gemini CLI | 1000 次/天免费 OAuth / Google 账号 | | **多模型切换** | OpenCode 或 Goose | 100+ models.dev / 58+ 提供商 | -| **VS Code 用户** | Cline 或 Continue | 59k Stars IDE 原生 / PR Checks | +| **VS Code 用户** | Cline 或 Continue | IDE 原生集成 / PR Checks | | **中文开发者** | Qwen Code 或 Kimi CLI | 6 语言 UI / 月之暗面中文模型 | | **CI/CD 自动化** | SWE-agent 或 OpenHands | 批量评估 / Docker 沙箱 | | **安全沙箱** | Codex CLI 或 Gemini CLI | 三平台 OS 沙箱 / TOML 策略引擎 | @@ -70,24 +67,26 @@ ## 快速对比表 -| Agent | 开发者 | 许可证 | Stars | 语言 | 提供商 | 特色 | -|------|--------|--------|-------|------|-------|------| -| [OpenCode](./docs/tools/opencode/) | Anomaly | MIT | **130k** | Go + TS | 100+ | 多客户端(TUI+Web+桌面),37 LSP | -| [Gemini CLI](./docs/tools/gemini-cli/) | Google | Apache-2.0 | **99k** | TypeScript | 1 | 8 策略模型路由,TOML 策略引擎 | -| [Claude Code](./docs/tools/claude-code/) | Anthropic | 专有 | **83k** | Rust | 1 | 50ms 启动,24 Hook 事件,Channels | -| [OpenHands](./docs/tools/openhands.md) | OpenHands | MIT | **70k** | Python | 100+ | Docker 沙箱,三层安全,多代理 | -| [Codex CLI](./docs/tools/codex-cli/) | OpenAI | Apache-2.0 | **68k** | TypeScript | 1 | 三平台 OS 沙箱,Cloud 远程执行 | -| [Cline](./docs/tools/cline.md) | Cline | Apache-2.0 | **59k** | TypeScript | 48+ | VS Code 原生,Git Checkpoint | -| [Aider](./docs/tools/aider/) | Paul Gauthier | GPL-3.0 | **42k** | Python | 100+ | 14 编辑格式,三槽位模型,/undo | -| [Goose](./docs/tools/goose/) | Block | Apache-2.0 | **34k** | Rust | 58+ | MCP 原生,11 Platform Extension,Recipe + Cron 调度 | -| [Continue](./docs/tools/continue.md) | Continue | Apache-2.0 | **32k** | TypeScript | 60+ | PR Checks CI 审查,语义索引 | -| [Warp](./docs/tools/warp.md) | Warp | 专有 | **26k** | Rust | 多种 | GPU 渲染终端,块结构输出 | -| [Qwen Code](./docs/tools/qwen-code/) | 阿里云 | Apache-2.0 | **21k** | TypeScript | 6+ | 免费 1000 次/天,Arena 多模型竞争,41 命令 | -| [SWE-agent](./docs/tools/swe-agent.md) | Princeton | MIT | **19k** | Python | 100+ | SWE-bench 评估,Docker 沙箱 | -| [Copilot CLI](./docs/tools/copilot-cli/) | GitHub | 专有 | **10k** | Shell | 多种 | 67 GitHub 工具,增长 ↑240%/月 | -| [Kimi CLI](./docs/tools/kimi-cli/) | 月之暗面 | Apache-2.0 | **7k** | Python | 6 | Wire 协议,D-Mail 时间回溯 | -| [Cursor](./docs/tools/cursor-cli.md) | Cursor | 专有 | - | TypeScript | 多种 | AI 原生 IDE,Background Agent | -| [Qoder CLI](./docs/tools/qoder-cli/) | QoderAI | 专有 | - | Go | 多种 | Quest 模式,Claude Code 兼容 | +> 为减少动态数字重复维护,Stars / 下载量 / 免费层等高频变化数据已迁移到 [`docs/data/agents-metadata.json`](./docs/data/agents-metadata.json)。 + +| Agent | 开发者 | 许可证 | 语言 | 提供商 | 特色 | +|------|--------|--------|------|-------|------| +| [OpenCode](./docs/tools/opencode/) | Anomaly | MIT | Go + TS | 100+ | 多客户端(TUI+Web+桌面),37 LSP | +| [Gemini CLI](./docs/tools/gemini-cli/) | Google | Apache-2.0 | TypeScript | 1 | 8 策略模型路由,TOML 策略引擎 | +| [Claude Code](./docs/tools/claude-code/) | Anthropic | 专有 | Rust | 1 | 50ms 启动,24 Hook 事件,Channels | +| [OpenHands](./docs/tools/openhands.md) | OpenHands | MIT | Python | 100+ | Docker 沙箱,三层安全,多代理 | +| [Codex CLI](./docs/tools/codex-cli/) | OpenAI | Apache-2.0 | TypeScript | 1 | 三平台 OS 沙箱,Cloud 远程执行 | +| [Cline](./docs/tools/cline.md) | Cline | Apache-2.0 | TypeScript | 48+ | VS Code 原生,Git Checkpoint | +| [Aider](./docs/tools/aider/) | Paul Gauthier | GPL-3.0 | Python | 100+ | 14 编辑格式,三槽位模型,/undo | +| [Goose](./docs/tools/goose/) | Block | Apache-2.0 | Rust | 58+ | MCP 原生,11 Platform Extension,Recipe + Cron 调度 | +| [Continue](./docs/tools/continue.md) | Continue | Apache-2.0 | TypeScript | 60+ | PR Checks CI 审查,语义索引 | +| [Warp](./docs/tools/warp.md) | Warp | 专有 | Rust | 多种 | GPU 渲染终端,块结构输出 | +| [Qwen Code](./docs/tools/qwen-code/) | 阿里云 | Apache-2.0 | TypeScript | 6+ | 免费 1000 次/天,Arena 多模型竞争,41 命令 | +| [SWE-agent](./docs/tools/swe-agent.md) | Princeton | MIT | Python | 100+ | SWE-bench 评估,Docker 沙箱 | +| [Copilot CLI](./docs/tools/copilot-cli/) | GitHub | 专有 | Shell | 多种 | 67 GitHub 工具,GitHub 生态集成 | +| [Kimi CLI](./docs/tools/kimi-cli/) | 月之暗面 | Apache-2.0 | Python | 6 | Wire 协议,D-Mail 时间回溯 | +| [Cursor](./docs/tools/cursor-cli.md) | Cursor | 专有 | TypeScript | 多种 | AI 原生 IDE,Background Agent | +| [Qoder CLI](./docs/tools/qoder-cli/) | QoderAI | 专有 | Go | 多种 | Quest 模式,Claude Code 兼容 | --- diff --git a/docs/SUMMARY.md b/docs/SUMMARY.md index 4967e799..55d10960 100644 --- a/docs/SUMMARY.md +++ b/docs/SUMMARY.md @@ -1,6 +1,8 @@ # 0. 一页总结:AI 编程 Code Agent 选型 > 给没时间看 34,600+ 行文档的人。2026 年 3 月。 +> +> **维护说明**:本页包含若干动态数据摘要。更新时请先核对 [`docs/data/agents-metadata.json`](./data/agents-metadata.json) 与 [`docs/evidence-index.md`](./evidence-index.md)。 ## 一句话定位 @@ -10,8 +12,8 @@ | **Copilot CLI** | GitHub 原生集成,读取所有主流指令文件(CLAUDE.md/GEMINI.md/AGENTS.md),67 个内置工具 | GitHub 重度用户和企业团队 | | **Codex CLI** | OpenAI 官方,三平台 OS 级沙箱(Seatbelt/Bubblewrap/Windows Tokens),Rust 核心 | 安全敏感场景和 OpenAI 生态用户 | | **Aider** | Git 原生老牌工具,14 种编辑格式,PageRank 仓库地图,99% 一人开发 | Git 重度用户和喜欢细粒度控制的开发者 | -| **Gemini CLI** | Google 官方,Stars 最多(99k),TOML 策略引擎,四阶段压缩算法 | Google Cloud 用户和大团队 | -| **Qwen Code** | Gemini CLI 分叉 + 阿里云生态,每天 1000 次免费,Arena 多模型竞争模式 | 中文开发者和成本敏感用户 | +| **Gemini CLI** | Google 官方,TOML 策略引擎,四阶段压缩算法 | Google Cloud 用户和大团队 | +| **Qwen Code** | Gemini CLI 分叉 + 阿里云生态,提供免费层,Arena 多模型竞争模式 | 中文开发者和成本敏感用户 | | **Kimi CLI** | 月之暗面出品,零遥测(隐私最佳),双模式交互(TUI + Shell) | 隐私敏感用户和国内开发者 | | **Goose** | Block 出品后捐赠 Linux 基金会,MCP 原生架构,398 个贡献者 | MCP 生态和开源社区 | | **OpenCode** | 多客户端(TUI+Web+桌面),37 个 LSP,100+ 模型提供商 | 需要多客户端和 IDE 集成的团队 | @@ -34,15 +36,14 @@ ## 关键数字对比 +> 动态数字(Stars、免费层、验证日期)请以 [`docs/data/agents-metadata.json`](./data/agents-metadata.json) 为准。 + | | Claude Code | Copilot CLI | Codex CLI | Aider | Gemini CLI | Qwen Code | Kimi CLI | |---|:-:|:-:|:-:|:-:|:-:|:-:|:-:| -| **Stars** | 82k | 10k | 67k | 42k | 99k | 21k | 7k | | **命令数** | ~60 | 34 | 28 | 42 | 39 | 40+ | 28 | | **工具数** | 20+ | 67 | 9 | — | 23 | 18 | 18 | | **沙箱** | ✓ | ✗ | ✓ | ✗ | ✓ | ✓ | ✗ | | **遥测** | 782 事件 | 有 | 有 | opt-in 10% | 194 键 | 阿里 RUM | **零** | -| **免费层** | ✗ | 有限 | ✗ | ✗ | 1500/天 | 1000/天 | 有限 | -| **月费** | $20-200 | $0-39 | 按量 | 按量 | 按量 | 按量 | 按量 | ## 安全等级 diff --git a/docs/comparison/features.md b/docs/comparison/features.md index 18c16c41..45b5c6a2 100644 --- a/docs/comparison/features.md +++ b/docs/comparison/features.md @@ -175,7 +175,7 @@ | Copilot CLI | 订阅制 | 1 premium request | 1 premium request | Copilot 订阅含配额 | | Cursor | 订阅制 | 1 fast request | 多个 request | Pro $20/月 500 次 | | Goose | API 按量 | ~$0.02-0.10 | ~$0.50-3 | 多提供商 | -| Gemini CLI | API 按量/免费 | 免费 | ~$0.10-1 | 有免费层级 | +| Gemini CLI | API 按量/免费 | 免费 | ~$0.10-1 | 1500 次/天免费层 | | OpenHands | API 按量 | ~$0.05-0.20 | ~$2-10 | 多代理消耗更高 | | Qwen Code | 免费/API | 免费 | 免费 | 每日 1000 次 | | Kimi CLI | API 按量 | ~$0.01-0.05 | ~$0.20-1 | 国内模型成本低 | diff --git a/docs/comparison/pricing.md b/docs/comparison/pricing.md index e525d1f7..e2a38634 100644 --- a/docs/comparison/pricing.md +++ b/docs/comparison/pricing.md @@ -1,20 +1,22 @@ # 14. 定价与成本对比 -> 2026 年 3 月数据。AI 编程工具的费用模式差异巨大——从完全免费到每月 $200+。 +> 动态定价与免费层信息请优先以 [`../data/agents-metadata.json`](../data/agents-metadata.json) 和 [`../data/CHANGELOG.md`](../data/CHANGELOG.md) 为准。本文保留结构化对比与成本分析方法。 ## 定价模式总览 -| Agent | 模式 | 月费 | 免费层 | 按量计费 | -|------|------|------|--------|---------| -| **Claude Code** | 订阅 + API | Pro $20, Max $100/$200 | 无 | API: 按 token | -| **Copilot CLI** | 订阅 | Free/Pro $10/Business $19/Enterprise $39 | ✓(有限) | Premium Requests 配额 | -| **Codex CLI** | API 按量 | 无月费 | 无 | 按 token | -| **Aider** | API 按量(自带 key) | 无月费 | 无(需 API key) | 取决于所选模型 | -| **Gemini CLI** | API + 免费层 | 无月费 | **1,500 次/天**(Gemini API) | API 按量 | -| **Qwen Code** | 免费 + API | 无月费 | **1,000 次/天**(OAuth) | DashScope 按量 | -| **Kimi CLI** | API 按量 | 无月费 | 有限免费额度 | Moonshot API 按量 | -| **Goose** | API 按量(自带 key) | 无月费 | 无 | 取决于所选模型 | -| **OpenCode** | API 按量 | 无月费 | 无 | 取决于提供商 | +> 本表仅保留定价结构。具体月费、免费层额度等高频变化数字请查阅 `docs/data/agents-metadata.json`。 + +| Agent | 模式 | 免费层形态 | 按量计费 | +|------|------|-----------|---------| +| **Claude Code** | 订阅 + API | 无 | API: 按 token | +| **Copilot CLI** | 订阅 | 有限 | Premium Requests 配额 | +| **Codex CLI** | API 按量 | 无 | 按 token | +| **Aider** | API 按量(自带 key) | 无 | 取决于所选模型 | +| **Gemini CLI** | API + 免费层 | 每日额度 | API 按量 | +| **Qwen Code** | 免费 + API | 每日额度 | DashScope 按量 | +| **Kimi CLI** | API 按量 | 有限免费额度 | Moonshot API 按量 | +| **Goose** | API 按量(自带 key) | 无 | 取决于所选模型 | +| **OpenCode** | API 按量 | 无 | 取决于提供商 | ## Claude Code 详细定价 @@ -94,12 +96,12 @@ API 按量价格(参考): | 策略 | 适用工具 | 说明 | |------|---------|------| | **选择小模型做简单任务** | 全部 | Haiku/mini 比 Opus 便宜 10-20 倍 | -| **利用免费层** | Gemini CLI, Qwen Code, Copilot | 日常简单任务可完全免费 | +| **利用免费层** | Gemini CLI, Qwen Code, Copilot | 先核对 `docs/data/agents-metadata.json` 中当前免费层额度 | | **Prompt Caching** | Claude Code, Aider | 减少重复系统提示的 token 费用 | | **上下文压缩** | 全部 | 定期 /compact 减少 token 累积 | | **Aider 的 /architect** | Aider | 用强模型规划、弱模型执行,节省 50%+ | -| **Copilot 免费模型** | Copilot CLI | gpt-5-mini 和 gpt-4.1 为 0x 倍率 | -| **订阅 vs API** | Claude Code | 日均 >$3.3 时 Max $100 更划算 | +| **Copilot 免费模型** | Copilot CLI | 具体模型倍率以官方定价页为准 | +| **订阅 vs API** | Claude Code | 应结合最新月费与任务频率重新估算 | --- diff --git a/docs/comparison/privacy-telemetry.md b/docs/comparison/privacy-telemetry.md index efa3d322..a2492ca8 100644 --- a/docs/comparison/privacy-telemetry.md +++ b/docs/comparison/privacy-telemetry.md @@ -1,21 +1,23 @@ # 3. 隐私与遥测对比 -> 各 CLI Agent 的数据采集、安全监控和隐私控制对比。基于源码分析和二进制反编译。 +> 各 CLI Agent 的数据采集、安全监控和隐私控制对比。高频变化的验证日期和证据状态请结合 [`../data/CHANGELOG.md`](../data/CHANGELOG.md) 与 [`../evidence-index.md`](../evidence-index.md) 一起查看。 ## 遥测系统对比 +> 本表保留能力边界与采集类型。若默认状态或证据完备度发生变化,请同步更新 `docs/evidence-index.md` 与 `docs/data/CHANGELOG.md`。 + | Agent | 遥测提供商 | 默认状态 | 采集 Machine ID | 采集硬件信息 | 采集 MAC 地址 | |------|-----------|---------|-----------------|-------------|-------------| -| **Claude Code** | Anthropic Metrics + Datadog + Segment | 开启 | **是**(IOPlatformUUID / /etc/machine-id) | **是**(CPU、主机名、平台) | **否** | -| **Copilot CLI** | GitHub/Microsoft 内部 | 开启 | 未确认 | **是**(平台信息) | 未确认 | -| **Codex CLI** | OpenAI 内部 | 开启 | 未确认 | **是**(平台信息) | 未确认 | -| **Aider** | PostHog | **关闭**(opt-in,10% 采样) | **是**(随机 UUID) | **是**(OS、架构) | **否** | -| **Gemini CLI** | OpenTelemetry + Google Clearcut | 开启 | **是**(持久化 UUID) | **是**(CPU/GPU/RAM 详细) | **否** | -| **Kimi CLI** | **无** | — | **否** | **否** | **否** | -| **OpenCode** | **无** | — | **否** | **否** | **否** | -| **Goose** | PostHog | **关闭**(opt-in) | **是**(随机 UUID) | **是**(OS、架构) | **否** | -| **Qwen Code** | OTEL(重品牌)+ **阿里云 RUM**(新增) | 开启 | **是**(继承 Gemini UUID) | **是**(继承 CPU/GPU/RAM) | **否** | -| **Qoder CLI** | Qoder 自有(api1.qoder.sh) | 开启 | **是**(`getMachineKey`) | 未确认 | **否** | +| **Claude Code** | Anthropic Metrics + Datadog + Segment | 开启 | 是 | 是 | 否 | +| **Copilot CLI** | GitHub/Microsoft 内部 | 开启 | 未确认 | 是 | 未确认 | +| **Codex CLI** | OpenAI 内部 | 开启 | 未确认 | 是 | 未确认 | +| **Aider** | PostHog | 默认关闭(opt-in) | 是 | 是 | 否 | +| **Gemini CLI** | OpenTelemetry + Google Clearcut | 开启 | 是 | 是 | 否 | +| **Kimi CLI** | 无 | — | 否 | 否 | 否 | +| **OpenCode** | 无 | — | 否 | 否 | 否 | +| **Goose** | PostHog | 默认关闭(opt-in) | 是 | 是 | 否 | +| **Qwen Code** | OTEL(重品牌)+ 阿里云 RUM | 开启 | 是 | 是 | 否 | +| **Qoder CLI** | Qoder 自有 | 开启 | 是 | 未确认 | 否 | ## 遥测端点 @@ -102,13 +104,15 @@ ## 证据来源 +> 证据状态、最后验证日期、补强优先级请统一查看 [`../evidence-index.md`](../evidence-index.md)。本节只保留分析方式入口。 + | Agent | 分析方式 | 证据文件 | |------|----------|----------| -| Claude Code | Bun 字节码反编译(v2.1.81) | `claude-code/EVIDENCE.md` | -| Copilot CLI | Node.js SEA 反编译(v1.0.11/0.0.403) | `copilot-cli/EVIDENCE.md` | -| Codex CLI | Rust 二进制 strings + --help(v0.116.0) | `codex-cli/EVIDENCE.md` | +| Claude Code | Bun 字节码反编译 | `claude-code/EVIDENCE.md` | +| Copilot CLI | Node.js SEA 反编译 | `copilot-cli/EVIDENCE.md` | +| Codex CLI | Rust 二进制 strings + --help | `codex-cli/EVIDENCE.md` | | Aider | 源码 `aider/analytics.py` | `aider/EVIDENCE.md` | | Gemini CLI | 源码 `packages/core/src/telemetry/` + `safety/` | `gemini-cli/EVIDENCE.md` | | Kimi CLI | 源码 `src/kimi_cli/` 全量搜索 | `kimi-cli/EVIDENCE.md` | | OpenCode | 源码 `internal/` 全量搜索 | `opencode/EVIDENCE.md` | -| Goose | 源码 `crates/goose/src/` + `crates/goose-cli/src/` | 源码分析 | +| Goose | 源码 `crates/goose/src/` + `crates/goose-cli/src/` | `goose/EVIDENCE.md` | diff --git a/docs/comparison/system-requirements.md b/docs/comparison/system-requirements.md index 0f51dc10..b854191b 100644 --- a/docs/comparison/system-requirements.md +++ b/docs/comparison/system-requirements.md @@ -1,6 +1,6 @@ # 5. 系统要求对比 -> 各工具的运行环境要求。数据来源: package.json engines / pyproject.toml / 二进制分析。 +> 各工具的运行环境要求。动态运行时版本与体积信息如有变化,请优先参考 [`../data/CHANGELOG.md`](../data/CHANGELOG.md) 记录的最近更新时间,并结合源码/安装包重新验证。 ## 语言与运行时要求 @@ -37,16 +37,18 @@ ## 二进制大小 -| Agent | 二进制大小 | 包含内容 | -|------|-----------|---------| -| **Claude Code** | ~227 MB | Bun 运行时 + JS bundle + 原生模块 (tree-sitter, sharp, audio) | -| **Copilot CLI** | ~133 MB | Node.js SEA + JS bundle (15MB + 11MB) + 原生模块 (keytar, pty) | -| **Codex CLI** | ~137 MB | Rust 静态链接 (musl) + ripgrep | -| **Goose** | ~50 MB | Rust 编译 (rmcp SDK) | -| **Gemini CLI** | ~50 MB (npm) | TypeScript + WASM (tree-sitter) | -| **Qwen Code** | ~55 MB (npm) | TypeScript + WASM (tree-sitter) | -| **Aider** | ~20 MB (pip) | Python 包 + 依赖 | -| **Kimi CLI** | ~15 MB (pip) | Python 包 + 依赖 | +> 安装体积和包大小属于高频变化信息,详细数值建议与 `docs/data/CHANGELOG.md` 一起维护;本表保留量级与组成说明。 + +| Agent | 体积量级 | 包含内容 | +|------|---------|---------| +| **Claude Code** | ~200MB+ | Bun 运行时 + JS bundle + 原生模块 (tree-sitter, sharp, audio) | +| **Copilot CLI** | ~100MB+ | Node.js SEA + JS bundle + 原生模块 (keytar, pty) | +| **Codex CLI** | ~100MB+ | Rust 静态链接 (musl) + ripgrep | +| **Goose** | ~50MB | Rust 编译 (rmcp SDK) | +| **Gemini CLI** | ~50MB | TypeScript + WASM (tree-sitter) | +| **Qwen Code** | ~50MB | TypeScript + WASM (tree-sitter) | +| **Aider** | ~20MB | Python 包 + 依赖 | +| **Kimi CLI** | ~15MB | Python 包 + 依赖 | ## 沙箱依赖 @@ -79,6 +81,6 @@ |------|-----| | 实现语言 | Go | | 运行时 | 无需额外运行时(静态链接二进制) | -| 二进制大小 | 43 MB | +| 二进制大小 | ~40MB | | 安装 | `npm install -g @qoder-ai/qodercli` | | Node.js 要求 | 仅 npm 安装需要(二进制本身不依赖 Node.js) | diff --git a/docs/data/CHANGELOG.md b/docs/data/CHANGELOG.md new file mode 100644 index 00000000..26788a04 --- /dev/null +++ b/docs/data/CHANGELOG.md @@ -0,0 +1,27 @@ +# docs/data 变更日志 + +> 用于记录动态数据层的更新时间、更新范围、来源与备注。 +> +> 目标:降低“数字改了但没人知道改了什么”的维护成本。 + +## 记录格式 + +每次更新建议记录以下内容: + +| 日期 | 文件 | 更新范围 | 数据来源 | 备注 | +|------|------|---------|---------|------| +| 2026-03-30 | `agents-metadata.json` | Stars / 下载量 / 证据状态 | npm Registry API / PyPI Stats / `gh api` | 初始化统一数据层 | + +## 变更记录 + +| 日期 | 文件 | 更新范围 | 数据来源 | 备注 | +|------|------|---------|---------|------| +| 2026-03-30 | `agents-metadata.json` | 初始化统一数据层;补充 Agent 元数据、免费层、证据状态、最后验证日期 | npm Registry API / PyPI Stats / `gh api` / 各 Agent 文档与 EVIDENCE.md | 首次建立 `docs/data/` | +| 2026-03-30 | `README.md`, `docs/SUMMARY.md` | 收敛高频变化的 Stars / 下载量 / 免费层引用,改为指向数据层 | `docs/data/agents-metadata.json` | 降低重复维护 | +| 2026-03-30 | `scripts/check_stale_data.py`, `scripts/check_all.py` | 新增动态数据漂移检查与统一检查入口 | 本仓库维护脚本 | 用于提交前校验 | + +## 使用建议 + +- 每次批量更新动态数据时,同时更新本文件 +- 如果只是修正文案、不涉及真实数据变更,可在备注中标明“文案收敛” +- 对外引用动态数字时,优先从 `docs/data/agents-metadata.json` 读取,再在本文件记录更新时间 diff --git a/docs/data/README.md b/docs/data/README.md new file mode 100644 index 00000000..d9ca9e0c --- /dev/null +++ b/docs/data/README.md @@ -0,0 +1,77 @@ +# docs/data + +本目录存放需要跨多个文档复用、且容易过时的数据源。 + +## 文件说明 + +- `agents-metadata.json` + - 统一维护 Agent 的动态指标和基础元数据 + - 包括:Stars、下载量、免费层、定价摘要、证据状态、最后验证日期 +- `SCHEMA.md` + - 说明 `agents-metadata.json` 的字段定义、推荐取值和维护约定 +- `agents-metadata.schema.json` + - 机器可校验的 JSON Schema,用于脚本校验字段结构 +- `CHANGELOG.md` + - 记录动态数据层的更新时间、来源、调整范围和维护备注 + +## 使用原则 + +### 1. 区分静态事实与动态事实 + +- **静态事实**:实现语言、架构模式、是否为分叉、证据路径 +- **动态事实**:Stars、下载量、价格、版本数、启动时间、趋势 + +### 2. 先看 schema,再改数据 + +修改 `agents-metadata.json` 前,建议先阅读 [`SCHEMA.md`](./SCHEMA.md)。结构校验由 [`agents-metadata.schema.json`](./agents-metadata.schema.json) 和 `python3 scripts/check_data_schema.py` 提供。 + +### 3. 动态事实必须带时间戳 + +所有动态数据都应包含 `as_of` 或 `last_verified`: + +```json +{ + "stars": "83k", + "downloads": { + "type": "npm_weekly", + "value": "1020万", + "as_of": "2026-03-26" + } +} +``` + +### 3. 汇总页尽量引用数据源,而不是手工散落维护 + +以下页面应优先从本目录读取或至少手动同步校验: + +- `README.md` +- `docs/SUMMARY.md` +- `docs/comparison/features.md` +- `docs/comparison/pricing.md` +- `docs/comparison/privacy-telemetry.md` +- `docs/comparison/system-requirements.md` +- `docs/tools/README.md` + +### 4. 证据状态标准 + +- `complete`:有完整多文件分析,且存在 `EVIDENCE.md` +- `partial`:有目录级分析,但证据仍不完整或主要来自二进制/外部线索 +- `single-file-only`:目前只有单文件综述,没有目录级深挖 + +## 维护建议 + +- 每次批量更新 Stars / 下载量 / 定价后,同步更新 `last_updated` +- 每次发生动态数据变更时,同时更新 `docs/data/CHANGELOG.md` +- 每次新增 Agent 后,同时补充此数据文件 +- 提交前运行: + +```bash +python3 scripts/check_all.py +``` + +如需单独执行,也可以使用: + +```bash +python3 scripts/check_repo_consistency.py +python3 scripts/check_stale_data.py +``` diff --git a/docs/data/SCHEMA.md b/docs/data/SCHEMA.md new file mode 100644 index 00000000..af007992 --- /dev/null +++ b/docs/data/SCHEMA.md @@ -0,0 +1,155 @@ +# agents-metadata.json Schema 说明 + +> 本文档说明 `docs/data/agents-metadata.json` 的字段结构、用途和维护约定。 +> +> 目标:让维护者知道每个字段的含义、哪些属于动态数据、哪些属于静态事实,以及何时应该更新。 + +## 顶层结构 + +```json +{ + "schema_version": 1, + "last_updated": "2026-03-30", + "maintainer_note": "...", + "agents": [ + { + "id": "claude-code", + "name": "Claude Code", + "category": "deep-analysis", + "license": "专有", + "developer": "Anthropic", + "implementation_language": "Rust", + "runtime": "Bun(内嵌)/ 原生二进制", + "package_ecosystem": "npm", + "stars": "83k", + "downloads": { + "type": "npm_weekly", + "value": "1020万", + "as_of": "2026-03-26" + }, + "pricing_summary": "$20-200 / API 按量", + "free_tier": "无", + "evidence": { + "status": "complete", + "source_type": "binary-analysis", + "evidence_path": "docs/tools/claude-code/EVIDENCE.md", + "last_verified": "2026-03-26" + } + } + ] +} +``` + +## 顶层字段 + +| 字段 | 类型 | 必填 | 含义 | +|------|------|------|------| +| `schema_version` | number | 是 | schema 版本号,用于后续字段演进 | +| `last_updated` | string (`YYYY-MM-DD`) | 是 | 数据文件最后一次整体更新日期 | +| `maintainer_note` | string | 否 | 给维护者的说明 | +| `agents` | array | 是 | Agent 元数据列表 | + +## Agent 对象字段 + +| 字段 | 类型 | 必填 | 动态/静态 | 含义 | +|------|------|------|-----------|------| +| `id` | string | 是 | 静态 | 稳定标识符,建议 kebab-case | +| `name` | string | 是 | 静态 | 面向文档显示的 Agent 名称 | +| `category` | string | 是 | 半静态 | 当前文档覆盖层级,如 `deep-analysis` / `single-file` | +| `license` | string | 是 | 半静态 | 许可证类型 | +| `developer` | string | 是 | 静态 | 开发者/组织 | +| `implementation_language` | string | 是 | 静态 | 主要实现语言 | +| `runtime` | string | 是 | 半静态 | 运行时或分发形态 | +| `package_ecosystem` | string | 是 | 半静态 | npm / pypi / desktop / none 等 | +| `stars` | string | 否 | 动态 | 社区热度指标,建议保持与外部来源一致 | +| `downloads` | object | 否 | 动态 | 下载量信息 | +| `pricing_summary` | string | 否 | 动态 | 定价摘要,适合汇总页使用 | +| `free_tier` | string | 否 | 动态 | 免费层摘要 | +| `evidence` | object | 是 | 半静态 | 证据完备度与入口 | + +## downloads 对象 + +| 字段 | 类型 | 必填 | 含义 | +|------|------|------|------| +| `type` | string | 是 | 指标类型,如 `npm_weekly` / `pypi_monthly` / `none` / `unknown` | +| `value` | string | 是 | 下载量展示值,如 `1020万`、`—` | +| `as_of` | string (`YYYY-MM-DD`) | 是 | 该下载量的统计时间 | + +## evidence 对象 + +| 字段 | 类型 | 必填 | 含义 | +|------|------|------|------| +| `status` | string | 是 | `complete` / `partial` / `single-file-only` | +| `source_type` | string | 是 | `source-analysis` / `binary-analysis` / `summary-analysis` / `official-docs` | +| `evidence_path` | string | 是 | 对应证据文档路径 | +| `last_verified` | string (`YYYY-MM-DD`) | 是 | 最近一次证据验证日期 | + +## 推荐取值 + +### `category` + +- `deep-analysis`:已有目录级多文件分析 +- `single-file`:目前只有单文件综述 + +### `downloads.type` + +- `npm_weekly` +- `pypi_monthly` +- `none` +- `unknown` + +### `evidence.status` + +- `complete` +- `partial` +- `single-file-only` + +### `evidence.source_type` + +- `source-analysis` +- `binary-analysis` +- `summary-analysis` +- `official-docs` + +## 维护约定 + +### 1. 哪些情况需要更新 `last_updated` + +以下任一情况都应更新顶层 `last_updated`: +- 批量更新 Stars / 下载量 / 免费层 / 定价摘要 +- 新增 Agent +- 修改 evidence 状态或最后验证日期 + +### 2. 哪些情况需要更新 `docs/data/CHANGELOG.md` + +以下情况建议同步记录: +- 动态数据变化 +- 字段结构变化 +- 批量文档收敛到数据层 + +### 3. 哪些情况需要同步检查其他文档 + +当下列字段变化时,应同步检查: + +| 字段 | 建议同步检查 | +|------|-------------| +| `stars` / `downloads` | `README.md`, `docs/SUMMARY.md`, `docs/comparison/features.md` | +| `pricing_summary` / `free_tier` | `docs/comparison/pricing.md`, `README.md`, `docs/SUMMARY.md` | +| `runtime` / `implementation_language` | `docs/comparison/system-requirements.md`, `README.md` | +| `evidence.*` | `docs/evidence-index.md`, `docs/comparison/privacy-telemetry.md` | + +## 校验建议 + +提交前运行: + +```bash +python3 scripts/check_all.py +``` + +如需单独排查: + +```bash +python3 scripts/check_data_schema.py +python3 scripts/check_repo_consistency.py +python3 scripts/check_stale_data.py +``` diff --git a/docs/data/agents-metadata.json b/docs/data/agents-metadata.json new file mode 100644 index 00000000..5aea711a --- /dev/null +++ b/docs/data/agents-metadata.json @@ -0,0 +1,415 @@ +{ + "schema_version": 1, + "last_updated": "2026-03-30", + "maintainer_note": "Dynamic metrics should be updated from official APIs or clearly labeled estimates. Static architecture facts should be sourced from repository analysis or EVIDENCE.md.", + "agents": [ + { + "id": "claude-code", + "name": "Claude Code", + "category": "deep-analysis", + "license": "专有", + "developer": "Anthropic", + "implementation_language": "Rust", + "runtime": "Bun(内嵌)/ 原生二进制", + "package_ecosystem": "npm", + "stars": "83k", + "downloads": { + "type": "npm_weekly", + "value": "1020万", + "as_of": "2026-03-26" + }, + "pricing_summary": "$20-200 / API 按量", + "free_tier": "无", + "evidence": { + "status": "complete", + "source_type": "binary-analysis", + "evidence_path": "docs/tools/claude-code/EVIDENCE.md", + "last_verified": "2026-03-26" + } + }, + { + "id": "copilot-cli", + "name": "Copilot CLI", + "category": "deep-analysis", + "license": "专有", + "developer": "GitHub", + "implementation_language": "TypeScript / Node.js SEA", + "runtime": "原生二进制(回退需 Node.js >= 24)", + "package_ecosystem": "npm", + "stars": "10k", + "downloads": { + "type": "npm_weekly", + "value": "64万", + "as_of": "2026-03-26" + }, + "pricing_summary": "$0-39 / Premium Requests", + "free_tier": "有限", + "evidence": { + "status": "complete", + "source_type": "binary-analysis", + "evidence_path": "docs/tools/copilot-cli/EVIDENCE.md", + "last_verified": "2026-03-26" + } + }, + { + "id": "codex-cli", + "name": "Codex CLI", + "category": "deep-analysis", + "license": "Apache-2.0", + "developer": "OpenAI", + "implementation_language": "Rust + Node.js wrapper", + "runtime": "原生二进制(npm 启动器需 Node.js >= 16)", + "package_ecosystem": "npm", + "stars": "68k", + "downloads": { + "type": "npm_weekly", + "value": "368万", + "as_of": "2026-03-26" + }, + "pricing_summary": "API 按量", + "free_tier": "无", + "evidence": { + "status": "complete", + "source_type": "binary-analysis", + "evidence_path": "docs/tools/codex-cli/EVIDENCE.md", + "last_verified": "2026-03-26" + } + }, + { + "id": "gemini-cli", + "name": "Gemini CLI", + "category": "deep-analysis", + "license": "Apache-2.0", + "developer": "Google", + "implementation_language": "TypeScript", + "runtime": "Node.js >= 20", + "package_ecosystem": "npm", + "stars": "99k", + "downloads": { + "type": "npm_weekly", + "value": "74万", + "as_of": "2026-03-26" + }, + "pricing_summary": "免费层 + API 按量", + "free_tier": "1500 次/天", + "evidence": { + "status": "complete", + "source_type": "source-analysis", + "evidence_path": "docs/tools/gemini-cli/EVIDENCE.md", + "last_verified": "2026-03-26" + } + }, + { + "id": "qwen-code", + "name": "Qwen Code", + "category": "deep-analysis", + "license": "Apache-2.0", + "developer": "阿里云", + "implementation_language": "TypeScript", + "runtime": "Node.js >= 20", + "package_ecosystem": "npm", + "stars": "21k", + "downloads": { + "type": "npm_weekly", + "value": "8.4万", + "as_of": "2026-03-26" + }, + "pricing_summary": "免费层 + DashScope 按量", + "free_tier": "1000 次/天", + "evidence": { + "status": "complete", + "source_type": "source-analysis", + "evidence_path": "docs/tools/qwen-code/EVIDENCE.md", + "last_verified": "2026-03-26" + } + }, + { + "id": "aider", + "name": "Aider", + "category": "deep-analysis", + "license": "GPL-3.0", + "developer": "Paul Gauthier", + "implementation_language": "Python", + "runtime": "Python >= 3.10", + "package_ecosystem": "pypi", + "stars": "42k", + "downloads": { + "type": "pypi_monthly", + "value": "78万", + "as_of": "2026-03-26" + }, + "pricing_summary": "API 按量", + "free_tier": "无", + "evidence": { + "status": "complete", + "source_type": "source-analysis", + "evidence_path": "docs/tools/aider/EVIDENCE.md", + "last_verified": "2026-03-26" + } + }, + { + "id": "kimi-cli", + "name": "Kimi CLI", + "category": "deep-analysis", + "license": "Apache-2.0", + "developer": "月之暗面", + "implementation_language": "Python", + "runtime": "Python >= 3.12", + "package_ecosystem": "pypi", + "stars": "7k", + "downloads": { + "type": "pypi_monthly", + "value": "45万", + "as_of": "2026-03-26" + }, + "pricing_summary": "API 按量", + "free_tier": "有限免费额度", + "evidence": { + "status": "complete", + "source_type": "source-analysis", + "evidence_path": "docs/tools/kimi-cli/EVIDENCE.md", + "last_verified": "2026-03-26" + } + }, + { + "id": "opencode", + "name": "OpenCode", + "category": "deep-analysis", + "license": "MIT", + "developer": "Anomaly", + "implementation_language": "TypeScript(v1.0+)", + "runtime": "Bun 1.3+", + "package_ecosystem": "none", + "stars": "130k", + "downloads": { + "type": "none", + "value": "—", + "as_of": "2026-03-26" + }, + "pricing_summary": "API 按量", + "free_tier": "无", + "evidence": { + "status": "complete", + "source_type": "source-analysis", + "evidence_path": "docs/tools/opencode/EVIDENCE.md", + "last_verified": "2026-03-26" + } + }, + { + "id": "goose", + "name": "Goose", + "category": "deep-analysis", + "license": "Apache-2.0", + "developer": "Block / Linux Foundation", + "implementation_language": "Rust", + "runtime": "原生二进制 / Rust 构建", + "package_ecosystem": "none", + "stars": "34k", + "downloads": { + "type": "none", + "value": "—", + "as_of": "2026-03-26" + }, + "pricing_summary": "API 按量", + "free_tier": "无", + "evidence": { + "status": "complete", + "source_type": "source-analysis", + "evidence_path": "docs/tools/goose/EVIDENCE.md", + "last_verified": "2026-03-26" + } + }, + { + "id": "qoder-cli", + "name": "Qoder CLI", + "category": "deep-analysis", + "license": "专有", + "developer": "QoderAI", + "implementation_language": "Go", + "runtime": "原生静态链接二进制", + "package_ecosystem": "npm-wrapper", + "stars": "-", + "downloads": { + "type": "unknown", + "value": "—", + "as_of": "2026-03-26" + }, + "pricing_summary": "信用制", + "free_tier": "300 credits", + "evidence": { + "status": "partial", + "source_type": "binary-analysis", + "evidence_path": "docs/tools/qoder-cli/EVIDENCE.md", + "last_verified": "2026-03-26" + } + }, + { + "id": "cline", + "name": "Cline", + "category": "single-file", + "license": "Apache-2.0", + "developer": "Cline", + "implementation_language": "TypeScript", + "runtime": "VS Code 扩展", + "package_ecosystem": "vscode-marketplace", + "stars": "59k", + "downloads": { + "type": "unknown", + "value": "—", + "as_of": "2026-03-26" + }, + "pricing_summary": "取决于模型提供商", + "free_tier": "取决于模型提供商", + "evidence": { + "status": "single-file-only", + "source_type": "summary-analysis", + "evidence_path": "docs/tools/cline.md", + "last_verified": "2026-03-26" + } + }, + { + "id": "continue", + "name": "Continue", + "category": "single-file", + "license": "Apache-2.0", + "developer": "Continue", + "implementation_language": "TypeScript", + "runtime": "IDE 扩展", + "package_ecosystem": "vscode-marketplace", + "stars": "32k", + "downloads": { + "type": "unknown", + "value": "—", + "as_of": "2026-03-26" + }, + "pricing_summary": "取决于模型提供商", + "free_tier": "取决于部署方式", + "evidence": { + "status": "single-file-only", + "source_type": "summary-analysis", + "evidence_path": "docs/tools/continue.md", + "last_verified": "2026-03-26" + } + }, + { + "id": "cursor-cli", + "name": "Cursor CLI", + "category": "single-file", + "license": "专有", + "developer": "Cursor", + "implementation_language": "TypeScript", + "runtime": "IDE / Desktop", + "package_ecosystem": "desktop", + "stars": "-", + "downloads": { + "type": "unknown", + "value": "—", + "as_of": "2026-03-26" + }, + "pricing_summary": "订阅制", + "free_tier": "有限", + "evidence": { + "status": "single-file-only", + "source_type": "summary-analysis", + "evidence_path": "docs/tools/cursor-cli.md", + "last_verified": "2026-03-26" + } + }, + { + "id": "openhands", + "name": "OpenHands", + "category": "single-file", + "license": "MIT", + "developer": "OpenHands", + "implementation_language": "Python", + "runtime": "Python / Docker", + "package_ecosystem": "pypi", + "stars": "70k", + "downloads": { + "type": "pypi_monthly", + "value": "125万", + "as_of": "2026-03-26" + }, + "pricing_summary": "API 按量", + "free_tier": "无", + "evidence": { + "status": "single-file-only", + "source_type": "summary-analysis", + "evidence_path": "docs/tools/openhands.md", + "last_verified": "2026-03-26" + } + }, + { + "id": "swe-agent", + "name": "SWE-agent", + "category": "single-file", + "license": "MIT", + "developer": "Princeton", + "implementation_language": "Python", + "runtime": "Python / Docker", + "package_ecosystem": "pypi", + "stars": "19k", + "downloads": { + "type": "unknown", + "value": "—", + "as_of": "2026-03-26" + }, + "pricing_summary": "API 按量", + "free_tier": "无", + "evidence": { + "status": "single-file-only", + "source_type": "summary-analysis", + "evidence_path": "docs/tools/swe-agent.md", + "last_verified": "2026-03-26" + } + }, + { + "id": "warp", + "name": "Warp", + "category": "single-file", + "license": "专有", + "developer": "Warp", + "implementation_language": "Rust", + "runtime": "桌面终端应用", + "package_ecosystem": "desktop", + "stars": "26k", + "downloads": { + "type": "unknown", + "value": "—", + "as_of": "2026-03-26" + }, + "pricing_summary": "订阅制", + "free_tier": "有限", + "evidence": { + "status": "single-file-only", + "source_type": "summary-analysis", + "evidence_path": "docs/tools/warp.md", + "last_verified": "2026-03-26" + } + }, + { + "id": "mini-swe-agent", + "name": "mini-swe-agent", + "category": "single-file", + "license": "MIT", + "developer": "Princeton", + "implementation_language": "Python", + "runtime": "Python", + "package_ecosystem": "pypi", + "stars": "-", + "downloads": { + "type": "unknown", + "value": "—", + "as_of": "2026-03-26" + }, + "pricing_summary": "教学参考", + "free_tier": "—", + "evidence": { + "status": "single-file-only", + "source_type": "summary-analysis", + "evidence_path": "docs/tools/mini-swe-agent.md", + "last_verified": "2026-03-26" + } + } + ] +} diff --git a/docs/data/agents-metadata.schema.json b/docs/data/agents-metadata.schema.json new file mode 100644 index 00000000..29a62dc2 --- /dev/null +++ b/docs/data/agents-metadata.schema.json @@ -0,0 +1,166 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://example.com/codeagents-x1/docs/data/agents-metadata.schema.json", + "title": "agents-metadata", + "type": "object", + "additionalProperties": false, + "required": [ + "schema_version", + "last_updated", + "agents" + ], + "properties": { + "schema_version": { + "type": "integer", + "minimum": 1 + }, + "last_updated": { + "type": "string", + "pattern": "^\\d{4}-\\d{2}-\\d{2}$" + }, + "maintainer_note": { + "type": "string" + }, + "agents": { + "type": "array", + "minItems": 1, + "items": { + "$ref": "#/$defs/agent" + } + } + }, + "$defs": { + "downloads": { + "type": "object", + "additionalProperties": false, + "required": [ + "type", + "value", + "as_of" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "npm_weekly", + "pypi_monthly", + "none", + "unknown" + ] + }, + "value": { + "type": "string", + "minLength": 1 + }, + "as_of": { + "type": "string", + "pattern": "^\\d{4}-\\d{2}-\\d{2}$" + } + } + }, + "evidence": { + "type": "object", + "additionalProperties": false, + "required": [ + "status", + "source_type", + "evidence_path", + "last_verified" + ], + "properties": { + "status": { + "type": "string", + "enum": [ + "complete", + "partial", + "single-file-only" + ] + }, + "source_type": { + "type": "string", + "enum": [ + "source-analysis", + "binary-analysis", + "summary-analysis", + "official-docs" + ] + }, + "evidence_path": { + "type": "string", + "minLength": 1 + }, + "last_verified": { + "type": "string", + "pattern": "^\\d{4}-\\d{2}-\\d{2}$" + } + } + }, + "agent": { + "type": "object", + "additionalProperties": false, + "required": [ + "id", + "name", + "category", + "license", + "developer", + "implementation_language", + "runtime", + "package_ecosystem", + "evidence" + ], + "properties": { + "id": { + "type": "string", + "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$" + }, + "name": { + "type": "string", + "minLength": 1 + }, + "category": { + "type": "string", + "enum": [ + "deep-analysis", + "single-file" + ] + }, + "license": { + "type": "string", + "minLength": 1 + }, + "developer": { + "type": "string", + "minLength": 1 + }, + "implementation_language": { + "type": "string", + "minLength": 1 + }, + "runtime": { + "type": "string", + "minLength": 1 + }, + "package_ecosystem": { + "type": "string", + "minLength": 1 + }, + "stars": { + "type": "string" + }, + "downloads": { + "$ref": "#/$defs/downloads" + }, + "pricing_summary": { + "type": "string" + }, + "free_tier": { + "type": "string" + }, + "evidence": { + "$ref": "#/$defs/evidence" + } + } + } + } +} diff --git a/docs/evidence-index.md b/docs/evidence-index.md new file mode 100644 index 00000000..d6e81430 --- /dev/null +++ b/docs/evidence-index.md @@ -0,0 +1,83 @@ +# 证据索引(Evidence Index) + +> 本页用于汇总每个 Agent 的证据完备度、分析方式、对应文档入口,以及建议的更新频率。 +> +> **目标**:把“这条结论来自哪里、验证到什么程度、何时需要复核”显式化,降低仓库维护成本。 + +## 证据状态定义 + +| 状态 | 含义 | 维护要求 | +|------|------|---------| +| `complete` | 已有目录级分析,且存在 `EVIDENCE.md` 或等价证据文档 | 核心结论需可回溯到源码、反编译结果或官方文档 | +| `partial` | 有多文件分析,但关键结论仍部分依赖外部材料、二进制侧信号或待补证据 | 应补足缺失证据,避免长期停留 | +| `single-file-only` | 当前仅有单文件综述,缺少目录级深挖与证据索引 | 若该 Agent 重要性提升,应优先升级为目录级分析 | + +## 证据来源类型 + +| 类型 | 说明 | +|------|------| +| `source-analysis` | 直接基于开源仓库源码分析 | +| `binary-analysis` | 基于二进制、反编译、strings、CLI 帮助输出等证据 | +| `official-docs` | 主要基于官方文档、定价页、产品文档 | +| `summary-analysis` | 综述级整理,证据粒度较粗 | + +## Agent 证据矩阵 + +| Agent | 分析深度 | 证据状态 | 证据来源 | 证据入口 | 最后验证 | 建议复核频率 | +|------|---------|---------|---------|---------|---------|-------------| +| Claude Code | 多文件 | `complete` | `binary-analysis` | `docs/tools/claude-code/EVIDENCE.md` | 2026-03-26 | 月度 | +| Copilot CLI | 多文件 | `complete` | `binary-analysis` | `docs/tools/copilot-cli/EVIDENCE.md` | 2026-03-26 | 月度 | +| Codex CLI | 多文件 | `complete` | `binary-analysis` | `docs/tools/codex-cli/EVIDENCE.md` | 2026-03-26 | 月度 | +| Gemini CLI | 多文件 | `complete` | `source-analysis` | `docs/tools/gemini-cli/EVIDENCE.md` | 2026-03-26 | 月度 | +| Qwen Code | 多文件 | `complete` | `source-analysis` | `docs/tools/qwen-code/EVIDENCE.md` | 2026-03-26 | 月度 | +| Aider | 多文件 | `complete` | `source-analysis` | `docs/tools/aider/EVIDENCE.md` | 2026-03-26 | 月度 | +| Kimi CLI | 多文件 | `complete` | `source-analysis` | `docs/tools/kimi-cli/EVIDENCE.md` | 2026-03-26 | 月度 | +| OpenCode | 多文件 | `complete` | `source-analysis` | `docs/tools/opencode/EVIDENCE.md` | 2026-03-26 | 月度 | +| Goose | 多文件 | `complete` | `source-analysis` | `docs/tools/goose/EVIDENCE.md` | 2026-03-26 | 月度 | +| Qoder CLI | 多文件 | `partial` | `binary-analysis` | `docs/tools/qoder-cli/EVIDENCE.md` | 2026-03-26 | 双周 | +| Cline | 单文件 | `single-file-only` | `summary-analysis` | `docs/tools/cline.md` | 2026-03-26 | 季度 | +| Continue | 单文件 | `single-file-only` | `summary-analysis` | `docs/tools/continue.md` | 2026-03-26 | 季度 | +| Cursor CLI | 单文件 | `single-file-only` | `summary-analysis` | `docs/tools/cursor-cli.md` | 2026-03-26 | 季度 | +| OpenHands | 单文件 | `single-file-only` | `summary-analysis` | `docs/tools/openhands.md` | 2026-03-26 | 季度 | +| SWE-agent | 单文件 | `single-file-only` | `summary-analysis` | `docs/tools/swe-agent.md` | 2026-03-26 | 季度 | +| Warp | 单文件 | `single-file-only` | `summary-analysis` | `docs/tools/warp.md` | 2026-03-26 | 季度 | +| mini-swe-agent | 单文件 | `single-file-only` | `summary-analysis` | `docs/tools/mini-swe-agent.md` | 2026-03-26 | 低优先级 | + +## 优先补强建议 + +### 第一优先级 + +1. **Qoder CLI** + - 已有目录级分析,但证据完备度仍弱于主要开源 Agent + - 建议补更多 CLI 参数、配置格式、遥测/安全、命令行为证据 + +2. **Continue / Cline / OpenHands** + - 影响力较大,但目前仍以单文件综述为主 + - 建议至少升级为“概述 + 架构 + 命令/工具 + EVIDENCE.md”四件套 + +### 第二优先级 + +3. **Cursor CLI / Warp** + - 用户关注度高,但闭源成分多 + - 建议补官方文档证据与行为验证边界,明确哪些结论来自源码、哪些来自官方表述 + +## 维护工作流建议 + +每次新增或更新 Agent 文档时,建议同步完成以下动作: + +1. 更新 `docs/data/agents-metadata.json` +2. 更新本页中的证据状态、最后验证日期、复核频率 +3. 如涉及关键结论变动,同步检查: + - `README.md` + - `docs/SUMMARY.md` + - `docs/tools/README.md` + - `docs/comparison/features.md` + - `docs/comparison/privacy-telemetry.md` + - `docs/comparison/pricing.md` + - `docs/comparison/system-requirements.md` + +## 读者说明 + +> `single-file-only` 不代表内容错误,只表示证据粒度和可审计性弱于目录级分析。 +> +> 对闭源 Agent,应尽量明确“可验证边界”:哪些是通过行为、CLI 帮助、二进制分析得出,哪些仅来自官方文档。 diff --git a/docs/guides/getting-started.md b/docs/guides/getting-started.md index d5c1e430..bb07dab6 100644 --- a/docs/guides/getting-started.md +++ b/docs/guides/getting-started.md @@ -349,4 +349,4 @@ chmod +x script.sh - [工具文档](../tools/) - 详细工具指南 - [功能对比](../comparison/features.md) - 横向对比 - [架构解析](../architecture/overview.md) - 代理如何工作 -- [基准测试](../benchmarks/) - 性能数据 +- [基准测试](../benchmarks/overview.md) - 性能数据 diff --git a/docs/tools/README.md b/docs/tools/README.md index db73a8bb..607b1455 100644 --- a/docs/tools/README.md +++ b/docs/tools/README.md @@ -46,9 +46,9 @@ ## 新增 Agent -| Agent | 文件 | 行数 | 特色 | +| Agent | 形态 | 深度 | 特色 | |------|------|------|------| -| [Qoder CLI](./qoder-cli/) | 单文件 | 179 | Go 原生,Quest 模式,Claude Code 兼容,信用制 | +| [Qoder CLI](./qoder-cli/) | 目录 | 多文件 | Go 原生,Quest 模式,Claude Code 兼容,信用制 | ## 增强系统 diff --git a/scripts/check_all.py b/scripts/check_all.py new file mode 100644 index 00000000..a15c2748 --- /dev/null +++ b/scripts/check_all.py @@ -0,0 +1,32 @@ +#!/usr/bin/env python3 +import subprocess +import sys +from pathlib import Path + +ROOT = Path('/root/git/codeagents-x1') +SCRIPTS = ROOT / 'scripts' +CHECKS = [ + ('data schema', SCRIPTS / 'check_data_schema.py'), + ('repository consistency', SCRIPTS / 'check_repo_consistency.py'), + ('stale data', SCRIPTS / 'check_stale_data.py'), +] + + +def run_check(label: str, script: Path) -> int: + print(f'==> Running {label}: {script.name}') + result = subprocess.run([sys.executable, str(script)], cwd=ROOT) + print(f'==> Exit code: {result.returncode}\n') + return result.returncode + + +def main() -> int: + exit_codes = [run_check(label, script) for label, script in CHECKS] + if any(code != 0 for code in exit_codes): + print('FAIL: one or more checks returned non-zero exit codes') + return 1 + print('OK: all repository checks passed') + return 0 + + +if __name__ == '__main__': + sys.exit(main()) diff --git a/scripts/check_data_schema.py b/scripts/check_data_schema.py new file mode 100644 index 00000000..fa068c35 --- /dev/null +++ b/scripts/check_data_schema.py @@ -0,0 +1,161 @@ +#!/usr/bin/env python3 +import json +import re +import sys +from datetime import datetime +from pathlib import Path + +ROOT = Path('/root/git/codeagents-x1') +DATA_FILE = ROOT / 'docs' / 'data' / 'agents-metadata.json' +SCHEMA_FILE = ROOT / 'docs' / 'data' / 'agents-metadata.schema.json' +DATE_RE = re.compile(r'^\d{4}-\d{2}-\d{2}$') +ID_RE = re.compile(r'^[a-z0-9]+(?:-[a-z0-9]+)*$') +CATEGORY_VALUES = {'deep-analysis', 'single-file'} +DOWNLOAD_TYPES = {'npm_weekly', 'pypi_monthly', 'none', 'unknown'} +EVIDENCE_STATUS = {'complete', 'partial', 'single-file-only'} +EVIDENCE_SOURCE_TYPES = {'source-analysis', 'binary-analysis', 'summary-analysis', 'official-docs'} +TOP_LEVEL_REQUIRED = {'schema_version', 'last_updated', 'agents'} +TOP_LEVEL_OPTIONAL = {'maintainer_note'} +AGENT_REQUIRED = { + 'id', 'name', 'category', 'license', 'developer', + 'implementation_language', 'runtime', 'package_ecosystem', 'evidence' +} +AGENT_OPTIONAL = {'stars', 'downloads', 'pricing_summary', 'free_tier'} +DOWNLOADS_REQUIRED = {'type', 'value', 'as_of'} +EVIDENCE_REQUIRED = {'status', 'source_type', 'evidence_path', 'last_verified'} + + +def load_json(path: Path): + with path.open('r', encoding='utf-8') as f: + return json.load(f) + + +def is_valid_date(value: str) -> bool: + if not isinstance(value, str) or not DATE_RE.match(value): + return False + try: + datetime.strptime(value, '%Y-%m-%d') + return True + except ValueError: + return False + + +def require_keys(obj: dict, required: set[str], optional: set[str], label: str, errors: list[str]): + keys = set(obj.keys()) + missing = required - keys + extra = keys - required - optional + for key in sorted(missing): + errors.append(f'{label}: missing required key `{key}`') + for key in sorted(extra): + errors.append(f'{label}: unexpected key `{key}`') + + +def validate_agent(agent: dict, index: int, errors: list[str], seen_ids: set[str]): + label = f'agents[{index}]' + if not isinstance(agent, dict): + errors.append(f'{label}: must be an object') + return + + require_keys(agent, AGENT_REQUIRED, AGENT_OPTIONAL, label, errors) + + agent_id = agent.get('id') + if not isinstance(agent_id, str) or not ID_RE.match(agent_id): + errors.append(f'{label}.id: must be kebab-case string') + elif agent_id in seen_ids: + errors.append(f'{label}.id: duplicate id `{agent_id}`') + else: + seen_ids.add(agent_id) + + for field in ['name', 'license', 'developer', 'implementation_language', 'runtime', 'package_ecosystem']: + value = agent.get(field) + if not isinstance(value, str) or not value.strip(): + errors.append(f'{label}.{field}: must be a non-empty string') + + category = agent.get('category') + if category not in CATEGORY_VALUES: + errors.append(f'{label}.category: must be one of {sorted(CATEGORY_VALUES)}') + + if 'stars' in agent and not isinstance(agent.get('stars'), str): + errors.append(f'{label}.stars: must be a string when present') + if 'pricing_summary' in agent and not isinstance(agent.get('pricing_summary'), str): + errors.append(f'{label}.pricing_summary: must be a string when present') + if 'free_tier' in agent and not isinstance(agent.get('free_tier'), str): + errors.append(f'{label}.free_tier: must be a string when present') + + downloads = agent.get('downloads') + if downloads is not None: + if not isinstance(downloads, dict): + errors.append(f'{label}.downloads: must be an object') + else: + require_keys(downloads, DOWNLOADS_REQUIRED, set(), f'{label}.downloads', errors) + if downloads.get('type') not in DOWNLOAD_TYPES: + errors.append(f'{label}.downloads.type: must be one of {sorted(DOWNLOAD_TYPES)}') + if not isinstance(downloads.get('value'), str) or not downloads.get('value').strip(): + errors.append(f'{label}.downloads.value: must be a non-empty string') + if not is_valid_date(downloads.get('as_of')): + errors.append(f'{label}.downloads.as_of: must be a valid YYYY-MM-DD date') + + evidence = agent.get('evidence') + if not isinstance(evidence, dict): + errors.append(f'{label}.evidence: must be an object') + else: + require_keys(evidence, EVIDENCE_REQUIRED, set(), f'{label}.evidence', errors) + if evidence.get('status') not in EVIDENCE_STATUS: + errors.append(f'{label}.evidence.status: must be one of {sorted(EVIDENCE_STATUS)}') + if evidence.get('source_type') not in EVIDENCE_SOURCE_TYPES: + errors.append(f'{label}.evidence.source_type: must be one of {sorted(EVIDENCE_SOURCE_TYPES)}') + if not isinstance(evidence.get('evidence_path'), str) or not evidence.get('evidence_path').strip(): + errors.append(f'{label}.evidence.evidence_path: must be a non-empty string') + if not is_valid_date(evidence.get('last_verified')): + errors.append(f'{label}.evidence.last_verified: must be a valid YYYY-MM-DD date') + + +def main() -> int: + errors: list[str] = [] + + if not DATA_FILE.exists(): + print(f'ERROR: missing data file {DATA_FILE.relative_to(ROOT)}') + return 1 + if not SCHEMA_FILE.exists(): + print(f'ERROR: missing schema file {SCHEMA_FILE.relative_to(ROOT)}') + return 1 + + try: + data = load_json(DATA_FILE) + load_json(SCHEMA_FILE) + except json.JSONDecodeError as exc: + print(f'ERROR: invalid JSON: {exc}') + return 1 + + if not isinstance(data, dict): + print('ERROR: top-level JSON must be an object') + return 1 + + require_keys(data, TOP_LEVEL_REQUIRED, TOP_LEVEL_OPTIONAL, 'root', errors) + + if not isinstance(data.get('schema_version'), int) or data.get('schema_version', 0) < 1: + errors.append('root.schema_version: must be an integer >= 1') + if not is_valid_date(data.get('last_updated')): + errors.append('root.last_updated: must be a valid YYYY-MM-DD date') + if 'maintainer_note' in data and not isinstance(data.get('maintainer_note'), str): + errors.append('root.maintainer_note: must be a string when present') + + agents = data.get('agents') + if not isinstance(agents, list) or not agents: + errors.append('root.agents: must be a non-empty array') + else: + seen_ids: set[str] = set() + for idx, agent in enumerate(agents): + validate_agent(agent, idx, errors, seen_ids) + + if errors: + for err in errors: + print(f'ERROR: {err}') + return 1 + + print('OK: data schema checks passed') + return 0 + + +if __name__ == '__main__': + sys.exit(main()) diff --git a/scripts/check_repo_consistency.py b/scripts/check_repo_consistency.py new file mode 100644 index 00000000..73e25c3a --- /dev/null +++ b/scripts/check_repo_consistency.py @@ -0,0 +1,125 @@ +#!/usr/bin/env python3 +import json +import re +import sys +from pathlib import Path + +ROOT = Path('/root/git/codeagents-x1') +DOCS = ROOT / 'docs' +DATA_FILE = DOCS / 'data' / 'agents-metadata.json' +README = ROOT / 'README.md' +SUMMARY = DOCS / 'SUMMARY.md' +TOOLS_INDEX = DOCS / 'tools' / 'README.md' +EVIDENCE_INDEX = DOCS / 'evidence-index.md' + +CHECK_FILES = [ + README, + SUMMARY, + TOOLS_INDEX, + DOCS / 'comparison' / 'features.md', + DOCS / 'comparison' / 'pricing.md', + DOCS / 'comparison' / 'privacy-telemetry.md', + DOCS / 'comparison' / 'system-requirements.md', +] + + +def read_text(path: Path) -> str: + return path.read_text(encoding='utf-8') + + +def load_data() -> dict: + return json.loads(read_text(DATA_FILE)) + + +def check_required_files(errors: list[str]): + for path in [DATA_FILE, README, SUMMARY, TOOLS_INDEX, EVIDENCE_INDEX]: + if not path.exists(): + errors.append(f'Missing required file: {path.relative_to(ROOT)}') + + +def check_evidence_paths(metadata: dict, errors: list[str]): + for agent in metadata.get('agents', []): + evidence_path = agent.get('evidence', {}).get('evidence_path') + if evidence_path: + full = ROOT / evidence_path + if not full.exists(): + errors.append(f"Missing evidence path for {agent['id']}: {evidence_path}") + + +def check_agent_mentions(metadata: dict, warnings: list[str]): + files_text = {path: read_text(path) for path in CHECK_FILES if path.exists()} + for agent in metadata.get('agents', []): + name = agent['name'] + mentions = [path.relative_to(ROOT).as_posix() for path, text in files_text.items() if name in text] + if not mentions: + warnings.append(f"Agent not mentioned in tracked summary files: {name}") + + +def check_links(errors: list[str], warnings: list[str]): + link_pattern = re.compile(r'\[[^\]]+\]\(([^)]+)\)') + ignored_literal_targets = {'链接', 'link', 'url', 'example', '.*'} + for md in ROOT.rglob('*.md'): + if '.git' in md.parts: + continue + text = read_text(md) + in_code_block = False + for line in text.splitlines(): + if line.strip().startswith('```'): + in_code_block = not in_code_block + continue + if in_code_block: + continue + for target in link_pattern.findall(line): + if target.startswith(('http://', 'https://', '#', 'mailto:')): + continue + normalized = target.split('#', 1)[0].strip() + if not normalized or normalized in ignored_literal_targets: + continue + candidate = (md.parent / normalized).resolve() + if not candidate.exists(): + errors.append(f'Broken relative link in {md.relative_to(ROOT)} -> {target}') + elif candidate.is_dir(): + index_md = candidate / 'README.md' + if not index_md.exists(): + warnings.append(f'Directory link without README target: {md.relative_to(ROOT)} -> {target}') + + +def check_tools_index_consistency(warnings: list[str]): + text = read_text(TOOLS_INDEX) + qoder_lines = [line for line in text.splitlines() if '[Qoder CLI](./qoder-cli/)' in line] + if any('单文件' in line for line in qoder_lines): + warnings.append('docs/tools/README.md lists Qoder CLI as a directory link but labels it 单文件; consider clarifying depth/type.') + + +def main() -> int: + errors: list[str] = [] + warnings: list[str] = [] + + check_required_files(errors) + if errors: + for item in errors: + print(f'ERROR: {item}') + return 1 + + metadata = load_data() + check_evidence_paths(metadata, errors) + check_agent_mentions(metadata, warnings) + check_links(errors, warnings) + check_tools_index_consistency(warnings) + + if errors: + for item in errors: + print(f'ERROR: {item}') + if warnings: + for item in warnings: + print(f'WARN: {item}') + + if errors: + return 1 + + print('OK: repository consistency checks passed') + return 0 + + +if __name__ == '__main__': + sys.exit(main()) diff --git a/scripts/check_stale_data.py b/scripts/check_stale_data.py new file mode 100644 index 00000000..064d92d9 --- /dev/null +++ b/scripts/check_stale_data.py @@ -0,0 +1,157 @@ +#!/usr/bin/env python3 +import json +import re +import sys +from collections import defaultdict +from datetime import date, datetime +from pathlib import Path + +ROOT = Path('/root/git/codeagents-x1') +DOCS = ROOT / 'docs' +DATA_FILE = DOCS / 'data' / 'agents-metadata.json' + +CHECK_FILES = [ + ROOT / 'README.md', + DOCS / 'SUMMARY.md', + DOCS / 'comparison' / 'features.md', + DOCS / 'comparison' / 'pricing.md', + DOCS / 'comparison' / 'privacy-telemetry.md', + DOCS / 'comparison' / 'system-requirements.md', + DOCS / 'evidence-index.md', +] + +DATE_PATTERN = re.compile(r'20\d{2}-\d{2}-\d{2}') +STALE_DAYS_WARNING = 45 +DYNAMIC_TERMS = ('Stars', 'stars', '下载', 'downloads', '验证', '测量') + + +def read_text(path: Path) -> str: + return path.read_text(encoding='utf-8') + + +def load_data() -> dict: + return json.loads(read_text(DATA_FILE)) + + +def parse_date(value: str) -> date: + return datetime.strptime(value, '%Y-%m-%d').date() + + +def should_scan_line(line: str) -> bool: + stripped = line.strip() + if not any(term in stripped for term in DYNAMIC_TERMS): + return False + if stripped.startswith('>'): + return False + if stripped.startswith('#'): + return False + return '|' in stripped or stripped.startswith('- ') + + +def collect_metadata_tokens(metadata: dict) -> dict[str, dict[str, set[str]]]: + tokens: dict[str, dict[str, set[str]]] = {} + for agent in metadata.get('agents', []): + bucket: dict[str, set[str]] = defaultdict(set) + name = agent['name'] + bucket['stars'].add(str(agent.get('stars', '')).strip()) + downloads = agent.get('downloads', {}) + bucket['downloads'].add(str(downloads.get('value', '')).strip()) + bucket['dates'].add(str(downloads.get('as_of', '')).strip()) + evidence = agent.get('evidence', {}) + bucket['dates'].add(str(evidence.get('last_verified', '')).strip()) + bucket['pricing'].add(str(agent.get('pricing_summary', '')).strip()) + bucket['free_tier'].add(str(agent.get('free_tier', '')).strip()) + tokens[name] = bucket + return tokens + + +def check_metadata_freshness(metadata: dict, warnings: list[str]): + today = date.today() + all_dates = [] + root_last_updated = metadata.get('last_updated') + if root_last_updated: + all_dates.append(('docs/data/agents-metadata.json:last_updated', root_last_updated)) + for agent in metadata.get('agents', []): + downloads_as_of = agent.get('downloads', {}).get('as_of') + evidence_verified = agent.get('evidence', {}).get('last_verified') + if downloads_as_of: + all_dates.append((f"{agent['id']}:downloads.as_of", downloads_as_of)) + if evidence_verified: + all_dates.append((f"{agent['id']}:evidence.last_verified", evidence_verified)) + for label, value in all_dates: + try: + days = (today - parse_date(value)).days + except ValueError: + warnings.append(f'无法解析日期: {label} -> {value}') + continue + if days > STALE_DAYS_WARNING: + warnings.append(f'数据可能过期: {label} 距今 {days} 天(阈值 {STALE_DAYS_WARNING} 天)') + + +def check_tracked_files_for_token_drift(metadata_tokens: dict[str, dict[str, set[str]]], warnings: list[str]): + for path in CHECK_FILES: + if not path.exists(): + continue + text = read_text(path) + for line_no, line in enumerate(text.splitlines(), start=1): + if not should_scan_line(line): + continue + matched_agents = [name for name in metadata_tokens if name in line] + for agent_name in matched_agents: + token_groups = metadata_tokens[agent_name] + if 'Stars' in line or 'stars' in line or 'Stars' in line: + if token_groups['stars'] and not any(token in line for token in token_groups['stars'] if token): + warnings.append( + f'{path.relative_to(ROOT)}:{line_no} 中 {agent_name} 的 Stars 可能未与 docs/data 同步: {line.strip()}' + ) + if '下载' in line or 'downloads' in line: + if token_groups['downloads'] and not any(token in line for token in token_groups['downloads'] if token and token != '—'): + warnings.append( + f'{path.relative_to(ROOT)}:{line_no} 中 {agent_name} 的下载量可能未与 docs/data 同步: {line.strip()}' + ) + + +def check_date_mentions_against_metadata(metadata: dict, warnings: list[str]): + known_dates = {metadata.get('last_updated', '')} + for agent in metadata.get('agents', []): + known_dates.add(agent.get('downloads', {}).get('as_of', '')) + known_dates.add(agent.get('evidence', {}).get('last_verified', '')) + known_dates = {value for value in known_dates if value} + + for path in CHECK_FILES: + if not path.exists(): + continue + text = read_text(path) + for line_no, line in enumerate(text.splitlines(), start=1): + if not should_scan_line(line): + continue + for found in DATE_PATTERN.findall(line): + if found not in known_dates: + warnings.append( + f'{path.relative_to(ROOT)}:{line_no} 出现未在 docs/data 注册的日期 {found}: {line.strip()}' + ) + + +def main() -> int: + warnings: list[str] = [] + if not DATA_FILE.exists(): + print('ERROR: missing docs/data/agents-metadata.json') + return 1 + + metadata = load_data() + metadata_tokens = collect_metadata_tokens(metadata) + check_metadata_freshness(metadata, warnings) + check_tracked_files_for_token_drift(metadata_tokens, warnings) + check_date_mentions_against_metadata(metadata, warnings) + + if warnings: + for item in warnings: + print(f'WARN: {item}') + return 0 + + print('OK: stale data checks passed') + return 0 + + +if __name__ == '__main__': + sys.exit(main()) From 03c09ba98fcabfec3563337e08ecb65ccd5653c5 Mon Sep 17 00:00:00 2001 From: wenshao Date: Mon, 30 Mar 2026 13:28:34 +0800 Subject: [PATCH 2/7] =?UTF-8?q?=E6=B7=B1=E5=8C=96=E4=B8=8A=E4=B8=8B?= =?UTF-8?q?=E6=96=87=E5=8E=8B=E7=BC=A9=E5=AF=B9=E6=AF=94=E5=B9=B6=E8=A1=A5?= =?UTF-8?q?=E5=85=85=E8=AF=81=E6=8D=AE=E8=BE=B9=E7=95=8C=E8=AF=B4=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Qwen-Coder --- .../context-compression-deep-dive.md | 153 ++++++++++++++---- 1 file changed, 122 insertions(+), 31 deletions(-) diff --git a/docs/comparison/context-compression-deep-dive.md b/docs/comparison/context-compression-deep-dive.md index 682c828c..05342e56 100644 --- a/docs/comparison/context-compression-deep-dive.md +++ b/docs/comparison/context-compression-deep-dive.md @@ -1,27 +1,52 @@ # 27. 上下文压缩算法深度对比 -> 上下文压缩决定了 AI 编程代理在长会话中的信息保留质量。从"一次失败永远放弃"到"四阶段+LLM 验证",实现差距巨大。 +> 上下文压缩决定了 AI 编程代理在长会话中的信息保留质量。不同 Agent 在触发阈值、摘要结构、验证步骤、失败处理和可定制性上差异明显。 + +> **说明**:本文混合使用 3 类证据——开源源码、二进制/官方文档、以及分叉关系推断。对闭源工具或分叉工具,若实现细节未在本仓库证据页中直接钉住,会显式标注“未公开 / 推断 / 待复核”。 ## 总览 -| Agent | 触发阈值 | 算法阶段 | 验证 | 自定义焦点 | 递归 | 后台 | 注入防御 | -|------|---------|---------|------|-----------|------|------|---------| -| **Gemini CLI** | **50%** | **4 阶段** | ✓✓(双 LLM) | ✗ | ✗ | 异步 | **✓** | -| **Goose** | **80%** | 渐进移除 | ✗ | ✗ | ✗ | ✓ | ✗ | -| **Kimi CLI** | **85%** 或 剩余 <50K | 1(结构化 XML) | ✗ | **✓** | ✗ | 异步+重试 | ✗ | -| **Claude Code** | **~95%** | **3 层** | ✗ | **✓** | ✗ | 即时 | ✗ | -| **Aider** | `done_messages > 1024` tokens | 1(递归) | ✗ | ✗ | **✓(×3)** | **✓(线程)** | ✗ | -| **Qwen Code** | 50%(继承) | 4 阶段(继承) | ✓✓ | ✗ | ✗ | 异步 | ✓ | -| **Copilot CLI** | 可配置 | 未公开 | 未知 | ✗ | 未知 | ✓ | 未知 | -| **Codex CLI** | 可配置 | `compact_prompt` | 未知 | ✓(配置) | 未知 | 未知 | 未知 | +| Agent | 触发阈值 | 主压缩路径 | 独立二次验证 | 自定义压缩焦点能力 | 递归 | 执行方式 | 压缩阶段防注入 | +|------|---------|-----------|-------------|------------------|------|---------|---------------| +| **Gemini CLI** | **50%** | **4 阶段** | **✓(Phase 4 Probe)** | ✗ | ✗ | 异步 | **✓** | +| **Goose** | **80%** | 渐进移除 + 回退摘要 | ✗ | ✗ | ✗ | 后台自动压缩 | 未见显式 compact prompt 防注入 | +| **Kimi CLI** | **85%** 或 剩余 <50K | 结构化 XML 摘要 | ✗ | **✓(/compact [FOCUS])** | ✗ | 异步+重试 | ✗ | +| **Claude Code** | **~95%**(版本/缓冲实现可能有差异) | **三层压缩体系** | 未见公开证据 | **✓(/compact [指令])** | ✗ | 非阻塞 | ✗ | +| **Aider** | `done_messages > 1024` tokens | 递归分割摘要 | ✗ | ✗ | **✓(最多 3 层)** | **后台线程** | ✗ | +| **Qwen Code** | 分叉继承,具体阈值待统一(50%/70% 证据冲突) | 4 阶段框架(分叉继承,待逐项复核) | 待复核 | ✗ | ✗ | 异步(继承推断) | 待复核 | +| **Copilot CLI** | 可配置 | 未公开 | 未知 | ✗ | 未知 | 后台 | 未知 | +| **Codex CLI** | 可配置 | 压缩提示可配置,具体算法未公开 | 未知 | **✓(配置级 `compact_prompt`)** | 未知 | 未知 | 未知 | + +> **表格限定**:这里的“压缩阶段防注入”仅指 compact/compression prompt 中是否存在显式的防注入指令,不代表产品整体是否具备注入检测能力;例如 Goose 在整体安全架构中仍有 `PromptInjectionScanner`。 -> **设计权衡:** 早触发(Gemini 50%)= 频繁压缩但上下文保留少;晚触发(Claude 95%)= 保留最多但接近极限风险高。 +> **设计权衡:** 早触发通常意味着更频繁压缩和更宽松的安全余量;晚触发通常意味着保留更多原始上下文,但若前置微压缩不足,接近极限时缓冲更紧张。 --- -## 一、Gemini CLI:四阶段压缩 + 双 LLM 验证(最复杂) +## 分析框架:压缩只是连续性工程的一部分 + +仅比较“几阶段压缩”容易忽略一个事实:多数 Agent 并不是等上下文满了才一次性总结历史,而是把压缩嵌入更大的连续性工程里——包括前置减载、生命周期 Hook、checkpoint、会话骨架、Prompt Caching 与 loop 控制。 + +| Agent | 压缩前减载 | 压缩后/之外的连续性补偿 | 用户可控项 | +|------|-----------|----------------------|-----------| +| **Gemini CLI** | 先截断旧工具输出(50K 预算) | `PreCompress` Hook + checkpoint / rewind + `codebase_investigator` 仓库调查 | 阈值固定;可手动 `/compress`(仓库文档多写作自动为主) | +| **Claude Code** | 微压缩(长工具输出截断/摘要) | `PreCompact` / `PostCompact` Hook + Prompt Caching | `/compact [指令]` | +| **Goose** | 每 10 个工具调用后台摘要;超限前优先移除中间工具输出 | UI 保留完整历史,活跃模型上下文仅保留摘要结果 | `GOOSE_AUTO_COMPACT_THRESHOLD`、`GOOSE_CONTEXT_STRATEGY`、手动 compact | +| **Kimi CLI** | loop_control 里预留 `reserved_context_size=50000` | `CompactionBegin/End` 事件 + checkpoint 绑定的 `/compact` 入口 | `/compact [FOCUS]` | +| **Aider** | 依赖显式文件管理降低上下文噪声 | 后台线程压缩 + 极长会话退化到 `summarize_all()` | 自动为主 | +| **Qwen Code** | 分叉继承 Gemini 压缩框架;并列 `LoopDetectionService` | `PreCompact` Hook + loop 检测服务 | 细节主要见仓库内部源码分析,尚未统一到证据页 | +| **Copilot CLI** | infinite sessions + 后台 compaction | checkpoint titles 作为会话骨架 | `/compact` + `infiniteSessions.*` 阈值配置 | +| **Codex CLI** | 通过 `model_context_window` 与自动 compact 阈值管理预算 | thread 级 compact 生命周期事件 | `/compact` + `compact_prompt` + `model_auto_compact_token_limit` | + +> **阅读提示**:下面各节主要比较“压缩本体”;但实际长会话体验往往同样取决于这些外围机制是否足够强。 + +--- + +## 一、Gemini CLI:四阶段压缩 + 双 LLM 验证(公开实现中流程最细的一类) > 源码:`packages/core/src/services/chatCompressionService.ts` +> +> 相关 prompt:`packages/core/src/prompts/snippets.ts` ### 完整流程 @@ -35,7 +60,7 @@ │ Phase 2: 分割(findCompressSplitPoint) │ ├── 保留最近 30%(COMPRESSION_PRESERVE_THRESHOLD = 0.3) - │ └── 仅在 user 消息边界分割(绝不在工具调用中间切断) + │ └── 优先在 user 消息边界分割,避免在工具调用中间切断 │ Phase 3: 摘要(压缩专用模型) │ ├── 使用 chat-compression-2.5-pro 模型 @@ -67,10 +92,12 @@ - **提示注入防御**:压缩 prompt 中内嵌安全指令,防止恶意工具输出通过压缩过程注入 - **双 LLM 验证**:Phase 4 用独立 LLM 调用批判性评估摘要完整性 - **膨胀检测**:压缩后 token 数反而更多时拒绝压缩 +- **压缩前可介入**:仓库文档可确认 `PreCompress` Hook,说明外部扩展点主要位于压缩前;压缩后的质量回补更多依赖内部 Phase 4 Probe,而不是后置 Hook +- **与 checkpoint / rewind 协同**:Gemini 的长会话连续性不只靠摘要压缩,还靠 checkpoint 和 rewind 维持状态回退能力;`codebase_investigator` 子代理也能在压缩后补偿部分仓库结构感知 --- -## 二、Aider:递归分割摘要(最优雅) +## 二、Aider:递归分割摘要(结构最简洁的一类) > 源码:`aider/history.py`(143 行) @@ -103,12 +130,16 @@ done_messages ──→ 总 token > max_tokens (1024)? - **后台线程**:压缩在独立线程运行,不阻塞用户输入 - **递归深度控制**:最多 3 层递归,超过则 `summarize_all()` - **第一人称视角**:摘要以 "I asked you..." 开头,模拟对话连续性 +- **保留/丢弃语义明确**:Aider 优先保留最近一半 tail 原文,只压缩较早的 head;但在极长会话里会逐步退化为 `summarize_all()`,即几乎全历史摘要化 +- **与显式文件管理协同**:Aider 通过 `/add`、`/drop`、`/read-only` 等显式文件管理降低无关上下文噪声,因此能以相对简洁的递归摘要机制维持可控性 --- ## 三、Claude Code:三层压缩体系 -> 来源:API 文档 `compact-2026-01-12` + 二进制分析 +> 来源:官方 API 文档 `compact-2026-01-12`;二进制分析见 `docs/tools/claude-code/EVIDENCE.md` +> +> 注:本仓库 `Claude Code` 证据页目前未系统收录压缩实现细节,以下若涉及阈值、小版本行为或 prompt 细节,主要依据 API 文档与二进制分析整理。 ### 三层设计 @@ -132,13 +163,26 @@ done_messages ──→ 总 token > max_tokens (1024)? /compact 保留数据库迁移相关讨论 ``` -自 v2.0.64 起压缩即时完成(非阻塞)。 +按本仓库现有 API 文档与二进制分析整理,当前资料将其描述为非阻塞体验。 + +除三层压缩外,Claude Code 还通过 Prompt Caching 降低系统提示与稳定前缀的重复开销。这意味着 Claude 的长会话续航不能仅归因于“~95% 晚触发”,还应把缓存视为压缩之外的重要减载手段。 --- -## 四、Goose:渐进移除策略(最独特) +## 四、Goose:渐进移除策略(策略差异最明显的一类) -> 源码:`context_mgmt/mod.rs`,阈值:`GOOSE_AUTO_COMPACT_THRESHOLD`(默认 0.8) +> 源码:`crates/goose/src/context_mgmt/mod.rs`,阈值:`GOOSE_AUTO_COMPACT_THRESHOLD`(默认 0.8) +> +> 注:本仓库 `Goose` 证据页当前更侧重遥测 / 安全 / MCP 架构,压缩实现细节主要见官方 smart-context-management 文档与仓库内其他二次分析文档。 + +### 两层体系:增量后台摘要 + 超限 compact + +仓库内二次分析与 Goose 官方 smart-context-management 文档共同指向一个更完整的流程: + +1. **增量后台摘要**:默认每超过 10 个工具调用,会先对较旧的工具输出生成后台摘要,降低一次性压缩负载 +2. **超限 compact**:当会话继续逼近 context limit,再启动“中间向外”的渐进移除与 full compact 回退链路 + +这说明 Goose 的设计重点不是“等到 80% 再一次性大总结”,而是尽量把历史工具输出持续折叠,保留头尾骨架与近期现场。 ### "中间向外"策略 @@ -156,11 +200,13 @@ done_messages ──→ 总 token > max_tokens (1024)? 9 段结构化 Markdown,使用 `` 标签包裹推理过程,核心指令:"不引入新想法"。 +> 注:这里关于“9 段 Markdown + ``”的细节,当前主要依据官方文档与仓库二次分析整理,证据强度弱于 Gemini / Aider / Kimi 这类可直接在本仓库源码分析文档中钉到实现细节的对象。 + --- ## 五、Kimi CLI:结构化 XML + 自定义焦点 -> 源码:`soul/compaction.py`、`prompts/compact.md` +> 源码:`src/kimi_cli/soul/compaction.py`、`src/kimi_cli/prompts/compact.md` ### 双触发条件 @@ -191,9 +237,51 @@ done_messages ──→ 总 token > max_tokens (1024)? 使用 `tenacity` 库指数退避:初始 0.3s,最大 5s,抖动 0.5,最多 3 次。 +### 命令入口与事件可观测性 + +- `/compact [FOCUS]` 在执行前会先检查 checkpoint 数;若为 0 则直接返回,不发起无意义压缩 +- 压缩生命周期在 Wire 事件流中可观测:`CompactionBegin/End` +- `compaction_trigger_ratio = 0.85` 与 `reserved_context_size = 50000` 位于同一 `loop_control` 区块,说明 Kimi 把压缩视为主循环预算治理的一部分,而不是单独的会话后处理器 + +--- + +## 六、Qwen Code:分叉继承 Gemini 压缩框架,但常量细节待统一 + +> 来源:`docs/tools/qwen-code/EVIDENCE.md`(确认基于 Gemini CLI 分叉)+ 本仓库其他对比分档 + +Qwen Code 的上下文压缩框架总体上沿袭 Gemini CLI:包括 `ChatCompressionService`、Hook 事件里的 `PreCompact`、以及整体的权限 / 沙箱 / telemetry 基础设施继承关系。 + +但就“是否**完全**继承 Gemini 的每个压缩常量和阈值”而言,本仓库当前证据仍有分层: + +- 多篇文档将其写为 **50%(继承 Gemini)** +- `docs/comparison/claude-code-speed-qwen-improvements.md` 又记录过 **70% 阈值触发**,并将 `COMPRESSION_TOKEN_THRESHOLD = 0.7` 视为仓库内部源码分析结论 +- `docs/comparison/qwen-code-feature-gaps.md` 还记录了一个更具体的失败处理线索:`hasFailedCompressionAttempt` 布尔断路器——一次压缩失败后,后续非强制压缩会跳过 + +因此,更稳妥的结论是: + +- **架构层面**:Qwen Code 继承了 Gemini 的压缩框架 +- **实现细节层面**:仓库内部分析已经出现 70% 阈值与单次失败断路器线索,但这些细节尚未统一汇总到 `docs/tools/qwen-code/EVIDENCE.md` 主证据页,仍应以分叉源码逐项复核 +- **系统治理层面**:Qwen 并非只靠压缩管理长会话;`LoopDetectionService` 与 `PreCompact` Hook 说明它把压缩放在更大的 loop / session 管理栈里 + +这也是本文在总览表中将 Qwen Code 标记为“分叉继承 / 待统一”的原因。 + --- -## 六、摘要 Prompt 哲学对比 +## 七、闭源与半闭源工具:算法未必公开,但控制面已能对比 + +对 Claude Code、Copilot CLI、Codex CLI 这类闭源或未完全公开实现,本文不试图“猜出完整算法”,而更关注当前**已证实的控制面**:用户能调什么、系统暴露了哪些阈值或事件、哪些部分仍未知。 + +| Agent | 已证实控制面 | 已证实生命周期/骨架 | 仍未知 | +|------|-------------|-------------------|------| +| **Claude Code** | `/compact [指令]`、`PreCompact` / `PostCompact`、`compact-2026-01-12` | 三层压缩体系、`` 输出约束 | 精确阈值常量、完整 compact prompt、微压缩算法细节 | +| **Copilot CLI** | `/compact`、`infiniteSessions.backgroundCompactionThreshold`、`bufferExhaustionThreshold` | infinite sessions、checkpoint titles 作为会话骨架 | 默认阈值数值、手动与后台 compact 是否共用同一实现 | +| **Codex CLI** | `/compact`、`compact_prompt`、`model_auto_compact_token_limit`、`model_context_window` | `thread/compact/start`、`thread/compacted` 事件 | 默认 compact prompt、默认阈值、`enable_request_compression` 与摘要 compact 的准确关系 | + +这里 Codex CLI 的特点尤其值得单列:它虽然没有公开完整压缩算法,但**用户可控项反而是三者里最清晰的**。这与 Claude Code / Copilot CLI 的“行为更明确、配置面更弱”形成对照。 + +--- + +## 八、摘要 Prompt 哲学对比 | Agent | 输出格式 | 视角 | 核心指令 | |------|---------|------|---------| @@ -205,7 +293,7 @@ done_messages ──→ 总 token > max_tokens (1024)? --- -## 七、设计模式总结 +## 九、设计模式总结 ### 早触发 vs 晚触发 @@ -213,23 +301,26 @@ done_messages ──→ 总 token > max_tokens (1024)? |------|------|--------|------|------| | 早触发 | Gemini CLI(50%) | 容量过半 | 压缩从容、有验证余地 | 频繁压缩、信息丢失多 | | 中触发 | Goose(80%)/ Kimi(85%) | 接近上限 | 平衡保留与安全 | 大会话可能来不及 | -| 晚触发 | Claude Code(~95%) | 接近极限 | 保留最多上下文 | 紧急压缩、无验证时间 | +| 晚触发 | Claude Code(~95%,实际表现可能受版本/缓冲实现影响) | 接近极限 | 保留最多上下文 | 紧急压缩、无验证时间 | ### 验证步骤的价值 -只有 Gemini CLI 实现了独立验证(Phase 4 Probe)。其他所有工具都信任单次 LLM 输出。这是**成本与质量的核心权衡**——额外一次 LLM 调用的成本 vs 压缩质量提升。 +在本文覆盖且实现细节可核实的 Agent 中,Gemini CLI 是目前唯一明确展示独立 Probe 验证步骤的方案。对 Claude Code、Copilot CLI、Codex CLI 这类闭源或细节未公开工具,更稳妥的表述应是“**未见公开证据**”而不是直接断言其不存在。这体现了成本与质量之间的一组典型权衡:额外一次 LLM 调用的成本 vs 压缩质量提升。 --- ## 证据来源 -| Agent | 源码文件 | 获取方式 | +> **证据强度说明**:Gemini / Aider / Kimi 的实现细节更多直接来自开源源码或本仓库源码分析文档;Claude Code / Copilot CLI / Codex CLI 更依赖官方文档、二进制分析或配置项;Goose 与 Qwen Code 的部分细节当前仍混合使用官方资料、仓库二次分析和分叉关系推断。 + + +| Agent | 主要来源 | 获取方式 | |------|---------|---------| -| Gemini CLI | `chatCompressionService.ts` + `prompts/snippets.ts` | GitHub 源码 | +| Gemini CLI | `packages/core/src/services/chatCompressionService.ts` + `packages/core/src/prompts/snippets.ts` | GitHub 源码 | | Aider | `aider/history.py`(143 行)+ `aider/prompts.py` | GitHub 源码 | -| Claude Code | API 文档 `compact-2026-01-12` + 二进制分析 | 官方文档 + strings | -| Kimi CLI | `soul/compaction.py` + `prompts/compact.md` | GitHub 源码 | -| Goose | `context_mgmt/mod.rs` + [官方文档](https://block.github.io/goose/docs/guides/sessions/smart-context-management/) | GitHub 源码 + 官方文档 | -| Qwen Code | 继承 Gemini CLI | GitHub 源码 | +| Claude Code | 官方 API 文档 `compact-2026-01-12` + `docs/tools/claude-code/EVIDENCE.md` | 官方文档 + 二进制分析 | +| Kimi CLI | `src/kimi_cli/soul/compaction.py` + `src/kimi_cli/prompts/compact.md` | GitHub 源码 | +| Goose | `crates/goose/src/context_mgmt/mod.rs` + [官方文档](https://block.github.io/goose/docs/guides/sessions/smart-context-management/) | GitHub 源码 + 官方文档 | +| Qwen Code | `docs/tools/qwen-code/EVIDENCE.md`(确认 Gemini CLI 分叉)+ 本仓库其他对比分档 | 分叉关系 + 仓库交叉审计 | | Copilot CLI | `infiniteSessions.backgroundCompactionThreshold` | SEA 反编译 | -| Codex CLI | `compact_prompt` 配置 | 二进制分析 | +| Codex CLI | `compact_prompt`、`model_auto_compact_token_limit` 配置项 | 二进制分析 | From 78492b26b0a59e71dd1d74118220a86cfb5ae78f Mon Sep 17 00:00:00 2001 From: wenshao Date: Mon, 30 Mar 2026 14:14:08 +0800 Subject: [PATCH 3/7] =?UTF-8?q?=E6=94=B6=E7=B4=A7=20Goose=20=E5=8E=8B?= =?UTF-8?q?=E7=BC=A9=E7=AD=96=E7=95=A5=E8=A1=A8=E8=BF=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Qwen-Coder --- docs/comparison/context-compression-deep-dive.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/comparison/context-compression-deep-dive.md b/docs/comparison/context-compression-deep-dive.md index 52757339..fb290152 100644 --- a/docs/comparison/context-compression-deep-dive.md +++ b/docs/comparison/context-compression-deep-dive.md @@ -31,7 +31,7 @@ |------|-----------|----------------------|-----------| | **Gemini CLI** | 先截断旧工具输出(50K 预算) | `PreCompress` Hook + checkpoint / rewind + `codebase_investigator` 仓库调查 | 阈值固定;可手动 `/compress`(仓库文档多写作自动为主) | | **Claude Code** | 微压缩(长工具输出截断/摘要) | `PreCompact` / `PostCompact` Hook + Prompt Caching | `/compact [指令]` | -| **Goose** | 每 10 个工具调用后台摘要;超限前优先移除中间工具输出 | UI 保留完整历史,活跃模型上下文仅保留摘要结果 | `GOOSE_AUTO_COMPACT_THRESHOLD`、`GOOSE_CONTEXT_STRATEGY`、手动 compact | +| **Goose** | 以 10 个工具调用为一批进行增量摘要;超限前优先移除中间工具输出 | UI 保留完整历史,活跃模型上下文仅保留摘要结果 | `GOOSE_AUTO_COMPACT_THRESHOLD`、手动 compact | | **Kimi CLI** | loop_control 里预留 `reserved_context_size=50000` | `CompactionBegin/End` 事件 + checkpoint 绑定的 `/compact` 入口 | `/compact [FOCUS]` | | **Aider** | 依赖显式文件管理降低上下文噪声 | 后台线程压缩 + 极长会话退化到 `summarize_all()` | 自动为主 | | **Qwen Code** | 分叉继承 Gemini 压缩框架;并列 `LoopDetectionService` | `PreCompact` Hook + loop 检测服务 | 细节主要见仓库内部源码分析,尚未统一到证据页 | @@ -179,7 +179,7 @@ done_messages ──→ 总 token > max_tokens (1024)? 仓库内二次分析与 Goose 官方 smart-context-management 文档共同指向一个更完整的流程: -1. **增量后台摘要**:默认每超过 10 个工具调用,会先对较旧的工具输出生成后台摘要,降低一次性压缩负载 +1. **增量后台摘要**:按 10 个工具调用为一批,对较旧的工具输出做增量摘要,降低一次性压缩负载 2. **超限 compact**:当会话继续逼近 context limit,再启动“中间向外”的渐进移除与 full compact 回退链路 这说明 Goose 的设计重点不是“等到 80% 再一次性大总结”,而是尽量把历史工具输出持续折叠,保留头尾骨架与近期现场。 From 1ac306ce6681e0ae3060a5a91bed6e32e896798b Mon Sep 17 00:00:00 2001 From: wenshao Date: Mon, 30 Mar 2026 15:02:58 +0800 Subject: [PATCH 4/7] =?UTF-8?q?=E6=94=B6=E7=B4=A7=E5=8E=8B=E7=BC=A9?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3=E4=B8=8E=E6=A0=BC=E5=BC=8F=E8=AE=A1=E6=95=B0?= =?UTF-8?q?=E8=A1=A8=E8=BF=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Qwen-Coder --- docs/comparison/context-compression-deep-dive.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/comparison/context-compression-deep-dive.md b/docs/comparison/context-compression-deep-dive.md index fb290152..18fd0abe 100644 --- a/docs/comparison/context-compression-deep-dive.md +++ b/docs/comparison/context-compression-deep-dive.md @@ -12,7 +12,7 @@ | **Goose** | **80%** | 渐进移除 + 回退摘要 | ✗ | ✗ | ✗ | 后台自动压缩 | 未见显式 compact prompt 防注入 | | **Kimi CLI** | **85%** 或 剩余 <50K | 结构化 XML 摘要 | ✗ | **✓(/compact [FOCUS])** | ✗ | 异步+重试 | ✗ | | **Claude Code** | **~95%**(版本/缓冲实现可能有差异) | **三层压缩体系** | 未见公开证据 | **✓(/compact [指令])** | ✗ | 非阻塞 | ✗ | -| **Aider** | `done_messages > 1024` tokens | 递归分割摘要 | ✗ | ✗ | **✓(最多 3 层)** | **后台线程** | ✗ | +| **Aider** | 总 token 数 > 1024(默认阈值) | 递归分割摘要 | ✗ | ✗ | **✓(最多 3 层)** | **后台线程** | ✗ | | **Qwen Code** | 分叉继承,具体阈值待统一(50%/70% 证据冲突) | 4 阶段框架(分叉继承,待逐项复核) | 待复核 | ✗ | ✗ | 异步(继承推断) | 待复核 | | **Copilot CLI** | 可配置 | 未公开 | 未知 | ✗ | 未知 | 后台 | 未知 | | **Codex CLI** | 可配置 | 压缩提示可配置,具体算法未公开 | 未知 | **✓(配置级 `compact_prompt`)** | 未知 | 未知 | 未知 | @@ -137,9 +137,9 @@ done_messages ──→ 总 token > max_tokens (1024)? ## 三、Claude Code:三层压缩体系 -> 来源:官方 API 文档 `compact-2026-01-12`;二进制分析见 `docs/tools/claude-code/EVIDENCE.md` +> 来源:本仓库现有 Claude Code 文档对 `compact-2026-01-12` 的记载 + 二进制分析上下文;补充见 `docs/tools/claude-code/02-commands.md` 与 `docs/tools/claude-code/EVIDENCE.md` > -> 注:本仓库 `Claude Code` 证据页目前未系统收录压缩实现细节,以下若涉及阈值、小版本行为或 prompt 细节,主要依据 API 文档与二进制分析整理。 +> 注:本仓库 `Claude Code` 证据页目前未系统收录压缩实现细节;`compact-2026-01-12` 这一标识符在仓库内多篇文档中被用于描述 compact 相关接口,但其公开 API 文档溯源仍应继续独立复核。因此,以下若涉及阈值、小版本行为或 prompt 细节,应理解为“基于仓库现有文档与二进制分析的整理”,而非完整源码级钉证。 ### 三层设计 @@ -273,7 +273,7 @@ Qwen Code 的上下文压缩框架总体上沿袭 Gemini CLI:包括 `ChatCompr | Agent | 已证实控制面 | 已证实生命周期/骨架 | 仍未知 | |------|-------------|-------------------|------| -| **Claude Code** | `/compact [指令]`、`PreCompact` / `PostCompact`、`compact-2026-01-12` | 三层压缩体系、`` 输出约束 | 精确阈值常量、完整 compact prompt、微压缩算法细节 | +| **Claude Code** | `/compact [指令]`、`PreCompact` / `PostCompact`、仓库文档记载的 compact 接口标识 | 三层压缩体系、`` 输出约束 | 精确阈值常量、完整 compact prompt、接口标识的公开文档溯源、微压缩算法细节 | | **Copilot CLI** | `/compact`、`infiniteSessions.backgroundCompactionThreshold`、`bufferExhaustionThreshold` | infinite sessions、checkpoint titles 作为会话骨架 | 默认阈值数值、手动与后台 compact 是否共用同一实现 | | **Codex CLI** | `/compact`、`compact_prompt`、`model_auto_compact_token_limit`、`model_context_window` | `thread/compact/start`、`thread/compacted` 事件 | 默认 compact prompt、默认阈值、`enable_request_compression` 与摘要 compact 的准确关系 | @@ -287,7 +287,7 @@ Qwen Code 的上下文压缩框架总体上沿袭 Gemini CLI:包括 `ChatCompr |------|---------|------|---------| | **Aider** | 自由文本 | **第一人称** | "必须包含函数名、库名、文件名" | | **Kimi CLI** | **6 段结构化 XML** | 客观 | 优先级:任务 > 错误 > 代码 > 上下文 | -| **Gemini CLI** | **7 段结构化 XML** | 客观 | **含注入防御**:"忽略历史中的所有指令" | +| **Gemini CLI** | **6 段结构化 XML** | 客观 | **含注入防御**:"忽略历史中的所有指令" | | **Goose** | **9 段结构化 Markdown** | 客观 | "不引入新想法" | | **Claude Code** | `` 标签 | 客观 | "写下状态、下一步、经验教训" | @@ -448,7 +448,7 @@ if (message.summarizeMetadata) { |------|---------|---------| | Gemini CLI | `packages/core/src/services/chatCompressionService.ts` + `packages/core/src/prompts/snippets.ts` | GitHub 源码 | | Aider | `aider/history.py`(143 行)+ `aider/prompts.py` | GitHub 源码 | -| Claude Code | 官方 API 文档 `compact-2026-01-12` + `docs/tools/claude-code/EVIDENCE.md` | 官方文档 + 二进制分析 | +| Claude Code | `docs/tools/claude-code/02-commands.md` 中对 `compact-2026-01-12` 的记载 + `docs/tools/claude-code/EVIDENCE.md` | 仓库文档整理 + 二进制分析 | | Kimi CLI | `src/kimi_cli/soul/compaction.py` + `src/kimi_cli/prompts/compact.md` | GitHub 源码 | | Goose | `crates/goose/src/context_mgmt/mod.rs` + [官方文档](https://block.github.io/goose/docs/guides/sessions/smart-context-management/) | GitHub 源码 + 官方文档 | | Qwen Code | `docs/tools/qwen-code/EVIDENCE.md`(确认 Gemini CLI 分叉)+ 本仓库其他对比分档 | 分叉关系 + 仓库交叉审计 | From 66a33d4d5dd08e83dfc8a953df0fce3e5bc6a894 Mon Sep 17 00:00:00 2001 From: wenshao Date: Mon, 30 Mar 2026 15:33:32 +0800 Subject: [PATCH 5/7] =?UTF-8?q?=E8=A1=A5=E5=85=85=E4=B8=8A=E4=B8=8B?= =?UTF-8?q?=E6=96=87=E5=8E=8B=E7=BC=A9=E7=A0=94=E7=A9=B6=E8=83=8C=E6=99=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Qwen-Coder --- .../context-compression-deep-dive.md | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/docs/comparison/context-compression-deep-dive.md b/docs/comparison/context-compression-deep-dive.md index 18fd0abe..2aa046ee 100644 --- a/docs/comparison/context-compression-deep-dive.md +++ b/docs/comparison/context-compression-deep-dive.md @@ -40,6 +40,20 @@ > **阅读提示**:下面各节主要比较“压缩本体”;但实际长会话体验往往同样取决于这些外围机制是否足够强。 +### 研究背景:为什么上下文压缩仍然必要 + +从近两年的论文与工程文章看,“上下文压缩”之所以仍是 Agent 设计中的核心问题,不是因为模型没有更大的 context window,而是因为**标称窗口大小**、**有效可用上下文**与**长任务稳定性**并不等价。 + +- **长上下文不等于高质量利用**:`Lost in the Middle`(Liu et al., 2023)指出,模型在长上下文里对中间位置的信息利用明显弱于首尾位置;这意味着“尽量保留全部原始历史”不一定优于“保留更高信号的摘要或结构化状态” +- **标称窗口不等于有效工作窗口**:`RULER`(Hsieh et al., 2024)强调,模型宣称支持的长上下文长度与其在复杂任务中的稳定可用上下文并不相同;随着长度和任务复杂度上升,真实可用窗口会缩水 +- **压缩只是 context engineering 的一个子问题**:Anthropic 在 `Effective Context Engineering for AI Agents` 中将 compression、retrieval、memory、context selection 放在同一框架下讨论,核心目标不是“塞进更多 token”,而是“保留最小但高信号的上下文” +- **compaction 并不总优于 reset**:Anthropic 在 `Harness Design for Long-Running Agentic Apps` 中进一步提出 `context anxiety`——某些模型在接近上下文上限时会提前收尾。此时 compaction 虽能保留连续性,却不一定能移除导致退化的状态;结构化 handoff + context reset 反而可能更稳 +- **压缩不只等于摘要**:`Selective Context`(Li et al., 2023)说明,prompt/context compression 还可以通过选择性剪枝完成,而不仅仅是生成摘要;这对理解 Copilot CLI / Codex CLI 这类“算法细节未公开,但配置面可控”的工具尤其重要 + +因此,本文比较的重点不是“谁保留了更多 token”,而是:**谁能在有限且会退化的有效上下文中,保留更高信号的信息,并用更低成本维持任务连续性。** + +> 参考:Liu et al., *Lost in the Middle* (2023);Hsieh et al., *RULER* (2024);Anthropic, *Effective Context Engineering for AI Agents*;Anthropic, *Harness Design for Long-Running Agentic Apps*;Li et al., *Selective Context* (2023) + --- ## 一、Gemini CLI:四阶段压缩 + 双 LLM 验证(公开实现中流程最细的一类) @@ -454,3 +468,11 @@ if (message.summarizeMetadata) { | Qwen Code | `docs/tools/qwen-code/EVIDENCE.md`(确认 Gemini CLI 分叉)+ 本仓库其他对比分档 | 分叉关系 + 仓库交叉审计 | | Copilot CLI | `infiniteSessions.backgroundCompactionThreshold` | SEA 反编译 | | Codex CLI | `compact_prompt`、`model_auto_compact_token_limit` 配置项 | 二进制分析 | + +### 外部研究 / 工程参考 + +- Liu et al., [*Lost in the Middle: How Language Models Use Long Contexts*](https://arxiv.org/abs/2307.03172), 2023 +- Hsieh et al., [*RULER: What’s the Real Context Size of Your Long-Context Language Models?*](https://arxiv.org/abs/2404.06654), 2024 +- Li et al., [*Selective Context: Compressing Context to Enhance Inference Efficiency of Large Language Models*](https://arxiv.org/abs/2310.06201), 2023 +- Anthropic, [*Effective Context Engineering for AI Agents*](https://www.anthropic.com/engineering/effective-context-engineering-for-ai-agents) +- Anthropic, [*Harness Design for Long-Running Agentic Apps*](https://www.anthropic.com/engineering/harness-design-long-running-apps) From f0de489c490ba5e70e736cbeac3fcbfc81a194f9 Mon Sep 17 00:00:00 2001 From: wenshao Date: Mon, 30 Mar 2026 17:39:37 +0800 Subject: [PATCH 6/7] =?UTF-8?q?=E7=BB=9F=E4=B8=80=E5=8E=8B=E7=BC=A9?= =?UTF-8?q?=E8=AF=81=E6=8D=AE=E5=8F=A3=E5=BE=84=E4=B8=8E=E8=A1=A8=E8=BF=B0?= =?UTF-8?q?=E8=BE=B9=E7=95=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Qwen-Coder --- .../context-compression-deep-dive.md | 36 +++++++++---------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/docs/comparison/context-compression-deep-dive.md b/docs/comparison/context-compression-deep-dive.md index 2aa046ee..92570459 100644 --- a/docs/comparison/context-compression-deep-dive.md +++ b/docs/comparison/context-compression-deep-dive.md @@ -13,7 +13,7 @@ | **Kimi CLI** | **85%** 或 剩余 <50K | 结构化 XML 摘要 | ✗ | **✓(/compact [FOCUS])** | ✗ | 异步+重试 | ✗ | | **Claude Code** | **~95%**(版本/缓冲实现可能有差异) | **三层压缩体系** | 未见公开证据 | **✓(/compact [指令])** | ✗ | 非阻塞 | ✗ | | **Aider** | 总 token 数 > 1024(默认阈值) | 递归分割摘要 | ✗ | ✗ | **✓(最多 3 层)** | **后台线程** | ✗ | -| **Qwen Code** | 分叉继承,具体阈值待统一(50%/70% 证据冲突) | 4 阶段框架(分叉继承,待逐项复核) | 待复核 | ✗ | ✗ | 异步(继承推断) | 待复核 | +| **Qwen Code** | 默认设置文档为 **70%**;框架源自 Gemini,早期资料曾写 50% | 4 阶段框架(分叉继承,待逐项复核) | 待复核 | ✗ | ✗ | 异步(继承推断) | 待复核 | | **Copilot CLI** | 可配置 | 未公开 | 未知 | ✗ | 未知 | 后台 | 未知 | | **Codex CLI** | 可配置 | 压缩提示可配置,具体算法未公开 | 未知 | **✓(配置级 `compact_prompt`)** | 未知 | 未知 | 未知 | @@ -31,10 +31,10 @@ |------|-----------|----------------------|-----------| | **Gemini CLI** | 先截断旧工具输出(50K 预算) | `PreCompress` Hook + checkpoint / rewind + `codebase_investigator` 仓库调查 | 阈值固定;可手动 `/compress`(仓库文档多写作自动为主) | | **Claude Code** | 微压缩(长工具输出截断/摘要) | `PreCompact` / `PostCompact` Hook + Prompt Caching | `/compact [指令]` | -| **Goose** | 以 10 个工具调用为一批进行增量摘要;超限前优先移除中间工具输出 | UI 保留完整历史,活跃模型上下文仅保留摘要结果 | `GOOSE_AUTO_COMPACT_THRESHOLD`、手动 compact | +| **Goose** | 以 10 个工具调用为一批进行增量摘要;超限前优先移除中间工具输出 | UI 保留完整历史,活跃模型上下文仅保留摘要结果 | 默认压缩阈值 `0.8` + 手动 compact(文档/环境变量命名待区分) | | **Kimi CLI** | loop_control 里预留 `reserved_context_size=50000` | `CompactionBegin/End` 事件 + checkpoint 绑定的 `/compact` 入口 | `/compact [FOCUS]` | | **Aider** | 依赖显式文件管理降低上下文噪声 | 后台线程压缩 + 极长会话退化到 `summarize_all()` | 自动为主 | -| **Qwen Code** | 分叉继承 Gemini 压缩框架;并列 `LoopDetectionService` | `PreCompact` Hook + loop 检测服务 | 细节主要见仓库内部源码分析,尚未统一到证据页 | +| **Qwen Code** | 分叉继承 Gemini 压缩框架;并列 `LoopDetectionService` | `PreCompact` Hook + loop 检测服务 | 当前项目设置文档默认值为 0.7,其他细节仍待统一到主证据页 | | **Copilot CLI** | infinite sessions + 后台 compaction | checkpoint titles 作为会话骨架 | `/compact` + `infiniteSessions.*` 阈值配置 | | **Codex CLI** | 通过 `model_context_window` 与自动 compact 阈值管理预算 | thread 级 compact 生命周期事件 | `/compact` + `compact_prompt` + `model_auto_compact_token_limit` | @@ -185,7 +185,7 @@ done_messages ──→ 总 token > max_tokens (1024)? ## 四、Goose:渐进移除策略(策略差异最明显的一类) -> 源码:`crates/goose/src/context_mgmt/mod.rs`,阈值:`GOOSE_AUTO_COMPACT_THRESHOLD`(默认 0.8) +> 源码位置见 `crates/goose/src/context_mgmt/mod.rs`;当前可稳定引用的是默认压缩阈值 **0.8**,文档名、环境变量名与实现常量名在仓库交叉文档中尚未完全统一。 > > 注:本仓库 `Goose` 证据页当前更侧重遥测 / 安全 / MCP 架构,压缩实现细节主要见官方 smart-context-management 文档与仓库内其他二次分析文档。 @@ -265,19 +265,20 @@ done_messages ──→ 总 token > max_tokens (1024)? Qwen Code 的上下文压缩框架总体上沿袭 Gemini CLI:包括 `ChatCompressionService`、Hook 事件里的 `PreCompact`、以及整体的权限 / 沙箱 / telemetry 基础设施继承关系。 -但就“是否**完全**继承 Gemini 的每个压缩常量和阈值”而言,本仓库当前证据仍有分层: +但就“当前默认阈值”与“早期资料中的继承表述”而言,本仓库现有证据需要分层处理: -- 多篇文档将其写为 **50%(继承 Gemini)** -- `docs/comparison/claude-code-speed-qwen-improvements.md` 又记录过 **70% 阈值触发**,并将 `COMPRESSION_TOKEN_THRESHOLD = 0.7` 视为仓库内部源码分析结论 +- `docs/tools/qwen-code/05-settings.md` 已将 `model.chatCompression.contextPercentageThreshold` 的默认值写为 **0.7(70%)** +- 多篇更早的对比文档仍把其概括为 **50%(沿袭 Gemini 默认阈值)** - `docs/comparison/qwen-code-feature-gaps.md` 还记录了一个更具体的失败处理线索:`hasFailedCompressionAttempt` 布尔断路器——一次压缩失败后,后续非强制压缩会跳过 因此,更稳妥的结论是: - **架构层面**:Qwen Code 继承了 Gemini 的压缩框架 -- **实现细节层面**:仓库内部分析已经出现 70% 阈值与单次失败断路器线索,但这些细节尚未统一汇总到 `docs/tools/qwen-code/EVIDENCE.md` 主证据页,仍应以分叉源码逐项复核 +- **当前设置层面**:项目内可直接引用的设置文档默认值为 **70%**;“50%”更适合视为早期继承关系或旧文档表述 +- **实现细节层面**:失败断路器等内部分析线索仍未统一汇总到 `docs/tools/qwen-code/EVIDENCE.md` 主证据页,仍应以分叉源码逐项复核 - **系统治理层面**:Qwen 并非只靠压缩管理长会话;`LoopDetectionService` 与 `PreCompact` Hook 说明它把压缩放在更大的 loop / session 管理栈里 -这也是本文在总览表中将 Qwen Code 标记为“分叉继承 / 待统一”的原因。 +这也是本文在总览表中将 Qwen Code 写为“框架继承 + 当前设置默认值 70%”而非简单复写 Gemini 数值的原因。 --- @@ -326,12 +327,9 @@ Anthropic 工程团队在长任务 harness 开发中发现:**模型在上下 > **Compaction vs Context Reset 的区别**(原文):Compaction 是"原地摘要,保持连续性";Context Reset 是"清空重来,代价是需要足够的交接信息让下一个 Agent 接手"。 -**这解释了压缩阈值差异的深层原因**: -- Claude Code 设 ~95% 阈值——如果使用 Opus 4.5+,context anxiety 的影响可能已大幅降低("largely removed"),使得更晚触发压缩成为可能 -- 如果使用 Sonnet 作为主模型,可能需要更早触发或使用 context reset -- Gemini CLI 50% 阈值——可能 Gemini 模型也存在类似的 context anxiety +这类工程观察更适合作为**理解压缩策略差异的解释框架**,而不是直接用于反推每个产品阈值的设计因果。换言之,它可以帮助理解为什么一些系统会更重视“保留连续性”,另一些系统会更重视“重置后重新交接”,但若缺少产品方直接说明,就不宜据此断言 Claude Code、Gemini CLI 或其他 Agent 的具体阈值就是由 `context anxiety` 直接决定的。 -> **实践建议**:压缩阈值不应只考虑"保留多少上下文",还应考虑"模型在多少容量下开始焦虑"。不同模型的焦虑阈值不同。 +> **实践建议**:压缩阈值不应只考虑"保留多少上下文",还应考虑模型在接近容量上限时的稳定性、摘要成本、交接复杂度与可验证性;但具体阈值设计仍应以各产品的直接证据为准。 ### "Context Rot"上下文腐烂(来源:[Effective Context Engineering](https://www.anthropic.com/engineering/effective-context-engineering-for-ai-agents),2025-09-29) @@ -359,7 +357,7 @@ Anthropic 工程团队在长任务 harness 开发中发现:**模型在上下 --- -## 八、压缩后的 UI 行为:清屏 vs 保留 +## 十、压缩后的 UI 行为:清屏 vs 保留 压缩不仅是后端操作——**用户看到什么**直接影响对 Agent 状态的认知。各 Agent 在压缩后的 UI 处理策略差异显著。 @@ -408,7 +406,7 @@ if (message.summarizeMetadata) { | Agent | 压缩后清屏? | 用户看到什么 | 来源 | |------|------------|------------|------| | **Claude Code** | **是** | "Summarized conversation" 标记 + 新的空白对话区域 | 二进制分析 v2.1.86 | -| **Kimi CLI**(Web UI) | **是** | 仅保留最后一轮用户消息起的内容 | 源码:`useSessionStream.ts` `CompactionEnd` handler | +| **Kimi CLI(Web UI)** | **是** | 仅保留最后一轮用户消息起的内容 | 源码:`useSessionStream.ts` `CompactionEnd` handler | | **Gemini CLI** | 否 | 内联显示 "Chat history compressed from X to Y tokens" | 源码:`compressCommand.ts` → `ui.addItem()` | | **Qwen Code** | 否 | 继承 Gemini(内联压缩状态消息) | 源码:`compressCommand.ts`(分叉) | | **Aider** | 否 | 后台静默替换消息列表,无可见变化(verbose 模式下显示一行日志) | 源码:`base_coder.py` L1002-1034 | @@ -420,14 +418,14 @@ if (message.summarizeMetadata) { | 策略 | 优势 | 劣势 | |------|------|------| -| **清屏**(Claude Code、Kimi) | 状态一致、心理重置、防误导 | 用户失去视觉上下文回溯、可能中断思路 | +| **清屏**(Claude Code、Kimi Web UI) | 状态一致、心理重置、防误导 | 用户失去视觉上下文回溯、可能中断思路 | | **保留**(Gemini、Qwen、Aider、Codex) | 视觉连续性、可回溯历史、不中断流程 | 用户可能误以为模型"记得"全部内容 | -> **核心洞察**:清屏与否反映了两种不同的设计哲学——**状态准确性**(显示的 = 模型知道的)vs **视觉连续性**(保留用户的阅读上下文)。Claude Code 和 Kimi CLI 选择了前者,其他 Agent 选择了后者。没有绝对的对错——这取决于用户对 Agent 状态感知的期望。 +> **核心洞察**:清屏与否反映了两种不同的设计哲学——**状态准确性**(显示的 = 模型知道的)vs **视觉连续性**(保留用户的阅读上下文)。就当前可核实证据看,Claude Code 与 Kimi Web UI 更接近前者,其他 Agent 更接近后者。没有绝对的对错——这取决于用户对 Agent 状态感知的期望。 --- -## 九、工具定义膨胀:134K tokens 的教训(来源:[Anthropic Engineering Blog](https://www.anthropic.com/engineering/advanced-tool-use),2025-11-24) +## 十一、工具定义膨胀:134K tokens 的教训(来源:[Anthropic Engineering Blog](https://www.anthropic.com/engineering/advanced-tool-use),2025-11-24) 上下文压缩不仅要处理对话历史——**工具定义本身就是上下文膨胀的主要来源**: From 1e82de970d84c79fa89d7510f1d110fe4b82df0e Mon Sep 17 00:00:00 2001 From: wenshao Date: Mon, 30 Mar 2026 19:08:11 +0800 Subject: [PATCH 7/7] =?UTF-8?q?=E6=94=B6=E7=B4=A7=20Kimi=20=E5=8E=8B?= =?UTF-8?q?=E7=BC=A9=E6=A0=BC=E5=BC=8F=E8=A1=A8=E8=BF=B0=E8=BE=B9=E7=95=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Qwen-Coder --- docs/comparison/context-compression-deep-dive.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/docs/comparison/context-compression-deep-dive.md b/docs/comparison/context-compression-deep-dive.md index 92570459..7c104491 100644 --- a/docs/comparison/context-compression-deep-dive.md +++ b/docs/comparison/context-compression-deep-dive.md @@ -10,7 +10,7 @@ |------|---------|-----------|-------------|------------------|------|---------|---------------| | **Gemini CLI** | **50%** | **4 阶段** | **✓(Phase 4 Probe)** | ✗ | ✗ | 异步 | **✓** | | **Goose** | **80%** | 渐进移除 + 回退摘要 | ✗ | ✗ | ✗ | 后台自动压缩 | 未见显式 compact prompt 防注入 | -| **Kimi CLI** | **85%** 或 剩余 <50K | 结构化 XML 摘要 | ✗ | **✓(/compact [FOCUS])** | ✗ | 异步+重试 | ✗ | +| **Kimi CLI** | **85%** 或 剩余 <50K | 带标签的结构化摘要 | ✗ | **✓(/compact [FOCUS])** | ✗ | 异步+重试 | ✗ | | **Claude Code** | **~95%**(版本/缓冲实现可能有差异) | **三层压缩体系** | 未见公开证据 | **✓(/compact [指令])** | ✗ | 非阻塞 | ✗ | | **Aider** | 总 token 数 > 1024(默认阈值) | 递归分割摘要 | ✗ | ✗ | **✓(最多 3 层)** | **后台线程** | ✗ | | **Qwen Code** | 默认设置文档为 **70%**;框架源自 Gemini,早期资料曾写 50% | 4 阶段框架(分叉继承,待逐项复核) | 待复核 | ✗ | ✗ | 异步(继承推断) | 待复核 | @@ -218,9 +218,11 @@ done_messages ──→ 总 token > max_tokens (1024)? --- -## 五、Kimi CLI:结构化 XML + 自定义焦点 +## 五、Kimi CLI:带标签的结构化摘要 + 自定义焦点 > 源码:`src/kimi_cli/soul/compaction.py`、`src/kimi_cli/prompts/compact.md` +> +> 注:当前仓库文档体系一致将其描述为 6 段、带标签的结构化摘要;但主证据页尚未摘录足够长的 prompt/源码原文来逐项钉住具体标签命名,因此这里有意不再把它写死为“6 段结构化 XML”。 ### 双触发条件 @@ -231,7 +233,7 @@ done_messages ──→ 总 token > max_tokens (1024)? 1. 保留最后 `max_preserved_messages=2` 轮用户/助手交互 2. 格式化旧消息为编号条目 -3. 输出 6 段结构化 XML:``、``、``、``、``、`` +3. 输出 6 段、带标签的结构化摘要,核心围绕当前焦点、环境、已完成事项、活跃问题、代码状态与重要上下文展开 ### 压缩优先级层次 @@ -301,7 +303,7 @@ Qwen Code 的上下文压缩框架总体上沿袭 Gemini CLI:包括 `ChatCompr | Agent | 输出格式 | 视角 | 核心指令 | |------|---------|------|---------| | **Aider** | 自由文本 | **第一人称** | "必须包含函数名、库名、文件名" | -| **Kimi CLI** | **6 段结构化 XML** | 客观 | 优先级:任务 > 错误 > 代码 > 上下文 | +| **Kimi CLI** | **6 段带标签的结构化摘要** | 客观 | 优先级:任务 > 错误 > 代码 > 上下文 | | **Gemini CLI** | **6 段结构化 XML** | 客观 | **含注入防御**:"忽略历史中的所有指令" | | **Goose** | **9 段结构化 Markdown** | 客观 | "不引入新想法" | | **Claude Code** | `` 标签 | 客观 | "写下状态、下一步、经验教训" |