接口变慢了、账单超了,第一反应是翻日志,结果日志里只有一行时间戳和「成功」。这篇不聊可观测性大道理,只给一份能直接照抄的字段清单:留哪几个字段就能复现一次请求的耗时构成和花费构成,以及哪几类内容写进去就是给自己埋雷。
接口变慢了、账单超了,很多人的第一反应是翻日志,结果翻出来只有一行时间戳加一个「成功」。这篇不聊可观测性的大道理,只给一份能直接照抄的字段清单:留哪几列,就能在事后还原一次请求的耗时构成和花费构成。
顺便把另一半说清楚——哪几类内容写进日志就是给自己埋雷。字段加得对不对,直接影响你以后能不能靠日志定位问题,而不是靠猜。
先想清楚:你要靠日志回答哪三个问题
加字段之前先认领问题。日志只服务三件事:这次慢在哪、这次为什么贵、这次是不是被重试堆出来的。想不清这三个问题就先别动字段,加得越多越没人看,半年后连写的人自己都不查了。
- 把「请求维度」和「聚合维度」分开:单条日志负责还原一次调用,看板负责把同一模型、同一渠道、同一时段的记录加总,两件事不要混在一张表里
- 单位与口径先统一:耗时统一毫秒、token 统一计数值,否则后面聚合还得逐条换算,约等于没记
- 字段命名保持稳定,改一次名等于让所有历史看板断裂,宁可新增字段也不要改老字段含义
一次请求最少留这几列
| 字段 | 解决什么问题 | 记录注意点 |
|---|---|---|
| 请求 ID 与时间戳 | 把一次调用串起来 | 用平台自带或自己生成,别用时间戳当主键 |
| 调用方标识 | 分清是谁在用、哪个应用在用 | 写应用名或标识,不要写自然人姓名 |
| 模型名 + 渠道 | 解释同名模型表现差异 | 两个字段分开记,不要合成一个字符串 |
| 总耗时 / 首字时间 | 区分排队慢还是生成慢 | 同一口径,单位统一 |
| 输入 / 输出 token | 算清花费构成 | 分开记,单价通常不一样 |
| 重试次数 / 状态码 | 识别异常放大 | 重试要带上一次的原因 |
身份与路由这几列是地基:请求 ID、时间戳、调用方标识、模型名、走的哪条渠道或分组。模型名和渠道一定要分开记,同一个模型名走不同渠道,延迟和成功率可能差出好几个档,合成一列以后就没法按渠道拆了。具体每次的数值口径,可以到 /tools/speed-test 先量出自己的延迟基线再定阈值。
用量与成本这几列容易被省掉,但省了就没法复盘。输入 token、输出 token、缓存命中部分、重试次数、是否命中限流,逐项记。输入输出分开记是因为单价通常不同,合并成一个总数,后期想回溯「贵在输入还是输出」就只能重跑。单价本身别写死在文档里,去 /official-api 和 /tools/token-price-calculator 核对当时的数字。
怎么判断「慢」和「贵」
- 先看首字时间拿它和你的延迟基线比,明显偏高说明卡在排队、网络或渠道调度,不是模型生成本身的问题。
- 再看生成段用总耗时减去首字时间,这一段长通常和输出长度正相关,先确认输出是不是本来就长,别急着换渠道。
- 最后看并发两步都正常但还是慢,再怀疑同时间的并发挤占,把同一时刻的其他请求拉出来一起看。
判断贵的顺序也一样要有逻辑:先比输入输出 token 的比例,看是不是输入侧膨胀了;再比同一任务的多次调用之间有没有差异,差异大说明提示词不稳定或上下文在累积;最后看重试次数是不是偏高。单看总花费永远看不出问题出在哪个环节。
重试会同时抬高耗时和 token 消耗,很多「莫名其妙变贵」最后都追到重试上。
还有一条容易忽略:看分布,不看单条。单条偶发波动没有判断价值,同一模型同一渠道在同一时段内的分布才能说明问题。窗口怎么定取决于你的调用量,调用少的时候拉长窗口,调用密的时候缩短。
这些内容不能进日志
- 密钥类:API Key、鉴权头、刷新令牌,一律脱敏或直接不记,日志系统的访问权限通常比你想的宽
- 用户原文:完整提示词和完整返回内容不要原文落盘,排查需要时记长度、哈希或前若干字符就够
- 个人信息与业务数据:手机号、身份证、订单号、内部表结构,能脱敏就脱敏,不能脱敏就只在受控环境短期留存
- 保留策略:留多久、谁能看、什么时候删,这条不写下来,日志系统迟早变成一堆没人敢清理的敏感数据
脱敏的边界不用自己拍脑袋,站内 /safety 和 /ai-dict/category/safety 里有关于数据与内容处理的口径,可以对着自己的业务场景逐条过一遍再决定哪些字段落盘。
落地顺序:从两列加到全量
- 第一步:只加总耗时和状态码先确认日志管道通不通、有没有丢数据,管道没跑通就加字段等于白加。
- 第二步:加模型名、渠道、输入输出 token这一步做完就能回答「哪个组合最贵」。这时候去 /usage 对照站内统计口径,确认自己的加总方式和平台一致。
- 第三步:加首字时间与重试次数这两项通常需要客户端侧打点,SDK 不直接给就在自己封装的那一层埋,别指望上游帮你补。
- 第四步:做脱敏、定留存、建聚合视图按模型、按渠道、按时段各建一个视图,没有聚合的单条日志只能靠人肉翻,翻两次就没人翻了。
渠道本身的稳定性也会影响你看到的日志分布,同一时段某个渠道成功率下滑,日志里就会表现为重试变多、耗时变长。选渠道之前可以先看看 /sites 和 /rankings 里的可信度与横向对比信息,把渠道质量和自己的日志表现对起来看,比单独盯一条曲线靠谱。
下一步先按第一、二步把总耗时、状态码、模型名、渠道和 token 这几列落下来,再拿一周的数据和站内统计口径对一遍;渠道质量、价格与可用性的当时数字,到 /sites、/rankings 和 /price-watch 上核对,避免凭记忆拍板。→常见问题
首字时间上游没返回怎么办?
大多数请求记录里不会直接给首字时间,需要在自己封装的那一层打点:发请求前记一个时间,收到第一个流式分片时再记一个,两者相减。非流式调用拿不到首字时间,那就退而记录连接建立时间和响应完成时间,能区分排队和生成即可。
日志里记模型名有什么用,账单上不就有?
账单通常是按天或按账号聚合的,看不到单次请求走的是哪条渠道、有没有重试。模型名加上渠道标识,才能把「同一个模型今天突然变慢变贵」定位到具体是渠道调度变了还是自己的调用方式变了。模型与厂商对应关系可到 /models 和 /providers 查。
字段加全了会不会存储成本很高?
纯结构化字段(数字、枚举、短字符串)的单条体积很小,真正把存储撑起来的是原文内容和长错误堆栈。做法是结构化字段全量留存,原文只在采样或报错时短存,并配上明确的过期删除策略。先算清楚每天多少条请求再决定保留天数。