这段时间朋友圈里聊“烧卡”的人特别多。凡是准备上车 Coding Agent 的团队,几乎都在纠结同一个问题:手头这个 base 模型,到底值不值得投几千卡时继续“练”?我前阵子刚交过一次昂贵的学费——把一个在榜单上分数挺好看的底座模型拿去做训练,结果第一版 Agent 版本连最基础的工具调用都站不稳,GPU 账单倒是烧得相当扎实。从那以后,我养成了一个习惯:不管模型宣传多好,先验货再烧卡,用 NVIDIA 那套三探针思路快速过滤一遍,能过再谈训练计划。
这篇文章就是把我的“验货流程”完整拆开,讲清楚三个探针分别探什么、怎么跑、怎么判读,以及我在实际探针过程中踩过的几个坑。如果你也正准备用某个底座模型自己训练 Coding Agent,这套流程能帮你省掉不少冤枉卡时。
1. 为什么是这三个探针——一张 GPU 账单换来的过滤原则
1.1 我那次白等了十天的高代价训练
事情说起来不算复杂。当时我们想做一个针对内部代码库的 Coding Agent,选型阶段看中了一个开源 base 模型,原因很直白:它在几份公开代码评测上的分数不算低,社区里也有不少人拿它做指令微调效果还不错。于是我们直接进入数据整理、配环境、拉集群,一口气训了将近十天,光 A100 就烧了上百卡时。
训练结束后,我很兴奋地把它接到 Agent 工作流里,结果第一个冒烟的端倪就出现在“工具调用”上。模型经常输出一段语义正确、语法没问题的代码,却不知道什么时候该调 search、什么时候该 read_file,甚至会把工具参数拼成一个不存在的 key。我反复调了提示词和采样参数,效果都很有限,最后只能推倒重来,换了一个底子更老实的小参数模型,反而稳定很多。
这十天 GPU 账单换来的教训很朴素:榜单分数高,不代表它适合做 Coding Agent 的底座。榜单考的是“能不能生成正确答案”,而 Coding Agent 真正要求的是“能不能在多步交互里稳定地干活”。这两件事的模型能力维度完全不同,只看静态分数做决策,约等于没验货就下订。
1.2 探针不是 benchmark——它探的是“可训练性”
后来我在 NVIDIA 公开的一些代码模型评估思路里,反复看到三个能力维度被强调:基础代码生成的正确性、工具调用环境的稳定性、模型在失败后的自我修复能力。这三条线几乎覆盖了 Coding Agent 训练中决定成败的全部关键点,我把它们整理成了三个探针。
探针和普通 benchmark 的最大区别在于,探针的目标不是排名,而是预判。我不需要它面面俱到,我只需要在半天到一天的时间里,用很少的样本和资源,判断“这个底座值不值得继续投入训练成本”。如果把训练看成一场长跑,benchmark 是看运动员平时的比赛成绩,探针则是起跑前的体测——项目不多、动作简单,但足以提前筛掉心肺功能不行的选手。
所以我给这次流程定的原则有三个:样本量小到能用单卡在半天内跑完;任务类型贴近真实 Agent 工作而不是纯刷榜;每项判断都要有明确的通过/危险线,而不是只看相对排名。下面依次讲这三支探针的具体设计。
2. 第一支探针:干净的代码生成正确率——验证下限“装得下”
2.1 探针样本怎么取,才不会让结果失真
第一支探针探的是最基础的问题:这个 base 模型能不能写对代码?这里的“写对”不要求它写得多漂亮,而是至少能完成功能、能通过隐藏测试、不会出现低级语法错误。如果这一步都不达标,后面的 Agent 训练基本是空中楼阁。
我用的是 2000 条小型编程题,样本不大,但构造上动了点心思。题目类型尽量贴近实际工程场景:包括但不限于输入输出格式化、数据清洗、配置文件解析、HTTP 接口的黏合代码、数组和字典的常见操作,而不是纯算法竞赛题。原因很简单,Coding Agent 日常处理的是工程问题,不是让你在 LeetCode 上秀技巧。
选样本时有几个容易犯的毛病,一定要避掉。第一是直接用网上现成的题目集合,这些题目十有八九已经躺在模型的训练语料里,探针会变成“记忆力测试”而不是能力测试;第二是题目里不能带完整的参考答案,否则模型生成的时候会顺着提示词里的模式走,探针结果虚高;第三是最好准备一些换皮题,把题目里的人名、变量名、函数名和业务场景全部换掉,甚至把参数顺序反转一遍,用来冲淡记忆效应。
判分的时候,我不只看 pass@1 这一个数。我同时记录四个信号:生成结果能否通过隐藏测试、是否存在语法错误、是否出现空实现或死循环、是否在代码里硬编码了测试用例。四个维度里只要有两个出问题,这支探针就算亮黄灯,因为这些问题在 Agent 场景会被放大,而不是变小。
2.2 我的判分规则:三个阈值必须一起看
很多人习惯只盯 pass@n,这是很大的误解。pass@n 高只能说明模型的采样多样性不错,能靠多采样碰出正确答案,但在 Coding Agent 场景里,你每步往往只采一次样,或者最多采两三次,靠多次采样兜底并不可靠。所以我自己的判分规则是看一组阈值:
| 指标 | 及格线 | 说明 |
|---|---|---|
| pass@1 | ≥ 0.5 | 单次采样能过的比例,低于这个值 Agent 跑一步错一步 |
| 语法错误率 | ≤ 0.1 | 生成代码不能执行的比率,超过一成说明模型输出层不稳 |
| 硬编码/空实现比例 | ≤ 0.05 | 模型试图“作弊”完成题目的比例,这个数高表示它学的是表面模式 |
我实测下来,很多分数好看的模型在 pass@1 上其实并不突出,靠的是 pass@10 往上拉升,这是典型的“采样型选手”,不适合做 Agent 底座。另外还有一个容易忽略的细节:判定代码正确时,命令行工具要提供足够清晰的错误信息,比如编译错误的具体行号、运行时异常的 traceback,这样后续第二、第三探针才能基于这些信息做多轮修复的测试。
3. 第二支探针:工具调用环的稳定性——看模型会不会干活
3.1 最小 Agent 环境的搭建思路
代码生成正确只是“能写”,Coding Agent 的核心是“能干”。它要在多轮交互中不断读懂任务、调用工具、处理返回结果、修正策略,最后把一件事做完。第二支探针探的就是这个动态过程。
不需要把整个 IDE 工作流搬过来,那太重了。我搭了一个最小可运行的 Agent 环境:给模型提供三四个假工具,比如 read_file、search_symbol、write_file、run_tests,每个工具都有明确的函数签名和返回格式,然后给它一个需要多步操作才能完成的任务,比如“在某个模拟项目里定位一个 bug 并修复”。
任务集控制在 80 条左右,每条任务都设计成必须调用至少三次工具才能完成,中间还有一步需要根据工具返回结果改变计划。这能强制模型展示它的多步决策能力,而不是单纯生成一段代码就结束。环境里我还会保留完整的对话历史,因为 Coding Agent 是多轮工作,模型的上下文利用能力也在这个探针里一起被验证。
这里有个关键细节:工具调用的输入输出格式必须严格贴近你未来训练数据里会用到的格式。如果你打算用 JSON function calling 风格,探针里就全用 JSON;如果你打算用代码解释器风格,探针里就模那个风格。原因是模型对提示格式非常敏感,探针的格式和训练格式如果不一致,探针预判的结果就没有参考价值。
3.2 核心指标与五连跑的判读方法
第二支探针我不能只看一轮结果,因为 Agent 任务本身有随机性。我的做法是同一组任务跑五遍,然后看几个统计量:
| 指标 | 含义 | 危险信号 |
|---|---|---|
| 任务完成率 | 能真正修好 bug 的比例,五遍至少三遍成功 | 五轮里两轮以下成功 |
| 工具调用格式错误率 | 模型输出参数无法被解析的比例 | 超过 5% 就直接淘汰 |
| 平均轮次 | 完成任务平均用了多少轮 | 超过 10 轮说明模型不会收敛 |
| 无效调用率 | 调用了并不存在的函数或错误参数 | 超过 10% 说明对工具的认知是糊的 |
最有意思的发现是这个:某个基础模型第一支探针表现很不错,pass@1 到了 0.6,语法错误率也不高,但第二支探针一跑就露馅,它经常在拿到工具返回结果之后“忘记”自己最初的任务,自顾自生成一段新的计划文本,或者重复调用同一个工具五六遍。这种问题在静态评测里完全看不出来,只有在多轮交互里才会暴露。
数据整理时我发现一个规律:工具调用格式错误率低的模型,后续做强化学习的收益往往更高,因为它能更快地从环境反馈里学到新策略;格式错误率高的模型,哪怕第一支探针分数很好,训练时也会花大量算力在“纠正输出格式”这个低水平问题上。所以第二支探针在我心里的权重是最重的,占整个判决表的 40%。
4. 第三支探针:自我纠错与上下文压力——判断能不能练出强 Agent
4.1 故意注入错误,观察模型的修复路径
一支探针测完“能不能生成”,再测完“能不能干活”,第三支要测的是“干砸了会不会自己站起来”。这部分是我在踩坑之后才补上的,因为真正能拿来训练的底座,不应该只是在顺利流程里表现稳定,还得在拿到失败反馈后自己找到问题并修好。
我把 40 条故意埋了 bug 的代码任务整理成一个测试集。这些任务会先让模型读一个带有明显错误的代码文件,然后运行测试并故意返回失败信息,观察模型能不能根据报错内容定位错误行,能不能解释问题原因,能不能生成修复补丁,补丁能不能通过测试验证。整个流程是一个闭环,像极了 Coding Agent 在真实项目里帮人修 bug 的场景。
我记录三个信号:修复成功率、平均修复轮数、修复过程中是否破坏其他已有测试。一个值得信赖的底座,修复成功率一般要在 0.7 以上,平均修复轮数不超过五轮,且在修复过程中不应该把原本通过的测试改挂掉。如果模型经常把一个小 bug 改成另一个更大的 bug,说明它对代码逻辑的理解只是表面上的,训练时很难让它从环境反馈里学到正确策略。
4.2 长上下文下的“翻旧账”能力
第三个探针还有一个隐藏测试点:上下文压力。真实 Coding Agent 的多轮交互会累积大量上下文,读过的文件、调用过的结果、改过的补丁都会留在对话窗口里。模型能不能在上下文很长的时候仍然记住最初的任务目标,这一点非常影响训练效果。
我通常会把同一个修复任务放在不同上下文长度下各跑一遍,比如短窗口两三千 token、中等窗口七八千 token、长窗口一两万 token,然后对比修复成功率。有些模型在小窗口下修复成功率能到 0.7,但上下文一长就开始“翻旧账”,把早期修改过的代码重新粘一遍,或者明显忽略掉中间的关键工具返回结果。
这类问题在训练中特别难靠数据解决,因为它是底座自身的注意力机制决定的。如果探针发现模型在长上下文下性能断崖式下跌,我会直接把它拉黑,而不是指望靠更多指令微调和强化学习去补救。上下文能力的衰减很难靠后期训练逆向修复,提前探出来能省下大量无效烧卡时间。
我个人给第三支探针定的及格线比较宽松:短上下文修复成功率不低于 0.6、中等上下文下降不超过 15%、长上下文下降不超过 20%。如果长上下文下降超过 30%,基本可以判定这个模型当前不适合做 Coding Agent 底座,除非你只做单轮代码补全,不做多轮维修场景。
5. 把三个探针的结果合成一张判决表——到底什么叫“值得烧卡”
5.1 打分权重和阈值建议
三个探针测完之后,如果你只得到三组数字,还是不知道该怎么拍板。我自己会做一步简单的折算,把结果压成单一分数,然后对照我总结的阈值做决策。
我用的权重大约是这样:第一支探针占 30%,因为它代表模型的基础代码下限;第二支探针占 40%,因为工具调用环的稳定性直接决定 Agent 能不能干活;第三支探针占 20%,因为自我修复是进阶能力但相对容易靠训练补齐。剩下的 10% 我会留给长上下文衰减率这类附加信号,这个占比不做硬性规定,但建议在写判决逻辑时保留一点人工审查空间。
| 总分区间 | 判决 | 建议动作 |
|---|---|---|
| ≥ 0.75 | 值得烧卡 | 可以进入正式数据整理和训练排期 |
| 0.6 ~ 0.75 | 有条件可练 | 只练和你业务场景高度匹配的小范围任务,别做全能力训练 |
| 0.5 ~ 0.6 | 不建议烧 | 换一个小参数但更稳定的底座,或者考虑用 API 模型做蒸馏 |
| < 0.5 | 直接淘汰 | 投入训练只会浪费卡时和人力 |
这套阈值不是来自什么官方标准,是我自己根据几次失败和两次成功训练梳理出来的经验值,但它的好处是能把一次模糊的判断变成透明的决策记录。团队里讨论要不要烧卡的时候,不再有人说“我感觉这个模型挺强的”,而是直接摆出三张探针报告,谁想说服谁就拿数据说话。
5.2 两个例外:探针没过但还可以烧的场景
经验归经验,算法归算法,我再补充两个例外情况,免得把流程用成教条。
第一种例外是你打算做“行为蒸馏”而不是能力训练。如果你的项目目标不是把这个底座训练成全能的 Coding Agent,而是让它的输出风格和你的训练数据保持一致,最终还是要调用一个更强的 API 模型来做决策,那探针分数低一点问题不大。因为训练只是让底座“话术对齐”,真正干活的核心还是外部模型兜底,这种情况下判断标准就完全不一样了,烧卡成本也不会太高。
第二种例外是探针整体分数虽然低,但某一个单项极其突出。比如第二支探针完成率非常高,只是第一支的语法错误率偏右,这种情况意味着模型本身适合做工具调用,只是代码生成细节没被充分激活。你可以考虑用极少量的高质量代码数据做一轮低成本 SFT,然后再跑一次探针,如果两个指标都恢复到及格线以上,那就值得继续烧。但如果你发现第一支探针低且第二支也低,那基本不用挣扎了。
6. 我保留的探针工具链和排雷点——照着跑一遍只花半天
6.1 用最少的算力完成三个探针的跑法
可能有朋友会问:我做探针不是为了省烧卡吗?怎么跑探针还要花不少资源和时间吧?我给一个低配参考流程,单卡就能完成,而且半天内能跑完。
第一支探针我用 2000 条题、batch size 8、max new token 控制在 512 左右,在单张主流计算卡上用 vLLM 或者类似的推理框架,大约两三个小时能跑完。判分脚本里我用的是一个轻量测试框架,每条题只有一个隐藏测试函数,这样判分很快,不需要启动一套复杂评测后端。你可以根据卡的情况调整题目数量,但我的经验是低于 1000 条的话判读会不太稳,建议别太省。
第二支探针的任务量从 2000 条减到 80 条,但每条任务要跑多轮,所以总耗时反而可能更长。我会把并行度开到 4,每个任务设定一个最大轮数上限比如 12 轮,超过就直接判失败并跳过,防止发生死循环式调用把时间耗光。80 条任务在单卡上大约两小时能跑完。第三支探针的任务量最小,40 条带 bug 的修复任务,通常一小时内能出结果。
整个流程下来,半天时间基本够用。相比动辄几周的训练周期,这半天时间花得极其划算。我甚至会在新模型开放下载的第一天就把它跑一遍,把探针报告存成一个 json 文件,和模型版本号一起归档,以后团队里谁想评估新底座,直接把新旧报告拉出来对比就行。
6.2 三个我踩过的探针翻车点
探针本身也不是没有误差的。我一开始以为把代码控制住就万事大吉,结果连续三次翻车,这里总结成三点,帮大家避雷。
第一个翻车点是提示词污染。我在第一支探针的提示词里放了一段“以下是来自某某竞赛的题目”的描述,结果模型好像被激起了某种记忆,生成质量比实际水平高了整整一截,等我把提示词改成无来源的纯任务描述后,分数立刻跌了十几个点。有些模型对提示词里的门派暗示非常敏感,你一旦告诉它这是一道知名题集里的题,它就开始“回忆”而不是“思考”。所以探针提示词必须跟你未来真实使用场景保持一致,最好直接用训练时要用的模板。
第二个坑是判分脚本用字符串匹配来判断生成代码正确。代码这东西千变万化,一个返回参数的顺序、一个引号的类型都会导致字符串不匹配,于是漏判很多实际上正确的结果。正确做法是真正把生成代码放到沙箱里执行,用测试用例校验行为,而不是靠肉眼或者字符串规则去猜。行为正确才是真正的通过。
第三个坑是样例数量太少导致波动大。我头一轮只选了 300 道第一探针题目,跑出来分数不错,但把样例扩充到 2000 道后,分数掉了不少,因为模型可能在巧的几道题上表现特别好,小样本很容易被偶然事件带偏。现在的做法是,每次换底座都统一用同一份探针题库,保证对比基准一致,不随意改动。
最后想补一句:探针不是万能钥匙。它只能帮你在低成本的条件下规避明显的高风险选择,不能保证高分底座一定训练成功。但把这三支探针纳入团队的评估流程之后,我们至少不会再出现“榜单分数很高、一上 Agent 就崩”的尴尬情况。烧卡之前先验货,每次新底座发布时花上半天跑一遍,比事后多烧几百卡时划算太多了。