RAG_V2_PLAN.md 5.9 KB

RAG v2: BM25 + Embedding + Rerank 混合检索方案

Context

当前 RAG 系统使用 BM25 关键词检索,存在核心缺陷:搜索"海上交通安全法与水污染防治法"时检索到行政检查清单而非法律原文,因为 BM25 只看关键词共现频率,无法理解语义。用户提议引入 qwen-embedding-v4 + qwen-rerank-8B + RRF 混合检索,预期显著提升检索准确性。

方案概览

查询
  ├─► BM25 检索 (现有 search_engine.py) → 排名列表 A
  ├─► 向量检索 (qwen-embedding-v4) → 排名列表 B
  └─► RRF 融合 (k=60) → top-20 候选
       └─► Rerank (qwen-rerank-8B) → 过滤 threshold=0.5 → top-5 结果

新增/修改文件清单

新增 3 个文件

文件 用途
qaagent67/scripts/search_engine_v2.py 混合检索引擎 (BM25+向量+RRF+Rerank)
qaagent67/scripts/build_vector_index.py 向量索引构建 (重新分块+调 embedding API)
qaagent67/scripts/rebuild_index_v2.py BM25 索引重建 (适配新分块参数)

修改 2 个文件

文件 改动
qaagent67/agent-config.yml 新增 rag.hybrid/embedding/rerank 配置段
qademo/app.py 改 1 行 import: from search_enginefrom search_engine_v2

不动的文件 (保留)

文件 说明
qaagent67/scripts/search_engine.py 现有 BM25 引擎,被 v2 内部调用
qaagent67/scripts/rebuild_index.py 现有索引构建,保留为参考
knowledge/maritime/rag_index.pkl 现有 BM25 索引,保留为 fallback
knowledge/maritime/rag_keywords.pkl 现有关键词索引,保留为 fallback

详细设计

1. build_vector_index.py — 向量索引构建

分块参数:

  • 分段符: \n\n
  • 最大长度: 1024 token (≈1024 中文字符)
  • 重叠: 200 token
  • 保留表格完整性 ([TABLE_START]...[TABLE_END])

流程:

  1. 读 processed/*.txt → 用新参数分块 → ~50-60K chunks
  2. 每 16 个 chunk 一批调 SiliconFlow embedding API
  3. 保存: rag_vectors_v2.npy (numpy float32 [N, dim]) + rag_vectors_meta_v2.pkl
  4. 同时构建新 BM25 索引: rag_index_v2.pkl + rag_keywords_v2.pkl
  5. 支持断点续传 (checkpoint 每 500 批)

API 调用:

POST https://api.siliconflow.cn/v1/embeddings
{"model": "Pro/Qwen/Qwen3-Embedding-0.6B", "input": ["text1", ...], "encoding_format": "float"}

预估:

  • ~55K chunks × 500 tokens = 27.5M tokens ≈ $0.30 一次性成本
  • 3,437 批 × 0.1s = ~6 分钟

2. search_engine_v2.py — 混合检索引擎

核心函数:

def search(query, top_k=5):
    # 1. BM25 检索 (调现有 search_engine.search)
    bm25_results = bm25_search(query, top_k=20)
    
    # 2. 向量检索 (embed query → cosine similarity)
    query_vec = _embed_query(query)
    vector_results = _vector_search(query_vec, top_k=20)
    
    # 3. RRF 融合
    fused = _rrf_fuse(bm25_results, vector_results, k=60)  # top-20
    
    # 4. Rerank
    reranked = _rerank(query, fused[:20])
    
    # 5. 过滤 threshold + 返回 top-k
    return [r for r in reranked if r['score'] >= 0.5][:top_k]

降级策略:

  • 向量索引不存在 → 纯 BM25
  • Embedding API 超时 → 纯 BM25
  • Rerank API 超时 → 跳过 rerank,直接用 RRF 结果

返回格式: 与现有 search() 完全一致: {source, chunk_id, score, text}

3. agent-config.yml 新增配置

rag:
  enabled: true
  collection: maritime_rag
  chunkSize: 1024
  chunkOverlap: 200
  chunkSeparator: "\n\n"
  topK: 5
  
  hybrid:
    enabled: true
    rrfK: 60
    rerankCandidates: 20
    similarityThreshold: 0.5
  
  embedding:
    model: Pro/Qwen/Qwen3-Embedding-0.6B
    baseUrl: https://api.siliconflow.cn/v1
    apiKeyEnv: SILICONFLOW_API_KEY
    batchSize: 16
  
  rerank:
    model: Pro/Qwen/Qwen3-Reranker-0.6B
    baseUrl: https://api.siliconflow.cn/v1
    apiKeyEnv: SILICONFLOW_API_KEY
    topN: 5

4. app.py 改动 (1 行)

# Before:
from search_engine import search

# After:
try:
    from search_engine_v2 import search
except ImportError:
    from search_engine import search

5. 存储格式

文件 格式 大小估算
rag_vectors_v2.npy numpy float32 [N, dim] ~225 MB (55K×1024×4)
rag_vectors_meta_v2.pkl pickle list of (source, chunk_id, text) ~50 MB
rag_index_v2.pkl pickle BM25 索引 ~30 MB
rag_keywords_v2.pkl pickle 关键词倒排 ~20 MB

不依赖向量数据库 — numpy brute-force cosine similarity 对 55K chunks 只需 <100ms。

6. 依赖

仅新增 numpy,已在 Docker 镜像的 pip install 中。无需 chromadb/faiss 等。

7. Docker 部署

# 构建索引 (一次性)
docker exec qademo python3 /app/agentexample/qaagent67/scripts/build_vector_index.py

# 重启 Web 服务 (自动使用 v2)
docker restart qademo

环境变量: SILICONFLOW_API_KEY=<your-key> (申请: https://cloud.siliconflow.cn/account/ak

影响分析

方面 影响
现有 BM25 代码 不动,被 v2 内部调用
Web 前端 无改动
Wiki 模式 不受影响
查询延迟 +200-500ms (embed+rerank API)
首次加载 ~2s (numpy mmap) vs 6s (pickle BM25)
索引构建 一次性 ~6 分钟 + ~$0.30
每次查询成本 ~$0.001 (1次embed + 1次rerank)

验证方式

  1. 单元测试: python search_engine_v2.py "海上交通安全法与水污染防治法" — 应检索到法律原文
  2. 对比测试: 同一问题 v1 vs v2 结果对比
  3. Web 测试:http://qa.lambdagent.cn:8080 提问验证
  4. 降级测试: 停掉 SiliconFlow API,验证 fallback 到 BM25

实施顺序

  1. 先验证 SiliconFlow embedding/rerank API 可用性 (curl 测试)
  2. 更新 agent-config.yml
  3. 编写 build_vector_index.py + 构建索引
  4. 编写 search_engine_v2.py
  5. 修改 app.py (1 行)
  6. 部署到 Docker + 验证