AI Agent 一旦开始执行命令、修改代码或调用外部服务,问题就不再只是“回答是否正确”,而是“它究竟能做什么”。Docker 在 WeAreDevelopers 主题演讲中把信任落到了三个具体支点上:Sandboxes 提供隔离边界,Kits 固化工具与权限,Cloud Sandboxes 则把同一套边界扩展到远程、按需创建的环境。
这套思路的重点不是让模型永远不犯错,而是让错误发生在一个权限有限、结果可追踪、环境可重建的执行空间里。
信任不应来自提示词,而应来自执行边界
系统提示词可以要求 Agent“不要删除文件”或“不要访问公网”,但提示词本身不是安全控制。提示注入、工具参数错误、依赖安装脚本以及模型误判,都可能绕过文字约束。
更可靠的做法是把 Agent 的 authority,也就是它实际拥有的权限,落实到运行时:
- 只读挂载输入代码,单独提供可写输出目录;
- 默认关闭网络,确有需要时再通过代理开放有限出口;
- 删除 Linux capabilities,禁止提权;
- 限制 CPU、内存、进程数和运行时间;
- 使用确定的镜像、依赖版本和启动命令;
- 记录输入、镜像标识、策略、工具调用与输出摘要。
这里有一个重要区别:Agent 的意图由模型产生,但 Agent 的权限必须由平台决定。 即使模型受到恶意网页或仓库内容影响,它也不应获得边界之外的能力。
Sandboxes、Kits 与 Cloud Sandboxes 各自解决什么
Sandboxes:限制单次执行的爆炸半径
沙箱负责回答:“这一次任务最多能影响哪些资源?” 一个代码修复 Agent 通常只需要读取仓库、写入补丁并运行测试,并不天然需要读取宿主机的 SSH 密钥、Docker Socket 或整个用户目录。
容器可以提供进程、文件系统和网络层面的隔离,但容器仍与宿主机共享内核。对于不可信代码、多租户环境或高价值凭据,仅依赖默认容器配置并不充分;还应考虑强化的容器运行时、虚拟机或 microVM,以及独立的凭据代理。
Kits:把工具和权限变成可复用合同
如果每个团队都手写一长串启动参数,策略很快会漂移。Kits 的价值可以理解为:把镜像、工具、挂载点、网络规则、资源限制和入口命令打包成可版本化的执行合同。
下面是一个用于表达这种合同的示意清单。它不是特定产品的官方配置格式,但可以作为内部平台 schema 的起点:
version: 1
name: python-review-agent
runtime:
image: registry.example.com/agents/python-reviewer@sha256:REPLACE_ME
read_only_rootfs: true
user: "10001:10001"
permissions:
network: deny
capabilities: []
mounts:
- source: ./repository
target: /workspace/repository
mode: read-only
- source: ./artifacts
target: /workspace/artifacts
mode: read-write
limits:
cpus: 1
memory: 512Mi
pids: 128
timeout: 300s
真正决定可复现性的不是 Kit 的名字,而是其中是否引用了不可变镜像、锁定依赖,并明确声明所有外部输入。
Cloud Sandboxes:把生命周期管理移出开发机
Cloud Sandboxes 适合需要并发执行、临时环境和集中审计的场景。远程环境可以在任务到来时创建,完成后销毁,避免长期工作区积累状态。
不过,“运行在云端”本身不等于安全。平台仍需回答:租户如何隔离、凭据如何按任务签发、日志保留多久、数据驻留在哪里,以及失败后环境能否可靠回收。
动手做一个最小的只读 Agent 沙箱
下面的例子使用一个确定性 Python 脚本模拟 Agent。它不调用模型,目的是单独验证执行边界:输入目录只读、输出目录可写、根文件系统只读,并且容器没有网络和额外 capabilities。
运行前需要安装 Docker。复制以下命令即可创建并执行示例:
mkdir -p ai-agent-sandbox/input ai-agent-sandbox/output
cd ai-agent-sandbox
cat > agent.py <<'PY'
from pathlib import Path
import hashlib
input_file = Path("/workspace/input/task.txt")
output_file = Path("/workspace/output/result.txt")
task = input_file.read_text(encoding="utf-8")
digest = hashlib.sha256(task.encode("utf-8")).hexdigest()
result = (
"Sandboxed agent result\n"
f"task: {task.strip()}\n"
f"input_sha256: {digest}\n"
)
output_file.write_text(result, encoding="utf-8")
print(result, end="")
PY
cat > Dockerfile <<'DOCKERFILE'
FROM python:3.12-alpine
WORKDIR /workspace
COPY agent.py /opt/agent.py
ENTRYPOINT ["python", "/opt/agent.py"]
DOCKERFILE
printf '%s\n' 'Review the payment module without modifying source files.' > input/task.txt
docker build -t agent-sandbox-demo:local .
docker run --rm \
--network none \
--read-only \
--cap-drop ALL \
--security-opt no-new-privileges=true \
--pids-limit 64 \
--memory 128m \
--cpus 0.5 \
--user "$(id -u):$(id -g)" \
--mount "type=bind,src=$PWD/input,dst=/workspace/input,readonly" \
--mount "type=bind,src=$PWD/output,dst=/workspace/output" \
--tmpfs /tmp:rw,noexec,nosuid,size=16m \
agent-sandbox-demo:local
cat output/result.txt
docker image inspect agent-sandbox-demo:local --format '{{.Id}}'
这段命令把几个关键控制放在了模型之外:
--network none阻止脚本直接访问模型 API 或其他外部服务;--read-only阻止它修改容器根文件系统;- 输入挂载使用
readonly,输出则进入单独目录; --cap-drop ALL与no-new-privileges缩小提权空间;- 资源参数限制失控进程的影响;
- 镜像 ID 和输入 SHA-256 可以进入审计记录。
真实 Agent 通常需要调用模型。可以这样实践:让沙箱只访问一个受控网关,由网关负责模型凭据、目标白名单、速率限制和请求审计,而不是把长期 API Key 注入沙箱。Docker 的 --network none 适合本地边界验证;生产系统需要配套的受限网络或代理机制。
上线前检查:能否重放同一份 authority
采用 Agent 沙箱时,不要只验证“任务跑通了”,还应检查以下问题:
- 镜像是否不可变:生产环境优先使用 digest,而不是可覆盖的标签。
- 输入是否完整记录:包括任务文本、仓库版本、工具参数和策略版本。
- 写权限是否最小化:不要为了方便挂载整个主目录或 Docker Socket。
- 网络是否默认拒绝:开放出口时,应指定域名、协议、身份与速率上限。
- 凭据是否短期有效:按任务签发,并限制到具体服务和操作。
- 失败是否可清理:超时、崩溃或控制面失联后,环境仍应自动销毁。
- 结果是否可追溯:保存日志、产物哈希、镜像 digest 和策略版本。
- 隔离级别是否匹配风险:容器并非所有威胁模型下的最终边界。
Sandboxes、Kits 和 Cloud Sandboxes 的共同价值,是把“相信 Agent 会听话”改造成“证明 Agent 只能在授权范围内行动”。当执行环境能够隔离、版本化和重放时,团队才有条件扩大 Agent 的自动化范围,而不必同步扩大事故半径。