RAG知识点_3_高级实践

RAG 知识点(三):高级实践与前沿技术

1. 双 Collection 架构

定义

双 Collection 架构是指同时维护两个向量集合:文档切片集合(document_chunks)和问答对集合(qa_pairs),并行检索后合并上下文。

为什么需要双 Collection

单一集合(仅文档切片)的局限:

  • 只能检索到原始文本片段
  • 无法利用已有的结构化问答对
  • 缺失"推理过程"等半结构化信息

双集合架构的优势:

  • document_chunks:提供"原始证据"
  • qa_pairs:提供"已整理的知识"和"推理过程"

架构示意

复制代码
用户问题
   ├──→ document_chunks 混合检索 → 文档片段
   └──→ qa_pairs 混合检索 → 相关问答对
             ↓
      上下文合并 + LLM 生成
             ↓
      带引用来源的答案

代码示例

python 复制代码
from pymilvus import MilvusClient, DataType, Function, FunctionType, AnnSearchRequest

client = MilvusClient(uri="http://localhost:19530")

# --- Collection 1: 文档切片 ---
doc_schema = client.create_schema()
doc_schema.add_field(field_name="id", datatype=DataType.INT64, is_primary=True, auto_id=True)
doc_schema.add_field(field_name="text", datatype=DataType.VARCHAR, max_length=2000,
                     enable_analyzer=True, enable_match=True)
doc_schema.add_field(field_name="file_name", datatype=DataType.VARCHAR, max_length=200)
doc_schema.add_field(field_name="dense_vector", datatype=DataType.FLOAT_VECTOR, dim=1024)
doc_schema.add_field(field_name="sparse_vector", datatype=DataType.SPARSE_FLOAT_VECTOR)

bm25_fn = Function(name="text_bm25", input_field_names=["text"],
                   output_field_names=["sparse_vector"], function_type=FunctionType.BM25)
doc_schema.add_function(bm25_fn)

# --- Collection 2: 问答对 ---
qa_schema = client.create_schema()
qa_schema.add_field(field_name="qa_id", datatype=DataType.INT64, is_primary=True, auto_id=True)
qa_schema.add_field(field_name="question", datatype=DataType.VARCHAR, max_length=1000,
                    enable_analyzer=True, enable_match=True)
qa_schema.add_field(field_name="answer", datatype=DataType.VARCHAR, max_length=2000)
qa_schema.add_field(field_name="reasoning", datatype=DataType.VARCHAR, max_length=2000)
qa_schema.add_field(field_name="dense_vector", datatype=DataType.FLOAT_VECTOR, dim=1024)
qa_schema.add_field(field_name="sparse_vector", datatype=DataType.SPARSE_FLOAT_VECTOR)

bm25_fn2 = Function(name="question_bm25", input_field_names=["question"],
                    output_field_names=["sparse_vector"], function_type=FunctionType.BM25)
qa_schema.add_function(bm25_fn2)

# --- 并行检索 ---
def dual_collection_search(query, query_vector, top_k=3):
    """同时对两个集合执行混合检索"""
    def hybrid_search(collection_name, output_fields):
        req_dense = AnnSearchRequest(data=[query_vector], anns_field="dense_vector",
                                     param={"nprobe": 10}, limit=top_k)
        req_sparse = AnnSearchRequest(data=[query], anns_field="sparse_vector",
                                      param={"metric_type": "BM25"}, limit=top_k)
        ranker = Function(name="rrf", function_type=FunctionType.RERANK,
                          params={"reranker": "rrf", "k": 100}, input_field_names=[])
        return client.hybrid_search(collection_name=collection_name,
                                    reqs=[req_dense, req_sparse], ranker=ranker,
                                    limit=top_k, output_fields=output_fields)

    doc_results = hybrid_search("documents", ["text", "file_name"])
    qa_results = hybrid_search("qa_pairs", ["question", "answer", "reasoning"])
    return doc_results, qa_results

关键要点

  1. 两个集合各有职责,各自独立支持混合检索
  2. 并行检索不增加延迟
  3. QA 对中的 reasoning 字段帮助 LLM 理解"为什么是这个答案"
  4. 每个检索结果标记来源,便于溯源

2. RAG 系统评估(RAGAS)

定义

RAGAS(Retrieval Augmented Generation Assessment)是评估 RAG 系统质量的框架。通过四大指标量化评估检索和生成质量,告别"凭感觉"。

四大核心指标

指标 评估对象 含义 目标
Context Precision 检索器 检索到的文档中有多少是真正相关的? 越高越好(避免噪音)
Context Recall 检索器 所有相关文档中被检索出来的比例 越高越好(避免遗漏)
Faithfulness LLM 生成 回答是否基于检索内容,没有编造? 越高越好(减少幻觉)
Answer Relevancy LLM 生成 回答是否真正解决了问题? 越高越好(答非所问扣分)

指标关系图

复制代码
用户问题
   ↓
[检索器] → Context Precision + Context Recall
   ↓
检索上下文 + 问题
   ↓
[LLM 生成] → Faithfulness + Answer Relevancy
   ↓
最终答案

代码示例(简化版评估器)

python 复制代码
class RAGEvaluator:
    def context_precision(self, retrieved_docs, relevant_docs):
        """精确率 = 检索到且相关的 / 检索到的"""
        if not retrieved_docs: return 0.0
        relevant_set = set(relevant_docs)
        return len(set(retrieved_docs) & relevant_set) / len(set(retrieved_docs))

    def context_recall(self, retrieved_docs, relevant_docs):
        """召回率 = 检索到且相关的 / 所有相关的"""
        if not relevant_docs: return 1.0
        return len(set(retrieved_docs) & set(relevant_docs)) / len(set(relevant_docs))

    def faithfulness_score(self, llm_answer, context_docs):
        """忠实度(简化版):答案内容在上下文中的覆盖率"""
        context_text = " ".join(context_docs)
        sentences = [s.strip() for s in llm_answer.replace("!","。").replace("?","。").split("。") if s.strip()]
        supported = sum(1 for s in sentences if any(s[i:i+4] in context_text for i in range(max(0, len(s)-3))))
        return supported / len(sentences) if sentences else 0.0

    def answer_relevancy_score(self, question, llm_answer):
        """答案相关性(简化版):答案中包含问题关键词的比例"""
        q_chars = question.replace(" ","").replace("?","")
        keywords = set(q_chars[i:i+2] for i in range(len(q_chars)-1))
        return sum(1 for kw in keywords if kw in llm_answer) / len(keywords) if keywords else 1.0

# 使用
evaluator = RAGEvaluator()
precision = evaluator.context_precision(["doc1", "doc2"], ["doc1", "doc3"])
recall = evaluator.context_recall(["doc1", "doc2"], ["doc1", "doc3"])
print(f"精确率:{precision:.2f},召回率:{recall:.2f}")

评估最佳实践

  1. 建立基线:改参数前先跑一次完整评估,记录基线分数
  2. 每次只改一个变量:不要同时改 Embedding + 切片参数 + LLM
  3. 评估数据集:最少 20 条,推荐 50-100 条
  4. 自动化:集成到 CI/CD,每次 PR 自动跑评估
  5. 人工抽查不可替代:定期人工检查 10-20 条回答质量

推荐评估工具

bash 复制代码
pip install ragas       # 最流行的 RAG 评估库
pip install deepeval    # DeepEval
pip install trulens-eval  # TruLens

3. Self-RAG(自反思 RAG)

定义

Self-RAG 让 LLM 在生成过程中自我判断:是否需要检索?检索到的内容是否相关?生成的内容是否被检索内容支持?通过"反思 Token"实现自我纠错。

核心流程

复制代码
用户问题
   ↓
[判断] 是否需要检索?
   ├── 不需要 → 直接生成
   └── 需要 → 执行检索
              ↓
         [判断] 检索结果是否相关?
              ├── 相关 → 基于检索结果生成
              └── 不相关 → 换种方式检索或放弃
                        ↓
                   [判断] 生成内容是否被支持?
                        ├── 支持 → 输出答案
                        └── 不支持 → 重新生成或修正

代码示例(简化实现)

python 复制代码
class SelfRAG:
    def __init__(self, llm_client, retrieval_fn):
        self.llm = llm_client
        self.retrieve = retrieval_fn

    def query(self, question):
        # Step 1: 判断是否需要检索
        need_retrieval = self._judge_need_retrieval(question)

        context = ""
        if need_retrieval:
            docs = self.retrieve(question)
            # Step 2: 判断检索结果是否相关
            relevant_docs = [d for d in docs if self._judge_relevance(question, d)]
            if relevant_docs:
                context = "\n".join(relevant_docs)

        # Step 3: 生成答案
        answer = self._generate(question, context)

        # Step 4: 判断答案是否被上下文支持
        if context and not self._judge_support(answer, context):
            answer = self._generate(question, context, instruction="仅基于上下文回答")

        return answer

    def _judge_need_retrieval(self, question):
        """判断问题是否需要检索外部知识"""
        resp = self.llm.chat.completions.create(model="qwen-plus", messages=[
            {"role": "user", "content": f"回答这个问题是否需要查找外部资料?只回答是或否:{question}"}
        ])
        return "是" in resp.choices[0].message.content

    def _judge_relevance(self, question, doc):
        """判断检索结果是否与问题相关"""
        resp = self.llm.chat.completions.create(model="qwen-plus", messages=[
            {"role": "user", "content": f"以下内容是否与问题相关?只回答是或否\n问题:{question}\n内容:{doc}"}
        ])
        return "是" in resp.choices[0].message.content

    def _judge_support(self, answer, context):
        """判断答案是否被上下文支持"""
        resp = self.llm.chat.completions.create(model="qwen-plus", messages=[
            {"role": "user", "content": f"以下答案是否完全基于上下文?只回答是或否\n上下文:{context}\n答案:{answer}"}
        ])
        return "是" in resp.choices[0].message.content

4. Corrective RAG(校正 RAG)

定义

Corrective RAG (CRAG) 在检索结果和生成结果之间增加一个评估器。如果检索质量低,则触发网络搜索作为后备方案,避免用低质量上下文生成答案。

核心流程

复制代码
用户问题 → 检索 → [评估器] 检索质量如何?
                      ├── 高质量 → 正常生成
                      ├── 低质量 → 触发网络搜索 → 合并结果 → 生成
                      └── 模糊 → 同时检索 + 网络搜索 → 融合 → 生成

代码示例

python 复制代码
class CorrectiveRAG:
    def __init__(self, llm_client, retrieval_fn, web_search_fn):
        self.llm = llm_client
        self.retrieve = retrieval_fn
        self.web_search = web_search_fn

    def query(self, question, threshold=0.5):
        # Step 1: 执行检索
        docs = self.retrieve(question)

        # Step 2: 评估检索质量
        quality_score = self._evaluate_retrieval_quality(question, docs)

        # Step 3: 根据质量决策
        if quality_score >= threshold:
            # 高质量:正常生成
            context = "\n".join(docs)
        else:
            # 低质量:触发网络搜索作为后备
            web_results = self.web_search(question)
            context = "\n".join(docs + web_results)

        # Step 4: 生成答案
        return self._generate(question, context)

    def _evaluate_retrieval_quality(self, question, docs):
        """评估检索质量(0-1 分)"""
        resp = self.llm.chat.completions.create(model="qwen-plus", messages=[
            {"role": "user",
             "content": f"评估以下检索结果对问题的相关性,输出0-1之间的分数:\n问题:{question}\n结果:{docs}"}
        ])
        try:
            return float(resp.choices[0].message.content.strip())
        except:
            return 0.3  # 默认低分

5. GraphRAG(图增强 RAG)

定义

GraphRAG 通过离线构建知识图谱(实体+关系),在检索时进行子图遍历,支持跨文档、跨章节的实体关系推理。解决了传统向量检索无法处理全局性问题(如"总结所有文档的主题")的缺陷。

与传统 RAG 对比

维度 传统 RAG GraphRAG
知识表示 文本切片 实体 + 关系 + 文本
检索方式 向量相似度 子图遍历 + 语义匹配
全局性问题 难以处理 天然支持
多跳推理 需要多轮检索 图遍历一次完成
构建成本 高(需抽取实体和关系)

代码示例(简化版)

python 复制代码
class SimpleGraphRAG:
    def __init__(self, llm_client, milvus_client):
        self.llm = llm_client
        self.milvus = milvus_client
        self.graph = {}  # entity -> [(relation, target_entity)]

    def build_graph(self, documents):
        """从文档中抽取实体和关系,构建知识图谱"""
        for doc in documents:
            resp = self.llm.chat.completions.create(model="qwen-plus", messages=[
                {"role": "user", "content": f"""从以下文本中抽取实体和关系,JSON格式:
                {{"entities": ["实体1", "实体2"], "relations": [{{"head": "实体1", "relation": "关系", "tail": "实体2"}}]}}
                文本:{doc}"""}
            ])
            # 解析并构建图
            import json
            try:
                data = json.loads(resp.choices[0].message.content)
                for rel in data.get("relations", []):
                    head, relation, tail = rel["head"], rel["relation"], rel["tail"]
                    self.graph.setdefault(head, []).append((relation, tail))
            except:
                pass

    def query(self, question, max_hops=2):
        """先定位实体,再沿图遍历获取关联信息"""
        # Step 1: 从问题中提取关键实体
        entities = self._extract_entities(question)

        # Step 2: 沿图遍历
        visited = set()
        results = []
        for entity in entities:
            self._traverse(entity, max_hops, 0, visited, results)

        # Step 3: 用遍历结果作为上下文生成答案
        context = "\n".join(results)
        return self._generate(question, context)

    def _traverse(self, entity, max_hops, current_hop, visited, results):
        """递归遍历知识图谱"""
        if entity in visited or current_hop > max_hops:
            return
        visited.add(entity)
        for relation, target in self.graph.get(entity, []):
            results.append(f"{entity} --[{relation}]--> {target}")
            self._traverse(target, max_hops, current_hop + 1, visited, results)

轻量化变体

  • LightRAG:减少图谱构建成本,适合中小规模
  • nano-GraphRAG:极简实现,适合快速验证
  • KAG:知识增强生成,结合规则和图谱

6. Agentic RAG(代理化 RAG)

定义

Agentic RAG 是 2026 年 RAG 技术的最新范式。LLM 不再是"被检索喂数据的答题者",而是"检索决策者"。Agent 根据问题复杂度自主决定:是否需要检索?使用什么工具?何时停止迭代?

核心架构

复制代码
用户问题 → Agent 决策循环
              ↓
         [思考] 下一步做什么?
              ├── 直接回答(信息够)
              ├── 调用向量检索工具
              ├── 调用图谱检索工具
              ├── 调用 SQL 查询工具
              ├── 调用网络搜索工具
              └── 请求用户澄清
              ↓
         [执行] 调用工具获取结果
              ↓
         [评估] 信息是否充分?
              ├── 充分 → 生成答案
              └── 不充分 → 继续决策循环

代码示例

python 复制代码
class AgenticRAG:
    def __init__(self, llm_client, tools):
        self.llm = llm_client
        self.tools = tools        # {"vector_search": ..., "graph_search": ..., "web_search": ...}
        self.max_iterations = 10
        self.confidence_threshold = 0.85

    def query(self, user_question):
        context = {"question": user_question, "retrieved": [], "iterations": 0}

        for iteration in range(self.max_iterations):
            # Step 1: Agent 思考下一步
            action = self._think(context)

            if action["type"] == "answer":
                return action["content"]

            elif action["type"] == "tool_call":
                # Step 2: 调用检索工具
                tool = self.tools[action["tool"]]
                result = tool.execute(action["params"])
                context["retrieved"].append({"tool": action["tool"], "result": result})

                # Step 3: 评估信息充分性
                if self._is_sufficient(context) and iteration >= 1:
                    return self._generate_final_answer(context)

            elif action["type"] == "clarify":
                return {"type": "clarification", "question": action["question"]}

        # 超过最大迭代次数,强制生成
        return self._generate_final_answer(context)

    def _think(self, context):
        """Agent 决策:基于当前上下文决定下一步"""
        prompt = f"""你是 RAG 检索代理。根据当前状态决定下一步:
        问题:{context['question']}
        已检索信息:{context['retrieved'][-3:] if context['retrieved'] else '无'}
        可用工具:{list(self.tools.keys())}

        返回 JSON:{{"type": "answer/tool_call/clarify", "content/tool/params/question": ...}}"""

        resp = self.llm.chat.completions.create(model="qwen-plus", messages=[
            {"role": "user", "content": prompt}
        ])
        return self._parse_action(resp.choices[0].message.content)

    def _is_sufficient(self, context):
        """评估已收集信息是否充分"""
        resp = self.llm.chat.completions.create(model="qwen-plus", messages=[
            {"role": "user",
             "content": f"基于以下信息能否回答问题?只回答是或否\n问题:{context['question']}\n信息:{context['retrieved']}"}
        ])
        return "是" in resp.choices[0].message.content

Agentic RAG vs 传统 RAG 对比

维度 传统 RAG Agentic RAG
检索策略 固定流水线 动态决策
工具选择 预定义 Agent 自主选择
迭代次数 单次 多轮,直到满意
复杂问题 难以处理 逐步分解
适用场景 简单问答 企业级 Copilot

7. TreeRAG(树状结构 RAG)

定义

TreeRAG 将文档组织为树状层级结构:叶子节点是细粒度切片(保障召回精度),中间节点是多级摘要(保障上下文连贯)。检索时"先找点,再展开阅读"。

核心思想

复制代码
文档
├── 第一章摘要 ← 中间节点
│   ├── 1.1节切片 ← 叶子节点(细粒度,精确匹配)
│   └── 1.2节切片
├── 第二章摘要
│   ├── 2.1节切片
│   └── 2.2节切片
└── 全文摘要 ← 根节点(粗粒度,全局理解)

代码示例

python 复制代码
class TreeRAG:
    def __init__(self, llm_client, milvus_client):
        self.llm = llm_client
        self.milvus = milvus_client
        self.tree = {}  # node_id -> {content, parent, children, embedding}

    def build_tree(self, document, chunk_size=500):
        """构建文档树"""
        # Step 1: 切片(叶子节点)
        chunks = self._chunk(document, chunk_size)

        # Step 2: 为每个切片生成摘要(中间节点)
        summaries = []
        for chunk in chunks:
            summary = self._summarize(chunk)
            summaries.append(summary)

        # Step 3: 生成全局摘要(根节点)
        global_summary = self._summarize("\n".join(summaries))

        # Step 4: 构建树结构并存入向量库
        root_id = self._store_node(global_summary, parent=None)
        for i, (summary, chunk) in enumerate(zip(summaries, chunks)):
            mid_id = self._store_node(summary, parent=root_id)
            self._store_node(chunk, parent=mid_id, is_leaf=True)

    def query(self, question, top_k=3):
        """先搜摘要定位章节,再展开叶子节点"""
        # Step 1: 搜索摘要节点(快速定位)
        summary_results = self.milvus.search("tree_summaries", data=[embed(question)], limit=top_k)

        # Step 2: 展开对应叶子节点(获取完整上下文)
        final_context = []
        for hit in summary_results[0]:
            node_id = hit["entity"]["node_id"]
            children = self.tree[node_id]["children"]
            for child_id in children:
                final_context.append(self.tree[child_id]["content"])

        return self._generate(question, "\n".join(final_context))

8. RAG 2026 技术演进全景

三代 RAG 范式对比

维度 RAG 1.0 (2023) RAG 2.0 (2024-2025) RAG 3.0 (2026)
核心架构 检索+生成 混合检索+Rerank Agentic + Graph
检索方式 纯向量检索 向量+BM25+Rerank Agent 动态选择工具
知识表示 文本切片 文本切片+元数据 文本+知识图谱+树
查询处理 原始查询 查询重写/扩展 Agent 自主分解
自我纠错 Rerank 精排 Self-RAG/CRAG
全局推理 不支持 有限 GraphRAG
适用复杂度 简单问答 中等问答 复杂推理

七大 RAG 变体概览

RAG 变体 核心痛点 关键技术 适用场景
Simple RAG 知识过时 向量检索+LLM 基础问答
Corrective RAG 检索噪声 评估器+网络搜索回退 高精度 QA
Self-RAG 幻觉、无关回答 反思Token+自我批评 高可靠领域
Speculative RAG 歧义查询 多路生成+评分选择 创意写作
Fusion RAG 片面观点 多源检索+信息整合 研报生成
Agentic RAG 复杂任务 Agent 循环+动态路由 企业级 Copilot
Graph RAG 全局理解 知识图谱+子图遍历 多跳推理

2026 落地建议

  1. 起步:混合检索 + Rerank 是投入产出比最高的起点
  2. 进阶:加入查询重写、Contextual Retrieval 提升检索质量
  3. 高级:构建 Agentic RAG 处理复杂任务
  4. 评估驱动:每次改动都跑 RAGAS 评估,数据说话
  5. 数据先行:数据质量是上游杠杆,治理好数据比调算法更有效

9. 生产级 RAG 最佳实践清单

知识库构建

  • 使用 PTI 流水线(Parse-Transform-Index)处理非结构化数据
  • 切片时添加文档级上下文摘要(Contextual Retrieval)
  • 同时构建稠密向量和稀疏向量(BM25 Function)
  • 为 QA 对单独建 Collection,利用结构化知识

检索优化

  • 使用混合检索(向量 + BM25)而非单一向量检索
  • 对 Top-K 结果进行 Rerank 精排
  • 设置相似度阈值(COSINE > 0.5)过滤噪声
  • 对复杂问题使用查询重写或子问题分解

生成优化

  • Prompt 中明确指示"仅基于上下文回答"
  • 限制上下文长度,避免 LLM 注意力分散
  • 引用来源标记,方便用户验证
  • 设置"不知道"兜底策略,避免幻觉

系统评估

  • 建立评估数据集(50+ 条测试问题)
  • 用 RAGAS 四大指标定期评估
  • 每次改动只改一个变量
  • 自动化评估集成到 CI/CD

运维保障

  • 监控检索延迟和 LLM 生成延迟
  • 定期更新知识库和评估集
  • 收集用户真实问题加入评估集
  • 设置知识库权限管控
相关推荐
大神科技AI定制1 小时前
告别Excel手工报价,用AI给非标产品报价提效
人工智能
AI视频剪辑官1 小时前
播客切片工具选型核心评价维度
网络·人工智能·算法
Black蜡笔小新1 小时前
制造业AI质检工作站/企业AI算力工作站DLTM重构工业质检全流程体系
人工智能·重构
禅思院2 小时前
AI对话前端从入门到崩溃:一个长对话引发的五层优化战争【引子】
前端·面试·架构
带刺的坐椅3 小时前
用 ChatModel 构建 LLM 驱动的 Java 应用
java·ai·llm·solon·rag·chatmodel
老程序猿3 小时前
一个撇号里,藏得下 3 个 bit——system prompt 隐写手法拆解
ai编程·claude
mONESY3 小时前
AI界的通用USB-C!一文吃透爆火的MCP协议,重构AI智能体底层架构
架构
杉氧3 小时前
兼容与共生:如何在旧项目中优雅地引入 Compose?
android·架构·android jetpack