216 项测试都过了,这个 Bug 还是没修好:我用 Seed-Evolving 跑了 9 次真实仓库任务

📅 发布时间:2026/10/2 16:23:56
216 项测试都过了,这个 Bug 还是没修好:我用 Seed-Evolving 跑了 9 次真实仓库任务
1. 216 项测试全绿Bug 为什么还在一次真实仓库任务的失败复盘如果你正在用 Coding Agent 跑真实仓库任务大概率遇到过这种场景终端里216 passed, 1 skipped模型解释写得头头是道补丁看起来也像模像样但用户报的那个问题依然能复现。这不是模型不会写代码而是它把「测试通过」当成了「问题解决」。Seed-Evolving 这类面向软件工程任务的模型在 SWE-bench 风格的仓库级问题上已经能独立读代码、改文件、跑测试但「测试全绿但 Bug 仍在」恰恰是它最容易翻车的地方。我这次用 Trae CN 加 doubao-seed-evolving在三个开源仓库的历史缺陷上各跑三轮一共 9 次任务全程录屏。结果很有意思T01 Flask 空 Blueprint 名称三轮全过补丁 SHA-256 前缀都一样T02 pytest 日志 fixture 状态恢复三轮语义一致T03 Requests 代理 URL 认证丢失三轮全部失败可见测试分别跑到 214、212、216 项通过但隐藏验收用例一次都没过。这篇文章就把这 9 次任务的配置、日志采集脚本、逐轮验证动作拆开讲清楚并说明怎么通过 TaoToken 统一 Key 和 API 通道接入模型做对照实验让你自己也能复现这套验证路径。适合谁看正在把 Coding Agent 接进日常开发流程的后端或全栈工程师想用 SWE-bench 思路做内部评测的技术负责人以及被「测试绿了但需求没完成」坑过的同学。核心检索词就三个Seed-Evolving、SWE-bench、Coding Agent 真实仓库任务验证。先说结论后面展开测试数量和测试价值不是一回事。如果 Agent 的根因判断偏了它新增的测试越贴合这个错误假设错误反而越显得可信。你要守住的不是「它有没有输出代码」而是「它解决的是不是原来的问题」。2. TaoToken 前置统一 Key 与 API 通道让 9 次对照实验可复现做这种多轮对照实验最怕的不是模型不稳定而是接入方式每轮不一样。今天用这个通道明天换那个 Key模型 ID 写错一个字符结果就没法对比。所以正式跑任务之前我先把模型接入统一到 TaoToken 上用同一套 Base URL、同一个 Key、同一个 Model ID 跑完 9 轮排除接入层带来的变量。TaoToken 在这里的角色是统一 API 通道你不需要为每个模型单独维护一套鉴权和地址改配置只改 Model ID 就行。官网入口在 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 地址是 https://taotoken.net/api 注意 API 地址不带 UTM 参数配置里直接写这个。为什么强调「统一」因为 T03 那种失败模式很容易被误判成「换个模型就好了」。但如果你接入层每轮都在变你根本分不清失败是模型能力问题、提示词问题还是通道把请求改坏了。统一通道之后9 轮之间唯一的变量就是任务本身和模型的随机性复盘才有意义。具体要准备三样东西我把它叫「三件套」后面配置里会反复出现第一是 Base URL统一写https://taotoken.net/api。第二是 API Key在控制台生成建议给这次实验单独建一个 Key方便按项目统计用量也方便实验结束后直接吊销。第三是 Model ID这次用的是 doubao-seed-evolving 对应的模型标识你在模型列表里选对应项即可不要手写猜测。如果你用的是 Claude Code 这类命令行 Agent接入方式是把 Base URL 和 Key 写进它的环境变量或配置文件如果你用的是 Cline、Cursor 这类插件通常在设置里填 OpenAI Compatible 的 Base URL 加 Key 加 Model ID。不管哪种三件套缺一不可尤其是 Model ID写错了会直接报模型不存在。这里插一句踩过的坑我第一轮跑 T03 的时候图省事复用了上一个项目的 Key结果那个 Key 绑了额度限制跑到一半请求被限流终端里出现的是超时而不是模型输出。当时差点以为是模型卡住了后来看日志才发现是 Key 的问题。所以实验用的 Key 一定单独建额度留够别和日常项目混用。准备好之后先别急着跑仓库任务。用一次最简单的对话请求验证通道是否通确认返回正常再进入正式任务。这一步花两分钟能省掉后面半小时的排查。验证请求的具体命令和预期返回放在第 4 节讲。3. 可复制配置任务目录、settings 片段与日志采集脚本这一节是全文最干的部分直接给可复制的配置。你照着建目录、填配置、放脚本就能搭出一套和本文一致的实验环境。先建任务目录结构。每个任务一个根目录每轮一个干净工作区互不继承seed-eval/ ├── tasks/ │ ├── T01-flask-blueprint/ │ │ ├── prompt.md │ │ ├── run-01/ │ │ ├── run-02/ │ │ └── run-03/ │ ├── T02-pytest-fixture/ │ └── T03-requests-proxy/ ├── hidden-tests/ │ ├── test_t01_hidden.py │ ├── test_t02_hidden.py │ └── test_t03_hidden.py └── logs/prompt.md里放固定任务描述九轮不改一个字。run-0x/是每轮从干净基线 clone 出来的仓库副本。hidden-tests/放模型看不见的验收用例这是整套实验的关键模型能看见仓库自带测试但看不见这里。接下来是接入配置。如果你用支持 OpenAI Compatible 的客户端配置片段长这样注意路径和字段名按你实际用的工具调整{ provider: openai-compatible, base_url: https://taotoken.net/api, api_key: sk-你的实验专用Key, model: doubao-seed-evolving, temperature: 0.2, max_tokens: 8192 }如果你用的是 Claude Code 这类走 Anthropic 协议的工具配置写在它的 settings 里Base URL 指向 TaoToken 的对应端点Key 和 Model ID 同样填三件套。Cline 或 Cursor 插件则在设置面板里选 OpenAI Compatible把上面三个值填进去。不管哪种base_url必须是https://taotoken.net/api不要多加斜杠或路径。然后是日志采集脚本。这个脚本每轮跑一次把终端输出、补丁、模型对话导出统一归档方便事后对比#!/usr/bin/env bash # collect.sh task_id run_id set -euo pipefail TASK_ID$1 RUN_ID$2 WORKDIRtasks/${TASK_ID}/${RUN_ID} LOGDIRlogs/${TASK_ID}/${RUN_ID} mkdir -p $LOGDIR # 1. 记录环境信息 { echo env python --version uname -a date -u %Y-%m-%dT%H:%M:%SZ } $LOGDIR/env.txt # 2. 跑可见测试并留日志 cd $WORKDIR python -m pytest -q 21 | tee $LOGDIR/visible-tests.log || true # 3. 导出生产代码补丁排除测试目录 git diff -- . :(exclude)tests $LOGDIR/model.patch git diff --stat $LOGDIR/diff-stat.txt # 4. 记录补丁指纹方便对比多轮是否一致 sha256sum $LOGDIR/model.patch | cut -c1-12 $LOGDIR/patch-sha.txt echo collected - $LOGDIR这个脚本有几个设计点值得说。第一git diff排除了tests目录因为模型经常自己补测试评分时要把它的测试还原只带生产代码补丁进私有副本否则它写一个符合自己假设的测试再让自己的实现通过等于自己给自己出题。第二patch-sha.txt只取前 12 位T01 三轮补丁完全一致SHA 前缀都是DE94C19453D1一眼就能看出稳定性。第三|| true是为了让测试失败时脚本继续跑完归档不然set -e会直接中断。隐藏验收的注入脚本单独写思路是复制一份干净仓库应用模型的生产补丁还原测试目录到基线再把你自己的隐藏用例拷进去跑#!/usr/bin/env bash # verify.sh task_id run_id set -euo pipefail TASK_ID$1 RUN_ID$2 SRCtasks/${TASK_ID}/${RUN_ID} VERIFY/tmp/verify-${TASK_ID}-${RUN_ID} rm -rf $VERIFY git clone -q $SRC $VERIFY cd $VERIFY # 应用模型的生产补丁 git apply logs/${TASK_ID}/${RUN_ID}/model.patch # 还原测试目录到基线去掉模型自己加的测试 git checkout -- tests/ # 注入隐藏验收用例 cp hidden-tests/test_${TASK_ID}_hidden.py tests/ # 跑隐藏用例 原有回归 python -m pytest tests/test_${TASK_ID}_hidden.py -q 21 | tee logs/${TASK_ID}/${RUN_ID}/hidden-tests.log python -m pytest -q 21 | tee logs/${TASK_ID}/${RUN_ID}/regression.log这套流程跑下来每轮你会得到四份关键材料可见测试日志、隐藏测试日志、回归日志、生产补丁。T03 的问题就是在这四份材料对比里暴露的——可见测试 216 项全过隐藏测试 0 通过回归全过说明模型没把仓库改坏但也没碰到缺陷位置。4. 验证请求与成功结果从通道连通到 T01/T02 通过配置搭好之后先验证通道。用一条最简单的请求确认 TaoToken 通道正常再进正式任务。命令行方式curl -s https://taotoken.net/api/v1/chat/completions \ -H Authorization: Bearer sk-你的实验专用Key \ -H Content-Type: application/json \ -d { model: doubao-seed-evolving, messages: [{role: user, content: 回复 OK 两个字母即可}], max_tokens: 16 }预期返回是一段 JSONchoices[0].message.content里是OK。如果这里报 401说明 Key 不对或没带上报模型不存在说明 Model ID 写错了报连接失败检查 Base URL 是不是写成了带路径的地址。这一步通了再进仓库任务。正式任务里T01 是最干净的一轮。任务描述是 Flask 的 Blueprint 不能使用空名称。模型三轮都定位到初始化入口在那里拒绝空字符串并补测试。每轮可见测试 60 项通过隐藏行为测试和原有回归也都通过。三轮model.patch不只是思路一样连完整补丁都相同SHA-256 前缀都是DE94C19453D1。这种问题离报错点近、输入边界清楚模型读完相关类很快收敛到合适位置补丁没有绕路也没有为了显得工作量大去动无关代码。T01 还出过一个小插曲值得单独讲。模型新增的公开测试刚好和我准备的隐藏测试重合导致隐藏补丁首次应用失败评分脚本一开始把结果记成失败。但代码其实没错是评测工具撞上了模型写的同名用例。我调整了评分流程保留生产代码恢复测试目录再注入评测方用例重跑后三轮都通过。这个过程很像平时排查 CI——红灯不一定说明业务代码有问题测试基础设施本身也可能出错。既然讲真实测试这段弯路也该写出来。T02 更像我平时遇到的维护问题。pytest 的日志捕获 fixture 会同时改变 logger 和 handler 的 level但清理阶段只恢复了一部分状态。单看当前测试可能没异常等下一条测试运行时前面留下的状态才开始影响结果。三轮里模型都沿着 fixture 的创建和销毁往下查保存 handler 原来的 level再在_finalize()中恢复。首轮和第三轮生产代码相同第二轮有一处语句顺序不同但不改变行为。三轮写出的测试不一样修复思路却一致。T02 让我觉得有意思的地方是「稳定」不一定等于每个字符都一样。实际做代码评审我不会要求两个开发者写出相同补丁只会看他们是否找到了同一个状态泄漏、有没有在正确的生命周期恢复、会不会伤到其他测试。从这个标准看T02 的三次表现是稳定的。这也说明验证 Coding Agent 时别只盯着补丁文本是否一致要看语义是否收敛到同一个根因。到这里通道验证和两个成功任务都跑通了。你可以用同样的目录结构和脚本把 T01、T02 复现一遍确认自己的环境、Key、Model ID 都对得上再进 T03 这种硬骨头。5. 本篇常见错排查401、local proxy failed、reading choices 与 OAuth这一节对照真实报错讲排查。这些错误我在 9 轮实验里基本都撞过一遍按出现频率排。401 Unauthorized。最常见原因就三类Key 没带、Key 写错、Key 被吊销或额度耗尽。先确认请求头里Authorization: Bearer sk-xxx格式正确注意 Bearer 后面有一个空格。如果格式没问题去控制台看这个 Key 的状态和余额。我前面提到的限流问题表现有时是 401 有时是 429看具体实现。实验用的 Key 单独建别和日常项目混用这是最省事的做法。local proxy failed / connection refused。这个报错通常不是 TaoToken 的问题而是你本地客户端配置了额外的网络层或者 Base URL 写错了。检查两点Base URL 是不是https://taotoken.net/api有没有多写路径或端口本地有没有残留的代理环境变量比如HTTP_PROXY、HTTPS_PROXY。在终端里unset HTTP_PROXY HTTPS_PROXY再试一次很多时候就好了。注意这里说的是清理本地环境变量不是让你去搞什么网络工具纯粹是排除配置干扰。Error reading choices / choices 字段为空。这个报错说明请求发出去了返回结构里没有choices。常见原因是 Model ID 写错服务端返回了一个错误对象而不是正常补全结果也可能是max_tokens设得太小返回被截断。先打印完整返回体看error字段再核对 Model ID 是否和模型列表里一致。三件套里 Model ID 最容易手写出错复制粘贴别手打。OAuth 相关报错。如果你用的是 Claude Code 这类走 OAuth 流程的工具报 OAuth 失败通常是登录态过期或配置里同时存在两套鉴权。处理方式是清掉旧的凭据缓存重新用 Key 方式配置Base URL 指向 TaoTokenKey 和 Model ID 填三件套。别让工具同时走 OAuth 和 Key 两条路会互相打架。测试全绿但隐藏用例失败。这不是报错但它是本文最想让你警惕的「静默失败」。排查动作是把模型的生产补丁单独拿出来还原测试目录注入你自己的隐藏用例。如果隐藏用例失败而可见测试全过说明模型的根因判断偏了。T03 就是这样三轮都定位到get_auth_from_url()但真正的问题在更前面的 URL 重建环节——认证信息在到达那个函数之前就已经丢了。输入本来是http://user:passexample.com/path?query经过重建函数后变成http://example.com/path?queryuser:password没被放回 netloc。后面把解析函数改得再稳也解决不了前面丢数据的问题。遇到这类静默失败多问一句数据从哪里进入中间经过哪些转换在哪个位置产生副作用如果只测某个局部函数很可能漏掉这种「数据在到达函数前已经丢了」的情况。这也是为什么我坚持隐藏用例要从用户真正走的路径开始而不是从模型认定的根因函数开始。6. 语义一致 CTA把 Seed-Evolving 接进你的验证流程九轮跑完我对 Seed-Evolving 的判断很具体它能独立阅读陌生代码、搜索调用关系、修改文件、补测试、跑回归。在边界清楚的 T01、T02 里它不只是给建议而是真的接住并完成了工程任务。但 T03 同样重要——216 项可见测试全过真实故障没消失。模型越强一份结构完整、解释充分、测试全绿的错误答案就越容易被相信。所以不管面对 Seed-Evolving 还是其他模型别把第一次输出直接当交付。让它说明根因、梳理数据链路、补一条真正经过用户路径的测试生产代码和模型新增测试分开检查重要修改放到干净上下文里复跑最后用模型看不见的用例验收。这些约束不是限制模型而是把它已经很强的能力引向正确结果。如果你想自己复现这套对照实验接入通道统一用 TaoToken 最省事。生成实验专用 Key 走 API Keys 页面https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 接入方式和参数说明看文档https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 想先手动验证模型对话行为用模型对话页面https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 如果你要把这类 Agent 长期接进编码流程、跑多轮任务Coding Plan 更合适https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。最后留一句我复盘时写在笔记里的话别只问它跑过了多少测试还要问这些测试有没有走过用户真正走的那条路。代码写出来不算测试变绿也不一定算用户遇到的那个问题消失了、原有功能没被破坏这件事才算交付。