RAG 系统进化论(八):Agentic RAG(智能体式 RAG),从回答问题到完成任务

RAG 系统进化论(八):Agentic RAG(智能体式 RAG),从回答问题到完成任务

本文导读: Agentic RAG(智能体式 RAG)把系统从执行固定问答流程,推进到自主规划和完成多步骤任务。本文将介绍任务规划、工具选择、多步检索、状态与检查点、并行执行、人工介入、预算和停止条件,理解系统如何根据中间结果调整行动,以及这种自主性带来的新风险。

上一篇的 Multimodal RAG(多模态 RAG)让系统能够检索和理解文本、表格、图片与页面。

但多数 RAG 仍然在执行一条预先设计好的流程:

text 复制代码
接收问题 → 检索证据 → 生成答案

对于简单问答,这已经足够。

如果用户提出一个开放式任务:

text 复制代码
分析过去六个月机械键盘退款率上升的原因,
找出受影响最大的产品和地区,
结合售后工单与产品手册提出三个改进建议。

系统不能通过一次检索直接完成。

它需要:

text 复制代码
查询退款率趋势
→ 找出异常月份
→ 分析产品和地区
→ 检索相关售后工单
→ 查看产品手册和故障说明
→ 验证不同来源是否一致
→ 汇总结论和建议

而且中间结果会改变后续步骤。

如果统计数据表明问题集中在 AX-2048-C,系统才需要继续检索该型号;如果问题集中在物流破损,就应该转向运输数据,而不是继续分析产品故障。

这就是 Agentic RAG 要解决的问题:

让系统围绕一个目标制订计划、选择工具、多步检索,并根据中间结果调整下一步行动。

什么是 Agentic RAG?

Agent(智能体)不是"调用了大模型的聊天机器人",而是一个能够围绕目标反复执行以下循环的系统:

text 复制代码
观察当前状态
      ↓
决定下一步行动
      ↓
调用工具获取新信息
      ↓
更新状态并检查目标
      ↓
继续、调整或停止

Agentic RAG 把检索放进这个循环:

Agentic RAG 与 Modular RAG 的区别

Modular RAG(模块化 RAG)也有路由和工具,但主要路径通常由开发者预先定义。

对比 Modular RAG Agentic RAG
输入 类型相对明确的问题 开放式目标或复杂任务
执行路径 从预设分支中选择 根据中间结果持续规划
工具调用 通常执行一次或固定组合 可以多轮选择和调用
停止方式 流程到达结束节点 判断目标完成或触发限制
典型场景 查政策、查订单、查报表 调查、研究、比较和任务执行

Agentic RAG 并不是一定更好。

能用固定工作流解决的问题,通常不需要引入自主循环。智能体带来的灵活性,也会增加不确定性、延迟和风险。

Agentic RAG 的完整循环

第一步:Planner 把目标拆成计划

Planner(规划器)把一个开放式目标拆成若干可执行任务。

对于退款率分析,初始计划可能是:

text 复制代码
任务 1:查询过去六个月总体退款率
任务 2:按产品和地区拆分异常
任务 3:检索异常产品的售后工单
任务 4:查看相关故障手册
任务 5:汇总原因、证据和建议

一份可执行计划不只包含文字说明,还应该包含:

text 复制代码
任务 ID
任务目标
依赖任务
允许使用的工具
完成条件
当前状态
ts 复制代码
interface PlanStep {
  // 为每个步骤设置稳定标识,便于记录依赖和执行结果
  id: string;

  // 描述该步骤需要得到的具体信息或结果
  objective: string;

  // 只有依赖步骤完成后,当前步骤才能执行
  dependencies: string[];

  // 限制该步骤可以使用的工具范围
  allowedTools: string[];

  // 明确什么结果表示当前步骤已经完成
  completionCriteria: string;

  // 保存等待、执行中、完成或失败等状态
  status: "pending" | "running" | "completed" | "failed";
}

计划不应该一次生成后永远不变。

当任务 2 发现异常集中在某个固件版本时,系统可以增加"查询该版本发布时间和变更内容"这一步。

第二步:Tool Selection 选择合适工具

Tool Selection(工具选择)根据当前任务,从允许列表中选择检索器或业务工具。

可能的工具包括:

text 复制代码
query_metrics:查询经营指标
search_tickets:检索售后工单
search_documents:检索产品手册
search_graph:查询实体关系
inspect_page:查看 PDF 页面或图片
get_order_status:查询订单状态

工具需要明确的输入、输出、权限和副作用。

查询文档通常是只读操作;发送消息、修改订单或创建工单会改变外部状态,风险完全不同。

ts 复制代码
interface AgentTool {
  // 工具名称必须来自系统注册表,智能体不能临时创造工具
  name: string;

  // 说明工具适合完成什么任务,以及不适合做什么
  description: string;

  // 标记工具是否会改变外部系统状态
  sideEffect: "none" | "reversible" | "irreversible";

  // 执行前校验结构化参数、用户权限和调用范围
  execute(
    input: unknown,
    context: AgentContext,
  ): Promise<ToolResult>;
}

模型只负责提出调用建议,真正执行前仍要经过系统校验。

第三步:Multi-step Retrieval 根据结果继续检索

Multi-step Retrieval(多步检索)指后一次查询依赖前一次查询结果。

例如:

text 复制代码
第一步:
查询退款率最高的产品
→ AX-2048-C

第二步:
查询 AX-2048-C 退款原因
→ E1007、按键失灵、运输破损

第三步:
只针对 E1007 检索工单和产品手册
→ 发现问题集中在固件 v3.2.1

第四步:
查询 v3.2.1 的发布时间和变更记录

这与一次生成多个查询不同。

Multi-Query(多查询)通常针对同一个问题并行扩大召回;多步检索则要先观察前一步,再决定下一步问什么。

ts 复制代码
async function executePlanStep(
  step: PlanStep,
  state: AgentState,
) {
  // 根据当前步骤目标和已有证据选择允许的工具
  const toolCall = await selectTool({
    objective: step.objective,
    evidence: state.evidence,
    allowedTools: step.allowedTools,
  });

  // 在执行前校验工具名称、参数、权限和副作用
  const validatedCall = validateToolCall(
    toolCall,
    state.user,
  );

  // 执行工具并获得新的数据、证据或错误
  const result = await runTool(validatedCall);

  // 将结果写入状态,供后续步骤决定新的检索方向
  return updateAgentState(state, step, result);
}

第四步:Memory 与 Checkpointer 保存任务状态

Agentic RAG 可能执行几十秒甚至更长时间,不能只依赖一次模型调用中的上下文。

Memory(记忆)保存任务过程中需要继续使用的信息,例如:

  • 用户目标;
  • 已完成的步骤;
  • 关键中间结论;
  • 已收集的证据;
  • 工具调用历史;
  • 用户补充的信息。

记忆不等于把所有历史原样放入 Prompt(提示词)。

更合理的做法是区分:

text 复制代码
短期状态:当前计划、最近结果和下一步
长期记忆:跨任务需要保留的用户偏好或业务事实
原始记录:完整工具输入、输出和证据来源

Checkpointer(检查点保存器)把当前 State(状态)持久化,使任务能够暂停、恢复或在失败后从某个节点重试。

ts 复制代码
async function saveCheckpoint(
  state: AgentState,
) {
  // 保存当前计划及每个步骤的执行状态
  const snapshot = {
    plan: state.plan,
    currentStepId: state.currentStepId,
    evidence: state.evidence,
    toolHistory: state.toolHistory,
    budget: state.budget,
  };

  // 使用任务 ID 保存版本化检查点,支持暂停后恢复
  await checkpointStore.save(
    state.taskId,
    snapshot,
  );
}

LangGraph(用于构建有状态工作流的框架)可以用状态、节点、边和检查点表达这类长流程,但框架不会自动解决计划质量、权限和停止条件。

第五步:并行处理互不依赖的任务

Parallel Tasks(并行任务)可以同时执行没有依赖关系的步骤。

例如,发现异常产品后,可以并行:

text 复制代码
检索售后工单
查询固件版本
查看产品手册
按地区统计退款率
ts 复制代码
async function runReadySteps(
  plan: PlanStep[],
  state: AgentState,
) {
  // 找出依赖已经完成、当前可以执行的步骤
  const readySteps = findReadySteps(plan);

  // 只并行执行互不依赖且没有写入冲突的只读任务
  const results = await Promise.allSettled(
    readySteps.map((step) =>
      executePlanStep(step, state),
    ),
  );

  // 合并成功结果并记录失败步骤,不让单个错误覆盖整个状态
  return mergeParallelResults(state, results);
}

会修改同一外部资源的任务不能盲目并行,否则可能产生重复操作和数据冲突。

第六步:Human-in-the-loop 让人参与关键决策

Human-in-the-loop(人在回路中)指系统在关键节点暂停,请求人工确认、修改或接管。

适合人工介入的情况包括:

  • 缺少会改变任务方向的重要信息;
  • 多个权威来源相互冲突;
  • 即将调用会产生外部影响的工具;
  • 涉及退款、审批、发送消息等高风险操作;
  • 结论置信度低但业务影响大。
text 复制代码
只读检索产品手册
→ 可以自动执行

根据分析结果创建召回工单
→ 必须人工确认
ts 复制代码
async function authorizeAction(
  call: ToolCall,
) {
  // 只读、低风险调用通过自动权限检查后可以执行
  if (call.sideEffect === "none") {
    return checkReadPermission(call);
  }

  // 会修改外部系统的调用生成清晰预览并暂停任务
  return requestHumanApproval({
    tool: call.name,
    input: call.input,
    expectedEffect: call.expectedEffect,
  });
}

人工确认不应该只显示"是否继续",而要明确展示将调用什么工具、使用哪些参数、产生什么影响。

第七步:Budget 与 Stop Condition 控制循环

Agentic RAG 最危险的问题之一,是系统不知道何时停止。

它可能不断:

text 复制代码
搜索 → 发现新问题 → 再搜索 → 再改计划

Budget(预算)为任务设置资源上限:

text 复制代码
最大步骤数
最大工具调用次数
最大 Token 数
最大费用
最长运行时间
每个数据源的调用上限

Stop Condition(停止条件)定义何时结束:

text 复制代码
目标已经完成
关键结论都有证据
没有新的有效信息
达到资源上限
连续多次工具失败
需要人工输入
ts 复制代码
function shouldStop(
  state: AgentState,
): StopDecision {
  // 目标的全部完成条件满足时正常结束
  if (allObjectivesCompleted(state.plan)) {
    return { stop: true, reason: "goal_completed" };
  }

  // 达到步骤、时间、调用次数或费用上限时强制停止
  if (isBudgetExceeded(state.budget)) {
    return { stop: true, reason: "budget_exceeded" };
  }

  // 连续失败或缺少必要输入时暂停并交给用户
  if (needsHumanInput(state)) {
    return { stop: true, reason: "human_input_required" };
  }

  // 其他情况下允许进入下一轮规划与执行
  return { stop: false };
}

把七个步骤串起来

ts 复制代码
async function runAgenticRAG(
  goal: string,
  user: UserContext,
) {
  // 根据用户目标生成带依赖、工具范围和完成条件的初始计划
  let state = await createAgentState(goal, user);
  state.plan = await createPlan(goal);

  while (true) {
    // 每轮开始前检查目标、预算、失败次数和人工介入条件
    const stop = shouldStop(state);
    if (stop.stop) {
      return finalizeTask(state, stop.reason);
    }

    // 选择当前可执行步骤,必要时并行调用检索工具
    state = await runReadySteps(state.plan, state);

    // 根据新证据判断原计划是否需要增加、删除或调整步骤
    state.plan = await revisePlan(
      state.plan,
      state.evidence,
    );

    // 保存检查点,确保长任务能够暂停和恢复
    await saveCheckpoint(state);
  }
}

这段流程的重点不是 while 循环,而是每轮都有:

text 复制代码
明确目标
受控工具
可检查状态
预算限制
停止条件
证据来源

Agentic RAG 引入了哪些技术和方案?

Agentic RAG 把检索放进一个能够持续规划、行动、观察和调整的任务循环。

技术 主要作用 产生的结果
Planner(规划器) 把开放式目标拆成可执行任务 带依赖和完成条件的计划
Tool Selection(工具选择) 根据当前任务选择检索器、API 或数据库 结构化工具调用
Multi-step Retrieval(多步检索) 根据中间结果继续寻找下一批证据 逐步扩展的证据集合
Memory(记忆) 保存任务历史、已有证据和关键决策 可复用的任务上下文
Checkpointer(检查点) 持久化运行状态 可暂停和恢复的任务
Parallel Execution(并行执行) 同时处理没有依赖关系的子任务 更短的任务等待时间
Human-in-the-loop(人在回路) 在高风险或不确定节点请求人工确认 审批、修改或补充信息
Budget 与 Stop Condition 限制步骤、时间、工具调用和费用 可控的停止结果

常见落地方式可以分成三类。

方案一:有边界的检索智能体

只允许智能体使用少量只读检索工具,并限制最大步骤数。

它适合研究、比较和故障调查,是从普通 RAG 演进到 Agentic RAG 的安全起点。

方案二:可恢复的长任务

text 复制代码
规划 → 执行 → 保存检查点
          ↓
     暂停、恢复或重新规划

通过 State(状态)、Memory 和 Checkpointer 保存任务进度,适合需要多轮检索、耗时较长的分析任务。

方案三:人工监督的业务智能体

智能体可以准备查询或操作方案,但涉及写数据库、发消息、退款和发布等高风险动作时,必须经过人工审批。

这种方案牺牲了一部分自动化程度,却能显著降低错误操作带来的风险。

Agentic RAG 解决了什么?

1. 支持开放式、多步骤任务

系统不再只回答一个事实问题,而可以执行调查、比较、分析和研究任务。

2. 根据中间结果调整计划

后续检索方向由真实结果决定,而不是在开始时写死。

3. 动态选择工具和数据源

系统可以围绕当前步骤选择数据库、文档、图谱、图片或业务接口。

4. 支持暂停、恢复和人工介入

检查点与 Human-in-the-loop 让长任务具备可控性。

Agentic RAG 还留下了什么问题?

能力越自主,行为越难预测。

错误会在多步中累积

早期步骤选错产品,后续查询、分析和结论可能全部建立在错误前提上。

成本和延迟更加不稳定

不同任务执行的步骤数不同,可能从几次调用增长到几十次调用。

安全边界更加重要

智能体可以选择工具并生成参数,必须防止越权查询、提示词注入、重复操作和未经确认的外部修改。

失败位置更难定位

最终答案错误,可能来自:

text 复制代码
计划错误
路由错误
工具参数错误
检索错误
证据判断错误
生成错误
停止过早或过晚

只看最终答案,已经无法判断系统在哪里出了问题。

下一篇:RAG 评测与可观测性

下一篇不再增加新的检索能力,而是回答一个更现实的问题:

text 复制代码
加入查询改写后真的更准了吗?
引入 Reranker 后提升了多少?
智能体为什么调用了错误工具?
一次任务花了多少时间和费用?
错误发生在检索、生成还是工作流节点?

Agentic RAG 让系统能够自主完成多步骤任务。

RAG 评测与可观测性要解决的是:

当系统越来越复杂时,我们怎样用数据证明它变好了,并定位每一次失败发生在哪里?

相关推荐
创安电气研究所1 小时前
用 Node.js 将变频器运行数据接入 MQTT
后端
阿里云大数据AI技术1 小时前
淘天集团基于 Fluss、Paimon 与 StarRocks 构建湖流一体数据链路
大数据·人工智能·flink
六边形战士DONK1 小时前
15-参数的点估计方法[矩估计,极大似然估计]
人工智能·机器学习·概率论
RFID固定资产管理系统2 小时前
适配媒体行业的固定资产管理软件有哪些功能与核心优势
大数据·人工智能·python·媒体
575772 小时前
GEO效果监测实战:用第三方工具交叉验证AI提及率
人工智能·chatgpt
AndrewHZ2 小时前
【LLM技术全景】阶段总结:技术原理篇核心知识回顾
人工智能·深度学习·算法·语言模型·大模型·llm·芯片开发
大勇前进2 小时前
告别 div 满天飞,HTML5 语义化标签真的有必要用吗?
后端
小满zs2 小时前
Go语言第六章(结构体)
后端·go