1. 为什么我要把 Agent 关进一台能随手删掉的微虚拟机
先说结论:Docker Sandboxes 是 Docker 官方给 Coding Agent 准备的一套隔离运行环境,每个 sandbox 对应一台独立的微虚拟机,有自己的 Linux 内核、文件系统、网络策略和 Docker Engine。它适合谁?适合那些想让 Agent 自己装依赖、跑测试、起 Compose,但又不想把宿主机 Docker socket 交出去的人。我第一次接触它的时候,最直观的感受是:这东西不是容器套壳,而是把「整台机器」打包成一个可以rm掉的单元。
为什么这件事值得单独写一篇?因为给 Coding Agent 选运行环境时,「容器 vs 微虚拟机」不是一道选择题,而是一个真问题。Agent 要真的在干活,就得有权限装包、改文件、跑构建。常见做法是把宿主机的/var/run/docker.sock挂进容器,等于把整台机器的 Docker 控制权交给它。风险不在 Agent 本身,而在共享宿主机内核和宿主机 Docker 这个前提上——一旦容器逃逸或者镜像被投毒,影响面是整个宿主机。
Docker Sandboxes 换了个思路:不共享内核,也不共享宿主机的 Docker,而是给每个任务一台可以删掉的微虚拟机。项目文件还在你的 Mac 上,但宿主机的 Docker 它碰不到。Agent 退出后环境还在,装过的包、拉过的镜像都保留,只有sbx rm才真正拆掉。这个设计对「人机协作改同一棵树」的场景特别友好:Agent 改的文件你这边立刻能看到,用平时的git diff就能审。
这篇只做一件事:在 Apple Silicon 的 Mac 上,从安装走到第一次把 Agent 跑起来。环境是 M1 Pro、sbx v0.38.0、OpenCode,宿主机上的 Docker 是 OrbStack。不是全 Agent 评测,也不讲隔离机制的全景,重点放在可复制的配置片段、启动命令,以及模型通道怎么接进来。模型这块我会用 TaoToken 的统一 Key 通道来打通,这样不用在 sandbox 里反复折腾各家 OAuth。
2. 装 sbx 之前,先把 TaoToken 的 Key 和通道准备好
在动手装 Docker Sandboxes 之前,我建议先把模型通道准备好,原因是 sandbox 不继承宿主机的登录态。你在 Mac 上已经登录好的 OpenCode、Claude Code,进到 sandbox 里是看不到的。与其在里面反复/connect,不如一开始就用一个统一的 API 通道,把 Base URL、Key、Model ID 三件套固定下来。
TaoToken 在这里扮演的角色就是统一 Key 通道:一个 Key 走多家模型,Base URL 固定,Model ID 按需切换。对 sandbox 这种「每次都要重新配一遍」的环境来说,省事的地方在于配置片段可以原样复制,不用为每个 provider 单独写策略规则。官网入口是 https://taotoken.net/?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite&utm_content= ,API 地址是 https://taotoken.net/api ,注意 API 地址不带 UTM 参数。
你需要提前做两件事。第一,拿到 API Key。登录后进控制台,在 API Keys 页面创建一个新 Key,复制出来存好。这个页面地址是 https://taotoken.net/console/api-keys?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite 。第二,确认你要用的 Model ID。如果你不确定选哪个,可以先去模型对话页面试一下,地址是 https://taotoken.net/chat?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite ,在里面切换模型发一条消息,确认能通,再把这个 Model ID 记下来填进 sandbox 配置。
这里有个容易踩的坑:很多人以为 sandbox 里能直接用宿主机 OpenCode 的登录态,结果进去发现要重新登录。如果你走的是订阅制 OAuth(比如某些订阅账号),sbx secret set只支持写入 API Key,不支持这种凭证,还得在 TUI 里/connect,并且给网络策略补域名规则。用 TaoToken 的统一 Key 就绕开了这一层,因为它是标准 API Key 形态,sbx secret set直接能写进去。
配置三件套长这样,先记下来,后面会用到:
| 配置项 | 值 |
|---|---|
| Base URL | https://taotoken.net/api |
| API Key | 你在控制台创建的那串 Key |
| Model ID | 你在模型对话页确认可用的那个模型标识 |
如果你后面要长期跑编码任务或者 Agent 工作流,可以顺带看一下 Coding Plan,地址是 https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite ,它更适合高频、长时间的编码场景。接入文档在 https://taotoken.net/doc?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite ,遇到字段不确定的时候可以对照查。
3. 可复制的 sandbox 配置:从安装到 OpenCode 启动
这一节是全文的核心,所有命令都可以直接复制。先说支持范围:官方名单里的 Mac 只有 Apple Silicon,系统至少 Sonoma 14,Homebrew cask 也写死 arm64,Intel Mac 现在装不上。这是产品支持范围,不是 Intel 机器不能做虚拟化。Docker Desktop 不是前置条件,sbx 自己拉微虚拟机,也不依赖你已经在用的 OrbStack。
第一步,安装 CLI 并登录:
brew trust docker/tap brew install docker/tap/sbx sbx loginsbx login走浏览器里的 Docker 账号。装完 CLI 不会自动拉起后台进程,这点和很多人预期不一样。我这边要先常驻 daemon,再初始化网络策略,否则后面执行sbx run之类的命令会因为策略未初始化而报错:
sbx daemon start sbx policy init balanceddaemon start是前台阻塞的,适合丢给 launchd 一类的进程管理,不要挂在你正用的那个终端里不管。网络策略官方分成三档:Open 全开,Locked Down 全拦,Balanced 是居中那档——默认拒绝,只放行模型 API、包管理器、代码托管和 Registry 这类常见开发站点。文档里也可以在第一次sbx run时交互选,两条路选一条即可。
第二步,进项目目录并启动 OpenCode:
cd ~/your-project sbx run opencode第一次会拉 OpenCode 的模板镜像,要等一会儿。起来的是 TUI,不是那种自动跳过确认的会话。项目目录是挂进去的,路径和 Mac 上一样,Agent 改的文件你这边立刻看得到。
第三步,把 TaoToken 的三件套写进 sandbox。这里有两种做法,取决于你用的 Agent 形态。如果是 OpenCode 这类支持配置文件的方式,可以在项目里放一份opencode.json:
{ "$schema": "https://opencode.ai/config.json", "provider": { "taotoken": { "npm": "@ai-sdk/openai-compatible", "name": "TaoToken", "options": { "baseURL": "https://taotoken.net/api", "apiKey": "{env:TAOTOKEN_API_KEY}" }, "models": { "your-model-id": { "name": "Your Model" } } } } }注意apiKey这里用的是环境变量引用,不要把 Key 硬编码进文件。然后在 sandbox 里写入 secret:
sbx secret set taotoken它会提示你粘贴 Key。写完之后,在 sandbox 的 shell 里确认环境变量能读到。如果你用的是 Claude Code 形态,配置走settings.json,路径和字段要对齐:
{ "env": { "ANTHROPIC_BASE_URL": "https://taotoken.net/api", "ANTHROPIC_API_KEY": "your-key-here", "ANTHROPIC_MODEL": "your-model-id" } }如果你用的是 Codex 形态,配置走auth.json,三件套同样要对齐 Base URL、Key、Model ID。这三个文件形态(opencode.json、settings.json、auth.json)是不同 Agent 的入口,选你实际用的那个,不要混着填。
第四步,如果你确实需要走 OAuth 类订阅,才需要补网络策略。用 TaoToken 统一 Key 的话,一般不需要额外放行,因为它是标准 API 端点。但如果你同时还想用别的 provider,可以这样加规则:
sbx policy allow network "*.example.com:443,api.example.com:443"停掉但留下环境用sbx stop,下次sbx run --name <sandbox>再连。不要了再sbx rm。需要进编辑器时,先sbx setup ssh,然后ssh <name>.sbx,VS Code 的 Remote-SSH 也能连这个主机名。
4. 验证请求:确认 Agent 真的连上了模型
配置写完不代表通了,得实际验证。我一般分两步:先在 sandbox 里用 curl 打一次 API,确认网络和 Key 都没问题;再让 OpenCode 跑一个真任务,确认端到端链路。
第一步,在 sandbox 的 shell 里发一个最小请求:
curl -s https://taotoken.net/api/v1/chat/completions \ -H "Authorization: Bearer $TAOTOKEN_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "your-model-id", "messages": [{"role": "user", "content": "ping"}], "max_tokens": 16 }'如果返回里有choices字段,说明 Key、Base URL、网络策略三者都通了。如果返回 401,说明 Key 没写对或者环境变量没读到;如果卡住不动,多半是网络策略没放行taotoken.net。Balanced 档默认放行常见开发站点,TaoToken 的 API 域名一般在这个范围内,但如果你手动改过策略,要确认没把它拦掉。
第二步,回到 OpenCode 的 TUI,丢一个真任务进去,比如「跑一下测试,把失败的那个补上」。文件改动会出现在你的工作区里,用平时的git diff看就行。这一步能过,说明 Agent 不只是连上了模型,还能在 sandbox 里实际读写项目、执行命令。
这里有个细节值得说:sandbox 里的 Docker Engine 是它自己的,你在里面docker ps,看到的不是 OrbStack。这意味着 Agent 可以在里面起 Compose、拉镜像、跑集成测试,而不会碰到你宿主机的 Docker。工作区里的.env、.git都能被 Agent 直接读到,没有额外的权限限制去挡它——隔离挡的是工作区外面,不是工作区里面。这一点要心里有数,敏感文件要么别放进工作区,要么给 Agent 一份隔离副本。
验证通过之后,你可以把这条链路固定下来:项目里放好配置文件,Key 走sbx secret set,每次sbx run opencode就能直接开工。需要长期跑的话,Coding Plan 那条通道会更合适,地址是 https://taotoken.net/coding-plan?utm_source=taotoken_aicg_blog_end&utm_medium=csdn&utm_campaign=rewrite 。
5. 常见报错排查:401、策略未初始化、OAuth 连不上
这一节按真实报错来对,都是我或者身边人实际撞过的。
401 Unauthorized。最常见的原因是 Key 没写进去,或者环境变量名对不上。先确认sbx secret set taotoken执行成功,再在 sandbox 里echo $TAOTOKEN_API_KEY看有没有值。如果配置文件里写的是{env:TAOTOKEN_API_KEY},要确保变量名完全一致。还有一种情况是 Key 复制时带了空格或者换行,重新复制一次。
local proxy failed / 策略未初始化。这个报错通常出现在你跳过sbx policy init直接sbx run的时候。解决方式是先sbx daemon start,再sbx policy init balanced,然后重试。如果 daemon 没起来,sbx run也会失败,确认 daemon 进程在跑。
reading choices 相关报错。这类报错一般出现在 API 返回体解析阶段,说明请求发出去了但返回格式不对。检查 Base URL 是不是写成了https://taotoken.net/api,不要多加或者少加/v1,具体以接入文档为准。Model ID 也要确认是模型对话页里验证过可用的那个,写错模型名有时会返回非预期结构。
OAuth 连不上 / device code 出不来。如果你走的是订阅制 OAuth 而不是 API Key,sbx secret set写不进去,得在 TUI 里/connect。Balanced 档默认不放行某些登录域名,device code 出不来,需要手动加规则:
sbx policy allow network "*.example.com:443,auth.example.com:443,accounts.example.com:443"用 TaoToken 统一 Key 的话,这一整类问题基本可以绕开,因为它是标准 API Key 形态,不需要走 OAuth 流程。
Agent 改了文件但宿主机看不到。确认你是在项目目录里执行的sbx run,工作区挂载路径和 Mac 上一致。如果路径不对,Agent 改的是 sandbox 内部的文件,宿主机自然看不到。
Intel Mac 装不上。这是产品支持范围问题,官方 cask 写死 arm64,不是你的机器有问题。目前只能在 Apple Silicon 上跑。
排查的时候有个通用思路:先确认 daemon 和策略,再确认 Key 和 Base URL,最后确认 Model ID。这三层从下往上查,基本能定位到问题在哪一层。
6. 把统一 Key 通道固定下来,下次直接开工
走到这里,你应该已经在 sandbox 里跑通了第一个 Agent 任务。回头看,真正费事的不是拉镜像,也不是装 CLI,而是模型怎么进去。sandbox 不继承宿主机登录态,订阅制 OAuth 还要单独/connect并放行网络策略。用 TaoToken 的统一 Key 通道,把 Base URL、Key、Model ID 三件套固定下来,这一步就变成可复制的配置,而不是每次重新折腾。
我自己的做法是:项目里放一份opencode.json,Key 走sbx secret set,网络策略保持 Balanced,需要额外域名再单独加。这样每次sbx run opencode就能直接开工,Agent 在微虚拟机里装依赖、跑测试、起容器,宿主机的 Docker 和内核都不受影响。工作区还是你的工作区,git diff还是你的git diff。
如果你要长期跑编码任务或者 Agent 工作流,建议把 Key 管理和通道固定下来,Coding Plan 那条路更适合高频场景。接入过程中遇到字段不确定的,对照接入文档查一下,比反复试错快。模型对话页面可以用来快速验证某个 Model ID 是否可用,确认了再填进配置。
最后提醒一句边界:工作区挂进去之后,.env对 Agent 是可见的。隔离挡的是工作区外面,不是工作区里面。工作区是不是必须直接读写、能不能换成给 Agent 一份隔离副本,这道边界具体打在哪,取决于你的项目敏感程度。想清楚这一点,再决定哪些目录挂进去。