fix: 缓存系统全面加固 — 版本失效 + 死代码清理 + 防御性改进

基于缓存审查报告 + Claude Code 交叉审查的反馈:

P0+ 语义缓存版本失效:
- sync.py: 文档变更后清空语义缓存,防止返回过时的 images/sources
- document_routes.py: 删除文档时同步清理缓存
- kb_routes.py: 删除向量库时同步清理缓存

P1.5 cache_type 包含式校验:
- intent_analyzer.py: != "rag_answer" 改为 == "intent_analysis"

P2+ Rerank Cache 版本失效:
- cache.py: increment_kb_version 时同时清空 rerank_cache

P1+P6 死代码清理:
- agentic.py: 移除未使用的 SemanticCache 实例和相关导入
- agentic_base.py: 移除未使用的语义缓存配置导入
- cache.py: 移除 _compute_doc_hash 和未使用的 doc_ids 参数
- engine.py: 移除 set_query_result 调用中的 doc_ids 参数

P7 缓存质量门槛:
- config.py: CACHE_MIN_SCORE 从 0.0 改为 0.3
This commit is contained in:
lacerate551
2026-06-21 16:08:58 +08:00
parent 21470ed28c
commit 0f339a0998
8 changed files with 58 additions and 107 deletions

View File

@@ -189,6 +189,8 @@ class RAGCacheManager:
# 失效旧版本缓存
self.query_cache.invalidate_by_version(old_version)
self.embedding_cache.invalidate_by_version(old_version)
# Rerank cache 无 kb_version 字段,文档变更时全量清空以防过时分数
self.rerank_cache.clear()
logger.info(f"知识库 {kb_name} 版本更新: {old_version} -> {new_version}")
return new_version
@@ -196,87 +198,41 @@ class RAGCacheManager:
# ==================== Query Cache 方法 ====================
@staticmethod
def _make_query_cache_key(query: str, kb_name: str, kb_version: int, doc_hash: str = "") -> str:
def _make_query_cache_key(query: str, kb_name: str, kb_version: int) -> str:
"""
生成查询缓存 key
Args:
query: 查询文本
kb_name: 知识库名称
kb_version: 知识库版本号
doc_hash: 相关文档版本哈希(细粒度失效)
Returns:
缓存 key
生成查询缓存 key(基于 kb_version 的粗粒度失效)
"""
if doc_hash:
# 细粒度:只失效相关文档的缓存
return hashlib.md5(
f"query:{query}:{kb_name}:{doc_hash}".encode()
).hexdigest()
else:
# 粗粒度:整个知识库版本变化时失效
return hashlib.md5(
f"query:{query}:{kb_name}:{kb_version}".encode()
).hexdigest()
return hashlib.md5(
f"query:{query}:{kb_name}:{kb_version}".encode()
).hexdigest()
def get_query_result(self, query: str, kb_name: str, doc_ids: List[str] = None) -> Optional[Dict]:
def get_query_result(self, query: str, kb_name: str) -> Optional[Dict]:
"""
获取查询缓存结果
始终使用粗粒度 key基于 kb_version确保 GET/SET key 一致。
Args:
query: 查询文本
kb_name: 知识库名称
doc_ids: 保留参数以兼容调用方签名(当前未使用)
"""
kb_version = self.get_kb_version(kb_name)
# 使用粗粒度 key与 SET 保持一致
key = self._make_query_cache_key(query, kb_name, kb_version)
return self.query_cache.get(key)
def set_query_result(self, query: str, kb_name: str, result: Dict, doc_ids: List[str] = None) -> None:
def set_query_result(self, query: str, kb_name: str, result: Dict) -> None:
"""
设置查询缓存结果
始终使用粗粒度 key基于 kb_version确保 GET/SET key 一致。
kb_version 在文档变更时自增,触发整个知识库的缓存失效。
Args:
query: 查询文本
kb_name: 知识库名称
result: 缓存结果
doc_ids: 保留参数以兼容调用方签名(当前未使用)
"""
kb_version = self.get_kb_version(kb_name)
# 使用与 GET 相同的粗粒度 key确保缓存可命中
key = self._make_query_cache_key(query, kb_name, kb_version)
self.query_cache.set(key, result, kb_version=kb_version)
def _compute_doc_hash(self, kb_name: str, doc_ids: List[str]) -> str:
"""
计算文档版本哈希
用于细粒度缓存失效:只失效相关文档变化时的缓存
"""
if not doc_ids:
return ""
# 从文档 ID 中提取 source文件名
sources = set()
for doc_id in doc_ids:
# doc_id 格式通常为 "filename_text_0" 或类似
parts = doc_id.split('_')
if parts:
sources.add(parts[0])
# 生成哈希
sources_str = ','.join(sorted(sources))
return hashlib.md5(f"docs:{sources_str}".encode()).hexdigest()
# ==================== Embedding Cache 方法 ====================
@staticmethod