Skip to content

第 13 章 · 知识库 Knowledge 与 RAG 入门

本章目标:理解 RAG 的完整链路,学会用 Agno 的 Knowledge 加载文档、配置本地向量库 LanceDB 与三方 Embedding 服务,并把知识库挂载到 Agent 实现可溯源的问答。

13.1 RAG 原理速览

大模型的参数里只有训练时见过的知识,对企业内部文档、最新资料一无所知,还可能一本正经地编造(幻觉)。**RAG(Retrieval-Augmented Generation,检索增强生成)**的思路是:先从你自己的资料库里"检索"出相关片段,再把片段塞进提示词让模型"照着答"。

完整链路分两个阶段:

  1. 写入阶段(Indexing):文档 → 切块(chunking)→ 向量化(embedding)→ 存入向量数据库;
  2. 查询阶段(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:

python
# 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 天带薪年假……")

依赖安装:

bash
pip install "agno[lancedb]" pypdf   # lancedb 与 PDF 读取支持

注意

insert() 会真实调用 Embedding API 并产生费用与耗时;开发阶段务必带上 skip_if_exists=True,否则每次运行都会重复入库。

13.3 把知识库挂到 Agent 上

只需给 Agentknowledge= 参数。此时 Agno 会自动给模型注册一个 search_knowledge_base 工具,由模型自己决定何时检索——这就是下一章要展开的 Agentic RAG:

python
# 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() 即可,返回的每条结果都带有内容和元数据:

python
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;两种模式的取舍见下一章。

python
# 传统 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. 想在不调用大模型的情况下验证"某个问题能不能检索到正确片段",应该怎么做?

🛠️ 动手实践

  1. 用 LanceDB + 三方 Embedding 建一个小知识库,灌入 3 段你自己的笔记文本,用 knowledge.search() 测试 5 个问题的召回效果。
  2. 把 13.3 的 RAG Agent 跑起来,故意问一个知识库里没有的问题,验证它是否按 instructions 承认"不知道"。
  3. 给知识库再 insert 一个公开 PDF URL,对比插入前后同一问题的回答质量差异。

掌握了基础 RAG 后,进入第 14 章:RAG 进阶学习切块策略、过滤与重排。