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

196 阅读13分钟

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

Agentic RAG:从用户目标、任务规划和工具选择到多步执行、状态管理与完成条件

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

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

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

接收问题 → 检索证据 → 生成答案

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

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

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

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

它需要:

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

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

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

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

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

什么是 Agentic RAG?

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

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

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

图 8-2:Agentic RAG 从目标规划、工具执行到反馈调整的自主循环

Agentic RAG 与 Modular RAG 的区别

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

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

Agentic RAG 并不是一定更好。

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

Agentic RAG 的完整循环

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

可能的工具包括:

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

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

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

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

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

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

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

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

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

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

例如:

第一步:
查询退款率最高的产品
→ AX-2048-C

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

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

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

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

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

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(提示词)。

更合理的做法是区分:

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

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

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(并行任务)可以同时执行没有依赖关系的步骤。

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

检索售后工单
查询固件版本
查看产品手册
按地区统计退款率
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(人在回路中)指系统在关键节点暂停,请求人工确认、修改或接管。

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

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

根据分析结果创建召回工单
→ 必须人工确认
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 最危险的问题之一,是系统不知道何时停止。

它可能不断:

搜索 → 发现新问题 → 再搜索 → 再改计划

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

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

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

目标已经完成
关键结论都有证据
没有新的有效信息
达到资源上限
连续多次工具失败
需要人工输入
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 };
}

把七个步骤串起来

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 循环,而是每轮都有:

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

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 的安全起点。

方案二:可恢复的长任务

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

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

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

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

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

Agentic RAG 解决了什么?

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

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

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

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

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

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

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

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

Agentic RAG 还留下了什么问题?

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

错误会在多步中累积

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

成本和延迟更加不稳定

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

安全边界更加重要

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

失败位置更难定位

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

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

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

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

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

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

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

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

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