使用文本生成或视觉理解模型时,不同推理请求可能出现输入内容的重叠(例如多轮对话或对同一本书的多次提问)。上下文缓存(Context Cache)技术会缓存这些请求的公共前缀,减少推理时的重复计算。这能提升响应速度,并在不影响回复效果的前提下降低您的使用成本。
为满足不同场景的需求,上下文缓存提供两种工作模式,可以根据对便捷性、确定性及成本的需求进行选择:
隐式缓存:此为默认的自动模式,无需配置,适合追求便捷的通用场景。系统会自动识别请求内容的公共前缀并进行缓存,但缓存命中率不确定。对命中缓存的部分收取 20% 的费用。
显式缓存:需要主动开启的缓存模式。用户需要主动为指定内容创建缓存以保证有效期(5分钟)内的确定性命中。创建缓存需支付125%的费用,后续命中仅需10%,适用于Agent、多轮对话等长上下文的场景。
隐式缓存与显式缓存互相独立且互斥,单个请求只能应用其中一种模式。
隐式缓存
支持的模型
文本生成模型
通义千问 Max:qwen-max
通义千问 Plus:qwen-plus
通义千问 Flash:qwen-flash
通义千问 Turbo:qwen-turbo
通义千问 Coder:qwen3-coder-plus、qwen3-coder-flash
视觉理解模型
通义千问 VL:qwen-vl-max、qwen-vl-plus
行业模型
角色扮演:qwen-plus-character
暂不支持快照与 latest 模型。
工作方式
向支持隐式缓存的模型发送请求时,该功能会自动开启。系统的工作方式如下:
查找:收到请求后,系统基于前缀匹配原则,检查缓存中是否存在您提示词的公共前缀。
判断:
若命中缓存,系统直接使用缓存结果进行后续部分的推理。
若未命中,系统按常规处理请求,并将本次提示词的前缀存入缓存,以备后续请求使用。
系统会定期清理长期未使用的缓存数据。上下文缓存命中概率并非100%,即使请求上下文完全一致,仍可能未命中,具体命中概率由系统判定。
使用时,不足 256 Token 的内容不会被缓存。
如何提升命中缓存的概率
隐式缓存的命中逻辑是判断不同请求的前缀是否存在重复内容。为提高命中概率,请将重复内容置于提示词开头,差异内容置于末尾。
文本模型:假设系统已缓存"ABCD",则请求"ABE"可能命中"AB"部分,而请求"BCD"则无法命中。
视觉理解模型:
如果对同一图像或视频进行多次提问,将user message 中的图像(image)或视频(video)放在文本信息(text)前面会提高命中概率。
如果对不同图像或视频提问同一问题,将文本信息放在图像或视频前面会提高命中概率。
如何计费
开启隐式缓存模式无需额外付费,OpenAI兼容-Batch方式调用无法享受缓存折扣。
当请求命中缓存时,命中的输入 Token 按 cached_token
计费(单价为input_token
单价的20%);未被命中的输入 Token 按标准 input_token
计费。
output_token
仍按原价计费。
示例:某请求包含 10,000 个输入 Token,其中 5,000 个命中缓存。费用计算如下:
未命中 Token (5,000):按 100% 单价计费
命中 Token (5,000):按 20% 单价计费
总输入费用相当于无缓存模式的 60%:(50% × 100%) + (50% × 20%) = 60%。
您可以从返回结果的cached_tokens
属性获取命中缓存的 Token 数。
OpenAI兼容-Batch方式调用无法享受缓存折扣。
命中缓存的案例
文本生成模型
OpenAI兼容
当您使用 OpenAI 兼容的方式调用模型并触发了隐式缓存后,可以得到如下的返回结果,在usage.prompt_tokens_details.cached_tokens
可以查看命中缓存的 Token 数(该 Token 数包含在usage.prompt_tokens
中)。
{
"choices": [
{
"message": {
"role": "assistant",
"content": "我是阿里云开发的一款超大规模语言模型,我叫通义千问。"
},
"finish_reason": "stop",
"index": 0,
"logprobs": null
}
],
"object": "chat.completion",
"usage": {
"prompt_tokens": 3019,
"completion_tokens": 104,
"total_tokens": 3123,
"prompt_tokens_details": {
"cached_tokens": 2048
}
},
"created": 1735120033,
"system_fingerprint": null,
"model": "qwen-plus",
"id": "chatcmpl-6ada9ed2-7f33-9de2-8bb0-78bd4035025a"
}
DashScope
当您使用DashScope Python SDK 或 HTTP 方式调用模型并触发了隐式缓存后,可以得到如下的返回结果,在usage.prompt_tokens_details.cached_tokens
可以查看命中缓存的 Token 数(该 Token 数包含在usage.input_tokens
中)。
使用 DashScope Java SDK 调用支持隐式缓存功能,但暂时无法查看cached_tokens
。
{
"status_code": 200,
"request_id": "f3acaa33-e248-97bb-96d5-cbeed34699e1",
"code": "",
"message": "",
"output": {
"text": null,
"finish_reason": null,
"choices": [
{
"finish_reason": "stop",
"message": {
"role": "assistant",
"content": "我是一个来自阿里云的大规模语言模型,我叫通义千问。我可以生成各种类型的文本,如文章、故事、诗歌、故事等,并能够根据不同的场景和需求进行变换和扩展。此外,我还能够回答各种问题,提供帮助和解决方案。如果您有任何问题或需要帮助,请随时告诉我,我会尽力提供支持。请注意,连续重复相同的内容可能无法获得更详细的答复,建议您提供更多具体信息或变化提问方式以便我更好地理解您的需求。"
}
}
]
},
"usage": {
"input_tokens": 3019,
"output_tokens": 101,
"prompt_tokens_details": {
"cached_tokens": 2048
},
"total_tokens": 3120
}
}
视觉理解模型
OpenAI兼容
当您使用 OpenAI 兼容的方式调用模型并触发了隐式缓存后,可以得到如下的返回结果,在usage.prompt_tokens_details.cached_tokens
可以查看命中缓存的 Token 数(该 Token 数包含在usage.prompt_tokens
中)。
{
"id": "chatcmpl-3f3bf7d0-b168-9637-a245-dd0f946c700f",
"choices": [
{
"finish_reason": "stop",
"index": 0,
"logprobs": null,
"message": {
"content": "这张图像展示了一位女性和一只狗在海滩上互动的温馨场景。女性穿着格子衬衫,坐在沙滩上,面带微笑地与狗进行互动。狗是一只大型的浅色犬种,戴着彩色的项圈,前爪抬起,似乎在与女性握手或击掌。背景是广阔的海洋和天空,阳光从画面的右侧照射过来,给整个场景增添了一种温暖而宁静的氛围。",
"refusal": null,
"role": "assistant",
"audio": null,
"function_call": null,
"tool_calls": null
}
}
],
"created": 1744956927,
"model": "qwen-vl-max",
"object": "chat.completion",
"service_tier": null,
"system_fingerprint": null,
"usage": {
"completion_tokens": 93,
"prompt_tokens": 1316,
"total_tokens": 1409,
"completion_tokens_details": null,
"prompt_tokens_details": {
"audio_tokens": null,
"cached_tokens": 1152
}
}
}
DashScope
当您使用DashScope Python SDK 或 HTTP 方式调用模型并触发了隐式缓存后,可以得到如下的返回结果,在usage.prompt_tokens_details.cached_tokens
可以查看命中缓存的 Token 数(该 Token 数包含在usage.input_tokens
中)。
使用 DashScope Java SDK 调用支持隐式缓存功能,但暂时无法查看cached_tokens
。
{
"status_code": 200,
"request_id": "06a8f3bb-d871-9db4-857d-2c6eeac819bc",
"code": "",
"message": "",
"output": {
"text": null,
"finish_reason": null,
"choices": [
{
"finish_reason": "stop",
"message": {
"role": "assistant",
"content": [
{
"text": "这张图像展示了一位女性和一只狗在海滩上互动的温馨场景。女性穿着格子衬衫,坐在沙滩上,面带微笑地与狗进行互动。狗是一只大型犬,戴着彩色项圈,前爪抬起,似乎在与女性握手或击掌。背景是广阔的海洋和天空,阳光从画面右侧照射过来,给整个场景增添了一种温暖而宁静的氛围。"
}
]
}
}
]
},
"usage": {
"input_tokens": 1292,
"output_tokens": 87,
"input_tokens_details": {
"text_tokens": 43,
"image_tokens": 1249
},
"total_tokens": 1379,
"output_tokens_details": {
"text_tokens": 87
},
"image_tokens": 1249,
"prompt_tokens_details": {
"cached_tokens": 1152
}
}
}
典型场景
如果您的不同请求有着相同的前缀信息,上下文缓存可以有效提升这些请求的推理速度,降低推理成本与首包延迟。以下是几个典型的应用场景:
基于长文本的问答
适用于需要针对固定的长文本(如小说、教材、法律文件等)发送多次请求的业务场景。
第一次请求的消息数组
messages = [{"role": "system","content": "你是一个语文老师,你可以帮助学生进行阅读理解。"}, {"role": "user","content": "<文章内容> 这篇课文表达了作者怎样的思想感情?"}]
之后请求的消息数组
messages = [{"role": "system","content": "你是一个语文老师,你可以帮助学生进行阅读理解。"}, {"role": "user","content": "<文章内容> 请赏析这篇课文的第三自然段。"}]
虽然提问的问题不同,但都基于同一篇文章。相同的系统提示和文章内容构成了大量重复的前缀信息,有较大概率命中缓存。
代码自动补全
在代码自动补全场景,大模型会结合上下文中存在的代码进行代码自动补全。随着用户的持续编码,代码的前缀部分会保持不变。上下文缓存可以缓存之前的代码,提升补全速度。
多轮对话
实现多轮对话需要将每一轮的对话信息添加到 messages 数组中,因此每轮对话的请求都会存在与前轮对话前缀相同的情况,有较高概率命中缓存。
第一轮对话的消息数组
messages=[{"role": "system","content": "You are a helpful assisatnt."}, {"role": "user","content": "你是谁?"}]
第二轮对话的消息数组
messages=[{"role": "system","content": "You are a helpful assisatnt."}, {"role": "user","content": "你是谁?"}, {"role": "assistant","content": "我是由阿里云开发的通义千问。"}, {"role": "user","content": "你能干什么?"}]
随着对话轮数的增加,缓存带来的推理速度优势与成本优势会更明显。
角色扮演或 Few Shot
在角色扮演或 Few-shot 学习的场景中,您通常需要在提示词中加入大量信息来指引大模型的输出格式,这样不同的请求之间会有大量重复的前缀信息。
以让大模型扮演营销专家为例,System prompt包含有大量文本信息,以下是两次请求的消息示例:
system_prompt = """你是一位经验丰富的营销专家。请针对不同产品提供详细的营销建议,格式如下: 1. 目标受众:xxx 2. 主要卖点:xxx 3. 营销渠道:xxx ... 12. 长期发展策略:xxx 请确保你的建议具体、可操作,并与产品特性高度相关。""" # 第一次请求的user message 提问关于智能手表 messages_1=[ {"role": "system", "content": system_prompt}, {"role": "user", "content": "请为一款新上市的智能手表提供营销建议。"} ] # 第二次请求的user message 提问关于笔记本电脑,由于system_prompt相同,有较大概率命中 Cache messages_2=[ {"role": "system", "content": system_prompt}, {"role": "user", "content": "请为一款新上市的笔记本电脑提供营销建议。"} ]
使用上下文缓存后,即使用户频繁更换询问的产品类型(如从智能手表到笔记本电脑),系统也可以在触发缓存后快速响应。
视频理解
在视频理解场景中,如果对同一个视频提问多次,将video放在text前会提高命中缓存的概率;如果对不同的视频提问相同的问题,则将text放在video前面,会提高命中缓存的概率。以下是对同一个视频请求两次的消息示例:
# 第一次请求的user message 提问这段视频的内容 messages1 = [ {"role":"system","content":[{"text": "You are a helpful assistant."}]}, {"role": "user", "content": [ {"video": "https://help-static-aliyun-doc.aliyuncs.com/file-manage-files/zh-CN/20250328/eepdcq/phase_change_480p.mov"}, {"text": "这段视频的内容是什么?"} ] } ] # 第二次请求的user message 提问关于视频时间戳相关的问题,由于基于同一个视频进行提问,将video放在text前面,有较大概率命中 Cache messages2 = [ {"role":"system","content":[{"text": "You are a helpful assistant."}]}, {"role": "user", "content": [ {"video": "https://help-static-aliyun-doc.aliyuncs.com/file-manage-files/zh-CN/20250328/eepdcq/phase_change_480p.mov"}, {"text": "请你描述下视频中的一系列活动事件,以JSON格式输出开始时间(start_time)、结束时间(end_time)、事件(event),不要输出```json```代码段”。"} ] } ]
显式缓存
支持的模型
当前仅支持通义千问Coderqwen3-coder-plus,暂不支持快照与 latest 模型。
如何使用
创建缓存:
首次发起请求时,需要为
messages
数组中的最后一个content
设置{"cache_control": {"type": "ephemeral"}}
,系统会使用整个messages
数组创建缓存块,有效期为5分钟。messages
格式如下:[ {"role": "system", "content": "你是一个有用的代码助手"}, { "role": "user", "content": [ { "type": "text", "text": <完整的红黑树代码实现>, }, { "type": "text", "text": "该代码主要实现了什么功能", "cache_control": {"type": "ephemeral"}, } ], } ]
命中缓存:
后续请求需要在有效期内发起,同样在最后一个
content
中设置cache_control
属性。系统会将新请求messages
的开始部分与已缓存的内容进行最长匹配,若与某个缓存块完全匹配则命中缓存,该缓存有效期会免费刷新(5分钟)。例如,第一次请求包含
system
和user
角色的内容并创建了缓存。若第二次请求开头包含相同的system
、user
,则会成功命中缓存,若开头包含相同的system
和不同的user
,则不命中缓存(需要完全匹配)。[ {"role": "system", "content": "你是一个有用的代码助手"}, { "role": "user", "content": [ { "type": "text", "text": <完整的红黑树代码实现>, }, { "type": "text", "text": "该代码主要实现了什么功能", } ], }, {"role": "assistant", "content": <模型的回复>}, { "role": "user", "content": [ { "type": "text", "text": "各个操作的时间复杂度是多少", "cache_control": {"type": "ephemeral"}, } ] } ]
可以通过响应中
usage
的字段查看缓存创建与命中情况:cache_type
:若类型为ephemeral
,则启用了显式缓存。cache_creation_input_tokens
:用于创建显式缓存的 Token 数。cached_tokens
:命中显式缓存的 Token 数。
如何计费
输入计费:
创建缓存时:用于创建缓存的 Token 按
input_token_cache_creation_5m
计费,单价为标准input_token
的 125%。若新创建的缓存块中包含已存在的缓存块,按增量(新缓存块Token数 - 已存在缓存块Token数)计费。命中缓存时:命中的 Token 按
input_token_cache_read
计费,单价为标准input_token
的 10%。其他情况:未命中且未创建缓存的 Token 按标准
input_token
计费。
输出计费:
output_token
始终按原价计费。
缓存限制
最小可缓存提示词长度为 1024 Token。
当前仅支持一个
cache_control
标记,且需要放置在messages
数组中的最后一个content
内,若放置于其他content
,系统将默认移动标记至最后一个content
。显式缓存的前缀匹配将从后向前进行,自动匹配最后20个
content
。当最后一个content
与缓存块间隔大于20个content
块时,不会命中缓存,建议创建新的缓存块。当前缓存类型仅支持
ephemeral
,有效期为5分钟。
可缓存内容
请求中可缓存的内容包括:
系统消息:
messages
中"role":"system"
的消息。工具:
tools
数组中的工具定义。会话消息:
messages
中,"role": "user"
和"role": "assistant"
的信息。工具调用结果:
messages
中的"role": "tool"
的信息。
使用示例
下面以多轮对话要求模型解释代码为例,展示如何开启显式缓存及查看返回结果。
OpenAI兼容
示例代码
返回结果
DashScope
示例代码
返回结果
第1轮:创建缓存
本次请求未命中缓存,因此 cached_tokens
为 0,输入的 message
被用于创建缓存。
OpenAI兼容
{
"choices": [
{
"message": {
"role": "assistant",
"content": "对于这个红黑树实现,各个操作的时间复杂度如下:<省略后续回答>"
},
"finish_reason": "stop",
"index": 0,
"logprobs": null
}
],
"object": "chat.completion",
"usage": {
"prompt_tokens": 2069,
"completion_tokens": 820,
"total_tokens": 2889,
"prompt_tokens_details": {
"audio_tokens": null,
"cached_tokens": 0,
"cache_creation": {
"ephemeral_5m_input_tokens": 2065
},
"cache_creation_input_tokens":2065,
"cache_type":"ephemeral"
}
},
"created": 1735120033,
"system_fingerprint": null,
"model": "qwen3-coder-plus",
"id": "chatcmpl-6ada9ed2-7f33-9de2-8bb0-xxxxxx"
}
DashScope
{
"status_code": 200,
"request_id": "f71f91ed-a019-9696-bdc7-xxxxxx",
"code": "",
"message": "",
"output": {
"text": null,
"finish_reason": null,
"choices": [
{
"finish_reason": "stop",
"message": {
"role": "assistant",
"content": "这段 Python 代码完整地实现了一个 **红黑树(Red-Black Tree)**<省略后续回答>"
}
}
]
},
"usage": {
"input_tokens": 2069,
"output_tokens": 757,
"total_tokens": 2826,
"prompt_tokens_details": {
"cache_creation": {
"ephemeral_5m_input_tokens": 2065
},
"cache_creation_input_tokens": 2065,
"cache_type": "ephemeral",
"cached_tokens": 0
}
}
}
第2轮:命中缓存
第二次请求的前半部分与第一次请求一致,成功命中缓存。cached_tokens
等于上一轮创建的缓存 Token 数。新的内容(上一轮的 assistant 回复 + 新的用户问题)则被用于创建新的、更长的缓存块。
OpenAI兼容
{
"choices": [
{
"message": {
"role": "assistant",
"content": "对于这个红黑树实现,各个操作的时间复杂度如下:<省略后续回答>"
},
"finish_reason": "stop",
"index": 0,
"logprobs": null
}
],
"object": "chat.completion",
"usage": {
"prompt_tokens": 2905,
"completion_tokens": 864,
"total_tokens": 3769,
"prompt_tokens_details": {
"audio_tokens": null,
"cached_tokens": 2065,
"cache_creation": {
"ephemeral_5m_input_tokens": 836
},
"cache_creation_input_tokens":836,
"cache_type":"ephemeral"
}
},
"created": 1735120033,
"system_fingerprint": null,
"model": "qwen3-coder-plus",
"id": "chatcmpl-6ada9ed2-7f33-9de2-8bb0-xxxxxx"
}
DashScope
{
"status_code": 200,
"request_id": "f71f91ed-a019-9696-bdc7-xxxxxx",
"code": "",
"message": "",
"output": {
"text": null,
"finish_reason": null,
"choices": [
{
"finish_reason": "stop",
"message": {
"role": "assistant",
"content": "## 红黑树各操作的时间复杂度分析<省略后续回答>"
}
}
]
},
"usage": {
"input_tokens": 2842,
"output_tokens": 1000,
"total_tokens": 3842,
"prompt_tokens_details": {
"cache_creation": {
"ephemeral_5m_input_tokens": 773
},
"cache_creation_input_tokens": 773,
"cache_type": "ephemeral",
"cached_tokens": 2065
}
}
}
常见问题
Q:为什么有时候发现创建显式缓存后没有命中?
A:显式缓存的最小 Token 数为 1024,且在有效期(默认5分钟)后会自动删除。当最后一个content
与已存在的缓存块的间隔大于20个内容块时,不会命中缓存,建议创建新的缓存块。
Q:为什么创建显式缓存后,截取一段前缀相同的提示词,无法命中?
A:显式缓存采用完全匹配而非前缀匹配策略,用于匹配的 content
内容必须与创建缓存时的内容完全一致才能命中。
Q:使用显式缓存命中后,是否会刷新(延长)有效期
A:是的,每次成功命中都会自动免费将该缓存块的有效期刷新为5分钟。
Q:不同用户之间的显式缓存是否会共享
A:不会。无论是隐式缓存还是显式缓存,数据都在用户级别隔离,不会共享。
Q:用了显式缓存后,原先的隐式缓存还生效吗?
A:不生效。隐式缓存和显式缓存是互斥的。
Q:为什么usage
的input_tokens
不等于cache_creation_input_tokens
和cached_tokens
的总和?
A:为了确保模型输出效果,后端服务会在用户提供的提示词之后追加少量 Token(通常在10以内),这些 Token 在 cache_control
标记之后,因此不会被计入缓存的创建或读取,但会计入总的 input_tokens
。