# RAG-MCP 项目功能增强方案

## 📋 项目背景

基于现有的RAG-MCP知识库检索系统，本方案旨在提升系统的通用性、易用性和实用性，使其更适合通过MCP服务被智能体调用。

**当前系统核心功能：**
- 多模式检索（Vector、BM25、Hybrid）
- MCP协议支持（STDIO + HTTP）
- 中文优化分词
- 基础索引管理

**主要改进目标：**
1. 增强检索精度控制（分数阈值、结果过滤）
2. 提供灵活的结果排序和重排序能力
3. 扩展高级检索功能（元数据过滤、批量查询、去重）
4. 完善索引管理（增量更新、文档CRUD）
5. 添加监控和分析能力
6. 丰富CLI和MCP工具集

---

## 🎯 功能增强详细设计

### 1. 搜索分数阈值过滤功能

#### 1.1 功能描述
为检索结果添加分数阈值过滤，只返回相关度达到指定阈值的文档，提升结果质量。

#### 1.2 技术设计

**配置层增强** (`src/config/settings.py`)：
```python
class RetrievalConfig(BaseModel):
    """检索配置"""
    # ... 现有配置 ...
    
    # 新增配置项
    score_threshold: float = Field(default=0.0, ge=0.0, le=1.0, 
                                   description="相关性分数阈值，低于此分数的结果将被过滤")
    min_score_threshold: float = Field(default=0.1, description="最小分数阈值")
    max_score_threshold: float = Field(default=0.9, description="最大分数阈值")
    use_adaptive_threshold: bool = Field(default=False, description="是否使用自适应阈值")
    adaptive_threshold_percentile: float = Field(default=0.5, ge=0.0, le=1.0,
                                                 description="自适应阈值分位数")
```

**查询引擎增强** (`src/core/query_engine.py`)：
```python
def execute_retrieve(
    self, 
    retriever, 
    question: str, 
    mode: str,
    score_threshold: Optional[float] = None,
    use_adaptive_threshold: bool = False
) -> dict:
    """执行检索，支持分数阈值过滤"""
    nodes = retriever.retrieve(question)
    
    # 应用分数阈值过滤
    if score_threshold is not None and score_threshold > 0:
        filtered_nodes = [
            node for node in nodes 
            if hasattr(node, 'score') and node.score >= score_threshold
        ]
        logger.info(f"阈值过滤: {len(nodes)} -> {len(filtered_nodes)} (阈值: {score_threshold})")
        nodes = filtered_nodes
    
    # 自适应阈值
    elif use_adaptive_threshold and nodes:
        scores = [node.score for node in nodes if hasattr(node, 'score')]
        if scores:
            threshold = np.percentile(scores, self.config.retrieval.adaptive_threshold_percentile * 100)
            nodes = [node for node in nodes if node.score >= threshold]
            logger.info(f"自适应阈值: {threshold:.4f}, 保留: {len(nodes)}")
    
    # ... 构建返回结果 ...
```

**MCP工具增强** (`src/mcp/handlers/tools_handler.py`)：

新增工具参数：
```json
{
    "name": "retrieve_documents",
    "inputSchema": {
        "properties": {
            "score_threshold": {
                "type": "number",
                "description": "相关性分数阈值（0-1），低于此分数的结果将被过滤",
                "minimum": 0.0,
                "maximum": 1.0
            },
            "use_adaptive_threshold": {
                "type": "boolean",
                "description": "是否使用自适应阈值",
                "default": false
            }
        }
    }
}
```

#### 1.3 使用示例

**Python API**:
```python
# 设置固定阈值
result = rag.retrieve(
    question="什么是RAG技术？",
    score_threshold=0.3,  # 只返回分数>=0.3的结果
    top_k=10
)

# 使用自适应阈值
result = rag.retrieve(
    question="什么是RAG技术？",
    use_adaptive_threshold=True,
    top_k=10
)
```

**CLI**:
```bash
# 使用阈值过滤
python cli.py retrieve --question "什么是RAG?" --threshold 0.3

# 自适应阈值
python cli.py retrieve --question "什么是RAG?" --adaptive-threshold
```

**MCP调用**:
```json
{
    "tool": "retrieve_documents",
    "arguments": {
        "question": "什么是RAG技术？",
        "top_k": 10,
        "score_threshold": 0.3,
        "mode": "hybrid"
    }
}
```

---

### 2. 结果排序和重排序功能

#### 2.1 功能描述
提供多种排序策略，支持基于分数、时间、长度、自定义权重等进行结果重排序。

#### 2.2 技术设计

**排序策略枚举**：
```python
from enum import Enum

class SortStrategy(str, Enum):
    """排序策略"""
    SCORE_DESC = "score_desc"         # 分数降序（默认）
    SCORE_ASC = "score_asc"           # 分数升序
    TIME_DESC = "time_desc"           # 时间降序（最新优先）
    TIME_ASC = "time_asc"             # 时间升序（最旧优先）
    LENGTH_DESC = "length_desc"       # 文本长度降序
    LENGTH_ASC = "length_asc"         # 文本长度升序
    DIVERSITY = "diversity"           # 多样性排序（去重相似文档）
    WEIGHTED = "weighted"             # 加权排序（分数+元数据）
```

**重排序器类** (`src/core/reranker.py`)：
```python
from typing import List, Optional
from llama_index.core.schema import NodeWithScore
import numpy as np

class ResultReranker:
    """结果重排序器"""
    
    def __init__(self, config: Optional[ConfigManager] = None):
        self.config = config or get_config_manager()
    
    def rerank(
        self,
        nodes: List[NodeWithScore],
        strategy: SortStrategy = SortStrategy.SCORE_DESC,
        weights: Optional[Dict[str, float]] = None,
        diversity_threshold: float = 0.8
    ) -> List[NodeWithScore]:
        """重排序结果"""
        
        if not nodes:
            return nodes
        
        if strategy == SortStrategy.SCORE_DESC:
            return sorted(nodes, key=lambda x: x.score or 0, reverse=True)
        
        elif strategy == SortStrategy.SCORE_ASC:
            return sorted(nodes, key=lambda x: x.score or 0, reverse=False)
        
        elif strategy == SortStrategy.TIME_DESC:
            return self._sort_by_time(nodes, descending=True)
        
        elif strategy == SortStrategy.TIME_ASC:
            return self._sort_by_time(nodes, descending=False)
        
        elif strategy == SortStrategy.LENGTH_DESC:
            return sorted(nodes, key=lambda x: len(x.node.text), reverse=True)
        
        elif strategy == SortStrategy.LENGTH_ASC:
            return sorted(nodes, key=lambda x: len(x.node.text), reverse=False)
        
        elif strategy == SortStrategy.DIVERSITY:
            return self._diversity_rerank(nodes, diversity_threshold)
        
        elif strategy == SortStrategy.WEIGHTED:
            return self._weighted_rerank(nodes, weights or {})
        
        return nodes
    
    def _sort_by_time(self, nodes: List[NodeWithScore], descending: bool = True) -> List[NodeWithScore]:
        """按时间排序"""
        def get_time(node):
            metadata = node.node.metadata or {}
            return metadata.get('created_at', metadata.get('modified_at', ''))
        
        return sorted(nodes, key=get_time, reverse=descending)
    
    def _diversity_rerank(self, nodes: List[NodeWithScore], threshold: float) -> List[NodeWithScore]:
        """多样性重排序，去除相似度过高的文档"""
        if not nodes:
            return nodes
        
        selected = [nodes[0]]  # 保留第一个（最高分）
        
        for node in nodes[1:]:
            # 检查与已选节点的相似度
            is_diverse = True
            for selected_node in selected:
                similarity = self._compute_text_similarity(
                    node.node.text, 
                    selected_node.node.text
                )
                if similarity > threshold:
                    is_diverse = False
                    break
            
            if is_diverse:
                selected.append(node)
        
        logger.info(f"多样性过滤: {len(nodes)} -> {len(selected)} (阈值: {threshold})")
        return selected
    
    def _weighted_rerank(self, nodes: List[NodeWithScore], weights: Dict[str, float]) -> List[NodeWithScore]:
        """加权重排序"""
        scored_nodes = []
        
        for node in nodes:
            # 基础分数
            base_score = node.score or 0
            
            # 元数据权重
            metadata = node.node.metadata or {}
            metadata_bonus = 0
            
            for key, weight in weights.items():
                if key in metadata:
                    value = metadata[key]
                    # 根据值类型计算加权
                    if isinstance(value, (int, float)):
                        metadata_bonus += value * weight
                    elif isinstance(value, bool) and value:
                        metadata_bonus += weight
            
            # 计算最终分数
            final_score = base_score + metadata_bonus
            node.score = final_score
            scored_nodes.append(node)
        
        return sorted(scored_nodes, key=lambda x: x.score, reverse=True)
    
    @staticmethod
    def _compute_text_similarity(text1: str, text2: str) -> float:
        """计算文本相似度（简单Jaccard相似度）"""
        words1 = set(text1.split())
        words2 = set(text2.split())
        
        if not words1 or not words2:
            return 0.0
        
        intersection = words1.intersection(words2)
        union = words1.union(words2)
        
        return len(intersection) / len(union)
```

#### 2.3 使用示例

**Python API**:
```python
from src.core.reranker import ResultReranker, SortStrategy

# 多样性排序
result = rag.retrieve(
    question="什么是RAG技术？",
    top_k=20,
    sort_strategy=SortStrategy.DIVERSITY,
    diversity_threshold=0.7
)

# 加权排序
result = rag.retrieve(
    question="最新的AI研究",
    sort_strategy=SortStrategy.WEIGHTED,
    weights={"priority": 0.3, "views": 0.0001}
)
```

**CLI**:
```bash
# 按分数降序（默认）
python cli.py retrieve --question "什么是RAG?" --sort score_desc

# 多样性排序
python cli.py retrieve --question "什么是RAG?" --sort diversity --diversity-threshold 0.7

# 按时间排序
python cli.py retrieve --question "最新研究" --sort time_desc
```

---

### 3. 高级检索功能

#### 3.1 元数据过滤

**功能描述**：根据文档元数据进行过滤，如文件类型、日期范围、标签等。

**技术设计**：
```python
class MetadataFilter:
    """元数据过滤器"""
    
    def __init__(self):
        self.filters = []
    
    def add_filter(
        self, 
        field: str, 
        operator: str, 
        value: Any
    ) -> "MetadataFilter":
        """
        添加过滤条件
        
        Args:
            field: 字段名
            operator: 操作符 (eq, ne, gt, lt, gte, lte, in, contains)
            value: 值
        """
        self.filters.append({
            "field": field,
            "operator": operator,
            "value": value
        })
        return self
    
    def apply(self, nodes: List[NodeWithScore]) -> List[NodeWithScore]:
        """应用过滤器"""
        filtered = []
        
        for node in nodes:
            metadata = node.node.metadata or {}
            
            if self._matches(metadata):
                filtered.append(node)
        
        return filtered
    
    def _matches(self, metadata: Dict) -> bool:
        """检查元数据是否匹配所有过滤条件"""
        for filter_def in self.filters:
            field = filter_def["field"]
            operator = filter_def["operator"]
            value = filter_def["value"]
            
            if field not in metadata:
                return False
            
            field_value = metadata[field]
            
            if not self._compare(field_value, operator, value):
                return False
        
        return True
    
    def _compare(self, field_value: Any, operator: str, value: Any) -> bool:
        """执行比较操作"""
        if operator == "eq":
            return field_value == value
        elif operator == "ne":
            return field_value != value
        elif operator == "gt":
            return field_value > value
        elif operator == "lt":
            return field_value < value
        elif operator == "gte":
            return field_value >= value
        elif operator == "lte":
            return field_value <= value
        elif operator == "in":
            return field_value in value
        elif operator == "contains":
            return value in str(field_value)
        return False
```

**使用示例**：
```python
# 过滤PDF文档
result = rag.retrieve(
    question="什么是RAG?",
    metadata_filters={
        "file_type": {"operator": "eq", "value": "pdf"},
        "created_at": {"operator": "gte", "value": "2024-01-01"}
    }
)
```

#### 3.2 批量查询

**功能描述**：一次性提交多个查询，提高效率。

**技术设计**：
```python
def batch_retrieve(
    self,
    questions: List[str],
    mode: Optional[str] = None,
    top_k: Optional[int] = None,
    shared_config: Optional[Dict] = None
) -> List[Dict]:
    """
    批量检索
    
    Args:
        questions: 问题列表
        mode: 检索模式
        top_k: 每个查询返回的结果数
        shared_config: 共享配置
    
    Returns:
        结果列表
    """
    results = []
    
    for idx, question in enumerate(questions):
        logger.info(f"批量检索 [{idx+1}/{len(questions)}]: {question[:50]}...")
        
        result = self.retrieve(
            question=question,
            mode=mode,
            top_k=top_k,
            **(shared_config or {})
        )
        results.append(result)
    
    return {
        "success": True,
        "count": len(questions),
        "results": results
    }
```

**MCP工具定义**：
```json
{
    "name": "batch_retrieve",
    "description": "批量检索多个问题",
    "inputSchema": {
        "type": "object",
        "properties": {
            "questions": {
                "type": "array",
                "items": {"type": "string"},
                "description": "问题列表"
            },
            "mode": {
                "type": "string",
                "enum": ["vector", "bm25", "hybrid"],
                "description": "检索模式"
            },
            "top_k": {
                "type": "integer",
                "description": "每个查询返回的结果数"
            }
        },
        "required": ["questions"]
    }
}
```

#### 3.3 语义相似文档搜索

**功能描述**：给定一个文档ID，查找与其语义相似的其他文档。

**技术设计**：
```python
def find_similar_documents(
    self,
    document_id: str,
    top_k: int = 5,
    similarity_threshold: float = 0.7
) -> Dict:
    """
    查找相似文档
    
    Args:
        document_id: 文档ID
        top_k: 返回数量
        similarity_threshold: 相似度阈值
    
    Returns:
        相似文档列表
    """
    # 获取源文档
    source_node = self._get_node_by_id(document_id)
    if not source_node:
        return {"success": False, "error": "文档不存在"}
    
    # 使用文档内容进行检索
    result = self.retrieve(
        question=source_node.text,
        mode="vector",
        top_k=top_k + 1,  # +1 以排除自身
        score_threshold=similarity_threshold
    )
    
    # 过滤掉源文档自身
    filtered_results = [
        r for r in result["results"] 
        if r.get("metadata", {}).get("node_id") != document_id
    ]
    
    return {
        "success": True,
        "source_document_id": document_id,
        "similar_documents": filtered_results[:top_k]
    }
```

---

### 4. 索引管理功能

#### 4.1 增量更新索引

**功能描述**：不需要重建整个索引，只添加新文档或更新已有文档。

**技术设计**：
```python
def add_documents(
    self,
    documents: List[str],
    document_ids: Optional[List[str]] = None,
    metadata_list: Optional[List[Dict]] = None
) -> Dict:
    """
    增量添加文档到索引
    
    Args:
        documents: 文档内容列表
        document_ids: 文档ID列表（可选）
        metadata_list: 元数据列表（可选）
    
    Returns:
        操作结果
    """
    if not self.index:
        return {"success": False, "error": "索引未初始化"}
    
    # 创建新节点
    nodes = []
    for i, doc in enumerate(documents):
        node = TextNode(
            text=doc,
            id_=document_ids[i] if document_ids else None,
            metadata=metadata_list[i] if metadata_list else {}
        )
        nodes.append(node)
    
    # 插入到索引
    self.index.insert_nodes(nodes)
    
    # 更新BM25索引
    if self.bm25_retriever:
        self._update_bm25_index(nodes)
    
    logger.info(f"成功添加 {len(nodes)} 个文档到索引")
    
    return {
        "success": True,
        "added_count": len(nodes),
        "document_ids": [n.id_ for n in nodes]
    }

def update_document(
    self,
    document_id: str,
    new_content: str,
    new_metadata: Optional[Dict] = None
) -> Dict:
    """
    更新文档
    
    Args:
        document_id: 文档ID
        new_content: 新内容
        new_metadata: 新元数据
    
    Returns:
        操作结果
    """
    # 删除旧文档
    delete_result = self.delete_document(document_id)
    if not delete_result["success"]:
        return delete_result
    
    # 添加新文档
    add_result = self.add_documents(
        documents=[new_content],
        document_ids=[document_id],
        metadata_list=[new_metadata] if new_metadata else None
    )
    
    return add_result

def delete_document(self, document_id: str) -> Dict:
    """
    删除文档
    
    Args:
        document_id: 文档ID
    
    Returns:
        操作结果
    """
    if not self.index:
        return {"success": False, "error": "索引未初始化"}
    
    try:
        self.index.delete_ref_doc(document_id, delete_from_docstore=True)
        logger.info(f"成功删除文档: {document_id}")
        
        return {
            "success": True,
            "document_id": document_id,
            "message": "文档删除成功"
        }
    except Exception as e:
        logger.error(f"删除文档失败: {e}")
        return {
            "success": False,
            "error": str(e)
        }
```

**MCP工具定义**：
```json
{
    "name": "add_documents",
    "description": "增量添加文档到索引",
    "inputSchema": {
        "type": "object",
        "properties": {
            "documents": {
                "type": "array",
                "items": {"type": "string"},
                "description": "文档内容列表"
            },
            "metadata_list": {
                "type": "array",
                "items": {"type": "object"},
                "description": "每个文档的元数据"
            }
        },
        "required": ["documents"]
    }
}
```

#### 4.2 索引优化和统计

**功能描述**：优化索引性能，提供详细的索引统计信息。

**技术设计**：
```python
def optimize_index(self) -> Dict:
    """优化索引"""
    # 移除重复节点
    # 压缩存储
    # 重建BM25索引
    pass

def get_detailed_stats(self) -> Dict:
    """获取详细统计信息"""
    stats = {
        "total_documents": 0,
        "total_nodes": 0,
        "avg_document_length": 0,
        "file_type_distribution": {},
        "index_size_mb": 0,
        "last_updated": None,
        "retrieval_modes": [],
    }
    # ... 实现统计逻辑 ...
    return stats
```

---

### 5. 监控和分析功能

#### 5.1 查询统计

**功能描述**：记录和分析查询模式、热门话题等。

**技术设计**：
```python
class QueryAnalytics:
    """查询分析器"""
    
    def __init__(self, storage_path: str = "logs/query_analytics.json"):
        self.storage_path = storage_path
        self.queries = []
    
    def record_query(
        self,
        query: str,
        mode: str,
        num_results: int,
        avg_score: float,
        duration_ms: float
    ):
        """记录查询"""
        self.queries.append({
            "timestamp": datetime.now().isoformat(),
            "query": query,
            "mode": mode,
            "num_results": num_results,
            "avg_score": avg_score,
            "duration_ms": duration_ms
        })
        
        # 定期持久化
        if len(self.queries) % 100 == 0:
            self.save()
    
    def get_statistics(self, days: int = 7) -> Dict:
        """获取统计信息"""
        # 查询频率
        # 热门话题
        # 平均响应时间
        # 检索模式分布
        pass
    
    def get_hot_topics(self, top_k: int = 10) -> List[str]:
        """获取热门话题"""
        # 使用TF-IDF或关键词提取
        pass
```

**MCP工具定义**：
```json
{
    "name": "get_analytics",
    "description": "获取查询统计和分析报告",
    "inputSchema": {
        "type": "object",
        "properties": {
            "days": {
                "type": "integer",
                "description": "统计天数",
                "default": 7
            },
            "report_type": {
                "type": "string",
                "enum": ["summary", "detailed", "hot_topics"],
                "description": "报告类型"
            }
        }
    }
}
```

---

### 6. 新增CLI命令

#### 6.1 命令列表

| 命令 | 功能 | 示例 |
|-----|------|------|
| `filter` | 使用阈值过滤检索 | `python cli.py filter --query "RAG技术" --threshold 0.3` |
| `sort` | 结果排序 | `python cli.py sort --query "AI研究" --strategy diversity` |
| `batch` | 批量查询 | `python cli.py batch --file queries.txt` |
| `add` | 添加文档 | `python cli.py add --file new_doc.txt` |
| `update` | 更新文档 | `python cli.py update --id doc123 --file updated.txt` |
| `remove` | 删除文档 | `python cli.py remove --id doc123` |
| `optimize` | 优化索引 | `python cli.py optimize` |
| `analyze` | 查询分析 | `python cli.py analyze --days 7` |
| `similar` | 查找相似文档 | `python cli.py similar --id doc123` |

#### 6.2 CLI增强示例

```bash
# 高级检索：阈值+排序+元数据过滤
python cli.py retrieve \
  --question "最新的AI研究" \
  --threshold 0.4 \
  --sort time_desc \
  --filter "file_type:pdf,created_at:>=2024-01-01" \
  --top-k 10

# 批量查询
echo "什么是RAG?\n什么是LLM?\n什么是Embedding?" | python cli.py batch

# 增量添加文档
python cli.py add --dir ./new_docs --metadata "category:research,priority:high"

# 查询分析
python cli.py analyze --report detailed --output analytics_report.json
```

---

### 7. 新增MCP工具

#### 7.1 完整工具列表

| 工具名 | 功能描述 |
|-------|---------|
| `build_index` | 构建索引（已有） |
| `query_knowledge` | LLM查询（已有） |
| `retrieve_documents` | 检索文档（已有，需增强） |
| `retrieve_with_filters` | **新增**：高级检索（阈值+排序+过滤） |
| `batch_retrieve` | **新增**：批量检索 |
| `find_similar` | **新增**：查找相似文档 |
| `add_documents` | **新增**：增量添加文档 |
| `update_document` | **新增**：更新文档 |
| `delete_document` | **新增**：删除文档 |
| `optimize_index` | **新增**：优化索引 |
| `get_analytics` | **新增**：获取统计分析 |
| `get_index_status` | 获取状态（已有） |
| `get_config` | 获取配置（已有） |
| `delete_index` | 删除索引（已有） |

#### 7.2 工具定义示例

**retrieve_with_filters** - 高级检索工具：
```json
{
    "name": "retrieve_with_filters",
    "description": "高级检索文档，支持分数阈值、排序策略、元数据过滤等",
    "inputSchema": {
        "type": "object",
        "properties": {
            "question": {
                "type": "string",
                "description": "检索问题"
            },
            "mode": {
                "type": "string",
                "enum": ["vector", "bm25", "hybrid"],
                "default": "hybrid"
            },
            "top_k": {
                "type": "integer",
                "default": 5,
                "minimum": 1,
                "maximum": 50
            },
            "score_threshold": {
                "type": "number",
                "description": "分数阈值（0-1）",
                "minimum": 0.0,
                "maximum": 1.0
            },
            "sort_strategy": {
                "type": "string",
                "enum": ["score_desc", "score_asc", "time_desc", "time_asc", "length_desc", "length_asc", "diversity", "weighted"],
                "default": "score_desc"
            },
            "metadata_filters": {
                "type": "object",
                "description": "元数据过滤条件",
                "additionalProperties": {
                    "type": "object",
                    "properties": {
                        "operator": {
                            "type": "string",
                            "enum": ["eq", "ne", "gt", "lt", "gte", "lte", "in", "contains"]
                        },
                        "value": {}
                    }
                }
            },
            "diversity_threshold": {
                "type": "number",
                "description": "多样性阈值（用于diversity排序）",
                "default": 0.8,
                "minimum": 0.0,
                "maximum": 1.0
            }
        },
        "required": ["question"]
    }
}
```

---

## 📊 系统架构图

```mermaid
graph TB
    subgraph "客户端层"
        A[Claude Desktop] --> B[MCP Client]
        C[CLI] --> D[Direct API]
        E[Web UI] --> F[HTTP API]
    end
    
    subgraph "MCP服务层"
        B --> G[MCP Server STDIO]
        F --> H[MCP Server HTTP]
        G --> I[MCP Handlers]
        H --> I
    end
    
    subgraph "服务层 - 新增功能"
        I --> J[RAG Service]
        J --> K[Query Engine Manager]
        J --> L[Index Manager]
        J --> M[新增: Reranker]
        J --> N[新增: Analytics]
        J --> O[新增: Metadata Filter]
    end
    
    subgraph "核心层"
        K --> P[Vector Retriever]
        K --> Q[BM25 Retriever]
        K --> R[Hybrid Retriever]
        L --> S[Index Builder]
        L --> T[Index Loader]
        L --> U[新增: Incremental Updater]
    end
    
    subgraph "存储层"
        P --> V[Vector Store]
        Q --> W[BM25 Store]
        S --> V
        S --> W
        V --> X[SimpleVectorStore]
        V --> Y[Qdrant]
        N --> Z[Analytics Store]
    end
    
    style M fill:#90EE90
    style N fill:#90EE90
    style O fill:#90EE90
    style U fill:#90EE90
    style Z fill:#90EE90
```

---

## 🔄 检索流程图（增强版）

```mermaid
flowchart TD
    Start([用户查询]) --> Input[接收查询参数]
    Input --> Parse[解析参数<br/>- question<br/>- mode<br/>- top_k<br/>- score_threshold<br/>- sort_strategy<br/>- metadata_filters]
    
    Parse --> Mode{选择检索模式}
    Mode -->|vector| Vector[向量检索]
    Mode -->|bm25| BM25[BM25检索]
    Mode -->|hybrid| Hybrid[混合检索]
    
    Vector --> Results[原始结果]
    BM25 --> Results
    Hybrid --> Results
    
    Results --> Threshold{应用阈值过滤}
    Threshold -->|score_threshold| Filter1[过滤低分结果]
    Threshold -->|adaptive| Filter2[自适应阈值]
    Threshold -->|无| NoFilter[跳过]
    
    Filter1 --> MetaFilter
    Filter2 --> MetaFilter
    NoFilter --> MetaFilter
    
    MetaFilter{元数据过滤}
    MetaFilter -->|有过滤条件| ApplyMeta[应用元数据过滤器]
    MetaFilter -->|无| SkipMeta[跳过]
    
    ApplyMeta --> Sort
    SkipMeta --> Sort
    
    Sort{排序策略}
    Sort -->|score_desc| SortScore[按分数降序]
    Sort -->|time_desc| SortTime[按时间降序]
    Sort -->|diversity| SortDiv[多样性排序]
    Sort -->|weighted| SortWeight[加权排序]
    
    SortScore --> Format
    SortTime --> Format
    SortDiv --> Format
    SortWeight --> Format
    
    Format[格式化结果] --> Record[记录查询统计]
    Record --> Return([返回结果])
    
    style Filter1 fill:#FFB6C1
    style Filter2 fill:#FFB6C1
    style ApplyMeta fill:#FFB6C1
    style SortDiv fill:#FFB6C1
    style Record fill:#FFB6C1
```

---

## 📝 实施计划

### Phase 1: 核心功能增强（1-2周）

#### 任务清单：
- [ ] **配置层增强**
  - [ ] 添加分数阈值配置项
  - [ ] 添加排序策略配置项
  - [ ] 添加元数据过滤配置项
  - [ ] 更新配置验证逻辑

- [ ] **查询引擎增强**
  - [ ] 实现分数阈值过滤
  - [ ] 实现自适应阈值
  - [ ] 更新`execute_retrieve`方法

- [ ] **重排序器实现**
  - [ ] 创建`ResultReranker`类
  - [ ] 实现各种排序策略
  - [ ] 实现多样性过滤
  - [ ] 实现加权排序

- [ ] **元数据过滤器**
  - [ ] 创建`MetadataFilter`类
  - [ ] 实现过滤逻辑
  - [ ] 集成到检索流程

### Phase 2: 索引管理功能（1周）

#### 任务清单：
- [ ] **增量更新**
  - [ ] 实现`add_documents`方法
  - [ ] 实现`update_document`方法
  - [ ] 实现`delete_document`方法
  - [ ] 更新BM25索引同步逻辑

- [ ] **索引优化**
  - [ ] 实现重复文档检测
  - [ ] 实现索引压缩
  - [ ] 实现索引统计

### Phase 3: 高级检索功能（1周）

#### 任务清单：
- [ ] **批量查询**
  - [ ] 实现`batch_retrieve`方法
  - [ ] 优化批量处理性能
  - [ ] 添加进度显示

- [ ] **相似文档搜索**
  - [ ] 实现`find_similar_documents`
  - [ ] 集成向量相似度计算

### Phase 4: 监控和分析（1周）

#### 任务清单：
- [ ] **查询分析器**
  - [ ] 创建`QueryAnalytics`类
  - [ ] 实现查询记录
  - [ ] 实现统计报告生成
  - [ ] 实现热门话题分析

- [ ] **性能监控**
  - [ ] 添加查询耗时记录
  - [ ] 添加资源使用监控

### Phase 5: MCP工具和CLI（1周）

#### 任务清单：
- [ ] **MCP工具更新**
  - [ ] 更新现有工具定义
  - [ ] 添加新工具：`retrieve_with_filters`
  - [ ] 添加新工具：`batch_retrieve`
  - [ ] 添加新工具：`find_similar`
  - [ ] 添加新工具：`add_documents`
  - [ ] 添加新工具：`update_document`
  - [ ] 添加新工具：`delete_document`
  - [ ] 添加新工具：`optimize_index`
  - [ ] 添加新工具：`get_analytics`

- [ ] **CLI命令增强**
  - [ ] 添加`filter`命令
  - [ ] 添加`sort`命令
  - [ ] 添加`batch`命令
  - [ ] 添加`add`命令
  - [ ] 添加`update`命令
  - [ ] 添加`remove`命令
  - [ ] 添加`optimize`命令
  - [ ] 添加`analyze`命令
  - [ ] 添加`similar`命令

### Phase 6: 测试和文档（1周）

#### 任务清单：
- [ ] **单元测试**
  - [ ] 测试分数阈值过滤
  - [ ] 测试排序策略
  - [ ] 测试元数据过滤
  - [ ] 测试批量查询
  - [ ] 测试增量更新

- [ ] **集成测试**
  - [ ] 端到端测试
  - [ ] MCP调用测试
  - [ ] CLI命令测试

- [ ] **文档更新**
  - [ ] 更新README
  - [ ] 创建功能使用指南
  - [ ] 创建API文档
  - [ ] 创建示例代码

---

## 🎨 使用场景示例

### 场景1: 精准文档检索
```python
# 智能体需要查找高质量相关文档
result = rag_service.retrieve(
    question="深度学习的最新进展",
    mode="hybrid",
    top_k=20,
    score_threshold=0.4,  # 只要高相关度结果
    sort_strategy="diversity",  # 保证结果多样性
    diversity_threshold=0.7
)
```

### 场景2: 时间敏感查询
```python
# 查找最新的研究文档
result = rag_service.retrieve(
    question="2024年AI研究突破",
    mode="hybrid",
    top_k=10,
    sort_strategy="time_desc",  # 按时间排序
    metadata_filters={
        "created_at": {"operator": "gte", "value": "2024-01-01"},
        "file_type": {"operator": "eq", "value": "pdf"}
    }
)
```

### 场景3: 批量知识提取
```python
# 智能体需要对多个主题进行研究
questions = [
    "什么是Transformer？",
    "什么是注意力机制？",
    "什么是BERT模型？",
    "什么是GPT模型？"
]

results = rag_service.batch_retrieve(
    questions=questions,
    mode="hybrid",
    top_k=5,
    score_threshold=0.3
)

# 结果汇总分析
for q, r in zip(questions, results["results"]):
    print(f"问题: {q}")
    print(f"相关文档数: {r['count']}")
```

### 场景4: 增量知识库维护
```python
# 智能体发现新知识，需要加入知识库
rag_service.add_documents(
    documents=["新发现的AI技术：量子神经网络..."],
    metadata_list=[{
        "source": "arxiv",
        "category": "quantum_ai",
        "created_at": "2024-12-01",
        "priority": "high"
    }]
)
```

### 场景5: 智能推荐相关文档
```python
# 用户阅读某文档后，推荐相关内容
similar_docs = rag_service.find_similar_documents(
    document_id="doc_12345",
    top_k=5,
    similarity_threshold=0.6
)
```

---

## 🔧 配置示例

### .env 配置文件更新
```env
# ========== 检索增强配置 ==========
# 分数阈值
SCORE_THRESHOLD=0.0
MIN_SCORE_THRESHOLD=0.1
MAX_SCORE_THRESHOLD=0.9

# 自适应阈值
USE_ADAPTIVE_THRESHOLD=False
ADAPTIVE_THRESHOLD_PERCENTILE=0.5

# 排序策略
DEFAULT_SORT_STRATEGY=score_desc
DIVERSITY_THRESHOLD=0.8

# 批量查询
BATCH_QUERY_LIMIT=50

# 查询分析
ENABLE_QUERY_ANALYTICS=True
ANALYTICS_STORAGE_PATH=logs/query_analytics.json
```

---

## 📈 预期效果

### 功能提升
1. **检索精度提升**：通过分数阈值过滤，减少低质量结果
2. **结果多样性**：通过多样性排序，避免返回重复内容
3. **灵活性增强**：支持多种排序和过滤策略
4. **效率提升**：批量查询减少网络开销
5. **维护便利**：增量更新无需重建整个索引

### 性能指标
- **查询精度**：提升20-30%（通过阈值过滤）
- **结果多样性**：提升40%（通过diversity排序）
- **批量查询效率**：提升50%（相比单次查询）
- **索引更新时间**：减少90%（增量 vs 全量）

### 用户体验
- **更准确的结果**：只返回真正相关的文档
- **更好的可读性**：结果去重，减少冗余
- **更快的响应**：批量操作优化
- **更灵活的控制**：丰富的参数配置

---

## 🔒 注意事项

### 1. 向后兼容性
- 所有新功能都是可选的，不影响现有API
- 默认行为保持不变
- 提供平滑的迁移路径

### 2. 性能考虑
- 分数阈值过滤在检索后进行，不影响检索性能
- 多样性排序可能增加计算开销，建议在结果数较少时使用
- 批量查询应设置合理的并发限制

### 3. 存储考虑
- QueryAnalytics需要额外存储空间
- 建议定期清理旧的分析数据
- 增量更新时注意BM25索引同步

### 4. 安全性
- 文档删除操作应有权限控制
- 批量操作应限制数量，防止滥用
- 敏感元数据应加密存储

---

## 📚 参考资料

### 相关技术
- [LlamaIndex Documentation](https://docs.llamaindex.ai/)
- [BM25 Algorithm](https://en.wikipedia.org/wiki/Okapi_BM25)
- [MCP Protocol](https://modelcontextprotocol.io/)
- [Result Reranking Strategies](https://arxiv.org/abs/2104.08663)

### 实现参考
- Elasticsearch的过滤和排序机制
- Pinecone的元数据过滤
- Weaviate的混合检索

---

## 📞 联系方式

如有问题或建议，请通过以下方式联系：
- 提交 GitHub Issue
- 发送 Pull Request
- 项目讨论区

---

**方案版本**: v1.0  
**创建日期**: 2026-01-09  
**最后更新**: 2026-01-09
