博客

LLM API 调用该记录哪些日志(以及永远不要记录什么)

为 LLM 集成做日志,重点不在数量,而在于一份能定位故障、归属成本、经受审计的字段清单,外加一条硬底线:密钥和客户内容绝不进入日志。

LLM API 调用该记录哪些日志(以及永远不要记录什么)

大多数 LLM 可观测性问题不是工具问题,而是 schema 问题。能快速定位故障、有把握地归属成本、从容回答审计问题的团队,并没有在记录一切。他们在稳定地记录那关键的一小撮字段,并且划了一条硬底线:密钥和客户内容永远不进日志。本文讲这份字段清单、必须挡在日志之外的东西,以及 LLM API 数据保留中朝两个方向都让人意外的部分:厂商保留的东西不是你的审计轨迹,而你保留的东西需要是有意为之的,因为相关控制确实存在,但它们不是默认开启的。本站的运维类文章已经连着几周在引用日志;这一篇讲的就是日志本身。

LLM API 日志:四个用途,一套 schema

一条有用的 LLM API 调用日志同时服务四个用途,你需要的字段直接对应到它们。

调试。HTTP 状态码;响应体中的错误type类型与message错误码;存在时的错误code消息字段;请求 ID;这个逻辑请求的重试次数;以及耗时。有了这些,一次失败就不再是一个故事,而是一条记录:尝试了什么、返回了什么、在重试序列的哪一步死掉的。

归属。实际使用的 model ID、端点,以及调用方身份:是哪个功能、哪个团队或哪个客户发起的调用。如果厂商在响应头里暴露了组织或 workspace 标识,也把它们记下来,因为它们让你能用自己的记录去和厂商的视图对账。API 用量归属日志是发票上的一个行项与产生它的代码路径之间的连接组织。值得打的标签维度,以及按这些维度分组为什么划算,见用量归属指南。

成本。每个响应的用量usage对象里的 token 计数,以及能说明缓存读取是否真的发生了的缓存相关字段。把这些字段记下来,成本复盘就从考古变成一次查询;其中的机制以及能证明缓存命中的字段,见缓存指南。

稳定性。回答“它是不是在变差”的计数器:按时间变化的限流响应、服务端错误响应、重试预算耗尽,以及实际应用的退避时长。这些指标是重试纪律在可观测性上的另一半,纪律本身见限流指南。

一套 schema,四个消费者。实用的技巧是每个逻辑请求(而不是每次底层尝试)写一条结构化日志,把上面所有内容都补进去,这样同一条记录既服务于值班工程师,也服务于财务的表格和审计员。

请求 ID:你排查 API 问题的锚点

如果你在 token 计数之外只记一个字段,那就记请求 ID。Anthropic 的错误文档对这一点说得很明确:每个 API 响应都包含一个唯一的request-id响应头,同一个标识也会作为错误响应体里的request_id字段出现,而且当你就某个具体请求联系支持时,你要提供这个 ID。最后这点才是关键。关于间歇性故障的支持对话,如果没有一个双方都能查询的标识,永远不会有进展;有了它,对话就变成一次查找。

以编程方式读取它很直接,但各 SDK 不同。Python 和 TypeScript SDK 把它暴露为顶层响应对象上的_request_id属性;C#、Go、Java 和 PHP SDK 通过各自的原始响应访问器暴露它,Ruby 则通过中间件。要读取其他响应头,比如anthropic-organization-id前面提到的这些,anthropic-workspace-id在所有 SDK 里都用同样的原始响应访问器(Ruby 里用同一个中间件)。在 Claude Platform on AWS 上,响应会带两个 ID:AWS 请求 ID,x-amzn-requestid它在 CloudTrail 中有索引,是查 CloudTrail 时要用的那个;另一个是 Anthropic 请求 ID,用于提交支持工单。如果你跑在那个环境里,两个都记;它们回答的是不同的问题。这条通用原则早于任何厂商存在:请求 ID 加错误码,就是把一次失败钉到一次调用上的那一对,而这正是错误码指南在分诊时假定你已经拥有的东西。

永远不进日志的内容

两类,没有任何值得破例的情形。第一类是凭证:API key、bearer token 和认证头,永远不该出现在日志输出里,任何级别都不行,包括 debug。这一点值得直说,因为泄露路径都很无聊:一个过于勤快的请求日志器打印了请求头,一个错误处理器把整个请求对象序列化了,一张支持工单里有人粘贴了配置。同样的纪律在 CI 流水线和应用日志里完全适用。

第二类是原始客户内容:完整的 prompt 和补全结果,尤其是当它们包含个人数据或受监管数据时。这条线更难守,因为原始内容对调试确实有用。替代工具箱:记录长度和哈希而不是正文;需要感受数据形态时,记录分类标签或脱敏样本;如果监管要求强制保留内容,就单独建一个受访问控制的存储,并配自己的保留计时器。一个可行的模式是三段式过滤:一份允许记录的字段名白名单;写入前的一遍清洗,丢弃任何匹配凭证形态的内容并在命中时告警;以及对日志存储本身的访问控制和保留期限。告警很重要;如果某种密钥形态出现在了日志流里,你希望几分钟内就知道,而不是等到下次审计。

LLM API 数据保留:厂商保留了什么

这里就是很多团队会朝一个方向误解的部分。厂商侧确实存在日志,而且默认不由你控制。OpenAI 的数据管控文档把两半都说得很清楚。

让人安心的一半:自 2023 年 3 月 1 日起,发送到 OpenAI API 的数据不会被用于训练或改进 OpenAI 的模型,除非客户明确选择加入数据共享。

运维意义上的另一半:API 用量会生成滥用监控日志,用于执行使用政策,这些日志可能包含客户内容,例如 prompt 和响应,以及派生元数据,例如分类器输出。默认情况下这些日志最多保留 30 天,除非法律要求更长保留期,或者为保护服务或第三方有合理必要。符合条件的客户可以通过获批零数据保留或修改版滥用监控,让客户内容不被写入这些日志,两者都需要事先批准并满足额外要求。对你架构的结论很直白:厂商的保留不是你的审计轨迹。如果你需要记录发生了什么、什么时候、花了多少、由谁调用,这些元数据得你自己留。

也不要朝另一个方向过度纠正。“不用于训练”不等于“什么都不保留”,而 30 天这个数字是某一类特定日志有文档依据的保留窗口,并不是承诺说 30 天后每个请求的每一丝痕迹都不可恢复。你的内部策略要对着真实的控制项来写,同一份文档按端点详细说明了这些控制项。

两个常被误读的保留控制项

那份文档里有两个细节值得牢记,因为它们会打破假设。

第一,零数据保留改变的是行为,不只是策略:启用之后,storeResponses 和 Chat Completions 端点的 store 参数总是被当作关闭处理false,即使请求试图把它设为开启true。所以一个假设“我设了 store=true,因此这段对话可以取回”的应用,在 ZDR 下就是错的,而且失败是静默的,因为请求会成功。如果你的产品依赖已存储的状态,就去按你组织实际的数据策略核实端点行为,而不是假设你的参数会生效。

第二,Responses API 默认有 30 天的应用状态保留期,当相关参数store被设为需要保留的取值时同样如此true;在这些情况下,响应数据至少会存储 30 天。把该端点当作无状态的团队会在两个方向上都被惊到:他们以为已经消失的数据其实被保留了,他们以为会保留的数据则受策略依赖的行为支配。同一个页面按端点列出了保留情况,包括哪些端点有资格使用更严格的控制项,还指出数据驻留是项目级配置选项、受资格限制,且定价可能与标准端点不同。这两点都要对照当前页面和你的账号来确认,而不是对照一篇博客文章,包括这一篇。

把日志与保留当作采购维度

一旦你把日志看成一个能力面,它就属于供应商选型,而不属于合同细则。评估时有四个值得问的问题:你能不能取回任意单次调用(包括失败的调用)的请求 ID;你能不能从响应里读到组织和 workspace 标识,让归属可被证明;保留姿态能否配置到你的合规团队需要的程度,审批又需要什么;以及数据在哪里处理和存储,如果驻留对你重要的话。这些问题会直接嵌进聚合访问与直连的对比里的架构权衡,因为中间层会改变谁持有日志、你能看到哪些标识。你所运行平台的端点级细节都在它自己的文档里。

字段地图

本站的运维系列已经长成一组文章,每一篇都依赖同一套可观测性底座。下面是它们与本套 schema 中字段的对应关系:

| 文章 | 它需要你日志里的什么 |
| :- | :- |
| 用量与成本归属 | token 计数、模型、调用方标签、组织与 workspace 标识 |
| 错误码分诊 | 状态码、错误类型与错误码、请求 ID |
| prompt 缓存 | 缓存读取与写入的 token 字段,用来证明命中 |
| CI 集成 | 密钥卫生:凭证完全不出现在日志里 |
| 限流与重试 | 限流与错误计数器、退避与预算指标 |

实施检查清单

  1. 定义白名单 schema:每个被记录字段的名称、类型和可空性,并在功能变化时复核它。
  2. 在每次调用上抓取请求 ID 和错误码,并把它们作为一等字段存储,而不是塞在一条 message 字符串里。
  3. 按逻辑请求把用量 token 字段和缓存字段记录为结构化数字。
  4. 给每次调用打上功能、团队和客户标识,并用厂商的响应头核对这些标签。
  5. 写入前过滤:丢弃形似凭证的字符串和已知的 PII 模式,并在过滤器命中时告警。
  6. 把调试日志与审计记录分开,两者使用不同的保留窗口。
  7. 限制谁能读取日志存储,并记录对它的访问。
  8. 每季度对照厂商当前文档重新审计 schema,因为端点和保留控制都会变。

这些也都不光鲜,但它决定了一个技术栈是你能运营的,还是你只能寄希望于它的。日志就是做出这个选择的地方,一次一个 schema 决策。