Skip to content

第 14 章 · RAG 进阶:Agentic RAG 与混合检索

本章目标:分清 Agentic RAG 与传统 RAG 两种模式,掌握切块策略、元数据过滤与重排器三项提升检索质量的关键技术。

14.1 Agentic RAG vs 传统 RAG

上一章的例子是 Agentic RAG:模型拿到一个 search_knowledge_base 工具,自己决定"要不要查、查什么词",还能对查询进行改写和多轮补充检索。而传统 RAG是固定流水线——每次提问都先检索,把结果直接注入提示词:

python
from agno.agent import Agent

# 传统 RAG:每次请求前先检索,参考内容自动拼进用户消息
traditional = Agent(
    model=model,
    knowledge=knowledge,
    add_knowledge_to_context=True,   # 检索结果直接加入上下文
)

# Agentic RAG:模型自主决定是否/如何检索(默认行为)
agentic = Agent(
    model=model,
    knowledge=knowledge,
    search_knowledge=True,           # 注册检索工具,交给模型决策
)
维度传统 RAGAgentic RAG
检索时机每次必检模型按需决定
延迟与成本低且可预测多一轮工具调用
复杂问题单次检索可能不够可改写查询、多次检索
适用场景简单问答、低延迟要求需要多步推理的知识工作

选型建议

客服 FAQ 这类"一问一答"用传统 RAG 足够;研究分析类任务用 Agentic RAG。两者可以并存配置。

14.2 切块策略:决定召回上限的第一要素

向量库里存的最小单位是 chunk。切得太大,一个片段里混入无关内容稀释相似度;切得太小,语义不完整。Agno 内置多种 Chunking 策略,挂在 Reader 上生效:

python
from agno.knowledge.chunking.fixed import FixedSizeChunking
from agno.knowledge.chunking.recursive import RecursiveChunking
from agno.knowledge.chunking.document import DocumentChunking
from agno.knowledge.reader.pdf_reader import PDFReader
from agno.knowledge.knowledge import Knowledge

# 固定长度:简单粗暴,适合格式规整的文本
fixed_reader = PDFReader(chunking_strategy=FixedSizeChunking(size=1500))

# 递归切块:按段落→句子→字符多级分隔符逐级回退,通用性最好
recursive_reader = PDFReader(chunking_strategy=RecursiveChunking())

# 文档结构切块:按标题/段落等文档结构边界切,保持章节完整
doc_reader = PDFReader(chunking_strategy=DocumentChunking())

knowledge = Knowledge(vector_db=vector_db)
knowledge.insert(path="handbook.pdf", reader=recursive_reader)

选型经验:Markdown/HTML 用结构化切块、代码用 Code Chunking、无结构长文用递归切块起步,效果不佳再尝试基于嵌入相似度断句的 Semantic Chunking。

14.3 元数据过滤:让检索"查得准"

给入库内容打上元数据标签,查询时按标签过滤,可以把检索范围从"全库"缩小到"该用户/该年份/该类型":

python
# 入库时附加 metadata
knowledge.insert(
    path="resumes/",
    metadata={"department": "engineering", "year": 2025},
)

# 方式一:Agent 级固定过滤——这个 Agent 永远只看 engineering 的文档
agent = Agent(
    model=model,
    knowledge=knowledge,
    search_knowledge=True,
    knowledge_filters={"department": "engineering"},
)

# 方式二:调用时临时过滤,多个条件之间是 AND 关系
agent.print_response(
    "总结 2025 年入职的工程师简历亮点",
    knowledge_filters={"year": 2025},
)

# 直接检索同样支持 filters
results = knowledge.search(query="Python 经验", filters={"department": "engineering"})

还可以开启 enable_agentic_knowledge_filters=True 让模型从用户提问中自动推断过滤条件(例如从"Jordan 的技能"里提取出 user_id=jordan),这需要配合 Contents DB 记录可用的过滤键。

14.4 重排器 Reranker:精排最后一道关

向量检索返回的是"粗排"结果。Reranker 用一个更重但更精准的交叉编码模型对候选片段逐一打分重新排序,把真正相关的顶到前面:

python
import os
from agno.knowledge.reranker.cohere import CohereReranker
from agno.vectordb.lancedb import LanceDb, SearchType

knowledge = Knowledge(
    vector_db=LanceDb(
        uri="tmp/lancedb",
        table_name="docs",
        search_type=SearchType.hybrid,   # 混合检索:向量 + 关键词双信号
        embedder=embedder,
        reranker=CohereReranker(model="rerank-v3.5"),   # 精排模型
    ),
)

三者组合的分工:混合检索同时捕捉语义相似和关键词精确匹配两类信号;重排再对这些候选做细粒度相关性排序。这是目前生产级 RAG 的标准三件套。

14.5 如何评估检索质量

改参数不能靠感觉,建立最小评估闭环:

  1. 准备 20–50 条「问题 → 应命中内容」的标注对;
  2. knowledge.search() 批量跑,统计命中率(top-k 里是否包含正确片段);
  3. 每次调整切块大小/换 Embedding 模型/加重排后重跑对比。
python
def hit_rate(kb, cases, k=5):
    hits = sum(
        any(c["keyword"] in r.content for r in kb.search(q=c["q"], top_k=k))
        for c in cases
    )
    return hits / len(cases)   # 例如 0.85 表示 85% 的问题召回了目标片段

本章小结

  • Agentic RAG(search_knowledge=True,模型自主检索)与传统 RAG(add_knowledge_to_context=True,先检后答)各有适用场景;
  • 切块策略通过 Reader 的 chunking_strategy 配置,递归切块是通用起点;
  • knowledge_filters 实现元数据过滤,enable_agentic_knowledge_filters=True 让模型自动推断过滤条件;
  • SearchType.hybrid + Reranker 是生产级检索的标准组合;
  • 用小规模标注集量化评估每次调优的效果。

🧪 随堂测验

点击你认为正确的选项。答错时会展示正确答案与原因解析。

1. Agentic RAG 与传统 RAG 的核心区别是什么?

2. 关于切块(chunking),下列说法正确的是?

3. 设置 knowledge_filters={"year": 2025} 后又传入 {"dept": "sales"},两个过滤条件如何生效?

4. Reranker 在检索链路中的作用是?

🛠️ 动手实践

  1. 同一份 PDF 分别用 FixedSizeChunking(size=1000)RecursiveChunking() 入库到两张表,用同一组问题对比 search() 召回差异。
  2. 给知识库内容加上 {"lang": "zh"/"en"} 元数据,实现中英文问题各自只检索对应语料。
  3. 为你的知识库写一个 10 条用例的 hit_rate 评估脚本,记录基线分数。

下一步进入第 15 章:推理 Reasoning,让模型学会"先想后答"。