以下是我们系统梳理过的大语言模型上下文缓存命中率测试全场景清单,按测试目的分为六大类,每个场景包含目的、方法与预期行为。
场景分类规则
| 类别 | 核心测试目标 | 关键逻辑 |
|---|---|---|
| 一、基础功能验证 | 确认缓存是否启用、是否遵循标准前缀匹配 | 阳性/阴性对照,核心模式 |
| 二、隔离与安全 | 验证缓存边界,防止跨会话/租户污染 | 强制前缀唯一性 |
| 三、参数与结构 | 确认非消息体参数、请求格式对缓存的影响 | 控制变量法 |
| 四、容量与稳定性 | 探测缓存的生命周期、容量上限、并发行为 | 压力、时间、并发维度 |
| 五、边界与异常 | 极端输入、不规范请求、特殊字符的鲁棒性 | 边界值测试 |
| 六、会话动态与高级行为 | 真实多轮对话、中途变更、多模态等复杂场景 | 动态行为模拟 |
一、基础功能验证(6 个场景)
1. identical(完全相同的请求)
- 目的:阳性对照。验证最基本的缓存读写功能。
- 方法 :连续发送两次完全一致的请求(
messages及所有参数相同),重复多轮。 - 预期 :第二次及后续请求的
cached_tokens接近prompt_tokens,命中率 > 95%,且稳定。 - 失败含义:若此场景不通过,说明缓存功能未启用或核心机制故障,无需继续其他测试。
2. same_prefix_diff_suffix(相同系统提示词 + 不同用户问题)
- 目的:验证生产环境核心模式------固定长前缀 + 动态短后缀。
- 方法 :构造约 1500 token 的固定
system消息,连续发送 10 次请求,每次user消息不同。 - 预期 :
cached_tokens应稳定等于system消息的 token 数(仅新增用户问题不命中),命中率 > 95%。 - 失败含义:若不稳定或命中率低,无法实现成本节省。
3. multi_turn(增量式多轮对话)
- 目的:验证对话历史逐轮累积时的缓存增量行为。
- 方法:模拟多轮对话,从第 1 轮开始逐步追加用户问题与助手回复,发送第 N 轮请求时测量缓存命中量。
- 预期 :随着轮次增长,
cached_tokens逐步增加,每一轮新增缓存量约等于上一轮的响应长度;历史消息几乎全部命中。 - 失败含义:若多轮后命中率不增或波动,聊天应用成本将随对话增长线性上升。
4. prefix_truncation(前缀截取)
- 目的:验证更短前缀能否复用更长前缀的缓存。
- 方法 :先发送长前缀请求,再发送其前半段作为
system消息的请求(完全子序列)。 - 预期:第二次请求的所有 token 都应命中缓存,命中率 ≈ 100%。
- 失败含义:若只命中部分,说明缓存匹配粒度非完整前缀,可能有固定长度或阈值限制。
5. partial_overlap(部分重叠前缀)
- 目的:验证仅前 N 个 token 共享时,共享部分是否被复用,分叉后不命中。
- 方法:发送前缀 A(共享部分 + 后缀 A),再发送前缀 B(相同共享部分 + 后缀 B)。共享部分长度 > 最低阈值(如 500 token)。
- 预期 :
cached_tokens精确等于共享部分的 token 数,分叉部分不命中。 - 失败含义:若全量命中或不命中,说明缓存匹配逻辑非标准(可能按请求级去重或长度匹配)。
6. empty_prefix(空前缀测试)
- 目的:探测系统消息为空时的缓存行为及最小有效前缀长度。
- 方法 :设置
system为空字符串或缺失,重复发送相同请求。 - 预期 :不应报错;若服务有最小阈值,
cached_tokens可为 0,但不应出现异常。 - 失败含义:报错则健壮性不足;若命中,说明存在非前缀的其他缓存机制。
二、隔离与安全(4 个场景)
7. different_system(完全不同的系统提示词)
- 目的:阴性对照。验证不同前缀之间绝不发生缓存命中。
- 方法 :构造两个从第一个 token 就完全不同的
system消息(使用不同 UUID 开头),交替发送。 - 预期 :所有迭代中
cached_tokens必须为 0。 - 失败含义:若命中,说明缓存键未严格基于前缀内容,存在跨会话污染风险。
8. isolated_sessions(会话隔离)
- 目的:验证不同会话(不同前缀流)的缓存互不干扰且不被淘汰。
- 方法:使用前缀 A 建立缓存,再用完全不相关的前缀 B 发送请求,再切回前缀 A,观察 A 是否仍命中。
- 预期:前缀 B 不命中 A 的缓存,且 A 的缓存未被冲掉。
- 失败含义:若不隔离,多租户/多任务场景将互相污染或频繁淘汰。
9. cross_api_key(跨 API Key 隔离)
- 目的:验证不同租户(API Key)之间的缓存隔离。
- 方法:使用 API Key1 发送前缀 P 建立缓存,用 API Key2 发送相同前缀 P。
- 预期 :API Key2 的
cached_tokens应为 0。 - 失败含义:租户间缓存共享,可能造成计费串扰和信息泄露。
10. dynamic_content_in_prefix(动态信息污染)
- 目的:验证固定前缀中混入动态内容(时间戳、随机数)是否会错误命中或污染缓存。
- 方法 :在静态前缀中嵌入
{timestamp}或随机 UUID,与纯静态前缀交替发送。 - 预期:带动态内容的前缀每次都不命中(因前缀变化),且不会污染纯静态前缀的缓存。
- 失败含义:若带动态内容的请求命中了静态前缀的缓存,说明缓存匹配过于宽松,存在上下文错误复用风险。
三、参数与结构(5 个场景)
11. identical_with_body_variation(参数无关性)
- 目的 :验证
max_tokens、temperature等参数变化时,相同messages是否仍命中缓存。 - 方法 :发送相同
messages,但分别使用不同max_tokens值。 - 预期 :应命中缓存,
cached_tokens与首次请求的prompt_tokens一致。 - 失败含义:说明缓存键包含了非消息体参数,客户端必须确保所有参数完全一致。
12. streaming_vs_non_streaming(流式与非流式)
- 目的 :验证
stream=True/False是否影响缓存命中。 - 方法 :先用
stream=False建立缓存,再用stream=True发相同前缀;反之亦然。 - 预期:两种模式应共享缓存,命中率一致。
- 失败含义:若不能互命中,需统一应用层调用方式。
13. role_order_variation(消息角色顺序变化)
- 目的 :验证
messages中 role 顺序(如system+uservsuser+system)是否视为不同前缀。 - 方法:发送相同文本但 role 排列不同的两个请求。
- 预期:应视为不同前缀,不命中缓存。
- 失败含义:若命中,缓存键生成逻辑可能忽略了 role 信息,导致上下文错乱。
14. model_switch(模型切换)
- 目的:验证不同模型之间缓存是否隔离。
- 方法:用模型 A 建立缓存,再用模型 B 发送相同前缀。
- 预期:模型 B 不应命中缓存。
- 失败含义:若跨模型共享,缓存键未包含模型维度,可能导致成本归属错误。
15. cache_key_with_http_headers(自定义 HTTP 头影响)
- 目的:验证自定义 HTTP 头是否被纳入缓存键。
- 方法 :相同请求体,分别带不同自定义头(如
X-Client-Version)发送。 - 预期:通常不应影响缓存命中。
- 失败含义:若影响,则客户端需要固定所有自定义头。
四、容量与稳定性(5 个场景)
16. cache_ttl(缓存生存时间)
- 目的:测定缓存从创建到失效的时间窗口。
- 方法:建立缓存后,分别间隔 0.5s、1s、2s、4s、8s... 发送相同前缀请求,直到不再命中。
- 预期:命中率在某时间点后突降为 0,得出 TTL 边界。
- 失败含义:若 TTL 过短(< 5 分钟),生产环境中用户稍作停顿即缓存全失,无法有效节约成本。
17. cache_capacity_and_eviction(缓存容量与淘汰策略)
- 目的:测定缓存池能容纳多少个不同前缀,以及淘汰规则(LRU/FIFO)。
- 方法:连续发送 N 个不同前缀(长度相同),再重发第一个前缀,观察是否命中。逐步增加 N。
- 预期:超过容量后最早的前缀不再命中;可测出最大缓存条目数。
- 失败含义:容量过小或淘汰策略不合理,高并发下命中率会骤降。
18. interleaved_prefixes(交替前缀稳定性)
- 目的:验证多个活跃前缀交替使用时,各自的缓存能否稳定共存而不被意外淘汰。
- 方法:交替发送前缀 A 和 B(A1→B1→A2→B2→A3→B3...),检查每次 A 请求是否命中 A,B 命中 B。
- 预期:只要总容量足够,两类请求均保持高命中率,无交叉淘汰。
- 失败含义:容量不足或淘汰策略过于激进,导致频繁切换任务时缓存无效。
19. rapid_fire_identical(极速重复请求)
- 目的:检测极短时间内重复相同请求时,是否存在缓存写入竞态导致命中率抖动。
- 方法:在 100ms 内连续发送 10 次完全相同请求。
- 预期:除第一次外,其余应全部命中,无 0% 抖动。
- 失败含义:若出现间歇性未命中,说明缓存写入异步或存在并发锁竞争。
20. concurrent_same_prefix(并发请求相同前缀)
- 目的:验证多个并发请求读取同一缓存前缀时的稳定性和一致性。
- 方法 :先建立缓存,然后同时发起 20 个并发请求(相同前缀,不同
user问题)。 - 预期:所有请求都命中缓存,且延迟明显低于首次。
- 失败含义:若部分未命中或延迟增加,缓存并发读能力不足。
五、边界与异常(4 个场景)
21. very_large_prefix(极大前缀)
- 目的:测试超长前缀(如 10 万 token)是否能被缓存,有无长度上限。
- 方法 :构造 10 万 token 的前缀,发送两次,第二次仅改
user问题。 - 预期:应命中大部分 token(如 > 90%)。
- 失败含义:若完全不命中或命中极少,存在最大缓存长度限制,长文档场景无法受益。
22. very_short_prefix(极短前缀)
- 目的:探测缓存生效的最小 token 阈值。
- 方法:使用仅几个 token 的前缀(如一个汉字),重复发送相同请求。
- 预期 :可能因低于阈值而
cached_tokens=0,但不报错;若命中则记录最小有效长度。 - 失败含义:无标准对错,主要用于了解服务限制。
23. malformed_messages(异常消息结构)
- 目的 :验证不规范的消息数组(如连续两条
user、system为空)是否导致缓存崩溃或污染。 - 方法:故意发送不符合最佳实践的消息序列。
- 预期:服务不应崩溃,缓存应将其视为独立前缀(不命中既有缓存)。
- 失败含义:崩溃或返回错误缓存值,表明健壮性不足。
24. unicode_boundary(多字节字符边界)
- 目的:验证 emoji、组合字符、从右向左文字等特殊 Unicode 是否影响 token 化及缓存匹配。
- 方法:前缀中使用 😀、é、阿拉伯文等,进行严格相同和微小差异(去组合符)的对比测试。
- 预期:完全相同的前缀能命中,有差异的不命中。
- 失败含义:若因多字节字符导致错误命中或漏命中,说明 tokenizer 与缓存键生成存在缺陷。
六、会话动态与高级行为(5 个场景)
25. mid_conversation_system_change(长对话中途切换 system prompt)
- 目的:验证多轮对话中突然修改系统指令后的缓存行为。
- 方法 :进行多轮对话后,在保持历史不变的情况下修改
system消息内容,继续发送后续请求。 - 预期:历史消息部分仍应命中缓存(因未变),系统指令部分不应命中(已变)。
- 失败含义:若历史缓存也被清空,说明系统指令变更导致整个缓存失效,影响中途任务切换。
26. cache_hit_continuity(命中率连续性/长稳测试)
- 目的:检验长时间、大量请求下命中率是否保持稳定。
- 方法:连续发送 100~1000 次相同前缀不同后缀的请求,记录每次命中率并观察时间序列。
- 预期:命中率始终 > 95%,无明显下降趋势或周期性抖动。
- 失败含义:若逐渐下降,可能存在内存泄漏或缓存碎片化问题。
27. error_recovery(错误恢复/重启测试)
- 目的:模拟服务端重启后缓存丢失的恢复行为。
- 方法:(若可配合)重启服务后立即用相同前缀发送请求,再发第二次。
- 预期:第一次不命中(缓存已清空),第二次应立即重建并命中。
- 失败含义:若重启后长时间无法重建缓存,或报错,需要应用层重试机制。
28. multimodal_image(多模态图片请求)
- 目的:验证包含图片的请求体是否支持缓存,以及缓存粒度。
- 方法:使用相同图片(base64)和文本前缀,连续发送两次,第二次仅改文本问题。
- 预期:若服务支持多模态缓存,文本部分可命中;若不支持,可能整个请求不被缓存。
- 失败含义:多模态应用无法获得成本优化,需确认服务能力边界。
29. special_characters_and_json(特殊字符与 JSON 结构)
- 目的:验证系统提示中包含 JSON 字符串、转义符等结构化内容时缓存行为是否正常。
- 方法:构造 system 消息为 JSON 对象或包含大量转义引号的字符串,重复发送。
- 预期:完全相同的前缀能命中,不应因转义处理导致误判。
- 失败含义:若命中失败,说明服务端可能在序列化/反序列化时改变了缓存键计算。
未纳入但可选的拓展场景
- prefix_sweep(前缀长度扫描):作为工具辅助功能,不属于单一测试场景,通常并入边界测试。
- cost_calculation_integrity(成本核算一致性) :验证
cached_tokens是否真实反映计费折扣,可在基础场景中附带检查。
以上共 29 个场景 ,覆盖了功能正确性、隔离性、稳定性、边界鲁棒性、动态行为等维度,构成一套面向生产环境的完整缓存命中率评估体系。这 29 个场景并非对所有 LLM 都完全适用 ,但它们构成了一个以"前缀缓存"为假设前提的通用评估框架 。是否适用,取决于被测 LLM 服务是否实现了标准的、基于请求前缀的上下文缓存 ,并且是否通过 API 暴露了可观测的缓存命中指标。下面我详细拆解这个逻辑链。
一、核心逻辑链:从"功能存在"到"场景适用"
[假设] LLM 服务具备前缀缓存功能
↓
[前提 1] 缓存机制是"基于请求前缀的 KV Cache 复用"
[前提 2] 服务端通过 API 返回了缓存命中量(如 cached_tokens)
[前提 3] 该指标真实反映物理缓存命中,而非注入常量
↓
[判断] 若满足以上前提 → 29 个场景几乎全部适用
[判断] 若部分满足 → 需裁剪场景,并改用间接测量手段
[判断] 若完全不满足 → 核心场景失效,只能做最基础的请求去重测试
二、场景的前置依赖分析
我将 29 个场景按其对服务端实现的前提依赖分为三个层级:
层级 1:强依赖"标准前缀缓存 + cached_tokens 字段"(15 个场景)
这些场景直接依赖于 服务端实现前缀缓存,并且 API 返回的 cached_tokens 字段能精确反映命中的 token 数量。
| 场景 | 核心依赖 |
|---|---|
| identical | cached_tokens 字段存在且可信 |
| same_prefix_diff_suffix | 同上 + 前缀匹配粒度精确到 token |
| multi_turn | 同上 + 支持历史消息增量缓存 |
| prefix_truncation | 同上 + 支持子前缀复用 |
| partial_overlap | 同上 + 精确到共享前缀边界 |
| different_system | 同上 + 缓存隔离 |
| isolated_sessions | 同上 + 会话级缓存隔离 |
| cross_api_key | 同上 + 租户隔离 |
| dynamic_content_in_prefix | 同上 + 精确前缀匹配 |
| cache_ttl | 同上 + 需要 cached_tokens 判断存活 |
| cache_capacity_and_eviction | 同上 + 需要定量测量缓存数量 |
| interleaved_prefixes | 同上 + 需要定量测量多前缀共存 |
| cache_hit_continuity | 同上 + 需要长时间稳定测量 |
| prefix_sweep | 同上 + 需要定量测量命中率随长度变化 |
| error_recovery | 同上 + 需要观察重启前后 cached_tokens 变化 |
若服务端不支持标准前缀缓存,或 cached_tokens 字段缺失/不可信,这 15 个场景将完全无法执行或结果无意义。
层级 2:中度依赖"缓存能力 + 可观测行为"(10 个场景)
这些场景不强制要求 cached_tokens 字段绝对精确 ,但需要服务端具备某种缓存能力,并能通过延迟变化、响应 ID 对比、或业务逻辑推断来间接判断。
| 场景 | 替代测量手段 |
|---|---|
| identical_with_body_variation | 可通过延迟降低或响应 ID 重复来判断缓存 |
| streaming_vs_non_streaming | 同上 |
| role_order_variation | 延迟对比 + 响应内容一致性 |
| model_switch | 延迟对比 |
| cache_key_with_http_headers | 延迟对比 |
| rapid_fire_identical | 延迟对比 + 响应 ID |
| concurrent_same_prefix | 延迟对比 + 响应 ID |
| very_large_prefix | 可通过是否报错、延迟趋势推断 |
| malformed_messages | 仅需观察是否报错或崩溃 |
| unicode_boundary | 可通过延迟和响应一致性判断 |
若服务端有缓存但未暴露 cached_tokens,这 10 个场景仍可执行,但结论的精确度会下降,从"定量评估"退化为"定性推断"。
层级 3:弱依赖"服务协议兼容性"(4 个场景)
这些场景几乎不依赖缓存实现细节,只要求被测服务兼容 OpenAI Chat Completions 协议即可运行。
| 场景 | 依赖 |
|---|---|
| empty_prefix | 仅需 API 接受空 system 消息 |
| very_short_prefix | 仅需 API 正常工作 |
| multimodal_image | 需要服务支持多模态输入(图片) |
| special_characters_and_json | 需要 API 正确解析 JSON 转义和 Unicode |
这四个场景主要用于测试 API 的健壮性和协议兼容性,而非缓存本身。它们对所有兼容 OpenAI 协议的 LLM 服务都适用。
三、不同 LLM 服务类型的适用性矩阵
| 服务类型 | 是否支持标准前缀缓存 | 适用场景范围 |
|---|---|---|
| DeepSeek 官方 API / vLLM/SGLang 自建服务(正确配置) | ✅ 是 | 29 个场景全部适用 |
部分第三方代理 (如之前测试的 suanyouyou.com) |
❌ 缓存非标准或字段不可信 | 只能执行层级 3 的 4 个场景 + 部分层级 2 场景(需依赖延迟) |
| OpenAI 官方 API(目前 GPT-4o 等已支持 Prompt Caching) | ✅ 是,但匹配粒度可能有差异 | 绝大部分适用,但需注意其缓存策略的独特规则(如对 system/user 顺序敏感) |
| Anthropic Claude API(支持 Prompt Caching) | ✅ 是,但实现机制不同(需显式标记缓存断点) | 核心思路可复用,但具体构造需适配 Anthropic 的 cache_control 字段 |
| 无缓存能力的基础 LLM 推理服务 | ❌ 无 | 仅层级 3 的 4 个协议兼容性场景可执行 |
| 云端无服务器推理(如 AWS Bedrock, Google Vertex AI) | 部分支持,且缓存行为不透明 | 取决于具体服务,通常无法获知 cached_tokens,需依赖延迟测量 |
四、结论与使用建议
核心结论 :这 29 个场景是以前缀缓存为测试目标的理想化全量评估体系 ,它们对所有正确实现了标准前缀缓存并暴露 cached_tokens 字段 的 LLM 服务适用。但对于其他类型服务,必须先做"缓存能力探测",再决定使用哪些场景。
实际操作流程:
- 先执行基础功能验证 中的
identical和different_system场景。 - 若
identical命中率 > 95% 且different_system命中率 = 0%,说明服务极大概率是标准前缀缓存,可以放心运行全量 29 个场景。 - 若
identical命中率中等(如 50%~80%)或different_system异常命中,说明缓存机制非标准,此时不应再直接使用cached_tokens数据,而应切换到层级 2 的间接测量场景,并转为"定性评估"。 - 若
identical命中率始终为 0%,说明服务无任何缓存,只保留层级 3 的协议兼容性场景即可。
这套逻辑能确保你不会用错工具,也避免了对一个"伪缓存"服务产生虚假的成本预期。