执行结果
当您运行智能体时,会收到以下两种结果之一:
- 如果调用
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 模式定义为输出类型时使用此类型。在这种情况下,JSON 已完成解析,但您仍需手动验证其类型。z.infer<outputType>——智能体将 Zod 模式定义为输出类型时使用此类型。系统会根据该模式自动解析输出。- 推断出的验证输出类型——智能体将受支持的 Standard 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,用于表示助手消息。RunInputItem,用于表示恢复运行时从RunState.pendingInput接纳的输入。RunReasoningItem,用于表示推理项目。RunToolSearchCallItem和RunToolSearchOutputItem,用于表示 Responses 工具搜索请求及其返回的已加载工具定义。RunToolCallItem和RunToolCallOutputItem,用于表示工具调用及其结果。RunToolApprovalItem,用于表示暂停并等待审批的工具调用。RunHandoffCallItem和RunHandoffOutputItem,用于表示交接请求和已完成的转移。
如果需要知道某个项目由哪个智能体生成,或者它是否标记了工具、工具搜索、交接或审批边界,请选择 newItems,而不是 output。使用 toolSearchTool() 时,通过这些工具搜索项目,可以最方便地检查在常规工具调用发生前加载了哪些延迟工具或命名空间。
如果本地工具或 MCP 服务器定义了 customDataExtractor,相应的 RunToolCallOutputItem.customData 将包含其返回的仅供 SDK 使用的元数据。这些数据适用于渲染提示或内部 ID 等应用 UI 状态。它们会在 RunState 序列化过程中保留,但不会包含在 history 中,也不会发送回模型。
RunToolCallOutputItem.output 是 SDK 侧的工具返回值。与 JSON 兼容的基本类型值、数组和普通对象在 RunState 序列化过程中会保留其结构。其他实时值仍采用现有的字符串回退方式。此包装值与 rawItem.output 保持独立;后者是 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,用于在运行期间追踪活跃智能体。currentTurn,用于检查实际到达请求边界的模型轮次。maxTurns,用于检查本次流式运行所应用的限制(null表示无限制)。
只有当模型请求获准发出时,currentTurn 才会递增。若最大轮次检查或阻塞型输入护栏阻止了请求,该值不会递增;恢复的运行则会从其 RunState 中保留的计数开始。
如果需要获取流式运行的最终稳定状态,请先等待 completed,再读取 finalOutput、history、interruptions 或其他汇总属性。有关逐事件处理方式,请参阅流式传输。
如果流式运行被取消,completed 仍会在清理完成后得到解决,并且 cancelled 会变为 true;但由于当前轮次从未完成,finalOutput 等轮次结束字段可能仍未设置。请使用 result.state(如果使用了 session,还需使用同一个 session)恢复该未完成的轮次,而不要追加新的用户消息。
诊断与高级字段
Section titled “诊断与高级字段”runContext 属性是结果中受支持的公开运行上下文视图。result.runContext.context 是您的应用上下文,同一对象还包含由 SDK 管理的运行时元数据,例如审批、用量和嵌套 toolInput。有关完整结构,请参阅上下文管理。
rawResponses 包含运行期间收集的原始模型响应。多步骤运行可能生成多个响应,例如在交接或重复的工具与模型循环中。
如果输出护栏拒绝了终止型函数工具结果,SDK 会清理 rawResponses 中的当前响应,以及由 SDK 管理的其他重放字段。请勿假定仍可通过此属性检查被拒绝的终止型工具输出。有关脱敏边界和限制,请参阅被拒绝的终止型工具输出。
每个响应还可能包含 requestId,即供应商的请求标识符(如果可用)。OpenAI Responses 和 Chat Completions 模型会为流式和非流式 HTTP 请求填充该字段;由于某些供应商和传输机制不会提供该字段,因此应将其视为可选字段。
对于 Chat Completions 文本输出,请检查规范化 output_text 部分的 providerData.annotations 以读取 URL 引用。非流式响应会保留供应商提供的消息注释。流式响应会保留随文本收到的有效 url_citation 注释、去除重复引用,并忽略格式错误或不受支持的注释结构。
对于 Chat Completions 音频,规范化模型响应会将仅包含音频的助手消息表示为带有 audio 内容部分的消息。当该消息成为运行项目时,可在 RunMessageOutputItem.rawItem 中检查同一部分。如果非流式响应同时包含文本或拒绝内容与音频,规范化助手消息会保留文本或拒绝内容,而完整的供应商响应仍可在 rawResponses[].providerData 中获取。对于流式混合输出,如果需要在供应商音频分块到达时获取它们,请检查原始模型流事件;完成后的 rawResponses 条目包含规范化文本或拒绝内容,但不包含重建后的音频。流式传输的 toTextStream() 辅助方法仅输出文本。
当 modelSettings.preserveRawUsage 为 true 时,每个已完成的响应还可能提供 rawUsage,它是在 SDK 规范化之前捕获的、独立且与 JSON 兼容的快照。规范化后的 Usage 仍可通过 response.usage 获取;rawUsage 会保留供应商特定的字段名,以及供应商所提供字段是省略还是显式赋值的状态。如果供应商省略用量信息,或无法安全复制有效负载,它可能为 undefined。rawUsage 仅在运行时存在,并会特意从序列化的 RunState 中省略,因此请在持久化并恢复运行前复制所需字段。
inputGuardrailResults 和 outputGuardrailResults 属性包含智能体级护栏结果。工具护栏结果则通过 toolInputGuardrailResults 和 toolOutputGuardrailResults 单独提供。
如果要记录护栏决策、检查护栏函数返回的额外元数据,或调试运行被阻止的原因,请使用这些数组。
对于被拒绝的终止型函数工具结果,SDK 会特意清理当前响应的护栏元数据。在 outputGuardrailResults 中,agentOutput 会变为 Output withheld by an output guardrail.,并移除 outputInfo。当前的 toolOutputGuardrailResults 会保留其判定结果,但省略 outputInfo;rejectContent 结果也会使用同一占位文本作为消息。此前已接受的历史结果保持不变。
如果某个护栏执行失败,其他已成功完成的同级护栏结果会保留在运行状态中。对于流式运行,请在 completed 被拒绝后检查结果数组;对于非流式运行,GuardrailExecutionError 会携带同一份已稳定的 state。
令牌用量汇总在 result.state.usage 中,其中会追踪本次运行的请求数和令牌总数。也可通过 result.runContext.usage 获取同一用量对象。对于流式运行,这些数据会随响应到达而更新。
已完成的流式或非流式 Chat Completions 调用都会计为一次请求,即使供应商省略了其用量对象。在这种情况下,由于供应商未报告令牌数,令牌总数会保持为零。
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, }); }}