Qwen3-Coder 评测仓库视角:用 aider code editing benchmark 追踪 LLM 代码编辑性能稳定性——Claude 3.5 Sonnet 实测数据复盘
2026/9/14 10:12:40 网站建设 项目流程

Qwen3-Coder 评测仓库视角:用 aider code editing benchmark 追踪 LLM 代码编辑性能稳定性——Claude 3.5 Sonnet 实测数据复盘

【免费下载链接】Qwen3-CoderQwen3-Coder is the code version of Qwen3, the large language model series developed by Qwen team.项目地址: https://gitcode.com/GitHub_Trending/co/Qwen3-Coder

本文以 Qwen3-Coder 仓库qwencoder-eval评测体系中收录的 aider 项目博客文章《Sonnet seems as good as ever》为主体,结合其配套基准数据与 benchmark 源码,系统讲解如何用 aider code editing benchmark 对 LLM 的代码编辑能力进行"随时间变化"的量化追踪。读完本文,你将掌握 Pass Rate 1 / Pass Rate 2 等核心指标的含义、基准数据文件中每个字段的来源,以及如何复现一套基于 Exercism 练习的代码编辑评测流程,从而用数据而非传闻判断模型是否"变笨了"。

背景:关于模型被"降智"的传闻与数据化验证思路

2024 年年中,社区中出现了大量猜测,认为 Anthropic 的 Claude 3.5 Sonnet 在更新后"被削弱"(dumbed-down)、"被阉割"(nerfed),整体表现不如发布初期。这类传闻在 LLM 快速迭代的时代屡见不鲜,但往往缺乏可量化的证据。

aider 团队的应对方式是:不靠体感,靠基准数据。在这篇发布于 qwencoder-eval/instruct/aider/aider/website/_posts/2024-08-26-sonnet-seems-fine.md 的文章中,作者将 Sonnet 自发布以来每一次干净、可比的 aider code editing benchmark 运行结果汇总成时间序列,得出结论:

Sonnet 在通过 API 执行 aider code editing benchmark 时,表现与发布之初一样好。

结论的核心依据是两点:

  • 图表显示的是方差(variance),而不是值得注意的退化(degradation)
  • 在提示词完全相同的条件下,基准结果本来就存在约 ±2% 的正常波动。

同时作者也诚实指出了该数据的局限:这些 API 基准结果无法捕获 Anthropic 网页版聊天(web chat)对 Sonnet 使用方式所做的任何调整,因此只能说明 API 通路下的模型能力未显著变化。

aider code editing benchmark:评测的是什么

要理解上述结论,首先需要明白这个基准到底在测什么。根据 benchmarks 说明文档 与 benchmark 目录 README,该基准建立在 Exercism python 练习集之上,选取其中 133 个练习作为测试用例。

每个练习包含三部分:

  1. 用 Markdown 书写的自然语言任务说明(instructions);
  2. 一个实现文件 stub,预先定义好需要实现的函数或类骨架;
  3. 一个独立的单元测试文件(如anagram_test.py)。

评测流程是一个完整的"端到端"闭环:模型不仅要把自然语言需求翻译成可执行代码,还必须以 aider 约定的编辑格式(如wholediffudiff)输出修改,让 aider 能够准确识别并落盘到本地源码文件中,随后由 harness 运行单元测试验证结果。正如 README 所强调的,这同时考验了模型的编码能力、编辑既有代码的能力,以及格式化编辑结果的能力

追踪方法:把每次基准运行变成时间序列中的一个数据点

Sonnet 上线后的两个月中,aider 团队进行了多次基准运行,原因各不相同,多数是为了评估 aider 自身系统提示词的小改动对效果的影响。这些运行并非为追踪模型而专门设计,但它们恰好构成了一个天然的"性能监控样本集"。

所有干净、可比的运行结果被汇总到数据文件 qwencoder-eval/instruct/aider/aider/website/_data/sonnet-fine.yml 中,共 20 条记录,时间跨度从 2024-06-20 到 2024-08-21。原博客页面通过 Chart.js 读取该 YAML 数据,以日期为 X 轴、通过率为 Y 轴绘制散点图,同时绘制 Pass Rate 1 与 Pass Rate 2 两个序列。以下为该图表的静态版:

图表下方对两个指标给出了明确定义:

  • Pass Rate 1:首次尝试的成功率(initial success rate);
  • Pass Rate 2:获得第二次修复机会(针对测试错误进行修改)之后最终的成功率;
  • aider 的 LLM code editing leaderboard 正是依据 Pass Rate 2 对模型进行排名的。

从 YAML 数据中可以提炼出每次运行的日期、编辑格式与两个通过率(其余字段将在下一节逐一解读):

运行日期编辑格式test_casesPass Rate 1Pass Rate 2aider 版本
2024-06-20diff13357.974.40.38.1-dev
2024-06-21diff13359.480.50.39.1-dev
2024-06-21diff13358.677.40.39.1-dev
2024-06-24udiff13362.474.40.39.1-dev
2024-06-24diff13357.974.40.39.1-dev
2024-06-24diff13359.476.70.39.1-dev
2024-06-24diff13358.675.90.39.1-dev
2024-06-24diff13359.475.20.39.1-dev
2024-06-24diff13358.676.70.39.1-dev
2024-07-04diff13357.177.40.42.1-dev
2024-07-06diff13357.978.20.42.1-dev
2024-07-24diff13359.478.20.45.2-dev
2024-07-28diff9459.683.00.45.2-dev
2024-08-14diff13357.975.90.50.1-dev
2024-08-18diff13354.978.90.50.2-dev
2024-08-18diff13356.478.90.50.2-dev
2024-08-18diff13356.478.20.50.2-dev
2024-08-21diff13357.182.00.51.2-dev
2024-08-21diff13363.279.70.51.2-dev
2024-08-21diff13363.980.50.51.2-dev

(注:2024-07-28 那次运行仅完成 94 个用例;最后三条 8 月 21 日的记录分别对应直连claude-3-5-sonnet-20240620与两轮 shell 命令提示词对比实验,模型主体仍为 Claude 3.5 Sonnet。)

从数据中可以清楚看到:Pass Rate 1 全程稳定在 54.9%–63.9% 之间,Pass Rate 2 稳定在 74.4%–83.0% 之间,8 月后半段的多次运行(78.9、78.2、82.0、79.7、80.5)与 6 月的水平相当甚至略高,没有任何系统性下滑的证据

数据字段逐项解读:YAML 记录背后的源码逻辑

sonnet-fine.yml中每条记录都包含 18 个字段,它们并非随意填写,而是由 benchmark.py 中的summarize_results()(第 297-436 行)在每次运行结束后自动汇总生成的。理解这些字段,是读懂任何模型基准报告的前提:

  • dirname / test_cases:运行目录名与完成用例数。源码中NUM_TESTS = (89, 133)(第 38 行),若完成的用例数不在其中,会打印incomplete警告——这正是上表 94 个用例那次运行被特别标注的原因。
  • model / edit_format / commit_hash:被测模型名、编辑格式与 aider 源码提交哈希(本地有未提交改动时追加-dirty后缀)。
  • pass_rate_1 / pass_rate_2:由passed_tests数组计算而来。源码中passed_tests[i]统计"第 i 次尝试后累计通过"的用例数,pass_rate = 100 * passed_tests[i] / completed_tests(第 377-381 行)。因为采用累计逻辑,Pass Rate 2 必然不低于 Pass Rate 1。
  • percent_cases_well_formed:格式正确的用例占比,源码计算为1.0 - num_with_malformed_responses / completed_tests(第 398 行),衡量模型响应能否被 aider 正确解析。
  • error_outputs:模型产生错误输出的次数,来自io.num_error_outputs
  • num_malformed_responses / num_with_malformed_responses:畸形响应的总条数,以及至少产生过一条畸形响应的用例数,来源于coder.num_malformed_responses
  • user_asks / lazy_comments:模型向用户提问的次数;lazy_comments则统计响应中匹配^[+]? *[#].* [.][.][.]正则模式的"偷懒注释"行数(第 599-602 行)。
  • syntax_errors / indentation_errors:第二次尝试反馈的测试错误中,以SyntaxErrorIndentationError开头的行数(第 628-629 行)。
  • exhausted_context_windows / test_timeouts:上下文窗口耗尽次数与单元测试超时次数(单次测试超时阈值为 60 秒,见run_unit_tests)。
  • command / date / versions / seconds_per_case / total_cost:复现命令、运行日期、aider 版本、平均每用例耗时与总花费。源码会按 commit hash 回溯aider/__init__.py中的__version__得到版本号(第 439-453 行)。

复现方法:如何自己跑一套代码编辑基准

如果你希望用同样的方法论验证其他模型(例如用 Qwen3-Coder 评测体系评估新模型),可以参考 benchmark 目录 README 中的完整流程。由于 harness 会不加人工审查地执行 LLM 生成的代码(README 明确警告模型可能生成import os; os.system("sudo rm -rf /")这类危险代码),基准必须在 docker 容器内运行

一次性环境准备:

# 克隆 aider 仓库 git clone git@github.com:paul-gauthier/aider.git cd aider # 创建存放基准结果的 scratch 目录 mkdir tmp.benchmarks # 克隆 exercism 练习集 git clone git@github.com:exercism/python.git # 把练习复制到基准 scratch 目录 cp -rp python/exercises/practice tmp.benchmarks/exercism-python # 构建 docker 容器 ./benchmark/docker_build.sh

启动容器并运行基准:

# 启动 docker 容器 ./benchmark/docker.sh # 在容器内以开发模式安装 aider(确保运行的是本地克隆的代码) pip install -e . # 运行基准:跑全部 133 个用例 ./benchmark/benchmark.py a-helpful-name-for-this-run --model gpt-3.5-turbo --edit-format whole --threads 10

运行后会在tmp.benchmarks/YYYY-MM-DD-HH-MM-SS--a-helpful-name-for-this-run/目录下生成结果,133 个用例会以随机顺序执行。benchmark.py的核心参数如下(来自 main() 函数定义):

参数默认值说明
--model/-mgpt-3.5-turbo模型名,与直接传给 aider 的写法一致
--edit-format/-e模型默认编辑格式(wholediffudiff等);实验性模型建议从whole开始
--tries/-r2每个用例的尝试次数:首轮失败后会把测试错误反馈给模型再修一轮
--threads/-t1并行执行的用例数;调试阶段用单线程,稳定后可提高到 10
--num-tests/-n-1(全部)运行前多少个用例即停止,便于小规模试跑
--keywords/-k只运行名字匹配关键词的用例(类似pytest -k
--clean/-c丢弃现有测试目录并重建干净副本
--cont继续已有的单个匹配目录
--stats/-s不运行测试,仅汇总已完成用例的统计信息
--diffs对比多个统计目录的用例结果差异
--graphs生成图表
--replay重放之前基准运行的.aider.chat.history.md响应
--max-apply-update-errors3应用更新失败达到该次数即终止用例
--no-unit-tests不运行单元测试
--no-aider不运行 aider(配合测试用途)
--verbose/-v详细输出
--exercises-direxercism-python存放练习文件的目录

生成统计报告时无需进入容器(因为只读 JSON 结果、不执行代码):

./benchmark/benchmark.py --stats tmp.benchmarks/YYYY-MM-DD-HH-MM-SS--a-helpful-name-for-this-run

从源码看两次尝试机制:Pass Rate 2 是如何"多给一次机会"的

run_test_real()(第 487-665 行)揭示了 Pass Rate 1 与 Pass Rate 2 之间的执行细节:

  1. 首轮,harness 将任务说明(含instructions_addendum补充提示)通过coder.run()交给模型(第 595 行);
  2. 然后执行run_unit_tests(),用python -m unittest discover -s <testdir> -t <testdir> -p "*_test.py"运行单元测试(第 668-692 行);
  3. 若全部通过,tests_outcomes记录True并提前结束;若失败,则截取前 50 行错误输出,拼上test_failures提示模板作为第二条消息再发给模型(第 632-635 行);
  4. 源码还会对测试输出做cleanup_test_output()处理,剥离Ran N tests in X.XXs等计时信息,避免模型被不稳定的时序噪声干扰(第 705-727 行)。

这一"修复失败后再试一次"的设计,正是原博客所强调的:第二次机会允许模型在首次理解有偏差时自我修正,而 Pass Rate 2 也因此成为 leaderboard 排名与"模型是否退化"判断的更有意义的指标。

结论与局限:如何正确解读"模型变笨了"的传闻

汇总两个月 20 次基准运行可以得出三点可复用的判断方法:

  1. 先看趋势,再看单点:单次运行结果天然带有约 ±2% 的方差,任何孤立的低分(如 8 月 18 日那次 54.9% 的 Pass Rate 1)都应放在时间序列中审视,而非直接当作"被削弱"的证据。
  2. 用累计修复率做最终判断:Pass Rate 2 比 Pass Rate 1 更稳健,8 月多次运行稳定在 78%–83%,与 6 月的 74%–80% 相比不仅没有下降,甚至略有抬升。
  3. 明确结论的边界:正如原博客明确声明的,这些结果只覆盖 API 通路下的代码编辑场景,无法反映 Anthropic 网页聊天产品层面对模型使用方式的调整;它也不能证明模型在所有任务类型上都未退化。

对致力于构建可靠 LLM 评测体系的团队而言,这套"固定提示词 + 固定用例 + 固定编辑格式 + 时间序列化记录"的方法论本身,比"某模型在某天的分数"更有参考价值——它把关于模型能力的主观传闻,变成了可以随时回放、对比与复现的客观数据。本文所述评测代码与数据已完整收录于本仓库的 qwencoder-eval/instruct/aider 目录下,感兴趣的读者可以直接阅读 benchmark.py、基准数据 与 原始博客文章 进一步深入。

【免费下载链接】Qwen3-CoderQwen3-Coder is the code version of Qwen3, the large language model series developed by Qwen team.项目地址: https://gitcode.com/GitHub_Trending/co/Qwen3-Coder

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询