note

  • OpenAI Sandbox Agents 的本质,是为 Agent 提供标准化、有状态、可恢复的执行环境。
  • 它将工作区初始化、Shell 执行、文件操作、会话管理和持久化能力集成到 Agents SDK 中,让开发者更容易构建 Coding Agent、数据分析 Agent 等需要真实文件操作的系统。
  • Manifest = 初始化;Session = 持续运行;Snapshot = 保存与恢复文件状态。

一、Sandbox Agents沙箱智能体

技术背景:为什么需要 Sandbox Agents?
传统 Agent 主要通过 LLM + Tool Calling + Agent Loop 完成任务,例如搜索网页、执行 Python、查询数据库等。

但对于 Coding Agent、数据分析等复杂任务,仅有工具调用还不够。例如让 Agent 修复一个代码 Bug,需要读取项目文件、修改代码、运行测试,并在任务中断后继续执行。

这里的难点不只是调用什么工具,还包括:工作区如何初始化、文件如何保存、执行环境如何隔离、任务如何恢复?

OpenAI Agents SDK 提供的 Sandbox Agents,就是将这些能力统一封装成一套有状态的执行机制。

它不是新的模型或训练算法,而是 Agent Harness 中负责工作区管理与代码执行的基础设施。

二、核心架构与执行原理

核心组件作用
SandboxAgent定义模型、指令及沙箱能力
Manifest声明新沙箱的初始文件和目录
Capabilities提供 Shell、Filesystem、Skills 等能力
SandboxRunConfig指定沙箱后端、会话及恢复配置
Sandbox Client实际执行命令和文件操作

执行流程:执行时,Runner 获取或创建 Sandbox Session,初始化工作区、绑定工具,再进入常规 Agent Loop。
在这里插入图片描述
当 LLM 决定执行 Shell 命令时,工具调用会被路由到 Sandbox Client;执行结果返回模型,模型据此决定继续操作还是结束。

设计本质:因此,Sandbox Agents 没有改变 Agent Loop 的基本原理,主要改变的是工具背后的执行环境及其生命周期管理。

三、状态管理与长期记忆

Sandbox Agents 支持三种容易混淆的机制:

  • Sandbox Session:当前运行中的执行环境,多次任务可以复用同一工作区。
  • Snapshot:保存工作区文件,用于之后初始化新的沙箱,不等于恢复原进程。
  • Memory:从历史 Agent 运行轨迹中提取可复用经验,供未来任务参考。

其中 Memory 比普通对话历史更进一步:它可以从历史 Rollout 中提炼经验,再整合为摘要、索引和详细记录;后续任务按需读取,避免将全部历史轨迹塞入上下文。

四、OpenAI Sandbox Agent代码实践

基于 OpenAI Agents SDK 构建一个简单的 Sandbox Agent,通过 OpenAI 兼容接口调用第三方大模型,并使用 UnixLocalSandboxClient 提供本地 Shell 执行环境。

实验自动创建包含潜在 Bug 的 calculator.py,利用 Manifest 初始化工作区,再由模型自主调用 Shell 工具读取代码、分析异常边界并输出修复建议。

关键配置:
SandboxAgent:定义模型、指令和工具能力。
Manifest + LocalDir:初始化测试代码工作区。
Shell():提供 exec_command 命令执行能力。
UnixLocalSandboxClient:负责在本地执行 Shell 命令。
Runner.run():驱动模型推理和工具调用循环。

本实验重点验证 Sandbox Agents 的工作区初始化和 Shell 工具调用能力,不涉及代码自动修改、Session 恢复和长期 Memory 机制。

import asyncio
import os
from pathlib import Path



from openai import AsyncOpenAI

from agents import (
    Runner,
    set_default_openai_api,
    set_default_openai_client,
    set_tracing_disabled,
)
from agents.run import RunConfig
from agents.sandbox import (
    Manifest,
    SandboxAgent,
    SandboxRunConfig,
)
from agents.sandbox.capabilities import Shell
from agents.sandbox.entries import LocalDir
from agents.sandbox.sandboxes.unix_local import (
    UnixLocalSandboxClient,
)

# 从配置读取模型与端点
MODEL = os.getenv("SANDBOX_MODEL", "gpt-5.1")
BASE_URL = os.getenv("OPENAI_BASE_URL") or None

def configure_model_provider() -> None:
    """按 .env 配置模型提供方。

    用非 OpenAI 的兼容端点(如 DashScope/Qwen)时:
    - 用自定义 client 指向该端点
    - 强制走 chat.completions(这些端点不支持 OpenAI 的 responses API)
    - 关闭 tracing(否则会尝试上传到 OpenAI 平台)
    """
    if BASE_URL and "openai.com" not in BASE_URL:
        client = AsyncOpenAI(
            api_key=os.getenv("OPENAI_API_KEY"),
            base_url=BASE_URL,
        )
        set_default_openai_client(client, use_for_tracing=False)
        set_default_openai_api("chat_completions")
        set_tracing_disabled(True)


async def main():
    # 1. 检查 API Key 并配置模型提供方
    if not os.getenv("OPENAI_API_KEY"):
        raise RuntimeError("请先在 .env 配置 OPENAI_API_KEY")
    configure_model_provider()
    print(f"使用模型: {MODEL}  端点: {BASE_URL or 'OpenAI 官方'}")

    # 2. 自动创建测试代码仓库
    base_dir = Path(__file__).resolve().parent
    repo_dir = base_dir / "repo"
    repo_dir.mkdir(exist_ok=True)

    test_code = '''
def divide(a, b):
    return a / b

def average(numbers):
    return sum(numbers) / len(numbers)
'''

    (repo_dir / "calculator.py").write_text(
        test_code.strip() + "\n",
        encoding="utf-8",
    )

    print(f"测试项目目录: {repo_dir}")

    # 3. 创建 Sandbox Agent
    agent = SandboxAgent(
        name="Code Reviewer",
        model=MODEL,
        instructions=(
            "你是一名资深 Python 代码审查工程师。"
            "请使用 Shell 工具(exec_command,例如 cat/rg)实际检查 repo/ 中的代码,"
            "识别潜在 Bug、边界条件和异常处理问题。"
            "给出具体的修复建议和测试建议。"
            "不要修改任何文件,使用中文回答。"
        ),
        # 非 OpenAI 端点(chat.completions)不支持 apply_patch/view_image 这类 hosted tool,
        # 也不支持 Compaction 注入的 context_management 参数;代码审查只需读文件,用 Shell 即可。
        capabilities=[Shell()],
        default_manifest=Manifest(
            entries={
                "repo": LocalDir(src=repo_dir),
            }
        ),
    )

    # 4. 运行 Agent
    print("\n开始运行 Sandbox Agent...\n")

    result = await Runner.run(
        agent,
        "请检查 repo/calculator.py,"
        "找出潜在 Bug,说明触发条件并给出修复建议。",
        run_config=RunConfig(
            sandbox=SandboxRunConfig(
                client=UnixLocalSandboxClient()
            )
        ),
    )

    # 5. 输出结果
    print("=" * 60)
    print("Agent 分析结果")
    print("=" * 60)
    print(result.final_output)


if __name__ == "__main__":
    asyncio.run(main())

同时打印日志内容如下,可以看到一开始rg 失败后改用 grep。命令能够在指定工作区执行,体现的是 Sandbox Runtime 的执行能力。Manifest、Session、Snapshot 等机制,则是 Sandbox Agents 相比简单 Shell 工具封装更值得关注的工程设计。

[1] 调用工具: exec_command
    参数: {"cmd": "rg -n 'def ' repo/calculator.py", "login": false, "tty": false}
    沙箱返回: Chunk ID: 0a928d Wall time: 0.0171 seconds Process exited with code 127 Output: sh: rg: command not found 

[2] 调用工具: exec_command
    参数: {"cmd": "grep -n 'def ' repo/calculator.py", "login": false, "tty": false}
    沙箱返回: Chunk ID: 7142dc Wall time: 0.0346 seconds Process exited with code 0 Output: 1:def divide(a, b): 4:def average(numbers): 

[3] 调用工具: exec_command
    参数: {"cmd": "grep -n 'def divide(' repo/calculator.py -A 10", "login": false, "tty": false}
    沙箱返回: Chunk ID: 5760ba Wall time: 0.0351 seconds Process exited with code 0 Output: 1:def divide(a, b): 2-    return a / b 3- 4-def average(numbers): 5-    return sum(numbers) / len(numbers) 

[4] 调用工具: exec_command
    参数: {"cmd": "grep -n 'def average(' repo/calculator.py -A 10", "login": false, "tty": false}
    沙箱返回: Chunk ID: 8c203b Wall time: 0.0302 seconds Process exited with code 0 Output: 4:def average(numbers): 5-    return sum(numbers) / len(numbers) 

Reference

[1] https://openai.github.io/openai-agents-python/sandbox/memory/
[2] OpenAI Sandbox Agents 深度解析:让 Agent 拥有工作区、执行与长期记忆

Logo

更多推荐