执行结果
当您运行智能体时,您将收到以下之一:
- 如果调用
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 |
OpenAI Responses API 链式调用中的 previousResponseId | 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。 - 用于 Responses 工具搜索请求及其返回的已加载工具定义的
RunToolSearchCallItem和RunToolSearchOutputItem。 - 用于工具调用及其结果的
RunToolCallItem和RunToolCallOutputItem。 - 用于因等待审批而暂停的工具调用的
RunToolApprovalItem。 - 用于交接请求和已完成转移的
RunHandoffCallItem和RunHandoffOutputItem。
只要您需要知道某个条目是由哪个智能体生成的,或者它是否标记了工具、工具搜索、交接或审批边界,就应选择 newItems 而不是 output。当您使用 toolSearchTool() 时,这些工具搜索条目也是检查在常规工具调用发生前加载了哪些延迟工具或命名空间的最简单方式。
继续或恢复对话
Section titled “继续或恢复对话”当前活跃智能体
Section titled “当前活跃智能体”lastAgent 属性包含最后一个运行的智能体。在发生交接后,这通常是下一轮用户输入应继续复用的最佳智能体。activeAgent 是同一值的别名。
在流式模式下,当运行仍在进行时,currentAgent 会告诉您当前哪个智能体处于活跃状态。
中断与可恢复状态
Section titled “中断与可恢复状态”如果某个工具需要审批,运行会暂停,interruptions 中将包含待处理的 RunToolApprovalItem。这可能包括直接工具触发的审批、交接后到达的工具触发的审批,或嵌套 agent.asTool() 运行中触发的审批。
通过 result.state.approve(...) / result.state.reject(...) 处理审批,然后将同一个 state 传回 run() 以恢复运行。您不必一次性处理所有中断。如果您在只处理了部分条目后重新运行,已解决的调用可以继续执行,而未解决的调用将保持待处理状态,并再次使运行暂停。
state 属性是结果背后可序列化的快照。可将其用于人机协作、重试流程,或任何需要稍后恢复已暂停运行的场景。
服务器管理的延续
Section titled “服务器管理的延续”lastResponseId 是在使用 OpenAI Responses API 链式调用时,下一轮作为 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:在运行过程中跟踪当前活跃智能体。
如果您需要流式运行的稳定最终状态,请在读取 finalOutput、history、interruptions 或其他摘要属性之前等待 completed。如需逐事件处理,请参阅流式传输指南。
如果流式运行被取消,completed 在清理完成后仍会 resolve,且 cancelled 会变为 true,但诸如 finalOutput 之类的回合结束字段可能仍未设置,因为当前回合从未完成。此时应使用 result.state(以及相同的 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, }); }}