# Prompt Cache 与成本 (/docs/cloud/services/model/guides/prompt-cache)



Prompt Cache 复用重复输入的前缀计算，不复用上一条回答。是否命中要看返回的缓存 token 数，不能凭回答相同或速度更快判断。

本页的 OpenAI 示例使用 `deepseek-flash`，不添加缓存控制参数。2026-10-12 实测：26,016 个输入 token 的第二次请求报告 25,856 个缓存 token；这是一组观测值，不是每次调用的保证。

## 1. 准备终端 [#1-准备终端]

将 Praxis 云 API Key 放入环境变量 `PRAXIS_API_KEY`；获取方式见 [Key 与鉴权](/docs/cloud/account/api-keys)。不要把 Key 写入代码。准备 Python 和 [uv](https://docs.astral.sh/uv/getting-started/installation/)；TypeScript 示例使用 [Bun](https://bun.sh/docs/installation)。

```bash
test -n "$PRAXIS_API_KEY"
```

期望：退出码为 0。示例默认使用 `https://api.deepraxis.ai`。切换环境时，将 `PRAXIS_API_BASE` 设为相应 API 域名，不带末尾斜杠或 API 路径。

将每段 Python 保存为标明的文件名，以 `uv run -q --no-project --with openai --with anthropic python <文件名>` 执行。各段代码独立运行。

## 2. 连续请求相同前缀 [#2-连续请求相同前缀]

将不常变的指令和资料放在前面，当前问题放在后面，保持模型、前缀内容和顺序一致。下面生成较长的演示资料并连续请求两次，会产生两次模型调用费用。

保存为 `prompt-cache.py`，运行 `uv run -q --no-project --with openai --with anthropic python prompt-cache.py`。

```python
import os
from openai import OpenAI

client = OpenAI(api_key=os.environ['PRAXIS_API_KEY'],
    base_url=os.environ.get('PRAXIS_API_BASE', 'https://api.deepraxis.ai') + '/openai/v1')
prefix = '\n'.join(f'Record {i}: Paris is in France. The demo temperature is 22 Celsius.' for i in range(1500))
hits = []
for turn in range(2):
    response = client.chat.completions.create(model='deepseek-flash',
        messages=[{'role':'system','content':prefix},
            {'role':'user','content':'What country is Paris in? Reply with one word.'}],
        reasoning_effort='none', max_tokens=64)
    print('X-Request-Id:', response._request_id)
    assert response.choices[0].finish_reason == 'stop'
    usage = response.usage
    assert usage and usage.prompt_tokens_details is not None
    cached = usage.prompt_tokens_details.cached_tokens
    assert cached is not None
    hits.append(cached)
    print(turn + 1, 'prompt_tokens:', usage.prompt_tokens, 'cached_tokens:', cached)
assert hits[1] > 0, 'No cache hit observed on the second request'
```

期望：输出两次输入和缓存 token 数，第二次 `cached_tokens > 0`，退出码为 0。重复运行时第一次也可能命中，不要求第一次为零。

`usage.prompt_tokens_details.cached_tokens` 是输入中的缓存部分，已包含在 `prompt_tokens` 内，不能再相加。缓存只减少符合条件的输入费用，不使输出免费；成本按所选模型的缓存输入、普通输入和输出单价计算，不套用固定折扣。缓存最短前缀和保留时间由模型决定。

## 3. 用 TypeScript 检查命中 [#3-用-typescript-检查命中]

保存为 `prompt-cache.ts`，运行 `bun prompt-cache.ts`；无需安装 SDK。

```typescript
import assert from 'node:assert/strict';
const base = process.env.PRAXIS_API_BASE ?? 'https://api.deepraxis.ai';
const prefix = Array.from({length: 1500}, (_, i) =>
  `Record ${i}: Paris is in France. The demo temperature is 22 Celsius.`).join('\n');
const hits: number[] = [];
for (let turn = 0; turn < 2; turn++) {
  const response = await fetch(`${base}/openai/v1/chat/completions`, {
    method: 'POST', headers: {'Authorization': `Bearer ${process.env.PRAXIS_API_KEY}`, 'Content-Type': 'application/json'},
    body: JSON.stringify({model: 'deepseek-flash', max_tokens: 64, reasoning_effort: 'none',
      messages: [{role: 'system', content: prefix},
        {role: 'user', content: 'What country is Paris in? Reply with one word.'}]}),
  });
  console.log('X-Request-Id:', response.headers.get('x-request-id'));
  const data = await response.json();
  assert(response.ok, JSON.stringify(data));
  assert.equal(data.choices[0].finish_reason, 'stop');
  const cached = data.usage.prompt_tokens_details?.cached_tokens;
  assert.equal(typeof cached, 'number');
  hits.push(cached);
  console.log(turn + 1, 'prompt_tokens:', data.usage.prompt_tokens, 'cached_tokens:', cached);
}
assert(hits[1] > 0, 'No cache hit observed on the second request');
```

期望：第二次报告正数 `cached_tokens`，退出码为 0。

## 4. 观察 Anthropic cache\_control [#4-观察-anthropic-cache_control]

Messages 可在稳定文本块上设置 `cache_control: {type: "ephemeral"}`。本例使用 `claude-opus-5`，连续调用后分别读取 `cache_creation_input_tokens`（写入）和 `cache_read_input_tokens`（读取）。Messages 的 `input_tokens` 是未计入读写缓存部分的输入；总输入为这三项之和。

本次实测请求被接受，但两次读写缓存数均为零，因此此例用于观察缓存状态，不承诺命中。`GET /openai/v1/models` 的 `supported_parameters` 可查询参数声明，但不是每次缓存命中的证明；最终仍以用量字段为准。

保存为 `prompt-cache-anthropic.py`，运行 `uv run -q --no-project --with openai --with anthropic python prompt-cache-anthropic.py`。

```python
import os
from anthropic import Anthropic

client = Anthropic(api_key=os.environ['PRAXIS_API_KEY'],
    base_url=os.environ.get('PRAXIS_API_BASE', 'https://api.deepraxis.ai') + '/anthropic')
prefix = '\n'.join(f'Record {i}: Paris is in France. The demo temperature is 22 Celsius.' for i in range(1500))
hits = []
for turn in range(2):
    raw = client.messages.with_raw_response.create(model='claude-opus-5', max_tokens=64,
        system=[{'type':'text','text':prefix,'cache_control':{'type':'ephemeral'}}],
        messages=[{'role':'user','content':'What country is Paris in? Reply with one word.'}])
    print('X-Request-Id:', raw.headers.get('x-request-id'))
    message = raw.parse()
    assert message.stop_reason == 'end_turn'
    usage = message.usage
    assert usage.cache_read_input_tokens is not None
    assert usage.cache_creation_input_tokens is not None
    hits.append(usage.cache_read_input_tokens)
    print(turn + 1, 'input:', usage.input_tokens, 'write:', usage.cache_creation_input_tokens,
        'read:', usage.cache_read_input_tokens)
print('HIT' if hits[1] > 0 else 'MISS: no cached input reported')
```

期望：两次请求完成，输出读写统计和 `HIT` 或 `MISS: no cached input reported`，退出码为 0。只有读取 token 为正数才算观察到命中；退出码 0 只证明请求和统计读取成功。

## 实测未命中时怎么处理 [#实测未命中时怎么处理]

本次 Messages 示例的实际结果是 `cache_creation_input_tokens=0`、`cache_read_input_tokens=0`，没有 HTTP 报错。不要把请求被接受等同于缓存生效。需要复现已验证的缓存命中时，运行上面的 `deepseek-flash` OpenAI 示例，并检查正数 `cached_tokens`。

为保持前缀可复用，确认两次请求使用相同模型和完整前缀；不要在前缀中加入时间戳或每次变化的标识。保留用量和 `X-Request-Id` 以便核对，不能用相同回答代替命中证据。

协议细节：[OpenAI](https://developers.openai.com/api/docs/guides/prompt-caching) · [Anthropic](https://platform.claude.com/docs/en/build-with-claude/prompt-caching)。

[API 参考 →](/docs/api/compatible/openai) · [Cookbook →](/docs/cookbook)
