第 13 章 · 知识库 Knowledge 与 RAG 入门
本章目标:理解 RAG 的完整链路,学会用 Agno 的
Knowledge加载文档、配置本地向量库 LanceDB 与三方 Embedding 服务,并把知识库挂载到 Agent 实现可溯源的问答。
13.1 RAG 原理速览
大模型的参数里只有训练时见过的知识,对企业内部文档、最新资料一无所知,还可能一本正经地编造(幻觉)。**RAG(Retrieval-Augmented Generation,检索增强生成)**的思路是:先从你自己的资料库里"检索"出相关片段,再把片段塞进提示词让模型"照着答"。
完整链路分两个阶段:
- 写入阶段(Indexing):文档 → 切块(chunking)→ 向量化(embedding)→ 存入向量数据库;
- 查询阶段(Retrieval):用户问题向量化 → 在向量库中找最相似的若干片段 → 拼进提示词 → 模型生成带依据的回答。
三个角色
- Embedder:把文本变成向量(一串浮点数),语义相近的文本向量距离更近;
- Vector DB:存向量并支持"最近邻检索",Agno 支持 LanceDB、PgVector、Chroma 等;
- Knowledge:Agno 对上面整条流水线的封装,负责读取、切块、入库、检索。
13.2 用 Knowledge 构建知识库
Knowledge 是 Agno 2.x 知识能力的核心类。创建时指定向量库和 Embedder,然后用 insert() 灌入内容——它支持本地路径、URL、纯文本等多种来源,并能自动识别 PDF、DOCX、CSV、Markdown 等格式选择合适的 Reader:
# knowledge_basic.py
import os
from agno.knowledge.knowledge import Knowledge
from agno.knowledge.embedder.openai import OpenAIEmbedder
from agno.vectordb.lancedb import LanceDb, SearchType
# 本地向量库 LanceDB:无需单独部署服务,数据落在本地目录
knowledge = Knowledge(
vector_db=LanceDb(
table_name="company_docs", # 向量表名
uri="tmp/lancedb", # 数据存储目录
search_type=SearchType.vector, # 向量检索(后续章节讲混合检索)
embedder=OpenAIEmbedder( # 三方 OpenAI 兼容 Embedding 服务
id="Qwen/Qwen3-Embedding-8B", # 以你的平台实际提供的模型 id 为准
api_key=os.getenv("EMBEDDING_API_KEY"),
base_url="https://api.siliconflow.cn/v1",
),
)
)
# 灌入内容:支持 url / path / 目录 / 纯文本
knowledge.insert(
url="https://agno-public.s3.amazonaws.com/recipes/ThaiRecipes.pdf",
skip_if_exists=True, # 已入库的内容跳过,避免重复索引
)
knowledge.insert(text_content="公司年假政策:入职满一年享有 5 天带薪年假……")依赖安装:
pip install "agno[lancedb]" pypdf # lancedb 与 PDF 读取支持注意
insert() 会真实调用 Embedding API 并产生费用与耗时;开发阶段务必带上 skip_if_exists=True,否则每次运行都会重复入库。
13.3 把知识库挂到 Agent 上
只需给 Agent 传 knowledge= 参数。此时 Agno 会自动给模型注册一个 search_knowledge_base 工具,由模型自己决定何时检索——这就是下一章要展开的 Agentic RAG:
# rag_agent.py
from agno.agent import Agent
from agno.models.openai import OpenAIChat
agent = Agent(
model=OpenAIChat(
id="deepseek-chat",
api_key=os.getenv("DEEPSEEK_API_KEY"),
base_url="https://api.deepseek.com/v1",
),
knowledge=knowledge,
search_knowledge=True, # 提供知识库时默认开启,显式写出更清晰
instructions=[
"回答前先搜索知识库。",
"回答末尾注明引用了哪些来源。",
"知识库里没有的内容,明确说不知道,不要编造。",
],
markdown=True,
)
agent.print_response("泰式椰奶鸡汤怎么做?")运行后观察日志,你会看到模型先发起一次工具调用(检索),拿到相关片段后才生成最终答案。
13.4 直接检索与结果溯源
有时你需要绕过模型直接测试检索质量——用 knowledge.search() 即可,返回的每条结果都带有内容和元数据:
results = knowledge.search(query="年假有多少天")
for r in results:
print("匹配度:", getattr(r, "score", None))
print("内容:", r.content[:100])
print("元数据:", r.meta_data) # 含来源文件名等,可用于溯源想让检索到的参考内容自动注入用户提示词(传统 RAG 模式)而非交给模型自主决定,可以打开 add_knowledge_to_context=True;两种模式的取舍见下一章。
# 传统 RAG:每次提问前固定执行一次检索并拼进上下文
traditional_rag_agent = Agent(
model=model,
knowledge=knowledge,
add_knowledge_to_context=True, # 检索结果自动加入用户消息
)
traditional_rag_agent.print_response("公司年假政策是什么?")13.5 常见坑
- Embedding 与提问不在同一"语义空间":入库和检索必须用同一个 Embedder 配置,换了模型必须重建整个向量表;
- 中文检索效果差:多半是 Embedding 模型不支持中文,选多语种模型(如 Qwen/BGE 系列);
- 忘记持久化目录:
uri指向临时目录会导致每次重启都要重新入库; - 切块太大:一个 chunk 塞进太多无关内容会稀释相似度,第 14 章详细讲切块策略。
本章小结
- RAG = 写入(切块→向量化→入库)+ 查询(检索→拼提示词→生成)两段链路;
Knowledge(vector_db=LanceDb(...), embedder=OpenAIEmbedder(...))是标准组合,LanceDB 免部署适合本地开发;Agent(knowledge=..., search_knowledge=True)让模型通过工具自主检索;knowledge.search()可脱离模型直接验证检索质量;- 入库与检索必须使用同一套 Embedding 配置。
🧪 随堂测验
点击你认为正确的选项。答错时会展示正确答案与原因解析。
1. 在 RAG 的写入阶段,文档经历的正确处理顺序是?
2. 给 Agent 传入 knowledge 参数后,Agno 默认的行为是?
3. 关于 Embedding 配置,下列说法错误的是?
4. 想在不调用大模型的情况下验证"某个问题能不能检索到正确片段",应该怎么做?
🛠️ 动手实践
- 用 LanceDB + 三方 Embedding 建一个小知识库,灌入 3 段你自己的笔记文本,用
knowledge.search()测试 5 个问题的召回效果。 - 把 13.3 的 RAG Agent 跑起来,故意问一个知识库里没有的问题,验证它是否按 instructions 承认"不知道"。
- 给知识库再 insert 一个公开 PDF URL,对比插入前后同一问题的回答质量差异。
掌握了基础 RAG 后,进入第 14 章:RAG 进阶学习切块策略、过滤与重排。