OpenAI Agents SDK 工程笔记:RunConfig.reasoning_item_id_policy 推理项 ID 保留/剥离与生产禁区
排障同学盯着一条跨厂商转写任务:上一回合的 reasoning 项带着 rs_tenantA_trace_... 形态的 ID 进了下一回合模型输入,也进了导出日志。另一条线则相反——为了“干净”设了 omit,断点续跑却还按旧 ID 去找推理段,对不上就整段重算。问题不在推理正文要不要给模型看,而在你把推理项 ID 的保留或剥离当成了可忽略的边角配置。真正决定续跑、审计与泄漏面的,是 RunConfig.reasoning_item_id_policy。
这篇只讲一个控制面:reasoning item 进入下一回合模型输入时的 ID 策略。它和 Usage 对账、new_items 清单专篇不同;也和“是否把 reasoning 正文塞进上下文”不是同一旋钮。本篇只写 ID 保留/剥离。结论全部在 Agents SDK 0.23.1 源码与离线假输入脚本上核对过,脚本不调用真实模型,结果落在 _w/fail-smoke/reasoning_id_policy.csv。

图注 左侧为 0.23.1 实测行为,右侧为四类种植失败。
源码里的三档与生效点
ReasoningItemIdPolicy 在 0.23.1 是字面量 "preserve" | "omit"。RunConfig.reasoning_item_id_policy 默认 None,文档写明:
| 取值 | 行为 |
|---|---|
None / "preserve" | 保留 reasoning item ID |
"omit" | 从 runner 构建的模型输入中剥离 reasoning item ID |
生效点不止一处。run_item_to_input_item 在 reasoning_item 且政策为 omit 时走 _without_reasoning_item_id,从字典里去掉 id;apply_reasoning_item_id_policy 对已转换的输入列表做同样剥离。prepare_input_with_session 在读历史时(非 OpenAI Conversations 会话)也会套用该政策,避免回放仍携带过期的 rs_... 导致 404。Run / RunState 会把解析后的政策挂到结果上,供续跑与流式跟随回合使用。
关键语义:_should_omit_reasoning_item_ids 仅当政策等于 "omit" 才为真;None 与 "preserve" 都不剥。只数 reasoning 条数、不看 ID 有无与政策快照,等于没观测这个控制面。
离线 smoke:四类种植失败
脚本构造带敏感形态 ID 的假 reasoning 项,分别套 None / preserve / omit,并种植四类误用:
| case | 配置 | 结果 | 说明 |
|---|---|---|---|
| baseline_None | policy=None | ID 仍在 | 与 preserve 同形 |
| preserve | preserve | ID 仍在 | 基线保留 |
| omit | omit | ID 被剥 | 哈希变化 |
| F1_preserve_leak | preserve 且把输入片段写入日志 | 敏感 ID 进日志 | 泄漏 |
| F2_omit_resume_miss | omit 后仍按 ID 续跑 | resume_miss | 断点对不上 |
| F3_no_policy_snapshot | 未落政策快照却宣称可审计 | unauditable | 假审计 |
| F4_callback_id_dedupe_miss | omit 后 session 回调仍按 ID 去重 | 去重键失效 | 与会话合并叠加 |
F1 最常见。生产默认 preserve(或 None)时,ID 可能编码租户、内部 trace 形态。导出到跨租户可读的日志、提示词缓存键或第三方评测集,就变成泄漏面。评测若只断言“有 reasoning 项”,不断言“对外载荷无内部 ID 形态”,F1 会长期绿着。
F2 是 omit 的配对事故。剥离之后,任何“按 reasoning id 取回中间态”的续跑、缓存、人工审批单都会找不到。正确续跑应改用 run_state / 业务侧稳定键,或在 omit 场景禁止 ID 寻址。
F3 出在可观测性。监控只数 reasoning 条数,不落 policy 与“ID 是否存在”的布尔/哈希。出事故时无法证明当时到底是 preserve 还是 omit,更无法证明导出是否含 ID。可审计必须包含政策快照。
F4 与 session_input_callback 叠加。回调作者以为还能按 ID 做集合差去重,实际 omit 已把 ID 剥掉,去重误判为“新项”,准备输入或落库逻辑偏移。两旋钮同开时,变更单要写清去重键算法。
推荐契约
from agents import RunConfig
# 对外转写 / 跨租户回放:倾向 omit,并禁止按 reasoning id 续跑
run_config = RunConfig(reasoning_item_id_policy="omit")
# 同租户断点续跑且需要 ID 寻址:显式 preserve,并脱敏日志
# run_config = RunConfig(reasoning_item_id_policy="preserve")
契约五条。一,对外暴露的模型输入片段、日志、评测 dump 在 preserve 下必须过 ID 形态脱敏,或改 omit。二,omit 场景禁止业务按 reasoning id 做断点续跑;改用 RunState 序列化或业务键。三,每次 run 落 reasoning_item_id_policy 快照与 ids_present(或输入片段哈希)。四,与 session_input_callback 同开时,去重不得假设 ID 仍在。五,不要用本政策代替“是否放入 reasoning 正文”的上下文策略。
生产禁区
| 禁区 | 为什么 |
|---|---|
| preserve 默认却把含租户形态 ID 打进日志/跨租户回放 | F1 |
| omit 后仍按 ID 续跑 | F2 |
| 只数 reasoning 条数、不落政策快照 | F3 |
| 回调按 ID 去重却已 omit | F4 |
| 把 ID 政策当成正文是否入上下文的开关 | 旋钮误用 |
| 跨厂商转写不做政策与哈希对照 | 泄漏与对不上并存 |
当天最小实验
九十分钟。
- 基线:policy=None 与 preserve,断言 ID 保留且片段哈希一致。
- omit:断言 ID 消失且哈希变化,记 CSV。
- 种植 F1:preserve 下把片段写入假日志,门禁正则拦内部 ID 形态。
- 种植 F2:omit 后按旧 ID 查找,断言 miss。
- 种植 F3:故意不写政策字段,断言审计校验失败。
- 种植 F4:omit + 假回调按 ID 去重,断言误判。
- 提交 runbook:对外默认 omit;同租户续跑若 preserve,日志必须脱敏。
验收标准不是“推理更干净”,而是四类种植失败稳定复现,且 policy + ids_present + frag_hash 可查。
和会话合并怎么并排
prepare_input_with_session 在读历史时会套用 ID 政策。先 omit 再让回调按 ID 过滤,等于在空键上做集合运算。并排验收表增加列:policy / callback_dedupe_key / ids_present。callback_dedupe_key=id 且 ids_present=false 不得合入。
OpenAI Conversations 会话路径对历史 ID 的处理与普通 session 不完全相同;本机核实注释写明非该会话才在读路径套用剥离。切换会话实现时要重跑种植包,不要假设行为一致。
变更单三句话
- 本变更显式设置
reasoning_item_id_policy,并写明续跑是否依赖 ID。 - CI 对 preserve 导出做敏感 ID 形态检查,对 omit 做 resume-by-id 必失败用例。
- 监控已采政策快照、ids_present 与片段哈希;缺快照告警。
审计字段最少清单
run_id、reasoning_item_id_policy、ids_present、frag_hash、exported、resume_key_type。resume_key_type 只能是 run_state / business_key / reasoning_id;选后者时政策必须为 preserve,且导出通道关闭或脱敏。
预发口令
第一,对外载荷是否可能含内部 ID 形态?有则 omit 或脱敏。第二,续跑键是否仍是 reasoning id?是则禁止 omit。第三,审计有无政策快照?无则不得宣称可审计。三句都过,ID 控制面才算起作用。
当天验收口令的补充句
第四,对外 dump 是否先经过与线上一致的 policy?不一致就冻结评测。第五,compaction 快照是否绑定了当时政策?换政策不得偷用旧快照。两句并入预发口令后,再签发布。
与用量、正文上下文的边界
Usage 对账关心 token 与请求次数;本政策不改计价公式,只改输入项是否带 ID 字段。有人以为 omit 会少算 reasoning token,这是误解——剥的是 ID,不是整段 reasoning 正文。若要控制正文是否进入上下文,应使用你们的上下文裁剪链(含 session 回调或 call_model_input_filter),不要扭 ID 政策。
跨厂商转写时,保留 ID 可能让对端 404 或拒识;剥离 ID 又可能让本侧续跑失联。转写工单应同时勾选:对端是否需要 ID、本侧续跑键是什么、导出是否对外。三勾缺一,按 F1/F2 处理。
假模型脚本怎么接 CI
CI 不必起真实模型:构造 type=reasoning 且带 id 的字典列表,直接调用 apply_reasoning_item_id_policy。断言表与本文 CSV 同构即可。若内部封装了 runner,再加一层“经 runner 构建的 next-turn input”集成测试,但仍可对假响应,无需网络。
什么时候选 preserve,什么时候选 omit
同租户、同存储、需要把审批挂到某一段推理 ID 上时,preserve 更省事:人工回放可以点到具体 rs_...。前提是日志与导出管道按内网级别保护,且 ID 形态不含可拼出租户号的明文;若 ID 本身就带租户前缀,preserve 等于把租户编进每一份转出的模型输入。
跨厂商、跨环境、给评测集或外部合作方看输入时,默认 omit。对端不认识你的 ID 空间,留着只会增加拒识与泄漏面。omit 之后,把续跑设计成“序列化 RunState / 业务幂等键”,不要保留“打开旧 ID”的隐藏依赖。
从 None 迁到显式 preserve 或 omit 时,不要只改配置。先扫一遍代码里是否存在 reasoning_id = item["id"] 之类寻址;再扫日志字段是否打印整段 input item。两处扫完,再合配置。
敏感 ID 形态的门禁正则
F1 门禁不必完美解析所有厂商 ID,只要卡住你们已确认的内部形态。例如断言对外 dump 中不出现 rs_tenant、内部 trace 前缀、或与租户表可关联的固定片段。正则假阳性可以进白名单,但白名单必须按文件级别审批,不能因为“都是调试”就全局关闭。
评测集入库前加一步:用与生产相同的 policy 跑一遍 apply_reasoning_item_id_policy,再存盘。避免“训练/评测样本是 preserve,线上是 omit”的静默分布漂移。
续跑键设计
推荐三级键,按优先级:
- RunState 官方序列化(若业务已接入);
- 业务幂等键(订单号、工单号、会话号 + 回合序号);
- 仅当政策为 preserve 且环境为同租户内网时,才允许 reasoning id。
变更单若勾选第 3 级,必须同时勾选“导出关闭或脱敏”。只勾第 3 级不勾脱敏,按 F1 打回。
与 compaction、会话实现的交叉
compaction 相关路径会把成功交换与当时的 reasoning_item_id_policy 绑在一起,避免用另一套政策回放旧摘要。换政策等于换审计世代:旧快照不得用新政策静默重放。OpenAI Conversations 会话与普通 session 在读历史是否套用剥离上有分叉,切换实现时重跑种植包。
值班排障清单
遇到“续跑找不到推理段”:先看政策是不是 omit,再看续跑键类型,最后才怀疑存储丢项。遇到“日志里冒出租户形态 ID”:先看政策是不是 preserve/None,再看导出是否走了未脱敏通道。两份清单贴在 runbook,比把问题一律甩给模型厂商快。
数字与行为均按本机 openai-agents 0.23.1 核实:默认 None;None/preserve 保留;omit 剥离;读历史与写转换路径均可能套用。离线 CSV 见 _w/fail-smoke/reasoning_id_policy.csv。升级次版本先重跑种植脚本。接口若改名或默认值变化,以源码与种植 CSV 为准,不硬背旧结论。
更多推荐



所有评论(0)