事情本身不复杂,线索都在日志里。给 20 个租户做成本分摊,每个请求都带同一份 3000 token 的 system 提示词,月底各租户成本加起来比账单多 40%,账单里其实有缓存命中折扣。

第一反应是「日志只记了 prompt_tokens 总量,没拆出 cached_tokens」,验证下来不成立。

把日志和配置对完,能解释这个现象的基本就这几处。前缀缓存只对逐字节一致的前缀生效,system 中间插了租户名就断掉。另一种情况是每个租户拼接顺序不同,前缀对不齐就命中不了。

不容易想到的是,计费按全价乘总 token,缓存部分没打折。

从返回体里取 cached_tokens 看命中比例

python -c "from openai import OpenAI;r=OpenAI().chat.completions.create(model='gpt-4o-mini',messages=[{'role':'system','content':'规则'*800},{'role':'user','content':'hi'}]);print(r.usage.prompt_tokens_details)"

然后把租户信息移到 system 之后保证前缀一致

python -c "print('system: 公共规则\nuser: 租户A 的问题')"

缓存与未缓存两部分分别计价

python -c "print(0.15/1e6*2000+2.5/1e6*1000)"

等前面都确认过,再用日账单校验分摊总额

curl -s "https://api.openai.com/v1/organization/costs?start_time=1730000000" -H "Authorization: Bearer $OPENAI_API_KEY" | jq '.data[].results[] | .amount.value'

恢复的判定其实很直接。各租户分摊合计与账单相差在 2% 以内,日志里 cached_tokens 占比稳定在 60% 以上。

这里还有个坑。前缀缓存按分钟级失效,低频租户几乎命不中,分摊模型里要给它留一档不含折扣的单价。拖得越久,排查成本越高,因为现场状态会被后续操作覆盖。

作者 9823189