进阶 C · Agentic RAG:Agent 驱动的自主检索
当问题需要"先查 A,根据 A 的结果再查 B,最后对比 C"时,传统的一轮检索不够。Agentic RAG 让 AI 自主决定检索策略。
1. 从被动检索到主动探索
css
传统 RAG: User→检索→生成 (一轮定胜负)
Agentic RAG: User→Agent 自我规划
├─ 检索A → 分析 → 发现需要B
├─ 检索B → 分析 → 还需要C
└─ 检索C → 综合回答
核心变化:检索不再是"用户问什么就搜什么",而是 Agent 自主决定"搜什么、搜几次、怎么搜"。
2. Agentic RAG 节点实现
php
// agentic-rag/agent.ts
import { tool } from "@langchain/core/tools";
import { AgentExecutor, createOpenAIFunctionsAgent } from "langchain/agents";
import { ChatOpenAI } from "@langchain/openai";
import { z } from "zod";
// Tool 1: 搜索知识库
const searchKB = tool(
async ({ query }) => {
const results = await vectorStore.similaritySearch(query, 5);
return results.map(r =>
`[来源: ${r.metadata.source}]\n${r.pageContent}`
).join("\n\n---\n\n");
},
{
name: "search_knowledge_base",
description: "搜索知识库中的文档。输入一个具体的搜索问题。",
schema: z.object({ query: z.string().describe("搜索查询") }),
}
);
// Tool 2: 搜索代码仓库
const searchCode = tool(
async ({ query, repoPath }) => {
// 调用 grep 或代码搜索 API
const { stdout } = await execAsync(`grep -rn "${query}" ${repoPath} --include="*.ts" | head -20`);
return stdout || "未找到匹配";
},
{
name: "search_codebase",
description: "在代码仓库中搜索。输入关键词和路径。",
schema: z.object({
query: z.string(),
repoPath: z.string().optional(),
}),
}
);
// Tool 3: 比较文档
const compareDocs = tool(
async ({ doc1Id, doc2Id, aspect }) => {
const [doc1, doc2] = await Promise.all([
getDocument(doc1Id), getDocument(doc2Id)
]);
return llm.invoke(`比较以下两篇文档关于"${aspect}"的异同:\n文档1: ${doc1}\n文档2: ${doc2}`);
},
{
name: "compare_documents",
description: "比较两篇文档在某个方面的异同。",
schema: z.object({
doc1Id: z.string(),
doc2Id: z.string(),
aspect: z.string(),
}),
}
);
// 组装 Agent
const agent = await createOpenAIFunctionsAgent({
llm: new ChatOpenAI({ model: "gpt-4o" }),
tools: [searchKB, searchCode, compareDocs],
prompt: ChatPromptTemplate.fromMessages([
["system", `你是一个知识检索 Agent。对于复杂问题:
1. 先分解问题,确定需要检索哪些信息
2. 逐一检索,分析结果
3. 如果信息不足,继续检索
4. 综合所有检索结果给出回答,并标注来源`],
["human", "{input}"],
["placeholder", "{agent_scratchpad}"],
]),
});
const executor = new AgentExecutor({ agent, tools: [searchKB, searchCode, compareDocs] });
3. 实战:复杂技术问题的多轮检索
vbnet
const result = await executor.invoke({
input: "我们项目的认证方案和业界最佳实践有哪些差距?需要改动哪些文件?"
});
// Agent 自主执行过程:
// Step 1: search_knowledge_base("认证最佳实践")
// Step 2: search_knowledge_base("当前项目认证实现")
// Step 3: search_codebase("authenticate", "./src")
// Step 4: compare_documents(doc1, doc2, "认证方案")
// Step 5: 综合回答
4. GraphRAG + AgenticRAG 组合
当 Agent 能同时操作文本检索和图谱检索:
php
// Tool 4: 图谱查询
const queryGraph = tool(
async ({ entity, relation }) => {
const result = await graphRetriever.search(entity);
return `与"${entity}"的关系:${JSON.stringify(result.relations)}`;
},
{
name: "query_knowledge_graph",
description: "查询知识图谱中某个实体的关联关系。",
schema: z.object({
entity: z.string(),
relation: z.string().optional(),
}),
}
);
典型对话:
css
User: "支付模块挂了会影响哪些服务?"
Agent:
1. query_graph("支付模块", "depends_on") → 发现 6 个直接依赖
2. search_kb("支付模块故障处理") → 拿到故障预案文档
3. 综合回答:列出影响的服务链 + 推荐的故障处理步骤
5. Agentic RAG 的工程挑战
| 挑战 | 表现 | 应对 |
|---|---|---|
| 过度检索 | Agent 连续检索 10+ 次不停止 | 设置 maxIterations=5 |
| 检索漂移 | 偏离原始问题,越搜越远 | 每次检索前让 Agent 确认"这一步能帮回答原问题吗" |
| 重复检索 | 用相似关键词反复搜 | 缓存检索结果,去重 |
| 成本爆炸 | Agent 每一步都调 LLM + Embedding | 设置 token 预算,简单问题降级为传统 RAG |
| 幻觉放大 | Agent 误解检索结果,基于错误信息继续检索 | 要求每轮输出"当前发现"供审计 |
6. 何时用 Agentic RAG
arduino
问题复杂度评估:
├─ 单概念查询 ("React.memo 怎么用") → 传统 RAG
├─ 比较查询 ("memo vs useMemo") → 传统 RAG + 多检索
└─ 探索性查询 ("我们的系统有哪些性能瓶颈?")
└─ Agentic RAG(需要自主探索)
经验法则:如果人类回答这个问题需要查 3 个以上不同来源,就值得用 Agentic RAG。
7. 最小可运行 Agentic RAG
php
// agentic-rag/minimal.ts
import { AgentExecutor, createOpenAIFunctionsAgent } from "langchain/agents";
import { ChatOpenAI } from "@langchain/openai";
export async function createMinimalAgentRAG(vectorStore: any) {
const searchTool = tool(
async ({ query }) => {
const results = await vectorStore.similaritySearch(query, 5);
return results.map(r => r.pageContent).join("\n---\n");
},
{ name: "search", description: "搜索知识库", schema: z.object({ query: z.string() }) }
);
const agent = await createOpenAIFunctionsAgent({
llm: new ChatOpenAI({ model: "gpt-4o" }),
tools: [searchTool],
prompt: ChatPromptTemplate.fromMessages([
["system", "你是知识库助手。复杂问题可以多次搜索后再回答。"],
["human", "{input}"],
["placeholder", "{agent_scratchpad}"],
]),
});
return new AgentExecutor({
agent,
tools: [searchTool],
maxIterations: 5,
returnIntermediateSteps: true, // 返回中间步骤供 UI 展示
});
}
系列完结。回到第一篇:RAG 架构全景与 Node.js 选型地图