OpenAI Agents SDK 工程笔记:RunConfig 追踪开关与生产禁区

千笔-AIWritePaper · https://www.aiwritepaper.com

把 Agents SDK 的 tracing 当成「开着就好」很容易踩坑:默认已启用 ,会把 LLM 生成、工具调用、handoff、guardrail 等写入 Traces 仪表盘;但默认也会在 span 里带上可能敏感的输入/输出 。官方 TracingRunning agents 把控制面收在 RunConfigtracing_disabledtrace_include_sensitive_dataworkflow_name / trace_id / group_idtrace_metadata,以及 tracing={"api_key": ...} / include_task_and_turn_spans。全局还有 set_tracing_disabledOPENAI_AGENTS_DISABLE_TRACINGset_tracing_export_api_key、长驻 worker 的 flush_traces()。ZDR(Zero Data Retention)组织上 tracing 不可用 。本文按工程笔记钉死开关语义、可跑 smoke 与生产禁区。示例模型名写作 gpt-4o以你账号可用快照与官方文档为准

图:上方 RunConfig 追踪字段;中部敏感数据与导出键;下方生产禁区与 flush。

目标说明

读完你应能独立完成五件事:

  1. 用一句话说清:tracing 默认开;单次 run 用 RunConfig.tracing_disabled=True 关,或用环境变量 / set_tracing_disabled 全局关。
  2. 写出可跑片段:RunConfig(workflow_name=..., group_id=..., trace_include_sensitive_data=False) smoke。
  3. 分清三层关闭:全局 env / 代码全局 / 单次 RunConfig;以及「关 tracing ≠ 立刻丢掉已缓冲导出」。
  4. 钉死敏感数据:trace_include_sensitive_data=False(或 OPENAI_AGENTS_TRACE_INCLUDE_SENSITIVE_DATA=0)省略 generation/function 的原始 I/O。
  5. 列出生产禁区:默认开敏感数据上生产、ZDR 环境仍指望仪表盘、Celery/FastAPI 后台任务不 flush_traces、把模型流量密钥与 tracing 导出混用却不隔离。

规格钉死(对照官方 Tracing / RunConfig):

  • 默认 :tracing 开启;默认 workflow 名是字面量 Agent workflow
  • 关闭三路径OPENAI_AGENTS_DISABLE_TRACING=1set_tracing_disabled(True)RunConfig(tracing_disabled=True)
  • 敏感数据RunConfig.trace_include_sensitive_data 默认 True;可按 run 关,或用环境变量改默认。
  • 元数据workflow_name / trace_id(须 trace_<32 字母数字>)/ group_id / trace_metadata
  • 导出键 :可用 set_tracing_export_api_key;单次 run 可用 RunConfig(tracing={"api_key": "..."});模型客户端可 use_for_tracing=False 再单独配 tracing 键。
  • 长驻进程BatchTraceProcessor 后台批导出;需要立刻可见时在 trace() 退出后调用 flush_traces()

适用边界

适合开 tracing

  • 开发与预发:要看 agent / generation / tool / guardrail / handoff span。
  • 多轮会话:用同一 group_id(如 thread id)串联多条 trace。
  • 非 OpenAI 模型:仍可用 OpenAI tracing 导出键把链路送到 Traces 仪表盘(见官方 third-party 说明)。
  • 需要按工作流命名:workflow_name="客服退款" 比默认 Agent workflow 可检索。

更适合先关或脱敏

  • 生产处理 PII / 密钥 / 病历 :先 trace_include_sensitive_data=False,再决定是否整 run 关闭。
  • ZDR 组织:官方写明 tracing 不可用;不要把「仪表盘空白」当 SDK bug。
  • 合规要求不得出境调试载荷 :关 tracing 或自建 set_trace_processors,不要默认打到 OpenAI 后端还当「本地日志」。

不该指望它单独搞定

  • 关 tracing = 已缓冲数据消失 :禁用后仍可能 flush_traces() 导出已缓冲内容。
  • include_task_and_turn_spans=False = 无追踪:只是更紧凑;agent/generation/function 等仍记。
  • response_id 相关元数据 = 已脱敏完毕:官方端点在脱敏后仍可能保留关联 id;自定义端点行为不同,勿一刀切假设。
  • 日志开关 = tracing 开关OPENAI_AGENTS_DONT_LOG_MODEL_DATA 管的是 Python 日志/诊断,不是 Traces 仪表盘。

风险提示

把生产流量的默认敏感 span 直接导出到共享项目,等于把用户输入写进可检索调试面。长驻 worker 不 flush,排障时会误判「没跑到 tracing」。模型走兼容端点却继续用同一把业务键导出 tracing,权限面纠缠难审计。

步骤与机制

1. RunConfig 追踪字段对照

字段 / 开关 做什么 不做什么
tracing_disabled 本 run 不记录 不清理已缓冲导出
trace_include_sensitive_data 是否纳入 LLM/工具 I/O 不等于关 tracing
workflow_name 逻辑工作流名 不是计费标签
group_id 多 trace 串联 不是自动会话存储
trace_id 指定 id 格式不对会出问题
tracing.api_key 本 run 导出键 不改模型请求键
include_task_and_turn_spans 是否含 task/turn 关了仍有其他 span
flush_traces() 阻塞刷出缓冲 不要在 trace() 未结束时乱刷半截

2. 可跑 smoke:workflow + 脱敏 + 可选关闭

pip install openai-agents,并导出 OPENAI_API_KEY(无 key 时至少应能 import 与构造 RunConfig)。

python 复制代码
import asyncio
from agents import Agent, Runner, RunConfig

MODEL = "gpt-4o"  # 占位:以账号可用快照为准

async def main() -> None:
    agent = Agent(
        name="TraceSmoke",
        instructions="用一两句回答;不要编造未给出的数字。",
        model=MODEL,
    )
    cfg = RunConfig(
        workflow_name="runconfig_tracing_smoke",
        group_id="thread_smoke_001",
        trace_include_sensitive_data=False,  # 生产默认建议关敏感载荷
        # tracing_disabled=True,  # 需要本 run 全关时再打开
        tracing={"include_task_and_turn_spans": False},
    )
    result = await Runner.run(
        agent,
        "金门大桥在哪座城市?只答城市名。",
        run_config=cfg,
    )
    print("ok", bool(result.final_output), "workflow", cfg.workflow_name)

if __name__ == "__main__":
    asyncio.run(main())

验收:进程无异常;有 key 时能拿到输出;构造时显式写了 workflow_nametrace_include_sensitive_data=False。无 key 时至少确认 RunConfig(...) 可实例化,且没有把脱敏开关留成「以后再说」。

3. 全局关闭与导出键隔离(可选)

python 复制代码
from openai import AsyncOpenAI
from agents import (
    set_default_openai_client,
    set_tracing_export_api_key,
    set_tracing_disabled,
)

# 模型走兼容端点时,常需要把 tracing 导出键拆开
client = AsyncOpenAI(base_url="https://example.invalid/v1", api_key="provider-key")
set_default_openai_client(client, use_for_tracing=False)
set_tracing_export_api_key("sk-tracing-only")

# 合规窗口临时全局关闭
# set_tracing_disabled(True)

单次 run 覆盖导出键:

python 复制代码
cfg = RunConfig(tracing={"api_key": "sk-tracing-123"})

4. 长驻 worker:trace 包一层 + flush

python 复制代码
from agents import Runner, flush_traces, trace

def job(prompt: str) -> str:
    try:
        with trace("celery_task", group_id="worker_pool_a"):
            result = Runner.run_sync(agent, prompt)
        return result.final_output
    finally:
        flush_traces()  # 在 trace 上下文退出后再刷

生产禁区

  1. 默认敏感数据开着上生产:用户输入、工具参数进仪表盘。
  2. ZDR 环境仍依赖 Traces 排障:官方不可用;另建可审计日志。
  3. Celery / FastAPI BackgroundTasks 不 flush:任务结束仪表盘空白,误判「没追踪」。
  4. 业务 key 与 tracing key 混用且不隔离use_for_tracing=False 未设,权限难拆。
  5. tracing_disabled 当「已删除历史 span」:只影响新记录;缓冲仍可能被 flush。
  6. trace_id 手写不合规格式:应用启动期才暴露,难查。
  7. 日志脱敏 env 当 tracing 脱敏DONT_LOG_*TRACE_INCLUDE_SENSITIVE_DATA
  8. 多租户共用同一 workflow 名且无 group_id:仪表盘无法按会话切开。

可验证清单

# 检查项 通过标准
1 本 run 是否显式 workflow_name 非默认 Agent workflow 或已文档化接受默认
2 生产是否关敏感载荷 trace_include_sensitive_data=False 或等价 env
3 关闭路径是否选对 全局 / 单次 / ZDR 三选一写进配置说明
4 长驻任务是否 flush trace() 退出后有 flush_traces()
5 导出键是否可轮换 tracing key 与模型 key 可分开轮换
6 smoke 是否可跑 上文片段 import + 构造通过

踩坑

  • 只在本地关敏感数据,预发配置漂移回默认 True。
  • set_trace_processors([]) 清空后以为「完全无导出」,却忘了自己还 add_trace_processor 了一个会打外网的处理器。
  • with trace() 内部过早 flush_traces(),刷出半截 span。
  • group_id 当成 session 持久化:它只关联 traces,不存对话历史。

开关决策树(可进配置说明)

场景 推荐 记录什么
本地单测 可开敏感数据,短 workflow 名 便于对照失败输入
预发联调 开 tracing,关敏感数据 group_id=预发环境名
生产 PII 关敏感或整 run 关 配置项 + 变更单
ZDR 组织 不要指望仪表盘 自建审计日志方案名
兼容端点 use_for_tracing=False + 导出键 两把键的轮换人
长驻队列 with trace + flush_traces 任务结束可见性 SLA

把上表抄进仓库 observability.md 比在聊天里约定「我们注意点」更可审计。

与 sessions / server 续写的边界

tracing 的 group_id 不是 会话存储。对话历史仍应选 sessions、to_input_list() 或 server 续写三选项之一;追踪只负责「这次工作流发生了什么」。常见误配:

  1. 以为设置了 group_id 就等于 SQLiteSession 已持久化。
  2. 在 session 与 previous_response_id 同 run 互斥报错时,去关 tracing「碰运气」。
  3. 用 trace 仪表盘里的输入回放代替业务审计日志。

正确拆分:状态 用会话机制;观测 用 tracing;授权用业务日志。三者不要互相冒充。

环境变量速查(启动前)

变量 作用 生产注意
OPENAI_AGENTS_DISABLE_TRACING 1 全局关 排障窗口要有打开流程
OPENAI_AGENTS_TRACE_INCLUDE_SENSITIVE_DATA 0/1 默认敏感载荷 与 RunConfig 覆盖关系写清
OPENAI_AGENTS_DONT_LOG_MODEL_DATA 日志是否含模型 I/O 不等于 tracing 脱敏
OPENAI_AGENTS_DONT_LOG_TOOL_DATA 日志是否含工具 I/O 同上
OPENAI_ORG_ID / OPENAI_PROJECT_ID 默认导出归属 多项目勿混

建议在应用入口打印「tracing_disabled / include_sensitive / workflow_default」三元组到启动日志(不要打印密钥),便于值班对照。

最小回归:两轮对照

无仪表盘时,至少在代码层做两轮构造回归:

  1. 轮 Atrace_include_sensitive_data=True(仅本地),确认字段可设。
  2. 轮 B :改为 False,确认生产配置模板采用 B。
  3. 额外一轮:tracing_disabled=True,确认与 B 可切换且有文档说明何时用。

把三轮结果记进 _w/tracing-smoke-checklist.md。没有记录的「我设过了」不算过线。

自定义处理器时的禁区加码

若使用 add_trace_processor / set_trace_processors

  • 替换默认处理器后,不会自动再发到 OpenAI,除非你自己加回去。
  • 自建处理器若同步写磁盘,注意别把敏感 span 明文落无加密盘。
  • 处理器抛错不应默默吞掉业务成功;至少打告警计数。

当天可交付

  1. 一份 RunConfig 生产模板(脱敏开、workflow 名规范、group_id 规则)。
  2. 一份 worker flush_traces 范例(或明确「接受分钟级延迟」的书面决定)。
  3. 一份 _w/tracing-smoke-checklist.md 勾选记录。
  4. 一份禁区清单贴进 PR 模板:敏感默认、ZDR、混用密钥、不 flush。

FAQ(工程值班常问)

Q:关了 trace_include_sensitive_data 之后,仪表盘里还能看见什么?

A:仍可看见工作流结构、agent/tool/handoff 等 span 骨架;官方端点场景下可能保留关联用的 response_id 一类元数据。不要假设「完全空白」,也不要假设「仍等于全量 I/O」。

Q:tracing_disabled=True 和环境变量全局关有何优先?

A:单次 RunConfig 适合「这一类请求脱敏/关闭」;环境变量适合整进程合规窗口。不要两套开关互相不知道,配置说明里写清覆盖关系。

Q:没有 OpenAI 模型键,还能看 Traces 吗?

A:官方允许为 tracing 单独设置导出键;非 OpenAI 模型也可在具备导出键时把链路送到仪表盘。具体以官方 Models / Tracing 章节为准,不要把「免费额度」数字写进对外承诺。

Q:流式 run 要不要特殊对待 tracing?

A:仍走同一套 RunConfig。需要立即可见时,同样在 trace 上下文结束后 flush_traces()。不要把「流式事件没刷完」误诊成 tracing 坏了。

Q:能不能用 tracing 替代审计日志?

A:不能。审计要回答「谁在何时对哪条业务记录做了授权决策」;tracing 回答「这次 agent 工作流的 span 树」。混用会在合规审查时两边都不合格。

配置模板示例(可进仓库)

python 复制代码
# prod_run_config.py --- 示意,键名勿提交
from agents import RunConfig

def build_prod_run_config(*, thread_id: str, workflow: str) -> RunConfig:
    return RunConfig(
        workflow_name=workflow,
        group_id=thread_id,
        trace_include_sensitive_data=False,
        tracing={"include_task_and_turn_spans": False},
    )

def build_local_debug_run_config(*, thread_id: str) -> RunConfig:
    return RunConfig(
        workflow_name="local_debug",
        group_id=thread_id,
        trace_include_sensitive_data=True,  # 仅本地
    )

build_prod_run_config 设为唯一生产入口,比在各调用点零散传字典更不容易漏脱敏。

失败含义(写进值班手册)

现象 可能含义 下一步
仪表盘完全无新 trace 全局关 / ZDR / 导出键错 / 未 flush 查三开关与 flush
有 trace 但无输入输出 脱敏已生效 预期行为;勿当故障
有输入输出在生产 脱敏未生效 立刻改默认并轮换项目权限
偶发可见、偶发不可见 worker 未统一 flush 在 finally 固定调用
trace_id 报错 格式不合规 用自动生成或严格校验

总结

RunConfig 是 tracing 的单次控制面:关不关、敏不敏、叫什么名字、跟哪次会话一组、用哪把导出键,都应在跑之前写死。可跑 smoke 证明开关可构造;生产禁区证明「默认开着」不等于「可以原样上线」。对照官方 Tracing / Running agents / Configuration;模型名与键名以你环境为准。

参考

相关推荐
AIGC大时代1 天前
OpenAI Agents SDK 工程笔记:sessions 记忆边界再核对与生产禁区
生产禁区·sessions·sqlitesession·sessionsettings