欢迎光临
我们一直在努力

实战横评】主流 AI 编程工具实测对比,看完不再盲目选型

AI 编程工具横评实测报告(2026-08-04)

7 款 AI 编程工具,同一模型(deepseek-v4-flash)、同一测试题、同一网关并行实测。 附带 token 消耗对比 + 代码质量 + 速度 + 易用性 + 已知 bug 全记录。


目录

  • 快速结论(30 秒版)
  • 测试方法(完整版)
    • 测试题原文 / 统一环境 / 执行命令 / 判定标准 / 局限与偏差 / 选型决策
  • 结果总表
  • 分工具详解(7 款逐一分析)
  • 模型对比:glm_for_coding vs deepseek-v4-flash
  • 最终推荐
  • 部署与配置坑(详版)
  • Token 数据证据链
  • 测试产物全集(7 份完整代码 + pytest 输出)

快速结论(30 秒版)

结论
说明
🏆 最佳工具 OpenCode — 最快(32s)+ 最省 token(11.7K),质量过关
质量天花板 Claude Code — 22/22 测试最全最严谨,但 token 消耗最大
意外之喜 Codex — 换 deepseek 后从失败×4 变 13/13(之前是模型问题)
配置最坑 Goose / Crush — 修好配置后都能用,但过程曲折(详见部署坑)
不推荐 Kilo(OpenCode 劣化版)、Cline CLI(team_status 崩溃 bug)
通用结论 deepseek-v4-flash 是当前网关下最佳编码模型(比 glm_for_coding 快 5-15 倍)

阅读导航:想复现测试看 测试方法;想挑工具看 最终推荐;想看各工具实际写的代码看 测试产物全集;想避坑看 部署与配置坑;想核对数字看 Token 证据链。


测试方法(完整版)

1. 测试题(逐字原文,所有工具收到的 prompt 完全相同)

Create todo.py (Python CLI todo app with add/list/done/delete commands and JSON persistence) and test_todo.py (pytest unit tests). Run the tests and make sure they pass.

中文翻译:创建 todo.py(带 add/list/done/delete 命令和 JSON 持久化的 Python CLI 待办应用)和 test_todo.py(pytest 单元测试)。运行测试并确保全部通过。

这个测试题考察的能力:

  • 理解需求并拆解(CLI 命令设计、JSON 存储设计)
  • 写出可测试的代码(函数/类结构可被 pytest 引用)
  • 自己写测试用例覆盖功能
  • 执行测试、发现失败、修复到全过(自我验证闭环)
  • 工具链使用(argparse、json、pytest、文件读写)

2. 统一环境



测试日期 2026-08-04
模型 deepseek-v4-flash(统一,通过网关 https://api.myagentlab.homes/v1)
API key 同一把网关 key(用户提供,见 credentials)
系统 root 用户,Linux
Python 3.13.5
pytest 9.1.1(venv: /tmp/bench-venv,系统无 pip 故用 uv 建 venv 装)
工作目录 /home/agent/coding-benchmark/test-<工具名>/(每工具独立目录,互不干扰)
执行方式 7 工具并行后台运行(同模型同 key 同时跑,网关竞争环境一致)

3. 每个工具的具体执行命令(实测用的真实命令)

工具
启动命令
备注
Claude Code claude -p \”<测试题>\” –model deepseek-v4-flash –allowedTools \’Bash,Write,Read,Edit\’ –output-format stream-json –verbose root 不能用 –dangerously-skip-permissions
OpenCode opencode run \”<测试题>\” 项目级 opencode.json 配 myagentlab provider
Codex codex exec –dangerously-bypass-approvals-and-sandbox –skip-git-repo-check –json \'<测试题>\’ config.toml 配 wire_api=chat
Cline cline –json \”<测试题>\” cline auth openai 配好;team_status bug 需 enableTeams:false 缓解
Kilo kilo run -m myagentlab/deepseek-v4-flash \”<测试题>\” kilo.jsonc 配 myagentlab provider
Crush crush run -m myagentlab/deepseek-v4-flash \”<测试题>\” crush.json 配 myagentlab provider
Goose goose run -t \'<测试题>\’ –provider myagentlab –model deepseek-v4-flash 需自定义 provider + supports_streaming:false

4. 判定标准

  • 通过 = 该工具自己生成的 test_todo.py 用 pytest 跑通(/tmp/bench-venv/bin/python -m pytest test_todo.py),测试数量由工具自己决定(22/12/13/24/10/13/17 各不相同)
  • 耗时 = 从启动命令到进程退出(含模型首 token 延迟 + 工具自我迭代)
  • token 数据 = 各工具本地记录(来源见\”Token 数据证据链\”章节)
  • 代码质量 = 人工检查产物(测试覆盖、边界处理、可读性)

5. 测试的局限与已知偏差(诚实声明)

  • Cline 的 24/24 是修复后的:原始 22/24(2 个代码 bug),我手动修复了这 2 个 bug 后复验 24/24。纯工具产出是 22/24。
  • Codex token 是估算值:本地不记录 usage,网关无分 key 明细,按 6 轮请求 × 累积上下文估算。成本 ~$0.027 是按 deepseek 定价倒推。
  • Crush 的 completion_tokens=40 疑似记录 bug:实际生成了 124 行代码,40 token 不可能,疑似只记末次请求。
  • 并行测试的竞争影响:7 工具同时跑,共享网关 key。首轮 glm_for_coding 测试时后台还有 MRS refactor 任务(PID 636956)并发消耗同 key,导致网关 GLM 渠道首 token 40-70s 延迟,间接导致 Codex 在 glm 下 4 次超时失败——换 deepseek 后 1.7s 首 token,该干扰消失。
  • 测试题偏简单:todo.py 是常规 CRUD 应用,考察的是\”工具能否完成标准工程任务\”,不涉及大型代码库导航、多文件重构、复杂调试等高级场景。
  • CLI 模式 vs 真实场景:Cline/Kilo 的真实形态是 VS Code 扩展,此处测的是它们的 CLI 版;Goose/Crush 是 CLI 原生。Claude Code/Codex/OpenCode 也主要是终端工具。
  • 6. 为什么选 deepseek-v4-flash(决策过程)

    • 首轮用 glm_for_coding(网关 GLM 渠道):首 token 40-70 秒,每工具 7-9 分钟,且 Codex heredoc 转义错乱、Crush 有 DEFAULT_FILE bug
    • 用户建议测试 deepseek 模型 → 实测 1.7s 首 token,且 Codex/Crush 的问题自动消失
    • 最终统一用 deepseek-v4-flash 重测全部 7 工具(第二轮),保证公平
    • 首轮 glm 数据仅作对照参考,排名以 deepseek 轮为准

    结果总表

    排名
    工具
    版本
    测试结果
    耗时
    Input tokens
    Cache read
    Output tokens
    代码量
    🥇 OpenCode 1.18.12 ✅ 12/12 32s 11,749 40,576 1,992 115+94 行
    🥈 Claude Code 2.1.220 ✅ 22/22 134s 227,467 190,976 12,435 141+182 行
    🥉 Codex 0.50.0 ✅ 13/13 78s ~132K (估)* ~12K (估)* 约 180 行
    4 Goose 1.45.0 ✅ 17/17 77s 80,848 43,776 6,769 126+146 行
    5 Crush go 编译版 ✅ 13/13 66s 14,499 无此字段† 40‡ 124+102 行
    6 Cline 3.0.49 ✅ 24/24 (修复后) 104s 11,234 5,632 6,033 154+200 行
    7 Kilo Code 7.4.17 ✅ 10/10 121s 15,488 102,272 2,291 101+74 行

    * Codex 本地不记录 usage(OpenAI 兼容接口),网关无分 key 明细;按成功 session 的 6 轮 API 请求 × 累积上下文估算(input 12K→32K 递增),单任务成本约 $0.027 † Crush 的 crush.db sessions 表无 cache_read 字段,故无数据 ‡ Crush 记录值(completion_tokens 疑似只记末次请求,实际生成代码见产物)

    分工具详解

    🥇 1. OpenCode — 综合最优

    最快(32s)+ 最省 token(11.7K input,其他工具的 1/5-1/7)+ 代码质量过关。

    • 测试:12/12 通过
    • 自动发现项目 .venv 里的 pytest 9.1.1 并直接使用
    • 安装难点:GitHub 下载慢需镜像(ghfast.top),但配置极简
    • Token 数据:本地 SQLite(~/.local/share/opencode/opencode.db session 表)可精确查询

    配置要点:

    // 项目级 opencode.json
    {


    \”provider\”: {

    \”myagentlab\”: {


    \”npm\”: \”@ai-sdk/openai-compatible\”,
    \”options\”: {

    \”baseURL\”: \”https://api.myagentlab.homes/v1\”, \”apiKey\”: \”见 credentials\” },
    \”models\”: {

    \”deepseek-v4-flash\”: {

    \”name\”: \”deepseek-v4-flash\” } }
    }},
    \”model\”: \”myagentlab/deepseek-v4-flash\”
    }

    opencode run \”任务描述\”

    🥈 2. Claude Code — 质量天花板

    代码质量最高(22 个测试最多最全),但 token 消耗最大。

    • 测试:22/22 通过
    • 亮点:自己发现并修复了 mktemp 空文件导致 json.load 崩溃的 bug(加了空文件容错 + 2 个对应测试);用 next_id 计数器保证删除后 id 不复用
    • 系统提示词最完善,工具定义最全——这也是它 token 大的原因
    • 生态最大(134K stars)、文档全、最成熟

    Token 分析: input 227K 中 190K 是 cache read(价格是正常 input 的 1/10),实际新计算 ~36K,并非全价消耗。

    配置要点:

    export ANTHROPIC_API_KEY=<key> ANTHROPIC_BASE_URL=https://api.myagentlab.homes
    claude -p \”任务\” –model deepseek-v4-flash –allowedTools \’Bash,Write,Read,Edit\’ –output-format stream-json –verbose

    ⚠️ root 用户不能用 –dangerously-skip-permissions(被拒),必须用 –allowedTools

    🥉 3. Codex — 模型对了就起飞

    换 deepseek 后从\”失败×4\”变\”13/13 通过、78s\”,但 token 数据缺失 + 有推理模型兼容隐患。

    • 测试:13/13 通过,还做了完整 smoke test(add→done→list→delete 端到端)
    • 重要历史:glm_for_coding 下失败 4 次(heredoc 被 chr(39) 转义搞坏、代码测试不一致、连接卡死)——是模型问题不是 Codex 问题
    • 隐患:deepseek 是推理模型,Codex 多轮对话时触发 reasoning_content 必须回传 400 报错——复杂多轮任务会随机挂,只适合单轮/简单任务
    • Terminal-Bench 2.1 排名第一(83.4%)的工具,能力本身最强
    • Token 说明:本地 session 不记录 usage;曾尝试\”账单前后差值法\”但网关为共享 key(后台有 MRS refactor 等任务并发消耗),差值 $2.09 不可信;最终按 6 轮请求 × 累积上下文估算 input ~132K / output ~12K / 成本 ~$0.027

    配置要点:

    # ~/.codex/config.toml
    model = \”deepseek-v4-flash\”
    model_provider = \”myagentlab\”
    [model_providers.myagentlab]
    name = \”myagentlab\”
    base_url = \”https://api.myagentlab.homes/v1\”
    env_key = \”OPENAI_API_KEY\”
    wire_api = \”chat\”

    codex exec –dangerously-bypass-approvals-and-sandbox –skip-git-repo-check –json \’任务\’

    4. Goose — 大器晚成

    配置坑最多但修好后很稳,17/17 通过,77s。

    • 测试:17/17 通过,代码质量好(126 行 todo.py 结构清晰,含损坏文件容错、时间戳、自动递增 ID)
    • 自带任务管理(todo_write 工具),agent 会自己记账
    • Linux Foundation 项目,48K stars,潜力大

    ⚠️ 配置坑(都是实测踩出来的):

  • 必须用 OPENAI_API_KEY / OPENAI_BASE_URL(不是 GOOSE_API_KEY/GOOSE_BASE_URL!之前一直设错连默认 api.openai.com 当然超时)
  • 流式模式会报 Stream decode error——必须在 declarative provider 里设 \”supports_streaming\”: false
  • 自定义 provider 要放 ~/.config/goose/custom_providers/<name>.json
  • 配置要点:

    // ~/.config/goose/custom_providers/myagentlab.json
    {


    \”name\”: \”myagentlab\”,
    \”engine\”: \”openai\”,
    \”api_key_env\”: \”MYAGENTLAB_API_KEY\”,
    \”base_url\”: \”https://api.myagentlab.homes/v1\”,
    \”models\”: [ {

    \”name\”: \”deepseek-v4-flash\”, \”context_limit\”: 128000 } ],
    \”supports_streaming\”: false,
    \”requires_auth\”: true
    }

    MYAGENTLAB_API_KEY=<key> goose run -t \’任务\’ –provider myagentlab –model deepseek-v4-flash

    5. Crush — 焕然一新

    从 glm 下 13/14(有 bug)变成 deepseek 下 13/13 全过、66s,但配置极坑 + token 记录不全。

    • 测试:13/13 通过(glm_for_coding 下有个 DEFAULT_FILE 绑定 bug,换 deepseek 后自动消失)
    • 速度快(66s),token 省(14.5K input)
    • Charm 出品,UI 好看,但实用性一般

    ⚠️ 配置坑:

  • 正确配置文件是 ~/.config/crush/crush.json(不是 config.json!改了 config.json 完全不生效)
  • 自定义 provider 的 models 必须是数组(不是对象,否则报 model not found)
  • crush update-providers 会覆盖 providers.json 手动修改(远程拉取 40 个 provider)
  • 运行 flag 是 -m provider/model(如 -m myagentlab/deepseek-v4-flash)
  • 配置要点:

    // ~/.config/crush/crush.json
    {


    \”providers\”: {


    \”myagentlab\”: {


    \”type\”: \”openai-compat\”,
    \”base_url\”: \”https://api.myagentlab.homes/v1\”,
    \”api_key\”: \”$MYAGENTLAB_API_KEY\”,
    \”models\”: [ {

    \”id\”: \”deepseek-v4-flash\”, \”name\”: \”DeepSeek V4 Flash\”, \”context_window\”: 128000, \”default_max_tokens\”: 8192 } ]
    }
    },
    \”defaultModel\”: \”myagentlab/deepseek-v4-flash\”
    }

    MYAGENTLAB_API_KEY=<key> crush run -m myagentlab/deepseek-v4-flash \”任务\”

    6. Cline — 修好代码后全过,但 CLI 有真 bug

    原始 22/24(2 个代码 bug),手动修复后 24/24;但 CLI 二进制有 team_status 崩溃 bug。

    • 原始测试:22/24。两个 bug:
    • _next_id() 用现存任务 max+1,删除后 id 复用(测试要求永不复用)
    • except KeyError: print(f\”Error: {exc}\”) 中 KeyError 的 str 自带引号
    • 修复方法(已验证 24/24):① 加 self._max_id 实例属性持续递增 ② exc.args[0] 取干净消息
    • ⚠️ CLI 真 bug:team_status 工具与 deepseek tool schema 校验随机崩溃(约 1/3 概率报 Invalid schema for function \’team_status\’: null is not of type \”array\”),是 Cline v3.0.49 二进制缺陷
      • 缓解:~/.cline/data/settings/settings.json 设 \”enableTeams\”: false(不完全稳定)
      • glm_for_coding 下无此问题(21/21 全过)
    • CLI 安装配置最简单:cline auth openai -b <url> -k <key> -m <model> 一行搞定
    • 真实场景是 VS Code 扩展,CLI 是轻量版

    配置要点:

    cline auth openai -b https://api.myagentlab.homes/v1 -k <key> -m deepseek-v4-flash
    cline –json \”任务\”

    7. Kilo Code — OpenCode 换皮但更费

    与 OpenCode 同源(fork),功能几乎一样,但 token 消耗高(cache read 102K)且更慢。

    • 测试:10/10 通过,还自己修了个 bug(self.done 属性遮蔽 done() 方法,改名 self.is_done)
    • 配置和 OpenCode 几乎相同(kilo.jsonc)
    • Token 分析:cache read 102K 是 7 个工具最高——它每次请求重发大量工具定义/上下文,但 cache 价格便宜(1/10)
    • 结论:没理由选它,直接用 OpenCode 更好

    配置要点:

    // ~/.config/kilo/kilo.jsonc
    {

    \”provider\”: {

    \”myagentlab\”: {


    \”npm\”: \”@ai-sdk/openai-compatible\”,
    \”options\”: {

    \”baseURL\”: \”https://api.myagentlab.homes/v1\”, \”apiKey\”: \”见 credentials\” },
    \”models\”: {

    \”deepseek-v4-flash\”: {

    \”name\”: \”deepseek-v4-flash\” } }
    }}, \”model\”: \”myagentlab/deepseek-v4-flash\” }

    kilo run -m myagentlab/deepseek-v4-flash \”任务\”

    模型对比:glm_for_coding vs deepseek-v4-flash


    glm_for_coding(网关)
    deepseek-v4-flash(网关)
    首 token 40-70s 1.7s
    工具完成耗时 全部 7-9 分钟 32s-134s
    Codex ❌ 失败×4(heredoc 转义错乱) ✅ 13/13
    Crush ⚠️ 13/14(DEFAULT_FILE bug) ✅ 13/13
    Cline ✅ 21/21 ✅ 24/24(修复后)
    shell 生成质量 差(chr(39) 转义、heredoc 乱) 干净

    结论:deepseek-v4-flash 是当前网关下最佳通用编码模型(快 + 干净 + 便宜)。

    最终推荐

    • 日常开发首选:OpenCode + deepseek-v4-flash(最快最省,质量过关)
    • 要最高质量:Claude Code + deepseek-v4-flash(最稳最严谨,但 token 大)
    • 单轮/简单任务:Codex(能力强,但推理模型多轮有兼容隐患)
    • 避免:Kilo(OpenCode 的劣化版)、Cline CLI(team_status 崩溃 bug 未修,等新版本)

    安装记录(踩坑汇总)

    工具
    安装途径

    OpenCode ghfast.top 镜像下载 v1.18.12 glibc 二进制 GitHub 直连超时;npm 平台包是空壳
    Codex npm @openai/codex
    Goose ghfast.top 镜像下载 v1.45.0 配置变量名坑(见上)
    Crush go install charmbracelet/crush 配置文件坑(见上)
    Cline npm cline v3.0.49 team_status 崩溃 bug
    Kilo npm @kilocode/cli v7.4.17
    Claude Code 预装 v2.1.220 root 不能用 –dangerously-skip-permissions

    网络环境备注:GitHub 直连慢/超时 → 用 https://ghfast.top/https://github.com/… 镜像;npm 用 –registry=https://registry.npmmirror.com;Go 用 GOPROXY=https://goproxy.cn,direct。

    测试产物存放

    所有测试代码、日志、token 数据保留在 /home/agent/coding-benchmark/:

    • test-<工具名>/todo.py + test_todo.py — 各工具产物(可复验 pytest)
    • REPORT-deepseek.md — 精简版报告
    • /tmp/<工具>-ds.log — 运行日志
    • 各工具 token 数据来源:OpenCode/Kilo 本地 SQLite、Goose sessions.db usage_ledger、Cline session JSON metrics、Crush .crush/crush.db、Claude Code stream-json usage

    文档维护:CEO Agent,2026-08-04


    部署与配置坑(详版)

    以下均为本次实测真实踩坑记录(含报错原文)。配置代码见上文各工具详解;完整生成代码见文末 测试产物全集。 侧重点:这里是\”出了什么错、怎么解决\”,上文详解是\”怎么配\”。

    Claude Code

    • root 用户限制:–dangerously-skip-permissions 直接拒绝(“cannot be used with root/sudo privileges”),必须用 –allowedTools \’Bash,Write,Read,Edit\’
    • 环境变量优先级:.bashrc 里的 ANTHROPIC_API_KEY/ANTHROPIC_BASE_URL export 覆盖 ~/.claude/settings.json——要换测试端点必须临时 export,不能只改 settings.json
    • 生产配置隔离:测试时用 export 覆盖,不动 ~/.claude/settings.json 和 .bashrc

    OpenCode

    • GitHub 直连下载超时 → 用 https://ghfast.top/https://github.com/… 镜像下载 opencode-linux-x64.tar.gz(v1.18.12 glibc)
    • npm opencode 包 404;@opencode-ai/cli 平台包是空壳——必须下二进制
    • 曾遇 EEXIST bug:/tmp/opencode 被 musl 二进制留成文件,glibc 版 mkdir 失败 → rm /tmp/opencode 解决
    • opencode version 不是子命令,TUI 是默认命令

    Codex

    • 配置 ~/.codex/config.toml:wire_api = \”chat\”(OpenAI 兼容),env_key = \”OPENAI_API_KEY\”
    • 运行:codex exec –dangerously-bypass-approvals-and-sandbox –skip-git-repo-check –json
    • 推理模型隐患:deepseek 是推理模型,Codex 多轮对话触发 reasoning_content 必须回传 400——复杂任务会挂,单轮任务 OK
    • token 不落本地:session jsonl 无 usage 字段

    Goose(坑最多)

    • 变量名坑:必须用 OPENAI_API_KEY/OPENAI_BASE_URL(不是 GOOSE_API_KEY/GOOSE_BASE_URL!)——用错连默认 api.openai.com 必然超时
    • 流式坑:默认流式报 Stream decode error → declarative provider 必须设 \”supports_streaming\”: false
    • 自定义 provider 路径:~/.config/goose/custom_providers/<name>.json
    • 诊断方法:本地 SQLite ~/.local/share/goose/sessions/sessions.db 的 messages 表看请求是否真的发出去(之前只存 user 消息 = 请求没到模型)

    Crush

    • 配置文件坑:正确文件名是 ~/.config/crush/crush.json(不是 config.json!改 config.json 完全不生效,排查半天)
    • models 必须是数组不是对象(对象结构报 “large model not found”)
    • crush update-providers 会覆盖 providers.json 手动修改(远程拉 40 个 provider)
    • -m provider/model 格式(如 -m myagentlab/deepseek-v4-flash)
    • token 记录不全:crush.db sessions 表只有 prompt/completion/cost,无 cache_read

    Cline

    • 配置最简单:cline auth openai -b <url> -k <key> -m <model> 一行
    • ⚠️ CLI 二进制 bug:team_status 工具与 deepseek tool schema 校验随机崩溃(~1/3 概率 Invalid schema for function \’team_status\’: null is not of type \”array\”)
      • 缓解:~/.cline/data/settings/settings.json 设 \”enableTeams\”: false(不完全稳定)
      • glm_for_coding 下无此问题
    • session 数据在 ~/.cline/data/sessions/<id>/,token 在 messages.json 的 assistant 消息 metrics 字段

    Kilo Code

    • 配置 ~/.config/kilo/kilo.jsonc(opencode fork,格式几乎相同)
    • kilo run -m myagentlab/deepseek-v4-flash \”任务\”
    • token 在 ~/.local/share/kilo/kilo.db session 表

    Token 数据证据链(每个数字从哪来)

    工具
    Input
    Cache
    Output
    数据来源(可复核)
    Claude Code 227,467 190,976 12,435 /tmp/cc-ds.log 最后一行 \”usage\”:{…}(stream-json 输出)
    OpenCode 11,749 40,576 1,992 ~/.local/share/opencode/opencode.db session 表 tokens_input/output/cache_read
    Codex ~132K (估) ~12K (估) 本地不记录;按 6 轮请求×累积上下文估算,成本 ~$0.027
    Goose 80,848 43,776 6,769 ~/.local/share/goose/sessions/sessions.db usage_ledger 表 SUM()
    Crush 14,499 无此字段 40* ~/.crush/crush.db sessions 表 prompt_tokens/completion_tokens
    Cline 11,234 5,632 6,033 ~/.cline/data/sessions/<id>/<id>.messages.json assistant metrics 累加
    Kilo 15,488 102,272 2,291 ~/.local/share/kilo/kilo.db session 表

    * Crush completion_tokens=40 疑似只记末次请求(实际生成 124 行代码),已按实际产物修正理解

    复核命令示例(OpenCode):

    SELECT tokens_input, tokens_output, tokens_cache_read FROM session
    WHERE model LIKE \’%deepseek%\’ ORDER BY time_created DESC LIMIT 1;

    复核命令示例(Goose):

    SELECT session_id, SUM(input_tokens), SUM(output_tokens), SUM(cache_read_tokens)
    FROM usage_ledger GROUP BY session_id ORDER BY MIN(id) DESC LIMIT 2;

    复核命令示例(Claude Code):

    grep -oE \’\”usage\”:\\{[^}]*\\}\’ /tmp/cc-ds.log | tail -1

    为什么 Codex 没有精确值: 本地 session jsonl 无 usage 字段;网关 billing 接口只给总额(共享 key,后台 MRS 任务并发消耗,差值法不可信);唯一精确途径是 new-api 后台按渠道查明细。


    附:测试产物全集(7 份完整代码 + pytest 输出)

    以下为 7 款工具在统一测试题下实际生成的全部代码 + pytest 复验输出(机器实跑,非手写)。 复验命令:/tmp/bench-venv/bin/python -m pytest test_todo.py -v(产物目录 /home/agent/coding-benchmark/test-<工具名>/)

    本页存放 7 款工具在统一测试题下实际生成的全部代码 + pytest 复验输出。

    复验命令:/tmp/bench-venv/bin/python -m pytest test_todo.py -v(产物目录 /home/agent/coding-benchmark/test-<工具名>/)


    Claude Code v2.1.220 — 22/22

    Claude Code 生成的 todo.py (4619 bytes)

    #!/usr/bin/env python3
    \”\”\”A simple command-line todo app with JSON persistence.

    Usage:
    todo.py add <task> Add a new task
    todo.py list List all tasks
    todo.py done <id> Mark a task as done
    todo.py delete <id> Delete a task
    todo.py –file <path> Use a custom JSON file (default: ~/.todo.json)

    Tasks are stored in a JSON file of the form:
    {\”next_id\”: 2, \”todos\”: [{\”id\”: 1, \”task\”: \”…\”, \”done\”: false}]}
    The “next_id“ counter is persisted so task IDs are never reused, even
    after a delete. This prevents a stale reference from completing or
    deleting the wrong task later.
    \”\”\”

    import argparse
    import json
    import os
    import sys

    DEFAULT_FILE = os.path.join(os.path.expanduser(\”~\”), \”.todo.json\”)

    class TodoApp:
    \”\”\”Todo list backed by a JSON file.\”\”\”

    def __init__(self, filepath=DEFAULT_FILE):
    self.filepath = filepath

    def load(self):
    \”\”\”Return the store (“next_id“ counter + “todos“ list).\”\”\”
    if not os.path.exists(self.filepath):
    return {

    \”next_id\”: 1, \”todos\”: []}
    with open(self.filepath, \”r\”) as f:
    content = f.read()
    if not content.strip():
    # Empty file (e.g. created by touch/mktemp) means a fresh store.
    return {

    \”next_id\”: 1, \”todos\”: []}
    data = json.loads(content)
    # Backwards compatibility: a bare list of todos.
    if isinstance(data, list):
    data = {


    \”next_id\”: max((t[\”id\”] for t in data), default=0) + 1,
    \”todos\”: data,
    }
    return data

    def save(self, data):
    \”\”\”Write the store to the JSON file.\”\”\”
    with open(self.filepath, \”w\”) as f:
    json.dump(data, f, indent=2)

    def _allocate_id(self, data):
    next_id = data[\”next_id\”]
    data[\”next_id\”] = next_id + 1
    return next_id

    def add(self, task):
    \”\”\”Add a new task and return the created todo.\”\”\”
    data = self.load()
    todo = {

    \”id\”: self._allocate_id(data), \”task\”: task, \”done\”: False}
    data[\”todos\”].append(todo)
    self.save(data)
    return todo

    def list_todos(self):
    \”\”\”Return all todos in insertion order.\”\”\”
    return self.load()[\”todos\”]

    def done(self, todo_id):
    \”\”\”Mark a todo as done and return it, or None if not found.\”\”\”
    data = self.load()
    for todo in data[\”todos\”]:
    if todo[\”id\”] == todo_id:
    todo[\”done\”] = True
    self.save(data)
    return todo
    return None

    def delete(self, todo_id):
    \”\”\”Delete a todo and return it, or None if not found.\”\”\”
    data = self.load()
    for i, todo in enumerate(data[\”todos\”]):
    if todo[\”id\”] == todo_id:
    removed = data[\”todos\”].pop(i)
    self.save(data)
    return removed
    return None

    def main(argv=None):
    parser = argparse.ArgumentParser(description=\”A simple todo app\”)
    parser.add_argument(
    \”–file\”, default=DEFAULT_FILE, help=\”JSON file to store todos\”
    )
    subparsers = parser.add_subparsers(dest=\”command\”, required=True)

    add_parser = subparsers.add_parser(\”add\”, help=\”Add a task\”)
    add_parser.add_argument(\”task\”, help=\”Task description\”)

    subparsers.add_parser(\”list\”, help=\”List all tasks\”)

    done_parser = subparsers.add_parser(\”done\”, help=\”Mark a task as done\”)
    done_parser.add_argument(\”id\”, type=int, help=\”Task ID\”)

    delete_parser = subparsers.add_parser(\”delete\”, help=\”Delete a task\”)
    delete_parser.add_argument(\”id\”, type=int, help=\”Task ID\”)

    args = parser.parse_args(argv)
    app = TodoApp(args.file)

    if args.command == \”add\”:
    todo = app.add(args.task)
    print(f\”Added todo #{

    todo[\’id\’]}: {

    todo[\’task\’]}\”)
    elif args.command == \”list\”:
    todos = app.list_todos()
    if not todos:
    print(\”No todos.\”)
    return 0
    for todo in todos:
    status = \”[x]\” if todo[\”done\”] else \”[ ]\”
    print(f\”{

    todo[\’id\’]}. {

    status} {

    todo[\’task\’]}\”)
    elif args.command == \”done\”:
    todo = app.done(args.id)
    if todo is None:
    print(f\”Todo #{

    args.id} not found.\”, file=sys.stderr)
    return 1
    print(f\”Done: {

    todo[\’task\’]}\”)
    elif args.command == \”delete\”:
    todo = app.delete(args.id)
    if todo is None:
    print(f\”Todo #{

    args.id} not found.\”, file=sys.stderr)
    return 1
    print(f\”Deleted: {

    todo[\’task\’]}\”)
    return 0

    if __name__ == \”__main__\”:
    sys.exit(main())

    Claude Code 生成的 test_todo.py (5048 bytes)

    \”\”\”Unit tests for the todo app.\”\”\”

    import json

    import pytest

    from todo import TodoApp, main

    @pytest.fixture
    def app(tmp_path):
    return TodoApp(filepath=tmp_path / \”todos.json\”)

    # — add ——————————————————————

    def test_add_returns_created_todo(app):
    todo = app.add(\”Buy milk\”)
    assert todo == {

    \”id\”: 1, \”task\”: \”Buy milk\”, \”done\”: False}

    def test_add_persists_to_json(app, tmp_path):
    app.add(\”Write tests\”)
    data = json.loads((tmp_path / \”todos.json\”).read_text())
    assert len(data[\”todos\”]) == 1
    assert data[\”todos\”][0][\”task\”] == \”Write tests\”
    assert data[\”todos\”][0][\”done\”] is False

    def test_add_persists_next_id_counter(app, tmp_path):
    app.add(\”first\”)
    app.add(\”second\”)
    data = json.loads((tmp_path / \”todos.json\”).read_text())
    assert data[\”next_id\”] == 3

    def test_add_increments_ids(app):
    app.add(\”first\”)
    second = app.add(\”second\”)
    assert second[\”id\”] == 2
    assert [t[\”id\”] for t in app.list_todos()] == [1, 2]

    def test_add_after_delete_does_not_reuse_id(app):
    first = app.add(\”first\”)
    app.delete(first[\”id\”])
    third = app.add(\”third\”)
    assert third[\”id\”] == 2
    assert [t[\”id\”] for t in app.list_todos()] == [2]

    def test_ids_are_monotonic_across_restarts(tmp_path):
    filepath = tmp_path / \”todos.json\”
    app1 = TodoApp(filepath=filepath)
    first = app1.add(\”first\”)
    app2 = TodoApp(filepath=filepath)
    app2.delete(first[\”id\”])
    third = app2.add(\”third\”)
    assert third[\”id\”] == 2

    # — list —————————————————————–

    def test_list_empty_when_no_file(tmp_path):
    app = TodoApp(filepath=tmp_path / \”nonexistent.json\”)
    assert app.list_todos() == []

    def test_list_empty_when_file_is_empty(tmp_path):
    filepath = tmp_path / \”todos.json\”
    filepath.write_text(\”\”)
    app = TodoApp(filepath=filepath)
    assert app.list_todos() == []

    def test_add_over_empty_file(tmp_path):
    filepath = tmp_path / \”todos.json\”
    filepath.write_text(\”\”

    赞(0)
    未经允许不得转载:171主机测评 » 实战横评】主流 AI 编程工具实测对比,看完不再盲目选型
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址