1. 引言:传统RAG的瓶颈与Agentic RAG的价值承诺

还记得第一次部署RAG系统时的兴奋吗?看着它从知识库中检索出相关文档,然后生成看似合理的回答,你一度以为“人工智障”终于要变成“人工智能”了。直到用户抛出一个稍微复杂点的问题——“帮我比较一下这三款产品的性价比,考虑售后和性能,我家在北京五环外,配送方便吗?”——你的RAG系统直接懵了。它要么只抓到了“产品”这个关键词,返回一堆产品列表;要么生成了一个看似完整却毫无逻辑的“缝合怪”回答。

那一刻你才明白,传统RAG就像一个只会背书的图书管理员:你问“秦始皇在哪年统一了六国”,它能迅速翻到第38页;但如果你问“如果秦始皇统一六国后立即下旨修长城,当时的国库能支撑多久?”,它只会眼巴巴地看着你,然后从两本不相干的书里各抄一段给你。

这种“死板检索”的本质,源于传统RAG的静态管道架构。你设计好检索器、写好Prompt模板、设置好Top-K值,整个流程就固定了。它不知道什么时候该换一种检索方式,不知道如何把一个大问题拆成小步骤,更不知道在第一次没找到答案时该怎么补救。这就像一个流水线机器人,无论来了什么工件,它都只会用同一个机械臂做同样的操作。

当你的用户查询从“公司Q2财报”进化到“我该不该买这家公司的股票,考虑一下它刚发的季报和竞争对手的动态,再结合一下最近的行业政策”时,传统RAG的局限性暴露无遗——信息过载(返回几十个文档让用户自己找答案)和逻辑断层(把不相关的片段强行拼接)成了家常便饭。

而Agentic RAG的到来,彻底改变了这个游戏规则。它不是对传统RAG的简单修补,而是一次范式转换——从“固定检索-生成管道”进化为“智能体驱动的自适应知识工作流”。在Agentic RAG中,我们引入了一个核心智能体,它不再机械地执行固定指令,而是像一个“主动的情报分析师”:收到任务后,它会先评估任务复杂度—是先查一波资料,还是直接回答?

需要调用哪些工具?是向量检索、网络搜索、还是执行一段爬虫代码?它还会对中间结果进行反思——这个结果够了吗?相关性是否足够?如果不够,要不要换个关键词重查?或者那把问题拆成两个子问题分别查?这种动态工具调用迭代优化的能力,让AI系统从“死板检索”真正进化成了“主动思考的知识助手”。

这篇文章,我将带你从底层原理到落地实战,深入拆解Agentic RAG。你将学到:Agentic RAG的核心架构与设计思想;如何用代码实现一个具备动态工具调用能力的智能体RAG系统;如何让智能体具备自我修正迭代优化的能力;以及在真实开发中应该避免哪些坑。不管你是刚入门RAG的开发者,还是已经部署过传统RAG的老手,这篇文章都将为你打开一扇新的大门——让AI真正学会“怎么思考”,而不只是“怎么背诵”。

2. 什么是Agentic RAG?从静态管道到智能体驱动的范式转换

图书管理员 vs 情报分析师:一个生动的比喻

想象你走进一个巨大的图书馆。传统RAG是那个最勤奋的图书管理员:你给他一个书名,他立刻跑去书架,按分类号精确找到那本书,翻到你指定的章节,然后把那段话抄给你。如果给的书名不准确,他就找不到了;如果你问的是需要综合多本书信息才能回答的问题,他最多把几本书都搬到你面前,你自己看着办。他高效、精准,但只适合处理“找已知信息”的简单任务。

而Agentic RAG则是那个训练有素的情报分析师。你告诉他:“帮我分析一下这个客户公司的竞争对手,他们最近三个月在电商平台的品牌声量变化,以及有没有负面舆情,顺便看看我们过去一年和他们的合作情况”。他不会转身就跑,而是会先停顿一下,在脑海中规划:嗯,这是一个多步骤任务,需要分阶段执行。第一步,去“内部CRM知识库”查合作记录;第二步,调用“新闻检索工具”查最近三个月的行业新闻;第三步,用“舆情分析工具”爬一下电商评论;第四步,把所有信息综合起来,生成一份结构化的分析报告。

如果在第一步发现合作记录太简略,他还会主动调整第二步的策略——比如重点查那些与公司主营业务相关的新闻。他不仅“知道如何检索”,更“知道如何规划检索”。

Agentic RAG vs 传统RAG:三大本质区别

从架构层面看,Agentic RAG和传统RAG至少存在三个本质区别:

区别一:策略动态性

传统RAG的策略是静态的、预先定义的。你的检索管道通常是:用户查询 → embedding → 向量检索 → Top-K个文档 → 拼接Prompt → LLM生成。整个过程就像一个火车时刻表,火车按指定轨道行驶,永远不会偏离。而Agentic RAG的策略是动态生成的。智能体可以基于当前查询的复杂度、意图、甚至历史对话,动态决定使用哪种策略。

举个例子:当用户问“什么是RAG?”时,智能体会选择最直接的向量检索,因为这是一个简单问题,直接查知识库就够了。但当用户问“RAG和微调各自适合什么场景?它们的优劣势分别是什么?如果我要给客户做一个问答机器人,应该选哪个?”,智能体可能选择多策略组合:先用向量检索查RAG和微调的基本定义,再调用网络搜索找最新的对比文章,最后用代码工具计算一下两种方案的成本(假设知识库中有成本数据)。

这是传统RAG做不到的。

区别二:工具调用能力

传统RAG的工具箱里只有一把锤子——向量检索。不论遇到什么类型的问题,都用同一套检索逻辑:embedding + 余弦相似度。而Agentic RAG配备了一个可插拔的工具箱。除了向量检索,它还拥有:

  • 结构化查询工具:用于查询数据库、知识图谱;
  • 网络搜索工具:当内部知识库信息不足时,实时抓取网络信息;
  • 代码执行工具:当需要进行计算、数据统计时,让智能体生成并执行代码;
  • 文档解析工具:用于处理PDF、Word等非结构化文件;
  • API调用工具:对接外部系统的RESTful接口。

这些工具不是摆设,智能体会根据当前任务的需要,主动“召唤”合适的工具组合。

区别三:结果迭代反馈机制

传统RAG是“一次过”的:你输入查询,它输出答案,整个过程无后顾之忧。而Agentic RAG内置了一个闭环反馈机制。智能体会对每次检索和生成的结果进行自我评估:

  • 相关性检查:检索到的文档真的和问题相关吗?如果只有一个关键词匹配但语义无关,智能体会意识到“这次检索失败了”,然后主动调整策略。
  • 完整性检查:检索到的信息能够完整回答问题吗?比如需要三个维度的信息,但只检索到了两个,智能体会自动补充第三次检索。
  • 一致性检查:从不同工具获得的信息是否相互矛盾?如果有矛盾,智能体会要求重新检索或尝试其他信息源。

这个反馈环是Agentic RAG实现“迭代优化”的核心。它让RAG系统从“一次性检索”进化为“多轮探索式检索”,就像人类在做一个复杂研究时,不断调整搜索关键词、切换数据库一样。

深入理解:Agentic RAG的设计思想

用一句话概括:Agentic RAG = 智能体 + 工具集 + 反馈循环。这个框架的底层设计思想,实际上是机器学习领域中“plan-and-execute”(先规划、再执行)范式的延伸。智能体不再是被动等待指令的“齿轮”,而是一个拥有“大脑”的决策者。它能感知当前状态(用户查询是什么?知识库有哪些?

已经查到了什么?),制定行动计划(应该先查什么?用什么工具?要不要拆分子任务?),执行并观察结果,然后根据反馈修正下一个动作。

最佳实践:在设计Agentic RAG系统时,不要试图一开始就让智能体具备“万能”能力。先从最简单的场景开始——给智能体配备2-3个核心工具(向量检索 + 网络搜索 + 代码执行),让它在这套小工具箱里学会“如何选择”。随着业务需求增加,再逐步扩展工具箱和决策逻辑。

这种设计思想让RAG真正实现了从“工具”到“助手”的跃升。你的AI系统不再是一个只会背书的机器人,而是一个能根据任务主动规划、能选择最合适工具、能自我反思和修正的智能助手。这正是Agentic RAG——作为RAG进阶智能体方案——的核心价值。

3. 核心架构拆解:智能体、工具集与迭代循环

理解了Agentic RAG的设计思想,我们来看看它的核心架构。一个成熟的Agentic RAG系统由三大组件构成:决策智能体可插拔工具集反馈循环。这三个组件之间的协作方式,决定了系统的智能程度和可靠性。

组件一:决策智能体——系统大脑

决策智能体是Agentic RAG系统的“大脑”,负责理解和分发任务。它通常基于LLM构建,但不仅仅是LLM本身——而是LLM配合一个推理框架的组合体。目前主流的推理框架有两种:

ReAct模式(Reasoning + Acting,推理与行动):智能体按照“思考 → 行动 → 观察 → 思考”的循环逻辑工作。当用户提问“哪家快递公司在长三角的配送时效最好?”,智能体会先思考:“这个问题需要查不同快递公司在长三角区域的配送数据”,然后调用相关工具去检索。拿到检索结果后,再思考:“数据不完整,缺少极兔快递的信息”,于是再次调用工具补充检索。

这种“边想边做”的模式,特别适合需要多轮探索的复杂问题。

Plan-and-Execute模式(规划-执行模式):智能体先制定一个完整的行动计划,然后按照计划逐步执行。比如同样的问题,智能体会先规划:“第一步,列出所有主流快递公司;第二步,逐个查询它们在长三角的配送时效;第三步,对比数据生成报告”。然后按部就班执行。这种模式的优势在于任务路径清晰、易于追踪调试,缺点是灵活度略低于ReAct模式。

提示:在实际开发中,ReAct模式更适合开放式、不确定性强的问题,而Plan-and-Execute模式更适合步骤明确、可预测的任务。我建议初学者从ReAct模式入手,因为它的“边想边做”逻辑更接近人类自然的思考方式,调试起来也更直观。当你对智能体行为模式足够熟悉后,再尝试Plan-and-Execute模式来应对那些明确需要“分步骤完成”的任务。

组件二:可插拔工具集——智能体之手

工具集是智能体与环境交互的“手”。每个工具本质上是一个封装好的函数或API,定义了输入、输出和功能描述。关键的设计要点是:每个工具的注册信息必须包含清晰的描述和参数说明。因为智能体依靠这些描述来决策“什么时候该用什么工具”。

一个典型的工具注册代码片段如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# 注册一个向量检索工具
tools = [
{
"name": "vector_search",
"description": "在内部知识库中进行语义检索,返回最相关的文档片段",
"parameters": {
"query": {"type": "string", "description": "检索查询"},
"top_k": {"type": "integer", "default": 5}
}
},
{
"name": "web_search",
"description": "通过搜索引擎获取互联网上的最新信息",
"parameters": {
"query": {"type": "string", "description": "搜索关键词"},
"num_results": {"type": "integer", "default": 5}
}
},
{
"name": "code_executor",
"description": "执行Python代码,用于数据计算、统计分析等任务。

代码必须使用print输出结果。",
"parameters": {
"code": {"type": "string", "description": "要执行的Python代码"}
}
}
]

注意:工具描述的质量直接影响智能体的决策准确度。太简略的描述会让智能体无法判断何时使用;太冗长的描述又可能让智能体陷入“信息过载”。一个好的做法是:在描述中说明“这个工具擅长解决什么问题”、“适合处理什么类型的数据”。比如对vector_search的描述,可以加上:“擅长处理需要理解语义相似性的问题,如技术概念解释、产品对比”等。

组件三:反馈循环——自我修正引擎

反馈循环是Agentic RAG相比传统RAG最具革命性的组件。它让系统具备自我修正迭代优化的能力。一个标准的反馈循环包含三个步骤:

步骤1:结果评估。智能体在每次工具调用后,都要对结果进行评估。评估维度包括:相关度(结果是否与查询强相关)、完整性(结果是否覆盖所有查询维度)、一致性(不同工具返回的信息是否相互吻合)。评估可以通过一个简单的Prompt来实现,例如:“请分析以下检索结果是否完整回答了用户问题。如果缺信息,请指出缺少什么;如果不相关,请返回’无相关结果’。”

步骤2:策略调整。如果结果评估不理想,智能体调整策略。可能的调整方式包括:

  • 查询重写:用HyperClarity(HyDE)风格的方式,将原始查询扩展或重写,生成更精确的检索语句;
  • 工具切换:换一个不同的工具重试。比如向量检索未找到结果,尝试网络搜索;
  • 任务拆分:将一个大问题拆成几个小问题,分别检索后再综合。

步骤3:终止决策。智能体在每次迭代后都要判断“是否可以终止”。终止条件通常包括:检索结果的置信度超过阈值、工具调用次数达到上限(防死循环)、迭代轮数达到上限(控制成本和延迟)。如果满足终止条件,智能体进入答案生成阶段;否则,回到步骤1继续迭代。

三者的协作流程

这三个组件的协作,构成了Agentic RAG的核心工作流:

  1. 接收查询 → 决策智能体分析用户意图和任务复杂度;
  2. 制定计划 → 基于分析结果,智能体决定需要哪些工具、按什么顺序调用;
  3. 执行工具 → 调用相应工具,获取中间结果;
  4. 反馈评估 → 智能体评估中间结果的质量;
  5. 迭代优化 → 如果不满意,调整策略(重写查询、换工具、拆分子问题),回到步骤3;
  6. 生成答案 → 当迭代终止后,基于所有检索结果,生成最终答案。

这个流程看起来复杂,但当你用代码实现它时,会发现核心逻辑其实只有几十行——关键不在于代码复杂度,而在于如何设计智能体的决策规则如何定义工具的交互接口。接下来,我们就用实战代码来演示这个过程。

4. 实战一:零基础搭建你的第一个Agentic RAG系统(动态工具调用实现)

理论终归要落地。在这一节,我们将从头构建一个最小可用的Agentic RAG系统。你将亲眼看到智能体如何根据用户查询,动态选择并调用不同工具,以及如何实现基本的迭代优化。

准备工作:环境与依赖

我们将使用Python标准库实现核心逻辑,不依赖LangChain等重量级框架,这样你能更清晰地理解底层原理。唯一的外部依赖是OpenAI的API(或者任何兼容的LLM API,如Qwen、DeepSeek),用于驱动智能体的决策和答案生成。

1
2
3
4
5
6
# 安装依赖
# pip install openai

import json
import openai
from typing import Callable, List, Dict, Any

实现核心:智能体决策引擎

智能体的核心决策逻辑是:给定一个用户查询和一套可用工具,LLM需要输出“我应该调用哪个工具,以及传入什么参数”。这一步通常通过给LLM一个结构化的Prompt来实现。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
def call_llm(prompt: str, response_format: str = "text"):
"""调用LLM,支持返回文本和结构化JSON"""
client = openai.OpenAI()
messages = [{"role": "system", "content": "你是一个智能助手,请按照要求输出。

"},
{"role": "user", "content": prompt}]
response = client.chat.completions.create(
model="gpt-4o", # 可根据需要替换模型
messages=messages,
temperature=0.0 # 决策任务建议使用低temperature,保证确定性
)
content = response.choices[0].message.content
if response_format == "json":
# 尝试从内容中提取JSON
try:
# 简单处理:找到第一个 { 和最后一个 } 之间的内容
start = content.index("{")
end = content.rindex("}") + 1
return json.loads(content[start:end])
except:
return content
return content

def build_tool_descriptions(tools: List[Dict]) -> str:
"""将工具列表格式化为LLM可理解的描述文本"""
descriptions = []
for tool in tools:
params_desc = "\n".join(
f" - {name}: {info['description']} (类型: {info['type']}, 默认: {info.get('default', '必填')})"
for name, info in tool["parameters"].items()
)
descriptions.append(f"工具名: {tool['name']}\n描述: {tool['description']}\n参数:\n{params_desc}")
return "\n\n".join(descriptions)

def agent_decision(query: str, tools: List[Dict], context: str = "") -> Dict:
"""让智能体决定下一步操作"""
tool_desc = build_tool_descriptions(tools)
decision_prompt = f"""
你是一个智能检索助手。当前用户查询: {query}

当前已有信息: {context if context else "暂无"}

你有以下工具可用:
{tool_desc}

请根据查询的需要,决定下一步操作。输出JSON格式:
{{
"action": "调用的工具名称或final_answer",
"params": {{"参数名": "参数值"}},
"reasoning": "你做出这个决定的原因"
}}

规则:
- 如果认为当前信息已经足够回答问题,action设为"final_answer"
- 否则,选择最合适的工具(只选一个),并填写正确的参数
- 如果某个工具已经调用过且结果不理想,换一个工具
"""
result = call_llm(decision_prompt, response_format="json")
return result

定义工具集:模拟真实场景

为了演示动态工具调用,我们定义三个典型的检索工具:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# 模拟知识库
knowledge_base = {
"产品A": "产品A是一款面向中小企业的CRM系统,注重客户管理和销售流程自动化。价格:199元/月。支持在线支付和银行转账。",
"产品B": "产品B是一款针对大型企业的ERP系统,包含财务、HR、供应链模块。

价格:899元/月。部署方式:支持云端和私有化。",
"产品C": "产品C是一款免费的CRM系统,提供基本客户管理功能,适合初创团队。高级功能需付费:99元/月。",
}

# 工具1: 内部知识库检索
def vector_search(query: str, top_k: int = 2) -> str:
"""基于关键词匹配的知识库检索(模拟语义检索)"""
# 简化实现:通过关键词匹配模拟相关性
results = []
for key, value in knowledge_base.items():
# 计算关键词匹配度
matched_words = len(set(query.split()) & set(key.split() + value.split()))
if matched_words > 0:
results.append((value, matched_words))
# 按匹配度排序
results.sort(key=lambda x: x[1], reverse=True)
if not results:
return "❌ 未在知识库中找到相关信息。

"
return "\n\n".join([f"[来源: {knowledge_base[key]}]\n内容: {value}" for key, value in results[:top_k]])

# 工具2: 网络搜索(模拟)
def web_search(query: str, num_results: int = 3) -> str:
"""模拟网络搜索,返回静态的测试数据"""
web_data = {
"产品对比": "根据用户评测,产品A的CRM功能最全面,产品B的ERP最好,产品C性价比最高。

",
"售后服务": "产品A提供7×24小时在线客服;产品B提供专属客户经理;产品C仅提供社区支持。",
"行业报告": "2024年CRM市场报告中,产品A市场份额领先,产品B在企业级市场表现突出。",
}
# 简单匹配
for key, value in web_data.items():
if key in query or any(word in key for word in query.split()):
return value
return "❌ 网络搜索未找到相关信息。

"

# 工具3: 代码执行(用于计算、统计等)
def code_executor(code: str) -> str:
"""执行简单的Python代码(安全沙箱)"""
try:
# 注意:实际生产环境需要更严格的沙箱措施
local_vars = {}
exec(code, {"__builtins__": {}}, local_vars) # 极度简化,仅供演示
return str(local_vars.get("result", "代码执行完成"))
except Exception as e:
return f"❌ 代码执行失败: {str(e)}"

# 注册工具
tools = [
{"name": "vector_search", "func": vector_search,
"description": "在内部知识库中检索产品信息、价格、功能等",
"parameters": {"query": {"type": "string", "description": "检索关键词,如产品名称"}}},
{"name": "web_search", "func": web_search,
"description": "搜索互联网上的最新信息,如用户评测、行业报告",
"parameters": {"query": {"type": "string", "description": "搜索关键词"}}},
{"name": "code_executor", "func": code_executor,
"description": "执行Python代码进行数据计算或分析。

代码中请将结果赋值给变量result。",
"parameters": {"code": {"type": "string", "description": "要执行的Python代码"}}}
]

主循环:实现动态工具调用

现在,我们编写Agentic RAG的主循环。智能体会持续决策→执行工具→评估结果,直到决定生成答案。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
def run_agentic_rag(query: str, max_iterations: int = 10):
"""
Agentic RAG主循环
参数:
query: 用户查询
max_iterations: 最大迭代次数,防止死循环
"""
context = "" # 累积的上下文信息
iteration_count = 0
tool_call_history = [] # 记录工具调用历史,防止重复无用的调用

while iteration_count < max_iterations:
iteration_count += 1
print(f"\n--- 第 {iteration_count} 次迭代 ---")

# 1. 智能体决策
decision = agent_decision(query, tools, context)
print(f"🤔 智能体决策: {decision['reasoning']}")
action = decision["action"]

# 2. 检查是否要终结
if action == "final_answer":
print("✅ 智能体认为信息足够,准备生成答案")
break

# 3. 执行工具调用
# 找到对应的工具
tool = None
for t in tools:
if t["name"] == action:
tool = t
break

if tool is None:
print(f"⚠️ 工具 {action} 不存在,跳过")
context += f"\n[注意] 调用 {action} 失败,工具不存在。

"
continue

# 获取参数
params = decision.get("params", {})

# 防止重复调用相同参数的相同工具
call_signature = f"{action}_{json.dumps(params, sort_keys=True)}"
if call_signature in tool_call_history:
print(f"⚠️ 检测到重复调用 {action},切换策略")
context += f"\n[注意] {action} 已用相同参数调用过,信息不足,请换一种方式。

"
continue
tool_call_history.append(call_signature)

# 执行工具
print(f"🔧 调用工具: {action}({params})")
try:
result = tool["func"](**params)
print(f"📥 工具返回: {result[:100]}...") # 只打印前100字符
except Exception as e:
result = f"❌ 工具调用出错: {str(e)}"
print(result)

# 4. 更新上下文
context += f"\n[工具调用: {action}]\n结果: {result}"

# 5. 生成最终答案
final_prompt = f"""
用户查询: {query}

基于以下检索信息,生成一个完整、准确的回答。如果信息不足,请明确指出缺失了什么。

检索信息:
{context}
"""

final_answer = call_llm(final_prompt, response_format="text")
print("\n=== 最终答案 ===")
print(final_answer)
return final_answer

# 测试运行
if __name__ == "__main__":
user_query = "产品A和产品C哪个更适合初创公司?考虑价格和功能。"
run_agentic_rag(user_query)

运行结果分析

当你运行上述代码,会看到智能体如何一步步决策:

  1. 第一次迭代:智能体意识到需要比较两款产品,首先调用vector_search分别检索产品A和产品C的信息;
  2. 第二次迭代:获取价格和基本功能信息后,智能体发现缺少关于“初创公司”场景的评估,于是调用web_search搜索相关评测;
  3. 第三次迭代:综合所有信息后,智能体认为信息足够,调用final_answer生成对比分析报告。

易错点提示:在实现过程中,最常见的问题是工具调用陷入死循环。比如智能体反复调用同一个工具,却因为参数写错而不断返回空结果。解决方案包括:①设置最大迭代次数(代码中max_iterations);②记录工具调用历史,防止重复调用相同参数的同一工具;③在工具返回空结果时,让智能体“尝试其他工具或换个关键词”。

这个最小原型虽然简单,但已经完整展示了Agentic RAG的核心能力——动态工具调用。你可以基于这个模板,替换真实的知识库和工具实现,快速搭建自己的智能体检索系统。

5. 实战二:迭代优化策略——让智能体学会自我修正

在上一节中,我们的智能体只是“选择工具、调用工具、然后结束”。但真实的Agentic RAG还需要一个关键能力:当第一次检索结果不理想时,智能体能够自我修正。这一节,我们将实现这个“迭代优化”的核心机制。

问题场景:经典的多信息需求查询

假设用户提问:“帮我比较一下产品A、B、C的性价比,考虑价格、功能和售后服务三个维度。” 这是一个典型的多维度综合查询。传统RAG的固定检索很可能只命中价格维度的文档,然后生成片面回答。而Agentic RAG的迭代优化,能确保所有维度都覆盖到。

实现迭代优化:查询重写与策略切换

迭代优化的核心逻辑是:智能体对每次检索结果进行评估,如果发现信息缺失或不完整,就调整策略继续检索。我们通过增加一个“信息完整性评估器”来实现。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
def evaluate_information_gap(query: str, context: str) -> List[str]:
"""
评估当前信息哪些维度还需要补充
返回一个列表,列出还需要检索的缺失维度
"""
eval_prompt = f"""
用户查询: {query}

当前已检索到的信息:
{context}

请分析:当前信息是否完整覆盖了用户查询的所有需求维度?
如果完整,请输出: []
如果有缺失,请输出缺失的维度列表,每个维度用一句话描述。
例如: ["缺少产品C的售后服务信息", "缺少三款产品的价格对比"]

注意:只输出JSON数组,不要输出其他内容。
"""
result = call_llm(eval_prompt, response_format="json")
if isinstance(result, list):
return result
return []

def generate_missing_query(gap: str) -> str:
"""根据缺失维度生成新的检索查询"""
gen_prompt = f"""
基于用户对"产品A、B、C的性价比对比"的需求,现在需要补充以下信息: {gap}
请生成一个精炼的检索查询,用于在知识库中搜索相关信息。

只返回查询语句,不要有其他内容。
"""
return call_llm(gen_prompt, response_format="text")

完整的迭代优化Agentic RAG系统

现在,我们把评估器集成到主循环中,实现“检索→评估→缺失→再检索”的迭代链路。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
def run_iterative_agentic_rag(query: str, max_iterations: int = 10):
"""
带迭代优化的Agentic RAG
"""
context = ""
iteration_count = 0

# 初始化:智能体先获取一次检索结果
initial_decision = agent_decision(query, tools, "")
if initial_decision["action"] == "vector_search":
# 先进行初步检索
result = vector_search(query, top_k=3)
context = f"[初次检索]\n{result}"
print(f"📥 初次检索完成: 共获取{len(result.split(chr(10)))}个信息片段")

while iteration_count < max_iterations:
iteration_count += 1
print(f"\n--- 第 {iteration_count} 轮迭代(评估与优化)---")

# 1. 评估信息完整性
gaps = evaluate_information_gap(query, context)

if not gaps:
print("✅ 信息完整,无需继续检索")
break

# 2. 针对缺失信息生成新的查询
for gap in gaps:
print(f"🔍 发现缺失信息: {gap}")
new_query = generate_missing_query(gap)
print(f"📝 生成新查询: {new_query}")

# 3. 使用合适的工具补充检索
# 这里简单处理:优先用vector_search,如果查不到则用web_search
result = vector_search(new_query, top_k=2)
if "未在知识库中找到" in result:
# 内部知识库没有,切换到网络搜索
print("⚠️ 内部知识库无相关结果,切换到网络搜索")
result = web_search(new_query)

context += f"\n[补充检索: {gap}]\n{result}"

# 检查是否达到迭代次数上限
if iteration_count >= max_iterations:
break

# 4. 基于完整的上下文生成答案
final_prompt = f"""
用户查询: {query}

经过多轮检索和完善,以下是所有收集到的信息:

{context}

请生成一个综合回答,确保覆盖价格、功能、售后服务三个维度,并给出性价比对比结论。
如果某些维度信息仍然缺失,请明确告知。
"""

final_answer = call_llm(final_prompt, response_format="text")
print("\n=== 最终答案 ===")
print(final_answer)
return final_answer

# 测试迭代优化版本
if __name__ == "__main__":
# 使用演示数据,但测试一个需要多轮查询的复杂问题
complex_query = "帮我分析产品A、产品B、产品C的性价比,考虑价格、功能和售后服务三个维度"
run_iterative_agentic_rag(complex_query)

运行效果演示与解读

当你运行这段代码,会看到智能体如何通过迭代优化逐步完善检索结果:

第1轮评估:智能体分析已有信息,发现“缺少产品B和产品C的售后服务信息”、“没有三款产品的直接价格对比”。

第2轮迭代:智能体生成新查询“产品B售后服务信息”、“产品C售后服务信息”、“三款产品价格对比”,逐一调用工具补充检索。

第3轮评估:发现信息基本完整,终止迭代,生成最终答案。

提示:迭代优化虽然强大,但也需要控制成本。每一次额外的工具调用都意味着额外的LLM调用和API费用。在实际项目中,建议设置“迭代次数上限”(5-10次)和“总消耗token上限”。同时,优先使用质量高、可靠性强的内部知识库工具,减少对昂贵的网络搜索调用。

进阶优化:让迭代更“聪明”

在实际项目中,单纯依靠“发现缺失→补充检索”还不够。你还可以实现更高级的优化策略:

策略1:动态结果验证。在每次补充检索后,让智能体验证新获取的信息是否与已有信息一致。如果存在明显矛盾(比如产品A的价格在两个来源中差了3倍),智能体应当标记冲突并寻求第三个来源验证。

策略2:智能终止决策。不一定每次都要填满所有维度。如果智能体对已获取信息的置信度很高,且剩余维度对最终答案的影响很小,可以提前终止。这需要引入一个“置信度阈值”。

策略3:回溯与修正。如果迭代过程中发现之前获取的信息有误(比如某个工具返回了冲突数据),智能体需要有能力“忘记”先前的错误信息,并重新检索正确内容。这类似于人类的“认知修正”过程。

最佳实践:迭代优化在以下场景中效果最为显著:①需要多源信息综合的查询;②知识库数据覆盖不全,需要动态补充;③用户意图不明确,需要在探索中逐步明确。对于简单的事实型查询(如“产品A的价格是多少”),直接使用传统RAG反而更高效。