如果你正在维护 Python Agent、local MCP 工具或 Session 后端版本升级不能只验“能启动”。这篇历史版本复盘把输入拒绝、恢复对账和本地环境分别转成验收项并逐一标出哪些是官方修复、哪些只是应用层建议。升级 Agent SDK 时最容易漏掉的不是“程序是否还能启动”而是一次看起来合法的工具调用在暂停、恢复、重试或切换执行环境后是否仍然属于原来的调用者、原来的参数和原来的副作用边界。OpenAI Agents SDK Pythonv0.22.1的 Release 变化正好把这条链路拆成了几个必须分别验收的契约local MCP Server 转换工具的 Server 级 Guardrail、可调用审批策略遇到缺失或空字符串参数时的 fail-closed、审批恢复和 Session 持久化、opt-in 的本地 Unix 环境隔离、Shell 工作目录以及取消清理。它们共同说明一个判断工具审批不是在按钮上点一次“允许”而是从入口到执行器、从暂停到恢复、从状态写入到副作用落地的一组连续核对。本文是历史版本的运行契约复盘不是当前最新版推荐。v0.22.1发布于 2026-09-08T09:18:00Z北京时间 9 月 8 日 17:182026 年 10 月 5 日采集并核验官方来源10 月 6 日冻结本次返工版本。本文只做静态整理目的是把升级时应补的回归矩阵写清楚。文中示例是框架无关的伪代码和测试思路不代表本项目已经接入、升级或运行该 SDK除明确标出的官方行为外矩阵、指纹和观测要求都是工程建议不是 SDK 已保证的功能。一、为什么“冒烟测试通过”仍然不够一个最小的冒烟测试通常只做三件事启动 Agent、调用一个工具、得到一个响应。这能发现导入错误、明显的类型错误和最短路径上的网络故障却无法覆盖以下情况风险最短路径为什么可能通过需要补的证据local MCP Server 转换出的工具未全部经过 Guardrail只测了第一个工具其他工具仍可绕过策略同一 local Server 暴露的每个 converted tool 都经过同一策略可调用审批策略遇到缺失或空字符串参数测试使用了完整参数未覆盖None或该审批路径对不可检视输入直接中断显式{}是否拒绝须另验 schema 和业务约束审批在恢复后被复用新 Run 没有暂停审批只在内存中存在恢复时重新核对调用者、工具和最终参数Session 写入失败后仍继续调用测试存储一直成功未注入半途失败停止后续模型/工具调用并恢复或对账到一致状态是否回滚按后端契约证明本地执行环境被误当成安全边界只验证命令能跑没有观察工作目录、凭据和网络环境 allowlist、目录、取消与清理记录可回读这几类问题都有一个共同特征系统表面上“没报错”但运行契约已经漂移。升级门禁应该先定义失败终态再去验证成功路径。二、v0.22.1 的变化应如何读官方 Release 提到的变化可以按四个层次理解。第一层是工具入口可为 local MCP servers 配置输入、输出 Guardrail并统一施加到每个 converted tool可调用needs_approval策略遇到缺失或空字符串参数时 fail-closed。第二层是暂停恢复特定序列化审批恢复路径修复了当前响应 item 的归属失败的 resumed Session append 在进一步模型调用前对账已完成工具不重跑。第三层是执行环境新增 opt-in 的 Unix-local 环境隔离默认仍继承宿主环境并包含 Shell 命令列表工作目录和取消清理修复。第四层是工程验收上面这些 SDK 修复各有适用范围不能推导出通用业务授权、事务或沙箱保证项目仍需用自己的回归样例证明。因此升级清单不能只写“把版本号改成0.22.1”。它至少要回答四个问题每个 local MCP Server 转换出的工具在到达执行器前是否都经过相同的策略恢复时继承的到底是哪一次批准、哪一组参数和哪一个调用主体状态写入失败时系统是否会停止后续模型调用和工具副作用并恢复或对账到一致状态本地执行环境的目录、变量、取消和清理是否有可观察证据三、第一道门Server-wide Guardrail 不能只测一个工具local MCP Server 级 Guardrail 的价值是让同一 Server 下转换出的工具共享输入或输出检查。PR #4632 区分了二者输入检查沿既有工具执行和审批生命周期运行输出检查面对的是转换后的 SDKToolOutput不是原始 MCPCallToolResult。输出拒绝发生在工具已有结果之后不能被写成“保证工具尚未执行”或“撤销外部副作用”。但“配置了 Server 级 Guardrail”不等于“所有路径都已经被项目证明覆盖”。工具列表变化、动态注册、错误分支和恢复路径都应分别验收。建议先建立一份运行时工具清单至少包含工具名、输入 schema、是否有外部副作用、所属 Server 和当前策略。然后对每个工具运行允许调用、输入策略拒绝、输出策略拒绝和参数无效四类样例。输入拒绝样例的关键断言不是返回了一条错误消息而是下游执行次数为零外部系统没有新增记录审计日志能定位到拒绝发生在执行器之前输出拒绝必须单独记录已发生的工具执行和副作用不能套用“执行次数为零”。可以把断言写成下面这种框架无关的形式。零副作用断言只适用于输入 Guardrail 拒绝输出 Guardrail 拒绝必须单独核对已发生的执行和副作用。# 输入拒绝专用 fixture输入未通过调用不能到达执行器。input_resultawaitrun_tool(namesend_email,argumentsinput_rejected_payload,)assertinput_result.statusrejectedassertinput_result.rejection.stageinput_guardrailassertside_effect_counter(send_email)0assertaudit.last.stageinput_guardrail# 输出拒绝发生在工具返回结果之后不能推断执行次数为零。output_resultawaitrun_tool(namesend_email,argumentsoutput_rejected_payload,)assertoutput_result.statusrejectedassertoutput_result.rejection.stageoutput_guardrailassertexecution_counter(send_email)1assertside_effect_counter(send_email)observed_side_effect_count如果同一个 local Server 既有只读查询也有写入、发送或删除工具不能因为只读工具通过就把整组策略标成通过。策略应按工具能力分层但覆盖性要按 Server 的完整 converted tools 暴露面验收。还要留意输入 Guardrail 的边界。输入门禁回答的是“这次调用能否到达执行器”不能代替工具自身的 schema 校验、业务权限、资源归属、租户隔离和目标对象存在性检查。输出检查则是另一条结果检查路径。Server-wide 策略也不自动扩展到远程 MCP Server 或另一个本地 Server跨 Server 的统一授权仍需要应用层或网关层显式设计。四、第二道门空参数必须保持 fail-closed这里的 “empty tool arguments” 不能简单翻译为“空对象”。PR #4545 针对可调用needs_approval策略检视 function-tool 参数的路径工具参数串缺失None或为空字符串时旧逻辑中的arguments or {}会把它们转换成{}导致依赖参数内容的审批策略可能返回“不需审批”工具继续执行。现在这些不可检视输入会直接中断不进入该审批 predicate也不执行工具无效 JSON 已通过此前修复保持 fail-closed。同一解析 helper 用于 Runner 工具执行和 Realtime session 工具调用不能将这个修复扩大成所有工具输入的通用校验保证。需要特别区分的是显式传入字符串{}仍是合法空对象。它之后是否拒绝取决于工具 schema 是否声明 required 字段、字段是否有minLength等约束以及业务层是否允许空参数。不能把该修复表述成“官方补丁会直接拒绝所有空对象”。至少准备以下互相独立的样例参数串缺失None参数串为空字符串显式传入{}而工具声明需要path应由 schema 校验拒绝调用传入{path: }但空字符串不符合业务约束调用传入未知字段且未知字段可能改变执行目标schema 中的必填字段类型不匹配。每个样例都要区分“输入不可检视”“schema 验证错误”和“执行错误”。前两类错误发生在工具进程启动前不能等工具启动后再由业务代码兜底。错误消息可以告诉调用方缺什么但不能回显密钥、完整凭据或内部路径。本文确指None和不把只含空格的字符串、显式{}或其他数据类型统称为同一个补丁用例。空参数的回归还应和审批恢复组合起来。作为应用层验收建议一个先被批准、随后参数串被清空的调用不能沿用旧批准一个先被拒绝、随后补齐参数的调用应重新计算调用身份并重新走审批。这些组合需要项目实测本文没有运行它们。五、第三道门审批必须绑定“这一次调用”暂停恢复最危险的误区是把审批看成一个布尔值approved True。官方 PR #4613 的修复范围是配置了输出 Guardrail 的后续轮次序列化审批恢复以 live item identity 保存 schema 1.17 的当前响应归属恢复 processed 和 interruption identity并让 schema 1.16 或不一致检查点在获批工具执行前 fail-closed。这里的 item 归属不能翻译成“已验证业务用户或租户”。应用层另外需要保存一次具体调用的身份包括调用主体、工具标识、规范化后的最终参数、目标资源、运行版本、Session 或检查点版本以及批准的有效期和撤销状态。下表与指纹示例属于应用设计建议不代表这些字段全部由 SDK 自动维护。可以用稳定摘要表达“工具 参数”的一部分身份importjsonfromhashlibimportsha256defcall_fingerprint(tool:str,arguments:dict)-str:bodyjson.dumps({tool:tool,arguments:arguments},ensure_asciiFalse,sort_keysTrue,separators(,,:),)returnsha256(body.encode()).hexdigest()这里sort_keysTrue只解决字典键顺序导致的伪变化不能替代调用主体、资源租户、有效期和撤销状态。工具名称变化、目标资源变化、任何有效参数变化都应让指纹发生变化。生产实现还应防止不同类型在规范化时被错误折叠例如字符串1不应和数字1被当作同一参数。审批恢复的最小回归矩阵如下场景预期暂停后原调用完整恢复可恢复调用身份和参数摘要不变恢复前工具名变化必须重新审批恢复前目标资源变化必须重新审批恢复前任一有效参数变化旧审批失效恢复时调用主体变化旧审批失效审批已过期或被撤销旧审批失效审批记录损坏或缺字段fail-closed不继续执行注意“批准后参数变化”不仅包括用户直接修改也包括模型在恢复前重新生成参数、服务端补默认值、别名解析和资源重定向。最终送进执行器的参数才是验收对象。六、第四道门Session 写入与执行必须有一致性边界Release 中关于 Session 写入和恢复失败的修复提醒我们把持久化当成运行契约的一部分。假设审批已完成系统准备把新的状态写入 Session如果写入在中途失败最危险的行为是继续请求模型或启动工具因为内存中的状态和持久化状态已经不一致。PR #4630 的处理方式是保留失败的 resumed appends在继续模型调用前完成恢复或对账并且不重跑已经完成的工具。PR #4630 明确要求恢复使用原后端、独占历史访问handoff/terminal recovery 和分布式 exactly-once 不在修复范围。一个可靠的测试需要主动注入写入失败随后观察模型调用次数、工具执行次数和 Session 内容。对“已完成工具、写入结果失败”的恢复样例关键断言应是对账前没有进一步模型调用恢复不重跑已完成工具已发生副作用计数保持原值而不是变成零。对“工具尚未启动、先提交状态失败”的应用设计样例则另外断言没有新的执行。具体是否通过替换回滚、追加补偿或其他方式恢复需要由采用的后端契约证明不能统一写成“必然回滚”。如果业务确实需要重试必须使用明确的幂等键并说明重试的是状态提交还是外部副作用。不能用“再跑一遍”掩盖一次不确定的发送、扣款或写入。恢复后的检查点也应记录版本号避免两个并发恢复分支互相覆盖。可以把一次恢复拆成几个可观测阶段读取检查点 → 校验调用主体 → 校验工具与参数 → 校验审批有效期 → 写入恢复状态 → 提交 Session → 允许模型继续 → 允许工具执行这条顺序是建议的应用层门禁不是 SDK 的统一执行时序“工具已完成、结果写入失败”的恢复路径必须保留既有执行事实。任一阶段失败都应停在该阶段并留下原因。只有一致性对账或恢复完成、必要的 Session 提交成功之后才允许继续。日志中需要有检查点版本、调用指纹和阶段名称但不要写入完整敏感参数。七、第五道门本地环境不是天然沙箱Unix-local环境、工作目录保留和取消清理为本地 Shell 执行提供了更清晰的契约但只有环境隔离配置是这里讨论的 opt-in 能力不能把所有工作目录和清理修复也叫作 opt-in。UnixLocalSandboxClient默认仍继承完整宿主环境设置inherit_host_environmentFalse才使用 SDK 的内置安全 allowlist也可以通过host_environment_allowlist指定应用自己的精确变量集合。Manifest.environment仍可覆盖所选宿主基线HOME固定到 workspace。继承策略属于受信任的运行时配置用于新建和恢复 session不序列化进 session state。“本地”也不等于“没有权限边界”。同一用户权限下工作目录可能含有凭据环境变量可能带着令牌网络仍可能可达取消也可能留下子进程或 PTY。未启用环境隔离时验收只能证明继承关系和风险可见不能写成已经完成环境收紧。回归时至少观察以下内容工作目录是否是配置值而不是进程启动目录的偶然继承启用隔离时环境变量是否符合 allowlist未启用时是否明确记录宿主环境继承秘密是否通过专门的注入机制传递取消后主进程、子进程和 PTY 是否都结束依赖、临时文件和输出是否按约定清理失败日志是否脱敏网络、文件和凭据权限是否符合项目真正的隔离模型。建议先使用无副作用命令验证目录、环境和取消再为实际工具补充最小权限测试。不要用“命令执行成功”作为安全证据安全证据应当是权限被限制、取消可观察、清理可回读。八、把版本升级变成一张可执行矩阵升级前可以先用这张表冻结验收范围维度最小样例通过证据工具入口每个 local MCP converted tool 分别测允许、输入拒绝、输出拒绝输入拒绝时执行次数为零输出拒绝记录既有执行不声称副作用回滚参数校验可调用审批路径的None/、无效 JSON另外测{} required、类型错误、未知字段区分补丁行为和应用 schema/业务约束错误脱敏审批恢复原调用、工具变化、参数变化、主体变化只有完整匹配才继承批准Sessionresumed append 失败及恢复另测应用提交失败原后端和独占访问条件可证明进一步模型调用前对账已完成工具不重跑本地环境默认继承、opt-in allowlist、目录、取消、PTY 清理默认值和启用后的隔离边界分别有可回读记录并发恢复两个恢复分支争用同一检查点版本冲突可见不静默覆盖观测Trace、审计、失败日志能关联检查点和调用指纹且无敏感泄露矩阵应保存“样例输入、预期终态、实际证据、运行版本、执行时间和责任人”。只保存一个“测试通过”布尔值会让下一次升级无法判断到底覆盖了什么。九、适用边界Release 说明不等于项目已验证本文的事实范围很窄只把 OpenAI Agents SDK Pythonv0.22.1与v0.22.0官方 Release 中可核对的变化转成升级门禁建议。没有安装 SDK没有升级锁文件没有连接 MCP Server没有调用真实模型没有运行 Sandbox也没有验证本项目的 Session 后端、业务授权或生产流量。因此以下说法目前都不能成立“项目已经升级到v0.22.1”“MCP 工具已经全部通过 Guardrail”“恢复审批已经在生产环境安全”“本地 Unix 环境可以替代容器或其他隔离方案”“官方 Release 已证明本项目没有越权风险”。能够成立的说法是官方 Release 暴露了需要回归的运行契约上面的矩阵提供了进入真实升级和发布前验证的最小骨架。下一步若要进入实战应在项目实际采用该 SDK 后在自己的隔离测试环境加入“缺失/空字符串参数 已批准恢复 Session 写入失败”的组合用例并记录执行次数和最终状态。不能把其他 SDK 的本地模拟结果移植为本 SDK 的实测证据。十、上线前检查清单记录 Agents SDK、MCP SDK 和运行环境的精确版本。列出每个 local MCP Server 的全部 converted tools、schema 和副作用等级远程 Server 另行取证。每个工具按实际能力分别测输入拒绝、输出拒绝及 schema 错误可调用审批路径另测None/、无效 JSON 和显式{}。输入拒绝证明下游执行未启动输出拒绝记录已经发生的工具执行和副作用。审批指纹绑定工具、规范化参数、调用主体和有效期。恢复时工具、资源、主体或参数变化都会使旧审批失效。resumed Session append 失败时对账先于进一步模型调用已完成工具不重跑原后端和独占访问条件可证明。本地执行环境的默认继承关系、opt-in allowlist、工作目录、取消和清理可回读。Trace 能关联检查点版本和调用指纹日志不泄露敏感值。预发布证据明确写出“静态核验”与“实际运行”的边界。官方来源OpenAI Agents SDK Python v0.22.1 ReleaseOpenAI Agents SDK Python v0.22.0 ReleasePR #4613serialized approval resume ownershipPR #4545fail closed on empty tool argumentsPR #4632server-wide guardrails to MCP toolsPR #4630recover failed resumed Session writesPR #4640configurable Unix-local environment isolation