07 - 知识库与 RAG:让 Agent 基于你的数据回答
一句话总结:用 Knowledge + 向量数据库把你的文档灌进去,Agent 就能基于你的数据回答问题,而不是瞎编。
问题:LLM 只知道训练数据
大模型很聪明,但它只知道训练截止日期之前的公开数据。你公司的内部文档?你自己写的技术笔记?上周刚发布的产品说明?它一概不知。
你问它”我们公司的年假政策是什么”,它只能瞎猜或者礼貌地说”我不知道”。
这时候你需要 RAG – Retrieval Augmented Generation,检索增强生成。
名字听着唬人,原理很简单:
- 把你的文档切成小块,存到一个可以搜索的数据库里
- 用户提问时,先搜索相关的文档片段
- 把搜到的内容塞给 LLM,让它基于这些内容来回答
打个比方:LLM 是一个聪明的学生,Knowledge 是他的教科书,RAG 就是”先翻书再答题”这个动作。不给教科书,再聪明也只能凭记忆瞎蒙;给了教科书,答案就靠谱多了。
核心组件
在 Agno 里实现 RAG 需要三样东西:
| 组件 | 作用 | 类比 |
|---|---|---|
| Knowledge | 知识库,管理文档的导入和检索 | 图书馆 |
| VectorDb | 向量数据库,存储文档的向量表示 | 书架 |
| Embedder | 嵌入器,把文本转成向量 | 编目员 |
向量是什么?简单说就是一串数字,用来表示文本的”语义”。两段话意思越接近,它们的向量就越相似。所以你搜”休假制度”,也能找到写着”年假政策”的文档 – 因为它们语义相近。
搭建知识库:用 ChromaDb
ChromaDb 是一个轻量级的向量数据库,不需要额外安装服务,开箱即用,非常适合本地开发和学习。
先装依赖:
pip install agno openai chromadb
然后搭建知识库:
from agno.knowledge.knowledge import Knowledge
from agno.knowledge.embedder.openai import OpenAIEmbedder
from agno.vectordb.chroma import ChromaDb
from agno.vectordb.search import SearchType
knowledge = Knowledge(
vector_db=ChromaDb(
collection="my_docs",
path="tmp/chromadb",
persistent_client=True,
search_type=SearchType.hybrid,
embedder=OpenAIEmbedder(id="text-embedding-3-small"),
),
)
几个参数说明一下:
- collection – 集合名称,类似数据库里的表名
- path – 数据存储路径,
persistent_client=True表示数据持久化到磁盘,脚本重启不丢 - search_type – 搜索方式,后面细讲,先用
hybrid就对了 - embedder – 用 OpenAI 的
text-embedding-3-small模型来生成向量,便宜又好用
往知识库里灌数据
知识库搭好了,接下来往里塞内容。Agno 支持多种数据源:
# 从 URL 加载
knowledge.insert(
url="https://docs.agno.com/introduction.md",
skip_if_exists=True, # 已存在就跳过,避免重复导入
)
# 直接塞文本
knowledge.insert(
name="Company FAQ",
text_content="我们公司成立于2020年,主要做AI产品开发。办公地点在北京中关村。",
)
# 从本地文件加载(支持 PDF、TXT、MD 等)
# knowledge.insert(name="Report", path="path/to/document.pdf")
insert() 做了什么?它把你的内容切成小块(chunking),用 Embedder 把每块转成向量,然后存到 ChromaDb 里。这些都是自动的,你不用操心细节。
给 Agent 接上知识库
知识库有了数据,接下来让 Agent 用起来:
from agno.agent import Agent
from agno.models.openai import OpenAIChat
from agno.knowledge.knowledge import Knowledge
from agno.knowledge.embedder.openai import OpenAIEmbedder
from agno.vectordb.chroma import ChromaDb
from agno.vectordb.search import SearchType
# 1. 创建知识库
knowledge = Knowledge(
vector_db=ChromaDb(
collection="my_docs",
path="tmp/chromadb",
persistent_client=True,
search_type=SearchType.hybrid,
embedder=OpenAIEmbedder(id="text-embedding-3-small"),
),
)
# 2. 导入内容
knowledge.insert(
url="https://docs.agno.com/introduction.md",
skip_if_exists=True,
)
# 3. 创建 Agent 并绑定知识库
agent = Agent(
model=OpenAIChat(id="gpt-4o-mini"),
knowledge=knowledge,
search_knowledge=True,
instructions="你是一个文档问答助手,基于知识库中的信息回答问题。如果知识库中没有相关信息就说不知道。",
markdown=True,
)
agent.print_response("Agno是什么?", stream=True)
关键参数:
- knowledge – 绑定知识库
- search_knowledge=True – 让 Agent 在回答前自动搜索知识库(默认就是 True,写出来是为了明确意图)
当用户提问时,Agent 会自动调用知识库搜索相关内容,把搜到的文档片段放进上下文,然后基于这些内容来回答。整个流程是自动的。
搜索类型:keyword vs vector vs hybrid
知识库搜索有三种方式,通过 search_type 参数控制:
keyword(关键词搜索)
按字面匹配。搜”年假”就找包含”年假”这个词的文档。简单粗暴,但如果用户说的是”休假天数”就搜不到”年假政策”了。
vector(向量搜索)
按语义匹配。把问题和文档都转成向量,计算相似度。搜”休假天数”也能找到”年假政策”,因为它们语义接近。但有时候精确匹配反而不如关键词。
hybrid(混合搜索)
两种都用,然后用 RRF(Reciprocal Rank Fusion)算法把结果融合排序。兼顾精确匹配和语义理解,大多数场景下效果最好。
from agno.vectordb.search import SearchType
# 三种搜索类型
SearchType.keyword # 关键词搜索
SearchType.vector # 向量搜索(默认)
SearchType.hybrid # 混合搜索(推荐)
没有特殊需求的话,用 hybrid 就完事了。
实战:公司 FAQ 机器人
来做一个实际的例子 – 把公司的常见问题灌进知识库,做一个内部问答机器人:
from agno.agent import Agent
from agno.models.openai import OpenAIChat
from agno.knowledge.knowledge import Knowledge
from agno.knowledge.embedder.openai import OpenAIEmbedder
from agno.vectordb.chroma import ChromaDb
from agno.vectordb.search import SearchType
# 创建知识库
knowledge = Knowledge(
vector_db=ChromaDb(
collection="company_faq",
path="tmp/chromadb",
persistent_client=True,
search_type=SearchType.hybrid,
embedder=OpenAIEmbedder(id="text-embedding-3-small"),
),
)
# 导入公司 FAQ
knowledge.insert(
name="FAQ",
text_content="""
Q: 公司的工作时间是什么?
A: 工作时间是早9点到晚6点,弹性工作制。
Q: 年假有多少天?
A: 入职第一年10天,之后每年增加1天,最多15天。
Q: 如何申请报销?
A: 在OA系统提交报销申请,附上发票照片,部门经理审批后财务处理。
Q: 远程办公政策是什么?
A: 每周可以远程办公2天,需要提前在系统上报备。
Q: 试用期多长?
A: 试用期3个月,表现优秀可以提前转正。
""",
skip_if_exists=True,
)
# 创建问答 Agent
agent = Agent(
model=OpenAIChat(id="gpt-4o-mini"),
knowledge=knowledge,
search_knowledge=True,
instructions=[
"你是公司的HR助手,专门回答员工关于公司政策的问题。",
"基于知识库中的信息回答,不要编造不存在的政策。",
"如果问题超出知识库范围,建议员工联系HR部门。",
"回答要简洁友好。",
],
markdown=True,
)
# 测试几个问题
agent.print_response("年假有多少天?")
agent.print_response("我想报销出差费用,怎么操作?")
agent.print_response("公司有健身房吗?") # 知识库里没有这个信息
第三个问题”公司有健身房吗”在知识库里找不到相关内容,Agent 应该会告诉用户它不知道,建议联系 HR – 因为我们在指令里明确说了”不要编造”。这就是 RAG 的优势:有据可查的就回答,查不到的就坦诚说不知道,而不是瞎编一个答案。
知识库 vs 上下文窗口:该选哪个
你可能会想:为什么不直接把所有文档塞进 system prompt 里?干嘛还要搞向量数据库这么复杂?
简单对比一下:
| 方案 | 优势 | 劣势 |
|---|---|---|
| 直接塞 prompt | 简单,不需要额外组件 | 文档多了放不下,token 费用高 |
| 知识库 + RAG | 支持海量文档,只检索相关部分 | 需要向量数据库,检索可能遗漏 |
经验法则:
- 文档总量在几千字以内 – 直接塞 prompt 就行,简单省事
- 文档总量上万字或持续增长 – 用知识库,否则上下文窗口撑不住,钱也烧不起
几个实用建议
数据质量比什么都重要。 垃圾数据灌进去,搜出来的也是垃圾。确保你导入的内容是干净、准确、有价值的。
给 insert 加上 skip_if_exists=True。 避免每次运行脚本都重复导入数据。
persistent_client=True 别忘了。 否则数据只存在内存里,脚本一关就没了。
instructions 里写清楚”不知道就说不知道”。 否则 Agent 搜不到相关内容时可能会编造答案。
生产环境考虑用 PgVector。 ChromaDb 适合开发和小规模使用,生产环境建议用 PostgreSQL + PgVector,更稳定,支持更大规模的数据。
今天学了什么
回顾一下关键概念:
- RAG 的核心思路是”先检索,再生成” – 让 LLM 基于你的数据回答,而不是凭空猜测
- Knowledge 是 Agno 的知识库类,负责管理文档的导入和检索
- ChromaDb 是一个轻量级向量数据库,本地开发首选,不需要额外服务
- Embedder 把文本转成向量,让语义搜索成为可能
- search_type 有三种:keyword(字面匹配)、vector(语义匹配)、hybrid(两者结合,推荐)
- search_knowledge=True 让 Agent 自动检索知识库,默认就是开启的
一个快速对照表:
| 你想做的事 | 用什么 |
|---|---|
| 让 Agent 基于自己的文档回答 | Knowledge + VectorDb |
| 本地开发快速验证 | ChromaDb |
| 生产环境大规模部署 | PgVector |
| 兼顾精确匹配和语义搜索 | SearchType.hybrid |
下一篇预告
08 - 安全护栏:别让 Agent 胡说八道
Agent 能力越大,风险越大。它可能泄露敏感信息、生成不当内容、或者被用户的 prompt injection 带跑偏。下一篇我们聊 Guardrails – 给 Agent 装上安全护栏,在输入和输出两端做检查,确保它不越界、不胡说、不被利用。从”能干活”进化到”安全地干活”。