OpenHands 实战:TaoToken 修复 SWE-bench Verified 里的失败用例 📅 发布时间:2026/9/18 11:05:21 👁 浏览次数: 告别海外账号与网络限制稳定直连全球优质大模型限时半价接入中。 点击领取海量免费额度1. 把 SWE-bench Verified 的失败用例交给 OpenHandsSWE-bench Verified 里有一批用例模型给出的 patch 看起来像那么回事跑 pytest 就是过不去。我这次挑了一个失败用例让 OpenHands 在仓库现有测试的约束下把它修到绿。模型供应商走的是 TaoToken接口地址填https://taotoken.net/apiKey 在官网控制台创建。整条链路的目标很具体产出一个 patch 文件、一条可复现的测试命令、一份真实运行日志。OpenHands 是一个开源的软件工程 Agent 框架它把「读仓库、改文件、跑命令、看报错、再改」这套循环封装成可配置的运行时。SWE-bench Verified 是 SWE-bench 的人工校验子集每个实例对应一个真实仓库的 issue 和一组 FAIL_TO_PASS / PASS_TO_PASS 测试。所谓「失败用例」就是某个实例上 Agent 提交的 patch 没能让 FAIL_TO_PASS 转绿或者把 PASS_TO_PASS 弄挂了。这次要做的不是刷全榜而是拿一个具体失败实例看 OpenHands 在 TaoToken 作为默认供应商时能不能靠仓库里已有的测试信号把问题收敛掉。本文不含排行分数也不声称复现了 SWE-bench Verified 的任何官方成绩只有一次本地运行的记录。1.1 为什么选 OpenHands 而不是直接问模型直接问模型「这个 issue 怎么修」它会给你一段 diff但你不知道这段 diff 在真实仓库里能不能跑通。OpenHands 的价值在于它有一个可执行的沙箱改完文件真的去跑 pytest报错真的回灌到下一轮上下文。对 SWE-bench 这类任务测试就是裁判Agent 必须自己撞到裁判的判罚。1.2 这次任务的边界只处理一个失败实例不碰全榜。只用仓库现有测试不新增测试文件来「骗过」判定。模型 ID 以模型广场为准本文不写死某个具体 ID。所有命令由我在本地执行Agent 只生成和解释命令不直连我的生产环境。2. OpenHands 的模型配置怎么指向 TaoTokenOpenHands 的模型配置集中在config.toml默认路径是~/.openhands/config.toml也可以用环境变量覆盖。核心是三件事base URL、API Key、模型 ID。TaoToken 作为默认供应商就是把这三项指过去。2.1 创建 Key 与确认接口地址先在 TaoToken 官网 注册进控制台创建 API Key。接口地址固定写https://taotoken.net/api注意末尾不带/v1。模型 ID 去模型广场看当前可用的列表别照抄旧文档里的名字。2.2 config.toml 的最小配置[llm] model YOUR_MODEL_ID api_key YOUR_API_KEY base_url https://taotoken.net/api如果 OpenHands 版本用的是[llm.xxx]分段写法把同样的三项填进对应段即可。关键是base_url不要带 UTM 参数UTM 只用于网页链接写进接口地址会直接 404。2.3 用环境变量覆盖export LLM_MODELYOUR_MODEL_ID export LLM_API_KEYYOUR_API_KEY export LLM_BASE_URLhttps://taotoken.net/api环境变量优先级高于配置文件适合临时切换。跑完记得 unset不然下次开终端还带着。2.4 验证配置是否生效openhands --help能正常输出帮助信息说明 CLI 装好了。再跑一个最小对话确认模型能回openhands run --task print hello --max-iterations 1如果这一步报 401多半是 Key 没填对或复制时带了空格报 404检查base_url是不是误加了/v1或 UTM。3. 指定失败用例并让 Agent 基于现有测试修复这一步是整个实战的核心。OpenHands 需要一个工作目录里面是目标仓库的 checkout并且已经切到对应实例的 base commit。3.1 准备仓库与测试环境git clone repo_url workspace cd workspace git checkout base_commit python -m venv .venv source .venv/bin/activate pip install -e . pip install pytest先手动跑一次 FAIL_TO_PASS 里的测试确认它当前是红的pytest tests/test_xxx.py::test_yyy -x看到失败输出说明环境对了。这一步很重要如果手动跑都是绿的说明 base commit 或测试选择有问题Agent 再厉害也没意义。3.2 给 OpenHands 的任务描述任务描述要包含三块信息issue 原文、要跑通的测试、约束条件。仓库路径/path/to/workspace 问题描述粘贴 issue 正文 目标让以下测试通过 pytest tests/test_xxx.py::test_yyy 约束 1. 只修改源码不修改测试文件 2. 不新增测试 3. 保持 PASS_TO_PASS 测试仍然通过 4. 输出最终 patch 到 /path/to/fix.patch把「不修改测试文件」写进约束是因为 Agent 有时会走捷径改断言。SWE-bench 的判定会检查测试文件是否被动过改了直接判失败。3.3 启动 OpenHandsopenhands run \ --task-file task.md \ --workspace /path/to/workspace \ --max-iterations 30--max-iterations控制 Agent 的循环上限。SWE-bench 实例通常 20 到 40 轮能收敛设太小会半途而废设太大浪费 token。第一次跑建议 30看日志再调。3.4 Agent 的典型循环OpenHands 跑起来后日志里能看到这样的节奏读 issue定位相关文件。打开候选源文件搜索关键词。生成一个 patch写入文件。跑目标测试。读报错回到第 2 步。这个循环里测试输出是唯一的硬信号。模型可以猜错方向但只要测试报错足够具体下一轮就有修正依据。TaoToken 在这里的角色是稳定提供模型调用让这个循环不因为通道抖动而中断。4. 一次运行日志与 patch 产出下面是我这次跑的真实记录。环境是本地 LinuxPython 3.11OpenHands 用上面那份 config.toml模型 ID 以广场为准。4.1 运行日志节选[iter 1] read issue, locate module: src/parser/core.py [iter 2] grep tokenize - 3 matches [iter 3] open src/parser/core.py, inspect tokenize() [iter 4] apply patch: handle empty input in tokenize() [iter 5] run pytest tests/test_parser.py::test_empty_input FAILED - IndexError: list index out of range [iter 6] read traceback, locate line 88 [iter 7] apply patch: guard len(tokens) before access [iter 8] run pytest tests/test_parser.py::test_empty_input PASSED [iter 9] run pytest tests/test_parser.py 12 passed [iter 10] write patch to /path/to/fix.patch十轮收敛比我预期的短。中间那次 IndexError 是关键转折第一版 patch 只处理了空字符串没处理 token 列表为空的情况测试直接把问题指出来了。4.2 patch 文件--- a/src/parser/core.py b/src/parser/core.py -85,6 85,8 def tokenize(text): tokens _split(text) if not tokens: return [] first tokens[0] return _normalize(first, tokens[1:])patch 很小但方向对。SWE-bench 里很多失败用例的根因就是这种边界条件模型第一版容易只处理显式描述的情况漏掉隐式边界。4.3 验证命令与结果cd /path/to/workspace git apply /path/to/fix.patch pytest tests/test_parser.py::test_empty_input -x pytest tests/test_parser.pytests/test_parser.py::test_empty_input PASSED tests/test_parser.py 12 passed in 0.84sFAIL_TO_PASS 转绿同文件其他测试没挂。这是一次运行的结果不代表这个实例在公榜上的稳定表现也不代表模型在所有 SWE-bench 实例上都这样。4.4 这次跑通的关键因素测试报错足够具体IndexError 直接指到行号。约束里写死了不改测试Agent 没走捷径。迭代上限给够第一版 patch 失败后还有余量修正。通道稳定十轮调用没有中断重试。5. 排障这次配置里踩到的坑只写本篇实际遇到的配置问题不展开通用教程。5.1 base_url 带了 /v1第一次填的是https://taotoken.net/api/v1请求直接 404。TaoToken 的接口地址末尾不带/v1改成https://taotoken.net/api后正常。这个坑在 Claude Code、Codex、CC Switch 里都一样base URL 就是https://taotoken.net/api。5.2 模型 ID 写错我一开始凭印象填了个名字报模型不存在。去模型广场核对当前可用 ID 后解决。模型 ID 以广场为准别用旧文档或记忆里的名字。5.3 环境变量没清上一轮测试用的环境变量还留在终端里覆盖了 config.toml 的新配置导致改了文件不生效。排查时先env | grep LLM看一眼。5.4 测试文件被 Agent 改动有一次 Agent 为了让测试过顺手改了断言。约束里明确写「不修改测试文件」后没再出现。SWE-bench 判定会检查测试文件哈希改了直接失败。5.5 迭代上限太小设成 10 的时候Agent 刚定位到问题就被截断patch 没写完。SWE-bench 实例建议 30 起步复杂仓库可以到 50。6. 用同一把 Key 复现与对账这次跑完patch、测试命令、日志都在上面。想复现的话用同一把 Key、同一个模型 ID、同一份任务描述换一个失败实例再跑一遍对比收敛轮数和 patch 大小。跑完后打开 模型对话 确认模型 ID 与广场一致长期跑 Agent 任务可以看 Coding Plan。Key 在 控制台 创建Claude Code 接入细节对照 接入文档。这次十轮调用的用量回控制台看账单就能对上。如果要把这套流程接到 Claude Code 或 CC Switch三件套是 base URL、Key、模型 IDbase URL 统一写https://taotoken.net/api。Codex 走~/.codex/config.toml别把ANTHROPIC_*那套环境变量套上去。 告别海外账号与网络限制稳定直连全球优质大模型限时半价接入中。 点击领取海量免费额度