通义千问 Code Qwen 算法赛道季军方案:MFTCoder 多任务微调配置与 HumanEval 验证实录
发布时间:2026/9/26 16:35:18来源:尧图网络
1. 通义千问 Code Qwen 算法赛道季军方案MFTCoder 多任务微调配置与 HumanEval 验证实录通义千问 Code Qwen 算法赛道季军方案的核心是把 Qwen 1.8B 和 Qwen 72B 的代码生成能力通过 MFTCoder 多任务微调推到比赛评测的上限。如果你正在做代码生成评测、想复现一套可落地的多语言微调流程或者手头有 HumanEval、MBPP 这类基准要跑这篇内容会给你一套能直接抄的配置骨架和验证脚本。MFTCoder 是 codefuse-ai 开源的多任务微调框架支持 Qwen、Llama、Baichuan 等模型核心能力是 LoRA/QLoRA 高效微调加多任务损失平衡。HumanEval 则是 OpenAI 2021 年推出的代码评测集164 道手工题覆盖 Python、JavaScript、Java、Go、C、Rust 六种语言用 passk 衡量功能正确性不是只看语法能不能过。季军方案的关键动作有两个一是用 MFTCoder 把六种语言的代码指令数据组织成多任务训练二是用 HumanEval 的 synthesize 和 fixtests 两类任务做本地验证trust cv。下面按可复制的顺序拆开讲。2. 原问题与场景多语言代码微调为什么容易翻车比赛初赛阶段官方给的基础模型是 Qwen 1.8B评测覆盖 Python、JavaScript、Java、Go、C、Rust 六种语言的代码生成。我们一开始只用了 Evol-instruction-66k 和 CodeExercise-Python-27k 两个数据集做 SFT结果 Python 的 synthesize 分数涨得不错但其他语言几乎没动。后来补了 C 和 Java 的数据分数才跟着上来。这说明一个很直接的问题多语言代码微调里数据覆盖不全会让模型偏科。更麻烦的是任务组织方式。MFTCoder 的设计是把每个 data_paths 当成一个下游任务多个任务一起训练靠加权损失做平衡。我们试过按编程语言种类来组织数据集也就是 Python 一个任务、Java 一个任务这样分结果模型效果反而变差。分析下来有两个原因不同语言之间的效果会相互制约而且每种语言的 token 比例失衡严重loss 优化会偏离。后来改成按数据来源组织任务比如 Evol 系列一个任务、Magicoder 一个任务语言混合在里面效果才稳定。复赛阶段更聚焦 LeetCode 类题目官方给了 50 条验证集。我们收集了 LeetCode 相关数据构造成类似验证集的格式上传到训练平台对 Qwen-72B 做训练。这里踩过一个坑训练数据里如果有缩进错误或语法错误模型会直接学到坏模式线下评估分数虚高但线上崩。所以复赛阶段我们反复检查 Python 编码规范并且坚持用本地验证集算测试用例通过比例trust cv不盲目信训练 loss。3. TaoToken 前置把 API Key 和接入文档准备好在跑 MFTCoder 训练和 HumanEval 评测之前你需要一个稳定的模型调用入口来做对比验证和结果复核。TaoToken 提供模型对话、Coding Plan、API Keys 和接入文档适合在本地训练之外做快速验证。操作路径很直接先到官网 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 注册账号然后进控制台 https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_contentconsoleutm_campaignrewrite 创建 API Key。API Key 在 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite 这个页面管理创建后复制保存后面配置环境变量要用。如果你只是想在训练前快速验证 Qwen 的代码生成 baseline可以直接用模型对话页面 https://taotoken.net/model-chat?utm_sourcetaotoken_aicg_blog_endutm_contentmodel-chatutm_campaignrewrite 试几条 HumanEval 的 prompt看看原始模型输出长什么样。长期做编码和 Agent 任务的话Coding Plan https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewrite 更适合额度按编码场景优化过。接入文档在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite里面有 API 的请求格式和参数说明配置时对着看就行。API 基础地址是 https://taotoken.net/api注意这个地址不加 UTM 参数直接用于代码里的 base_url。环境变量建议这样设export TAOTOKEN_API_KEY你的API Key export TAOTOKEN_BASE_URLhttps://taotoken.net/api这样后面写验证脚本时可以直接读环境变量不用把 Key 硬编码进代码。4. 可复制配置MFTCoder 多任务微调骨架MFTCoder 的项目地址在 codefuse-ai/MFTCoder需要切换到 codeqwen_competition 分支然后进入 mft_peft_hf 目录。这个目录是 HuggingFace PEFT 的微调入口支持 LoRA 和 QLoRA。启动命令用 accelerate 包装关键参数如下# 单机单卡示例按实际硬件调整 N_GPU_PER_NODE1 N_NODE1 accelerate launch \ --num_machines $N_NODE \ --num_processes $(($N_NODE*$N_GPU_PER_NODE)) \ --use_deepspeed \ --deepspeed_multinode_launcher standard \ --zero_stage 2 \ --offload_optimizer_device cpu \ --offload_param_device none \ --gradient_accumulation_steps 1 \ --gradient_clipping 1.0 \ --zero3_init_flag false \ --zero3_save_16bit_model false \ --main_training_function main \ --mixed_precision bf16 \ --dynamo_backend no \ --same_network \ --machine_rank $RANK \ --main_process_ip $MASTER_ADDR \ --main_process_port $MASTER_PORT \ --rdzv_backend static \ mft_accelerate.py --train_config configs/qwen_train_config_1_8B.json训练配置文件 qwen_train_config_1_8B.json 里最关键的是 data_paths 字段。它的值必须是字符串格式的路径列表比如[路径1,路径2,路径3]每个路径代表一个下游任务路径里可以包含一个或多个 JSONL 文件。路径数量可以是一个或多个。我们季军方案里没有按语言分任务而是按数据来源分比如 Evol 系列一个路径、Magicoder 一个路径、CodeExercise 一个路径这样多语言数据在任务内部混合避免语言间相互制约。MFTCoder 的损失函数支持多种加权模式核心是 loss_func_mft 里的 weighted_loss_mode 参数。case1 是全局 token 加权case2 是样本级平均case3 和 case4 是任务级加权。我们实测下来 case3 在多任务场景下更稳因为它按每个任务的有效 token 数做归一化避免大任务主导 loss。代码里 task_id 的形状是[[1], [2], [4], [3], ..., [1]]每个样本对应一个任务 ID训练时通过 task_mask 和 task_id 做任务级 loss 聚合。数据准备阶段我们收集的数据集包括 bigcode/humanevalpack、TokenBender/code_instructions_122k_alpaca_style、ehartford/dolphin-coder、theblackcat102/evol-codealpaca-v1、ise-uiuc/Magicoder-Evol-Instruct-110K、codefuse-ai/Evol-instruction-66k 等。筛选去重的原则是同一道题的不同解法只保留一个语法错误的直接丢缩进不规范的修正后再用。去重后按数据来源分任务每个任务写成一个 JSONL 文件字段对齐 MFTCoder 的输入格式。5. 验证请求与成功结果HumanEval 评测脚本训练完之后用 MFTCoder 自带的预测脚本跑 HumanEval。脚本在 src/evaluation/launch_generate_codeqwen.sh核心逻辑是遍历任务列表对每个任务调 main.py 生成结果。任务列表包括 humanevalsynthesize 的六种语言、humanevalfixtests 的六种语言以及 mbpp。配置如下N_NODE1 N_GPU_PER_NODE1 tasks(humanevalsynthesize-python humanevalsynthesize-java humanevalsynthesize-js humanevalsynthesize-cpp humanevalsynthesize-go humanevalsynthesize-rust humanevalfixtests-python humanevalfixtests-java humanevalfixtests-js humanevalfixtests-cpp humanevalfixtests-go humanevalfixtests-rust mbpp) model/path/to/local/model/checkpoint model_nameyour-model-name generation_base_dir/path/to/hold/generated/results if [ ! -d $generation_base_dir ]; then mkdir $generation_base_dir; fi batch_size1 n_samples1 # Qwen base model 的 eos 是 |endoftext|微调后是 |im_end| eos_token|im_end| useruser assistantassistant systemsystem end_tag|im_end| start_tag|im_start| system$start_tag$system$\n$end_tag$\n for task in ${tasks[]}; do if [ $task mbpp ]; then prefix$system$start_tag${user}$\n suffix$end_tag$\n$start_tag${assistant} else prefix suffix fi generations_path$generation_base_dir/generations_$model_name/generations_$task\_$model_name.json if [ ! -d $generation_base_dir/generations_$model_name ]; then mkdir $generation_base_dir/generations_$model_name; fi echo start to launch .... accelerate launch \ --num_machines $N_NODE \ --num_processes $(($N_NODE*$N_GPU_PER_NODE)) \ main.py \ --model $model \ --task $task \ --prompt instruct \ --n_samples $n_samples \ --batch_size $batch_size \ --max_length_generation 2000 \ --do_sample False \ --temperature 0.2 \ --precision bf16 \ --eos $eos_token \ --seed 999999999 \ --add_special_tokens True \ --trust_remote_code \ --generation_only \ --save_generations_path $generations_path \ --prefix $prefix \ --suffix $suffix echo Task $task done done跑完之后generations 目录下会生成每个任务的 JSON 文件。HumanEval 的评测逻辑是对每道题把模型生成的代码和 canonical_solution 对比跑 test 字段里的单元测试统计 pass1。pass1 就是只生成一个答案时正确的比例pass10 是生成 10 个答案里至少有一个正确的比例。我们初赛阶段 Python synthesize 的 pass1 从 baseline 的 0.2 左右涨到 0.35 以上六种语言平均也有明显提升。复赛线下验证集分数 0.62A 榜 0.5B 榜 0.2798最终拿到季军。如果你想用 TaoToken 的模型对话做快速对比可以写一个简单的 Python 脚本调 APIimport os import requests api_key os.environ[TAOTOKEN_API_KEY] base_url os.environ[TAOTOKEN_BASE_URL] prompt from typing import List def has_close_elements(numbers: List[float], threshold: float) - bool: \\\ Check if in given list of numbers, are any two numbers closer to each other than given threshold. has_close_elements([1.0, 2.0, 3.0], 0.5) False has_close_elements([1.0, 2.8, 3.0, 4.0, 5.0, 2.0], 0.3) True \\\ resp requests.post( f{base_url}/v1/chat/completions, headers{Authorization: fBearer {api_key}}, json{ model: qwen-coder, messages: [{role: user, content: prompt}], temperature: 0.2, max_tokens: 512 } ) print(resp.json()[choices][0][message][content])这个脚本能帮你快速看原始模型和微调后模型的输出差异适合在正式评测前做 sanity check。6. 本篇常见错排查第一个高频错误是 data_paths 格式写错。MFTCoder 要求它是字符串格式的路径列表比如[path1,path2]如果你直接写 JSON 数组或者用空格分隔训练启动时会报解析错误。检查方法是看 config 文件里 data_paths 的值是不是带引号的字符串。第二个错误是 eos_token 设错。Qwen base model 的 eos 是|endoftext|微调后的模型 eos 是|im_end|。如果评测时 eos 设错生成结果会在不该停的地方停或者一直生成到 max_lengthpass1 会异常低。排查方法是看生成结果里有没有大量重复或截断。第三个错误是任务组织方式按语言分。前面说过按语言分任务会导致语言间相互制约和 token 比例失衡。如果你发现某个语言分数特别低先检查 data_paths 是不是按语言拆的。改成按数据来源分让多语言在任务内部混合。第四个错误是训练数据里有语法错误或缩进错误。复赛阶段我们反复强调这一点因为模型会学到坏模式。排查方法是写一个简单的 Python 脚本对每个 JSONL 文件里的代码字段做 ast.parse 检查语法不过的直接丢。第五个错误是评测时 prefix 和 suffix 设错。HumanEval synthesize 任务不需要 prefix 和 suffix但 MBPP 需要加 system prompt 和 user/assistant 标记。如果 MBPP 的 prefix 没设模型不知道要生成什么格式分数会崩。检查方法是看 launch_generate_codeqwen.sh 里 task 为 mbpp 时的分支逻辑。第六个错误是 accelerate 启动参数和硬件不匹配。比如单卡机器上设了 N_NODE2或者 deepspeed zero_stage 设成 3 但显存不够。排查方法是先用 N_NODE1、N_GPU_PER_NODE1、zero_stage2 跑通再逐步加卡。7. 语义一致 CTA按场景选入口如果你在排障或接入阶段卡住优先看 API Keys 和接入文档。API Keys 在 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite接入文档在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite里面有请求格式、参数说明和错误码解释。如果你要验证模型输出、对比微调前后的代码生成质量用模型对话页面 https://taotoken.net/model-chat?utm_sourcetaotoken_aicg_blog_endutm_contentmodel-chatutm_campaignrewrite直接贴 HumanEval 的 prompt 就能看结果。如果你长期做编码任务、Agent 开发或者需要稳定额度跑批量评测Coding Plan https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewrite 更适合额度按编码场景优化不用每次手动调。最后说一个实操细节HumanEval 的 test 字段里有些题目的单元测试依赖 import比如 Go 语言的 test_setup 字段。跑评测前先确认 main.py 里有没有处理这些依赖否则会出现测试用例跑不起来但代码本身正确的情况。我们复赛阶段就因为这个丢过几分后来在评测脚本里加了 import 检查才修好。
网站建设高端定制企业官网