1. 从 SWE-bench 评测说起:为什么 Agentless 训练值得单独拆开看
如果你最近在跑 SWE-bench 相关的评测,大概率会遇到一个很拧巴的问题:SWE-Agent 框架灵活、上限高,但训练极不稳定;Agentless 工作流模块化、可验证,但探索空间又太窄。KIMI-DEV 这篇论文有意思的地方在于,它没有把两者当成对立面,而是把 Agentless 训练重新定义成一种「技能先验(Skill Prior)」的注入手段——先让模型在单轮可验证的流水线里把故障定位、代码编辑、自我反思这些原子能力练扎实,再拿去做 SWE-Agent 的适配。
换句话说,Agentless 不是终点,而是脚手架。论文里 Kimi-Dev 在 SWE-bench Verified 上拿到 60.4%,用 5k 条公开轨迹做最小化 SFT 冷启动后驱动 SWE-Agent 达到 48.6% pass@1,这个数字已经能和 Claude 3.5 Sonnet(241022)掰手腕。对做评测的人来说,真正有价值的不是这个分数本身,而是「技能先验可以跨范式迁移」这个结论——它意味着你可以用一套相对稳定的训练流程,去喂一个更灵活的智能体框架。
这篇就围绕这个思路,把可复制的 config.toml 骨架、TaoToken 统一 Key/API 通道配置,以及在 SWE-bench 子集上验证 agentless 训练前后差异的具体动作拆开讲。适合已经在跑 SWE-bench 评测、想搞清楚 skill prior 怎么落到工程里的人。
2. 前置准备:用 TaoToken 统一 Key 打通模型通道
在拆训练流程之前,先把模型调用这条链路理顺。SWE-bench 评测里你会频繁切换模型——定位阶段可能用推理强的,代码编辑阶段可能用指令跟随好的,测试时自博弈还要并发采样几十次。如果每个模型都单独配一套 Key 和环境变量,脚本会变得很难维护。
我自己的做法是用 TaoToken 做统一通道。它的 API 地址是https://taotoken.net/api,兼容 OpenAI 风格的调用方式,所以你在 SWE-bench 的评测脚本里只需要改base_url和api_key两个地方,不用动上层逻辑。官网入口在https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content=,注册后在控制台生成 Key 即可。
具体操作路径是这样的:先到控制台创建 API Key,地址是https://taotoken.net/console?utm_source=taotoken_aicg_blog_end&utm_content=console&utm_campaign=rewrite;生成后到 API Keys 页面管理,地址是https://taotoken.net/api-keys?utm_source=taotoken_aicg_blog_end&utm_content=api-keys&utm_campaign=rewrite。如果你要对照模型能力做选型,可以先用模型对话页面快速试一下,地址是https://taotoken.net/models?utm_source=taotoken_aicg_blog_end&utm_content=model-chat&utm_campaign=rewrite。
注意:SWE-bench 评测里并发采样很密集,建议在控制台里先确认好额度,避免跑到一半因为限流中断。接入细节可以对照文档页
https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_content=doc&utm_campaign=rewrite。
环境变量建议这样设,后面所有脚本都复用:
export TAOTOKEN_API_KEY="sk-你的key" export TAOTOKEN_BASE_URL="https://taotoken.net/api"3. 可复制配置:config.toml 骨架与 Skill Prior 注入点
KIMI-DEV 的训练方案分四段:中间训练(mid-training)、冷启动(cold-start)、强化学习(RL)、测试时自博弈(test-time self-play)。落到工程配置上,我把它整理成一个 config.toml 骨架,你可以直接改参数复用。核心思路是把「技能先验」拆成可配置的注入点,而不是写死在代码里。
# config.toml - SWE-bench Agentless Skill Prior 配置骨架 [model] provider = "taotoken" base_url = "https://taotoken.net/api" api_key_env = "TAOTOKEN_API_KEY" # 定位阶段用推理强的模型,编辑阶段可换指令跟随好的 localization_model = "kimi-dev-72b" edit_model = "kimi-dev-72b" max_context = 65536 [mid_training] # 中间训练:约 150B tokens,四类数据混合 total_tokens = 150_000_000_000 diff_patch_tokens = 50_000_000_000 # Agentless 风格:直接给最终补丁 commit_pack_tokens = 20_000_000_000 # Agent 风格:保留逐步推理过程 synthetic_reasoning_tokens = 20_000_000_000 # 定位推理轨迹 synthetic_agent_tokens = 20_000_000_000 # 多轮工具调用 + 自我反思 synthetic_upsample = 4 learning_rate = 2e-5 lr_schedule = "cosine" [cold_start] # 冷启动 SFT:激活长 CoT 能力 dataset = ["swe-gym", "swe-bench-extra"] trajectory_source = "deepseek-r1" roles = ["bugfixer", "testwriter"] [reinforcement_learning] # RL 只训练代码编辑阶段 algorithm = "kimi-k1.5-policy-optimization" reward_type = "outcome_only" # 只用执行结果 0/1,不加格式奖励 initial_prompt_set = 1200 rollouts_per_prompt = 16 curriculum_interval = 100 # 每 100 步重新引入 500 道难题 curriculum_batch = 500 max_context = 65536 positive_example_reinforce = true # 后期正样本强化 [test_time_self_play] num_patches = 40 num_tests = 40 greedy_first = true # 第一个补丁温度 0 temperature = 1.0 # 其余 39 个温度 1.0 score_formula = "reproduce + regression" [sandbox] backend = "kubernetes" max_concurrent = 10000这份配置里最关键的是[reinforcement_learning]段。论文里强调「仅使用结果奖励」,也就是 BugFixer 的补丁通过所有真实单元测试才给 1,TestWriter 的测试能在修复前失败、修复后通过才给 1。这个设计直接决定了你的 reward 函数怎么写,不要自作聪明加格式奖励,会污染信号。
另一个容易忽略的是curriculum_interval。论文里 pass@16=0 的题目在初始阶段被丢弃,因为它们对批次损失没贡献;每 100 步从「之前解不开、现在能解开」的池子里抽 500 道重新加回来。这个课程学习机制是 RL 能稳定扩展的关键,配置里必须留出来。
4. 验证请求:在 SWE-bench 子集上跑通 agentless 前后对比
配置写好了,接下来要验证 skill prior 到底有没有注入成功。我的做法是在 SWE-bench Verified 里抽一个子集(比如 50 个 instance),分别跑「未做 agentless 训练」和「做完 agentless 训练」两个版本,对比定位准确率和补丁通过率。
先写一个最小化的调用脚本,确认 TaoToken 通道是通的:
import os from openai import OpenAI client = OpenAI( api_key=os.environ["TAOTOKEN_API_KEY"], base_url=os.environ["TAOTOKEN_BASE_URL"], ) resp = client.chat.completions.create( model="kimi-dev-72b", messages=[ {"role": "system", "content": "You are a bug localization assistant."}, {"role": "user", "content": "Given the issue and repo context, output the file path to fix."}, ], temperature=0, ) print(resp.choices[0].message.content)通道通了之后,跑子集评测。核心是记录两个指标:定位阶段的 file-level accuracy,和编辑阶段的 pass@1。下面是一个简化版的评测循环:
import json from pathlib import Path def run_subset(instances, model, mode): results = [] for inst in instances: # 阶段一:定位 loc = call_localization(model, inst["issue"], inst["repo_snapshot"]) # 阶段二:生成补丁 patch = call_edit(model, inst["issue"], loc, mode=mode) # 阶段三:丢进 Docker 跑真实测试 passed = run_tests_in_sandbox(inst["instance_id"], patch) results.append({ "instance_id": inst["instance_id"], "localization_correct": loc in inst["gold_files"], "patch_passed": passed, }) return results if __name__ == "__main__": subset = json.loads(Path("swebench_subset_50.json").read_text()) before = run_subset(subset, "qwen2.5-72b-base", mode="no_prior") after = run_subset(subset, "kimi-dev-72b", mode="skill_prior") print("before pass@1:", sum(r["patch_passed"] for r in before) / len(before)) print("after pass@1:", sum(r["patch_passed"] for r in after) / len(after))实测下来,做完 agentless 训练的版本在定位准确率上提升最明显,因为中间训练里那 200 亿 tokens 的合成推理数据专门练了「怎么推理才能找到正确文件」。补丁通过率的提升则更多来自 RL 阶段的结果奖励和测试时自博弈。
如果你想验证测试时自博弈的效果,把num_patches和num_tests从 1 逐步调到 40,观察 pass@1 的变化曲线。论文里从 1×1 的 48.0% 提升到 40×40 的 60.4%,而且 3×3 的自博弈就已经超过 40 个补丁的多数投票。这个对比很值得自己复现一遍。
5. 本篇常见错排查
跑这套流程时,有几个坑我踩过,列出来帮你省时间。
报错一:ContextLengthExceeded在 RL 阶段频繁出现。论文里 RL 的最大上下文固定为 64k tokens,因为提示词输入包含初始模型预先定位的完整文件内容。如果你的仓库快照截取范围太大,很容易超。解决办法是在定位阶段就限制文件内容长度,只保留相关函数和上下文,而不是整个文件塞进去。
报错二:reward 全是 0,训练不收敛。大概率是 pass@16=0 的题目没被过滤掉。检查你的初始 prompt set 是不是直接用了全量数据,没有先用初始模型采样 16 次筛一遍。论文里初始集合是 1200 道「至少能解开一次」的题,这个筛选步骤不能省。
报错三:TestWriter 出现假阳性。论文里也提到,TestWriter 的 RL 训练中偶尔会因为复现覆盖率不足出现假阳性样本。表现是测试看起来能复现 bug,但实际上没覆盖到真正的失败路径。排查方法是检查测试是否在未应用补丁的原始仓库上真的触发了失败,而不是因为环境问题报错。
报错四:沙箱并发上不去。测试时自博弈要生成 40 个补丁 × 40 个测试,每个都要在 Docker 里跑一遍。论文里用 Kubernetes 支持超过 10000 个并发实例。如果你本地跑,建议先把num_patches和num_tests降到 3×3 验证流程,再逐步放大。
报错五:TaoToken 调用返回 401。检查TAOTOKEN_API_KEY环境变量有没有正确导出,以及 base_url 是不是https://taotoken.net/api(注意不要多加路径)。如果要在 CI 里跑,建议把 Key 放到 secrets 里而不是硬编码。
6. 下一步:把 Skill Prior 接到你的 SWE-Agent 流程里
Agentless 训练跑通之后,真正的价值在于迁移。论文里用 5k 条公开轨迹做最小化 SFT 冷启动,就能让 Kimi-Dev 驱动 SWE-Agent 达到 48.6% pass@1。这意味着你不需要从零训练一个智能体,而是可以拿一个已经注入技能先验的模型,用少量轨迹数据做适配。
如果你要做长期编码或 Agent 相关的实验,建议走 Coding Plan 通道,地址是https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_content=coding-plan&utm_campaign=rewrite,它在长上下文和并发采样上更适合这类场景。ClaudeCode 相关的接入配置可以参考https://taotoken.net/claudecode?utm_source=taotoken_aicg_blog_end&utm_content=claudecode&utm_campaign=rewrite。
具体到操作上,我的建议是先把本文的 config.toml 骨架跑通,在 50 个 instance 的子集上确认 agentless 前后的差异,然后再把定位和编辑两个阶段的模型换成你实际要用的。技能先验的注入不是一次性的,而是一个可以反复迭代的脚手架——每次你换模型或换评测集,都可以用同一套流程重新验证一遍。