OpenAI Agents API 如何处理长时间运行的 AI Agent?Context、Tools、Subagents 与 JSON 状态管理完整教程
9 月 10 日公测的卖点不是「再开一个 chat」。官方把 Codex 上跑了几天的 harness 交出来:Session 续着,上下文会被 compact,subagent 自带一份上下文。本文只写长任务怎么活:你存什么 JSON,OpenAI 替你压什么,断线后看哪段 items。
阅读前速览
| 对象 | 干什么 | 你该存什么 |
|---|---|---|
| Session | 可续的实例,跨小时、跨窗口 | session_id |
| Turn | 一次输入启动的异步工作 | turn_id / 完成事件 |
| Items | 已保存的消息和工具调用 | 断线后回放用 |
| Compact | 接近窗口上限时自动压缩 | 关键字段另存 |
| Subagent | 独立上下文,并行干活 | 并发上限 |
空闲的 session 不等于这一轮成功。看 turn 事件和 items,不要看最后一句自然语言。
长任务活在 Session 里,不活在更长的 prompt 里
Agents API 处理长时间运行的办法很具体:你建一个 durable session,后续输入都打到同一个 session_id。接近上下文上限时,harness 自动 compact 早先的内容。独立子任务可以派给 subagent。你不用自己拼完整聊天记录。
- 续跑:把
session_id跟业务会话绑在一起。同一条会话,不要新建第二个 session。 - 断线:事件流不重放。把 session 和 items 拉回来,不要假设客户端还记得上一跳。
- 钱和单号:compact 会丢掉细节。订单号、金额、审批结果写在你自己的 JSON 里。
Session 和工具 JSON 怎么接,见 OpenAI Agents API 完整解析。循环该不该交给托管,见 Agents API vs Responses API。若 Agent 和 Function Calling 还糊在一起,先读 AI Agent 完整指南。
Session 续着,Turn 异步跑
创建时一次声明模型、工具、环境和是否开 multi_agent。官方创建口是 POST /v1/agents/sessions,header 带 OpenAI-Beta: agents=v1。托管沙箱写 openai_hosted:
{
"agent": {
"model": "gpt-6-astra",
"instructions": "Look up orders. Confirm before any refund. Delegate independent lookups to subagents.",
"tools": [
{
"type": "function",
"name": "lookup_order",
"parameters": {
"type": "object",
"properties": {
"order_id": { "type": "string", "pattern": "^[A-Z]-\\d{4}$" }
},
"required": ["order_id"],
"additionalProperties": false
}
},
{ "type": "web_search" }
],
"multi_agent": { "enabled": true, "max_concurrent_subagents": 3 }
},
"environment": { "type": "openai_hosted", "workspace_directory": "/workspace" },
"input": [
{
"role": "user",
"content": [{ "type": "input_text", "text": "Look up A-1042 and keep the case open." }]
}
]
}
同一条 session 上再发 agent.session.input.message。空闲就开新 turn;还在跑就转向当前 turn。取消用 agent.session.input.cancel,session 和已保存工作还在:
{
"events": [
{
"type": "agent.session.input.message",
"input": [
{
"role": "user",
"content": [
{ "type": "input_text", "text": "Warehouse marked A-1042 packed. Continue." }
]
}
]
}
]
}
看结局,不要看「现在闲不闲」。官方事件是 agent.session.turn.completed、failed、cancelled。turn 完成也不等于每个工具都成功。需要函数结果时,去读 required_actions。
工具链跨小时,回写还是 JSON
长任务里,模型仍然只填参数。轮到你的 function,harness 停住,你按 turn_id / call_id 交结果。四小时后回写,形状不变:
{
"type": "tool_result",
"turn_id": "turn_4",
"call_id": "call_3c91",
"success": true,
"output": "{\"order_id\":\"A-1042\",\"status\":\"packed\"}"
}
function 要你执行;MCP 和 web_search 可以由 harness 自己走。subagent 继承 MCP 和网页搜索,不继承 function 工具。需要查自家订单的副作用,留在主 Agent。
门还是 Schema。宽 object 在长任务里更危险:compact 之后模型更容易填错单号。MCP 那一行只是另一张工具表,边界见 MCP Tool Schema vs Function Calling。
Compact 压的是窗口,不是你的账本
官方写明:接近上下文上限时,Agents API 自动 compact 早先内容,让工作跨多个窗口。你不必自己实现压缩。这和 Responses 上的 context_management / /responses/compact 不是同一层。
- Agents API:session 自己压。你拿回 items,核对单号还在不在。
- Responses:要自己开 compact,或调用 compact 端点。加密的 compaction item 当下一窗的输入,不要手剪。
- 两边都成立:压缩丢细节。金额、确认、放行仍由宿主写。
把 order_id 只活在对话里,等于把账本交给摘要。Schema 怎么当门,见 AI 为什么需要 JSON Schema。
Subagent:并行,但上下文分开
打开 multi_agent.enabled 后,harness 自带创建、传话、等待、打断。你不用自己声明这些工具。items 里会出现协调动作:
{
"data": [
{
"type": "function_call",
"turn_id": "turn_4",
"call_id": "call_3c91",
"name": "lookup_order",
"arguments": "{\"order_id\":\"A-1042\"}"
},
{
"type": "create_subagent_call",
"agent_id": "agent_main",
"task": "Compare A-1042 packing notes with the invoice."
}
]
}
- 独立上下文:每个 subagent 自己一份。主 Agent 用 create / message / wait / interrupt 收口。
- 并发要封顶:默认最多 6 个(不含协调者)。生产里写死更小的数。
- 完成项 ≠ 子任务结束:
create_subagent_call完成,只说明派出去了。看agent.session.subagent.created和该 subagent 自己的 items。
handoff 该是可审计的 JSON,不是一句「请交给账单组」。怎么收成 Schema,见 JSON Schema 与 AI Agent 工作流。
你持有的状态,不要指望 compact 替你记
OpenAI 替你存 session 配置、对话和已保存工作。你至少还要一份业务状态,断线也能重建:
{
"session_id": "sess_8f21",
"order_id": "A-1042",
"last_turn_id": "turn_4",
"last_call_id": "call_3c91",
"awaiting": "tool_result",
"compact_checkpoint": "after_turn_3"
}
这份对象跟 Session、SDK session、Responses conversation、sandbox 都不是同一个资源。删一份不会自动清另一份。数据驻留目前只在美国;自建沙箱也不等于 Zero Data Retention。
五步把跨窗口任务跑完
不要从演示视频倒推。按对象走:
- 创建一次 session,把
session_id写进你的会话。工具表和 Schema 一次收紧。 - 订事件再发后续输入。先订流,再打
agent.session.input.message,否则早期事件会丢。 - 停在 required_actions 就回写。用同一对
turn_id/call_id,不要另开 session 重试。 - 断线拉 items。流不重放。按
order=asc列出,对上单号和等待中的调用。 - compact 之后再核一次账本。摘要里没有
A-1042,下一跳就会填错。
五步都落在对象上,长任务才是可恢复的。少一步,你就是在赌窗口还没满。
复盘长任务,先摊开两段 JSON
出问题的多半不是模型变笨,是对象对不上。
- 把 session items 和你本地状态 格式化,确认
session_id/call_id对得上。 - 用 JSONPath 提取 抽出
order_id、turn_id、subagent 的agent_id。 - compact 前后的 items JSON Diff。单号漂了,先看压缩,再怪模型。
- 主 Agent 的 items 和某个 subagent 的 items 分开列。混在一页里,协调动作会对错人。
- 订单、session、内网 MCP 不要贴进公共格式化站。JSONSort 在浏览器本地跑。
两段轨迹都能重建,你才知道任务是续上的,不是重新猜的。
常见误区
- 以为空闲就是成功。看
turn.completed/failed/cancelled,再看工具结果。 - 断线后等流重放。官方写明流不重放。拉 session 和 items。
- 把单号只活在对话里。compact 之后,摘要可能丢掉
A-1042。 - 开 multi_agent 却不设并发上限。默认 6 个也会扇出 token 和副作用。
- 让 subagent 去跑你的 function。子代理不支持 function 工具。查单留在主 Agent。
- 把 Session 和 Conversation 当成同一份。删一份不会自动清另一份。
FAQ
长时间运行是不是把 prompt 写得更长?
不是。靠的是 durable session、自动 compact、以及你自己存的业务 JSON。更长的系统提示解决不了窗口上限。
Agents API 的 compact 和 Responses 的 compact 能混用吗?
不要混。Agents session 自己压上下文。Responses 用 context_management 或 /responses/compact。两套资源,两套下一窗输入。
断线后怎么恢复?
用存下来的 session_id 取回 session 和 items。流不会重放错过的事件。先对齐 last_turn_id 和未完成的 call_id,再决定回写还是续消息。
subagent 能不能调用我的 lookup_order?
不能。官方写明 subagent 不支持 function 工具。它们继承 MCP、网页搜索和环境里的文件 / 命令。查自家订单,留在主 Agent。
自建沙箱是不是就能做 Zero Data Retention?
不能。官方写明 Agents API 目前只支持美国数据驻留,也不支持 ZDR。选 self-hosted 沙箱不会让它变成 ZDR。
结论
长时间运行不是更聪明的模型。它是一份可续的 Session、一次自动 compact、以及你自己握住的 JSON 状态。工具参数、turn 事件、subagent items,都只是这条链上的对象。
先写清你断线后还能不能重建 A-1042。能,任务才算活着。模型会换;session_id 和 Schema 应该先稳定。
延伸阅读
- OpenAI Agents API 完整解析 Session、Tool Calling、Schema 怎么接
- Agents API vs Responses API 循环该由谁跑
- AI Agent 是什么?完整指南 运行时与 JSON 契约
- AI 为什么需要 JSON Schema Schema / Function Calling / Structured Output
- JSON Schema 与 Agent 工作流 把工具和状态收成 Schema
- JSONSort 本地工具箱 格式化、校验、Diff
- 全部文章 更多 JSON 与 AI 开发笔记
更新记录: 首次发布