Skip to content
🔗 分享本题
查看我的学习进度 →

语义缓存动漫知识图:语义相似只是命中候选,还需校验租户、权限、语言、TTL 和知识版本,并在更新时失效

记忆点:语义相似只是候选,作用域和知识版本决定能否复用。

💡 答案要点

语义缓存 = 用语义相似度判断是否命中缓存

问题背景:

  • 传统缓存:精确匹配(相同问题 → 相同答案)
  • 语义缓存:语义相似 → 相同答案
用户问题 A:"如何优化 Python 代码性能?"
用户问题 B:"Python 性能优化方法有哪些?"
→ 语义相似 → 命中缓存

用户问题 C:"如何优化 Python 代码性能?"
用户问题 C 再次问:"如何优化 Python 代码性能?"
→ 完全相同 → 精确命中

核心挑战:

挑战说明解决方案
相似度阈值设太高 → 命中率低;设太低 → 答案不相关线上 A/B 测试调参
向量检索开销每次请求都要做向量检索粗排 + 精排
缓存失效知识库更新后,缓存可能过期TTL + 版本号
多租户不同用户看到不同答案用户级缓存隔离

实现架构:

用户问题

┌─────────────┐
│ Query 向量化 │ → embedding
└─────────────┘

┌─────────────┐
│ 缓存命中判断 │ → 向量数据库检索 top-k
└─────────────┘

命中? → 是 → 返回缓存答案
    ↓ 否
┌─────────────┐
│ 正常 RAG 流程 │ → 执行检索 + 生成
└─────────────┘

┌─────────────┐
│ 写入缓存    │ → 新问题 + 答案 → 向量存入
└─────────────┘

实现示例:

展开 Python 代码示例(32 行)
python
import numpy as np

class SemanticCache:
    def __init__(self, threshold=0.85, ttl=3600):
        self.cache = []  # [(embedding, question, answer, timestamp)]
        self.threshold = threshold
        self.ttl = ttl

    def get(self, question, embedding):
        # 1. 向量检索
        scores = [cosine(e1, embedding) for e1, _, _, _ in self.cache]

        # 2. 找最佳匹配
        if not scores:
            return None

        best_idx = np.argmax(scores)
        best_score = scores[best_idx]

        # 3. 检查阈值和 TTL
        if best_score >= self.threshold:
            _, _, answer, timestamp = self.cache[best_idx]
            if time.time() - timestamp < self.ttl:
                return answer

        return None

    def set(self, question, embedding, answer):
        # 检查缓存大小,超限时淘汰最旧的
        if len(self.cache) > 10000:
            self.cache.pop(0)
        self.cache.append((embedding, question, answer, time.time()))

性能对比:

方案命中率延迟成本
无缓存0%500ms¥0.01/次
精确缓存10-20%10ms¥0.002/次
语义缓存30-50%50ms¥0.005/次

面试话术:

示例表达(仅在能用本人经历或可复现实验佐证时使用): "语义缓存是 RAG 成本优化的杀手级功能。我实测命中率 30-50%,配合向量数据库(如 Qdrant)的 ANN 索引,缓存检索只要 50ms,比直接调用 LLM 快 10 倍。关键是相似度阈值要调好,我一般设 0.85——太高容易漏命中,太低答案不相关。"