大模型缓存命中技术实战:Prompt设计、代码示例与命中率调优

API工程 实践大模型缓存命中技术实战openstarry.com

适用场景:| | 长上下文任务 适用模型:OpenAI、DeepSeek、通义千问等支持缓存的主流厂商

一、缓存命中的工作原理 先搞清楚缓存是怎么工作的,后面所有的写法才有依据。

缓存系统以 Prompt 的起始部分(前缀)为匹配对象。新请求到来时,系统提取前缀,在缓存池中查找是否有完全一致的前缀。完全一致则命中(Cache Hit),按缓存折扣价计费;稍有不同则未命中(Cache Miss),按原价计费。

关键认知:这是字符级别的精确匹配,不是语义相似度匹配。

"退货政策"和"退款流程"意思差不多,但缓存系统看的是字符串——只要字符不同,就是100% Miss。哪怕系统提示词里多了一个空格、一个句号、一个换行符,都会在匹配点之后全部失效。

1.1 精确前缀缓存 vs 语义缓存:两层保障 前面讲的"固定前缀匹配"是第一层缓存,需要你自己控制 Prompt 结构来触发。它的优点是确定性强——只要前缀一致,100% 命中。

部分平台(如 OpenStarry)在此基础上额外提供了一层语义缓存,作为第二层保障。

语义缓存不看字符串是否完全一致,而是判断两个问题的语义是否相近。比如:

用户 A 问:"怎么退货?"

用户 B 问:"退货流程是什么?"

用户 C 问:"我要退货,怎么操作?"

这三个问题字符串完全不同,精确前缀缓存无法命中。但语义缓存能识别出它们问的是同一件事,直接返回已缓存的标准答案。

对开发者的实际意义:

你不需要为语义缓存做任何额外配置——它是平台侧自动生效的。你只需要做好两件事:

继续按"固定前缀"原则写 Prompt,确保第一层缓存命中

如果第一层没命中(比如用户问法差异太大),语义缓存还会在后台尝试兜底

两层叠加之后,重复性问题的实际缓存命中率会明显高于单纯依赖前缀匹配。

不同厂商的缓存规则略有差异,接入前先确认:

OpenAI:要求固定前缀 ≥ 1024 Token 才会进入缓存

DeepSeek:自动前缀缓存,无硬性门槛

通义千问:支持显式和隐式两种缓存模式

二、Prompt怎么写才能命中缓存 先看一个绝大多数人都在犯的错。

反模式(命中率 ≈ 0%) python user_question = "我的订单号是12345,什么时候发货?" prompt = f"用户问题:{user_question}\n请回答:" # 问题放在开头 每次用户问不同的问题,整个前缀都变了,缓存完全无效。

正解(命中率 80%+) python

固定部分放最前面

system = "你是一个客服助手,请根据公司政策回答问题。" fixed_doc = "退货需在7天内完成,逾期不处理..."

变化部分放最后面

user_question = "我的订单号是12345,什么时候发货?" prompt = f"{system}\n\n{fixed_doc}\n\n用户问题:{user_question}\n回答:" 核心原则就一句话:固定的内容放最前面,变化的内容放最后面。

缓存匹配看的是请求前缀。前面一大段完全一样,后面拼什么问题都不影响命中。

实际操作:把Prompt拆成三块 区块 内容 变化频率 头部固定区 系统角色、任务说明、输出格式 几乎不变 中部半固定区 文档、知识库、历史摘要 低频更新 尾部变化区 用户当前问题 每次不同 按"头部 → 中部 → 尾部"的顺序拼接即可。

三、代码实战与预热 3.1 跨厂商字段差异 不同厂商返回的缓存命名字段不一样,先看清楚:

OpenAI / 通义千问:usage.prompt_tokens_details.cached_tokens

DeepSeek:usage.prompt_cache_hit_tokens

3.2 通用读取函数 python def get_cached_tokens(response, provider="openai"): """跨厂商读取缓存命中的输入 Token 数""" usage = response.usage if provider == "deepseek": return getattr(usage, "prompt_cache_hit_tokens", 0) details = getattr(usage, "prompt_tokens_details", None) return getattr(details, "cached_tokens", 0) if details else 0 3.3 完整调用示例 python response = client.chat.completions.create( model="gpt-4o-mini", messages=[ {"role": "system", "content": "你是一个财务分析师,这是公司财报..."}, {"role": "user", "content": "2024年Q3营收是多少?"} ], )

cached_tokens = get_cached_tokens(response, provider="openai") print(f"缓存命中: {cached_tokens > 0}") print(f"输入Token: {response.usage.prompt_tokens}") print(f"其中缓存命中: {cached_tokens}") 第一次请求:缓存未命中,系统建立缓存。第二次请求(相同前缀,不同问题):缓存命中,享受折扣价。

上线缓存后,第一件事就是把 cached_tokens 打到日志里。不监控命中率,优化就是瞎搞。

3.4 预热:让批量任务第一次就命中 缓存有个特性:第一次请求永远不命中。如果批量任务只跑一次,缓存跟你没关系。解决办法是预热——正式跑之前先发几个请求把缓存建起来。

python import time

def warm_up_cache(fixed_prompt, sample_questions, model="gpt-4o-mini"): for q in sample_questions[:3]: # 只用前3个预热 client.chat.completions.create( model=model, messages=[ {"role": "system", "content": fixed_prompt}, {"role": "user", "content": q} ] ) time.sleep(0.5) print("预热完成") 几个要点:

3到5个请求足够,别发几十个,容易触发限流

每个请求间隔0.5到1秒

预热完等几秒再开始正式任务

3.5 调试技巧 构建一个确定达标的固定前缀,确保测试时能触发 OpenAI 的缓存(≥ 1024 Token):

python import tiktoken

def build_fixed_prefix(min_tokens=1024): """构建一个 Token 数至少为 min_tokens 的固定前缀""" enc = tiktoken.encoding_for_model("gpt-4o-mini") base_text = "请用中文回答以下问题。" long_text = base_text * 300 tokens = enc.encode(long_text) final_text = enc.decode(tokens[:min_tokens]) return final_text

fixed_prefix = build_fixed_prefix()

第一次请求(建立缓存)

r1 = client.chat.completions.create( model="gpt-4o-mini", messages=[{"role": "user", "content": fixed_prefix + "问题A"}] ) print(get_cached_tokens(r1)) # 应该为 0

第二次请求(前缀完全相同,只变末尾)

r2 = client.chat.completions.create( model="gpt-4o-mini", messages=[{"role": "user", "content": fixed_prefix + "问题B"}] ) print(get_cached_tokens(r2)) # 应该 > 0 四、三个高频场景与五个坑 4.1 多轮对话 别每轮都把完整对话历史传进去,前缀会越来越长、越来越乱。

正确做法:

system前缀保持完全不变

每轮结束后把历史对话压缩成摘要,放进固定区

用户的新问题始终放在最后

4.2 多租户 在系统提示词最前面加上租户标识,每个租户前缀不同,缓存天然隔离:

text 【租户:customer_A】 你是一个客服助手... 重点:租户ID格式必须绝对固定,今天加个空格明天改个写法,缓存就全废了。

4.3 动态内容 别把时间戳这类每次都变的东西放进固定区:

python

❌ 不要这样

prompt = f"今天是{datetime.now()},请分析..."

✅ 用相对表达

prompt = "请基于当前日期进行分析..." 4.4 五个最容易踩的坑 坑1:以为语义相似就能命中

"退货政策"和"退款流程"意思差不多——但缓存看的是字符级完全匹配。只要字符不同,就是100% Miss。固定内容写成模板,用的时候直接拼,别手改。

坑2:忽略空格和换行符

python prompt1 = "你好\n请回答" prompt2 = "你好请回答" # 换行符没了 → 完全不同 建议用 strip() 清理首尾空白,但内部结构保持稳定。常见情况是Prompt末尾多了个换行,命中率直接从80%掉到0。

坑3:预热太猛

一次性发100个请求预热,结果触发限流。3到5个请求温和预热就够了。

坑4:切换模型不重新预热

从gpt-4切到gpt-4o,旧缓存全部失效。切换模型后必须重新预热。

坑5:忽略模型版本变更

可用同一段测试文本分别计算Token数,数值不同说明Tokenizer已变更,需重新预热。

五、最后说几句实在的 检查你的Prompt:固定内容移到开头,命中率能从≈0%提到80%+

把 cached_tokens 打到日志里:不监控命中率,优化就是瞎搞

批量任务前预热:3到5个请求,让首次批量就享受缓存

每周看一眼命中率:低于50%就该重构Prompt了

切换模型时重新预热:别指望旧缓存能用

缓存不是什么高级技巧,就是个习惯问题。对于10万Token的文档分析或者仓库级AI编程,它能把输入成本压到原来的几分之一。

很多团队的问题是:上线的时候想起来加缓存,后面改Prompt随手一改,缓存就废了,也没人发现。

把"缓存友好"当成写Prompt的基本习惯,而不是出了成本问题再去补救。

修订依据(2026-08):OpenAI Prompt Caching定价、DeepSeek API Docs。各厂商政策调整快,落地前请复核官方发布。

第二篇(价值篇) 文章概要

本文从套餐选型视角解读大模型缓存命中的实际价值。对比Coding Plan(按次计费)与Token Plan(按量计费)两种套餐的计费逻辑与适用场景,分别阐述缓存如何让每次调用处理更大任务、让固定预算支撑更多请求,并补充语义缓存作为额外增值点。最后给出选型三问与三个基本操作习惯,帮助读者根据自身业务选择套餐、写对Prompt,让每笔投入都物有所值。

SEO标签

标签:AI 大模型 API套餐 Coding Plan Token Plan 缓存命中 成本优化 套餐选型

摘要:大模型API套餐买Coding Plan还是Token Plan?缓存命中如何让两种套餐都更值钱?本文从算账视角解读缓存的价值,不讲代码,只讲选型逻辑与操作习惯。

你的AI API套餐买对了吗?缓存命中让每次调用更值 很多买了Coding Plan的开发者觉得:缓存命中是按量付费才该操心的事,我按次计费,省不省钱关我什么事?

这个想法会让你浪费掉套餐的一大半价值。

不管是按次计费的Coding Plan还是按量计费的Token Plan,缓存命中都能直接提升你的套餐使用率。区别只是:前者让你每次调用能处理更复杂的任务,后者让你同样的预算能跑更多的请求。

这篇不讲代码、不讲API字段,只讲三件事:套餐怎么选、缓存怎么让套餐更值钱、选型时问自己哪三个问题。

一、两类套餐到底有什么区别 目前API平台的套餐分两大类,计费逻辑完全不同:

Coding Plan(按次计费)

计费单位是调用次数,固定月费包含固定次数。每次调用独立计费,不管传了多少Token,都只扣1次。

适合AI编程(Cursor、Claude Code)、批量任务、固定上下文查询等场景。痛点在于次数有限,希望每次调用能处理尽可能复杂的任务。

Token Plan(按量计费)

计费单位是Token,按实际消耗量扣费。用多少扣多少,成本与Token消耗量直接挂钩。

适合高频对话、长文档分析、RAG应用等场景。痛点在于预算固定,额度用完即止,希望同样的钱能处理更多请求。

两类用户都需要关注缓存,只是诉求不同。

二、Coding Plan用户:缓存让每次调用能处理更大的任务 买了Coding Plan最常见的浪费是:拿它当普通对话用——每次只问一个简单问题,传几百个Token,得到一个短回答。一次调用只干了几分钱的活,但扣掉的是一整次额度。

更合理的用法是:一次调用处理一整份合同、一个代码仓库、一篇长文档。这样每次调用的价值才够高。

缓存怎么帮你?

假设你是做合同审查的,每次审查都要先上传一份10万Token的公司标准合同范本作为固定背景,然后针对具体条款提问。

没有缓存时:每次调用模型都要重新处理这10万Token的范本。虽然按次计费不收Token费,但超长上下文会导致响应变慢,甚至超时。你的套餐调用次数,可能有相当一部分因为超时而浪费。

命中缓存后:把10万Token的固定范本放在Prompt最前面,系统缓存命中。模型不需要重新处理范本,直接基于缓存回答新问题。响应速度从10-20秒降到3-5秒,每次调用都能稳定处理10万Token级别的任务。

一句话:Coding Plan加缓存,等于用一次调用的额度,办原本需要海量Token才能办的事。

三、Token Plan用户:缓存让固定预算能跑更多请求 买了Token Plan最直观的痛点是额度消耗太快。每月看着固定的预算额度,但如果每次请求都要传几万Token的固定文档,实际跑下来的请求量可能远低于预期。

缓存怎么帮你?

假设你的业务需要每次请求都附带一份2万Token的背景文档作为回答依据。

没有缓存时:每次请求这2万Token都按全价计费。如果你的套餐预算是固定的,能支撑的请求量很快就会触顶。

命中缓存后:把背景文档放在Prompt最前面,系统缓存命中。这2万Token按缓存折扣价计费,通常是全价的1/3到1/10。同样的月度预算,能支撑的请求量可能翻几倍。

一句话:Token Plan加缓存,同样的预算,能跑的业务量完全不是一个量级。

四、插一句:部分平台还有一层"语义缓存" 前面说的缓存逻辑都是基于"前缀完全一致"的精确匹配,你需要自己控制 Prompt 结构来触发。

但部分平台(如 OpenStarry)在这个基础上还额外做了一层语义缓存——它不看字符串是否完全一样,而是判断问题的意思是否相近。

举个例子:

"怎么退货?"

"退货流程是什么?"

"我要退货,怎么操作?"

这三个问题写法不同,精确缓存无法命中。但语义缓存能识别出它们问的是同一件事,直接复用之前的答案。

这对你意味着什么?

你不需要多做什么,平台会自动处理。它的实际价值是:在用户问法多样、你没办法完全控制Prompt格式的场景下,多一层兜底,让你的套餐次数或额度用得更充分。

五、选套餐前问自己三个问题 看完上面的分析,选套餐时可以问自己三个问题:

第一问:我的任务有没有大量重复的固定上下文?

有(固定系统角色、公司政策文档、代码仓库说明)→ 你是缓存红利的最大受益者。如果任务复杂度高、调用量适中,Coding Plan更划算;如果调用量很大、需要弹性,Token Plan更合适。

没有 → 缓存帮不上大忙,根据业务量直接估算选择。

第二问:我更在意成本可预测还是极致弹性?

要固定月费、不怕突发流量 → Coding Plan,账单就是固定的。

要用多少付多少、预算可控 → Token Plan,但需要监控消耗。

第三问:我是否需要灵活切换不同厂商的模型?

需要跨模型切换 → Coding Plan通常可跨模型使用,一个套餐调多个厂商。

只用特定厂商的高端模型 → Token Plan通常是厂商专属,注意确认套餐支持的模型范围。

六、让套餐更值钱的基本操作 不写代码,只说习惯。

第一步:固定内容放最前面,变化内容放最后面。

这是最重要的一步,没有之一。缓存匹配看的是请求前缀,前缀完全一样,后面再怎么变都不影响命中。

写Prompt时养成习惯:系统角色、固定文档、知识库这些不变的内容永远放在开头;用户的问题、本次请求的特殊指令永远放在末尾。

第二步:确认固定前缀够长。

OpenAI要求固定前缀至少1024 Token才会进入缓存。DeepSeek和通义千问没有硬性门槛,但固定部分太短也建议扩充。

如果固定内容不够长,可以把更多背景知识、历史摘要沉淀到固定区,或者换用没有1024门槛的模型。

第三步:定期看一眼缓存命中率。

缓存命中率是衡量你套餐用得值不值的关键指标。如果命中率持续偏低,说明固定前缀里可能混进了动态内容,检查一下。

七、说几句实在的 缓存不是什么高级技巧,就是个习惯问题。

很多团队的情况是:上线时想起来加缓存,后面改Prompt随手一改,缓存就废了,也没人发现。直到月底看到账单才惊呼怎么这么贵。

把"缓存友好"当成写Prompt的基本习惯:

固定内容永远放最前面

变化内容永远放最后面

每次改Prompt时,确认固定前缀没被破坏

每周看一眼命中率

对于10万Token的文档分析或者仓库级AI编程,缓存能让你的套餐使用率翻几倍。这不是省点零花钱,是直接决定同样的预算,你的业务能跑多大的量。

选对套餐,写对Prompt,每次调用都不浪费。

修订依据(2026-08):OpenAI Prompt Caching定价、DeepSeek API Docs、OpenStarry最新套餐定价。各厂商政策调整快,落地前请复核官方发布。

以 AI 之力,筑未来之境

现在注册,立即免费获赠 200 次大模型调用权益

免费注册 →