openai-agents-python 沙盒智能体记忆(Sandbox Agent Memory)实战指南:启用、读取、生成与隔离
【免费下载链接】openai-agents-pythonA lightweight, powerful framework for multi-agent workflows项目地址: https://gitcode.com/GitHub_Trending/op/openai-agents-python
沙盒智能体记忆(Sandbox Agent Memory)是 openai-agents-python 中一类独立于对话式Session记忆的持久化机制:它把一次沙盒运行中的经验、用户偏好和纠错反馈提炼成工作区内的文件,供后续运行学习复用,从而降低 token 消耗、人工干预和任务描述成本。本文基于官方中文文档 docs/zh/sandbox/memory.md 为主线,结合仓库源码与完整示例,系统讲解记忆的启用、读取、生成、多轮对话与多智能体隔离布局,读完即可在自己的沙盒智能体工作流中落地"一次修复、永久受益"的记忆能力。
注意:沙盒智能体目前处于Beta 阶段(文档明确标注)。在正式发布之前,API 细节、默认值和支持的功能可能发生变化,未来也会提供更高级的功能。
什么是沙盒记忆:与 SDK 对话式 Session 的区别
官方文档开篇即给出定义:记忆可让未来的沙盒智能体运行从先前的运行中学习。它独立于 SDK 的对话式Session记忆——后者用于存储消息历史记录;而沙盒记忆会将先前运行中的经验提炼为沙盒工作区中的文件(如MEMORY.md、memory_summary.md、rollout_summaries/),本质上是"文件系统层面的长期知识库"。
启用记忆可以为未来运行降低三类成本:
- 智能体成本:如果智能体花费很长时间才完成某个工作流,下一次运行所需的探索应该会更少,从而减少 token 使用量和完成时间;
- 用户成本:如果用户纠正了智能体或表达了偏好,未来的运行可以记住这些反馈,从而减少人工干预;
- 上下文成本:如果智能体之前完成过某项任务,而用户希望在此基础上继续推进,则用户无需查找先前的对话或重新输入所有上下文,任务描述可以更短。
两个官方示例贯穿全文:
- examples/sandbox/memory.py:完整的两轮运行示例——修复一个 bug、生成记忆、恢复快照,并在后续验证器运行中使用该记忆;
- examples/sandbox/memory_multi_agent_multiturn.py:采用独立记忆布局的多轮、多智能体示例。
启用记忆:把Memory()添加为沙盒智能体的能力
启用方式非常直接:将Memory()作为一项能力(capability)添加到SandboxAgent中:
from pathlib import Path import tempfile from agents.sandbox import LocalSnapshotSpec, SandboxAgent from agents.sandbox.capabilities import Filesystem, Memory, Shell agent = SandboxAgent( name="Memory-enabled reviewer", instructions="Inspect the workspace and preserve useful lessons for follow-up runs.", capabilities=[Memory(), Filesystem(), Shell()], ) with tempfile.TemporaryDirectory(prefix="sandbox-memory-example-") as snapshot_dir: sandbox = await client.create( manifest=manifest, snapshot=LocalSnapshotSpec(base_path=Path(snapshot_dir)), )能力依赖:为什么需要Shell()和Filesystem()
文档明确了两条依赖规则,源码也在Memory.required_capability_types()中做了校验(见 src/agents/sandbox/capabilities/memory.py):
- 如果启用了读取,
Memory()需要Shell()——当注入的摘要信息不足时,智能体需要能够读取和搜索记忆文件; - 当启用实时记忆更新时(默认启用),还需要
Filesystem()——这样当智能体发现记忆已过时或用户要求更新记忆时,它可以更新memories/MEMORY.md。
产物存储位置与复用前提
默认情况下,记忆产物存储在沙盒工作区的memories/目录下。要在后续运行中复用这些产物,需要保留并复用整个已配置的记忆目录,方式有两种:
- 保持使用同一个实时沙盒会话;
- 从已持久化的会话状态或快照中恢复(例如上例中的
LocalSnapshotSpec+client.resume(sandbox.state))。
全新的空白沙盒最初没有任何记忆。
读取与生成的开关:Memory(generate=None)与Memory(read=None)
Memory()默认同时启用记忆读取和生成。但在两种典型场景下需要关闭其一:
Memory(generate=None):只读不写。适用于内部智能体、子智能体、检查器或一次性工具智能体执行的运行——它们通常不会提供太多有价值的信息,不应污染记忆库;Memory(read=None):只写不读。适用于"运行应生成供日后使用的记忆,但用户不希望该运行受现有记忆影响"的场景。
源码中对这一约束也有兜底校验:如果read与generate同时为None,会直接抛出ValueError("Memory requires at least one ofreadorgenerate.")(见 src/agents/sandbox/capabilities/memory.py)。
读取记忆:渐进式披露(Progressive Disclosure)
记忆读取采用渐进式披露策略,避免一次性把全部历史塞进上下文:
- 运行开始时注入摘要:SDK 会将一个简短摘要
memory_summary.md注入智能体的开发者提示词,其中包含普遍有用的技巧、用户偏好以及可用记忆的索引。这给智能体足够的上下文去判断先前工作是否可能相关; - 按需搜索索引:当先前工作看起来相关时,智能体会使用当前任务中的关键词,在已配置的记忆索引(
memories_dir下的MEMORY.md)中进行搜索; - 按需打开详情:只有在任务需要更多细节时,它才会打开已配置的
rollout_summaries/目录下相应的先前运行摘要。
摘要注入的源码细节
在 src/agents/sandbox/capabilities/memory.py 的instructions()方法中可以看到具体实现:
- 读取
{memories_dir}/memory_summary.md,若文件不存在(WorkspaceReadNotFoundError)或内容为空,则不注入任何提示词; - 注入前会经过
truncate_text(..., TruncationPolicy.tokens(_MEMORY_SUMMARY_MAX_TOKENS))截断,常量_MEMORY_SUMMARY_MAX_TOKENS = 15_000(同文件第 15 行),即摘要上限约 1.5 万 token; - 最终通过
render_memory_read_prompt(memory_dir=..., memory_summary=..., live_update=...)渲染成一段开发者提示词,其中会注明记忆目录路径和是否允许实时更新。
记忆可能过时:live_update实时更新
记忆可能会过时。智能体会被要求仅将记忆视为参考,并以当前环境为准。默认情况下,记忆读取会启用live_update(MemoryReadConfig.live_update: bool = True,见 src/agents/sandbox/config.py),因此如果智能体发现记忆已过时,可以在同一次运行中更新已配置的MEMORY.md。
何时应禁用实时更新?文档给出的建议是:当智能体应读取记忆但不应在运行期间修改记忆时,例如对延迟敏感的运行——关闭实时更新可以省去写文件的耗时,但代价是过时记忆的"债务"会累积,直到下一次整合才可能被纠正(示例 examples/sandbox/memory.py 的注释对此有详细说明)。
生成记忆:两阶段流水线与工作区布局
一次运行结束后,沙盒运行时会将该运行片段追加到对话文件中;累积的对话文件会在沙盒会话关闭时被处理。这一调度逻辑由 src/agents/sandbox/memory/manager.py 中的SandboxMemoryGenerationManager实现:运行期间把结果序列化为 rollout JSONL(enqueue_result),会话关闭前的flush()钩子触发阶段一提取与最终的一次阶段二整合。
记忆生成分为两个阶段:
- 阶段 1:对话提取(Phase 1: conversation extraction)。记忆生成模型处理一个累积的对话文件并生成对话摘要;系统、开发者和推理内容会被省略;如果对话过长,则会截断对话以适应上下文窗口,同时保留开头和结尾。模型还会生成原始记忆提取内容(raw memory extract)——从对话中提取的精简笔记,供阶段 2 整合;
- 阶段 2:布局整合(Phase 2: layout consolidation)。整合智能体读取某个记忆布局的原始记忆,在需要更多依据时打开对话摘要,并将其中的模式提取到
MEMORY.md和memory_summary.md中。
默认工作区布局
workspace/ ├── sessions/ │ └── <rollout-id>.jsonl └── memories/ ├── memory_summary.md ├── MEMORY.md ├── raw_memories.md (intermediate) ├── phase_two_selection.json (intermediate) ├── raw_memories/ (intermediate) │ └── <rollout-id>.md ├── rollout_summaries/ │ └── <rollout-id>_<slug>.md └── skills/其中标记为(intermediate)的文件是中间产物:raw_memories/保存每次 rollout 的原始记忆(由阶段 1 生成,格式包含rollout_id、updated_at、rollout_path、rollout_summary_file、terminal_state,见 src/agents/sandbox/memory/manager.py),rollout_summaries/保存对应运行的对话摘要,phase_two_selection.json记录阶段 2 整合时选择了哪些记忆。
用MemoryGenerateConfig配置记忆生成
from agents.sandbox import MemoryGenerateConfig from agents.sandbox.capabilities import Memory memory = Memory( generate=MemoryGenerateConfig( max_raw_memories_for_consolidation=128, extra_prompt="Pay extra attention to what made the customer more satisfied or annoyed", ), )MemoryGenerateConfig的完整字段及源码默认值(见 src/agents/sandbox/config.py)如下:
| 字段 | 默认值 | 说明 |
|---|---|---|
max_raw_memories_for_consolidation | 256 | 阶段 2 整合时最多考虑的近期原始记忆数量,取值必须大于 0 且不超过 4096(源码__post_init__校验) |
phase_one_model | "gpt-5.4-mini" | 阶段 1 单次 rollout 提取所使用的模型 |
phase_one_model_settings | ModelSettings(reasoning=Reasoning(effort="medium")) | 阶段 1 的模型设置(推理强度 medium),接受ModelSettings实例或其字段字典 |
phase_two_model | "gpt-5.5" | 阶段 2 记忆整合所使用的模型 |
phase_two_model_settings | ModelSettings(reasoning=Reasoning(effort="medium")) | 阶段 2 的模型设置 |
extra_prompt | None | 附加到内置记忆提取/整合提示词末尾的开发者指引 |
extra_prompt的用法:用它告诉记忆生成器哪些信号对你的使用场景最重要。例如面向市场推广(GTM)的智能体,可以让它重点保留客户和公司详细信息。源码注释(src/agents/sandbox/config.py)给出了三条实用建议:
- 用几条聚焦的要点或简短段落,而非大段额外说明;
- 尽量控制在约 5k token 以内,通常越短越好;
- 阶段 1 的记忆生成模型已经收到一个大型内置提示词 + 截断后的对话,过大的
extra_prompt会挤占真正需要总结的证据空间。
遗忘机制:让记忆跟上最新环境
如果近期原始记忆数量超过max_raw_memories_for_consolidation(默认 256),阶段 2 将只保留最新对话中的记忆并删除较旧的记忆。新旧顺序以对话最后更新时间为准(源码中取自 rollout payload 的updated_at字段)。这种遗忘机制有助于让记忆反映最新环境,避免过时经验长期占据整合空间。
多轮对话:SDKSession+ 同一个实时沙盒会话
对于多轮沙盒聊天,需要把常规 SDKSession与同一个实时沙盒会话结合使用:
from agents import Runner, SQLiteSession from agents.run import RunConfig from agents.sandbox import SandboxRunConfig conversation_session = SQLiteSession("gtm-q2-pipeline-review") sandbox = await client.create(manifest=agent.default_manifest) async with sandbox: run_config = RunConfig( sandbox=SandboxRunConfig(session=sandbox), workflow_name="GTM memory example", ) await Runner.run( agent, "Analyze data/leads.csv and identify one promising GTM segment.", session=conversation_session, run_config=run_config, ) await Runner.run( agent, "Using that analysis, write a short outreach hypothesis.", session=conversation_session, run_config=run_config, )关键点:
- 两次运行都传入同一个 SDK 对话会话(
session=conversation_session),因此共享同一个session.session_id,两次运行都会追加到同一个记忆对话文件; - 这不同于
sandbox参数——它标识的是实时工作区,不会用作记忆对话 ID; - 沙盒会话关闭时,阶段 1 会处理累积的对话,因此可以从整个交流过程而不是两个孤立的轮次中提取记忆。
记忆对话 ID 的解析顺序
如果希望多次Runner.run(...)调用形成一次记忆对话,需要在这些调用中传入一个稳定标识符。当记忆将一次运行与某个对话关联时,按以下顺序解析:
conversation_id——当你将其传入Runner.run(...)时;session.session_id——当你传入 SDKSession(例如SQLiteSession)时;RunConfig.group_id——当上述两者均不存在时;- 每次运行生成的 ID——当不存在稳定标识符时(此时每次
Runner.run()各自成为独立的记忆对话)。
记忆隔离布局:用MemoryLayoutConfig区分不同智能体
记忆隔离基于MemoryLayoutConfig,而不是智能体名称。具有相同布局和相同记忆对话 ID 的智能体会共享一个记忆对话和一份整合后的记忆;具有不同布局的智能体则会分别保存各自的运行文件、原始记忆、MEMORY.md和memory_summary.md,即使它们共享同一个沙盒工作区。
当多个智能体共享一个沙盒但不应共享记忆时,使用独立布局:
from agents import SQLiteSession from agents.sandbox import MemoryLayoutConfig, SandboxAgent from agents.sandbox.capabilities import Filesystem, Memory, Shell gtm_agent = SandboxAgent( name="GTM reviewer", instructions="Analyze GTM workspace data and write concise recommendations.", capabilities=[ Memory( layout=MemoryLayoutConfig( memories_dir="memories/gtm", sessions_dir="sessions/gtm", ) ), Filesystem(), Shell(), ], ) engineering_agent = SandboxAgent( name="Engineering reviewer", instructions="Inspect engineering workspaces and summarize fixes and risks.", capabilities=[ Memory( layout=MemoryLayoutConfig( memories_dir="memories/engineering", sessions_dir="sessions/engineering", ) ), Filesystem(), Shell(), ], ) gtm_session = SQLiteSession("gtm-q2-pipeline-review") engineering_session = SQLiteSession("eng-invoice-test-fix")这样可以防止 GTM 分析被整合到工程错误修复记忆中,反之亦然。
MemoryLayoutConfig字段与隔离的源码实现
MemoryLayoutConfig(src/agents/sandbox/config.py)只有两个字段,默认值均为顶层目录名:
| 字段 | 默认值 | 说明 |
|---|---|---|
memories_dir | "memories" | 整合后记忆文件(MEMORY.md、memory_summary.md等)存放目录 |
sessions_dir | "sessions" | 每次 rollout 的 JSONL 对话产物存放目录 |
源码对路径做了严格校验(src/agents/sandbox/capabilities/memory.py):必须是相对于沙盒工作区根目录的相对路径,不能是绝对路径、不能包含..逃逸根目录、不能为空。
在 src/agents/sandbox/memory/manager.py 的get_or_create_memory_generation_manager中可以看到隔离的落地方式:记忆生成管理器以(memories_dir, sessions_dir)为 key 按会话登记;同一沙盒会话内,若两个Memory能力使用了相同的memories_dir或相同的sessions_dir但布局不同,会抛出UserError,提示"改用不同的目录以隔离记忆,或使用相同布局以共享记忆"——这从机制上保证了布局不混淆。
完整示例实战:两轮运行 + 快照恢复 + 记忆验证
官方示例 examples/sandbox/memory.py 完整演示了记忆的闭环,其流程如下:
- 构建清单(Manifest):用
Manifest(entries={...})构造一个带 bug 的示例项目acme-metrics(report.py中format_invoice_total的计算逻辑错误:total = subtotal + tax_rate),并附带一个会失败的测试; - 第一轮运行:提示词为
"Inspect workspace and fix invoice total bug in src/acme_metrics/report.py.",智能体修复 bug;当async with sandbox块退出、沙盒会话关闭时,阶段 1/阶段 2 自动生成记忆产物; - 快照恢复:通过
client.resume(sandbox.state)在新的沙盒会话中恢复同一工作区——这样第二轮运行依赖的是记忆而非进程内状态; - 第二轮运行:提示词为
"Add a regression test for the previous bug you fixed.",智能体从注入的memory_summary.md得知第一轮的修复细节,直接写出回归测试; - 打印产物树:示例末尾的
_print_memory_tree会输出sessions/、memories/MEMORY.md、memory_summary.md、raw_memories/、rollout_summaries/等目录的内容,便于直观验证记忆生成结果。
运行方式(示例代码支持--model参数):
python examples/sandbox/memory.py --model gpt-5.6-sol多智能体多轮场景可运行:
python examples/sandbox/memory_multi_agent_multiturn.py --model gpt-5.6-sol该示例在同一个沙盒工作区内分别演示了 GTM 智能体两轮对话(memories/gtm布局)与工程智能体单轮修复(memories/engineering布局),并在结尾打印两个布局各自的目录树与 JSONL 会话内容,可直接对照本文的布局章节理解隔离效果。
小结
沙盒智能体记忆把"运行经验"变成了工作区内的可复用文件:读取侧用渐进式披露 + 实时更新保证低成本、不过时;生成侧用两阶段流水线(对话提取 → 布局整合)把原始对话提炼为MEMORY.md与memory_summary.md;多轮对话靠稳定的记忆对话 ID(conversation_id→session.session_id→group_id→ 随机 ID)聚合;多智能体隔离靠MemoryLayoutConfig的不同memories_dir/sessions_dir实现。
值得留意的工程细节包括:记忆产物仅在沙盒会话关闭时处理(阶段 1 逐 rollout、阶段 2 统一整合,见 src/agents/sandbox/memory/manager.py 的flush实现);max_raw_memories_for_consolidation提供基于更新时间的遗忘机制;摘要注入有 1.5 万 token 截断保护。相关单元测试见 tests/sandbox/test_memory.py,可进一步了解各配置项的行为边界。由于该功能处于 Beta 阶段,生产环境落地前请关注默认值与 API 的后续演进。
【免费下载链接】openai-agents-pythonA lightweight, powerful framework for multi-agent workflows项目地址: https://gitcode.com/GitHub_Trending/op/openai-agents-python
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考