OpenHands 实战:TaoToken 跑通一个小型 Flask 仓库的依赖升级与 pytest

发布时间:2026/9/18 16:31:19
OpenHands 实战:TaoToken 跑通一个小型 Flask 仓库的依赖升级与 pytest 告别海外账号与网络限制稳定直连全球优质大模型限时半价接入中。 点击领取海量免费额度1. 为什么挑 OpenHands 做这次依赖升级OpenHands 是一个把「写代码、跑命令、看报错、再改」串成闭环的开源 Agent 运行时。它和只会在编辑器里补全的助手不一样你给它一个仓库路径和一句任务描述它会自己开 shell、装依赖、跑测试失败后读 traceback 再改。这种「能执行、能观察、能重试」的特性正好适合做一类很烦但很典型的活——把老仓库里的requests换成httpx同时补齐 pytest 用例。我这次选的靶子是一个开源小型 Flask 仓库结构简单一个app.py暴露两三个 REST 接口一个services/目录里封装了对外部 HTTP 服务的调用测试目录里只有零散几个用例。任务目标写得很具体把services/下所有requests.get/post替换成httpx的等价调用补上超时与异常处理再为每个接口补 pytest 用例最后要求pytest -q全绿。要让 OpenHands 真正跑起来绕不开一个配置问题它的 LLM 后端默认指向哪。这一步我把默认供应商设成 TaoTokenKey 在 TaoToken 创建Base URL 写https://taotoken.net/api。下面把 docker run 命令、config.toml 关键字段、以及 Agent 每一步的 Token 累计和卡住重试点都摊开讲。2. OpenHands 的 LLM 配置把默认供应商指向 TaoTokenOpenHands 的配置分两层一层是运行时容器怎么起一层是 Agent 用哪个模型、走哪个 endpoint。很多人卡在第二层因为 OpenHands 的配置项名字和 Claude Code、Codex 都不一样套错就会 401 或 404。2.1 docker run 起运行时OpenHands 官方推荐用容器跑因为 Agent 需要在隔离环境里执行命令。下面这条命令把工作目录挂进去并把端口暴露出来docker run -it --rm \ --name openhands-flask-upgrade \ -p 3000:3000 \ -v /Users/me/repos/flask-mini:/workspace/flask-mini \ -v /Users/me/.openhands:/root/.openhands \ -e SANDBOX_RUNTIME_CONTAINER_IMAGEdocker.all-hands.dev/all-hands-ai/runtime:0.20-nikolaik \ -e LOG_ALL_EVENTStrue \ docker.all-hands.dev/all-hands-ai/openhands:0.20几个点值得说清楚。-v把本地仓库挂到容器里的/workspace/flask-miniAgent 改的就是你本地这份代码不是容器里的一次性副本。第二个-v把~/.openhands挂出来配置和会话记录才不会随容器销毁。SANDBOX_RUNTIME_CONTAINER_IMAGE指定 Agent 执行命令用的沙箱镜像版本要和主镜像对齐否则会出现「Agent 能对话但跑不了命令」的怪状态。2.2 config.toml 关键字段OpenHands 读~/.openhands/config.toml。把默认供应商设成 TaoToken核心就这几行[core] workspace_base /workspace max_iterations 60 runtime docker [llm] model YOUR_MODEL_ID api_key YOUR_API_KEY base_url https://taotoken.net/api custom_llm_provider openai temperature 0.2 max_output_tokens 4096model填什么以模型广场为准不要凭记忆写一个不存在的 ID。base_url就是https://taotoken.net/api末尾不带/v1OpenHands 会自己拼路径。custom_llm_provider设成openai是因为 TaoToken 走的是 OpenAI 兼容协议OpenHands 用这个 provider 名去构造请求。max_iterations我设 60因为依赖替换加补测试这种任务Agent 会反复跑 pytest迭代次数给少了会在中途被截断。Key 从 TaoToken 控制台 创建创建时选好模型权限。如果你同时用 Claude Code那边的三件套是ANTHROPIC_BASE_URL、ANTHROPIC_AUTH_TOKEN、ANTHROPIC_MODEL或者写进~/.claude/settings.json的env段Codex 走~/.codex/config.toml不要把ANTHROPIC_*套到 Codex 上。OpenHands 这套[llm]字段和它们都不通用这是最容易踩的坑。2.3 验证配置是否生效起容器后先在 OpenHands 界面里发一句「列出当前工作目录的文件」看它能不能正常返回。如果返回 401多半是 Key 没填对或权限不匹配如果返回 404检查base_url是不是被误加了/v1。这一步过了再进正式任务。3. 让 Agent 把 requests 换成 httpx 并补 pytest任务描述我写得比较克制没有把每一步都写死留出 Agent 自己探索的空间仓库在 /workspace/flask-mini。任务 1. 把 services/ 目录下所有 requests 调用替换成 httpx保留原有函数签名。 2. 为每个 HTTP 调用补上 timeout 和异常处理。 3. 在 tests/ 下为每个 Flask 接口补 pytest 用例覆盖成功和超时两种路径。 4. 跑 pytest -q确保全部通过。 不要改动 app.py 的路由定义。3.1 Agent 的执行轨迹与 Token 累计下面这张表是我这次运行的逐步记录。Token 数是 OpenHands 界面里显示的累计值不是估算步骤Agent 动作累计 Token是否卡住重试点1列目录、读 services/ 下三个文件4.2k否-2生成 httpx 替换补丁写入文件11.8k否-3跑 pytest报 ImportError: httpx14.1k是装依赖4pip install httpx重跑 pytest18.6k否-5两个用例失败读 traceback24.3k是改异常分支6修正超时异常类型重跑29.7k否-7补 tests/test_api.py 三个用例38.4k否-8全量 pytest -q全绿41.2k否-第 3 步的卡住很典型Agent 改了代码但没意识到环境里没装 httpx。它的第一反应是重跑测试看到 ImportError 后才去装依赖。这里如果max_iterations设得太小Agent 可能在装依赖前就被截断。第 5 步的卡住更值得说它一开始把httpx.TimeoutException写成了httpx.Timeout测试里 mock 的超时路径没被捕获traceback 指向异常类型不匹配。Agent 读了报错后自己改对了。3.2 卡住重试点清单把这次运行里所有需要人工介入或 Agent 自我纠正的点列出来方便你复现时对照依赖缺失Agent 改完代码直接跑测试遇到 ImportError 才装包。可以在任务描述里加一句「先确认依赖已安装」省一轮迭代。异常类型写错httpx的超时异常是httpx.TimeoutException不是httpx.Timeout。Agent 第一次写错靠 traceback 纠正。mock 路径不对补测试时 Agent 一开始 mock 了requests.get但代码已经换成 httpxmock 目标要改成httpx.Client.get。测试隔离两个用例共享了同一个 Flask test client状态串了。Agent 第二次迭代才改成每个用例独立 fixture。超时参数单位httpx的timeout单位是秒Agent 一开始按毫秒填了 5000测试跑得极慢后来改成 5。这五个点里前两个是环境与 API 细节后三个是测试写法。它们都不是「模型不够聪明」而是 Agent 在真实仓库里必然遇到的摩擦。OpenHands 的价值就在于它能自己读报错、自己重试你只需要在配置里把迭代次数和超时留够。3.3 最终交付的改动跑完后git diff显示services/下三个文件共 14 处requests调用被替换新增tests/test_api.py含 6 个用例requirements.txt里requests换成httpx。pytest -q输出6 passed。这份改动可以直接提 PR。4. 用同一把 Key 复现与对账这次运行全程用同一把 Key、同一个模型 ID、同一个 Base URL。如果你想复现步骤是在 TaoToken 创建 Key把config.toml里的api_key、base_url、model三行改成你的值起容器贴任务描述然后对照上面的 Token 累计表看每一步消耗。需要说明的是上面那张 Token 表是一次运行的结果不代表任何公榜分数。它只说明这个任务在 OpenHands 里大概要花多少上下文。不同模型、不同仓库规模数字会差很多。跑完后可以打开 模型对话 确认这次调用是否入账模型 ID 是否和广场一致。长期做这类 Agent 任务可以看 Coding PlanKey 在 控制台 创建Claude Code 接入的三件套对照 接入文档。5. 这次配置里最容易错的三个地方第一个是base_url末尾的/v1。OpenHands 的 OpenAI provider 会自己拼/chat/completions你再加/v1就变成/v1/v1/chat/completions直接 404。第二个是custom_llm_provider和model的搭配provider 写openaimodel 就要填广场上 OpenAI 兼容协议下的 ID不要填一个 Anthropic 专属的模型名。第三个是容器挂载~/.openhands不挂出来配置改了不生效因为容器每次重建都读镜像里的默认值。这三个错我都踩过排障顺序建议是先看 OpenHands 日志里实际发出的请求 URL再看 Key 权限最后看模型 ID 是否在广场存在。URL 对了、Key 对了、模型 ID 对了剩下的就是 Agent 自己的迭代问题和配置无关。 告别海外账号与网络限制稳定直连全球优质大模型限时半价接入中。 点击领取海量免费额度