OpenClaw 在 Docker 里跑 Agent 沙箱,Gateway 拉起来之后,真正决定成败的是沙箱内 Agent 调模型走哪条通道:这里统一用 TaoToken,Key 从 https://taotoken.net/?utm_source=taotoken_aicg_blog_end 拿,填进工具的 Base URL 是 https://taotoken.net/api,末尾不加 /v1。按原文的 docker-setup.sh 或 docker-compose.yml 把 Gateway 起起来只是第一步,容器能跑、沙箱能建、Agent 能接活,都不代表它的模型调用已经通了。相当多人卡在“沙箱里命令执行成功,但 AI 那边一直转圈或者回一句鉴权失败”,根因通常不在 Docker,而在通道配置。
这篇按 Agent 视角把链路拆开:先分清 Gateway 与 Sandbox 各自负责什么,再把模型通道从环境变量一路填到 OpenClaw 的 provider 配置,最后用一次最小任务验证沙箱里的调用确实从统一 API 出去、也能在 TaoToken 侧查到记录。文中所有注册、建 Key、看模型、看用量的动作,都落到同一个入口;涉及配置文件的部分给可复制片段,字段名以你本机 OpenClaw 版本的示例为准,因为不同版本对通道字段的命名有差异。
1. docker-setup.sh 拉起的 Gateway 与 Agent 沙箱,其实是两条线
1.1 Gateway 常驻负责调度,Sandbox 按需创建负责执行
很多人第一次跑 OpenClaw,会以为“容器起来了就是装好了”。实际结构是两层:Gateway 是一个常驻服务容器,对外暴露端口、维护会话、决定要不要给某个任务开沙箱;Agent Sandbox 是按任务创建的短命容器,Agent 在里面执行 shell、读写挂载目录、跑生成的脚本,任务结束就回收。两层混在一起看,日志就会乱。
先把两条线分别确认一遍,比直接看报错快得多:
docker compose -f docker-compose.yml up -d docker ps --format 'table {{.Names}}\t{{.Status}}\t{{.Ports}}' docker logs -f openclaw-gateway上面的服务名、镜像值请以你本地那份 compose 文件或 docker-setup.sh 输出为准,不要照抄别人的名字。docker ps里应该能看到常驻的 Gateway;沙箱容器平时不一定存在,只有任务触发时才短暂出现。如果你在docker ps里一直看不到沙箱,说明问题在调度层,还没轮到模型通道。
1.2 sandbox.enabled 打开的是一道边界,不只是一个开关
原文提到配置sandbox.enabled,这一步的含义是:Agent 生成的可执行命令不再直接跑在 Gateway 容器里,而是被丢进一个受限容器。这个受限容器通常会限制 CPU、内存、网络访问,并且只挂载你指定的工作目录。对“让 AI 帮我在临时环境里跑一段代码”这种需求,这是必要的隔离手段。
但有两个细节必须提前想清楚。第一,挂载宿主机 Docker Socket(/var/run/docker.sock)是 Gateway 能创建沙箱容器的常见前提,等于把宿主机的容器控制权交给了这个容器,所以别在这台机器上跑你输不起的东西,也别把生产数据卷顺手挂进去。第二,沙箱的工作目录尽量用一次性目录,任务结束连同容器一起删,避免上一次任务残留的文件影响下一次判断。
1.3 沙箱里每一次 tool call 都要回到模型,这才是额度消耗点
Agent 的运转是个循环:模型给出下一步动作,沙箱执行,把结果回灌给模型,模型再决定下一步。也就是说,沙箱里执行的每一步,都在触发一次大模型调用。真正吃掉 Token 的不是docker pull,也不是脚本本身,而是这个循环里的对话请求。
理解了这点,配置放哪就清楚了:模型通道属于 Gateway 层的能力,通过环境变量或配置文件注入,再下发给沙箱内的 Agent 进程。不要把 Key 写进沙箱镜像里,也不要在沙箱里另配一套通道,否则排查问题时你会不知道哪一层生效。一个 Agent 沙箱跑得稳不稳,一半看隔离,一半看通道是否统一。
2. 把 OpenClaw 的模型通道指到 TaoToken:从建 Key 到 compose 注入
2.1 先建一把只给 OpenClaw 用的 Key
打开 TaoToken,注册登录后进控制台创建 API Key,建议命名成openclaw-sandbox这类一眼能认出来的名字,复制下来当作下文里的YOUR_API_KEY。单独建一把的好处很实际:沙箱在跑什么、有没有异常请求、额度被谁消耗,都能一把 Key 对应一个用途,出问题直接停用这一把,不影响你本机其他工具。
顺手在模型广场确认一下要用的模型 ID,后面配置文件里会填。不要凭记忆写一个名字进去,模型列表会变,写错的表现通常是 404 或者“model not found”这类看起来像网络问题的报错。
2.2 docker-compose.yml 里用环境变量把通道传进 Gateway
Docker 部署的场景下,最省事的做法是环境变量加.env文件。下面的片段是结构示意,键名请对齐你本地 compose 文件里的实际写法:
services: openclaw-gateway: image: openclaw/gateway:latest # 以你本地 docker-setup.sh 生成的镜像值为准 restart: unless-stopped ports: - "8080:8080" env_file: - .env environment: OPENCLAW_SANDBOX_ENABLED: "true" OPENCLAW_MODEL_PROVIDER: "openai-compatible" OPENCLAW_MODEL_BASE_URL: "https://taotoken.net/api" OPENCLAW_MODEL_API_KEY: "${TAOTOKEN_API_KEY}" OPENCLAW_MODEL_ID: "${TAOTOKEN_MODEL_ID}" volumes: - /var/run/docker.sock:/var/run/docker.sock - ./data:/data - ./sandbox-workspace:/sandbox-workspace配套的.env只放敏感值,别提交进仓库:
TAOTOKEN_API_KEY=YOUR_API_KEY TAOTOKEN_MODEL_ID=YOUR_MODEL_ID注意OPENCLAW_MODEL_BASE_URL这一行,值是https://taotoken.net/api,结尾不带/v1。有些工具模板自带/v1后缀,直接粘进去就会出现/api/v1/v1/...这种双份路径,症状是 404,但看着像“服务挂了”。改完记得docker compose up -d重建容器,只改.env不重建,容器里读到的还是旧值。
2.3 模型配置文件里的 provider 块
如果你的 OpenClaw 版本把模型通道放在配置文件里而不是纯环境变量,通常是一段 provider 声明。字段名各版本略有差别,以本机自带的示例文件为准,结构大致是:
# 结构示意,键名以本机 OpenClaw 版本的模型配置示例为准 models: providers: - name: taotoken type: openai-compatible base_url: https://taotoken.net/api api_key: ${TAOTOKEN_API_KEY} models: - id: YOUR_MODEL_ID这里同样只写https://taotoken.net/api,不要带 UTM 参数、不要带/v1。配置文件和环境变量同时存在时,先搞清楚哪一层优先级更高,否则你会对着“明明改了却没生效”发呆。建议只保留一处来源:要么全走.env,要么全走配置文件,另一处留空或删除。
2.4 字段对照表:哪里填什么,错了会怎样
| 配置项 | 该填的值 | 常见错误写法 | 典型症状 |
|---|---|---|---|
| Base URL | https://taotoken.net/api | 结尾加/v1,或加上网站参数 | 404、路径拼接异常 |
| API Key | YOUR_API_KEY(从 https://taotoken.net/?utm_source=taotoken_aicg_blog_end 创建) | 填了别处复制的旧 Key | 401 未授权 |
| 模型 ID | 以 https://taotoken.net/?utm_source=taotoken_aicg_blog_end 模型广场当时列表为准 | 凭记忆写名字、随手加日期后缀 | model not found |
| 注入位置 | .env或 provider 配置,二者只留一处 | 两处都写且值不一致 | 改了不生效 |
表里这几行基本覆盖了初次接入的全部翻车方式。把它当检查清单用,比反复重启容器效率高。
3. 一次最小任务:确认沙箱里的 Agent 真的从统一通道出去
3.1 发一条不碰任何真实数据的任务
配置改完,先在 Gateway 界面下发一条轻量任务,例如“在沙箱工作目录里创建 hello.py,打印 Python 版本并运行”。命令由 Agent 生成、沙箱执行,你只看两件事:任务是否在沙箱容器里完成,以及对话窗口有没有正常返回模型输出。这条任务不读取任何业务数据,也不要求沙箱访问内部网络,出问题只可能是通道本身。
如果任务卡住,先在 Gateway 日志里找关键词,再进沙箱容器看进程状态。顺序不要反:先判断是调度没起来,还是模型请求没发出去,能省掉一半时间。
3.2 进沙箱容器手工发一次请求
想确认通道本身是否可达,最直接的办法是在沙箱里手工打一次接口:
docker exec -it openclaw-sandbox-xxxxx sh curl -sS https://taotoken.net/api/v1/chat/completions \ -H "Authorization: Bearer $OPENCLAW_MODEL_API_KEY" \ -H "Content-Type: application/json" \ -d '{"model":"YOUR_MODEL_ID","messages":[{"role":"user","content":"ping"}]}'沙箱容器名字是临时的,用docker ps现查。这里拼出来的完整路径是https://taotoken.net/api加上接口路径,属于工具自己该做的事;如果你在 Base URL 里也补了/v1,这里就会变成双份。手工请求能返回内容,说明网络、鉴权、模型名三项都没问题,剩下的故障点就落在 Gateway 的配置读取上。
3.3 回 TaoToken 侧核对这次调用
请求通了之后,回到 https://taotoken.net/?utm_source=taotoken_aicg_blog_end 的控制台看一眼刚刚的记录,时间点和模型 ID 应该对得上。这一步别省:沙箱里跑的任务多起来以后,唯一能把“哪次异常调用是谁发出来的”说清楚的,就是调用记录。想更快确认模型是否可用,也可以用同一把 Key 在模型对话里发一条消息,行为和 API 一致,但省去了写请求的时间。
4. 沙箱跑不通时,对着这几类错排查
4.1 401:Key 根本没进沙箱
最常见的一种。表现形式是沙箱里命令执行成功,Agent 一调模型就报鉴权失败。原因通常是.env改了但容器没重建,或者 Key 只写进了 Gateway 环境,没有下发到沙箱容器的运行环境。在沙箱里执行env | grep -i key(只确认变量是否存在,别把值贴到任何聊天窗口或日志里)可以快速定位。变量不存在,就是注入链路断了,跟 Key 本身是否有效无关。
4.2 404 与路径拼接:Base URL 多了 /v1
https://taotoken.net/api/v1/v1/chat/completions这种路径不存在。处理方式是把 Base URL 改回https://taotoken.net/api,保存后重建容器。还有一种 404 是模型 ID 写错,报错文案有时不含“model”字样,容易被当成路由问题。区分方法很简单:换成模型对话里可用的模型 ID 再试一次,如果通了就是名字写错。
4.3 Docker Socket 权限与沙箱创建失败
sandbox.enabled打开后,Gateway 需要通过 Docker Socket 创建容器。如果日志里出现permission denied /var/run/docker.sock,检查执行用户是否在 docker 组,或者 compose 里有没有把 socket 正确挂上。改完记得重启 Gateway,因为 socket 权限是进程启动时读到的。这条错和你填的 Key、Base URL 完全无关,别在通道配置上绕圈。
4.4 沙箱容器出网与 DNS
有些环境里宿主能出网,沙箱容器却不行,表现是请求超时而不是报错。先确认沙箱容器的网络模式是否允许出网,再确认容器内 DNS 能否解析域名。如果宿主本身就对这台机器做了严格的出网限制,那要先解决网络策略问题,配置再正确也发不出去。
4.5 Agent 想让沙箱去动生产库时,把命令拦下来
这是个容易被忽略的边界问题。沙箱能执行代码,不代表它应该被用来连生产库、跑诊断脚本或执行导入导出。Codex、Claude Code 这类工具在这里的正确用法是生成或解释 SQL、对照表结构,把语句给你;真正执行必须由你在本地客户端或目标数据库上手动做,然后把报错原文贴回对话继续分析。沙箱的定位是隔离的临时执行环境,不是生产运维入口,这条线守住了,后面很多麻烦都不会发生。
5. 多 Agent 长期跑沙箱时,Key 与额度怎么管
5.1 一个 Agent 一把 Key,出问题只停一把
当你的 OpenClaw 上跑了多个 Agent,或者同一个 Gateway 服务了不同项目,别让它们共用一把 Key。按用途拆分,比如openclaw-sandbox给自己评测用,openclaw-team给团队共享环境用。这样某天某个 Agent 进入死循环疯狂调用时,你停用的影响面是可预期的,而不是所有任务一起趴窝。密钥在控制台的 API Keys 页面统一创建和管理。
5.2 沙箱用完就删,记录留在通道侧
沙箱的设计意图就是短命:任务结束删容器、删工作目录,把现场清干净。真正需要长期保留的是调用记录,因为它决定了你能不能复现“某天某次任务为什么贵”。把沙箱当临时工位、把通道侧的记录当账本,这两件事分开以后,扩容和排查都会顺很多。
5.3 下一步:把这次跑通的链路沉淀成习惯
沙箱跑通之后,建议按这个顺序往下走:先在 TaoToken 模型对话 里用同一把 Key 验证模型可用,再打开 Coding Plan 评估长期跑的用量是否合适,新 Key 统一在 控制台 API Keys 创建便于日后逐把停用。如果你还想把这套通道接到本机命令行工具上,环境变量对照可以看 Claude Code 接入文档,字段含义和本文的 Base URL 写法是一致的。
沙箱这类东西最容易出现的错觉是“容器活着就等于服务正常”。真正需要盯住的,是沙箱里那个 Agent 每次思考有没有拿到模型的回话,以及这些回话是不是都记在了同一本账上。