[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fwz7vup7M8wGiQbuERmMxlqyx6ax5OsyBVRc5k_w7kyo":3},{"item":4,"related":51},{"id":5,"type":6,"title":7,"slug":8,"summary":9,"body":10,"coverUrl":11,"productScreenshots":12,"productLinks":13,"authorName":14,"authorUrl":15,"authorSubject":16,"category":17,"tags":22,"sourceLabel":39,"sourceName":40,"sourceUrl":41,"status":42,"seoTitle":43,"seoDescription":44,"canonicalUrl":45,"isFeatured":46,"sno":47,"sortOrder":48,"publishedAt":49,"updatedAt":50,"createdAt":50},"5ef7ce44-0678-40b4-95e0-af4fe8a6b0a7","article","提示词也能缓存：固定前缀为什么能省钱提速？","prompt-caching-prefix-kv-cache","Prompt caching 缓存的不是旧答案，而是模型处理重复提示词前缀时产生的中间状态。本文解释它与语义缓存的区别、为什么顺序会影响命中、如何整理 Agent 上下文，以及多租户场景中的隔离风险。","很多 AI 应用会反复发送同一批内容：系统指令、工具定义、产品文档、代码仓库摘要、对话历史。虽然每次请求的最后一句问题不同，但前面可能有几万 token 完全一样。\n\n如果模型每次都从头计算这些重复前缀，延迟和成本都会被重复放大。Prompt caching 的思路是：已经计算过的前缀可以暂存，下一个请求命中时直接复用中间状态。\n\n## 先给结论：Prompt caching 缓存的是计算，不是答案\n\n它和常见的语义缓存不是一回事。\n\n- **语义缓存**：两个问题意思相近，就尝试复用旧答案。\n- **Prompt caching**：两个请求前缀完全相同，就复用模型处理输入时产生的中间计算结果。\n\n因此，Prompt caching 不会让模型把旧答案直接发给用户。它仍然会读取新问题并生成新答案，只是跳过一部分已经完成的输入计算。\n\n在开源推理框架 vLLM 中，这种机制通常叫 prefix caching：系统把共享前缀对应的 KV Cache 分块保存，并在后续请求中复用。[vLLM Automatic Prefix Caching](https:\u002F\u002Fdocs.vllm.ai\u002Fen\u002Flatest\u002Fdesign\u002Fprefix_caching\u002F)\n\n## 为什么“顺序”比“内容”更重要\n\n模型看到的输入不是一个无序资料库，而是一串 token。缓存通常匹配的是从开头开始的连续前缀：前面有一个字符、工具定义或消息顺序不同，后面的缓存就可能无法继续复用。\n\n可以把 Prompt 想成：\n\n~~~text\n[稳定系统指令]\n+ [稳定工具定义]\n+ [稳定项目资料]\n+ [变化的对话历史]\n+ [变化的用户问题]\n~~~\n\n如果把用户问题插到最前面，整个后续前缀都会失去复用机会；如果把稳定内容集中放在前面，变化内容放在后面，命中概率就更高。\n\n这也是为什么 Agent 的工具列表、系统指令和文件摘要不应该每轮随机排序。即使模型逻辑上认为两个列表等价，缓存系统看到的 token 序列也可能完全不同。\n\n## 一次请求怎样命中缓存\n\n简化后的过程是：\n\n~~~mermaid\nflowchart LR\n    A[请求前缀] --> B{是否有相同缓存块?}\n    B -->|是| C[复用 KV Cache]\n    B -->|否| D[计算并写入缓存]\n    C --> E[处理新增 token]\n    D --> E\n    E --> F[生成回答]\n~~~\n\n缓存并不是把原文简单放到 Redis 里。推理引擎保存的是模型针对前缀计算出的中间状态，因此它和具体模型、tokenizer、推理实现及缓存布局有关。更换模型、改变关键参数或改变前缀内容，都可能让旧缓存失效。\n\n## 最有效的工程整理方式\n\n### 把稳定内容前置\n\n系统说明、工具 schema、固定示例和项目级规则应尽量放在前面。用户问题、当前时间、随机追踪 ID 等动态内容放后面。\n\n### 保持序列化稳定\n\n工具定义、JSON 字段和枚举值要稳定排序。不要因为一次请求的业务数据不同，就重新生成一份字段顺序随机的 schema。\n\n### 把高频变化拆出上下文\n\n如果每次只需要少量状态，不要把完整数据库快照都拼进前缀。可以先检索、再把当前真正需要的片段放在变化区域。\n\n### 观察命中率而不是猜\n\n至少记录：输入 token 数、缓存命中 token 数、前处理延迟、总延迟和缓存写入次数。账单下降但缓存命中率很低，可能只是请求量下降；延迟变快但输出变差，则可能是上下文整理时误删了重要信息。\n\n## TTL 会改变收益模型\n\n缓存不是永久存在。不同服务可能采用不同的缓存生命周期、最小前缀长度、显式断点和定价规则。OpenAI 的早期 Prompt Caching 说明采用了自动匹配公共前缀的方式，并在响应中返回命中的 token 数；Anthropic 的 API 文档则同时提供自动缓存和显式断点等选择。[OpenAI Prompt Caching](https:\u002F\u002Fopenai.com\u002Findex\u002Fapi-prompt-caching\u002F)、[Anthropic Prompt Caching](https:\u002F\u002Fplatform.claude.com\u002Fdocs\u002Fen\u002Fbuild-with-claude\u002Fprompt-caching)\n\n工程上不要把某个平台的具体 TTL 或折扣写死成架构假设。真正应该稳定的是“公共前缀尽量稳定、缓存命中可以观测、未命中也能正常工作”。\n\n## 多租户场景要注意缓存隔离\n\n如果不同用户共享一个推理服务，缓存命中机制可能引入侧信道：攻击者可以通过响应时间或命中行为推测某些前缀是否曾经出现。vLLM 的安全文档就专门讨论了多租户 Prefix Cache 的隔离问题，并提供了通过 cache salt 进行隔离的方式。[vLLM 安全说明](https:\u002F\u002Fgithub.com\u002Fvllm-project\u002Fvllm\u002Fblob\u002Fmain\u002Fdocs\u002Fusage\u002Fsecurity.md)\n\n缓存设计至少需要回答三个问题：\n\n1. 哪些前缀可以跨用户共享？\n2. 哪些内容必须按租户或用户隔离？\n3. 缓存失效和清理是否有明确策略？\n\n不要因为“缓存里没有原文答案”就忽略隐私。中间状态仍然可能承载输入信息，缓存键和命中信号也可能暴露业务行为。\n\n## 什么时候值得做\n\nPrompt caching 最适合长上下文、重复工具定义、代码 Agent、长对话和批量文档处理。如果每个请求都很短、前缀高度随机，缓存命中带来的收益就有限。\n\n一句话总结：**Prompt caching 的第一优化目标不是“让模型记住答案”，而是让请求保持一段足够长、足够稳定的共同前缀。**\n\n## 来源\n\n- [vLLM：Automatic Prefix Caching](https:\u002F\u002Fdocs.vllm.ai\u002Fen\u002Flatest\u002Fdesign\u002Fprefix_caching\u002F)\n- [OpenAI：Prompt Caching in the API](https:\u002F\u002Fopenai.com\u002Findex\u002Fapi-prompt-caching\u002F)\n- [Anthropic：Prompt caching](https:\u002F\u002Fplatform.claude.com\u002Fdocs\u002Fen\u002Fbuild-with-claude\u002Fprompt-caching)","\u002Fuploads\u002F2026-09-08\u002F182822f9-05a3-4d2b-8766-bc5daf93effd.jpg",[],[],"Foundit","https:\u002F\u002Ffoundit.cn","foundit-ai-editorial",{"id":18,"name":19,"slug":20,"description":21},"6179d3b6-dc34-4483-9ded-3cd9f1b37a47","科普","abbreviation","介绍各领域新兴概念",[23,27,31,35],{"id":24,"name":25,"slug":26},"88d2bc27-0e0f-468a-b907-2991cb97b87b","人工智能","ai",{"id":28,"name":29,"slug":30},"a2ccffe0-49b2-458b-baf6-a83a1b20443d","大语言模型","llm",{"id":32,"name":33,"slug":34},"a202d639-99a6-488a-a712-4d4c6ffd7e15","开发","dev",{"id":36,"name":37,"slug":38},"7c76bfc2-f80f-4ee0-a95d-27bd8708b434","技术","slug","vLLM 与模型平台官方文档","vLLM：Automatic Prefix Caching","https:\u002F\u002Fdocs.vllm.ai\u002Fen\u002Flatest\u002Fdesign\u002Fprefix_caching\u002F","published","Prompt Caching 详解：如何用固定前缀减少大模型延迟和成本","解释 Prompt caching、Prefix caching 与语义缓存的区别，说明前缀顺序、TTL、命中率和多租户隔离如何影响 AI 应用性能。",null,false,42,0,"2026-09-08T00:00:00.000Z","2026-09-08T03:19:26.522Z",[52,62,70],{"id":53,"type":6,"title":54,"slug":55,"summary":56,"coverUrl":57,"authorName":58,"sno":59,"publishedAt":60,"createdAt":61},"0e2211d6-a9cc-4151-aec3-ea60ef2575f2","本地大模型部署：用 Ollama 与 llama.cpp 把模型搬进你自己的机器","local-llm-deployment-ollama-llama-cpp","数据敏感、要离线、想省 API 账单？本地部署值得了解。","https:\u002F\u002Foxqtewbrpuiouqqjrvdv.supabase.co\u002Fstorage\u002Fv1\u002Fobject\u002Fpublic\u002Fpublic-media\u002F2026-07-20\u002Fbf471546-ff4c-4fee-a01c-8a41157e5a8c.jpg","Foundit AI",76,"2026-07-19T00:00:00.000Z","2026-07-20T01:11:41.120Z",{"id":63,"type":6,"title":64,"slug":65,"summary":66,"coverUrl":67,"authorName":14,"sno":68,"publishedAt":49,"createdAt":69},"7f7b281e-b9d6-406f-8d79-9dfb33145f5e","WebTransport：为什么实时 AI 应用不一定应该使用 WebSocket？","webtransport-realtime-ai-apps","WebSocket 适合通用双向消息，但复杂实时 AI 应用还可能需要可靠流、双向流和可以丢弃的临时数据。本文解释 WebTransport 的 session、stream 和 datagram，比较它与 SSE、WebSocket、WebRTC 的边界，并讨论鉴权与部署。","\u002Fuploads\u002F2026-09-08\u002F2247cab5-87b7-4b92-8871-e6adac14dc47.jpg",44,"2026-09-08T03:19:19.069Z",{"id":71,"type":6,"title":72,"slug":73,"summary":74,"coverUrl":75,"authorName":14,"sno":76,"publishedAt":77,"createdAt":78},"0c00fd8d-379a-4c58-a542-460bb3575b72","MCP Apps：让 AI 对话里的工具带上交互界面","mcp-apps-interactive-tool-ui","MCP Apps 通过 ui:\u002F\u002F 资源、工具元数据和沙箱 iframe，让 MCP 服务器可以向宿主提供交互式 HTML 界面。本文解释工具与 UI 的关联、权限边界、文本回退和安全模型。","\u002Fuploads\u002F2026-09-12\u002F9e795ab0-aa98-480f-ad6d-a2013530b302.jpg",48,"2026-09-12T00:00:00.000Z","2026-09-12T03:56:44.551Z"]