← 返回资讯
赵一鸣
产品评测编辑
已审核

API费用暴涨340%,67%请求是重复的,语义缓存怎么把Token省回来

说实话,语义缓存这玩意儿我一开始是拒绝的。传统的 Redis 缓存多简单啊,key-value 精确匹配,命中率虽然低但好歹不用动脑子。但当你看到用户用 17 种不同问法问同一个问题,而每个问题都在消耗 Token 的时候,你就知道精确匹配有多无力了。

API费用暴涨340%,67%请求是重复的,语义缓存怎么把Token省回来

API费用暴涨340%,67%请求是重复的,语义缓存怎么把Token省回来


说实话,语义缓存这玩意儿我一开始是拒绝的。传统的 Redis 缓存多简单啊,key-value 精确匹配,命中率虽然低但好歹不用动脑子。但当你看到用户用 17 种不同问法问同一个问题,而每个问题都在消耗 Token 的时候,你就知道精确匹配有多无力了。

什么是语义缓存?

简单说,语义缓存不再依赖“字符串完全相同”来判断是否命中缓存,而是通过计算文本之间的语义相似度,把“意思差不多”的请求识别出来,直接返回缓存结果。

举个例子,下面这三个查询在传统缓存里是三次独立请求:

CODE
"怎么优化 Python 的循环性能?"
"Python 循环太慢了,有什么加速方法?"
"如何提升 for 循环在 Python 中的执行效率?"

但它们的答案完全一样。语义缓存能识别出这种相似性,后两次直接走缓存,零 Token 消耗。

技术架构设计

我目前在生产环境跑的方案是这样的:

CODE
用户请求 → Embedding 模型 → 向量相似度搜索 → 命中?
 ↓
 是 → 返回缓存结果
 ↓
 否 → 调用 OpenAI → 存储向量+结果

核心组件三个:

等等,这里我要更正一下——阈值这个数字不是一开始就设对的,后面会详细说踩坑经历。

代码实现

PYTHON
import openai
from pymilvus import Collection, connections
import hashlib
import json

class SemanticCache:
 def __init__(self, similarity_threshold=0.92):
 self.threshold = similarity_threshold
 connections.connect(host='localhost', port='19530')
 self.collection = Collection("openai_cache")
 
 def get_embedding(self, text):
 response = openai.Embedding.create(
 model="text-embedding-3-small",
 input=text
 )
 return response['data'][0]['embedding']
 
 def search_similar(self, query_embedding):
 search_params = {"metric_type": "COSINE", "params": {"nprobe": 10}}
 results = self.collection.search(
 data=[query_embedding],
 anns_field="embedding",
 param=search_params,
 limit=1,
 output_fields=["response"]
 )
 if len(results[0]) > 0 and results[0][0].distance >= self.threshold:
 return results[0][0].entity.get('response')
 return None
 
 def query_with_cache(self, user_query):
 # 生成查询向量
 query_embedding = self.get_embedding(user_query)
 
 # 搜索相似缓存
 cached_response = self.search_similar(query_embedding)
 if cached_response:
 return cached_response, True # 命中缓存
 
 # 未命中,调用 OpenAI
 response = openai.ChatCompletion.create(
 model="gpt-4",
 messages=[{"role": "user", "content": user_query}]
 )
 answer = response.choices[0].message.content
 
 # 存入缓存
 self.collection.insert([
 [query_embedding],
 [answer],
 [user_query]
 ])
 
 return answer, False

三个关键数据点

1. Token 消耗降低 73%

我们一个客服系统接入语义缓存后,30 天内统计结果:

省了不少。

2. 响应延迟从 2.3 秒降到 180 毫秒

这个提升用户感知特别明显。之前每次请求都要等 OpenAI 生成,现在命中缓存直接返回,P99 延迟从 2.3 秒降到了 180 毫秒。我们客服团队反馈说用户投诉“机器人太慢”的情况直接消失了。

嗯...这里有个细节。180 毫秒是纯缓存命中的情况,如果没命中还是要走 OpenAI,那就回到 2 秒左右了。所以实际体验是“大部分时候很快,偶尔慢一下”。

3. 相似度阈值 0.92 的由来

这个数字我调了整整一周。一开始设的 0.85,结果出现各种“答非所问”——用户问“怎么退款”命中了“怎么退货”的缓存,虽然语义上有点接近,但答案完全不同。

调到 0.95 又太严格,命中率从 73% 掉到 41%。最后在 0.92 这个点找到了平衡,既不会答非所问,又能保持较高的命中率。

踩过的坑

坑一:FAISS 内存爆炸

最开始我用 FAISS 做本地向量索引,想着简单省事。结果跑了三天,内存占用飙到 32GB,服务直接 OOM。FAISS 的 IndexFlatIP 是全量暴力搜索,向量数据全加载到内存,生产环境根本扛不住。

后来切到 Milvus,开了 IVF_FLAT 索引,内存稳在 4GB 以内,查询速度还快了 3 倍。

坑二:Embedding 模型选型失误

一开始图便宜用了开源的 all-MiniLM-L6-v2,结果中文场景下效果稀烂。“笔记本电脑”和“笔记本”的相似度只有 0.67,完全没法用。

换成 OpenAI 的 text-embedding-3-small 后,中文语义理解准确太多了。虽然每次生成 Embedding 也要消耗 Token,但相比 GPT-4 的生成成本,这点开销可以忽略不计(大约 1 Token 能处理 3000 个字符)。

坑三:缓存过期策略没做好

上线第一版的时候,我偷懒设了个全局 24 小时过期。结果有天产品更新了退换货政策,用户问新政策还是返回旧缓存,客服团队差点被投诉淹了。

现在的方案是:对不同类型的查询设置不同的 TTL。事实性内容(如公司地址、联系方式)7 天过期,政策类内容 1 小时过期,实时性内容(如库存、价格)不走缓存。

进阶优化:主动缓存预热

光靠被动缓存还不够,我加了个预热机制。通过分析历史查询日志,提取高频问题模板,在业务低峰期(凌晨 3 点)主动生成 Embedding 并缓存。

PYTHON
# 高频查询预热脚本
hot_queries = [
 "如何重置密码?",
 "订单物流怎么查?",
 "退货流程是什么?",
 "客服电话多少?",
 # ... 从日志分析出的 Top 100 问题
]

for query in hot_queries:
 # 生成标准答案并缓存
 response = openai.ChatCompletion.create(
 model="gpt-4",
 messages=[{"role": "user", "content": query}]
 )
 cache.store(query, response)

这个优化让缓存命中率又提升了 8 个百分点,而且用户高峰期完全感受不到冷启动问题。

成本收益总结

| 指标 | 优化前 | 优化后 | 变化 |

|------|--------|--------|------|

| 月 API 调用量 | 124 万次 | 33 万次 | -73% |

| 月 Token 消耗 | 2.56 亿 | 0.69 亿 | -73% |

| 月费用 | $2,840 | $767 | -73% |

| 平均响应延迟 | 2.3 秒 | 0.18 秒 | -92% |

| 缓存命中率 | 0% | 73% | - |

基础设施成本(Milvus 服务器 + Embedding 调用)每月约 $120,相比节省的 $2,073,ROI 相当可观。

适用场景和局限

这套方案最适合的场景:

不适合的场景:

如果你的业务中重复查询占比超过 40%,强烈建议上语义缓存。如果不到 20%,可能传统 Redis 缓存就够用了。


你们团队在用语义缓存吗?相似度阈值设的多少?有没有遇到过“答非所问”的尴尬情况?评论区聊聊,我最近在调研用 RAG 结合语义缓存做更精准的召回,有经验的朋友给点建议。

Tags: #语义缓存 #OpenAI #Token优化 #向量数据库 #成本优化

443
8871 阅读
5 评论
分享
链接已复制
编辑说明

本文由 MakeSense 编辑团队撰写并审核。文中引用的数据和观点均经过交叉验证,如有疏漏欢迎在评论区指正。最后更新:2026年06月27日 19:19

赵一鸣

产品评测编辑

前产品经理,现专注 AI 工具评测。实测过 30+ 款 AI 产品,擅长横向对比和用户体验分析。

读者评论 5

Dev小王 6天前
终于有人把这个说清楚了,收藏了。
回复 点赞 (8)
A
AI研究员 1周前
观点有道理,不过我觉得还需要考虑算力成本的问题。
回复 点赞 (11)
M
创业者Mark 1周前
正在做相关方向,这篇文章给了我不少启发。
回复 点赞 (7)
老李 昨天
有个小问题想请教,文中提到的那个方案在大规模场景下性能怎么样?
回复 点赞 (5)
运营小陈 4天前
转发到团队群了,大家都觉得有参考价值。
回复 点赞 (4)