agno 检索增强生成(RAG)实战指南:传统 RAG、Agentic RAG、知识过滤与自定义检索器逐例精讲
本指南以 agno 仓库 cookbook/02_agents/07_knowledge 目录下的 8 个官方示例(及其 README.md)为主体骨架,系统讲解如何在 agno Agent 上落地检索增强生成(RAG):从把知识直接注入上下文的传统 RAG,到把知识库检索变成工具调用的 Agentic RAG,再到重排序、推理工具、多语言向量模型、知识过滤、自定义检索器和引用格式控制等进阶能力。读完本文,你将能依据自己的数据形态与精度要求,选用或组合出合适的 RAG 方案,并在本地 PostgreSQL(pgvector)或 LanceDB 上复现全部示例。
一、目录概览:一条从“传统 RAG”到“Agentic RAG 全家桶”的学习路径
该目录是 cookbook 中"07_knowledge"专题的完整示例集,README 将其定位为 "Examples for retrieval-augmented generation, knowledge filters, and custom retrievers."(检索增强生成、知识过滤与自定义检索器示例),共 8 个可独立运行的文件:
| 示例文件 | 核心主题 | 关键 Agent 参数 |
|---|---|---|
| traditional_rag.py | 传统 RAG:检索结果注入用户上下文 | add_knowledge_to_context=True, search_knowledge=False |
| agentic_rag.py | Agentic RAG:知识检索作为按需工具 | search_knowledge=True(默认开启) |
| agentic_rag_with_reasoning.py | Agentic RAG + 显式推理工具 + 重排序 | tools=[ReasoningTools(...)] |
| agentic_rag_with_reranking.py | Agentic RAG + Cohere 语义重排序 | reranker=CohereReranker(...) |
| rag_custom_embeddings.py | 自定义向量模型(多语言) | SentenceTransformerEmbedder/Reranker |
| knowledge_filters.py | 静态过滤与 Agentic 过滤 | knowledge_filters / enable_agentic_knowledge_filters |
| custom_retriever.py | 用自定义检索函数替代 Knowledge | knowledge_retriever=my_retriever |
| references_format.py | 控制引用返回格式(JSON/YAML) | references_format="yaml" |
建议按表中顺序阅读与运行:前两个文件对照出"传统 vs Agentic"两种范式差异,随后四个文件层层叠加推理、重排序与自定义 embedding 能力,最后三个文件展示检索链路上的过滤、替换与输出控制技巧。
二、运行前置:环境、PostgreSQL 与启动方式
README 明确列出三个前置条件,这是本地复现所有示例的前提:
- 加载环境变量:使用
direnv allow载入仓库环境配置(其中包含OPENAI_API_KEY)。所有示例均默认调用 OpenAI 的模型与向量接口。 - 创建 demo 运行环境:执行
./scripts/demo_setup.sh(位于仓库根目录 scripts/demo_setup.sh)创建虚拟环境,之后统一用.venvs/demo/bin/python运行 cookbook。 - 启动 PostgreSQL(pgvector):执行
./cookbook/scripts/run_pgvector.sh(位于 cookbook/scripts/run_pgvector.sh),该脚本会启动一个内置 pgvector 扩展的 PostgreSQL 容器。
启动完成后,统一用如下命令运行任意示例:
.venvs/demo/bin/python cookbook/02_agents/07_knowledge/<file>.py
需要特别说明的是部分示例有额外第三方依赖。示例与目录内的 TEST_LOG.md 记录了真实验证结果:agentic_rag_with_reasoning.py、agentic_rag_with_reranking.py 因缺少 cohere 包、rag_custom_embeddings.py 因缺少 sentence_transformers 包而失败(ModuleNotFoundError)。其中 agentic_rag_with_reranking.py 的头部注释给出了完整安装命令:
uv pip install openai agno cohere lancedb sqlalchemy
即凡涉及 Cohere 重排序与多语言 embedding 的文件,需先自行补齐 cohere 或 sentence_transformers 依赖。其余 5 个文件在 pgvector 运行的环境下均已通过(PASS),可作为基线对照。
三、两种 RAG 范式的核心分野:注入上下文还是工具化检索
目录的前两个文件是理解 agno RAG 设计的钥匙。二者共用同一份 Knowledge 与同一数据源(一份泰国菜谱 PDF),差别仅在 Agent 的构造参数上。
3.1 传统 RAG:add_knowledge_to_context=True
traditional_rag.py 的核心代码如下:
agent = Agent(
model=OpenAIResponses(id="gpt-5.2"),
knowledge=knowledge,
# Enable RAG by adding context from the `knowledge` to the user prompt.
add_knowledge_to_context=True,
# Set as False because Agents default to `search_knowledge=True`
search_knowledge=False,
markdown=True,
)
传统 RAG 的语义是"每轮都检索":开启 add_knowledge_to_context 后,每次用户提问前,agnto 会把知识库中与问题相关的文档片段拼进(prompt)上下文,模型在生成时天然"看得到"外部资料。示例特意将 search_knowledge 置为 False,注释明确说明这是因为 Agent 默认 search_knowledge=True——必须显式关闭,才能让"注入上下文"成为唯一的知识来源。从源码角度,对应逻辑位于 libs/agno/agno/agent/_messages.py 的消息组装流程中:当 agent.add_knowledge_to_context 为真时,会基于用户消息内容检索知识并拼装上下文(_messages.py 中 add_knowledge_to_context 分支调用知识检索后把文档注入消息上下文)。
3.2 Agentic RAG:search_knowledge=True(默认)
agentic_rag.py 的核心代码如下:
agent = Agent(
model=OpenAIResponses(id="gpt-5.2"),
knowledge=knowledge,
# Add a tool to search the knowledge base which enables agentic RAG.
# This is enabled by default when `knowledge` is provided to the Agent.
search_knowledge=True,
markdown=True,
)
Agentic RAG 的语义是"按需检索":Agent 被赋予一个名为 search_knowledge_base 的工具,是否检索、检索什么、检索几次都由模型根据对话内容自主决策。示例注释强调:"当为 Agent 提供 knowledge 时该能力默认开启"。这一机制在 libs/agno/agno/agent/_default_tools.py 中有完整实现:search_knowledge_base(query) 工具会"优先检查 knowledge_retriever,若未设置则回退到 knowledge.search()",其返回的引用内容随后按 references_format 决定是否走过滤逻辑(详见后文)。
两类模式的取舍很直观:
- 传统 RAG:确定性强、调用成本可预期,适合"每次回答都需要外部事实底座"的固定任务;
- Agentic RAG:灵活节省 token,模型能判断"何时不需要查知识库",还能多轮追问式检索,适合开放域问答。
四、给 Agentic RAG 叠加推理与重排序
既然 Agentic RAG 把检索交给模型自主判断,检索质量的保障就显得关键。目录中两个进阶示例分别从"回答侧"与"检索侧"入手。
4.1 Agentic RAG + 显式推理工具(reasoning tools)
agentic_rag_with_reasoning.py 将知识底座从 pgvector 换成了 LanceDB,并同时引入两路增强:
from agno.knowledge.embedder.cohere import CohereEmbedder
from agno.knowledge.reranker.cohere import CohereReranker
from agno.tools.reasoning import ReasoningTools
knowledge = Knowledge(
vector_db=LanceDb(
uri="tmp/lancedb",
table_name="agno_docs",
search_type=SearchType.hybrid,
embedder=CohereEmbedder(id="embed-v4.0"),
reranker=CohereReranker(model="rerank-v3.5"),
),
)
agent = Agent(
model=OpenAIResponses(id="gpt-5.2"),
knowledge=knowledge,
search_knowledge=True,
tools=[ReasoningTools(add_instructions=True)],
instructions=[
"Include sources in your response.",
"Always search your knowledge before answering the question.",
],
markdown=True,
)
值得注意的三处设计:
- 数据注入走异步批量接口:运行时调用
knowledge.ainsert_many(urls=[...]),即 Knowledge 提供的异步批量插入方法(对应源码 libs/agno/agno/knowledge/knowledge.py 中的ainsert_many),适用于一次灌入多个文档 URL 的场景; - 推理显式化:
ReasoningTools把"思考"暴露为可调用的工具,配合instructions中"先检索知识库再回答、回复中附带来源"两条指令,让生成链路可解释; - 重排序前置于向量库:
reranker=CohereReranker(model="rerank-v3.5")被配置在 LanceDb 上,检索结果会先经 Cohere 语义重排再交给模型。
运行该示例时使用 show_full_reasoning=True,可完整观察到模型"先检索→再推理→后回答"的过程。
4.2 Agentic RAG + 纯重排序方案(reranking)
agentic_rag_with_reranking.py 则把注意力集中在"检索侧质量"这一件事上——用 OpenAI 做向量化、用 Cohere 做重排序,形成分工明确的流水线:
knowledge = Knowledge(
vector_db=LanceDb(
uri="tmp/lancedb",
table_name="agno_docs",
search_type=SearchType.hybrid,
embedder=OpenAIEmbedder(id="text-embedding-3-small"), # Use OpenAI for embeddings
reranker=CohereReranker(model="rerank-multilingual-v3.0"), # Use Cohere for reranking
),
)
在向量检索阶段,"初筛"靠 embedding 相似度,往往会把语义近似的文档一并召回;重排序阶段再让一个专用的排序模型(如 Cohere rerank-multilingual-v3.0)对召回结果做精细化打分,把最相关片段顶到最前。这是生产级 RAG 最常见的质量兜底手段,尤其适合召回量较大或文档主题相近的场景。
4.3 小结:两个示例的叠加关系
agentic_rag_with_reasoning.py= Agentic RAG(Cohere embedding + 重排)+ReasoningTools显式推理;agentic_rag_with_reranking.py= Agentic RAG(OpenAI embedding)+ Cohere 重排,是"最简可复制的重排升级路径"。
两者都基于 LanceDB(本地文件数据库,uri="tmp/lancedb",无需额外容器),因此不需要启动 pgvector,但都需要 cohere 依赖。
五、完全本地化:多语言 embedding + 自托管重排序
rag_custom_embeddings.py 展示了一个"不走云厂商、全部本地模型"的多语言 RAG 实现。其示例数据本身颇具代表性——10 条关于护肤与美妆趋势的文本,分别用英语、德语、西班牙语、中文、日语书写,用于验证跨语言检索的正确性:
from agno.knowledge.embedder.sentence_transformer import SentenceTransformerEmbedder
from agno.knowledge.reranker.sentence_transformer import SentenceTransformerReranker
knowledge = Knowledge(
vector_db=PgVector(
db_url="postgresql+psycopg://ai:ai@localhost:5532/ai",
table_name="sentence_transformer_rerank_docs",
embedder=SentenceTransformerEmbedder(
id="sentence-transformers/paraphrase-multilingual-MiniLM-L12-v2"
),
reranker=SentenceTransformerReranker(model="BAAI/bge-reranker-v2-m3"),
),
)
两个值得留意的工程细节:
- 数据逐条写入并打元数据:示例用循环调用
knowledge.insert(text_content=result, metadata={"source": "search_results"}),印证了 Knowledge.insert 的签名能力——该方法支持path、url、text_content三种内容来源,并接受metadata、include/exclude、upsert、skip_if_exists等参数(见源码insert()的实现与 docstring); - embedding 与重排序全链路本地化:
SentenceTransformerEmbedder使用paraphrase-multilingual-MiniLM-L12-v2做多语言向量化,SentenceTransformerReranker使用BAAI/bge-reranker-v2-m3做跨语言重排序,数据不需出本地即可完成从向量化到排序的整条链路。
该示例同样会以 show_full_reasoning=True 的方式运行三条测试查询,其中第三条 "Compare skincare and makeup information across languages" 专门用于验证"跨语言归并检索"的能力——这正是多语言 embedding + 多语言 reranker 组合的价值所在。运行前请确保已安装 sentence_transformers(见 TEST_LOG.md 中的失败记录)。
六、知识过滤:静态过滤与 Agentic 过滤
knowledge_filters.py 解答了一个真实痛点:知识库里混着多类文档时,如何让检索只命中"对的那一簇"。其 README 定位为 "Filter knowledge searches with static or agentic filters"。
6.1 静态过滤:创建期写死过滤条件
from agno.filters import EQ
agent_static = Agent(
model=OpenAIResponses(id="gpt-5.2"),
knowledge=knowledge,
search_knowledge=True,
# Use FilterExpr objects for type-safe filtering
knowledge_filters=[EQ("cuisine", "thai")],
markdown=True,
)
静态过滤在 Agent 创建时设定,对每一次检索都生效。示例用 EQ("cuisine", "thai") 把检索范围限定在菜系为 thai 的文档内。注意注释强调应"使用 FilterExpr 对象做类型安全过滤"——对应仓库源码 libs/agno/agno/filters.py 中定义于基类 FilterExpr 之上的比较算子:EQ(字段等值)、IN(字段值落在集合内)等。FilterExpr 还通过运算符重载支持组合逻辑:|(OR)、&(AND)、~(NOT),可构造如 OR(AND(EQ("status","active"), GT("age",18)), EQ("role","admin")) 的嵌套表达式;源码中另有 MAX_FILTER_DEPTH = 10 的递归深度上限,用于防止深层嵌套表达式引发栈溢出,说明过滤表达式是被递归求值的。同时,Agent 侧参数 knowledge_filters 的类型为 Union[Dict[str, Any], List[FilterExpr]](见 libs/agno/agno/agent/_cli.py 的 create_agent_cli 参数定义),既支持简洁的字典写法,也支持上面这种强类型的表达式列表。
6.2 Agentic 过滤:让模型在运行时决定过滤值
agent_agentic = Agent(
model=OpenAIResponses(id="gpt-5.2"),
knowledge=knowledge,
search_knowledge=True,
# Let the agent choose filter values based on the user's query
enable_agentic_knowledge_filters=True,
markdown=True,
)
Agentic 过滤与静态过滤相对:过滤键值不由开发者在创建期写死,而是由模型在每次收到用户问题时动态推导。例如对 "Find me a Thai dessert recipe.",模型可能自动产出 cuisine=thai 与 dish_type=dessert 之类的过滤条件后再去检索。该参数在 Agent 内部会联动到工具构建逻辑与系统提示词:_default_tools.py 中的 search_knowledge_base_with_filters 工具支持将 Agent 传入的过滤器与运行时模型推导出的过滤条件合并(源码注释可见 get_agentic_or_user_search_filters 的处理流程),并且开启后 Agent 的系统提示会注入相应的"如何推导过滤条件"说明(对应 libs/agno/agno/agent/_messages.py 中以 enable_agentic_filters 为关键字的提示词拼接分支)。
示例在运行阶段对两个 Agent 分别提问:
print("--- Static filters (cuisine=thai) ---")
agent_static.print_response("What soup recipes do you have?", stream=True)
print("\n--- Agentic filters ---")
agent_agentic.print_response("Find me a Thai dessert recipe.", stream=True)
可直观观察到:静态过滤的 Agent 始终只检索 cuisine=thai,而 Agentic 过滤的 Agent 会针对不同提问生成不同过滤条件。生产建议是——过滤维度固定时用静态过滤(可控、省 token),过滤维度随用户意图变化时用 Agentic 过滤。
七、用自定义检索函数替换 Knowledge:knowledge_retriever
custom_retriever.py 解决的是另一类问题:如果数据根本不在 agno 的 Knowledge/向量库体系里,而是散落在内部 API、数据库或搜索引擎背后,怎么办?
答案是不再构建 Knowledge 实例,而是写一个普通的 Python 函数当作 knowledge_retriever:
def my_retriever(
query: str, num_documents: Optional[int] = None, **kwargs
) -> Optional[List[dict]]:
"""Search documents by simple keyword matching."""
query_lower = query.lower()
results = [
doc
for doc in DOCUMENTS
if query_lower in doc["content"].lower() or query_lower in doc["title"].lower()
]
if num_documents:
results = results[:num_documents]
return results if results else None
agent = Agent(
model=OpenAIResponses(id="gpt-5.2"),
# Use a custom retriever instead of a Knowledge instance
knowledge_retriever=my_retriever,
# search_knowledge is True by default when knowledge_retriever is set
markdown=True,
)
要点解析:
- 函数签名契约:接收
query与可选的num_documents,返回Optional[List[dict]]。dict 中可含title、content等字段;未命中时返回None而非空列表; - 接入即工具:示例注释说明——当设置了
knowledge_retriever时,search_knowledge默认即为True,该函数会被包装为 Agent 的search_knowledge_base工具。这与 libs/agno/agno/agent/_default_tools.py 的实现完全对应:工具的检索函数"优先调用knowledge_retriever,未设置时才回退到knowledge.search()"; - 示例本身是占位实现:文件头部注释明确写着 "In production, this could call an external API, database, or search engine"——示例用三篇内存文档 + 关键词匹配演示协议,生产环境中把函数体换成任意后端调用即可无缝接入 Agentic RAG。
八、控制引用格式:references_format
references_format.py 关注的是给模型的"检索证据"如何排版:
agent = Agent(
model=OpenAIResponses(id="gpt-5.2"),
knowledge=knowledge,
search_knowledge=True,
# Format knowledge references as YAML instead of the default JSON
references_format="yaml",
markdown=True,
)
文件 docstring 明确指出:默认情况下引用以 JSON 返回;将 references_format 设为 "yaml" 则改为 YAML。当多个文档被检索回来时,JSON 数组与 YAML 缩进块在 token 占用与模型可读性上会有差异——YAML 往往更紧凑易读,是降低上下文冗余的一种低成本手段。在源码侧,references_format 正是 search_knowledge_base 工具内部决定引用内容以何种结构返回的判断依据(见 libs/agno/agno/agent/_default_tools.py 中 if agent.references_format == "json": ... 的分支)。
九、验证与排障:以 TEST_LOG 为参照
目录内的 TEST_LOG.md 记录了 2026-02-13 在 .venvs/demo/bin/python + pgvector 环境下的逐文件实测结果,可作为运行预期与排障基线:
| 示例 | 结果 | 说明 |
|---|---|---|
| agentic_rag.py | PASS(18s) | 无额外依赖 |
| custom_retriever.py | PASS(10s) | 无需向量库 |
| knowledge_filters.py | PASS(14s) | 需 pgvector |
| references_format.py | PASS(13s) | 需 pgvector |
| traditional_rag.py | PASS(12s) | 需 pgvector |
| agentic_rag_with_reasoning.py | FAIL | 缺少 cohere 依赖 |
| agentic_rag_with_reranking.py | FAIL | 缺少 cohere 依赖 |
| rag_custom_embeddings.py | FAIL | 缺少 sentence_transformers 依赖 |
对照此表可快速定位问题:报 ModuleNotFoundError: No module named 'cohere' 就执行 uv pip install cohere,报 sentence_transformers 缺失则补齐对应包。此外,凡是 db_url="postgresql+psycopg://ai:ai@localhost:5532/ai" 的示例都依赖 ./cookbook/scripts/run_pgvector.sh 启动的容器(ai:ai@localhost:5532 为该脚本的默认连接串);凡是使用 LanceDB 的示例则无需容器但会在 tmp/lancedb 下生成本地库文件。
十、延伸阅读建议
想深入这些示例背后的机制,建议继续精读以下仓库路径:
- Knowledge 类本体:libs/agno/agno/knowledge/knowledge.py,含
insert/ainsert_many/search等方法签名; - 知识检索工具实现:libs/agno/agno/agent/_default_tools.py,
search_knowledge_base的封装与过滤合并逻辑; - 知识注入上下文的流程:libs/agno/agno/agent/_messages.py,
add_knowledge_to_context与系统提示词拼接; - 过滤表达式体系:libs/agno/agno/filters.py,
FilterExpr、EQ/IN/AND/OR/NOT等算子的完整定义; - OpenAI Embedder 实现:libs/agno/agno/knowledge/embedder/openai.py;
- 同主题更多组合示例:可参考 cookbook/00_quickstart 中的基础用法,或 cookbook/07_knowledge 下更系统的分专题示例,进一步理解 Knowledge 在其他语境(如 Agent OS、Workflow)中的运用。
结语
通过 cookbook 02_agents/07_knowledge 这 8 个示例,可以清晰看到 agno 在 RAG 上的设计主线:以 Knowledge + VectorDB 为统一数据底座,通过 add_knowledge_to_context(传统注入)与 search_knowledge(工具化检索)两种开关切换范式,再用 reranker、ReasoningTools、knowledge_filters、knowledge_retriever、references_format 等旋钮逐级调优检索质量、控制成本与输出结构。无论你的数据是 PDF、URL、纯文本,还是藏在内部系统中的专有接口,都能在 agno 上以"先跑通传统 RAG → 升级 Agentic RAG → 叠加重排/过滤"的路径快速落地一套生产可用的知识问答能力。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0629
MiniCPM5-2BMiniCPM5-2B 是一款面向端侧、本地部署和资源受限场景的 2B 稠密 Transformer,能够达到同尺寸开源模型 SOTA 水平。Markdown00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
HivisionIDPhotos⚡️HivisionIDPhotos: a lightweight and efficient AI ID photos tools. 一个轻量级的AI证件照制作算法。Python07
DragonOSDragonOS is an operating system developed from scratch using Rust, with Linux compatibility. It is designed for **Serverless** scenarios. 使用Rust从0自研内核,具有Linux兼容性的操作系统,面向云计算Serverless场景而设计。Rust00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00