AgentSDK的沙箱系统提供安全隔离的代码执行环境,确保Agent执行的命令不会危害主机系统。
Agent可能会:
rm -rf /)┌────────────────────────────────────┐
│ 主机系统 │
│ ┌──────────────────────────────┐ │
│ │ AgentSDK Runtime │ │
│ │ │ │
│ │ ┌────────────────────────┐ │ │
│ │ │ Sandbox │ │ │
│ │ │ ┌──────────────────┐ │ │ │
│ │ │ │ Agent执行代码 │ │ │ │
│ │ │ │ (隔离环境) │ │ │ │
│ │ │ └──────────────────┘ │ │ │
│ │ │ - 限制文件访问 │ │ │
│ │ │ - 限制网络访问 │ │ │
│ │ │ - 限制资源使用 │ │ │
│ │ └────────────────────────┘ │ │
│ └──────────────────────────────┘ │
└────────────────────────────────────┘
AgentSDK支持三种沙箱执行模式,满足不同场景需求:
graph TB
subgraph 模式1: 会话级沙箱 - AgentSDK默认
A1[客户端发起任务] --> B1[Agent创建]
B1 --> C1[沙箱初始化]
C1 --> D1[任务1执行]
D1 --> E1[任务2执行]
E1 --> F1[任务N执行]
F1 --> G1[Agent关闭]
G1 --> H1[沙箱销毁]
end
subgraph 模式2: 任务级沙箱 - Manus模式
A2[客户端发起任务1] --> B2[创建沙箱1]
B2 --> C2[执行任务1]
C2 --> D2[销毁沙箱1]
E2[客户端发起任务2] --> F2[创建沙箱2]
F2 --> G2[执行任务2]
G2 --> H2[销毁沙箱2]
end
subgraph 模式3: 沙箱池模式 - 企业级优化
P1[沙箱池预热] --> P2[沙箱1-待命]
P1 --> P3[沙箱2-待命]
P1 --> P4[沙箱N-待命]
T1[任务1] --> P2
T2[任务2] --> P3
P2 --> R1[执行完成-归还池]
P3 --> R2[执行完成-归还池]
end
style 模式1 fill:#e1f5e1
style 模式2 fill:#ffe1e1
style 模式3 fill:#e1e5ff
| 模式 | 沙箱生命周期 | 适用场景 | 优点 | 缺点 |
|---|---|---|---|---|
| 会话级 | Agent创建→关闭 | 长对话、状态保留 | 无重复创建开销 保留执行上下文 | 长期占用资源 |
| 任务级 | 每个任务独立 | 高安全要求、无状态任务 | 完全隔离 无状态污染 | 冷启动延迟 成本较高 |
| 沙箱池 | 预热+复用 | 高并发、低延迟 | 极低延迟 资源利用率高 | 需要状态清理 管理复杂 |
AgentSDK支持多种沙箱后端:
| 沙箱类型 | 隔离级别 | 使用场景 | 性能 | 成本 |
|---|---|---|---|---|
| LocalSandbox | 进程级 | 开发测试 | 高 | 免费 |
| AliyunSandbox | 容器级 | 生产环境 | 中 | 按用量 |
| VolcengineSandbox | 容器级 | 生产环境 | 高 | 按用量 |
| MockSandbox | 无隔离 | 单元测试 | 极高 | 免费 |
ag, err := agent.Create(ctx, &types.AgentConfig{
Sandbox: &types.SandboxConfig{
Kind: types.SandboxKindLocal,
WorkDir: "./workspace",
},
}, deps)
ag, err := agent.Create(ctx, &types.AgentConfig{
Sandbox: &types.SandboxConfig{
Kind: types.SandboxKindLocal,
WorkDir: "/workspace",
Config: map[string]interface{}{
"use_docker": true,
"image": "golang:1.21",
"memory": "512m",
"cpu": "1.0",
},
},
}, deps)
ag, err := agent.Create(ctx, &types.AgentConfig{
Sandbox: &types.SandboxConfig{
Kind: types.SandboxKindAliyun,
WorkDir: "/workspace",
Config: map[string]interface{}{
"region": "cn-hangzhou",
"access_key": os.Getenv("ALIYUN_ACCESS_KEY_ID"),
"secret_key": os.Getenv("ALIYUN_ACCESS_KEY_SECRET"),
// 可选配置
"timeout": 300, // 超时时间(秒)
"memory_limit": 1024, // 内存限制(MB)
"cpu_limit": 2.0, // CPU限制(核心数)
"network_mode": "restricted", // 网络模式
},
},
}, deps)
# .env文件
export ALIYUN_ACCESS_KEY_ID="your-access-key"
export ALIYUN_ACCESS_KEY_SECRET="your-secret-key"
export ALIYUN_REGION="cn-hangzhou"
graph TB
subgraph 客户端环境
APP[应用程序] --> SDK[AgentSDK Runtime]
end
subgraph AgentSDK Runtime
SDK --> AGENT[Agent实例]
AGENT --> MW[中间件栈]
AGENT --> EXEC[工具执行器]
end
subgraph 阿里云
EXEC -->|HTTPS API| AGENTBAY[AgentBay服务]
AGENTBAY --> FC[函数计算]
FC --> CONTAINER1[容器实例1]
FC --> CONTAINER2[容器实例2]
FC --> CONTAINERN[容器实例N]
CONTAINER1 --> FS1[文件系统]
CONTAINER1 --> NET1[网络]
FS1 --> OSS[OSS对象存储]
NET1 --> VPC[VPC网络]
end
subgraph 安全边界
AGENTBAY --> IAM[访问控制<br/>AccessKey/SecretKey]
FC --> LIMIT[资源限制<br/>CPU/内存/磁盘]
NET1 --> FW[安全组<br/>流量控制]
end
style 客户端环境 fill:#e1f5e1
style AgentSDK Runtime fill:#fff4e1
style 阿里云 fill:#e1e5ff
style 安全边界 fill:#ffe1e1
ag, err := agent.Create(ctx, &types.AgentConfig{
Sandbox: &types.SandboxConfig{
Kind: types.SandboxKindVolcengine,
WorkDir: "/workspace",
Config: map[string]interface{}{
"region": "cn-beijing",
"access_key_id": os.Getenv("VOLC_ACCESS_KEY_ID"),
"secret_access_key": os.Getenv("VOLC_SECRET_ACCESS_KEY"),
// 可选配置
"instance_type": "standard", // standard/performance
"timeout": 600,
"auto_destroy": true,
},
},
}, deps)
mockSandbox := sandbox.NewMockSandbox()
// 预设命令返回
mockSandbox.SetOutput("ls", "file1.txt\nfile2.txt\n")
mockSandbox.SetOutput("cat README.md", "# Hello\n...")
ag, err := agent.Create(ctx, &types.AgentConfig{
Sandbox: &types.SandboxConfig{
Kind: types.SandboxKindMock,
},
}, &agent.Dependencies{
SandboxFactory: func() sandbox.Sandbox {
return mockSandbox
},
// ...
})
func TestAgentWithMockSandbox(t *testing.T) {
mock := sandbox.NewMockSandbox()
mock.SetOutput("go test", "PASS\nok\t...")
ag, _ := agent.Create(ctx, config, &agent.Dependencies{
SandboxFactory: func() sandbox.Sandbox {
return mock
},
})
result, _ := ag.Chat(ctx, "运行测试")
assert.Contains(t, result.Text, "测试通过")
}
下图展示了从客户端发起请求到沙箱执行完成的完整交互流程:
sequenceDiagram
autonumber
participant C as 客户端
participant A as Agent
participant M as 中间件栈
participant E as 工具执行器
participant S as 沙箱
participant R as 云端沙箱<br/>(Aliyun/Volcengine)
C->>A: Chat("列出当前目录文件")
activate A
A->>M: WrapModelCall()
activate M
Note over M: 文件系统中间件<br/>子Agent中间件<br/>总结中间件
M->>A: LLM响应(需要调用bash工具)
deactivate M
A->>E: 调用bash工具
activate E
E->>E: 解析参数<br/>构造Command
alt 本地沙箱
E->>S: Execute(ls -la)
activate S
S->>S: 进程隔离执行
S-->>E: Result{Stdout, ExitCode}
deactivate S
else 云端沙箱
E->>R: 发起远程调用
activate R
R->>R: 容器启动(~2s)
R->>R: 执行命令
R-->>E: Result{Stdout, ExitCode}
deactivate R
end
E-->>A: 工具执行结果
deactivate E
A->>M: WrapModelCall(带工具结果)
activate M
M->>A: LLM最终响应
deactivate M
A-->>C: 流式返回结果
deactivate A
| 阶段 | 本地沙箱耗时 | 云端沙箱耗时 | 说明 |
|---|---|---|---|
| 1-3 LLM推理 | ~500ms | ~500ms | 第一次模型调用 |
| 4-6 工具准备 | ~10ms | ~10ms | 参数解析和验证 |
| 7-9 沙箱执行 | ~50ms | ~2s | 云端需要冷启动 |
| 10-12 LLM响应 | ~300ms | ~300ms | 第二次模型调用 |
| 总耗时 | ~860ms | ~2.8s | - |
ls)可缓存结果type Sandbox interface {
// 执行命令
Execute(ctx context.Context, cmd *Command) (*Result, error)
// 文件操作
ReadFile(ctx context.Context, path string) ([]byte, error)
WriteFile(ctx context.Context, path string, content []byte) error
ListFiles(ctx context.Context, path string) ([]FileInfo, error)
// 生命周期
Start(ctx context.Context) error
Stop(ctx context.Context) error
Health(ctx context.Context) error
}
type Command struct {
Command string // 命令字符串
Args []string // 参数
Env map[string]string // 环境变量
WorkDir string // 工作目录
Timeout time.Duration // 超时时间
StdinData []byte // 标准输入
}
type Result struct {
Stdout string // 标准输出
Stderr string // 标准错误
ExitCode int // 退出码
Duration time.Duration // 执行时长
Error error // 错误(如有)
}
// Agent执行bash命令
ag.Chat(ctx, `
运行以下Go程序:
go run main.go
然后告诉我输出是什么
`)
沙箱中执行:
$ go run main.go
Hello, World!
// Agent操作文件
ag.Chat(ctx, `
1. 创建一个hello.txt文件
2. 写入"Hello AgentSDK"
3. 读取并验证内容
`)
沙箱操作:
$ echo "Hello AgentSDK" > /workspace/hello.txt
$ cat /workspace/hello.txt
Hello AgentSDK
// Agent安装依赖
ag.Chat(ctx, `
安装所需的Python包:
pip install requests beautifulsoup4
然后运行scraper.py
`)
// Agent运行测试
ag.Chat(ctx, `
运行所有单元测试:
go test ./...
如果有失败,分析原因
`)
Sandbox: &types.SandboxConfig{
Kind: types.SandboxKindAliyun,
Config: map[string]interface{}{
// CPU限制
"cpu_limit": 2.0, // 2个CPU核心
"cpu_request": 1.0, // 请求1个核心
// 内存限制
"memory_limit": 2048, // 2GB
"memory_request": 1024, // 请求1GB
// 磁盘限制
"disk_limit": 10240, // 10GB
// 超时限制
"timeout": 600, // 10分钟
"idle_timeout": 300, // 空闲5分钟自动销毁
},
}
Config: map[string]interface{}{
// 网络模式
"network_mode": "restricted", // none/restricted/full
// 允许的域名白名单
"allowed_domains": []string{
"api.github.com",
"registry.npmjs.org",
},
// 禁止的域名黑名单
"blocked_domains": []string{
"*.internal.com",
},
// 代理配置
"http_proxy": "http://proxy.example.com:8080",
}
Config: map[string]interface{}{
// 挂载卷
"volumes": []map[string]string{
{
"source": "/host/data",
"target": "/workspace/data",
"readonly": false,
},
},
// 状态持久化
"persistent_volume": "/mnt/agent-state",
"restore_on_start": true,
}
Config: map[string]interface{}{
// 自定义镜像
"image": "my-registry.com/agent-runtime:v1.0",
// 镜像拉取策略
"image_pull_policy": "IfNotPresent", // Always/IfNotPresent/Never
// 镜像凭据
"image_pull_secrets": []string{"my-registry-secret"},
}
Config: map[string]interface{}{
// 只读挂载
"readonly_paths": []string{
"/etc",
"/usr",
},
// 禁止访问
"blocked_paths": []string{
"/proc",
"/sys",
},
// 临时目录
"temp_dir": "/tmp/agent",
"auto_clean_temp": true,
}
Config: map[string]interface{}{
// 允许的命令
"allowed_commands": []string{
"ls", "cat", "echo",
"go", "python3", "node",
"git", "npm", "pip",
},
// 禁止的命令
"blocked_commands": []string{
"rm", "dd", "mkfs",
"sudo", "su",
},
}
Config: map[string]interface{}{
// 允许传递的环境变量
"env_whitelist": []string{
"PATH",
"HOME",
"LANG",
},
// 禁止的环境变量
"env_blacklist": []string{
"AWS_*",
"GITHUB_TOKEN",
},
}
// 订阅Monitor通道获取沙箱事件
monitorCh := ag.Subscribe([]types.AgentChannel{
types.ChannelMonitor,
}, nil)
for envelope := range monitorCh {
if e, ok := envelope.Event.(*types.MonitorSandboxExecutionEvent); ok {
log.Printf("沙箱执行: Command=%s Duration=%v ExitCode=%d",
e.Command, e.Duration, e.ExitCode)
}
}
type MonitorSandboxResourceEvent struct {
CPUUsage float64 // CPU使用率
MemoryUsage int64 // 内存使用(字节)
DiskUsage int64 // 磁盘使用(字节)
NetworkIn int64 // 网络入(字节)
NetworkOut int64 // 网络出(字节)
}
Config: map[string]interface{}{
// 资源告警阈值
"alert_cpu_threshold": 80.0, // CPU使用率超过80%
"alert_memory_threshold": 90.0, // 内存使用率超过90%
"alert_disk_threshold": 95.0, // 磁盘使用率超过95%
// 告警回调
"alert_webhook": "https://alerts.example.com/webhook",
}
// 开发环境
if os.Getenv("ENV") == "development" {
sandboxKind = types.SandboxKindLocal
}
// 测试环境
if os.Getenv("ENV") == "test" {
sandboxKind = types.SandboxKindMock
}
// 生产环境
if os.Getenv("ENV") == "production" {
sandboxKind = types.SandboxKindAliyun
}
Config: map[string]interface{}{
// 短任务
"timeout": 30, // 30秒
// 长任务(编译、测试)
"timeout": 600, // 10分钟
// 批量处理
"timeout": 3600, // 1小时
}
Config: map[string]interface{}{
"auto_clean": true,
"clean_on_stop": true,
"max_disk_usage": 5 * 1024 * 1024 * 1024, // 5GB
}
result, err := sandbox.Execute(ctx, cmd)
if err != nil {
// 检查错误类型
if errors.Is(err, context.DeadlineExceeded) {
log.Println("命令超时")
} else if errors.Is(err, sandbox.ErrResourceLimit) {
log.Println("资源限制")
} else {
log.Printf("执行失败: %v", err)
}
return err
}
// 检查退出码
if result.ExitCode != 0 {
log.Printf("命令失败: %s", result.Stderr)
}
// 复用沙箱实例
type SandboxPool struct {
pool chan sandbox.Sandbox
}
func (p *SandboxPool) Get() sandbox.Sandbox {
select {
case sb := <-p.pool:
return sb
default:
return sandbox.New()
}
}
func (p *SandboxPool) Put(sb sandbox.Sandbox) {
select {
case p.pool <- sb:
default:
sb.Stop(context.Background())
}
}