Files
ailine/app/rag/README.md
root 8d4fc76a95
Some checks failed
构建并部署 AI Agent 服务 / deploy (push) Failing after 6m16s
修改容器生成
2026-04-21 00:00:56 +08:00

16 KiB
Raw Blame History

在线 RAG 检索与生成系统 (Online RAG Retriever)

该模块负责 RAG 系统的阶段二:在线检索与生成。它接收用户提问,从知识库中检索出上下文,利用各种高级策略去噪、融合,并作为增强上下文输入给大语言模型 (LLM)。

🎯 核心架构

技术栈

组件 技术选型 版本 说明
基础检索 Qdrant 1.17+ HNSW 稠密向量检索
混合检索 Qdrant + BM25 内置 稠密 + 稀疏向量融合
查询改写 LangChain 内置 MultiQueryGenerator 多路改写
RRF 融合 自实现 - reciprocal_rank_fusion 倒数排名融合
重排序 llama.cpp 本地服务 OpenAI 兼容 Rerank API
编排框架 asyncio Python 3.10+ 异步并行检索

检索流水线

┌─────────────────────────────────────────────────────────────┐
│                      用户提问                                │
└──────────────────────┬──────────────────────────────────────┘
                       │
                       ▼
┌─────────────────────────────────────────────────────────────┐
│              MultiQueryGenerator                             │
│           多路查询改写 (num_queries=3)                        │
│   "如何申请项目资金?" → ["项目资金申请流程", "经费申请步骤"]  │
└──────────────────────┬──────────────────────────────────────┘
                       │
                       ▼
┌─────────────────────────────────────────────────────────────┐
│              并行检索 (asyncio.gather)                        │
│  ┌──────────────┐  ┌──────────────┐  ┌──────────────┐       │
│  │  查询1 检索   │  │  查询2 检索   │  │  查询3 检索   │       │
│  │  (k=20)      │  │  (k=20)      │  │  (k=20)      │       │
│  └──────────────┘  └──────────────┘  └──────────────┘       │
└──────────────────────┬──────────────────────────────────────┘
                       │
                       ▼
┌─────────────────────────────────────────────────────────────┐
│           reciprocal_rank_fusion (RRF)                       │
│   RRF_score(d) = Σ 1/(k + rank_q(d))  (k=60)                │
│   融合多路检索结果,去重排序                                  │
└──────────────────────┬──────────────────────────────────────┘
                       │
                       ▼
┌─────────────────────────────────────────────────────────────┐
│              LLaMaCPPReranker                                │
│   远程重排序 (bge-reranker-v2-m3)                             │
│   返回 Top-N (top_n=5) 最相关文档                             │
└──────────────────────┬──────────────────────────────────────┘
                       │
                       ▼
┌─────────────────────────────────────────────────────────────┐
│              返回增强上下文                                  │
│   format_context() → 格式化输出                               │
└─────────────────────────────────────────────────────────────┘

技术特性

  • 多路查询改写:通过 LLM 将单一问题改写为多个不同角度的查询
  • RRF 融合算法Reciprocal Rank Fusion无需评分归一化的融合算法
  • 远程重排序:使用 llama.cpp 服务的 OpenAI 兼容 Rerank API
  • 混合检索支持:稠密向量 + BM25 稀疏向量混合检索
  • 异步并行检索:多路查询并行执行,提升检索速度
  • 优雅降级:重排序器不可用时自动降级到基础融合结果

📂 架构与文件结构

app/rag/
├── __init__.py
├── retriever.py          # Qdrant 基础检索与混合检索
├── reranker.py           # llama.cpp 远程重排序器
├── query_transform.py    # 多路查询改写生成器
├── fusion.py             # RRF 倒数排名融合算法
├── pipeline.py           # RAG 流水线编排
└── tools.py              # LangChain Tool 封装

🎯 演进路线与算法详解 (Roadmap)

  • 核心算法: 近似最近邻搜索 (ANN, 常用 HNSW 算法)。将用户问题转化为向量后,计算它与库中向量的余弦相似度 (Cosine Similarity),取距离最近的 K 个块。
  • 优缺点: 速度极快。但只能捕捉"语义相似",如果用户搜索特定专有名词、编号、订单号,纯向量检索往往会失效(产生"幻觉"匹配)。
  • 实现指南:
    • 使用 rag_indexer.embedders.LlamaCppEmbedder 作为嵌入模型
    • 使用 app/rag/retriever.py 中的 create_base_retriever 创建基础检索器
    • 配置 search_kwargs={"k": 20} 进行初步召回
from app.rag.retriever import create_base_retriever

retriever = create_base_retriever(
    collection_name="rag_documents",
    embeddings=embeddings,
    search_kwargs={"k": 20}
)
docs = retriever.invoke("什么是 RAG")

Level 2: 混合检索与重排序 (Hybrid Search + Reranker)

混合检索旨在结合向量的"语义泛化"与关键词的"精准匹配",随后利用重排序模型过滤噪声。

1. 基础召回 (混合检索)

  • 核心原理: 结合基于 HNSW 的 Dense Vector 相似度搜索与基于 TF-IDF 的 BM25 稀疏检索 (Sparse Vector)。
  • 实现指南: 使用 app/rag/retriever.py 中的 create_hybrid_retriever 函数,配置 dense_k=10sparse_k=10,总召回 20 条结果。
from app.rag.retriever import create_hybrid_retriever

retriever = create_hybrid_retriever(
    collection_name="rag_documents",
    embeddings=embeddings,
    dense_k=10,
    sparse_k=10,
    score_threshold=0.3
)

2. 二次精排 (Cross-Encoder)

  • 核心原理: 不同于双塔模型(分别算向量再求距离),交叉编码器将"用户问题 + 检索到的单例文档"拼接后整体输入 Transformer 模型,由模型直接输出 0~1 的相关性得分,精度极高。
  • 实现指南:
    • 使用 app/rag/reranker.py 中的 LLaMaCPPReranker 类,加载 bge-reranker-v2-m3 模型
    • 设置 top_n=5 保留最相关的 5 条结果
from app.rag.reranker import LLaMaCPPReranker

reranker = LLaMaCPPReranker(
    base_url="http://127.0.0.1:8083",
    api_key="your-api-key",
    top_n=5
)
sorted_docs = reranker.compress_documents(documents, query)

Level 3: RAG-Fusion (多路改写与倒数排名融合)

RAG-Fusion 通过大模型发散思维,将单一问题改写为多个相似问题,扩大搜索面,再利用数学统计算法合并结果。

1. 多路查询改写

  • 核心原理: 克服用户初始提问词不达意或视角受限的问题。
  • 实现指南: 使用 app/rag/query_transform.py 中的 MultiQueryGenerator 类,配置 num_queries=3 生成 3 个不同角度的查询。
from app.rag.query_transform import MultiQueryGenerator

generator = MultiQueryGenerator(llm=llm, num_queries=3)
queries = await generator.agenerate("如何申请项目资金?")
# 返回:["如何申请项目资金?", "项目资金申请流程是什么?", "申请项目经费需要哪些步骤?"]

2. 倒数排名融合 (RRF)

  • 核心原理: RRF (Reciprocal Rank Fusion) 是一种无需评分归一化的融合算法。公式为 RRF_score(d) = Σ 1/(k + rank_q(d)),有效避免某一极端检索结果主导全局。
  • 实现指南: 使用 app/rag/fusion.py 中的 reciprocal_rank_fusion 函数,配置 k=60 实现倒数排名融合。
from app.rag.fusion import reciprocal_rank_fusion

# 多个查询的检索结果
doc_lists = [result1, result2, result3]
fused_docs = reciprocal_rank_fusion(doc_lists, k=60)

Level 4: Agentic RAG / Self-RAG (智能体与自我反思)

  • 核心原理: 基于 LangGraph 的 ReAct (Reasoning and Acting) 状态机路由。大模型并非每次都去死板地执行检索,而是先判断问题:"这是闲聊?还是需要查知识库?"。如果是后者,模型输出一个 ToolCall 指令,触发检索。

  • 实现指南: 使用 app/rag/tools.py 中的 search_knowledge_base 工具,将其绑定到 LangGraph 状态机中。

  • 示意图:

┌──────────┐     ┌──────────────┐     ┌──────────┐     ┌────────
│   User   │────>│ LangGraph    │────>│ RAG_Tool │────>│ Qdrant │
│          │     │ Agent        │     │          │     │        │
│ "公司报  │     │ 思考: 这是   │     │ ToolCall │     │ RAG-   │
│ 销流程?"│     │ 内部规章问题 │     │ search_  │     │ Fusion │
│          │     │ 需要查资料   │     │ knowledge│     │ & 混合 │
│          │<────│ 资料充分,   │<────│ 返回最相 │<────│ 检索   │
│ "根据知  │     │ 开始撰写回答 │     │ 关5条规定 │     │ Cross- │
│ 识库规定 │     │              │     │          │     │ Encoder│
│ ..."     │     │              │     │          │     │ 重排   │
└──────────     └──────────────     └──────────┘     └────────┘

Level 5: GraphRAG 集成 (基于图和关系的 RAG)

  • 核心原理: 结合知识图谱的结构化关系和向量检索的语义相似度,解决跨文档复杂关系推理问题。
  • 实现指南:
    • 使用 langchain_community.graphs 模块构建知识图谱
    • 配置本地大模型(如 Gemma-4-E4B)用于实体关系抽取
    • 实现混合检索逻辑,结合向量相似度和图路径分析
from langchain_community.graphs import Neo4jGraph
from langchain_experimental.graph_transformers import LLMGraphTransformer

# 实体关系抽取
transformer = LLMGraphTransformer(llm=local_llm)
graph_documents = transformer.convert_to_graph_documents(documents)

# 存储到图数据库
graph = Neo4jGraph(url="bolt://localhost:7687")
graph.add_graph_documents(graph_documents)

🔧 核心组件详解

1. 检索器 (retriever.py)

提供基于 Qdrant 的向量检索能力。

基础检索器

from app.rag.retriever import create_base_retriever

retriever = create_base_retriever(
    collection_name="rag_documents",
    embeddings=embeddings,
    search_kwargs={"k": 20}
)

混合检索器

from app.rag.retriever import create_hybrid_retriever

retriever = create_hybrid_retriever(
    collection_name="rag_documents",
    embeddings=embeddings,
    dense_k=10,
    sparse_k=10,
    score_threshold=0.3
)

2. 多路查询改写 (query_transform.py)

通过 LLM 将用户问题改写为多个不同版本,扩大搜索面。

from app.rag.query_transform import MultiQueryGenerator

generator = MultiQueryGenerator(llm=llm, num_queries=3)
queries = await generator.agenerate("如何申请项目资金?")

3. RRF 融合算法 (fusion.py)

Reciprocal Rank Fusion 算法,公式:RRF_score(d) = Σ 1/(k + rank_q(d))

from app.rag.fusion import reciprocal_rank_fusion

# 多个查询的检索结果
doc_lists = [result1, result2, result3]
fused_docs = reciprocal_rank_fusion(doc_lists, k=60)

4. 重排序器 (reranker.py)

使用 llama.cpp 服务的 OpenAI 兼容 Rerank API 对检索结果重排序。

from app.rag.reranker import LLaMaCPPReranker

reranker = LLaMaCPPReranker(
    base_url="http://127.0.0.1:8083",
    api_key="your-api-key",
    top_n=5
)
sorted_docs = reranker.compress_documents(documents, query)

5. RAG 流水线 (pipeline.py)

组合上述组件的完整检索流水线。

from app.rag.pipeline import RAGPipeline

pipeline = RAGPipeline(
    retriever=retriever,
    llm=llm,
    num_queries=3,
    rerank_top_n=5,
)

# 异步检索
docs = await pipeline.aretrieve("如何申请项目资金?")

# 格式化上下文
context = pipeline.format_context(docs)

🔄 与 Agent 系统集成

封装为 LangChain Tool

from langchain_core.tools import tool
from app.rag.pipeline import RAGPipeline

@tool
def search_knowledge_base(query: str) -> str:
    """搜索知识库获取相关信息"""
    docs = pipeline.retrieve(query)
    return pipeline.format_context(docs)

绑定到 LangGraph

from app.graph.graph_builder import GraphBuilder

# 将 RAG 工具添加到工具列表
tools = AVAILABLE_TOOLS + [search_knowledge_base]

# 构建图
builder = GraphBuilder(llm, tools, tools_by_name)
graph = builder.build().compile(checkpointer=checkpointer)

⚙️ 环境配置

变量名 说明 默认值
QDRANT_URL Qdrant 向量数据库地址 http://127.0.0.1:6333
QDRANT_API_KEY Qdrant API 密钥 -
LLAMACPP_RERANKER_URL llama.cpp 重排序服务地址 http://127.0.0.1:8083
LLAMACPP_API_KEY llama.cpp API 密钥 -

🚀 快速开始

# 1. 初始化嵌入模型
from rag_core.embedders import LlamaCppEmbedder
embedder = LlamaCppEmbedder()
embeddings = embedder.as_langchain_embeddings()

# 2. 创建检索器
from app.rag.retriever import create_base_retriever
retriever = create_base_retriever(
    collection_name="rag_documents",
    embeddings=embeddings,
    search_kwargs={"k": 20}
)

# 3. 创建 RAG 流水线
from app.rag.pipeline import RAGPipeline
pipeline = RAGPipeline(
    retriever=retriever,
    llm=llm,
    num_queries=3,
    rerank_top_n=5,
)

# 4. 执行检索
docs = pipeline.retrieve("如何申请项目资金?")

# 5. 格式化上下文
context = pipeline.format_context(docs)
print(context)

📊 检索策略对比

策略 优点 缺点 适用场景
基础向量检索 速度快,语义理解好 专有名词匹配差 通用问答
混合检索 语义 + 关键词匹配 需要配置稀疏向量 专业术语查询
多路改写 + RRF 搜索面广,结果稳定 延迟略高 复杂问题
重排序 精度高 依赖额外模型 最终精排

🤝 与 rag_indexer 集成

  • 向量存储:共享 Qdrant 集合,确保嵌入模型一致
  • 文档存储:使用 PostgreSQL 存储父块,通过 UUID 映射
  • 集合名称:默认使用 rag_documents 集合

详见 rag_indexer/README.md