传统 RAG 是「用户一提问,先把整个知识库搜一遍再回答」。但知识一多、来源一杂,这种方法很容易答非所问。Agentic RAG 不一样:它让 Agent 自己决定「该去哪个知识库搜、搜几次、要不要换来源」。本教程用 LlamaIndex 搭一个「多知识库路由」Agent,可复现。
📚 本教程适合:已了解基础 RAG、想解决「检索不准、来源混乱」的开发者。需要 Python 3.10+ 和 OpenAI 兼容的 API Key(用于嵌入与生成)。
Step 1:准备环境与概念
1 装依赖,认清两者区别
pip install llama-index llama-index-llms-openai llama-index-embeddings-openai
| 静态 RAG | Agentic RAG | |
|---|---|---|
| 检索时机 | 每次都搜全部 | Agent 按需决定搜哪个、搜几次 |
| 多来源 | 混在一起搜,易串味 | 每个来源独立成工具,精准调用 |
| 适合 | 单一小知识库 | 产品/政策/技术多库并存 |
Step 2:建多个独立索引
2 把不同文档建成不同库
from llama_index.core import VectorStoreIndex, SimpleDirectoryReader, Settings
from llama_index.llms.openai import OpenAI
from llama_index.embeddings.openai import OpenAIEmbedding
Settings.llm = OpenAI(model="gpt-4o-mini", temperature=0)
Settings.embed_model = OpenAIEmbedding(model="text-embedding-3-small")
# 假设本地有 data/products/ 和 data/policies/ 两个目录
product_index = VectorStoreIndex.from_documents(
SimpleDirectoryReader("data/products/").load_data()
)
policy_index = VectorStoreIndex.from_documents(
SimpleDirectoryReader("data/policies/").load_data()
)
💡 把「产品手册」和「公司制度」分开建索引,是避免回答串味的关键。真实项目里可以再加技术文档库、FAQ 库等。
Step 3:把每个索引包成工具
3 给 Agent 递上「检索工具」
from llama_index.core.tools import QueryEngineTool
tools = [
QueryEngineTool.from_defaults(
query_engine=product_index.as_query_engine(),
name="product_catalog",
description="产品、价格、功能相关问题,用这个。",
),
QueryEngineTool.from_defaults(
query_engine=policy_index.as_query_engine(),
name="company_policies",
description="退款、隐私、公司制度类问题,用这个。",
),
]
description 写清楚很重要:Agent 靠这段描述来判断「该调哪个工具」。写得越具体,路由越准。否则它可能乱选库,反而更不准。
Step 4:用 ReActAgent 串起来
4 Agent 自己挑库回答
from llama_index.core.agent import ReActAgent
agent = ReActAgent.from_tools(
tools=tools,
llm=Settings.llm,
verbose=True, # 打印 Thought→Action→Observation 推理链
max_iterations=10,
)
response = agent.chat("企业客户的退款政策是什么?我们的 Pro 版多少钱?")
print(str(response))
# Agent 会自动:先用 company_policies 查退款,再用 product_catalog 查价格
🔍
verbose=True 时你能看到 Agent 的「内心戏」:它先想、再决定调哪个工具、看到结果后是否继续——调试检索不准时特别有用。Step 5:再加一个普通函数工具
5 混合「检索」与「计算」能力
from llama_index.core.tools import FunctionTool
from datetime import datetime
def get_today() -> str:
"""返回当前日期。"""
return datetime.now().strftime("%Y-%m-%d")
tools.append(FunctionTool.from_defaults(fn=get_today))
# 重新建 agent 时把更新后的 tools 传进去即可
# 例如问「今天日期是多少,顺便告诉我 Pro 版价格」
# Agent 会先调 get_today,再调 product_catalog
检索质量决定上限:Agentic RAG 不是魔法,垃圾进垃圾出——文档分块策略、嵌入模型质量、索引是否过期,都会直接影响回答。大文档建索引会消耗 token 和时间,建议先在小样本上验证;Agent 多次检索也会增加调用次数与成本。模型名(如 gpt-4o-mini)以官方文档为准。
常见问题速查
| 现象 | 大概率原因 & 解决 |
|---|---|
| 回答还是串味 | 工具 description 太模糊,或索引里文档混在一起,重新分库 |
| Agent 不调工具 | description 没说清何时用,或问题本身不需要检索 |
| 很慢/很贵 | max_iterations 太大或库太多,按需收紧 |
| 索引为空 | 目录路径错或文档格式不支持,先打印 load_data() 结果 |