跳至主要内容

OpenAI 托管沙盒:构建安全的 AI 财务分析师

学习如何使用 OpenAI 托管沙盒构建安全的 AI 财务分析师:从上传财务数据、运行代理驱动的分析,到生成并下载报告、图表和支持性数据文件。
· 9分钟 阅读

使用 AI 探索

AI 代理已经远不止于简单的文本生成。它们现在可以编写代码、运行命令、处理文件、修复错误,并自主完成多步任务。

但大型语言模型并非总是可预测的。

即使指令清晰,代理也可能生成出乎意料的命令,或修改本不该改动的内容。直接在本地机器或应用服务器上运行这些代码,可能引入不必要的风险。

在本教程中,我将使用 OpenAI 托管沙盒来构建一个安全的 AI 财务分析师。我们将上传一份财务数据集,将代理连接到隔离环境,让它在其中执行分析并生成产物,然后下载生成的报告、图表和数据文件。

财务分析师只是一个示例。主要目标是理解如何为 AI 代理提供一个可控的环境,使其能安全地运行代码并处理文件。

什么是 OpenAI 托管沙盒?

沙盒是一个隔离的环境,代码可以在其中运行,而不会对承载您应用的系统拥有不受限的访问权限。

这对 AI 代理尤为有用,因为它们的行为并非完全可预测。

代理可能被指示修改某个文件,却生成影响另一个目录的命令,安装意料之外的依赖,或执行您未预期的操作。

与其让这些命令直接在您的笔记本电脑或服务器上运行,不如把代理放入沙盒中。

OpenAI 为此提供了自己的托管沙盒环境。

它为代理提供一个真实的 Linux 工作空间,带有文件系统和 shell,同时将执行与您的本地系统隔离开来。

在沙盒内,代理可以:

  • 读取和写入文件。
  • 创建并执行脚本。
  • 运行 shell 命令。
  • 检查命令输出。
  • 修复错误并重新运行代码。
  • 生成报告、数据集、图表和其他产物。

您还可以控制沙盒的访问范围。

例如,您可以只上传完成任务所需的文件,并在代理不需要外部信息时禁用网络访问。

使用 OpenAI 沙盒的不同方式

OpenAI 提供多种方式在隔离环境中运行代理或模型。主要区别在于您希望 OpenAI 代管执行与代理工作流的程度。

1. Shell 工具

最简单的选项是Shell 工具。它允许模型通过 Responses API 在 OpenAI 托管的容器内运行 shell 命令。

response = client.responses.create(
    model=MODEL,
    tools=[{
        "type": "shell",
        "environment": {"type": "container_auto"}
    }],
    input="Analyze the files in /mnt/data."
)

当您主要需要代码执行、文件处理或命令行任务时,这是一个不错的选择。

2. Agents API

相比之下,Agents API 是更托管化的方案。OpenAI 同时管理代理会话和托管环境。

stream = client.beta.agents.sessions.create(
    agent={
        "model": MODEL,
        "instructions": "Analyze the data and create a report."
    },
    environment={"type": "openai_hosted"},
    input="Analyze the files in the workspace.",
    stream=True,
)

当您希望 OpenAI 为您管理更多代理运行时与沙盒生命周期时,这很有用。

3. SandboxAgent

SandboxAgent 属于 Agents SDK,适用于沙盒工作空间是应用核心部分的代理。

from agents.sandbox import SandboxAgent
from agents.sandbox.capabilities import Shell

agent = SandboxAgent(
    name="Financial Analyst",
    model=MODEL,
    capabilities=[Shell()],
)

当您需要持久化的工作空间、文件、产物,或对沙盒提供商有更大灵活性时,这种方式效果很好。

4. Agents SDK + ShellTool

本指南采用的就是这种方法。

我们自行创建 OpenAI 托管的容器,然后使用 ShellTool 将代理连接到该特定环境。

sandbox_shell = ShellTool(
    environment={
        "type": "container_reference",
        "container_id": container.id,
    }
)

我们选择这种方式,因为它在简洁性与可控性之间取得了良好平衡。

OpenAI 负责管理沙盒基础设施,而我们仍可控制容器、文件、网络访问、代理指令、工具以及执行流程。

如何使用 OpenAI 托管沙盒

下面我们来演示如何使用 OpenAI 托管沙盒创建一个安全的财务分析代理。

1. 配置环境和项目

我们将使用 Jupyter Notebook 来搭建并测试整个流程。

Notebook 将负责安装所需 SDK、上传数据集、创建沙盒、启动代理,以及下载最终产物等任务。

但需要注意的是,财务分析本身不会在 Jupyter 内运行。

一旦代理连接到 OpenAI 沙盒,其代码执行、shell 命令、校验、计算和产物生成都会在托管沙盒环境中完成。

可以将 Jupyter 视为控制层,而沙盒是执行环境。

首先安装 OpenAI Python SDK 和 OpenAI Agents SDK:

%pip install -q -U openai openai-agents

您还需要通过 OPENAI_API_KEY 环境变量提供 OpenAI API 密钥。

本教程使用一份虚构公司的数据集,存放在:

financial_data/northstar_cloud_financial_statements.csv

接下来,导入所需库,并定义模型、输入 CSV、本地输出目录,以及预期由代理生成的文件列表。

import json
import os
from pathlib import Path

from IPython.display import Markdown, SVG, display


MODEL = os.getenv("OPENAI_MODEL", "gpt-6-luna")

STATEMENT_CSV = Path(
    "financial_data/northstar_cloud_financial_statements.csv"
)

OUTPUT_DIR = Path("financial_analysis_output")
OUTPUT_DIR.mkdir(exist_ok=True)

EXPECTED_ARTIFACTS = [
    "analyze_financials.py",
    "calculated_metrics.csv",
    "unusual_movements.csv",
    "financial_trends.svg",
    "investment_analysis.md",
    "analysis_run.json",
]

assert os.getenv("OPENAI_API_KEY"), \
    "Set OPENAI_API_KEY before continuing."

assert STATEMENT_CSV.exists(), \
    f"Missing input: {STATEMENT_CSV.resolve()}"

print(f"Model: {MODEL}")
print(
    f"Input: {STATEMENT_CSV} "
    f"({STATEMENT_CSV.stat().st_size:,} bytes)"
)

输出:

Model: gpt-6-luna
Input: financial_data\northstar_cloud_financial_statements.csv (1,480 bytes)

这些断言可在创建任何 OpenAI 资源前进行快速自检。如果缺少 API 密钥或找不到数据集,Notebook 会立刻停止,而不是在流程后期才失败。

OUTPUT_DIR 是一个本地 Jupyter 目录,我们最终会将从沙盒下载的文件保存到这里。

EXPECTED_ARTIFACTS 则定义了我们期望代理在沙盒内创建的文件。

2. 上传财务数据

在沙盒处理我们的财务数据之前,需要先将 CSV 上传到 OpenAI。

这一步由 Jupyter Notebook 完成。它会读取本地文件,并通过 OpenAI Files API 发送。

from openai import OpenAI

client = OpenAI()

with STATEMENT_CSV.open("rb") as handle:
    uploaded_input = client.files.create(
        file=handle,
        purpose="user_data",
    )

print(f"Uploaded raw statements: {uploaded_input.id}")

输出:

Uploaded raw statements: file-C6Pb6RhZrVPR4Fiq9tZ6Hn

您的文件 ID 会不同。

返回的文件 ID 很重要,因为我们在创建沙盒时会用到它。与其将 CSV 内容复制到提示中,不如将原始文件直接附加到代理的工作环境。

此时,Northstar 的财务报表已由 OpenAI 保存,但代理仍然没有执行环境。

我们接下来创建它。

3. 创建 OpenAI 托管沙盒

现在可以创建代理实际执行财务分析的托管环境了。

使用 Containers API 创建新的沙盒,并通过文件 ID 附加已上传的 CSV:

container = client.containers.create(
    name="northstar-financial-analysis",
    file_ids=[uploaded_input.id],
    memory_limit="4g",
    network_policy={"type": "disabled"},
)

print(f"OpenAI sandbox: {container.id}")

输出:

OpenAI sandbox: cntr_6ab7a1080b4081938d8d08ab67ac963c084798905ec997e9

该沙盒配置了 4 GB 内存,且上传的财务报表从一开始就可在其中使用。

我们还禁用了网络访问:

network_policy={"type": "disabled"}

我们的财务分析不需要来自互联网的信息,因此没有理由为代理提供外部网络访问。所需内容都在 CSV 中。

4. 定义财务分析师的任务

沙盒为代理提供了一个安全的工作空间,但我们仍需明确希望它执行的具体事项。

我们没有给出诸如“分析这家公司”这样的模糊指令,而是提供了详细任务,描述计算、校验检查、需要生成的文件,以及代理如何自我核验。

ANALYST_INSTRUCTIONS = """
You are a skeptical senior buy-side financial analyst preparing an investment-committee memo.

Every analytical operation must occur in the hosted shell container under /mnt/data. Do not
estimate results mentally or ask the caller to calculate anything.

Find the uploaded Northstar statement CSV. Write analyze_financials.py using only the Python
standard library and execute it. Validate required columns, numeric values, unique ordered years,
and total_assets = total_liabilities + equity for every row. Calculate revenue growth, gross/
operating/net margins, current and quick ratios, total-liabilities-to-equity, average-balance ROA
and ROE, interest coverage, free cash flow, FCF margin, cash conversion, receivables growth, and
inventory growth. Leave a ratio blank when its denominator makes it undefined.

Flag absolute year-over-year movements of at least 15%, operating-margin moves of at least two
percentage points, and receivables growth exceeding revenue growth by at least ten points. Create
calculated_metrics.csv, unusual_movements.csv, financial_trends.svg, investment_analysis.md, and
analysis_run.json in /mnt/data. The SVG must contain four readable chart panels without external
packages.

The report must cover Executive view, KPI table, Profitability, Liquidity and leverage, Cash flow
and earnings quality, Unusual movements, Bull case, Bear case, Diligence questions, Data
limitations, and Conclusion. Tie receivables, deferred revenue, stock compensation, capex, and
interest expense to evidence; separate facts from hypotheses and cite filenames and years.

analysis_run.json must contain input_filename, row_count, year_range, validation_results,
generated_filenames, and execution_directory='/mnt/data'. validation_results must include
accounting_equation_passed_every_row=true. Run the script, inspect every artifact, independently
recompute at least three 2025 metrics in a second command, and fix discrepancies. Do not finish
until all six required files exist and are non-empty.
"""

这里有一个重要的设计选择。

我们并不是要求模型只在响应中对财务分析进行推理。

指令明确要求其编写代码、执行代码、检查结果、核验部分计算,并纠正任何不一致之处。

我们还告知代理,所有分析操作都必须在托管沙盒内的 /mnt/data 下进行。

这为代理提供了清晰的工作流:

定位数据 → 进行校验 → 编写分析脚本 → 运行脚本 → 生成产物 → 检查结果 → 核验计算 → 必要时修复错误。

这使沙盒成为真正的工作环境,而不仅是临时文件存储。

5. 将代理连接到沙盒

接下来,我们将一个 OpenAI 代理连接到之前创建的容器。

我们通过 ShellTool 来实现。

from agents import Agent, ModelSettings, Runner, ShellTool

sandbox_shell = ShellTool(
    environment={
        "type": "container_reference",
        "container_id": container.id,
    }
)

analyst = Agent(
    name="Sandbox Financial Analyst",
    model=MODEL,
    instructions=ANALYST_INSTRUCTIONS,
    tools=[sandbox_shell],
    model_settings=ModelSettings(tool_choice="required"),
)

关键部分是:

"type": "container_reference",
"container_id": container.id,

这告诉 ShellTool 连接到我们已创建的沙盒,而不是创建或使用其他执行环境。

我们还设置:

tool_choice="required"

这会强制代理在运行中使用工具,而不是仅通过普通文本回复完成任务。

对于本教程,这正是我们所需。

代理不应仅仅解释如何计算财务指标。它应当使用 shell,在沙盒内执行代码,并产出所需文件。

6. 让代理执行分析

数据集上传、沙盒运行、代理通过 ShellTool 连接就绪后,我们现在可以启动分析。

result = await Runner.run(
    analyst,
    "Analyze Northstar entirely inside the sandbox and produce every required artifact.",
    max_turns=30,
)

display(Markdown(result.final_output))

这会启动财务分析代理,并为其提供之前创建的沙盒访问权限。

Output of the OpenAI Agent

代理的最终输出确认分析已在 /mnt/data 内顺利完成,包括数据校验、指标检查,以及全部六个必需产物的创建。

7. 下载生成的产物

分析已完成,但生成的文件仍保存在 OpenAI 沙盒内。

接下来,我们列出容器中的文件,检查所有预期产物是否已生成,并将其下载到本地目录。

remote_files = {
    Path(item.path).name: item
    for item in client.containers.files.list(container.id)
}

missing = [
    name for name in EXPECTED_ARTIFACTS
    if name not in remote_files
]

assert not missing, f"Sandbox did not create: {missing}"

for name in EXPECTED_ARTIFACTS:
    remote = remote_files[name]
    destination = OUTPUT_DIR / name

    client.containers.files.content.retrieve(
        remote.id,
        container_id=container.id,
    ).write_to_file(destination)

    assert destination.stat().st_size > 0, \
        f"Empty artifact: {destination}"

    print(
        f"Downloaded {name}: "
        f"{destination.stat().st_size:,} bytes"
    )

输出:

Downloaded analyze_financials.py: 22,778 bytes
Downloaded calculated_metrics.csv: 3,740 bytes
Downloaded unusual_movements.csv: 25,405 bytes
Downloaded financial_trends.svg: 13,846 bytes
Downloaded investment_analysis.md: 12,159 bytes
Downloaded analysis_run.json: 1,522 bytes

现在,您可以打开本地的 financial_analysis_output 目录,检查代理创建的一切内容。

该文件夹包含分析脚本、计算指标、异常波动标记、完整投资备忘录、校验清单,以及反映财务趋势的 SVG 可视化。

Financial analysis report generated by the OpenAI Agent

investment_analysis.md 文件包含主体书面分析,覆盖管理层摘要、盈利能力、流动性、杠杆、现金流、异常波动,以及乐观与悲观情景等。

Financial analysis visualization generated by the OpenAI Agent

您也可以打开 financial_trends.svg 来查看可视化结果。

无需先读完整报告,它即可快速展现主要财务趋势,如收入、盈利能力、利润率及其他关键指标。

需要强调的一点是,我们不会简单地下载代理恰好创建的任意文件。

Notebook 会先将沙盒内容与 EXPECTED_ARTIFACTS 进行比对。

如果缺少任何必需文件,断言会失败。我们还会检查每个下载文件都非空。

这为接受代理输出前提供了一个简单的验证步骤。

8. 清理沙盒

一旦文件下载并验证完成,我们就不再需要临时沙盒和上传的源文件。

删除这两个资源:

client.containers.delete(container.id)
client.files.delete(uploaded_input.id)

这会在工作流结束后移除托管容器和上传的财务数据集。

清理临时资源是个良好收尾步骤,尤其当您在代理工作流中经常创建沙盒时。

结语

OpenAI 托管沙盒的最大优势在于整个工作流都在同一生态内完成。

您无需连接单独的沙盒提供商、配置自有云环境,或构建并维护容器基础设施。

您可以创建沙盒、附加文件、控制网络访问、让代理在其中工作、取回结果,并在完成后删除环境——全部通过 OpenAI 平台完成。

这让工作流的管理简化了许多。

在本教程中,我使用搭配 ShellTool 的 OpenAI Agents SDK,因为它能以直接方式将代理连接到现有容器,同时仍保留对指令、文件、工具和执行流程的控制权。

在 OpenAI 生态内,还有其他方式可构建同类工作流,包括更直接的代理 API 和更高层的沙盒抽象。

不过在这个示例中,Agents SDK 在简洁与控制之间达到了恰当的平衡。

核心要点是,您现在可以在不离开 OpenAI 生态的情况下,为 AI 代理提供真实的执行环境:

创建沙盒 → 附加数据 → 连接代理 → 运行任务 → 获取产物 → 删除沙盒。

对于需要运行代码、操作文件、生成报告或执行多步分析的代理应用而言,这是非常实用的模式。

FAQs

OpenAI 托管沙盒可以保持活动多长时间?

OpenAI 托管沙盒会一直保持活动,直到您通过 API 明确删除该会话为止。如果在没有保活或任何活动的情况下保持运行,它将在一小时不活动后自动过期并被删除。当前无法配置此不活动超时时间。

OpenAI 沙盒预装了哪些编程语言?

尽管 Python 是数据分析的标准选择,但托管容器开箱即带有多个预装运行时。该环境原生支持 Python 3.11、Node.js 22.16、Java 17.0、PHP 8.2、Ruby 3.1 和 Go 1.23。

上传到沙盒的文件会用于训练 OpenAI 模型吗?

不会。发送到 OpenAI API 的数据——包括附加到 Containers API 的文件以及在沙盒中执行的代码——均为私有。除非您明确选择共享数据,否则这些数据不会用于训练或改进 OpenAI 的基础模型。

沙盒环境是否会产生超出 API token 用量之外的额外费用?

会。托管沙盒会使用容器算力资源,其计费与标准的基于 token 的模型用量分开。 因此,在代理完成后立即明确删除容器及其附加文件,是一项重要的节省成本的最佳实践。

Abid Ali Awan

作者

Abid Ali Awan

作为一名持证的数据科学家,我热衷于利用前沿技术打造创新的机器学习应用。凭借在语音识别、数据分析与报告、MLOps、对话式人工智能以及自然语言处理方面的扎实背景,我不断打磨构建智能系统的能力,力求带来切实影响。除技术专长外,我也擅长沟通,能够将复杂概念提炼为清晰、简明的表述。因此,我成为数据科学领域备受关注的博主,与不断壮大的数据专业人士社区分享洞见与实践经验。目前,我专注于内容创作与编辑,借助大语言模型打造有力且吸引人的内容,帮助企业与个人更好地发挥数据价值。

主题