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
关键要点
- 两个集合各有职责,各自独立支持混合检索
- 并行检索不增加延迟
- QA 对中的 reasoning 字段帮助 LLM 理解"为什么是这个答案"
- 每个检索结果标记来源,便于溯源
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}")
评估最佳实践
- 建立基线:改参数前先跑一次完整评估,记录基线分数
- 每次只改一个变量:不要同时改 Embedding + 切片参数 + LLM
- 评估数据集:最少 20 条,推荐 50-100 条
- 自动化:集成到 CI/CD,每次 PR 自动跑评估
- 人工抽查不可替代:定期人工检查 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 落地建议
- 起步:混合检索 + Rerank 是投入产出比最高的起点
- 进阶:加入查询重写、Contextual Retrieval 提升检索质量
- 高级:构建 Agentic RAG 处理复杂任务
- 评估驱动:每次改动都跑 RAGAS 评估,数据说话
- 数据先行:数据质量是上游杠杆,治理好数据比调算法更有效
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 生成延迟
- 定期更新知识库和评估集
- 收集用户真实问题加入评估集
- 设置知识库权限管控