☰
aider 基准测试框架(Benchmark Harness)完整指南:在 Docker 中用 polyglot 练习集量化评测 LLM 编码能力
2026/10/10 10:18:10 网站建设 项目流程

aider 基准测试框架(Benchmark Harness)完整指南:在 Docker 中用 polyglot 练习集量化评测 LLM 编码能力

【免费下载链接】aideraider is AI pair programming in your terminal项目地址: https://gitcode.com/GitHub_Trending/ai/aider

本指南围绕 aider 仓库中的 benchmark/README.md 展开,系统讲解 aider 官方基准评测框架的设计动机、搭建步骤、运行方式与结果解读,并结合 benchmark.py、docker.sh、Dockerfile 等源码说明其底层工作机制。读完本文,你将掌握一套可复现的评测流程,能够独立对任意模型跑通评测并获得pass_rate、成本、延迟等量化指标。

一、评测框架要解决什么问题

aider 官方博客曾用专项文章介绍这一评测方案(仓库内的原始文稿见 aider/website/_posts/2024-12-21-polyglot.md)。这套框架的定位非常明确:用定量手段衡量 aider 与不同 LLM 协作时的真实表现。

评测基于 Exercism 编程练习扩展出的 polyglot 练习集。每个练习本质上是一次端到端任务:给定一段自然语言需求,模型必须产出可执行代码,并让代码被正确保存到源文件中、通过配套单元测试。因此它检验的不只是模型的“写代码能力”,还包括两个容易被人忽略的环节:

  1. 编辑既有代码的能力——模型必须理解项目上下文并做针对性修改;
  2. 格式化代码编辑的能力——模型产出的补丁或整文件内容必须能被 aider 解析并落地到本地源码。

只有在两个环节都成功时,单元测试才可能通过,最终评分才有意义。

为什么必须放进 Docker 跑

评测脚本会直接执行 LLM 生成的代码,而这些代码从未经过任何人工审查。模型完全有可能生成危害宿主机的代码,README 中举了一个直白的例子:

import os; os.system("sudo rm -rf /")

因此官方在 benchmark.py 中加入了硬性保护:正常运行评测前会检查环境变量AIDER_DOCKER,未设置时直接打印警告并拒绝执行。这就是为什么整套流程“被设计为必须在 docker 容器内运行”。

二、任务全景与目录构成

评测工作拆成 3 个主要环节:

  1. 安装与初始化:准备练习集、scratch 目录、构建容器镜像,一次性完成;
  2. 运行评测:在容器内对所有练习执行多轮修复-测试循环;
  3. 生成报告:汇总各练习的成功/失败情况并输出 YAML 统计。

benchmark 目录中的相关脚本与用途如下:

文件作用
benchmark.py核心评测入口,含运行评测、生成统计两大功能(基于 typer 构建的 CLI)
prompts.py追加给模型的指令模板(修改约束、测试失败反馈模板)
docker_build.sh构建名为aider-benchmark的镜像
docker.sh启动评测容器并注入必要环境变量与挂载目录
Dockerfile容器内多语言工具链(Python/Go/Rust/Node/Java/C++)
npm-test.sh、cpp-test.shJS 与 C++ 练习的测试驱动脚本
swe_bench.py生成 SWE-bench 横向对比图的绘图脚本
test_benchmark.py针对输出清洗函数cleanup_test_output的单元测试

三、阶段一:搭建评测环境

以下步骤只需要执行一次。

# 1) 克隆 aider 仓库(如尚未克隆) git clone https://gitcode.com/GitHub_Trending/ai/aider aider # 2) 在 aider 仓库根目录下创建存放评测结果的 scratch 目录 cd aider mkdir tmp.benchmarks # 3) 克隆练习集仓库(Aider-AI 组织下的 polyglot-benchmark),放在 scratch 目录里 git clone <polyglot-benchmark 仓库地址> tmp.benchmarks/polyglot-benchmark # 4) 构建 docker 镜像 ./benchmark/docker_build.sh

几个值得留意的设计点:

  • tmp.benchmarks是默认的结果根目录。从源码看,这个路径可用环境变量AIDER_BENCHMARK_DIR覆盖(见 benchmark.py),例如容器内它被设置为/benchmarks;
  • polyglot-benchmark是 Exercism 风格的练习集,内部按“语言 / exercises / practice / 练习名”组织,每个练习目录里带有.docs/instructions.md等任务描述文件与.meta/config.json配置文件(见后文第四节的运行原理);
  • docker_build.sh的核心就是调用docker build --file benchmark/Dockerfile -t aider-benchmark .,把当前工作区作为构建上下文。

容器里预装了哪些工具链

从 Dockerfile 可以看到,镜像会一次性装好几乎所有主流语言环境,以覆盖 polyglot 练习集:基于 buildpack-deps:jammy、Python 3.11(由 deadsnakes PPA 提供)、Go 1.21.5(自动适配 amd64/arm64)、Rust(rustup)、Node.js 20 + Jest 相关依赖(jest、@babel/core、babel-jest、@types/jest等)、OpenJDK 21、CMake 与 Boost。镜像构建时还会以可编辑模式把/aider安装进 Python 环境,并声明/aider为工作目录。

四、阶段二:运行评测

启动容器

./benchmark/docker.sh

docker.sh 做了这些关键配置:

  • --memory=12g/--memory-swap=12g:限制容器最多使用 12G 内存,防止失控进程拖垮宿主机;
  • 将当前目录挂载为/aider,将tmp.benchmarks/挂载为/benchmarks,评测产物落在宿主机磁盘上;
  • 注入AIDER_DOCKER=1(放行上述运行检查)与AIDER_BENCHMARK_DIR=/benchmarks;
  • 透传OPENAI_API_KEY等 API 密钥环境变量;
  • 记录容器内 bash 历史(HISTFILE=/aider/.bash_history),方便复查。

容器内安装源码并运行

# 以开发模式(可编辑安装)安装 aider, # 这样跑的就是你 clone 下来的代码,包括尚未提交的本地改动 pip install -e .[dev] # 运行评测 ./benchmark/benchmark.py a-helpful-name-for-this-run \ --model gpt-3.5-turbo \ --edit-format whole \ --threads 10 \ --exercises-dir polyglot-benchmark

执行结束后,会在tmp.benchmarks/下生成一个以时间戳命名的结果目录,形如:

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

如果目录名不带日期前缀,脚本会自动补上YYYY-MM-DD-HH-MM-SS--(见 resolve_dirname)。默认情况下脚本会随机打乱全部练习的顺序再执行(benchmark.py),避免次序带来的系统偏差。

常用参数说明

README 推荐用./benchmark/benchmark.py --help查看全部参数,并重点提示以下几个:

  • --model:模型名称,与你直接传给 aider 的写法一致;
  • --edit-format:编辑格式名称,同样与传给 aider 的一致。评测新模型时,官方建议从whole起步——整文件重写格式兼容性最好;
  • --threads:并行执行的练习数。调通环境或换新模型时先用单线程(默认即 1),结果稳定后可加大提速,README 提到对 OpenAI API 用 10 线程效果不错;
  • --num-tests:最多跑多少个练习就停止,适合调试环境时小规模验证;
  • --keywords:只运行名称中包含指定关键字的练习(类似pytest -k);
  • --read-model-settings=<filename.yml>:从 YAML 文件加载模型设置,格式可参考仓库中的 aider/website/docs/config/adv-model-settings.md。

除此之外,结合 benchmark.py 的 CLI 定义,还有一批对进阶评测有用的参数:

参数默认值作用
--tries/-r2每个练习最多尝试轮数(第一轮生成 + 失败后带测试报错再修),pass_rate_N就来自第 N 轮的成功率
--num-ctx无覆盖模型上下文窗口大小
--languages/-l无只评测指定语言(逗号分隔),如python,javascript
--graphs关闭评测完成后生成图表
--clean/-c关闭丢弃已有测试目录并重建干净副本
--cont关闭继续(匹配到的)单一日志目录中未完成的测试
--new关闭强制新建带日期的结果目录(同名目录已存在时用)
--no-unit-tests关闭不执行单元测试
--no-aider关闭不调用 aider(供纯测试或对照实验)
--diffs关闭对多个结果目录做逐练习的成败 diff
--replay无重放上一次评测的.aider.chat.history.md对话(用于调试编辑格式等)
--reasoning-effort无对支持思考预算的模型设置推理强度
--thinking-tokens无对支持思考预算的模型设置思考 token 上限
--editor-model/--editor-edit-format无覆盖 architect 等模式下“编辑模型”的模型与格式
--stats-languages无统计时只纳入指定语言的练习

注意两个运行层面的约定:并行调度由lox库的thread(threads)(run_test)完成(benchmark.py);评测期间网络重试超时会被拉长到 24 小时(LONG_TIMEOUT = 24 * 60 * 60,见 benchmark.py),尽量让每个练习都有完整的机会跑完。

五、阶段三:生成评测报告

统计工作只是读取结果文件、汇总指标,并不会执行任何不安全代码,因此无需进入容器,在宿主机上直接跑:

# 针对指定结果目录生成统计 ./benchmark/benchmark.py --stats tmp.benchmarks/YYYY-MM-DD-HH-MM-SS--a-helpful-name-for-this-run

若省略目录名,脚本会自动挑最近 24 小时内最新更新的结果目录(find_latest_benchmark_dir)。

输出是一份 YAML 记录,README 给出了完整样例:

- dirname: 2024-07-04-14-32-08--claude-3.5-sonnet-diff-continue test_cases: 225 model: claude-3.5-sonnet edit_format: diff commit_hash: 35f21b5 pass_rate_1: 57.1 pass_rate_2: 77.4 percent_cases_well_formed: 99.2 error_outputs: 23 num_malformed_responses: 4 num_with_malformed_responses: 1 user_asks: 2 lazy_comments: 0 syntax_errors: 1 indentation_errors: 0 exhausted_context_windows: 0 test_timeouts: 1 command: aider --sonnet date: 2024-07-04 versions: 0.42.1-dev seconds_per_case: 17.6 total_cost: 3.6346

关键指标解读

  • pass_rate_#是核心指标,含义是“全部测试通过的任务所占百分比”。会有多个(pass_rate_1、pass_rate_2……),个数取决于--tries参数——第 N 轮表示给了模型 N 次“看到测试失败并继续修复”机会后的累计通过率。源码中对应逻辑位于 summarize_results;
  • YAML 同时记录了该次运行生效的全部设置,以及运行时刻仓库的 git 提交哈希——若工作区存在未提交改动,哈希会带上(dirty)后缀。评测前先git commit是官方建议的好习惯,这样model、edit_format、commit_hash三者即可基本锁定一次可复现的实验(哈希与脏状态判断见 benchmark.py);
  • 其余字段刻画“过程健康度”:percent_cases_well_formed(格式正确的响应占比)、error_outputs、num_malformed_responses(无法被解析成合法编辑的响应次数)、user_asks、lazy_comments(模型偷懒只写注释未动手的次数)、syntax_errors/indentation_errors、exhausted_context_windows(上下文窗口耗尽次数)、test_timeouts(测试超时次数),以及seconds_per_case单练习平均耗时、total_cost总花费。

官方排行榜就由这类 YAML 记录汇总而成,历史数据可以直接在本仓库中查看,例如 aider/website/_data/polyglot_leaderboard.yml(含dirname、test_cases、pass_rate_1、pass_rate_2、total_cost、commit_hash等字段的 225 个练习的完整记录),更多说明见 aider/website/docs/leaderboards/index.md。如果你想贡献自己的评测结果,官方欢迎通过 PR 向aider/website/_data/下的榜单数据文件提交新记录。

六、评测循环的源码级工作原理

6.1 练习发现与副本隔离

脚本先按exercises/practice目录结构收集所有练习(支持--languages过滤),再把它们从原始练习集复制一份到带时间戳的结果目录中执行(benchmark.py),保证每次评测的输入是干净副本,可被--clean随时重建。

6.2 每个练习的单测循环

对单个练习,核心逻辑在 run_test_real,其流程可以归纳为:

  1. 读取任务配置:解析练习目录下的.meta/config.json,得到test(测试文件)、example(示例实现)、solution(待修改的骨架文件)三类文件清单(benchmark.py)。.meta/**、.docs/**以及测试/示例文件都会被显式加入“忽略集合”,保证模型只负责改真正的实现文件;
  2. 组装自然语言指令:拼接.docs/introduction.md、.docs/instructions.md、instructions.append.md,再追加 prompts.py 中定义的instructions_addendum模板,其中强调“不要改动既有函数/类名(可能被测试引用)、只用标准库、不要建议安装新包”;
  3. 创建 Coder 并发送请求:用Coder.create(...)以指定edit_format实例化编码器,设置use_git=False、stream=False、关闭 shell 命令建议,并禁止加载任何额外文件(coder.get_file_mentions = lambda x: set()),确保每次交互严格限于该练习的骨架文件(benchmark.py);
  4. 执行单元测试:按测试文件扩展名选择测试命令(见 6.3),超时上限 3 分钟(timeout = 60 * 3);
  5. 失败反馈重试:只要测试失败就把报错原文拼进下一条消息(模板为 prompts.py 中的test_failures:“测试是正确的,不要修改测试,请修复代码”)再次让模型修复,直到通过或达到--tries次数(benchmark.py)。测试输出在回灌给模型前会经过cleanup_test_output清洗——去掉in 0.003s这类计时信息并把绝对路径替换成目录名,避免与代码无关的随机噪声影响模型(该函数还有配套单测 test_benchmark.py,把"Ran 5 tests in 0.003s\nOK"规范成"\nOK");
  6. 记录结果:每个练习生成一份.aider.results.json,含模型名、编辑格式、逐轮测试结果tests_outcomes、耗时、成本、各种错误计数与对话哈希等(benchmark.py);同时.aider.chat.history.md会留存完整对话,供复盘或--replay重放。

6.3 多语言测试命令映射

run_unit_tests依据测试文件扩展名选择执行器(benchmark.py):

扩展名测试命令
.pypytest
.rscargo test -- --include-ignored
.gogo test ./...
.js/aider/benchmark/npm-test.sh(符号链接共享镜像内 npm 依赖并执行npm run test,npm-test.sh)
.cpp/aider/benchmark/cpp-test.sh(cmake -DEXERCISM_RUN_ALL_TESTS=1+make,cpp-test.sh)
.java./gradlew test

细节处理还包括:Java 测试会移除@Disabled(...)注解强制全量执行;每一轮测试前把原始测试文件重新复制回工作目录,防止上轮被意外改动;每轮结束后清理 Rusttarget/debug、Javabuild、Nodenode_modules等构建残留,避免跨练习串扰。

6.4 汇总统计逻辑

--stats走 show_stats / summarize_results:遍历结果目录下所有*.aider.results.json,按练习聚合pass_rate_#,并累加各类错误计数与 token 用量;若某次(model, edit_format)组合出现多条记录会给出提示;结果不完整(已完成数小于总练习数)时会打印 Warning。最后还会额外输出每练习平均成本与“按全量练习外推”的预计总成本。

七、局限与注意事项

  • 这套脚本是面向 aider 开发者的内部工具,普通终端用户通常不需要也不应该运行它;
  • 由于 LLM 生成的代码会在无人监督下执行,评测必须在 Docker 容器内进行,且建议先单线程小规模验证环境、再上并行;
  • 部分工具以 bash 脚本实现(如docker.sh、npm-test.sh),在 Windows 上难以直接使用;
  • --threads太大可能被 API 限流,成本也会随--tries与练习数量线性上升,量产前先用--num-tests和--keywords做小范围验证会更稳妥;
  • 复现实验时请先提交代码再开跑,否则结果会带上-dirty标记而难以精确定位代码版本。

【免费下载链接】aideraider is AI pair programming in your terminal项目地址: https://gitcode.com/GitHub_Trending/ai/aider

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

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

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

立即咨询