ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

openai-agents-python RunItem 生命周期全解析:从模型输出到结果、流、会话与回放

openai-agents-python RunItem 生命周期全解析:从模型输出到结果、流、会话与回放 openai-agents-python RunItem 生命周期全解析从模型输出到结果、流、会话与回放【免费下载链接】openai-agents-pythonA lightweight, powerful framework for multi-agent workflows项目地址: https://gitcode.com/GitHub_Trending/op/openai-agents-python本文以 OpenAI Agents Python SDKopenai-agents-python的 RunItem运行项生命周期为主线系统梳理一个语义条目在单次 Agent 运行中如何从模型输出被转换为公开RunItem、内部工具执行记录再流向RunResult、语义流事件、会话持久化、追踪与RunState序列化并最终以输入形式回放给模型的完整链路。读完本文你将掌握三种条目视图new_step_items/session_step_items/generated_items的取舍、新增条目类型时需要同步更新的全部代码面、兼容性红线以及回放完整性的关键算法孤儿调用修剪、reasoning 配对、ID 策略。本文对应的源码参考文档为仓库中的 .agents/references/run-item-lifecycle.md所有代码级结论均可在 src/agents 目录下核实。RunItem 是什么运行中的最小语义单元在继续阅读之前先建立一个基本认知RunItem 是 Agent 运行过程中产生的一个可观测、可回放、可持久化的语义条目。它包裹了来自模型响应的原始条目raw_item同时携带该条目所属的 Agent 引用。其公共定义位于 src/agents/items.py基类RunItemBase持有agent产生该条目的 Agent与raw_item原始 Responses 条目可能是输出项ResponseOutputItem或输入项ResponseInputItemParam基类通过弱引用weakref保存 Agent并提供了release_agent()方法允许下游在需要时释放对 Agent 的强引用以避免内存泄漏基类提供to_input_item()方法将输出项转换为可供模型使用的输入项——这是回放机制的入口。items.py中定义了两组重要类型别名TResponseInputItem/TResponseOutputItem/TResponseStreamEvent分别对应 OpenAI SDK 中的输入项、输出项与流事件RunItem全部 14 种运行项的联合类型详见下文。而ModelResponse同样定义在 src/agents/items.py则是模型适配器返回的统一载体其output字段是一个list[TResponseOutputItem]并携带usage、response_id可用于后续Runner.run的previous_response_id续跑、request_id以及可选的raw_usage快照。ModelResponse.to_input_items()会对所有输出项执行回放清洗剥离created_by等仅输出端存在的字段。条目流一个语义条目的五次变身参考文档给出了运行时一个语义条目的完整流转链路共五个阶段。我们从源码层面逐一印证模型适配器返回模型适配器将 Provider 的输出统一封装为ModelResponse其output字段即ModelResponse.output类型为list[TResponseOutputItem]。这是条目的原始形态。模型响应处理process_model_response()定义于 src/agents/run_internal/turn_resolution.py内部实现见process_model_response函数把识别出的输出项转换为公开的RunItem对象进入ProcessedResponse.new_items内部可执行的工具运行记录如ToolRunFunction、ToolRunHandoff、ToolRunComputerAction、ToolRunCustom、ToolRunLocalShellCall、ToolRunShellCall、ToolRunApplyPatchCall、ToolRunMCPApprovalRequest、ToolRunFunctionNotFound等均定义于 src/agents/run_internal/run_steps.py。ProcessedResponse是这一阶段的核心产物除了上面两类数据外还包含tools_used使用的全部工具名、interruptions等待用户决策的ToolApprovalItem列表等字段并提供has_tools_or_approvals_to_run()与has_interruptions()两个判断方法。工具执行与移交execute_tools_and_side_effects()src/agents/run_internal/turn_resolution.py负责协调工具执行、审批、护栏guardrail与 handoff将执行结果转化为ToolCallOutputItem等输出条目并在SingleStepResult中选定next_step。SingleStepResultsrc/agents/run_internal/run_steps.py的next_step是以下四种联合类型之一NextStepHandoff切换到新 AgentNextStepFinalOutput产出最终输出NextStepRunAgain继续下一轮循环NextStepInterruption因工具审批请求而中断可用于 HITL 人工介入流程。结果分发单步产生的条目随后被分别馈送给RunResult用户可见的结果见 docs/results.md语义流事件RunItemStreamEvent见 src/agents/stream_events.py会话持久化src/agents/run_internal/session_persistence.py追踪tracingRunState序列化src/agents/run_state.py。回放转换可回放条目通过RunItem.to_input_item()或run_item_to_input_item()转换回模型输入后者定义于 src/agents/run_internal/items.py。SDK 独有元数据如工具描述、标题会在回放前被剥离。参考文档特别强调必须把 Provider 载荷、公开 RunItem 与内部执行记录三者区分开。一个 Provider 条目可能只需要被观测而不需要本地执行例如 hosted 工具调用服务器端已经执行完毕而一个本地工具运行记录则可能需要保留选定的 SDK 工具对象与路由身份如ToolRunFunction.function_tool以便后续恢复或审批时使用。三种视图Generated、Session 与 Model Input参考文档指出不要试图把三种视图强塞进同一个列表因为历史持久化、用户可见结果、下一次 Provider 请求的正确性要求各不相同。三者的源码落点如下视图含义源码位置new_step_items当前步骤本轮生成的条目SingleStepResult.new_step_itemssrc/agents/run_internal/run_steps.pysession_step_items完整的、未过滤的条目序列当 handoff 或输入过滤器把某些条目从下一次模型请求中剔除、但会话历史仍须保留它们时使用SingleStepResult.session_step_items同文件generated_items公开的可观测视图当session_step_items存在时优先使用它SingleStepResult.generated_items属性同文件源码中generated_items的实现逻辑src/agents/run_internal/run_steps.py为property def generated_items(self) - list[RunItem]: items ( self.session_step_items if self.session_step_items is not None else self.new_step_items ) return self.pre_step_items items也就是说generated_items 步骤之前的条目 优先取session_step_items否则取new_step_items。这保证了即使输入过滤器或 handoff 历史嵌套nest_handoff_history省略了部分条目用户通过RunResult观测到的序列依然是完整、无断层的。参考文档还特别强调模型输入是一种回放视图而非规范存储视图。在构造下一次 API 请求之前以下内容可能需要进行过滤或归一化审批占位符ToolApprovalItem不允许被转换为输入项其to_input_item()直接抛出AgentsException见 src/agents/items.pySDK 独有元数据strip_internal_input_item_metadata()会剥离_agents_tool_description、_agents_tool_title等内部键不支持的 ID孤儿调用没有对应输出的工具调用。normalize_input_items_for_api()src/agents/run_internal/items.py正是这一层归一化的实现入口。RunItem 类型全景src/agents/items.py 中RunItem联合类型共包含 14 种条目各条目在流事件、回放与持久化中的角色如下表类型语义回放说明InputItem恢复运行时准入的输入携带input_id用于 exactly-once 会话追踪直接作为输入MessageOutputItem模型的文本消息输出走通用输出→输入转换ToolSearchCallItemResponses API 工具搜索请求支持部分 dict 快照剥离created_by后回放ToolSearchOutputItem工具搜索的输出同上HandoffCallItem表示从当前 Agent 移交的 function 工具调用可回放HandoffOutputItem移交发生后的输出携带source_agent/target_agent可回放ToolCallItem工具调用函数、计算机操作、文件搜索、web 搜索、MCP、代码解释器等携带tool_name/call_id属性与tool_origin元数据可回放ToolCallOutputItem工具调用的输出output为工具真实返回值raw_item为字符串表示可携带 SDK 独有custom_datato_input_item()会剥离 hosted 工具输出中的status/shell_output/provider_data等 Responses API 尚不接受的字段ReasoningItem模型的推理条目思维链受reasoning_item_id_policy控制是否保留 IDMCPListToolsItem对 MCP 服务器列出工具的调用可回放MCPApprovalRequestItem/MCPApprovalResponseItemMCP 审批请求与响应可回放CompactionItemresponses.compact产生的压缩条目to_input_item()原样返回raw_itemToolApprovalItem需要审批后才能执行的工具调用不可回放to_input_item()抛出异常必须在构造输入前过滤其中ToolCallItem的tool_name与call_id是属性property支持从 dict 或类型化对象两种形态中提取ToolCallOutputItem.call_id会保证返回字符串。ItemHelpers类则提供了常用的辅助方法例如extract_last_content()、extract_text()、text_message_outputs()、tool_call_output_item()根据工具返回值构造标准function_call_output支持普通字符串、JSON schema 校验输出、结构化输出input_text/input_image/input_file形态。添加或更改条目类型必须同步更新的八个代码面参考文档的核心价值之一是给出了新增条目类型的完整变更清单——每一个适用面都必须同步更新遗漏任何一处都会造成流事件、会话或恢复链路的不一致。逐条对应源码如下公开类型与回放更新 src/agents/items.py 中的RunItem联合类型、访问器与回放转换to_input_item。内部执行记录更新 src/agents/run_internal/run_steps.py 中的ProcessedResponse与各类ToolRun*可执行记录。响应识别与副作用更新 src/agents/run_internal/turn_resolution.py 中的 Provider 输出识别process_model_response、条目创建、副作用与下一步选择execute_tools_and_side_effects/get_single_step_result_from_response。执行、去重、审批与输出更新 src/agents/run_internal 下的tool_execution.py、tool_actions.py或tool_planning.py。归一化与指纹更新 src/agents/run_internal/items.py 中的归一化、回放转换、指纹fingerprint_input_item/digest_input_item、去重deduplicate_input_items/deduplicate_input_items_preferring_latest以及 Provider 边界元数据剥离strip_internal_input_item_metadata。注意其中的_TOOL_CALL_TO_OUTPUT_TYPE映射表例如function_call→function_call_output、shell_call→shell_call_output、tool_search_call→tool_search_output——新增工具调用类型必须同步登记该映射孤儿修剪与去重算法都依赖它。语义流事件更新 src/agents/stream_events.py 及流式队列辅助代码。序列化更新 src/agents/run_state.py使条目在中断后可以存活并恢复。会话持久化更新 src/agents/run_internal/session_persistence.py 中的会话转换、清洗与重试记账如save_result_to_session、admit_pending_input。此外若新条目贡献了可观测的工具或模型工作还需要同步更新追踪tracing与用量usage转换逻辑。兼容性规则参考文档列出了四条红线全部可以从源码中找到印证1. 流事件名称兼容敏感RunItemStreamEvent.name的合法取值定义在 src/agents/stream_events.py其中包括message_output_created、handoff_requested、tool_called、tool_search_called、tool_output、reasoning_item_created、mcp_approval_requested等。值得注意的是源码中的注释handoff_occured, # This is misspelled, but we cant change it because that would be a breaking change也就是说handoff_occured拼写是错误的但它是兼容性敏感的公共事件名即使修复拼写也属于破坏性变更必须走显式的 breaking-change 计划。这是公共流事件名称不得重命名规则的活教材。2. 保留 Provider ID 与不透明数据必须保留 Provider 提供的 ID 与不透明 Provider 数据直到其所属边界有意移除不得凭空发明 ID也不得为了让回放看起来有效而把畸形值强转成合法值SDK 独有元数据用于展示、路由、审批、工具来源或恢复需要保留但在发送给不接受它们的 Provider 之前必须剥离。后者的典型实现是strip_internal_input_item_metadata()它会移除_agents_tool_descriptionTOOL_CALL_SESSION_DESCRIPTION_KEY与_agents_tool_titleTOOL_CALL_SESSION_TITLE_KEY两个内部键而_dedupe_key()中对FAKE_RESPONSES_ID占位 ID 的处理则体现了不把占位值当作真实持久身份的原则。3. 工具调用与输出的 call ID 配对工具调用call与输出output对必须在执行、回放、会话持久化与恢复全链路中保持同一个字符串 call ID。ToolCallItem.call_id与ToolCallOutputItem.call_id都优先从raw_item的call_id字段提取dict 形态还会回退到id而ItemHelpers.tool_call_output_item()在构造function_call_output时直接复用了tool_call.call_id从源头保证了配对一致性。4. 空值与假值输出是合法值空字符串、False、结构化输出、图像、文件与自定义工具输出都是合法的工具返回值除非公共工具契约明确拒绝。源码中ItemHelpers._convert_tool_output()对已知结构化输出类型ToolOutputText/ToolOutputImage/ToolOutputFileContent及带type字段的 dict走结构化转换其余值才走str(output)而_convert_tool_output_as_structured()对空列表/元组有专门保护all([])为True会错误地产生空结构化输出列表导致工具结果丢失因此先判空再 stringify。这意味着代码库刻意避免用宽泛的真值检查来判断输出是否存在。回放完整性孤儿修剪、reasoning 配对与 ID 策略回放replay是把历史条目重新组装成下一次模型请求的过程其正确性直接影响续跑resume与重试。参考文档给出了四组关键规则。1. 孤儿调用只修剪 SDK 拥有配对权的历史prepare_model_input_items()src/agents/run_internal/items.py是核心入口def prepare_model_input_items( caller_items: Sequence[TResponseInputItem], generated_items: Sequence[TResponseInputItem] (), ) - list[TResponseInputItem]: normalized_caller_items normalize_input_items_for_api(list(caller_items)) if not generated_items: return normalized_caller_items normalized_generated_items normalize_input_items_for_api(list(generated_items)) filtered_generated_items drop_orphan_function_calls(normalized_generated_items) return normalized_caller_items filtered_generated_items注意孤儿修剪只作用于 runner 生成的generated_items绝不触碰调用方提供的caller_items除非存在显式的公共归一化契约。同样normalize_resumed_input()只对恢复时的列表输入执行drop_orphan_function_calls()。drop_orphan_function_calls()的修剪逻辑相当精细依据_TOOL_CALL_TO_OUTPUT_TYPE判断哪些调用已有对应输出_completed_call_ids_by_type已完成的调用不会被当作孤儿program程序化工具调用是特殊的父级若有被保留的 hosted 调用或工具输出仍引用它_PROGRAM_OWNED_HOSTED_ITEM_TYPES中的hosted_tool_call、file_search_call、web_search_call、mcp_call等则程序保持活跃否则整条程序调用链会被修剪_is_pending_hosted_shell_call()允许status为in_progress的 hosted shell 调用在没有输出时继续挂起。tests/test_run_internal_items.py中有对应测试例如test_drop_orphan_function_calls_preserves_non_mapping_entries、test_replay_pruning_drops_orphan_program_call_chain、test_drop_orphan_function_calls_preserves_active_program_call_chain、test_replay_pruning_preserves_program_owned_hosted_items可作为行为契约的回归保障。2. 修剪孤儿调用时必须同步删除关联 reasoning 项drop_orphan_function_calls()内部通过_drop_reasoning_items_preceding_dropped_calls()实现若某条工具调用被作为孤儿删除则紧随其后的非 reasoning 条目已被删除时紧邻其前的 reasoning 条目也会被一并删除。原因在 docstring 中写得很清楚——Responses API 会拒绝没有必需后续条目的 reasoning 条目错误信息形如Item rs_... of type reasoning was provided without its required following item。但规则同样重要不要仅仅因为本地的后续条目缺失就删除孤立的 reasoning 条目——如果会话由服务器端管理server-managed conversation state该条目可能归服务器所有本地无权修剪。3.reasoning_item_id_policyomit只剥离 SDK 生成的 IDapply_reasoning_item_id_policy()与run_item_to_input_item(..., reasoning_item_id_policy...)均在 src/agents/run_internal/items.py实现该策略_should_omit_reasoning_item_ids()仅在策略为omit时生效_without_reasoning_item_id()只对type reasoning且携带id的 dict 条目剥离id字段。该策略不重写调用方最初的输入run_item_to_input_item只作用于 SDK 生成的条目必须能在RunState恢复后继续存活result.py中可见_reasoning_item_id_policy会被存入状态并从状态恢复并且可能被后续的call_model_input_filter覆盖——如果过滤器有意返回带 ID 的条目则以此为准。4. 匿名工具搜索配对的边界_matched_anonymous_tool_search_call_indexes()实现了匿名tool_search_call与匿名tool_search_output的配对规则从后向前扫描将匿名输出与最新的兼容匿名调用配对。规则明确匿名输出绝不与命名调用配对缺失 call ID 也不构成发明持久 Provider 身份的正当理由。5.provider_data与 Provider ID 的边界所有权provider_data和 Provider ID 具有边界特定的所有权在原始结果raw results与接受它们的 Provider 请求中应原样保留但在 SDK 契约要求净化条目的会话历史与服务器会话历史中应剥离私有或不适合回放的元数据。这一原则同样体现在ToolCallOutputItem.to_input_item()对provider_data的剥离以及extract_mcp_request_id()/extract_mcp_request_id_from_run()从 hosted MCP 审批载荷中提取请求 ID 时对provider_data.id的兼容处理。审查清单六步验证新条目生命周期参考文档为开发者在修改条目链路后提供的审查清单可直接作为 PR 自检工具全链路追踪从 Provider 响应出发依次跟踪该条目经过 result、stream、session、replay 直到RunState的每一个环节双形态测试当适配器同时支持类型化 Provider 对象与 mappingdict载荷时两种形态都要测试run_internal/items.py中大量isinstance(x, dict)与BaseModel的分支就是为兼容这两种形态而设计往返验证确认 ID、元数据与输出值在每一个必需的往返round-trip中都不丢失过滤与去重测试过滤与去重后最新的合法调用/输出对仍然保留可参考deduplicate_input_items_preferring_latest的因果前驱条目保持在最早位置、其他已识别条目保持最新位置策略以及_DEDUPE_EARLIEST_ANCHOR_ITEM_TYPES对mcp_approval_request、reasoning等锚点条目的特殊处理流序一致性对比流式事件顺序与非流式条目序列是否一致双管理模式测试孤儿修剪与 reasoning 配对必须在客户端管理的回放client-managed replay与服务器端管理的续跑server-managed continuation两种模式下分别验证——二者的所有权边界完全不同。深入阅读公开条目类型与回放转换src/agents/items.py语义流事件定义src/agents/stream_events.py内部条目工具归一化/指纹/去重/孤儿修剪/ID 策略src/agents/run_internal/items.py内部步骤数据结构ProcessedResponse/SingleStepResult/NextStep*src/agents/run_internal/run_steps.py响应处理与工具执行编排src/agents/run_internal/turn_resolution.py会话持久化src/agents/run_internal/session_persistence.py可序列化运行状态RunStatesrc/agents/run_state.py相关测试tests/test_items_helpers.py、tests/test_run_internal_items.py、tests/test_stream_events.py、tests/test_run_state.py面向用户的运行与结果文档docs/running_agents.md、docs/results.md总而言之RunItem 生命周期是 openai-agents-python 运行时的语义主干模型输出、工具执行、移交、审批、护栏、会话、追踪与恢复都围绕这层统一的条目抽象展开。理解本文的三种视图、八个更新面、四条兼容红线与五组回放完整性规则你就能在扩展 Agent 能力新增工具类型、条目类型或 Provider 适配时做到改一处、处处闭环避免流事件、会话历史与续跑链路的隐性断裂。【免费下载链接】openai-agents-pythonA lightweight, powerful framework for multi-agent workflows项目地址: https://gitcode.com/GitHub_Trending/op/openai-agents-python创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表