用量、可观测性与供应商适配

本节目标

记录足以复现与定位问题的非敏感元数据,用 adapter 隔离供应商差异,并以真实任务评测比较替换方案。

每次调用最少记录什么

  • 应用 operation_id、trace/span ID 与服务端请求 ID;
  • provider adapter 版本、实际模型标识、提示/schema/上下文选择器版本;
  • 开始时间、首事件延迟、总耗时、attempt 次数与最终状态;
  • 输入、输出及缓存相关的供应商 usage 字段;
  • 解析、schema、拒绝、截断、限流等标准化错误类别;
  • 业务评测结果或人工纠正,但不默认记录原始敏感文本。

先保存供应商原始 usage 的结构化副本,再派生统一指标;不同供应商对 token、缓存、推理或工具用量的定义不一定相同。价格表动态变化,成本估算要带价格版本与货币,最终账单以供应商为准。

原始字段应保留命名空间和 adapter 版本,统一字段则明确转换公式。缺失值保持 unknown/not_reported,不要填 0。OpenTelemetry 的 GenAI semantic conventions 可提供跨系统词汇,但当前规范已移到独立仓库,registry 中仍有 development/deprecated 属性;不要把网页上的字段名当永久稳定 API。采用的 convention 版本、稳定性级别和自定义扩展都要记录,升级时对 dashboard 与告警做迁移测试。

以当前 Gemini Interactions v1 为例,usage 总量字段是可选的 total_input_tokens、total_output_tokens 与 total_tokens;早期或其他 API family 的字段名不能直接套用,字段缺失也不等于零。Anthropic Messages、OpenAI Responses 同样应先按各自原生结构保存,再由带版本的 adapter 派生统一指标。

状态、存储、保留与日志不是一回事

截至 2026-07-21,三家当前 family 的默认值不同,而且都可能受账户、功能与治理配置影响:

API family当前服务端状态/保留事实集成动作
OpenAI ResponsesResponse 默认保存 30 天,可用 store:false 关闭;Conversation 对象及其 Items 不受同一 30 天 TTL 约束;previous-response 链中的先前输入 token 仍计费分开记录 Response storage、Conversation 生命周期与计费;ZDR/手工状态要保存全部必要 output Items
Anthropic MessagesAPI prompts/outputs 通常默认不保留,但当前 Covered Models Fable 5/Mythos 5 有 30 天例外;部分有状态功能另有保留;structured-output schema 可缓存至多 24 小时按模型与功能核对 retention/ZDR;schema 中不要放 PHI、秘密或用户原文
Gemini Interactions v1默认 store=true;免费项目保存 1 天,付费项目可配置 7/14/28/55 天,默认且最长 55 天每次显式决定 store,保存期进入数据分类、删除与句柄失效测试

这些是 feature/state 层事实,不是完整 DPA、法律保留或滥用监控承诺。Anthropic 当前还明确说明,即使已有 ZDR/HIPAA 安排,法律要求或自动 trust-and-safety 标记的数据仍可能保留,标记的输入输出最长可到 2 年;其他 Provider 也必须按账户合同与适用功能另行核验,不能从 store 字段推出“绝对零保留”。

这些 Provider 合同也不包括你的反向代理、APM、队列、对象存储、crash dump、SDK debug log 和数据仓库。即使请求设置 store:false,完整 payload 仍可能被自己的日志链路保存;反过来,服务端保留也不能替代应用 durable conversation/execution ledger。上线前做一张数据流清单:每份正文、schema、tool result、trace 与 usage 在哪里复制、谁可访问、保留多久、如何删除。

Adapter 的职责

ApplicationRequest
  -> Capability check
  -> ProviderAdapter.map_request()
  -> Official SDK / HTTP
  -> ProviderAdapter.map_events_or_response()
  -> ApplicationResponse

adapter 应显式声明能力:schema、streaming、tools、图片等。无法等价映射时返回 unsupported_capability,而不是删掉字段继续运行。保留原始错误与完成原因以便排障,同时对上层输出有限、稳定的内部枚举。

可观测但不泄密

日志采用 allowlist:默认记录长度、哈希、版本和类别,而非完整提示、上下文、工具参数或认证头。按风险决定采样与保留期,并限制访问。指标聚合不能含高基数字段如完整用户 ID;必要关联使用受控的不可逆标识。

trace、log 与 metric 的职责不同:trace 关联一次业务操作及其 attempts,log 记录离散状态和结构化错误,metric 聚合延迟、用量与失败率。服务端 request ID 适合进入受控日志或 span 属性,不应作为低基数 metric label。

日志还要区分“请求的设置”和“实际结果”:请求模型/配置与响应报告模型、请求 store 与前序是否可检索、计划 retry 与实际 attempts、估算成本与最终账单都应分别保存。这样发生路由、fallback、别名漂移或句柄过期时,才能解释差异,而不是只剩一个看似统一的 model 字段。

比较供应商或模型

固定任务评测集、提示合同与上下文,比较质量切片、解析率、拒答、延迟分位数、用量、成本和故障率。功能表只能说明“声称支持”,不能证明业务等价。先影子或小流量验证,再切换生产。

练习与自测

为一次调用设计日志 schema,并逐字段标注“必须、可选、禁止”。设计两个 adapter 的能力矩阵。自测:只凭平均延迟和每 token 单价能否决定迁移?还缺哪些任务级证据?

掌握检查

  • 一次 operation 的全部 attempts 可由 operation/trace ID 关联,每次服务端 request ID 单独保留。
  • 原始 usage、统一指标、转换公式、adapter 版本和价格版本可追溯。
  • 缺失字段保持 unknown,不把未报告用量、缓存或成本写成 0。
  • 日志使用 allowlist,不默认保存提示、上下文、工具参数、认证头或个人信息。
  • adapter 能力不匹配显式失败,未知错误和终止状态保留原始类型。
  • Provider storage、产品保留期、自有日志保留与 durable 业务状态分别建模;store=false 不被误当“全链路无留存”。
  • OTel GenAI convention 固定版本与稳定性级别,升级时验证属性迁移,不直接复制易变 registry。
  • 供应商比较使用相同任务集和质量/安全门槛,并观察延迟分位数与故障率。

下一步

先进入 可靠客户端项目与自测,再完成 三家 Provider 合同测试。后者把 capability matrix 落到 OpenAI Responses、Anthropic Messages 与 Gemini Interactions v1 的独立状态机和续接合同,而不是只比较字段名称。

参考资料