使用 OpenAI Agents SDK 与 Modal Sandboxes 运行可执行代理
很多代理应用卡在同一个问题上:模型会规划,但真正需要读文件、改代码、跑命令、产出文件时,执行环境往往和代理逻辑混在一起。结果是权限边界不清晰,状态难追踪,工程上也不容易扩展。
OpenAI Agents SDK 的沙箱执行模式把这两个层次拆开了:
- 编排层:保留在主应用中,负责模型调用、代理决策和流程控制
- 执行层:放进隔离的 sandbox,负责文件访问、命令执行和产物生成
这种拆分适合需要“真正动手”的代理场景,例如:
- 检查项目目录
- 读取和修改源码
- 运行测试
- 生成构建产物
- 基于文件系统内容作答
这里采用 Modal Sandboxes 作为执行后端,构建一个可实际运行的 Python 示例,让代理在隔离环境里查看项目文件并给出基于工作区内容的回答。
OpenAI Agents SDK 沙箱能力带来了什么
Agents SDK 的沙箱能力不是简单地给模型加几个工具,而是把“代理”和“工作区”作为一等概念暴露出来。
关键能力包括:
| 能力 | 作用 |
|---|---|
| 原生 sandbox 支持 | 让代理运行在隔离环境中 |
Manifest |
定义代理可见的文件、目录与输出 |
SandboxAgent |
将代理绑定到真实工作区 |
SandboxRunConfig |
控制一次运行所使用的沙箱会话 |
| 类 Codex 工具 | 支持文件编辑、shell 命令、项目检查 |
| MCP 支持 | 连接外部工具与服务 |
Skills 与 AGENTS.md 支持 |
为代理补充更明确的项目约束 |
| 多提供方支持 | 可切换 Modal、E2B、Cloudflare、Daytona、Blaxel、Runloop、Vercel |
工程上的核心价值很明确:应用负责决策,沙箱负责执行。不可信、不可预期或高副作用的动作,不直接发生在主进程里。
运行前准备
需要安装以下依赖:
pip install "openai-agents[modal]" modal
还需要两个账户:
- OpenAI 账户:用于调用模型 API,需要可用额度,并确保账户已完成验证以访问支持的模型
- Modal 账户:用于创建隔离执行环境,免费额度足够测试
配置 OpenAI API Key。
macOS 或 Linux:
export OPENAI_API_KEY="your_openai_api_key"
Windows PowerShell:
$env:OPENAI_API_KEY="your_openai_api_key"
本地登录 Modal:
modal setup
执行后会打开浏览器登录并生成 token。完成授权后,凭据会被写入本地环境。
示例目标
下面构建一个小型支持工单分流项目。代理需要先检查工作区中的文件,再回答这个服务做什么,以及发布前需要确认什么。
工作区里放入三个文件:
README.mdsrc/app.pydocs/release-checks.md
这类结构足以说明 Manifest 的作用:代理并不是只靠提示词回答,而是基于一个真实项目目录进行检查和推理。
定义沙箱工作区
先创建 main.py,导入需要的模块:
import asyncio
from agents import ModelSettings, Runner
from agents.run import RunConfig
from agents.sandbox import Manifest, SandboxAgent, SandboxRunConfig
from agents.sandbox.entries import File
from agents.extensions.sandbox import ModalSandboxClient, ModalSandboxClientOptions
然后定义工作区内容:
manifest = Manifest(
entries={
"README.md": File(
content=(
b"# Support Ticket Triage\n\n"
b"Small service that labels customer tickets by urgency and team.\n"
)
),
"src/app.py": File(
content=(
b"def route_ticket(subject: str, customer_tier: str) -> dict:\n"
b" urgent = customer_tier == \"enterprise\" or \"outage\" in subject.lower()\n"
b" return {\n"
b" \"priority\": \"high\" if urgent else \"normal\",\n"
b" \"team\": \"support-ops\" if urgent else \"customer-care\",\n"
b" }\n"
)
),
"docs/release-checks.md": File(
content=(
b"# Release Checks\n\n"
b"- Confirm routing rules match the current support escalation policy.\n"
)
),
}
)
这里的 Manifest 定义了沙箱内存在的文件系统视图。代理能看到什么、检查什么、修改什么,都从这里开始。
这个例子中的项目逻辑很简单:
README.md说明服务用途src/app.py包含工单分流逻辑docs/release-checks.md给出发布检查项
创建绑定工作区的代理
接着创建 SandboxAgent:
agent = SandboxAgent(
name="Modal Sandbox Assistant",
model="gpt-5.4-mini",
instructions=(
"You are a coding assistant reviewing a small production service. "
"Inspect the sandbox workspace before answering. "
"Keep the answer short and practical."
),
default_manifest=manifest,
model_settings=ModelSettings(tool_choice="required"),
)
这里有几个关键点:
SandboxAgent
普通代理可以只依赖上下文文本,而 SandboxAgent 面向真实工作区。它能检查文件、理解目录结构,并结合沙箱内容作答。
default_manifest=manifest
把前面定义的工作区直接绑定到代理默认运行环境中。
tool_choice="required"
这一项很重要。它要求模型优先使用可用工具,而不是仅凭记忆或提示词上下文直接输出。对于需要读文件、看代码的任务,这是更稳妥的设置。
模型选择
示例使用 gpt-5.4-mini,目标是更快返回结果。如果任务涉及更多文件编辑、测试执行和长链路操作,模型速度与成本需要单独权衡。
创建 Modal 沙箱客户端
代理需要一个实际的沙箱提供方。这里选用 Modal。
client = ModalSandboxClient()
options = ModalSandboxClientOptions(
app_name="openai-agents-modal-demo",
workspace_persistence="tar",
)
参数含义如下:
ModalSandboxClient():指定 Modal 为沙箱后端app_name="openai-agents-modal-demo":在 Modal 中显示的应用名workspace_persistence="tar":控制工作区文件在运行过程中的打包与持久化方式
如果未来切换到其他沙箱提供方,整体代理代码通常不需要大改,主要替换的是对应的 client 实现。
启动沙箱会话
基于 manifest 创建沙箱,并启动会话:
sandbox = await client.create(
manifest=manifest,
options=options,
)
await sandbox.start()
这一步之后,一个隔离的 Modal 工作区已经在线,里面包含预先定义的三个文件。接下来的文件检查、命令执行、代码修改,都发生在这个环境里,而不是本地宿主机。
在沙箱中运行代理
把活动中的沙箱会话传给 SandboxRunConfig,再通过 Runner.run() 启动一次代理执行:
result = await Runner.run(
agent,
(
"Explain what this service does and name one production check "
"before release. Keep it under 3 sentences."
),
run_config=RunConfig(
sandbox=SandboxRunConfig(session=sandbox),
workflow_name="Modal sandbox example",
),
)
print(result.final_output)
这里的职责边界很清晰:
- 模型负责理解任务与生成回答
SandboxRunConfig告诉 SDK:本次运行要使用哪个沙箱会话- 沙箱提供真实文件系统与执行环境
workflow_name用于标识这次运行流程
如果一切正常,输出会类似下面这样:
This service triages customer support tickets by assigning urgency and routing them to the right team. One production check before release is to confirm the routing rules still match the current support escalation policy.
这个回答不是仅靠提示词推测出来的,而是建立在工作区文件内容之上。
清理沙箱资源
运行结束后应主动关闭并删除沙箱,避免无用会话继续占用计算资源。
await client.aclose(sandbox)
更稳妥的方式是放进 finally 块里,确保异常情况下也会清理。
完整脚本
下面是完整可运行示例:
import asyncio
from agents import ModelSettings, Runner
from agents.extensions.sandbox import ModalSandboxClient, ModalSandboxClientOptions
from agents.run import RunConfig
from agents.sandbox import Manifest, SandboxAgent, SandboxRunConfig
from agents.sandbox.entries import File
async def main():
manifest = Manifest(
entries={
"README.md": File(
content=(
b"# Support Ticket Triage\n\n"
b"Small service that labels customer tickets by urgency and team.\n"
)
),
"src/app.py": File(
content=(
b"def route_ticket(subject: str, customer_tier: str) -> dict:\n"
b" urgent = customer_tier == \"enterprise\" or \"outage\" in subject.lower()\n"
b" return {\n"
b" \"priority\": \"high\" if urgent else \"normal\",\n"
b" \"team\": \"support-ops\" if urgent else \"customer-care\",\n"
b" }\n"
)
),
"docs/release-checks.md": File(
content=(
b"# Release Checks\n\n"
b"- Confirm routing rules match the current support escalation policy.\n"
)
),
}
)
agent = SandboxAgent(
name="Modal Sandbox Assistant",
model="gpt-5.4-mini",
instructions=(
"You are a coding assistant reviewing a small production service. "
"Inspect the sandbox workspace before answering. "
"Keep the answer short and practical."
),
default_manifest=manifest,
model_settings=ModelSettings(tool_choice="required"),
)
client = ModalSandboxClient()
options = ModalSandboxClientOptions(
app_name="openai-agents-modal-demo",
workspace_persistence="tar",
)
sandbox = await client.create(
manifest=manifest,
options=options,
)
await sandbox.start()
try:
result = await Runner.run(
agent,
(
"Explain what this service does and name one production check "
"before release. Keep it under 3 sentences."
),
run_config=RunConfig(
sandbox=SandboxRunConfig(session=sandbox),
workflow_name="Modal sandbox example",
),
)
print(result.final_output)
finally:
await sandbox.aclose()
if __name__ == "__main__":
asyncio.run(main())
本地测试
在 main.py 所在目录执行:
python main.py
正常情况下,流程如下:
- 创建 Modal sandbox
- 把
Manifest中定义的文件加载进工作区 - 运行代理
- 输出最终回答
- 清理沙箱会话
执行过程中也可以打开 Modal 控制台查看 openai-agents-modal-demo 的日志,确认沙箱是否成功创建、启动、使用和销毁。
做成交互式 Web 应用
单次脚本验证通路没有问题,但实际使用通常需要多轮交互。一个更实用的做法是用 Gradio 包一层聊天界面,让代理持续在 sandbox 中工作。
先安装 Gradio:
pip install gradio
然后创建 app.py,把同样的 OpenAI Agents + Modal Sandbox 逻辑封装进聊天应用中。交互式版本通常会做两件事:
- 复用现有 sandbox 会话,避免每条消息都重新创建环境
- 把代理输出通过浏览器界面展示出来,支持追问、编辑文件和执行测试
启动方式:
python app.py
终端会输出本地地址,形式类似:
* Running on local URL: http://127.0.0.1:7860
* To create a public link, set share=True in launch().
打开这个地址后,可以让代理完成更接近真实开发流程的任务,例如:
- 解释项目作用
- 创建新文件
- 修改已有代码
- 补充测试
- 在 sandbox 内执行
pytest
一次典型操作中,代理会新增 src/routing_rules.py,再创建 tests/test_routing_rules.py,然后运行 pytest 验证变更。测试结果为 6 个测试全部通过,说明新增辅助模块与原有工单分流逻辑兼容。
这个方案适合什么场景
适用场景主要包括:
- 代码代理需要访问真实项目文件
- 需要隔离执行命令,避免污染本地环境
- 需要把输出文件、日志或测试结果带回主应用
- 需要把代理执行和应用编排分层管理
典型任务包括:
- 仓库检查
- 自动修复
- 测试生成与执行
- 构建产物生成
- 文档同步更新
- 基于项目上下文回答问题
常见边界与问题
1. 编排层和执行层的区别
编排层 位于 Python 应用中,负责代理逻辑、模型调用和决策流程。
执行层 是隔离的 sandbox,负责文件读写、命令执行和代码运行。
两者分离后,不可预期的操作不会直接影响主应用。
2. 是否必须使用 Modal
不是。Modal 只是一个可选提供方。Agents SDK 还支持:
- E2B
- Cloudflare
- Daytona
- Blaxel
- Runloop
- Vercel
替换提供方时,通常只需更换对应的 sandbox client,主体代理结构可以保持不变。
3. Manifest 为什么重要
没有 Manifest,代理只能依赖提示词里的文字描述。
有了 Manifest,代理才能真正看到项目文件结构,并基于实际内容进行检查、修改和推理,结果会更可控,也更贴近工程事实。
4. 这和 ChatGPT 的 Code Interpreter 是一回事吗
不是。
- Code Interpreter 是面向终端用户的内建功能
- Agents SDK 的 sandbox 是面向开发者的框架能力
前者是产品功能,后者是工程接口。开发者需要自己管理工作区、文件内容和 sandbox 生命周期。
实际使用中的取舍
这个方案的优点比较明确:
- 权限边界清晰
- 工作区可控
- 可接入真实文件与命令执行
- 主应用和高风险执行逻辑解耦
但也有工程成本:
- 交互式应用搭建比单次脚本复杂
- 日志可观测性仍然有限
- 运行耗时受沙箱启动、文件操作和测试执行影响
- 长链路任务可能需要调大超时参数
在一次包含文件创建和测试运行的流程中,sandbox 可能会超时,实际可通过把超时时间从 300 秒提高到 600 秒来完成完整任务。这类问题在需要修改代码并跑测试的代理场景里比较常见。
另一个现实问题是可观测性。等待代理完成任务时,如果日志不够细,很难快速判断当前是在检查文件、编辑代码,还是执行测试。对于多步代理流程,更细粒度的步骤日志会明显降低排障成本。
小结
OpenAI Agents SDK 与 Modal Sandboxes 的组合,适合需要真实执行能力的代理应用。代理逻辑留在主应用中,文件和命令放进隔离环境里执行,结构更干净,也更接近可上线的工程设计。
对于只做问答的代理,这种架构偏重。对于需要读仓库、改文件、跑测试、产生产物的代理,这种分层基本是必要条件。
关于
关注我获取更多资讯