适用场景:| | 长上下文任务 适用模型: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最新套餐定价。各厂商政策调整快,落地前请复核官方发布。