init: RAG 知识库服务初始提交

- 后端 API(Flask + Gunicorn)
- RAG 引擎(混合检索 + 云端 Reranker + 引用溯源)
- 文档解析(MinerU + 多格式支持)
- Docker 生产部署配置
- 排除前端项目、敏感配置、模型文件
This commit is contained in:
lacerate551
2026-06-04 17:35:27 +08:00
commit 100d1a06eb
158 changed files with 64534 additions and 0 deletions

262
core/adaptive_topk.py Normal file
View File

@@ -0,0 +1,262 @@
"""
自适应 TopK 策略
根据检索置信度动态调整 top_k
- 低置信度:扩大检索范围
- 高置信度:缩小检索范围
- 中等置信度:保持原样
使用方式:
from core.adaptive_topk import AdaptiveTopK
strategy = AdaptiveTopK()
adjusted_k, should_retrieve = strategy.adjust(top_score, initial_k)
"""
from dataclasses import dataclass
from typing import Tuple, Optional
import logging
logger = logging.getLogger(__name__)
@dataclass
class AdaptiveConfig:
"""自适应配置"""
# 置信度阈值
low_confidence_threshold: float = 0.5 # 低于此值认为是低置信度
high_confidence_threshold: float = 0.8 # 高于此值认为是高置信度
# 扩展/收缩比例
expand_ratio: float = 2.0 # 低置信度时扩大倍数
shrink_ratio: float = 0.5 # 高置信度时缩小比例
# 限制
min_top_k: int = 3 # 最小 top_k
max_top_k: int = 20 # 最大 top_k
# 是否启用
enabled: bool = True
class AdaptiveTopK:
"""
自适应 TopK 策略
核心逻辑:
1. 第一次检索返回结果后,检查最高得分
2. 根据得分判断置信度
3. 决定是否需要调整 top_k 重新检索
"""
def __init__(self, config: AdaptiveConfig = None):
"""
初始化
Args:
config: 配置对象如果为None则使用默认配置
"""
self.config = config or AdaptiveConfig()
def adjust(
self,
top_score: float,
initial_k: int,
current_results_count: int = 0
) -> Tuple[int, bool, str]:
"""
根据置信度调整 top_k
Args:
top_score: 当前检索结果的最高得分 (0-1)
initial_k: 初始 top_k
current_results_count: 当前结果数量
Returns:
(adjusted_k, should_retrieve, reason)
- adjusted_k: 调整后的 top_k
- should_retrieve: 是否需要重新检索
- reason: 调整原因
"""
if not self.config.enabled:
return initial_k, False, "disabled"
# 低置信度:扩大检索范围
if top_score < self.config.low_confidence_threshold:
adjusted_k = min(
int(initial_k * self.config.expand_ratio),
self.config.max_top_k
)
if adjusted_k > initial_k:
return adjusted_k, True, f"low_confidence({top_score:.2f}<{self.config.low_confidence_threshold})"
# 高置信度:可以缩小范围(但不重新检索)
elif top_score > self.config.high_confidence_threshold:
adjusted_k = max(
int(initial_k * self.config.shrink_ratio),
self.config.min_top_k
)
# 高置信度时不需要重新检索,只是返回时可以截断
return adjusted_k, False, f"high_confidence({top_score:.2f}>{self.config.high_confidence_threshold})"
# 中等置信度:保持原样
return initial_k, False, f"medium_confidence({top_score:.2f})"
def get_final_results(
self,
results: list,
adjusted_k: int,
reason: str
) -> list:
"""
获取最终结果
Args:
results: 检索结果列表
adjusted_k: 调整后的 top_k
reason: 调整原因
Returns:
截断后的结果列表
"""
if "high_confidence" in reason:
# 高置信度时截断结果
return results[:adjusted_k]
return results
def get_config_dict(self) -> dict:
"""获取配置字典"""
return {
"enabled": self.config.enabled,
"low_confidence_threshold": self.config.low_confidence_threshold,
"high_confidence_threshold": self.config.high_confidence_threshold,
"expand_ratio": self.config.expand_ratio,
"shrink_ratio": self.config.shrink_ratio,
"min_top_k": self.config.min_top_k,
"max_top_k": self.config.max_top_k
}
class AdaptiveTopKWithStats(AdaptiveTopK):
"""
带统计的自适应 TopK 策略
记录每次调整的统计信息,用于分析和优化
"""
def __init__(self, config: AdaptiveConfig = None):
super().__init__(config)
self.stats = {
"total_queries": 0,
"low_confidence_count": 0,
"high_confidence_count": 0,
"medium_confidence_count": 0,
"re_retrieve_count": 0
}
def adjust(
self,
top_score: float,
initial_k: int,
current_results_count: int = 0
) -> Tuple[int, bool, str]:
"""带统计的调整"""
self.stats["total_queries"] += 1
adjusted_k, should_retrieve, reason = super().adjust(
top_score, initial_k, current_results_count
)
# 更新统计
if "low_confidence" in reason:
self.stats["low_confidence_count"] += 1
elif "high_confidence" in reason:
self.stats["high_confidence_count"] += 1
else:
self.stats["medium_confidence_count"] += 1
if should_retrieve:
self.stats["re_retrieve_count"] += 1
return adjusted_k, should_retrieve, reason
def get_stats(self) -> dict:
"""获取统计信息"""
return self.stats.copy()
def reset_stats(self):
"""重置统计"""
self.stats = {
"total_queries": 0,
"low_confidence_count": 0,
"high_confidence_count": 0,
"medium_confidence_count": 0,
"re_retrieve_count": 0
}
# ==================== 便捷函数 ====================
def create_adaptive_topk(
enabled: bool = True,
low_threshold: float = 0.5,
high_threshold: float = 0.8,
expand_ratio: float = 2.0,
shrink_ratio: float = 0.5
) -> AdaptiveTopK:
"""
创建自适应 TopK 策略
Args:
enabled: 是否启用
low_threshold: 低置信度阈值
high_threshold: 高置信度阈值
expand_ratio: 扩展比例
shrink_ratio: 收缩比例
Returns:
AdaptiveTopK 实例
"""
config = AdaptiveConfig(
enabled=enabled,
low_confidence_threshold=low_threshold,
high_confidence_threshold=high_threshold,
expand_ratio=expand_ratio,
shrink_ratio=shrink_ratio
)
return AdaptiveTopK(config)
# ==================== 测试 ====================
if __name__ == "__main__":
import sys
if sys.platform == 'win32':
sys.stdout.reconfigure(encoding='utf-8')
print("=" * 60)
print("自适应 TopK 策略测试")
print("=" * 60)
strategy = AdaptiveTopKWithStats()
test_cases = [
(0.3, 5, "低置信度 - 应该扩展"),
(0.6, 5, "中等置信度 - 保持"),
(0.9, 5, "高置信度 - 应该收缩"),
(0.45, 10, "边界低置信度"),
(0.8, 10, "边界高置信度"),
]
for top_score, initial_k, description in test_cases:
adjusted_k, should_retrieve, reason = strategy.adjust(top_score, initial_k)
print(f"\n{description}")
print(f" 输入: top_score={top_score}, initial_k={initial_k}")
print(f" 输出: adjusted_k={adjusted_k}, should_retrieve={should_retrieve}")
print(f" 原因: {reason}")
print("\n" + "=" * 60)
print("统计信息:")
stats = strategy.get_stats()
for key, value in stats.items():
print(f" {key}: {value}")