☰
OpenHands 配 TaoToken:Docker 沙箱里跑通 LLM 编程的 config.toml 骨架
2026/9/28 19:24:59 网站建设 项目流程

1. 为什么要在 Docker 沙箱里给 OpenHands 接一条统一 Key 通道

OpenHands 是一个把 LLM 当“执行大脑”的开源编程 Agent,它能读你的仓库、改文件、跑命令、看报错再自己修。它和普通补全插件最大的区别是:它真的会动手。而它动手的地方,是一个隔离的 Docker 沙箱容器,不是你的宿主机。这个设计很关键——Agent 跑偏了最多把沙箱搞坏,你的系统盘和家目录是安全的。

但很多人第一次在 Linux 上把 OpenHands 跑起来后,会卡在同一个地方:模型接不上。表现是界面能打开、任务能提交,但 Agent 一直转圈,或者日志里反复出现鉴权失败、连接超时、模型名不识别。原因通常不是 OpenHands 本身,而是 LLM 通道没配对:要么 Key 填错位置,要么 base_url 没指向兼容端点,要么 config.toml 和 Docker 环境变量两处配置打架。

这篇就聚焦这一件事:在 Linux 上用 Docker 启动 OpenHands 之后,怎么通过一条统一的 Key/API 通道把 LLM 接进去,让第一次代码任务真正跑通。我会给出一份可以直接复制的 config.toml 骨架、一份 Docker 环境变量骨架,然后用一个“自动修复小 bug”的真实任务来验证,最后把常见的报错路径一条条排掉。适合已经在 Linux 上装好 Docker、想让 OpenHands 真正干活的人。

2. TaoToken 前置:把 Key 和端点先准备好

OpenHands 支持多种 LLM 提供方,配置上分两层:一层是 OpenHands 应用自己的 config.toml,一层是传给沙箱容器的环境变量。两层都要指向同一个可用的 API 端点,否则会出现“应用以为配好了、沙箱里请求却发不出去”的割裂。

我用的统一通道是 TaoToken,它提供 OpenAI 兼容的接口,所以 OpenHands 里凡是填 base_url 和 api_key 的地方都能直接对接。你需要先拿到两样东西:

一是 API Key。登录后在控制台创建,格式通常是一串以特定前缀开头的字符串。这个 Key 只显示一次,复制好放安全的地方。

二是确认端点地址。对话补全走的是兼容 OpenAI 的路径,base_url 填https://taotoken.net/api,注意这里不要带任何查询参数。模型名按你实际要用的填,比如claude-sonnet-4-5这类,具体以文档里的模型列表为准。

注意:Key 不要写进会提交到 Git 的文件里。config.toml 如果放在仓库内,用环境变量引用,或者把 config.toml 加进 .gitignore。

相关入口我放在这里,按需取用:创建和管理 Key 在 API Keys;接入参数和字段说明看 接入文档;想先在网页里验证模型通不通,用 模型对话。

3. 可复制配置:config.toml 骨架 + Docker 环境变量骨架

3.1 config.toml 骨架

OpenHands 的 config.toml 一般放在工作目录下,或者通过挂载进容器。下面这份骨架把 LLM 段单独拎出来,字段名按 OpenHands 的约定来,你只需要替换模型名和 Key 来源。

[core] # 工作区路径,容器内路径,和挂载点保持一致 workspace_base = "/opt/workspace_base" # 缓存目录,避免每次重建 cache_dir = "/opt/workspace_base/.cache" [llm] # 统一通道的兼容端点,不要带查询参数 base_url = "https://taotoken.net/api" # 模型名按实际可用列表填写 model = "claude-sonnet-4-5" # 从环境变量读取,避免明文写死在文件里 api_key = "${TAOTOKEN_API_KEY}" # 采样温度,改代码任务建议低一点,稳定优先 temperature = 0.2 # 单次最大输出,修 bug 场景够用 max_output_tokens = 4096 # 请求超时,网络抖动时给足余量 timeout = 120 [sandbox] # 沙箱类型,Docker 环境下用 docker type = "docker" # 沙箱内也注入同一套 Key,保证 Agent 执行时能调模型 runtime_extra_env = { TAOTOKEN_API_KEY = "${TAOTOKEN_API_KEY}" }

这里有两个容易踩的点。第一,api_key用${TAOTOKEN_API_KEY}这种引用写法,前提是启动 OpenHands 的进程环境里真的有这个变量,否则会解析成空字符串,表现为 401。第二,runtime_extra_env是给沙箱容器用的,很多人只配了应用层,忘了沙箱层,结果 Agent 在容器里执行到需要调模型的步骤就断。

3.2 Docker 环境变量骨架

启动命令里把 Key 通过-e注入,同时把 config.toml 挂载进去。下面这份可以直接改路径用。

# 先导出 Key,避免写进命令历史 export TAOTOKEN_API_KEY="你的Key" # 工作区目录 WORKSPACE_BASE=$(pwd)/workspace mkdir -p "$WORKSPACE_BASE" docker run -it --rm \ --pull=always \ -e SANDBOX_USER_ID=$(id -u) \ -e WORKSPACE_MOUNT_PATH=$WORKSPACE_BASE \ -e TAOTOKEN_API_KEY="$TAOTOKEN_API_KEY" \ -v $WORKSPACE_BASE:/opt/workspace_base \ -v $(pwd)/config.toml:/opt/workspace_base/config.toml:ro \ -v /var/run/docker.sock:/var/run/docker.sock \ -p 3000:3000 \ --add-host host.docker.internal:host-gateway \ --name openhands-app-$(date +%Y%m%d%H%M%S) \ ghcr.io/opendevin/opendevin:0.8

几个参数的作用值得说清楚。-e TAOTOKEN_API_KEY把 Key 传进应用容器;-v config.toml把配置只读挂载进去,容器重建也不丢;-v /var/run/docker.sock让 OpenHands 能创建和管理它自己的沙箱容器,这个不挂,Agent 起不来;--add-host host.docker.internal:host-gateway让容器内能访问宿主机网络,某些本地服务场景会用到。

提示:如果你不想把 Key 放进环境变量,也可以写进一个.env文件,用--env-file .env加载,效果一样,但记得把.env加进 .gitignore。

4. 验证请求:用一次真实的小 bug 修复跑通全链路

配置写完不算通,得让 Agent 真的改一次代码。我准备了一个最小可复现的 bug:一个 Python 函数在列表为空时抛异常。

4.1 准备待修复的代码

在$WORKSPACE_BASE下建一个buggy.py:

def average(nums): # 当 nums 为空时,这里会 ZeroDivisionError return sum(nums) / len(nums) if __name__ == "__main__": print(average([1, 2, 3])) print(average([]))

4.2 提交任务给 OpenHands

浏览器打开http://localhost:3000,在任务框里输入:

修复 buggy.py 中的 average 函数,使其在输入为空列表时返回 0 而不是抛异常。 修改后运行该文件确认两个调用都不报错。

提交后观察 Agent 的动作序列。正常情况下它会:读取buggy.py、定位到len(nums)为 0 的分支、写入修复、在沙箱里执行python buggy.py、看到输出2.0和0、给出完成总结。

4.3 期望的成功结果

修复后的函数大致长这样:

def average(nums): if not nums: return 0 return sum(nums) / len(nums)

终端输出应该是:

2.0 0

如果你在 OpenHands 界面里看到 Agent 完成了文件修改并贴出了执行输出,说明从应用层到沙箱层、再到 LLM 通道,整条链路是通的。这一步跑通,后面接更复杂的任务才有意义。

5. 本篇常见错排查:从 401 到沙箱起不来

5.1 鉴权失败(401 / invalid api key)

最常见。先确认三件事:Key 是否复制完整、有没有多余空格;base_url是否写成了带路径或查询参数的地址;环境变量是否真的传进了容器。进容器里验证一下:

docker exec -it <容器名> env | grep TAOTOKEN

如果输出为空,说明-e没生效,检查启动命令。如果变量在,但请求仍 401,用 curl 直接打一次兼容端点,排除 Key 本身的问题:

curl -s https://taotoken.net/api/chat/completions \ -H "Authorization: Bearer $TAOTOKEN_API_KEY" \ -H "Content-Type: application/json" \ -d '{"model":"claude-sonnet-4-5","messages":[{"role":"user","content":"ping"}]}'

返回正常内容说明 Key 和端点没问题,问题在 OpenHands 配置层。

5.2 模型名不识别(model not found)

OpenHands 里填的model必须和通道支持的模型名完全一致,大小写、连字符都不能错。不确定时先去模型列表里核对,别凭记忆填。填错的表现是请求发出去了但立刻返回错误,Agent 会反复重试同一个名字。

5.3 沙箱起不来(Cannot connect to the Docker daemon)

这个报错说明 OpenHands 应用容器里访问不到宿主机的 Docker。检查启动命令里有没有挂/var/run/docker.sock,以及当前用户有没有权限操作 Docker。用docker ps在宿主机确认守护进程正常,再确认挂载路径没写错。

5.4 请求超时(timeout / connection reset)

改代码任务里 Agent 会连续发多次请求,网络抖动时容易超时。把 config.toml 里的timeout调大,比如 180。如果频繁 reset,检查是不是有本地网络策略拦了出站,或者容器 DNS 解析有问题,可以在启动命令里加--dns 8.8.8.8试一次。

5.5 配置不生效(改了 config.toml 没反应)

OpenHands 可能读的是容器内另一份配置,或者你挂载的路径和它默认查找的路径不一致。确认挂载目标路径和workspace_base对得上,改完配置后重启容器,别指望热加载。用docker exec进容器cat一下挂载进去的 config.toml,确认内容是你改后的版本。

6. 接下来怎么用:按场景选入口

链路跑通之后,OpenHands 能做的事就多了:批量重构、补测试、按 issue 描述改代码。如果你主要是长期跑编码任务、想让 Agent 持续在项目里干活,建议用 Coding Plan 这类面向编码场景的通道,配额和稳定性更适合长时间会话。如果你还在调模型参数、想先确认某个模型在改代码任务上的表现,去 模型对话 里手动试几轮,比在 Agent 里反复试错快得多。Key 的创建和轮换在 API Keys,字段含义和兼容细节以 接入文档 为准。

最后留一个我自己的习惯:每次改完 config.toml,先用第 5.1 节那条 curl 打一次,确认 Key 和端点活着,再启动 OpenHands。这样能把“通道问题”和“Agent 问题”分开,排障时少绕很多路。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询