Prompt 缓存
自动托管的开源权重模型会自动缓存重复的 prompt 前缀。当一次请求的系统 prompt、工具和早期消息与同一模型的近期请求相同时,该共享前缀将从缓存中读取,并按模型输入价格的 25% 计费。无需手动启用,且写入缓存免费。
工作原理
- 前缀顺序 — Prompt 按顺序读取:系统 prompt $\to$ 工具定义 $\to$ 消息。缓存从该序列的起始端匹配,直到出现第一个不同的 token 为止。
- 命中定义 — 如果一次请求的 prompt 开头与近期请求的内容相同(通常是同一对话的上一轮,并附加了新消息),则匹配的前缀部分为缓存输入;其后的所有内容为常规输入。
- 粒度 — 缓存以 1,568 tokens 为一块保存 prompt,因此短于约 1,500 tokens 的 prompt 不会被缓存。回复中的缓存计数是你的输入计数乘以 prompt 中被缓存的比例,向下取整。它不一定是块大小的整数倍。
- 未命中时 — 开头不在缓存中的请求按常规输入单价计费。缓存的 prompt 没有公布保留时长,也不保证命中:请查看
usage了解请求从缓存中取了多少。 - 没有开关 — 请求无需主动启用,也没有任何字段可以关闭缓存。
- 适用模型 — 所有托管的开源权重 ID。GET /v1/models 会报告其 capabilities.prompt_caching: true 以及 pricing.cached_input_per_million_usd。Shannon 模型则按统一费率计费。
在回复中查看缓存命中
发送两个以相同长系统提示词开头的请求,并打印各自的用量。第一个数字是请求的输入,第二个数字是其中从缓存读取的部分。
from openai import OpenAI
client = OpenAI(api_key="YOUR_API_KEY", base_url="https://api.shannon-ai.com/v1")
handbook = open("handbook.txt").read() # a long text that stays the same
def ask(question):
response = client.chat.completions.create(
model="Kimi-K3-3BIT-REAP",
messages=[
{"role": "system", "content": handbook},
{"role": "user", "content": question},
],
)
usage = response.usage
print(usage.prompt_tokens, usage.prompt_tokens_details.cached_tokens)
ask("What is the refund policy?")
ask("Who approves travel?") # same start: read the second number import { readFileSync } from "node:fs";
import OpenAI from "openai";
const client = new OpenAI({ apiKey: "YOUR_API_KEY", baseURL: "https://api.shannon-ai.com/v1" });
const handbook = readFileSync("handbook.txt", "utf8"); // a long text that stays the same
async function ask(question) {
const response = await client.chat.completions.create({
model: "Kimi-K3-3BIT-REAP",
messages: [
{ role: "system", content: handbook },
{ role: "user", content: question },
],
});
const usage = response.usage;
console.log(usage.prompt_tokens, usage.prompt_tokens_details.cached_tokens);
}
await ask("What is the refund policy?");
await ask("Who approves travel?"); // same start: read the second number # handbook.txt is a long text that stays the same. jq builds the JSON body from it
# and prints the usage object of the reply. Run it twice with different questions.
jq -Rs '{
model: "Kimi-K3-3BIT-REAP",
messages: [
{role: "system", content: .},
{role: "user", content: "What is the refund policy?"}
]
}' handbook.txt \
| curl -s https://api.shannon-ai.com/v1/chat/completions \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d @- \
| jq .usage 定价
缓存输入 token 按模型输入费率的 25% 计费,四舍五入至每 1M $0.001。写入缓存无需额外付费,输出按常规计费。每个 ID 的缓存费率见“模型与定价”表。 模型与定价
一次调用的输入按 (输入 − 缓存) × 输入单价 + 缓存 × 缓存单价 计费。缓存计数永远不会大于输入计数。
| 模型 | 输入 / 1M | 缓存输入 / 1M |
|---|---|---|
DeepSeek-V4-Pro-0813-3BIT-REAP | $1.95 | $0.488 |
GLM-5.2-3BIT-REAP | $0.73 | $0.183 |
Kimi-K3-3BIT-REAP | $3.83 | $0.958 |
Nemotron3Ultra-3BIT-REAP | $0.75 | $0.188 |
MiniMax-M3-3BIT-REAP | $0.50 | $0.125 |
DeepSeek-V4-Flash-0731-W4A16-AUTOROUND-REAP | $0.50 | $0.125 |
Kimi-K2.6-W4A16-AUTOROUND-REAP | $0.78 | $0.195 |
Laguna-S-2.1-W4A16-AUTOROUND-REAP | $0.50 | $0.125 |
inkling-W4A16-AUTOROUND-REAP | $1.42 | $0.355 |
MiMo-V2.5-Pro-W8A16 | $0.50 | $0.125 |
MiMo-V2.5-W8A16 | $0.50 | $0.125 |
Hy3-W8A16 | $0.50 | $0.125 |
用量日志列出每次调用的缓存输入。其计费 tokens 和费用已经包含缓存单价。 密钥与用量
使用字段
| 端点 | 缓存输入 | 推理 |
|---|---|---|
/v1/chat/completions | usage.prompt_tokens_details.cached_tokens — prompt_tokens 的一部分 | usage.completion_tokens_details.reasoning_tokens — completion_tokens 的一部分 |
/v1/responses | usage.input_tokens_details.cached_tokens — input_tokens 的一部分 | usage.output_tokens_details.reasoning_tokens — output_tokens 的一部分 |
/v1/messages | usage.cache_read_input_tokens — 独立报告:input_tokens 为非缓存部分;cache_creation_input_tokens 始终为 0 | 思考过程计入 output_tokens |
{
"usage": {
"prompt_tokens": 20000,
"completion_tokens": 812,
"total_tokens": 20812,
"prompt_tokens_details": {
"cached_tokens": 18000
},
"completion_tokens_details": {
"reasoning_tokens": 604
}
}
} {
"usage": {
"input_tokens": 20000,
"input_tokens_details": {
"cached_tokens": 18000
},
"output_tokens": 812,
"output_tokens_details": {
"reasoning_tokens": 604
},
"total_tokens": 20812
}
} {
"usage": {
"input_tokens": 2000,
"cache_read_input_tokens": 18000,
"cache_creation_input_tokens": 0,
"output_tokens": 812
}
} 流式回复在最终用量中带有相同的字段。你无需特意请求:
| 端点 | 用量的返回位置 |
|---|---|
/v1/chat/completions | data: [DONE] 之前最后一个数据块上的 usage。每个流都会发送。 |
/v1/responses | response.completed 事件的 response.usage。 |
/v1/messages | message_delta 事件的 usage。message_start 的 usage 全为零。 |
提高缓存命中率
- 确保多次调用之间的系统 prompt 和工具定义在字节级保持一致。将时间戳或请求 ID 等单次调用值放在最新消息的末尾,而不是系统 prompt 中。
- 仅在历史记录后追加内容。编辑、修剪或总结早期的对话轮次会改变前缀,导致第一个更改点之后的所有内容都被计为常规输入。
- 在调用之间不要重新排列工具、消息或内容块,并确保每次以相同方式序列化 JSON(工具 Schema、工具参数和结果)。
- 一个对话中请始终使用同一个模型 id,并在上一次调用之后尽快发送后续调用。
在以下情况下,API 会保持对话开头稳定:
- 在对话后面发送的
system或developer消息保持在原位。它不会改变 prompt 的开头,因此它之前的轮次仍保持缓存。 - 之前 assistant 轮次中工具调用的参数按值比较。该 JSON 的键顺序和空白无关紧要。
- 三个端点以相同方式读取对话。在另一个端点上继续的对话,只要内容相同,就保留共享的前缀。
请求字段
支持 prompt_cache_key(聊天补全与响应)以及 Messages 内容块中的 cache_control,因此现有客户端代码无需更改即可运行。两者都不是必须的:缓存是自动的,即使没有它们也能正常工作。
| 字段 | 发送到 | 含义 |
|---|---|---|
prompt_cache_key | /v1/chat/completions, /v1/responses | OpenAI API 的缓存路由键。 |
cache_control | /v1/messages | Anthropic API 中内容块、system 块或消息上的缓存断点。 |
stream_options | /v1/chat/completions | include_usage 用于在 OpenAI API 上请求流的用量。在这里,每个流都以用量结尾。 |
计算 tokens
两个免费端点 POST /v1/tokenize 和 POST /v1/messages/count_tokens 可在发送之前,为托管开源权重模型统计一段文本或整个请求的 tokens。 它们有专门的页面: Token 计数