Qwen3-Coder 评测实践:ExecRepoBench 仓库级代码补全基准的环境搭建、多级掩码机制与端到端评估指南
2026/9/13 18:50:28 网站建设 项目流程

Qwen3-Coder 评测实践:ExecRepoBench 仓库级代码补全基准的环境搭建、多级掩码机制与端到端评估指南

【免费下载链接】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

ExecRepoBench 是面向真实软件开发场景的仓库级(repository-level)代码补全基准,它从活跃的 Python 仓库中抽取 1.2K 个样本,并要求模型在跨文件依赖上下文中完成被掩码的代码片段,同时配套 Repo-Instruct 指令语料以提升开源大语言模型的代码补全能力。本文以 ExecRepoBench README 为骨架,结合 qwencoder-eval 评测目录下的真实实现(create_test_repo.py、eval.py、utils.py 等),完整讲解数据下载、评测环境准备、四类补全任务的构造原理,以及基于 vLLM 的生成与 pass@1/编辑相似度评估全流程。读完本文,你将能够在本仓库中复现 ExecRepoBench 的完整评测链路,并理解其 AST 多级掩码与跨文件上下文组织的底层设计。

ExecRepoBench 是什么:仓库级代码补全评测的核心思想

传统代码补全基准(如 HumanEval 的 FIM 变体)通常在单文件内构造任务,而真实开发中,一个函数往往依赖同仓库其他模块中定义的类、工具函数与配置。ExecRepoBench 的核心目标正是填补这一空白:它以多文件协作、存在复杂跨文件依赖的活跃 Python 仓库为素材,构建"前缀 + 被掩码片段 + 后缀"的补全样本,让模型在参考了仓库其他文件内容后才能正确恢复被掩码的代码。

根据 README 的 Dataset Summary,该工作同时贡献了两样东西:

  • ExecRepoBench 基准:包含 1.2K 条来自活跃 Python 仓库的样本,用于评测仓库级代码补全;
  • Repo-Instruct 指令语料:用于改善开源 LLM 在真实编程场景中的补全能力,与基准配套使用。

与基准配套的是基于抽象语法树(AST)的多级语法掩码方法:不是随机挖掉几行,而是按代码的逻辑单元(语句 statement、表达式 expression、函数 function/block)有策略地掩码,从而让评测任务覆盖不同粒度的补全难度。从源码看,这一思想在 prepare_multi_level_completion 中得到了完整实现(下文详述)。

数据下载与目录结构

获取 ExecRepoBench 数据集

README 给出了基于 Hugging Face + Git LFS 的下载方式:

git lfs install git clone https://huggingface.co/datasets/CSJianYang/ExecRepoBench

数据集通过 Hugging Face 分发,因此需要先安装并启用 Git LFS。下载完成后,建议将数据目录与本仓库的评测脚本配合使用:本仓库的评测脚本默认从./ExecRepoBench./repos/./test_set/等相对路径读取仓库与测试集(见下文各脚本的默认参数),实际操作时请按需将数据集软链或拷贝到对应位置,或通过命令行参数显式指定路径。

评测脚本目录速览

本仓库中 ExecRepoBench 的完整评测实现位于qwencoder-eval/base/benchmarks/ExecRepoBench/,核心文件与职责如下:

文件职责
create_test_repo.py测试仓库环境创建、测试数据构造、正确性验证(四种 action 入口)
eval.sh一键评测入口:先生成再评估
eval_models.sh带默认参数的评测调用示例
eval.pyvLLM 推理生成 + 正确性/编辑相似度评估
utils/prompt_template.py各模型家族的 FIM 提示模板
utils/utils.py语言符号表、BM25、相关度排序、编辑相似度等工具
create_environment.sh / test_repo_correctness.sh单仓库环境创建与正确性验证示例

环境准备:Miniconda 与测试仓库依赖隔离

ExecRepoBench 的正确性评估需要在隔离的 Python 环境中运行每个被测仓库的测试套件,因此环境准备是整个流程的第一步。README 给出的步骤为:

wget https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh bash Miniconda3-latest-Linux-x86_64.sh

安装 Miniconda 后,通过 create_test_repo.py 的prepare_environmentsaction 批量创建环境:

export PATH=./miniconda3/envs/vllm/bin/:$PATH python create_test_repo.py --action "prepare_environments"

从 prepare_test_repo_environment 的实现可以看到它实际做了四件事:

  1. 遍历repo_root_path(默认./repos/)下每个仓库,跳过build目录与点开头目录;
  2. 为每个仓库创建独立的 conda 环境:conda create -p {env_dir}/envs/repo_{repo_name} python=3.9 -y
  3. 依次执行pip install -r requirements.txt(若存在)与pip install -e .安装仓库本身及其依赖;
  4. 统一安装评测依赖:pytest pytest-cov pytest-benchmark coincidence cssutils docutils openpyxl hypothesis pycodestyle

create_environment.sh 给出了单仓库(markdown-it-py)的等价手动流程,方便调试单个环境。每个仓库一个独立环境的隔离设计,保证了某个仓库的依赖不会污染其他仓库的测试结果,也避免了"评测环境错误"被误判为"模型补全错误"。

验证评测环境

环境创建完成后,用以下命令验证所有仓库能否真正跑通测试(即环境本身是否完整可用):

export PATH=./miniconda3/envs/vllm/bin/:$PATH python create_test_repo.py --action "verify_all_repo_correctness"

该 action 对应 evaluate_all_correctness:读取test_set/test.jsonl(ground truth 掩码样本),逐条执行"还原中间代码 + 运行仓库测试",统计 pass@1。如果某仓库环境缺失依赖或仓库本身无法安装,此步会提前暴露问题。此外还提供了output_environmentsaction,可将每个仓库环境的pip freeze导出到{env_dir}/repo_requirements/,用于复现评测环境。

端到端评估:eval.sh 一键评测的完整拆解

标准评估命令

README 给出的核心评估命令如下:

ROOT_DIR="./ExecRepoBench" MODEL_NAME="qwen2.5-coder-base-7B" MODEL_DIR="./qwen/Qwen2.5-Coder-7B" INPUT_PATH="./test_set/exec_repo_bench.jsonl" OUTPUT_PATH="./results/${MODEL_NAME}/generation.jsonl" WORKERS=64 TP=1 EXTRA_ARGS="-max_context_tokens 8192 -max_tokens 32768 -max_generation_tokens 1024" bash ${ROOT_DIR}/eval.sh ${MODEL_NAME} ${MODEL_DIR} ${INPUT_PATH} ${OUTPUT_PATH} ${WORKERS} ${TP} "${EXTRA_ARGS}"

其中eval.sh接受 7 个位置参数,逐一说明:

参数含义默认值
MODEL_NAME($1)模型名称标识,用于生成结果目录与提示模板匹配(如qwen2.5-coder-base-
MODEL_DIR($2)本地模型权重路径(Hugging Face 格式,含config.json
INPUT_PATH($3)测试集 JSONL 路径
OUTPUT_PATH($4)生成结果输出路径
WORKERS($5)评估阶段并行进程数64
TP($6)vLLM 张量并行 GPU 数1
EXTRA_ARGS($7)透传给 eval.py 的额外生成参数

eval.sh 内部的两个阶段

查看 eval.sh 源码,它本质上是"生成 + 评估"两个阶段的封装,并用结果文件是否存在作为断点续跑的判据:

  1. 生成阶段:若${OUTPUT_PATH}不存在,则执行:
python eval.py \ -model_name ${MODEL_NAME} -model_dir ${MODEL_DIR} \ -input_path ${INPUT_PATH} -output_path ${OUTPUT_PATH} \ -workers ${WORKERS} -generation_only \ -tensor_parallel_size ${TP} ${EXTRA_ARGS}
  1. 评估阶段:若${OUTPUT_PATH}.metric不存在,则执行:
python eval.py \ -model_name ${MODEL_NAME} -model_dir ${MODEL_DIR} \ -input_path ${INPUT_PATH} -output_path ${OUTPUT_PATH} \ -workers ${WORKERS} -evaluation_only

这种设计意味着:生成结果一旦落盘,重复运行脚本不会重复推理;评测结果一旦产出,也不会重复执行测试,非常适合长时评测任务的中断恢复。eval_models.sh 则是把 README 中的示例命令固化为可直接运行的脚本。

eval.py 的关键参数

parse_args 定义了完整的参数集,除eval.sh透传的参数外,值得关注的有:

  • -context_order {far, close}:上下文文件的排列顺序,默认close(将相关度最高的文件放在最靠近被掩码文件的位置);
  • -env_path(默认./repo/envs/)与-repo_dir(默认./repos):指向评测环境与仓库源码根目录;
  • -max_context_tokens(默认 4096):跨文件上下文预算;
  • -max_generation_tokens(默认 512):单条补全生成的最大 token 数;
  • -max_tokens(默认 8192):总序列长度上限;
  • -verbose:打印每条样本的执行细节。

generate_samples会读取模型config.json中的max_position_embeddings/n_positions作为模型支持的最大长度;若模型上限小于-max_tokens,会自动将max_tokens收敛到模型上限并把max_context_tokens设为其一半,避免越界(eval.py)。

四种补全任务与 AST 多级掩码机制(源码级解析)

任务类型分布

ExecRepoBench 的每个仓库样本按固定比例混合四类补全任务,这一逻辑在 create_samples 中体现(每仓库 100 个样本,i从 0 到 99):

样本序号任务类型掩码方式说明
i < 3Random Single-line Completion随机掩 1 行单行级补全,最简单
3 ≤ i < 6Random Multi-line Completion随机掩 ≤10 行连续多行补全
6 ≤ i < 9Random Span Completion随机掩 ≤30 字符片段级补全,粒度最细
i ≥ 9Grammar-based Completion基于 AST 掩码按逻辑单元(block/statement/expression)掩码

create_prefix_suffix_code(create_test_repo.py)实现了前三种随机掩码:随机行掩码与随机字符掩码都会做边界处理,保证 prefix/suffix 的换行格式正确。生成的样本字段结构为:repo_namefile_nameprefix_codemiddle_codesuffix_codecontext_code(仓库内其他文件的完整内容)以及fill_type

多级语法掩码:从 AST 到补全任务

第四类"Grammar-based Completion"是 ExecRepoBench 的方法核心,实现在 prepare_multi_level_completion:

  1. 用 tree-sitter 解析被掩码文件,得到 AST;
  2. 遍历 AST 收集 10 类节点:import、comment、return 语句、if 语句、for 语句、while 语句、class 定义、function 定义、赋值语句、表达式语句;
  3. 按配置的采样比例随机选择一类节点(如IF_STATEMENT_TYPE: 0.15FOR_STATEMENT_TYPE: 0.15IMPORT_TYPE: 0.1FUNCTION_TYPE: 0.1COMMENT_TYPE: 0.05等),再从该类节点中随机挑一个作为掩码候选;
  4. 80% 概率直接掩整个节点;若节点跨行过多(>10 行)或位于文件边界,则退化为掩节点内部的某个子节点;
  5. 依据节点的字节区间(start_byte/end_byte)切出 prefix/middle/suffix 三段。

随后 create_samples 通过NODE_TYPE2LEVEL映射将 tree-sitter 节点类型归为三个逻辑层级:class_definition/function_definition/if_statement/for_statement/while_statement归为blockimport_statement/return_statement归为statementassignment/expression_statement/identifier/attribute等归为expression,最终形成grammar-based: blockgrammar-based: statementgrammar-based: expression三类带难度的任务标签。

树节点遍历依赖 tree-sitter 的游标接口,实现见 traverse_tree。各语言的 AST 节点类型映射集中在 utils.py 的 language_symbols,覆盖 Python、Java、C++、C#、TypeScript、JavaScript、PHP,例如 Python 的if_statement对应IF_STATEMENT_TYPE,C++ 的preproc_include对应IMPORT_TYPE。这意味着多级掩码方法在原理上可推广到多语言,而当前基准版本落地在 Python 仓库上。

样本过滤规则

为保证任务质量,create_samples 会对生成的中间代码做过滤:长度需大于 10 字符且小于 512 字符、不能与已有样本重复、不能包含#(避免掩码注释行)。同时在 prepare_test_repo_data 中通过is_valid_file排除tests/docs/build/目录以及setup.pyevaluate_repo.py等文件,确保只有业务源码参与任务构造。

跨文件上下文组织:相关度排序与长度预算

仓库级补全的关键在于如何把"仓库上下文"塞进有限的模型窗口。ExecRepoBench 的上下文组织分三步:

  1. 相关度打分:utils.get_relevance 结合两类信号为每个仓库文件打分——(a)import 依赖:解析被掩码代码的 import 语句(见 extract_imports),凡是定义了这些模块的文件获得加分(过滤掉已安装的第三方包,用 is_installed_package 判断);(b)BM25 词法相似度:用 BM25 实现(k1=1.5,b=0.75)计算每个上下文文件与被掩码代码的相似度并归一化。两者相加得到最终相关度。

  2. 按相关度排序create_samples中对context_code按相关度降序排列(create_test_repo.py),并在推理时以-context_order close将相关度最高的文件放在最靠近被掩码文件的位置(eval.py),模仿人类开发者"参考最相关文件"的习惯。

  3. token 预算分配:在 get_prompt 中,先按-max_context_tokens预算依次填入上下文文件(超预算的文件从右侧截断);随后在max_tokens - max_generation_tokens - max_context_tokens的剩余预算内,把被掩码文件的前缀从左侧截断、后缀从右侧截断(各占一半)。截断工具 truncate_prompt 基于 tokenizer 实现。

提示模板:面向不同模型家族的 FIM 格式适配

由于 ExecRepoBench 用于评测多种开源代码模型,get_prompt 根据model_name自动选择对应家族的 FIM 模板,模板定义集中在 prompt_template.py:

模型家族匹配关键字模板形式
Qwen2.5-Coder(base)qwen2.5-coder-base-<\|repo_name\|>+<\|file_sep\|>上下文 +{context}<\|fim_prefix\|>{prefix}<\|fim_suffix\|>{suffix}<\|fim_middle\|>
CodeQwen1.5 / StarCodercodeqwen1.5-base/starcoder-<repo_name>/<file_sep>上下文 +<fim_prefix>/<fim_suffix>/<fim_middle>
StarCoder2starcoder2-## 文件标题式上下文 + suffix 逐行加#注释前缀
DeepSeek-Coderdeepseek-coder#文件标题式上下文 +<|tool▁calls▁begin|>/<|tool▁call▁begin|>/<|tool▁call▁end|>模板
指令模型(如qwen2.5-coder-Cqwen2.5-coder-Cchat 模板:REPO_COMPLETE_TEMPLATE+SYSTEM_PROMPT,经apply_chat_template格式化
CodeLLaMA / Granite / OpenCoder / Codestral / CodeGeeX / Yi-Coder / CodeGemma各自前缀## 文件标题式上下文 + suffix 注释化的续写式 prompt

其中 Qwen2.5-Coder 的仓库级 FIM 格式会在上下文部分注入<|repo_name|><|file_sep|>标记,让模型显式感知仓库边界;codeqwen-base还会为生成阶段设置<file_sep>作为停止符(eval.py),防止模型继续生成到下一个文件。

生成与评估:vLLM 推理、pass@1 与编辑相似度

推理生成

generate_samples 使用 vLLM 批量推理:SamplingParams(temperature=0.0, top_p=0.95, max_tokens=args.max_generation_tokens),即贪心解码(temperature=0 保证确定性)。vLLM 引擎通过worker_use_ray=True启动,tensor_parallel_size支持多 GPU 张量并行。每条样本生成结果以generated_middle_code字段写回并落盘为 JSONL。

正确性评估

评估阶段 的核心是evaluate_correctness

  1. prefix_code + generated_middle_code + suffix_code重组为完整文件;
  2. 把仓库源码拷贝到临时目录(copy_src_to_dest),用生成的代码覆盖被掩码文件,避免污染原始仓库;
  3. 切换到该仓库的隔离 conda 环境({env_path}/repo_{repo_name}/bin),运行python evaluate_repo.py,超时上限 240 秒;
  4. 返回码为 0 记 1.0 分,否则记 0.0 分并记录 stderr;超时同样记 0 分并注明原因。

并行评估通过multi_tasks_from_objs(utils.py)以-workers个进程分块执行,-chunk_size控制每个 worker 处理的样本数。

指标输出

最终在{OUTPUT_PATH}.metrics中输出:

  • pass@1:正确还原(通过仓库测试)的样本占比;
  • es(edit similarity):基于 fuzzywuzzy 的fuzz.ratio(cal_edit_sim),对去除注释与空行的生成代码与 ground truth 计算编辑相似度,衡量"即使测试未通过,补全内容与参考答案的贴近程度";
  • fill_type分组的细分指标(Random Single-line/Multi-line/Spangrammar-based: expression/statement/block各自的 pass@1 与 es),并汇总生成 LaTeX 表格字符串,便于论文结果呈现(eval.py)。

评测流程小结与注意事项

将整条链路串起来,一次完整的 ExecRepoBench 评测分为四步:

  1. 下载数据git lfs install && git clone拉取数据集;
  2. 安装 Miniconda 并准备环境create_test_repo.py --action "prepare_environments"为每个仓库创建隔离 conda 环境;
  3. 验证环境create_test_repo.py --action "verify_all_repo_correctness"确认所有仓库测试可运行;
  4. 评测模型:按 README 的 7 参数命令调用eval.sh,得到generation.jsonlgeneration.jsonl.resultsgeneration.jsonl.metrics

实操中需要注意:eval.sh默认从./ExecRepoBench./qwen/./test_set/等相对路径取数,运行前请将数据布局对齐脚本预期;prepare_environments要求先激活 vLLM 所在环境(export PATH=./miniconda3/envs/vllm/bin/:$PATH);评估阶段依赖每个仓库可安装且测试可运行,verify_all_repo_correctness是降低误判率的必要前置步骤;生成阶段使用贪心解码,若要复现论文中的多次采样请自行调整SamplingParams

引用

若在你的研究或工程中使用了 ExecRepoBench 数据与方法,请按 README 的 Citation 引用原始论文:

@article{yang2024execrepobench, title={ExecRepoBench: Multi-level Executable Code Completion Evaluation}, author={Yang, Jian and Zhang, Jiajun and Yang, Jiaxi and Jin, Ke and Zhang, Lei and Peng, Qiyao and Deng, Ken and Miao, Yibo and Liu, Tianyu and Cui, Zeyu and others}, journal={arXiv preprint arXiv:2412.11990}, year={2024} }

本篇指南对应的可运行脚本与全部源码证据均位于本仓库 qwencoder-eval/base/benchmarks/ExecRepoBench/ 目录,可直接对照阅读与复现。

【免费下载链接】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),仅供参考

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

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

立即咨询