跳到主要内容

语义缓存:一次推理服务一千次提问

这一章讲三件事: 为什么「缓存」在 agent 时代突然变得如此划算(长尾分布); 一个语义缓存的完整构造——从基础版到四层增强;以及让它长期不腐化的填充与驱逐策略。 原书给它的定位:能把延迟和推理成本降 10–100 倍,同时保持准确1

1. 为什么现在需要它:长尾分布

看你应用的查询流量分布——大概率是「长尾」:少数查询占了大头流量(原书观察:单个热门查询 可以独占 20% 以上的全部流量),而 60–70% 的查询只被问过几次2

这决定了优化的正确姿势:抓住「头部」——原书的算术是 top 20% 的查询类型覆盖约 80% 的流量; 他顺手讽刺了一句:头部 agent 公司广告里吹的「成功处理 68% 的查询」,也不过如此3

那让 agent 自己处理一切行不行?原书算了一笔硬账:agent 每次都要为新查询「推理」 (规划用什么工具、怎么检索),这意味着多次 LLM 调用;单次调用就要 2–20+ 秒, 消费级应用等不起。可以穷尽各种手段压单次成本,但规模化之下「你总会无解」—— 除非上语义缓存(他还开了个玩笑:除非你有十亿美元的量子计算机,那大概是本书出版 5-10 年后的事)4

2. 语义缓存是什么:拦截规划,复用路径

普通缓存存「答案」;语义缓存存「solution path(解决路径)」——agent 为某类问题规划出的 工具调用方案。它蹲在查询入口,干一件事:拿新查询做向量搜索,如果命中缓存里某个查询 (相似度过阈值),直接复用它的解决路径,把 agent 的规划步骤整个跳过5

重要澄清(原书专门强调):语义缓存通常不消灭推理,只替代规划段。 回答仍要生成,但「该走哪条路」这个最贵的思考被复用了。特例也存在:FAQ 类静态内容 可以把现成答案整个存进缓存,零推理返回;甚至可以缓存调优过的 SQL,连检索都提速6

效果数字(原书引用 AWS、OpenAI、Intercom 的报告): 语义缓存加持的完整 agent, 响应 600 毫秒–2 秒;不加持的同类 agent 要 5–6 秒7

一笔更直观的账:设一次推理念 1 美元,某热门查询每天来 1000 次—— 无缓存:每天 1000 美元;有缓存:第一次 1 美元,之后全免。而且省的不止这一个查询: 所有与它相似度过阈值的变化说法都被覆盖——一次推理,服务一片查询8。 还有两条容易被忽略的收益:一致性(LLM 非确定,同一问题两次回答可能不同; 金融场景里「换个说法答案就变」是事故,缓存钉死同一解决路径)和可控性 (发现某个路径能答得更好,人工替换缓存里的方案即可,不动其他任何东西)9

3. 主走查:从基础版到四层增强

原书的代码实验室用 all-MiniLM-L6-v2(本地小模型)+ ChromaDB 搭了个语义缓存, 然后一步步打补丁。每一步都在治一种真实的病:

基础版(步骤 3)

SemanticCache 类:add(query, soln_path) 把「查询→解决路径」存入; search(query, threshold=0.75) 拿查询嵌入做相似搜索,分数 ≥ 0.75 才返回缓存的路径10

增强 1:实体遮蔽,治「缓存碎片化」

「AAPL 2023 年股价?」和「TSLA 2024 年股价?」应该走同一个工具——区别只是传参。 但字面不同就各自嵌入,缓存被无意义的变体撑爆。实体遮蔽(entity masking) 在嵌入前 把变量替换成占位符:AAPL/TSLA → [TICKER],2023/2024 → [YEAR]—— 两条查询坍缩成「What was [TICKER] stock price in [YEAR]?」,一条缓存通吃11

增强 2:交叉式的编码器(cross-encoder),治「假相似」

召回越好,误伤越多:「What's my balance?」和「What's my account number?」 在向量空间里很近,但意思完全不同——余额和账号答错了都是事故12

普通嵌入把两条查询各自独立编码;交叉编码器(cross-encoder)则, 交叉编码器把「候选查询+缓存查询」放在一起重读、按「是不是同一意图」打分。 流水线变成:向量粗筛(快,宽)→ 交叉编码器精验(慢,严),各取所长13

增强 3:自适应阈值,治「一刀切」

金融交易类查询,匹配阈值该调高——宁可放过,不可答错;探索性闲聊,阈值放低, 多命中几个无妨。阈值按查询类型动态调整,而不是全局一个数14

增强 4:自动回填,让缓存自学

未命中时调用兜底(完整的 agent 规划),拿到结果立刻写回缓存—— 「今天每一次未命中,都是明天的一次命中」。命中率随时间自动爬升15

未命中的分层兜底

自动回填背后是完整的分层架构,原书给了各层延迟16:

延迟干什么
key-value 精确查找50–60 毫秒字面完全一致的查询(营销邮件里预埋的查询可以人工保证字面一致,直落这层)
语义向量搜索100 毫秒–2 秒语义缓存主战场(本章代码实验室)
完整 agent 规划2–10 秒全新查询;规划结果回填缓存,不浪费

(原书还列了规则兜底路线,如 Rasa 的 Two-Stage Fallback:意图分类+置信度阈值决定何时转人工17。)

4. 填充:让缓存覆盖面涨上去

光等用户来喂太慢,要主动扩展缓存里的查询集合。原书列了四种生成策略18:

  • LLM 改写:「How do I invest in bonds?」→「What's the process for purchasing bonds?」等变体;
  • 回译: 查询译到另一种语言再译回来,得到结构自然变化的同义句; 原书观察到语言家族有性格:罗曼语系擅长风格变化,汉藏语系带来的多样性更高;
  • 同义词与缩写展开: 新手说「retirement savings」,顾问说「qualified plan allocations」——同一个意思的两副面孔;
  • 前置生成: 分析用户行为模式——搜「IRA 缴费上限」的人接着会问「补缴上限」——抢在被问之前把答案准备好。 书里的标杆是 Morgan Stanley:从 7000 条固定查询做到「有效回答任意问题」19

扩展前必查重,这是最容易踩的坑: 新变体若与已有查询相似度过阈值、且解决路径相同——别加, 纯冗余;若解决路径不同——必须加,否则用户会经由相似匹配走到错误的路径上。 这就是「缓存污染」的入口20

域约束是安全网。 金融里「Fed」=Federal Reserve、「munis」=municipal bonds 该合并; 但 EBITDA ≠ earnings(前者剔除了利息、税、折旧、摊销)、gross ≠ net、 已实现 ≠ 未实现收益——这些长得像的词绝不能互为同义词。手段:自动校验替换是否保意、 硬编码(即写死在程序里、不许变更)的禁并清单、专家复核21

5. 驱逐:让缓存不变臭

缓存会腐化:市场变了、法规改了,昨天的正确答案今天是毒药。四级策略,由简到繁22:

策略驱逐谁
TTL(按时间)过期的条目;「股价」类要短 TTL,「法国首都」类几乎永不过期
LRU + 语义衰减最久未用的,叠加「语义漂移」权重——语言和领域知识在变,老条目的语义相关性会衰减
按表现修剪高命中但低满意度的毒条目;信号:点赞点踩、查询立刻被重述、会话被放弃
语义聚类去重把语义空间(即所有向量所在的高维空间,意思越近位置越近)里扎堆的冗余条目合并,省资源、防不一致

最后一级提醒了语义缓存与传统缓存的本质区别:删一条不是腾地方,是要保住语义覆盖面 ——删错一条,几十个相关查询的命中都会塌23

6. 边界与局限

  • 阈值(0.75)是拍的默认值,真实系统要在自己的查询分布上校准——第 06 章的评测方法直接适用;
  • 书里的成本数字(600ms–2s 等)来自厂商报告,原书自己也说「数字天天在变,用你自己系统的数据」7;
  • 缓存与记忆的边界:语义缓存记住「常见问题怎么答」,不记住「这个用户经历过什么」——后者是第 12 章的主题24

7. 可带走的

  1. 长尾分布是前提:top 20% 查询 ≈ 80% 流量,缓存头部就赢了大半。
  2. 缓存 solution path,不是答案——规划被复用,生成照常走。
  3. 实体遮蔽防碎片:变量换占位符,一条缓存服务一族查询。
  4. 「余额 vs 账号」:向量近≠意图同,交叉编码器是必要的第一道精验。
  5. 扩展查询集先查重:同路径的冗余、异路径的必须加——否则污染缓存。
  6. EBITDA≠earnings:域禁并清单是金融类缓存的安全带。
  7. 驱逐是四级阶梯:TTL → LRU+语义衰减 → 按表现 → 聚类去重;毒条目的共性是「高命中低满意」。

8. 原文地图

主题原书章原文位置
10-100 倍目标Semantic Cachestext/88-fm-semantic-caches.txt:46(搜「10–100x」)
长尾模式与 20%/60-70%Semantic Cachestext/88-fm-semantic-caches.txt:99(搜「long-tail pattern」)
68% 讽刺与 top 20% 覆盖 80%Semantic Cachestext/88-fm-semantic-caches.txt:106(搜「68%」)
agent 推理成本 2-20+ 秒Semantic Cachestext/88-fm-semantic-caches.txt:109(搜「2–20+ seconds」)
量子计算机玩笑Semantic Cachestext/88-fm-semantic-caches.txt:109(搜「quantum computers」)
拦截器与 solution pathSemantic Cachestext/88-fm-semantic-caches.txt:127(搜「interceptor」)
不消灭推理只替代规划Semantic Cachestext/88-fm-semantic-caches.txt:133(搜「planning stage」)
静态内容零推理/缓存 SQLSemantic Cachestext/88-fm-semantic-caches.txt:136(搜「static」)
600ms-2s vs 5-6sSemantic Cachestext/88-fm-semantic-caches.txt:130(搜「600-millisecond」)
缓存组件三件套(来源/时间/质量分)Core components of semantic cachestext/89-fm-core-components-of-semantic-caches.txt:14(搜「Provenance information」) · text/89-fm-core-components-of-semantic-caches.txt:20(搜「0.95」)
Roth IRA 两问之辨The intelligence layer between the query and the responsetext/90-fm-the-intelligence-layer-between-the-query-and-the.txt:4(搜「Roth IRA tax benefits」)
1000 次/天的账与相似覆盖The intelligence layer between the query and the responsetext/90-fm-the-intelligence-layer-between-the-query-and-the.txt:16(搜「1,000 times a day」) · text/90-fm-the-intelligence-layer-between-the-query-and-the.txt:29(搜「above the similarity threshold」)
延迟 0.03-0.3sThe intelligence layer between the query and the responsetext/90-fm-the-intelligence-layer-between-the-query-and-the.txt:26(搜「0.03–0.3 seconds」)
一致性与非确定性The intelligence layer between the query and the responsetext/90-fm-the-intelligence-layer-between-the-query-and-the.txt:32(搜「not deterministic」)
未命中三层兜底与延迟The intelligence layer between the query and the responsetext/90-fm-the-intelligence-layer-between-the-query-and-the.txt:55(搜「50–60 milliseconds」) · text/90-fm-the-intelligence-layer-between-the-query-and-the.txt:61(搜「Full agent planning」)
Rasa Two-Stage FallbackThe intelligence layer between the query and the responsetext/90-fm-the-intelligence-layer-between-the-query-and-the.txt:71(搜「Two-Stage Fallback」)
基础缓存与 0.75 阈值Step 3 – basic semantic cachetext/93-fm-step-3-basic-semantic-cache.txt:4(搜「all-MiniLM-L6-v2」) · text/93-fm-step-3-basic-semantic-cache.txt:25(搜「threshold=0.75」)
实体遮蔽Step 4 – entity masking for better generalizationtext/94-fm-step-4-entity-masking-for-better-generalization.txt:1(搜「Entity masking」) · text/94-fm-step-4-entity-masking-for-better-generalization.txt:7(搜「TICKER」)
余额 vs 账号Step 5 – cross-encoder verificationtext/95-fm-step-5-cross-encoder-verification.txt:4(搜「balance」)
交叉编码器原理Step 5 – cross-encoder verificationtext/95-fm-step-5-cross-encoder-verification.txt:7(搜「cross-encoder」)
自适应阈值Step 6 – adaptive thresholdstext/96-fm-step-6-adaptive-thresholds.txt:4(搜「mission-critical」)
自动回填自学Step 7 – auto-population with fallbacktext/97-fm-step-7-auto-population-with-fallback.txt:4(搜「fallback」) · text/97-fm-step-7-auto-population-with-fallback.txt:7(搜「self-learning」)
四种扩展策略(改写/回译/同义词)LLM-based paraphrasing · Back-translation · Synonym and lexical expansiontext/99-fm-llm-based-paraphrasing.txt:4(搜「paraphrases」) · text/100-fm-back-translation-for-natural-variation.txt:4(搜「Back-translation」) · text/101-fm-synonym-and-lexical-expansion.txt:21(搜「retirement savings」)
前置生成与 Morgan StanleySynthetic query generationtext/102-fm-synthetic-query-generation.txt:4(搜「proactively」) · text/102-fm-synthetic-query-generation.txt:10(搜「Morgan Stanley」)
扩展先查重(同路径冗余/异路径必须加)Putting it all togethertext/98-fm-putting-it-all-together.txt:40(搜「well semantically represented」)
EBITDA 与域约束Domain-specific constraintstext/103-fm-domain-specific-constraints.txt:4(搜「EBITDA」) · text/103-fm-domain-specific-constraints.txt:7(搜「munis」)
TTLTime-based evictiontext/104-fm-time-based-eviction.txt:4(搜「time-to-live」)
LRU+语义衰减Least recently used with semantic decaytext/105-fm-least-recently-used-with-semantic-decay.txt:7(搜「semantic decay」)
按表现修剪与信号Performance-based pruningtext/106-fm-performance-based-pruning.txt:4(搜「poor user satisfaction」所在段,搜「high retrieval rates」) · text/106-fm-performance-based-pruning.txt:7(搜「thumbs up/down」)
聚类去重Semantic clustering for redundancy eliminationtext/107-fm-semantic-clustering-for-redundancy-elimination.txt:4(搜「clustering」)
缓存是活的基础设施Semantic clustering for redundancy eliminationtext/107-fm-semantic-clustering-for-redundancy-elimination.txt:27(搜「living infrastructure」)
缓存到记忆的过渡Semantic clustering for redundancy eliminationtext/107-fm-semantic-clustering-for-redundancy-elimination.txt:30(搜「memory」)

Footnotes

  1. 出处:「Semantic Caches」第 46 段(text/88-fm-semantic-caches.txt:46,搜「10–100x」)。

  2. 出处:「Semantic Caches」第 99 段(text/88-fm-semantic-caches.txt:99,搜「long-tail pattern」)。

  3. 出处:「Semantic Caches」第 106 段(text/88-fm-semantic-caches.txt:106,搜「68%」)。原文还给出 Pareto 指数与资源分配的关系(α=1.0 时 top 20% 覆盖约 80% 流量)。

  4. 出处:「Semantic Caches」第 109 段(text/88-fm-semantic-caches.txt:109,搜「2–20+ seconds」)与同段(text/88-fm-semantic-caches.txt:109,搜「quantum computers」)。

  5. 出处:「Semantic Caches」第 127-129 段(text/88-fm-semantic-caches.txt:127,搜「interceptor」)。

  6. 出处:「Semantic Caches」第 136 段(text/88-fm-semantic-caches.txt:136,搜「static」)。

  7. 出处:「Semantic Caches」第 130 段(text/88-fm-semantic-caches.txt:130,搜「600-millisecond」)。原文同时提醒「数字天天变,最重要的数字来自你自己的系统」。 2

  8. 出处:「The intelligence layer between the query and the response」第 16-29 段(text/90-fm-the-intelligence-layer-between-the-query-and-the.txt:16,搜「1,000 times a day」;text/90-fm-the-intelligence-layer-between-the-query-and-the.txt:29,搜「above the similarity threshold」)。

  9. 出处:「The intelligence layer between the query and the response」第 32 段(text/90-fm-the-intelligence-layer-between-the-query-and-the.txt:32,搜「not deterministic」)与第 35 段(同文件,搜「curated」)。

  10. 出处:「Step 3 – basic semantic cache」第 4 段(text/93-fm-step-3-basic-semantic-cache.txt:4,搜「all-MiniLM-L6-v2」)与第 25 段(text/93-fm-step-3-basic-semantic-cache.txt:25,搜「threshold=0.75」)。

  11. 出处:「Step 4 – entity masking for better generalization」第 4-7 段(text/94-fm-step-4-entity-masking-for-better-generalization.txt:1,搜「Entity masking」;text/94-fm-step-4-entity-masking-for-better-generalization.txt:7,搜「TICKER」)。

  12. 出处:「Step 5 – cross-encoder verification」第 4 段(text/95-fm-step-5-cross-encoder-verification.txt:4,搜「balance」)。

  13. 出处:「Step 5 – cross-encoder verification」第 7-17 段(text/95-fm-step-5-cross-encoder-verification.txt:7,搜「cross-encoder」)。

  14. 出处:「Step 6 – adaptive thresholds」第 4-7 段(text/96-fm-step-6-adaptive-thresholds.txt:4,搜「mission-critical」)。

  15. 出处:「Step 7 – auto-population with fallback」第 4-7 段(text/97-fm-step-7-auto-population-with-fallback.txt:4,搜「fallback」;text/97-fm-step-7-auto-population-with-fallback.txt:7,搜「self-learning」)。

  16. 出处:「The intelligence layer between the query and the response」第 55-61 段(text/90-fm-the-intelligence-layer-between-the-query-and-the.txt:55,搜「50–60 milliseconds」;text/90-fm-the-intelligence-layer-between-the-query-and-the.txt:61,搜「Full agent planning」)。

  17. 出处:「The intelligence layer between the query and the response」第 71 段(text/90-fm-the-intelligence-layer-between-the-query-and-the.txt:71,搜「Two-Stage Fallback」)。

  18. 出处:「LLM-based paraphrasing」第 4 段(text/99-fm-llm-based-paraphrasing.txt:4,搜「paraphrases」);「Back-translation for natural variation」第 4-18 段(text/100-fm-back-translation-for-natural-variation.txt:4,搜「Back-translation」);「Synonym and lexical expansion」第 4-21 段(text/101-fm-synonym-and-lexical-expansion.txt:21,搜「retirement savings」)。

  19. 出处:「Synthetic query generation」第 7 段(text/102-fm-synthetic-query-generation.txt:7,搜「catch-up contributions」)与第 10 段(text/102-fm-synthetic-query-generation.txt:10,搜「Morgan Stanley」)。

  20. 出处:「Putting it all together」第 40 段(text/98-fm-putting-it-all-together.txt:40,搜「conflicting」)。原文:路径相同不必加、不同则必须加,否则用户会匹配到错误路径。

  21. 出处:「Domain-specific constraints」第 4-10 段(text/103-fm-domain-specific-constraints.txt:4,搜「EBITDA」;text/103-fm-domain-specific-constraints.txt:7,搜「munis」)。

  22. 出处:「Time-based eviction」第 4 段(text/104-fm-time-based-eviction.txt:4,搜「time-to-live」);「Least recently used with semantic decay」第 7 段(text/105-fm-least-recently-used-with-semantic-decay.txt:7,搜「semantic decay」);「Performance-based pruning」第 4-7 段(text/106-fm-performance-based-pruning.txt:7,搜「thumbs up/down」);「Semantic clustering for redundancy elimination」第 4 段(text/107-fm-semantic-clustering-for-redundancy-elimination.txt:4,搜「clustering」)。

  23. 出处:「Semantic clustering for redundancy elimination」第 4 段(text/107-fm-semantic-clustering-for-redundancy-elimination.txt:4,搜「semantic space」)。

  24. 出处:「Semantic clustering for redundancy elimination」第 30 段(text/107-fm-semantic-clustering-for-redundancy-elimination.txt:30,搜「memory」)。