1. OpenHands 的 Agent 跑在容器里,模型得你自己接
1.1 Docker 起来了,不等于它就能干活
先把结论放在前面:OpenHands 用 Docker 跑起来只要一条命令,卡住多数人的是浏览器打开 http://localhost:3000 之后要填的模型配置。TaoToken 的 Key 到 https://taotoken.net/?utm_source=taotoken_aicg_blog_end 创建,Base URL 填 https://taotoken.net/api,两分钟就能把这条链路接上。
那个 5.5 万 Star 的开源编程 Agent 之所以吸引人,是它不像补全工具那样只猜下一行,而是你给一个任务,它自己开终端、自己改文件、自己跑测试、自己看报错再重试。听起来很唬人,但镜像里既没有模型权重,也没有随包附赠的额度。容器只是一个调度器加一层 Web 界面,真正决定它聪不聪明的,是你后面接上来的那条模型通道。
所以第一次启动 OpenHands,你会遇到一个很典型的场景:界面出来了,任务框也能打字,可是左侧状态栏一直在等你把模型配好。这一步没配好,它连第一步规划都出不来,更别说动你的仓库。
1.2 TaoToken 在这条链路里的位置:只给两样东西
把需求拆开看就清晰了——OpenHands 要开始思考,需要一个能访问的模型接口地址和一把能过认证的 Key,就这两样。TaoToken 提供的正是这两样:统一的接口地址是 https://taotoken.net/api,Key 从官网控制台创建。
它既不是 OpenHands 的内置功能,也不是什么需要额外装的插件。你在 OpenHands 的模型设置里,完全可以把它当成任意一个 OpenAI 兼容或 Anthropic 兼容的服务来填——选了对应的 Provider,然后把地址和 Key 换成 TaoToken 给你的那套。理解这一点之后,后面所有步骤都是照着界面填格子,没有玄学。
2. 把 OpenHands 容器起在 localhost:3000
2.1 docker run 里三个不能省的参数
原文的部署方式就是一条 docker run。参数不多,但有几个省掉就会出问题。下面这段可以直接改着用,镜像的版本 tag 请去官方仓库对照当前值,不要照抄某个写死的旧版本号:
docker run -it --rm --pull=always \ -e SANDBOX_RUNTIME_CONTAINER_IMAGE=docker.all-hands.dev/all-hands-ai/runtime:<runtime-tag> \ -e LOG_ALL_EVENTS=true \ -v /var/run/docker.sock:/var/run/docker.sock \ -v ~/.openhands:/.openhands \ -p 3000:3000 \ --add-host host.docker.internal:host-gateway \ --name openhands-app \ docker.all-hands.dev/all-hands-ai/openhands:<app-tag>三个地方值得单独说。-v /var/run/docker.sock:/var/run/docker.sock是把宿主机的 Docker 交给 OpenHands 使用,它每接一个任务都会另起一个沙箱容器去执行命令,这条不挂上,任务会在准备阶段直接失败,日志里能看到连不上 Docker daemon 一类的报错。-p 3000:3000决定你之后访问的端口。-v ~/.openhands:/.openhands用来把配置持久化,不然每次重启容器,模型设置都得重填一遍,前期调试时会很烦。
如果你是 Windows 环境,把~/.openhands换成明确的盘符路径,例如D:\openhands-state;--add-host在 Docker Desktop 上通常用不上,留着也不影响。
2.2 第一屏就是模型选择,别误会成自带额度
容器起来之后,浏览器打开 http://localhost:3000,第一屏基本都会落到模型配置上。界面上常常会推荐 Claude 3.7 Sonnet 这类模型,看起来像是开箱即用的默认能力。实际上那只是它给你的建议项,Key 要你自己准备,接口地址也要你自己指过去。默认推荐写什么,和你能不能跑起来是两码事。
这里还有个常见误判:有人以为「容器能起来 = 网络是通的」,于是直接把官方默认项填上去,结果一提交任务就卡住。OpenHands 本身不会替你去申请任何凭证,它只负责发请求。
2.3 启动前顺手确认的两件事
一是端口有没有被占用,3000 被别的服务占了就换成-p 3001:3000,然后访问 3001。二是磁盘,Agent 每接一个任务都会拉一次运行环境,长期跑的话留出足够空间。这两件事不解决,后面排查模型问题时会白白绕远路——你以为是 Key 不对,其实是容器根本没跑顺。
3. 模型设置里的 Base URL 填 https://taotoken.net/api
3.1 先去控制台建一把 Key
打开 TaoToken,注册登录后在控制台创建一把 API Key,复制出来先放在一边。顺手在模型广场看一眼当前有哪些模型 ID,等下要填进 OpenHands。Key 通常只在创建时完整显示一次,没存下来就直接再建一把,不用在这上面纠结。本文所有示例里,Key 一律用占位符YOUR_API_KEY表示,别把真实 Key 贴进任何截图或文章里。
3.2 Provider、Base URL、Model 三格怎么对应
OpenHands 的模型设置可以理解成三格,一格都别填错:
| 设置项 | 填什么 | 备注 |
|---|---|---|
| Provider | 选与模型家族匹配的项 | OpenAI 兼容选 OpenAI,Anthropic 系选 Anthropic |
| Base URL / API Base | https://taotoken.net/api | 末尾不要加/v1 |
| API Key | YOUR_API_KEY | 从 TaoToken 控制台创建的那把 |
| Model | 模型广场里的 ID | 以当时列表为准,不要手写猜测的 ID |
有两点特别容易踩。第一,Base URL 是给 OpenHands 这个程序去请求接口用的,不是给人点开的网页,所以不要填官网地址,更不要把带查询参数的那串贴进去,那串是给人看的落地页,程序请求它会拿到一堆 HTML。第二,这个地址末尾不带/v1,客户端会自己拼路径,你多写一层就会变成重复路径,请求直接失败。
3.3 不想每次在界面里填,也可以走环境变量
如果你习惯用命令行重开容器,可以顺手把默认模型用环境变量带进去,省得每次进界面再点一遍:
docker run -it --rm --pull=always \ -e LLM_MODEL=<模型广场里的模型 ID> \ -e LLM_API_KEY=YOUR_API_KEY \ -e LLM_BASE_URL=https://taotoken.net/api \ -v /var/run/docker.sock:/var/run/docker.sock \ -v ~/.openhands:/.openhands \ -p 3000:3000 \ --name openhands-app \ docker.all-hands.dev/all-hands-ai/openhands:<app-tag>具体变量名以你所用镜像版本的配置说明为准。如果你已经把配置目录挂出来并保存过设置,界面里那条记录会优先于环境变量,两边不一致时以界面为准,这也是很多人「明明改了环境变量却没生效」的原因。
4. 让它做个小任务,确认通道真的通了
4.1 任务一:给仓库加一份日文版 README
配置保存之后,别急着丢一个大型 issue 进去,先用小任务跑通。找一个自己 clone 到本地工作目录的小仓库,在对话框里写清楚边界和验收标准:
请在当前仓库根目录新增 README.ja.md。 内容对应 README.md 的日文翻译,保持原有标题层级、代码块和链接不变。 完成后列出新增或修改的文件路径。任务描述里把「做什么、在哪做、怎么算完成」写全,比写一大堆形容词有用得多。这里要提醒一句边界:OpenHands 跑在沙箱容器里,它能做的是改代码、跑测试、看报错;涉及生产库的诊断 SQL、编译、组件注册这类动作,让它生成命令或脚本,你自己在本机或 SQL*Plus 里执行完,再把结果和报错贴回对话。别让它去连生产机器执行操作。
4.2 任务二:修一个 issue
小任务通了之后,可以再试一个带排查的任务。把 issue 的描述或链接贴进对话框,要求它先复现、再定位、最后改并跑测试:
请阅读以下 issue 描述,先在本地复现问题, 说明复现步骤和观察到的现象,再给出最小改动方案, 修改完成后运行仓库里的测试命令并贴出结果。这个任务能顺带验证两件事:一是模型在多轮规划下是否稳定,二是你的通道在连续多次请求时有没有被限流或断开。
4.3 从哪里看出来调用真的走了模型
判断通道是否生效,看两处。一是 Agent 的思考过程有没有正常推进——规划、选工具、执行、观察结果,这几步是否成串出现;如果模型没接上,它在第一步就会停住,或者反复重试同一个动作,不会真的去动文件。二是任务结束后去看实际结果:README.ja.md是不是真的出现在仓库里,diff 是不是合理,测试有没有跑过。
如果结果是「动作流走完了但文件没变」「一直卡在等待模型返回」,那就不是 OpenHands 的问题,回到上一节检查地址和 Key。
5. 认证失败先查 Base URL,再查 Key
5.1 两个最高频的填错
排第一的是把官网地址当接口地址填了。有人在模型设置里直接贴了 https://taotoken.net/?utm_source=taotoken_aicg_blog_end,界面不会立刻拦住你,但一发请求就是认证失败或者返回一段 HTML——那是给人看的页面,不是接口。记住分工:官网落地址用于注册、建 Key、看模型广场和看用量;填进 OpenHands 的地址只有https://taotoken.net/api。
排第二的是末尾多了/v1。这个错误尤其隐蔽,因为它看起来「更规范」,但拼接之后路径就重复了,返回的往往不是 401 而是 404,很多人会顺着认证方向查半天。
5.2 报错对照表
| 现象 | 大概率原因 | 处理方式 |
|---|---|---|
| 401 / Unauthorized | Key 复制不完整、带空格、或已被删除 | 回控制台重新创建一把 |
| 404 / Not Found | Base URL 多了/v1,或填成了官网地址 | 改成https://taotoken.net/api |
| 一直转圈不出结果 | 模型 ID 写错,或该模型不在当前可用列表 | 去模型广场核对 ID |
| 任务起不来,日志报 Docker 相关 | 没有挂载docker.sock | 检查-v参数 |
排查顺序建议固定下来:先看 Base URL 是不是https://taotoken.net/api,再看模型 ID 是不是从列表里复制的,最后才怀疑 Key。这个顺序能省掉大量无用功,因为地址类的错误出现频率远高于 Key 本身失效。
5.3 用同一把 Key 换个入口验证
如果 OpenHands 里始终认证不过,先把 Key 本身摘出去。在 TaoToken 模型对话 里用同一把 Key 发一条测试消息,能正常回来,说明 Key 没问题,问题就在 OpenHands 这边的地址或模型 ID 上;如果那边也不通,那就是 Key 或账户状态的问题,重新建一把最快。
这一步的价值在于把问题一分为二,避免在界面和 Key 之间来回猜。
6. 跑通之后去对一下这次调用
6.1 任务跑完,回控制台看用量
OpenHands 的一个任务往往包含多轮规划和多次工具调用,一次跑下来消耗不算小,尤其是让它反复读文件、跑测试的时候。回到 https://taotoken.net/?utm_source=taotoken_aicg_blog_end 的用量页面,能看到这次调用有没有记上账、落在哪个模型上。如果发现用量比预期高,很可能是循环没有被正常终止,或者任务描述太模糊导致它反复试错,这两点都可以通过收紧验收标准来改善。
6.2 接下来可以做的事情
如果你打算让 OpenHands 长期在后台跑任务,先评估一下用量节奏,再决定走哪种计费方式;Key 统一在 控制台 API Keys 里创建和管理,换机换容器只要换这一把。日常想快速验证某个模型 ID 能不能用,直接在 TaoToken 模型对话 里发一条最省事。
最后补一个容易被忽略的点:容器化 Agent 很强,但它终究是个会自己动手的执行者。第一次接入某个仓库时,先给它一个干净的分支和可回滚的工作目录,等小任务稳定跑通几次,再把范围放大。通道接对了,剩下的就是任务描述的功夫。