> ## Documentation Index
> Fetch the complete documentation index at: https://docs.siflow.cn/llms.txt
> Use this file to discover all available pages before exploring further.

# Prompt 缓存（Prompt Caching）

> 了解算秩 Prompt Caching 如何复用稳定上下文，降低长提示词、工具定义、长文档问答和代码分析的重复处理成本。

Prompt Caching 用于复用请求中重复出现的上下文内容，减少模型对相同输入的重复处理。它常用于长系统提示词、固定工具说明、长文档问答、多轮会话和代码库分析等场景。

Prompt Caching 不会改变模型的生成逻辑。它只影响重复上下文的处理方式、请求耗时和用量统计；模型仍会基于当前请求中的完整上下文生成新的回复。

## 使用场景

* **长系统提示词**：多个请求复用相同的角色设定、输出规则、安全边界或产品说明。
* **固定工具定义**：Function Calling 场景中，工具列表、参数 Schema 和工具说明在多轮请求中保持稳定。
* **长文档多轮问答**：用户围绕同一份文档、合同、论文或会议记录连续提问。
* **代码库分析**：多次请求复用同一组代码片段、项目结构或约束说明。
* **RAG 后续追问**：首轮请求传入较长检索结果，后续请求继续围绕相同材料提问。

## 支持的模型

不同模型对 Prompt Caching 的支持情况可能不同。使用前请在 [模型广场](https://console.siflow.cn/model-inference/models) 查看模型详情，并结合 API 指南确认是否支持缓存、是否需要显式开启，以及用量统计中如何展示缓存命中。

## 工作机制

Prompt Caching 通常围绕“重复上下文”生效。应用在多次请求中保留相同或高度一致的上下文前缀和消息顺序，模型服务在可命中的情况下复用已处理的上下文，从而减少重复计算。

一次可复用的请求通常包含以下部分：

* 稳定的 `system` 提示词。
* 固定的工具定义、输出格式或约束说明。
* 重复使用的长文档、代码片段、知识库内容或检索结果。
* 每次请求变化的用户问题、少量新增上下文或会话补充。

典型流程如下：

1. 将长期复用的内容放在请求前半部分，并保持顺序稳定。
2. 将每次变化的用户问题或临时上下文放在稳定内容之后。
3. 多次请求复用相同前缀和消息顺序，尽量避免无意义改写、重排或插入动态信息。
4. 通过响应中的 `usage` 或用量统计页面观察是否出现缓存相关字段。
5. 根据延迟、成本和命中情况，决定是否继续使用长上下文、改用 RAG，或调整上下文组织方式。

<Note>
  缓存命中通常依赖上下文是否可复用。即使模型支持 Prompt Caching，频繁变化的 prompt、随机插入的元数据、不断重排的消息顺序，也可能降低命中效果。不同模型的命中时机和命中范围可能不同，不要假设某一次请求一定命中缓存。
</Note>

## 与 Long Context 和 RAG 的关系

Prompt Caching、Long Context 和 RAG 解决的问题不同：

| 能力             | 主要作用             | 适合场景                  |
| -------------- | ---------------- | --------------------- |
| Prompt Caching | 复用重复上下文，减少重复处理   | 多次请求共享相同长前缀或固定材料      |
| Long Context   | 在单次请求中放入更多上下文    | 一次性阅读、分析或总结较长材料       |
| RAG            | 先检索相关片段，再把片段放入请求 | 知识库较大、问题范围不固定、只需要局部证据 |

如果每次请求都围绕同一份长材料继续追问，Prompt Caching 可能更适合与 Long Context 搭配使用。如果知识库很大、每次问题只需要少量片段，优先使用 RAG 减少无关上下文。

## 关键字段

* `messages`：承载系统提示、历史消息和可复用上下文。为了提升缓存复用机会，应尽量保持可复用部分的顺序和内容稳定。
* `model`：选择具体模型。不同模型是否支持 Prompt Caching、缓存命中规则和用量字段可能不同。
* `usage.prompt_tokens`：本次请求的输入 token 数。长上下文请求通常会增加该数值。
* `usage.prompt_tokens_details.cached_tokens`：如果返回该字段，可用于观察本次输入中可能命中的缓存 token 数。不同模型可能不返回该字段，字段含义和计费口径请以 API 指南为准。

使用 `stream=True` 时，缓存相关用量信息也可能出现在流式响应末尾的 `usage` 中。不同模型的返回情况可能不同，客户端应按字段是否存在进行处理。

完整请求参数、返回字段和计费规则请以 API 指南为准。能力文档只说明 Prompt Caching 的基本使用方式和应用侧组织原则。

## 使用建议

* **保持可复用内容和消息顺序稳定**：把系统提示词、工具定义、长文档或固定约束放在请求前半部分，并在多次请求中保持内容、消息顺序和结构一致。
* **把动态内容放在后面**：将用户当前问题、时间戳、临时变量、检索补充或会话新增内容放在稳定前缀之后。
* **避免无意义改写**：频繁调整空格、标题、字段顺序或工具描述，可能降低缓存命中机会。
* **控制重复上下文规模**：缓存可以降低重复处理成本或延迟，但不应成为无限塞入上下文的理由。
* **结合用量和耗时观察效果**：如果响应中返回 `cached_tokens` 或用量页面展示缓存相关指标，可以结合请求耗时和成本判断是否有效。
* **与 RAG 搭配使用**：对于大型知识库，先检索最相关片段，再让可复用的系统提示词、工具定义或固定材料保持稳定。
* **注意输出预算**：Prompt Caching 主要作用于输入上下文。生成的输出仍会消耗 `max_completion_tokens` 预算。

## 限制说明

* Prompt Caching 不保证每次请求都能命中缓存。命中情况可能受模型、请求内容、消息顺序、API 入口和服务端调度影响。
* 首次请求或前几次请求可能不会返回 `cached_tokens`。即使后续请求命中缓存，不同模型的命中时机和命中范围也可能不同。
* Prompt Caching 不会让模型记住请求之外的内容。需要模型使用的材料仍必须在当前请求中提供，或通过已确认的缓存机制引用。
* Prompt Caching 不改变模型回答质量，也不保证相同输入每次生成完全一致。
* `cached_tokens` 可以作为观察缓存命中的参考，但不等同于完整计费规则。缓存有效期、是否需要显式开启、是否产生额外费用以及命中后的计费方式，必须以 API 指南和模型详情为准。
* 如果输入超过模型上下文限制，Prompt Caching 不能替代上下文窗口。仍需要减少输入、拆分任务，或选择上下文窗口更大的模型。
* 不要在可复用上下文中放入不应被后续请求复用的敏感信息、一次性凭证或用户私密数据。

## 调用示例

示例使用环境变量读取 API Key，避免将密钥写入代码。

```bash theme={null}
export API_KEY="YOUR_API_KEY"
```

这段代码不演示特定的缓存开启参数，只演示如何组织更容易复用的稳定上下文：

1. 将固定规则和长材料放在前面。
2. 将每次变化的问题放在后面。
3. 多次请求复用相同的 `stable_context`。
4. 如响应返回 `cached_tokens`，打印该字段用于观察。

示例中的模型仅用于展示调用方式。实际接入时，请在模型广场确认模型是否支持 Prompt Caching，以及响应中是否返回缓存相关用量字段。

```python theme={null}
import os
from openai import OpenAI

client = OpenAI(
    api_key=os.environ["API_KEY"],
    base_url="https://api.siflow.cn/model-api",
)

stable_context = """
你是一名严谨的文档分析助手。
请只基于 <document> 中的材料回答问题。
如果材料中没有答案，请说明无法从材料中确认。

<document>
在这里放入会被多次复用的长文档、代码片段、产品说明或检索结果。
后续请求应尽量保持这部分内容不变。
</document>
"""


def ask(question: str):
    response = client.chat.completions.create(
        model="glm-5.2",
        messages=[
            {"role": "system", "content": stable_context},
            {"role": "user", "content": question},
        ],
        max_completion_tokens=512,
    )

    print(response.choices[0].message.content)

    prompt_details = getattr(response.usage, "prompt_tokens_details", None)
    if prompt_details:
        cached_tokens = getattr(prompt_details, "cached_tokens", None)
        print("cached_tokens:", cached_tokens)


ask("请总结这份材料的三个核心结论。")
ask("请列出材料中仍需要确认的问题。")
```

如果第一次请求没有看到 `cached_tokens`，可以连续发送几次保持相同稳定前缀的请求进行观察。不要依赖某一次请求必然命中缓存。
