AI agent 能调用工具以后,测试就不能只看回答。它可能创建文件、更新状态、发送消息、触发外部接口。如果这些动作直接跑在真实环境里,哪怕只是一次试运行,也可能留下错误数据。
沙箱环境的目标,是让 agent 在接近真实的流程里演练,但把影响限制在可回收空间。它不是测试环境的另一个名字,而是一套“允许 agent 尽量真实执行,但所有副作用可观察、可拦截、可撤销”的机制。
先给结论:沙箱要隔离三类资源
| 资源 | 隔离方式 |
|---|---|
| 文件 | 临时目录、只读源文件、写入白名单 |
| 接口 | mock 服务、测试 token、环境标识 |
| 数据 | 快照副本、测试账号、可重置状态 |
沙箱不是简单加一个 test=true,而是一组明确边界。
一套最小沙箱架构
可以把沙箱拆成四层:
Agent Runtime
-> Tool Gateway
-> Sandbox Adapter
-> Mock / Snapshot / Outbox / Temp Files
| 层级 | 职责 |
|---|---|
| Agent Runtime | 生成计划和工具调用意图 |
| Tool Gateway | 校验权限、环境、工具版本 |
| Sandbox Adapter | 把真实写入转换为模拟写入 |
| Sandbox Storage | 保存临时文件、outbox、快照和报告 |
关键点是:agent 不应该直接知道每个 mock 的细节。它仍然调用同一组工具,由 adapter 决定在沙箱里如何执行。
一、文件沙箱要保护源文件
如果 agent 要改文件,先让它在临时目录或副本里执行。源文件只读,输出文件进白名单目录。执行结束后展示 diff,由人确认是否合并。
这适合代码生成、内容批改、配置迁移等场景。agent 可以充分执行,但不会直接污染主目录。
文件沙箱可以设计成这样:
{
"sandboxId": "sbx_20260506_001",
"readRoots": ["/project/src", "/project/docs"],
"writeRoot": "/tmp/agent-sandbox/sbx_20260506_001",
"blockedPatterns": [".env", "*.key", "node_modules/**", "dist/**"],
"diffMode": "required_before_apply"
}
执行结束后生成变更清单:新增文件、修改文件、删除意图、风险提示。真正合并前必须有人看 diff。
二、接口沙箱要有测试 token
不要把正式 token 用在演练环境。测试 token 应该只能访问测试数据,只能调用允许的接口,并且所有返回都带环境标识。
工具层也要校验环境,避免 agent 把测试请求发到正式接口。
工具请求里建议强制带环境字段:
{
"tool": "updateTaskStatus",
"environment": "sandbox",
"sandboxId": "sbx_20260506_001",
"payload": {
"taskId": "task_fixture_01",
"status": "ready_for_review"
}
}
如果 environment=sandbox 却访问正式 host,Tool Gateway 应该直接拒绝。这个校验必须在工具层做,不能只靠 prompt。
三、外发动作默认模拟
邮件、通知、Webhook 等外发动作在沙箱中默认不真实发送,而是写入 outbox 记录。记录内容包括收件人、标题、正文摘要、触发原因和 traceId。
人工确认后,才允许进入真实发送流程。
outbox 记录至少包含这些字段:
| 字段 | 用途 |
|---|---|
| sandboxId | 关联演练批次 |
| channel | email / webhook / message |
| recipientPreview | 脱敏后的接收方 |
| payloadSummary | 外发内容摘要 |
| triggerReason | agent 为什么要发送 |
| confirmationRequired | 是否需要确认 |
| realSendBlocked | 是否已阻止真实发送 |
这样审核人员可以看到 agent 想发什么,但不会真的发出去。
四、数据快照要可重置
沙箱数据要能恢复到固定状态。否则每次测试后的残留数据都会影响下一轮结果。
常见做法:准备固定 fixture、每轮测试前重置数据库、写入操作记录到独立 schema、定期清空临时文件。
推荐用 fixture 描述“初始世界”:
{
"fixtureName": "content_review_flow_basic",
"users": [{ "id": "editor_01", "role": "editor" }],
"tasks": [{ "id": "task_fixture_01", "status": "draft" }],
"documents": [{ "id": "doc_rule_01", "title": "发布规则" }]
}
每次演练前重建 fixture,演练后保存 diff。这样不同 prompt 版本、模型版本、工具版本可以在同一组初始条件下比较。
五、沙箱报告要能支持发布决策
演练结束后,不要只输出“完成”。沙箱报告至少要包含:
- 运行了哪些任务
- 调用了哪些工具
- 哪些写入被模拟
- 哪些外发被拦截
- 是否触发权限拒绝
- diff 是否符合预期
- 成本和耗时
- 是否建议进入灰度
报告样例:
{
"sandboxId": "sbx_20260506_001",
"promptVersion": "brief-agent-v8",
"summary": {
"runs": 20,
"passed": 18,
"blockedUnsafeActions": 2,
"outboxItems": 5
},
"recommendation": "hold",
"reason": "2 个任务在信息不足时仍尝试外发通知"
}
这类报告能把“感觉可以上线”变成“哪些条件达标”。
六、失败案例:演练环境误用正式 Webhook
一个团队测试 agent 发布流程时,文件和数据库都使用测试环境,但 Webhook 地址仍是正式配置。一次演练触发了真实通知。
修复后,所有工具都必须读取统一环境配置,沙箱模式下外发动作只能写 outbox,无法访问正式 Webhook。团队还增加了发布前演练报告:只要出现真实外发 host,报告直接标记为阻断。
七、沙箱 Checklist
- 文件写入是否限制在临时目录
- 源文件是否默认只读
- 接口是否使用测试 token
- 外发动作是否进入 outbox
- 沙箱数据是否可重置
- 工具是否校验环境标识
- 演练结果是否能生成 diff 或报告
- Tool Gateway 是否强制校验环境
- outbox 是否阻止真实外发
- fixture 是否能重复构造同一初始状态
- 沙箱报告是否能支持发布决策
结语
AI agent 的沙箱环境不是降低效率,而是让团队更敢测试。把文件、接口、外发、数据快照和演练报告隔离清楚,agent 才能在上线前暴露问题,而不是在真实流程里制造风险。
延伸阅读:


