现场是这样的。多轮任务每轮间隔六七分钟,账单里缓存命中的 token 只占一成,前缀内容其实完全一致,模型也没换过。
中间走过弯路,把「前缀里带了时间戳或随机 id,每次内容都不一样」当成主因,改完现象没变。
排查方向其实有限,先把可能性排一排。默认缓存保留时间较短,间隔一长前缀就失效;请求被调度到不同节点,缓存不跨节点共享;前缀长度不足最小 token 数时根本不会进缓存。
先看响应里缓存命中的 token 数
curl -s https://api.openai.com/v1/chat/completions -H "Authorization: Bearer $OPENAI_API_KEY" -H "Content-Type: application/json" -d '{"model":"gpt-4o-mini","messages":[{"role":"system","content":"固定的长前缀"},{"role":"user","content":"问题"}]}' | jq '.usage.prompt_tokens_details'
再往下确认前缀里有没有易变内容
python -c "import re;print(bool(re.search(r'20\\d\\d-',open('prompt.txt').read()[:200])))"
随后把稳定前缀前置并用会话键归组
curl -s https://api.openai.com/v1/chat/completions -H "Authorization: Bearer $OPENAI_API_KEY" -H "Content-Type: application/json" -d '{"model":"gpt-4o-mini","messages":[{"role":"system","content":"固定的长前缀"}],"prompt_cache_key":"job-42"}' | jq '.usage.prompt_tokens_details.cached_tokens'
剩下的就是按天统计缓存命中占比
curl -s "https://api.openai.com/v1/organization/usage/completions?start_time=$(date -d '-2 day' +%s)&bucket_width=1d" -H "Authorization: Bearer $ADMIN_KEY" | jq -r '.data[].results[]|"\(.input_cached_tokens) \(.input_tokens)"'
别只看报错消失,验证要多做一步。cached_tokens 占输入 token 的比例回到一半以上,同样的多轮任务单轮费用明显下降,账单里缓存项不再是零。
容易忽略的是,缓存是按前缀逐 token 匹配的,任何一处不同都算新前缀,把时间戳这类变量挪到尾部,命中率会立刻不一样。同一份配置在测试环境跑通,不代表线上没事,两边的默认值经常不一样。
