使用 Sandbox 部署 Agent
概述
本文以一个可以被外部调用的 Agent 服务为例,介绍如何在百度智能云 智能体沙箱-Sandbox 中完成从模板构建、实例创建,到服务访问、数据持久化和实例回收的完整流程。
Sandbox 兼容 E2B SDK,可以按需使用 CVENI 访问用户 VPC、平台持久化存储、CFS 共享存储,以及固定域名访问沙箱内的自定义端口。
一、准备工作
1. 安装 SDK
建议使用 e2b python sdk 使用,建议版本如下:
| 类型 | 建议版本 |
|---|---|
| e2b | 2.21.1 |
| e2b-code-interpreter | 2.6.2 |
| e2b-desktop | 2.3.1 |
1pip install e2b==2.21.1 e2b-code-interpreter==2.6.2 e2b-desktop==2.3.1
2. 创建 API Key
在 Sandbox 控制台 创建 API Key,并将 Key 安全注入运行环境。不要把真实 Key 写入代码仓库、镜像或日志。
1import os
2os.environ["E2B_DOMAIN"] = "sandbox-execute.gz.baidubce.com" # 替换为实际地域
3os.environ["E2B_API_KEY"] = "bce-v3/YOUR_API_KEY" # 替换为控制台创建的 API Key
请将域名替换成您的实际地域:
北京地域域名: sandbox-execute.bj.baidubce.com
广州地域域名:sandbox-execute.gz.baidubce.com
苏州地域域名: sandbox-execute.su.baidubce.com

3. 选择资源规格
在构建自定义模板时,需要根据 Agent 的负载特征选择合理的 CPU 和内存配比。CPU 与内存的比值支持 1:1、1:2、1:4。
| CPU (核) | 内存 (MiB) | 适用场景 |
|---|---|---|
| 2 | 2048 | 轻量脚本、纯文本处理 Agent |
| 2 | 4096 | 中等负载,含 LLM API 调用 |
| 4 | 4096 | 并发工具调用、多线程 Agent |
| 4 | 8192 | 浏览器自动化(browser-use)、多工具并发 |
| 8 | 8192 | 高并发 Agent |
建议:先以 2C4G 跑压测,再按实测峰值向上选择,避免过度配置导致成本浪费。
二、构建自定义模板
基于官方模板或自有镜像构建,将 Agent 依赖预打包到模板中,可大幅缩短沙箱冷启动时间。
2.1 基于官方模板扩展
1from e2b import Template
2import os
3
4os.environ["E2B_DOMAIN"] = "sandbox-execute.gz.baidubce.com"
5os.environ["E2B_API_KEY"] = "bce-v3/YOUR_API_KEY"
6
7template = (
8 Template()
9 .from_template("code-interpreter-v1") # 官方基础模板
10 .run_cmd("pip install openai langchain faiss-cpu") # 预装 Agent 依赖
11 .run_cmd("useradd -m -s /bin/bash agent") # 创建运行用户(可选)
12 .set_user("agent") # 设置默认用户
13
14
15)
16
17build = Template.build_in_background(
18 template,
19 alias="my-agent-template", # 自定义模板 ID,后续创建沙箱时使用
20 cpu_count=4,
21 memory_mb=4096,
22)
23
24print(f"template_id: {build.template_id}")
25print(f"build_id: {build.build_id}")
2.2 基于私有镜像构建
1template = (
2 Template()
3 .from_image(
4 image="ccr-XXXXX-pub.cnc.gz.baidubce.com/YOUR_REPO/agent:v1", # 镜像当中需要包含bash
5 username="YOUR_USERNAME", # 私有仓库需要填写,公开仓库可省略
6 password="YOUR_PASSWORD",
7 )
8)
9
10build = Template.build_in_background(
11 template,
12 alias="my-agent-from-image",
13 cpu_count=4,
14 memory_mb=4096,
15)
提示:构建状态可在 CFC 控制台的"模版-自定义模板"页面查看(
ready/building/error)。构建完成前创建沙箱会使用上一次成功的构建,后续将移动至 AX 控制台。
三、判断网络需求(是否打通用户 VPC)
不需要访问用户 VPC 内部资源
- 直接跳过本步骤,使用平台公网出口即可。
需要访问用户 VPC 内部资源(如私有数据库、内网 API)
- 通过 CVENI(CrossVPCEni)将沙箱的默认出口路由到用户 VPC,在创建沙箱时指定以下 metadata:
1sandbox = Sandbox.create(
2 template="my-agent-template",
3 timeout=3600,
4 metadata={
5 # CVENI 网络配置
6 "baidubce_subnetId": "sbn-YOUR_SUBNET_ID",
7 "baidubce_securityGroupId": "g-YOUR_SG_ID",
8 # 不需要走用户 VPC 的 CIDR(集群内流量保持走 eth0)
9 "baidubce_defaultRouteExcludedCidrs": "100.79.8.0/21, 5.0.0.0/8",
10 },
11)
| 参数 | 说明 |
|---|---|
baidubce_subnetId |
用户 VPC 子网 ID,沙箱的跨 VPC 网卡将绑定到此子网 |
baidubce_securityGroupId |
普通安全组 ID,控制跨 VPC 出入方向流量 |
baidubce_defaultRouteExcludedCidrs |
不走用户 VPC 的 CIDR 列表,集群内通信必须排除 |
前置条件:
- API Key 的所属用户需与 VPC 属于同一百度云账号。
若沙箱同时需要访问公网,需在用户 VPC 中完成以下操作:
- 购买 EIP 并绑定 NAT 网关;
- 在 VPC 路由表中为沙箱所在子网添加默认路由(
0.0.0.0/0),下一跳指向 NAT 网关,使该子网的出口流量经 NAT 访问公网。
四、判断存储需求
根据 Agent 的数据访问模式选择合适的存储方案:
1Agent 需要持久化自身数据(依赖包、模型权重、会话状态)?
2├─ 是 → 使用平台原生持久化(data_persistence 模式)→ 第 4.1 节
3│ └─ CFS(跨实例共享,适合多沙箱共享模型文件)
4│
5│
6└─ 否
7 │
8 多个沙箱需要共享同一份数据?
9 ├─ 是 → 在沙箱内手动挂载 CFS → 第 4.2 节
10 └─ 否 → 无需额外存储配置,直接创建沙箱
4.1 使用平台原生持久化
data_persistence 模式将容器可写层绑定到共享存储,pause/resume 后磁盘数据完整保留。注意模板/镜像升级会导致数据丢失。
1from e2b_code_interpreter import Sandbox
2
3sandbox = Sandbox.create(
4 template="my-agent-template",
5 timeout=1800, # 30 分钟无活动后触发 on_timeout
6 metadata={
7 "baidubce_persistenceMode": "data_persistence",
8 "baidubce_dataPersistenceSizeGb": "10", # 可写层大小,范围为 [1, 100] GiB
9 },
10 lifecycle={
11 "on_timeout": "pause", # 超时后自动暂停,而不是销毁
12 },
13)
14
15 # 务必保存 sandbox_id,后续恢复沙箱时需要使用
16sandbox_id = sandbox.sandbox_id
17print(f"sandbox_id: {sandbox_id}")
恢复沙箱:
1from e2b_code_interpreter import Sandbox
2
3 # 使用之前保存的 sandbox_id 重新连接沙箱
4sandbox = Sandbox.connect(
5 sandbox_id,
6 timeout=1800,
7)
注意:
data_persistence仅保留文件系统,不保留进程和内存。resume 后容器重新冷启动,已写入磁盘的内容(已装的包、数据文件等)仍然存在。
4.2 在沙箱内手动挂载 CFS(共享存储)
适用于多个沙箱实例共享同一份数据(如预置的工具包、共享知识库)的场景。需要先打通用户 VPC(参考第三步)。
1import time
2
3sandbox = Sandbox.create(
4 template="my-agent-template",
5 timeout=3600,
6 metadata={
7 "baidubce_subnetId": "sbn-YOUR_SUBNET_ID",
8 "baidubce_securityGroupId": "g-YOUR_SG_ID",
9 "baidubce_defaultRouteExcludedCidrs": "100.79.8.0/21, 5.0.0.0/8",
10 },
11)
12
13 # 挂载 CFS(挂载点的 VPC 子网需与创建沙箱的 subnetId 保持一致)
14sandbox.commands.run(
15 "mkdir -p /mnt/shared && "
16 "mount -t nfs4 -o minorversion=1,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2,noresvport "
17 "cfs-XXXXX.lb-XXXXX.cfs.bj.baidubce.com:/shared /mnt/shared",
18 user="root",
19)
20print("CFS 挂载成功")
五、创建沙箱实例
将前几步的参数组合,完整创建示例如下。根据实际需求选择对应的参数组合即可。
场景 A:纯公网 Agent,无持久化需求
1import os
2from e2b_code_interpreter import Sandbox
3
4os.environ["E2B_DOMAIN"] = "sandbox-execute.gz.baidubce.com"
5os.environ["E2B_API_KEY"] = "bce-v3/YOUR_API_KEY"
6
7sandbox = Sandbox.create(
8 template="my-agent-template",
9 timeout=3600,
10)
场景 B:需要访问用户 VPC + 本地文件持久化
1sandbox = Sandbox.create(
2 template="my-agent-template",
3 timeout=1800,
4 metadata={
5 # 网络:打通用户 VPC
6 "baidubce_subnetId": "sbn-YOUR_SUBNET_ID",
7 "baidubce_securityGroupId": "g-YOUR_SG_ID",
8 "baidubce_defaultRouteExcludedCidrs": "100.79.8.0/21, 5.0.0.0/8",
9 # 存储:可写层持久化
10 "baidubce_persistenceMode": "data_persistence",
11 "baidubce_dataPersistenceSizeGb": "50",
12 },
13 lifecycle={
14 "on_timeout": "pause",
15 },
16)
17sandbox_id = sandbox.sandbox_id
场景 C:多 Agent 共享模型文件(CFS 挂载)
1sandbox = Sandbox.create(
2 template="my-agent-template",
3 timeout=3600,
4 metadata={
5 "baidubce_subnetId": "sbn-YOUR_SUBNET_ID",
6 "baidubce_securityGroupId": "g-YOUR_SG_ID",
7 "baidubce_defaultRouteExcludedCidrs": "100.79.8.0/21, 5.0.0.0/8",
8 },
9)
10
11 # 挂载共享存储
12sandbox.commands.run(
13 "mount -t nfs4 -o minorversion=1,rsize=1048576,wsize=1048576,hard,timeo=600,retrans=2,noresvport "
14 "cfs-XXXXX.lb-XXXXX.cfs.bj.baidubce.com:/models /mnt/models",
15 user="root",
16)
六、文件操作与命令执行
沙箱就绪后,通过 e2b SDK 进行交互。
命令执行
1 # 同步执行,等待结果
2result = sandbox.commands.run(
3 "python3 /app/run_task.py --input /data/input.json",
4 user="root",
5 timeout=300,
6)
7print(result.stdout)
8print(result.stderr)
9
10 # 流式输出(适合长时任务)
11sandbox.commands.run(
12 "python3 /app/long_task.py",
13 user="root",
14 on_stdout=lambda line: print("OUT:", line),
15 on_stderr=lambda line: print("ERR:", line),
16)
17
18 # 后台启动服务(不等待结束)
19sandbox.commands.run(
20 "python3 /app/agent_server.py --port 8080",
21 user="root",
22 background=True,
23 timeout=0,
24)
文件操作
1 # 写入文件
2sandbox.files.write("/data/config.json", '{"model": "gpt-4", "max_tokens": 2048}', user="root")
3
4 # 读取文件
5content = sandbox.files.read("/data/output.txt", user="root")
6print(content)
7
8 # 列目录
9files = sandbox.files.list("/data", user="root")
10for f in files:
11 print(f.name, f.size)
12
13 # 检查文件是否存在
14exists = sandbox.files.exists("/data/result.json", user="root")
15
16 # 创建目录
17sandbox.files.make_dir("/data/workspace", user="root")
七、访问沙箱内的服务
沙箱内的自定义服务可通过固定域名从外部访问,格式为:
1<port>-<sandbox-id>.<region>.sandbox-execute.baidubce.com
获取访问地址
1 # 获取沙箱内 8080 端口的外部访问地址
2host = sandbox.get_host(8080)
3service_url = f"https://{host}"
4print(f"Agent 服务地址: {service_url}")
5
6 # 获取访问 Token(访问用户自定义服务时需要添加到请求头)
7access_token = sandbox.get_info()._envd_access_token
8
9import requests
10resp = requests.post(
11 f"{service_url}/v1/chat",
12 headers={
13 "X-Access-Token": access_token,
14 "Content-Type": "application/json",
15 },
16 json={"message": "你好"},
17)
18print(resp.json())
域名规则说明
| 组成部分 | 示例值 | 说明 |
|---|---|---|
<port> |
8080 |
沙箱内监听的端口号 |
<sandbox-id> |
sbx-abc123 |
沙箱唯一 ID,由创建接口返回 |
<region> |
gz / bj / su |
沙箱所在地域 |
注意:访问用户自定义服务时,需要在请求头中携带
X-Access-Token,否则返回 403。e2b SDK 的commands.run和files操作无需手动携带 Token,SDK 会自动注入。
完整示例
以下展示了一个完整的 Agent 部署流程,包含 VPC 打通和持久化:
1import os
2import time
3import requests
4from e2b_code_interpreter import Sandbox
5from e2b.sandbox.commands.command_handle import CommandExitException
6
7os.environ["E2B_DOMAIN"] = "sandbox-execute.bj.baidubce.com"
8os.environ["E2B_API_KEY"] = "bce-v3/YOUR_API_KEY"
9
10 # ── 1. 创建沙箱实例 ──────────────────────────────────────────────
11sandbox = Sandbox.create(
12 template="my-agent-template",
13 timeout=1800,
14 metadata={
15 # 打通用户 VPC
16 "baidubce_subnetId": "sbn-YOUR_SUBNET_ID",
17 "baidubce_securityGroupId": "g-YOUR_SG_ID",
18 "baidubce_defaultRouteExcludedCidrs": "100.79.8.0/21, 5.0.0.0/8",
19 # 可写层持久化
20 "baidubce_persistenceMode": "data_persistence",
21 "baidubce_dataPersistenceSizeGb": "50",
22 },
23 lifecycle={"on_timeout": "pause"},
24)
25
26sandbox_id = sandbox.sandbox_id
27print(f"[OK] 沙箱已创建: {sandbox_id}")
28
29 # ── 2. 等待 Agent 服务就绪 ───────────────────────────────────
30def wait_for_service(sandbox, port, timeout=60):
31 deadline = time.time() + timeout
32 while time.time() < deadline:
33 try:
34 result = sandbox.commands.run(
35 f"ss -tuln | grep -q ':{port}' && echo ready",
36 user="root",
37 )
38 if "ready" in result.stdout:
39 return
40 except CommandExitException:
41 pass
42 time.sleep(2)
43 raise TimeoutError(f"服务端口 {port} 在 {timeout}s 内未就绪")
44
45wait_for_service(sandbox, 8080)
46print("[OK] Agent 服务就绪")
47
48 # ── 3. 获取访问地址和 Token ──────────────────────────────────
49host = sandbox.get_host(8080)
50token = sandbox.get_info()._envd_access_token
51service_url = f"https://{host}"
52print(f"[OK] 服务地址: {service_url}")
53
54 # ── 4. 调用 Agent ────────────────────────────────────────────
55resp = requests.post(
56 f"{service_url}/v1/run",
57 headers={"X-Access-Token": token, "Content-Type": "application/json"},
58 json={"task": "分析最近一周的销售数据并生成摘要"},
59 timeout=120,
60)
61print(resp.json())
62
63 # ── 5. 下载结果文件 ──────────────────────────────────────────
64result_content = sandbox.files.read("/data/output/summary.md", user="root")
65print(result_content)
66
67 # ── 6. sandbox_id 持久化到业务系统,以便后续恢复 ────────────
68 # db.save(user_id, sandbox_id) # 由业务系统自行实现
注意事项
- 保存 sandbox_id:使用
data_persistence模式时,sandbox_id 是恢复沙箱的唯一凭据,务必在业务系统中持久化。 - 超时与 pause:
timeout指沙箱最后一次活动到触发on_timeout的时间(秒),建议结合实际 Agent 任务时长设置,避免任务执行期间被误 pause。 - CFS 挂载点与 VPC 一致性:手动挂载 CFS 时,CFS 挂载点所在 VPC必须与
baidubce_subnetId所在 vpc 保持一致。 - 自定义模板限制:每个用户默认最多创建 5 个自定义模板,最多同时存在 2 个构建任务。
- 访问 Token:通过
sandbox.get_host(port)获取的地址访问用户自定义服务时,请求头中必须携带X-Access-Token,SDK 内置的commands和files接口无需手动处理。
评价此篇文章
