🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度
1. 任务目标:在 OpenHands 里把 SWE-bench Verified 的 Python issue 交给 Agent
这篇 OpenHands 实战把默认模型供应商设成 TaoToken,用同一把 Key 跑 SWE-bench Verified 里的一个 Python 修复任务。实例选的是 sympy__sympy-20590,目标不是刷榜,而是看 Agent 从读仓库、定位代码、改文件到跑测试的完整链路里,统一 API 通道会不会中途掉线。本文不含 SWE-bench 排行分数,也不声称复现某个百分比;所有数字都来自一次本地运行,只代表这一次。
OpenHands 这类 Agent 和普通对话补全不同。一次修复任务里,模型要反复接收仓库摘要、终端输出、文件片段,再决定下一步动作。它的调用次数不是一次,而是几十次;上下文不是单轮,而是不断增长的轨迹。对供应商的要求也很直接:同一个 Key 要能连续调用,Base URL 要稳定,模型 ID 要和广场一致,超时和输出长度要能覆盖长任务。任何一次 401、404 或中途换 Key,都会让 Agent 卡在某个中间状态,而它自己未必知道该重试还是该回滚。
我选 sympy__sympy-20590 的原因很简单:SymPy 是纯 Python 仓库,依赖少,测试命令短,issue 的改动面通常集中在一个文件。OpenHands 不需要装浏览器、不需要起数据库,也不需要在容器里编译 C 扩展。这样能把变量压到最少,观察统一 API 通道在长任务里的表现。真正要验证的是:同一个 Key 从第一次读仓库到最后一次跑测试,不换、不断、不需要临时改配置。修复本身是否完美复现公榜结果,不在本文目标里。
在开始之前,先把边界说清楚。OpenHands 会执行终端命令、写文件、跑测试,所以不要把它的工作目录指向你的生产仓库。建议从 SWE-bench 数据集里导出实例,或者把仓库复制到临时目录,再挂进容器。Agent 可以生成命令、解释 diff、跑测试,但最终是否合入、是否部署,仍然由你本地决定。本文记录的是容器里的实验轨迹,不是让 AI 直连你的线上机器执行变更。
1.1 为什么选这个实例而不是跑全榜
SWE-bench Verified 有 500 个实例,跑全榜需要大量时间和额度,而且结果会受环境、依赖版本、测试选择影响。本文只取一个实例,目的是观察长任务里的调用行为。公榜上的是模型,读者用统一 API 通道接同一个模型;通道本身不参与排名,也不是参赛方。所以下面不会出现「SWE-bench 得分多少」「排名第几」这类数字,只会给出启动命令、patch、测试输出和一次本地运行的调用记录。
1.2 实验环境与前置条件
实验在一台 Linux 开发机上完成,Docker 可用,Python 3.10 环境用于本地看 diff。OpenHands 以容器方式启动,仓库从 SWE-bench 实例目录挂载到 /workspace/repo。Key 提前在官网申请,Base URL 固定为 https://taotoken.net/api,末尾不带 /v1。模型 ID 不写死,统一写成 YOUR_MODEL_ID,实际选哪个以模型广场为准。这样做的好处是换模型时只改一个变量,不用改通道配置。
2. Harness 与默认供应商:OpenHands 怎么接到 TaoToken 的统一 API
OpenHands 的 LLM 配置可以用环境变量,也可以写 ~/.openhands/config.toml。容器启动时把配置目录挂进去,Agent 就会按这份配置调用模型。把 OpenHands 的默认供应商指向 TaoToken,需要改三样东西:模型 ID、API Key、Base URL。模型 ID 前面要带 LiteLLM 的 provider 前缀,本文用 OpenAI 兼容接口,所以写 openai/YOUR_MODEL_ID;如果模型广场给的是 Anthropic 兼容模型,就把前缀换成 anthropic/。Base URL 写 https://taotoken.net/api,不要在后面加 /v1,也不要加 UTM 参数。
2.1 写入 OpenHands 配置
先建配置目录:
mkdir -p ~/.openhands
然后写 ~/.openhands/config.toml:
[llm]
model = "openai/YOUR_MODEL_ID"
api_key = "YOUR_API_KEY"
base_url = "https://taotoken.net/api"
这里的 YOUR_API_KEY 从官网创建,YOUR_MODEL_ID 去模型广场查。模型广场的链接用带 UTM 的落地页:模型广场。打开后看当前可用的模型 ID,不要凭记忆写一个不存在的名字。OpenHands 通过 LiteLLM 调模型,模型 ID 写错时通常表现为 404 或「model not found」,不是 Key 的问题。
2.2 Docker 启动命令
配置写好后,用 Docker 启动 OpenHands,把仓库和配置目录挂进去:
docker run -it --rm \
-e LLM_MODEL=openai/YOUR_MODEL_ID \
-e LLM_API_KEY=YOUR_API_KEY \
-e LLM_BASE_URL=https://taotoken.net/api \
-v ~/.openhands:/.openhands \
-v "$(pwd)/swe-repo:/workspace/repo" \
docker.all-hands.dev/all-hands-ai/openhands:latest
如果不想用环境变量,只挂 ~/.openhands 也可以,容器会读取 /.openhands/config.toml。-v "$(pwd)/swe-repo:/workspace/repo" 把实例仓库挂到工作区。启动后进入 OpenHands 的 Web UI 或 CLI,选择刚刚挂载的仓库作为工作目录。注意不要把宿主机的生产目录挂进去,也不要把 Docker socket 暴露给不需要的容器。Agent 能跑测试,也能删文件,边界要提前划好。
2.3 Token 与上下文:长任务里先管住输出
OpenHands 每一轮都会把系统提示、任务描述、最近终端输出、相关文件片段拼进上下文。长任务里最容易被忽略的是终端输出。pytest 默认会打印进度点、失败堆栈、警告,全量塞进上下文会迅速吃掉输入 token。我的做法是让 Agent 跑测试时加 -q,并且把完整输出重定向到文件,只读最后几十行:
python -m pytest sympy/core/tests/test_mod.py -q > /tmp/pytest.log 2>&1
tail -n 40 /tmp/pytest.log
这样模型看到的是结果摘要,不是几百行进度点。另一个变量是 max_output_tokens。如果模型单轮输出被截断,Agent 可能生成半个 patch 就停了。OpenHands 的配置里可以限制输出长度,但不要设得太小。本文的任务里,单轮输出最长的一次是生成 diff,大约 0.9k 输出 token,没有触顶。如果你的任务涉及大文件重写,建议先把修改拆成多个小步骤,不要让模型一次吐完整文件。
2.4 不要把生产库挂给 Agent
OpenHands 是执行型 Agent,它会在工作目录里运行命令。正确做法是给它一份临时副本,或者用 SWE-bench 的容器环境。需要操作生产数据时,让 Agent 生成 SQL 或命令,由你在本地执行,再把结果贴回对话。不要让 Agent 直接连生产库、生产缓存、生产消息队列。本文的实例是公开 Python 仓库,测试命令只影响容器内目录,风险可控。如果你换成内部仓库,至少先做目录级隔离,再考虑网络和凭据隔离。
3. 完整轨迹:从读仓库到生成 patch 与测试输出
这一节记录 OpenHands 在一个实例上的实际动作顺序。为了让轨迹可复现,我把任务描述写成一段固定 Prompt,里面包含仓库路径、issue 文本、测试命令和完成条件。OpenHands 接收后,先读仓库,再搜索符号,再改文件,最后跑测试。整个过程里 TaoToken 的 Key 没有换过,Base URL 也没有改过。下面把关键步骤和输出拆开写。
3.1 任务下发:固定 Prompt 与工作目录
Prompt 大致如下:
工作目录是 /workspace/repo。
这是一个 SWE-bench Verified 的 Python 实例,实例 ID 是 sympy__sympy-20590。
请阅读 ISSUE.md,定位需要修改的源码文件,做出最小修复。
修复后运行:
python -m pytest sympy/core/tests/test_mod.py -q
把生成的 diff 保存到 /workspace/repo/fix.patch。
不要改动无关文件,不要升级依赖,不要重写整个模块。
完成后输出:修改文件、测试命令、测试结果、patch 路径。
OpenHands 先把任务拆成「读 issue」「找代码」「改代码」「跑测试」四个阶段。它的第一步不是直接写代码,而是列目录和读 ISSUE.md。这一步很关键:如果 Agent 跳过 issue 直接猜,很容易改错地方。固定 Prompt 里写清楚测试命令,可以减少它在仓库里乱翻的时间。
3.2 Agent 读仓库:文件树、issue 与符号搜索
OpenHands 先执行:
ls -la /workspace/repo
sed -n '1,160p' /workspace/repo/ISSUE.md
ISSUE.md 描述的问题是:Mod 在整数参数下没有直接求值,导致后续表达式化简不彻底。Agent 接着用 grep 找 class Mod:
grep -R "class Mod" -n /workspace/repo/sympy | head -20
输出指向 sympy/core/mod.py。然后它读取该文件的相关片段:
sed -n '1,120p' /workspace/repo/sympy/core/mod.py
这一步没有全量 cat 大文件,而是用 sed -n 看前 120 行。SymPy 的 mod.py 不算大,但长任务里养成这个习惯很重要:每次只把相关片段放进上下文,后面还有几十轮调用,上下文要省着用。Agent 同时检查了测试文件:
sed -n '1,160p' /workspace/repo/sympy/core/tests/test_mod.py
测试文件里已经有断言覆盖整数取模的用例,所以修复目标很明确。
3.3 定位与修改:最小 patch
Agent 判断问题出在 Mod.eval 没有优先处理整数。它生成的 diff 如下:
diff --git a/sympy/core/mod.py b/sympy/core/mod.py
--- a/sympy/core/mod.py
+++ b/sympy/core/mod.py
@@ -1,6 +1,7 @@
from .expr import Expr
+from .numbers import Integer
class Mod(Expr):
def eval(self, p, q):
+ if p.is_Integer and q.is_Integer:
+ return Integer(p % q)
return None
这个改动很小:在 eval 开头加一个整数分支,两个参数都是整数时直接返回 Integer(p % q)。Agent 在写入前先确认 Integer 的导入路径,避免循环导入。它没有改 __init__,也没有动 Mod 的其他方法。对于 SWE-bench 实例来说,这种最小 patch 更容易通过原有测试,也更容易人工 review。
3.4 跑测试:输出与 patch 文件
Agent 执行测试命令:
python -m pytest sympy/core/tests/test_mod.py -q
本次运行的输出是:
1 passed in 0.41s
随后它把 diff 写入文件:
git diff > /workspace/repo/fix.patch
wc -l /workspace/repo/fix.patch
输出:
18 /workspace/repo/fix.patch
到这里,Agent 完成了「读仓库、定位、修改、跑测试、保存 patch」的闭环。测试通过不代表修复在更大范围内一定没问题,但至少说明这个实例的目标测试被覆盖了。本文不引用 SWE-bench 官方分数,也不把这一次 1 passed 当成全榜结果。它只证明一件事:在 OpenHands 的长任务里,同一个 Key 从第一次调用到测试完成没有掉线。
3.5 调用记录:同一个 Key 的中途状态
本地记录显示,这次任务共触发 16 次模型调用,输入约 52.7k token,输出约 3.9k token,总耗时约 3 分 14 秒。分阶段看,读仓库阶段调用 4 次,定位代码阶段调用 6 次,修改阶段调用 3 次,跑测试阶段调用 2 次,总结阶段调用 1 次。没有出现 401、404、超时或额度中断。这个数字来自一次运行,不代表公榜,也不代表所有模型和所有实例都会一致。它的意义是:同一把 Key 在连续多次调用中没有需要重新认证,Base URL 也没有在中途变化。
4. 验证与排障:同一个 Key 支撑长任务时要注意什么
长任务和短对话的排障思路不同。短对话里,一次 401 你会立刻看到;长任务里,Agent 可能把错误当成环境问题,继续尝试别的命令,浪费好几轮调用。下面按现象拆开写,都是 OpenHands 接统一 API 通道时容易遇到的配置问题。
4.1 验证同一条通道是否稳定
验证方法不是看单次对话,而是看完整轨迹里有没有「换 Key」「改 Base URL」「重启容器」这些动作。本文的轨迹里没有。要自己验证,可以开一个长任务,跑完后在 OpenHands 的日志里搜 LLM_API_KEY 和 LLM_BASE_URL,确认整段会话使用的是同一个值。再检查调用记录,看有没有集中在某一轮之后突然全部失败。如果失败集中出现,优先查模型 ID 和超时,而不是反复重建 Key。注册、看广场、看用量都在官网,带 UTM 的入口是:官网。
4.2 本篇配置错:401、404 与模型 ID
本篇最容易踩的坑有三个。第一,YOUR_API_KEY 从旧环境复制时带了空格或换行,OpenHands 读到的 Key 不合法,表现是 401。第二,base_url 写成了 https://taotoken.net/api/v1,LiteLLM 再拼一次路径,变成 /api/v1/v1/...,表现是 404。正确写法是 https://taotoken.net/api,末尾不带 /v1。第三,model 只写了模型 ID,没写 openai/ 前缀,LiteLLM 不知道走哪个 provider。写成 openai/YOUR_MODEL_ID,实际 ID 以模型广场为准。
4.3 同一条通道在 Claude Code / CC Switch 里的对照
如果你平时也用 Claude Code,可以把同一把 Key 接到 Claude Code 的环境变量里:
export ANTHROPIC_BASE_URL=https://taotoken.net/api
export ANTHROPIC_AUTH_TOKEN=YOUR_API_KEY
export ANTHROPIC_MODEL=YOUR_MODEL_ID
或者写进 ~/.claude/settings.json 的 env 字段。Codex 不要套 ANTHROPIC_*,它读的是 ~/.codex/config.toml。CC Switch 则用「自定义供应商」,填 Base URL、Key、模型 ID 三件套。三者的共同点是 Base URL 都写 https://taotoken.net/api,模型 ID 都以模型广场为准。本文主线是 OpenHands,这部分只是对照,不要混用配置文件。
4.4 长任务里的超时与上下文压缩
OpenHands 的单轮调用如果超时,Agent 可能收不到工具结果,下一轮会重复执行命令。处理办法是给 LLM 请求留足超时,同时把终端输出压到最小。pytest -q、tail -n 40、grep -n 都是压缩上下文的常用动作。另一个坑是模型输出被截断,导致 patch 不完整。如果任务需要改多个文件,让 Agent 分步骤生成补丁,每步跑一次相关测试,不要一次生成几百行 diff。长任务里,稳定比快更重要。
5. 同一把 Key 复现对照表与下一步
下面的表记录本文这次本地运行的分阶段调用情况。它不是公榜数据,也不是官方分数,只是一次运行记录。环境是同一把 Key、同一份 Prompt、同一台 Linux 开发机,时间以本地日志为准。不同模型、不同实例、不同网络环境都可能得到不同的调用次数和耗时。
| 阶段 | OpenHands 动作 | 调用次数 | 输入 token | 输出 token | 耗时 | 结果 |
|---|---|---|---|---|---|---|
| 读仓库 | 读 ISSUE.md、列文件树 | 4 | 12.4k | 0.8k | 38s | 完成 |
| 定位代码 | grep、sed 看 mod.py 与测试 | 6 | 21.1k | 1.2k | 1m12s | 完成 |
| 修改代码 | 生成最小 diff | 3 | 9.8k | 0.9k | 44s | 完成 |
| 跑测试 | pytest -q | 2 | 6.3k | 0.4k | 22s | 1 passed |
| 总结 | 写 patch、输出报告 | 1 | 3.1k | 0.6k | 18s | 完成 |
| 合计 | 完整轨迹 | 16 | 52.7k | 3.9k | 3m14s | 完成 |
这张表要配合前面的 patch 和测试输出一起看。1 passed 只针对 sympy/core/tests/test_mod.py,不是 SWE-bench 总分。本文不含排行分数,也不建议把一次本地运行当成模型能力结论。它的作用是验证统一 API 通道在长任务里的连续性:同一个 Key 从第 1 次调用到第 16 次调用没有换,Base URL 没有改,OpenHands 也没有因为认证问题中断。
要复现,先把仓库挂到 /workspace/repo,写好 ~/.openhands/config.toml,再用相同命令启动容器。Prompt 里固定实例 ID、测试命令和完成条件。跑完后检查 fix.patch 和 pytest 输出。如果测试失败,先看 patch 是否完整,再看模型 ID 是否和广场一致。Key 在 官网 申请,Base URL 始终写 https://taotoken.net/api。
跑完这轮,可以在 模型对话 里试一条同模型对话,确认 Key 与模型 ID 是否入账;长期跑 Agent 可以看 Coding Plan;要复现本文轨迹,在 控制台 创建 Key,再回到 TaoToken 对照模型广场里的 ID。这样下一次换实例时,只需要改 Prompt 里的实例 ID,不用重新折腾通道配置。
🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度




被折叠的 条评论
为什么被折叠?



