执行结果
当您运行智能体时,会收到以下两者之一:
- 如果调用
run时未传入stream: true,则收到RunResult - 如果调用
run时传入了stream: true,则收到StreamedRunResult。有关流式传输的详细信息,也请查看流式传输指南。
这两种结果类型都提供相同的核心结果视图,例如 finalOutput、newItems、interruptions 和 state。StreamedRunResult 还添加了流式传输控制项,例如 completed、toStream()、toTextStream() 和 currentAgent。
合适结果视图的选择
Section titled “合适结果视图的选择”大多数应用只需要少数几个属性:
| 如果您需要… | 使用 |
|---|---|
| 展示给用户的最终答案 | finalOutput |
| 带有完整本地对话记录、可直接重放的下一轮输入 | history |
| 仅包含本次运行中新生成的模型格式项目 | output |
| 带有智能体/工具/交接元数据的丰富运行项目 | newItems |
| 通常应处理下一轮用户输入的智能体 | lastAgent 或 activeAgent |
使用 previousResponseId 进行 OpenAI Responses API 链式调用 | lastResponseId |
| 待处理审批和可恢复快照 | interruptions 和 state |
| 应用上下文、审批、用量和嵌套智能体工具输入 | runContext |
当前嵌套 Agent.asTool() 调用的元数据,例如在 customOutputExtractor 内部 | agentToolInvocation |
| 原始模型调用或护栏诊断 | rawResponses 和护栏结果数组 |
finalOutput 属性包含最后运行的智能体的最终输出。此结果可能是:
string—— 未定义outputType的任何智能体的默认值unknown—— 如果智能体将 JSON schema 定义为输出类型。在这种情况下,JSON 已被解析,但您仍必须手动验证其类型。z.infer<outputType>—— 如果智能体将 Zod schema 定义为输出类型。输出将自动根据此 schema 进行解析。undefined—— 如果智能体未生成输出(例如,在生成输出前就已停止)
当流式传输运行仍在进行中,或运行在到达最终输出前因审批中断而暂停时,finalOutput 也会是 undefined。
如果您使用具有不同输出类型的交接,应使用 Agent.create() 方法而不是 new Agent() 构造函数来创建智能体。
这将使 SDK 能够推断所有可能交接中的输出类型,并为 finalOutput 属性提供联合类型。
例如:
import { Agent, run } from '@openai/agents';import { z } from 'zod';
const refundAgent = new Agent({ name: 'Refund Agent', instructions: 'You are a refund agent. You are responsible for refunding customers.', outputType: z.object({ refundApproved: z.boolean(), }),});
const orderAgent = new Agent({ name: 'Order Agent', instructions: 'You are an order agent. You are responsible for processing orders.', outputType: z.object({ orderId: z.string(), }),});
const triageAgent = Agent.create({ name: 'Triage Agent', instructions: 'You are a triage agent. You are responsible for triaging customer issues.', handoffs: [refundAgent, orderAgent],});
const result = await run(triageAgent, 'I need to a refund for my order');
const output = result.finalOutput;// ^? { refundApproved: boolean } | { orderId: string } | string | undefined输入和输出视图
Section titled “输入和输出视图”这些属性回答的是不同的问题:
| 属性 | 包含的内容 | 最适用于 |
|---|---|---|
input | 本次运行的基础输入。如果交接输入过滤器重写了历史记录,这里会反映运行继续时使用的过滤后输入。 | 审计本次运行实际使用了什么输入 |
output | 仅包含本次运行生成的模型格式项目,不含智能体元数据。 | 仅存储或重放新的模型增量 |
newItems | 带有智能体/工具/交接元数据的丰富 RunItem 包装器。 | 日志、UI、审计和调试 |
history | 从 input + newItems 构建的、可直接重放的下一轮输入。 | 手动聊天循环和客户端管理的对话状态 |
实践中:
- 当您在应用中手动维护整个对话时,使用
history。 - 当您已经在其他地方存储了之前的历史记录,只想获取本次运行中新生成的项目时,使用
output。 - 当您需要智能体关联、工具输出、交接边界或审批项目时,使用
newItems。 - 如果您使用
conversationId或previousResponseId,通常不会将history传回run()。相反,只传入新的用户输入并复用服务器管理的 ID。完整对比请参阅运行智能体。
history 是在类似聊天的用例中维护完整历史记录的便捷方式:
import { Agent, user, run } from '@openai/agents';import type { AgentInputItem } from '@openai/agents';
const agent = new Agent({ name: 'Assistant', instructions: 'You are a helpful assistant knowledgeable about recent AGI research.',});
let history: AgentInputItem[] = [ // initial message user('Are we there yet?'),];
for (let i = 0; i < 10; i++) { // run 10 times const result = await run(agent, history);
// update the history to the new output history = result.history;
history.push(user('How about now?'));}newItems 为您提供运行期间所发生事件的最丰富视图。常见项目类型包括:
RunMessageOutputItem,用于助手消息。RunReasoningItem,用于推理项目。RunToolSearchCallItem和RunToolSearchOutputItem,用于 Responses 工具搜索请求及其返回的已加载工具定义。RunToolCallItem和RunToolCallOutputItem,用于工具调用及其结果。RunToolApprovalItem,用于因审批而暂停的工具调用。RunHandoffCallItem和RunHandoffOutputItem,用于交接请求和已完成的转移。
每当您需要知道某个项目由哪个智能体生成,或者它是否标记了工具、工具搜索、交接或审批边界时,请优先使用 newItems 而不是 output。当您使用 toolSearchTool() 时,这些工具搜索项目是检查在正常工具调用发生前加载了哪些延迟工具或命名空间的最简单方式。
如果本地工具或 MCP 服务器定义了 customDataExtractor,对应的 RunToolCallOutputItem.customData 会包含返回的、仅供 SDK 使用的元数据。此数据适用于应用 UI 状态,例如渲染器提示或内部 ID。它会在 RunState 序列化后保留,但会被排除在 history 之外,也不会发送回模型。
对话的继续或恢复
Section titled “对话的继续或恢复”lastAgent 属性包含最后运行的智能体。在交接后,这通常是下一轮用户输入最适合复用的智能体。activeAgent 是同一值的别名。
在流式传输模式下,运行仍在进行时,currentAgent 会告诉您当前哪个智能体处于活跃状态。
中断和可恢复状态
Section titled “中断和可恢复状态”如果某个工具需要审批,运行会暂停,并且 interruptions 会包含待处理的 RunToolApprovalItem。这可能包括由直接工具触发的审批、由交接后到达的工具触发的审批,或由嵌套 agent.asTool() 运行触发的审批。
通过 result.state.approve(...) / result.state.reject(...) 处理审批,然后将同一个 state 传回 run() 以恢复运行。您不需要一次性处理所有中断。如果您只处理部分项目后重新运行,已处理的调用可以继续,而未处理的调用会保持待处理状态并再次暂停运行。
state 属性是结果背后的可序列化快照。将它用于人机协作、重试流程,或任何需要稍后恢复已暂停运行的场景。
服务器管理的延续
Section titled “服务器管理的延续”当您使用 OpenAI Responses API 链式调用时,lastResponseId 是下一轮中作为 previousResponseId 传入的值。
如果您已经使用 history、session 或 conversationId 继续对话,通常不需要 lastResponseId。如果您需要多步骤运行中的每个原始模型响应,请改为检查 rawResponses。
嵌套智能体工具元数据
Section titled “嵌套智能体工具元数据”agentToolInvocation 用于嵌套 Agent.asTool() 结果,尤其是当您位于 customOutputExtractor 内部并希望获取当前工具调用的元数据时。它不是通用的”整个运行已完成”摘要字段。
在该嵌套上下文中,agentToolInvocation 会提供:
toolNametoolCallIdtoolArguments
如果还需要传入该嵌套智能体工具运行的结构化输入,请将它与 result.runContext.toolInput 配合使用。
在普通顶层 run() 结果中,这通常是 undefined。该元数据仅在运行时存在,不会序列化到 RunState 中。有关相关模式,请参阅 Agents as tools。
StreamedRunResult 继承上面相同的结果视图,但增加了流式传输专用控制项:
toTextStream(),仅用于助手文本。toStream()或for await ... of stream,用于完整事件流。completed,用于等待运行和所有后处理回调完成。error和cancelled,用于检查最终流式传输状态。currentAgent,用于在运行过程中跟踪活跃智能体。
如果您需要流式传输运行稳定后的最终状态,请先等待 completed,再读取 finalOutput、history、interruptions 或其他摘要属性。有关逐事件处理,请参阅流式传输指南。
如果流式传输运行被取消,completed 仍会在清理后解析,并且 cancelled 会变为 true,但由于当前轮次从未完成,finalOutput 等轮次结束字段可能仍未设置。请使用 result.state(如果使用了 session,则还要使用同一个 session)恢复这个未完成的轮次,而不是追加一条新的用户消息。
诊断和高级字段
Section titled “诊断和高级字段”runContext 属性是结果上受支持的运行上下文公共视图。result.runContext.context 是您的应用上下文,同一个对象还携带由 SDK 管理的运行时元数据,例如审批、用量和嵌套 toolInput。完整结构请参阅上下文管理。
rawResponses 包含运行期间收集到的原始模型响应。多步骤运行可能会产生多个响应,例如跨交接或重复的工具/模型循环。
inputGuardrailResults 和 outputGuardrailResults 属性包含智能体级护栏结果。工具护栏结果会通过 toolInputGuardrailResults 和 toolOutputGuardrailResults 单独公开。
当您想记录护栏决策、检查护栏函数返回的额外元数据,或调试某次运行为何被阻止时,请使用这些数组。
Token 用量会聚合在 result.state.usage 中,它会跟踪本次运行的请求数和 Token 总数。同一个用量对象也可以通过 result.runContext.usage 获取。对于流式传输运行,此数据会随响应到达而更新。
import { Agent, run } from '@openai/agents';
const agent = new Agent({ name: 'Usage Tracker', instructions: 'Summarize the latest project update in one sentence.',});
const result = await run( agent, 'Summarize this: key customer feedback themes and the next product iteration.',);
const usage = result.state.usage;console.log({ requests: usage.requests, inputTokens: usage.inputTokens, outputTokens: usage.outputTokens, totalTokens: usage.totalTokens,});
if (usage.requestUsageEntries) { for (const entry of usage.requestUsageEntries) { console.log('request', { endpoint: entry.endpoint, inputTokens: entry.inputTokens, outputTokens: entry.outputTokens, totalTokens: entry.totalTokens, }); }}