Skip to content

Agent 编排 ​

Agent 不是「更聪明的 ChatBot」,而是能自己决定下一步做什么的程序。这篇的重点不是「怎么让它更自主」,而是怎么给它装上刹车。

1. 从 ChatBot 到 Agent ​

形态一次请求里发生什么
ChatBot一问一答,固定流程
带工具的 ChatBot一问 → 最多调几个工具 → 答(由我们写好顺序)
Agent一问 → 模型自己决定「查什么/调什么/要不要再查」→ 多轮 → 答

分界线在决策权归谁:流程写死在代码里 = 工作流;流程由模型动态决定 = Agent。

代价:不可预测(同样的输入可能走出不同路径)、成本不可控(可能调 1 次也可能调 20 次)、调试困难。所以真实项目里最常见的是**「工作流 + 局部 Agent」**。

2. ReAct:最常用的循环 ​

Question: 用户问「我们上季度华东区销售额同比增长多少?」
  Thought: 需要先查上季度华东区销售额,再查去年同期
  Action: query_sales({"region":"华东","quarter":"2026Q1"})
  Observation: 1280 万
  Thought: 还需要去年同期的数据
  Action: query_sales({"region":"华东","quarter":"2025Q1"})
  Observation: 1000 万
  Thought: 同比增长 28%,可以回答了
  Final Answer: 同比增长 28%(1280 万 vs 1000 万)
Question: 用户问「我们上季度华东区销售额同比增长多少?」
  Thought: 需要先查上季度华东区销售额,再查去年同期
  Action: query_sales({"region":"华东","quarter":"2026Q1"})
  Observation: 1280 万
  Thought: 还需要去年同期的数据
  Action: query_sales({"region":"华东","quarter":"2025Q1"})
  Observation: 1000 万
  Thought: 同比增长 28%,可以回答了
  Final Answer: 同比增长 28%(1280 万 vs 1000 万)

三个必须有的东西:

  1. 停止条件:拿到足够信息,或达到最大步数;
  2. 观察压缩:工具结果要截断/摘要,否则几轮就撑爆上下文;
  3. 失败可恢复:工具报错后,让模型看到错误并决定换路,而不是直接崩。

常见失败:

症状原因处理
反复调同一个工具结果不满足它,或者没看懂返回值返回值加明确字段 + 提示「已查询过,不要重复」
死循环缺停止条件最大步数 + 同一工具连续失败 2 次就中止
越绕越远任务太开放收紧系统提示词,给出明确的子目标
忘记已有信息上下文被工具结果挤满中间结果摘要,只保留关键数字

3. Plan-and-Execute:先列计划再执行 ​

Plan: 
  1. 查订单 → 2. 判断是否超时 → 3. 超时则查物流 → 4. 生成答复
Execute: 逐步执行,每步可观察
Replan: 某步失败/结果异常 → 重新规划剩余步骤
Plan: 
  1. 查订单 → 2. 判断是否超时 → 3. 超时则查物流 → 4. 生成答复
Execute: 逐步执行,每步可观察
Replan: 某步失败/结果异常 → 重新规划剩余步骤
对比ReActPlan-and-Execute
决策粒度每步都问模型一次规划,多次执行
成本步数多、调用多调用少、省 token
灵活性高(随时改主意)低(计划错了要 replan)
适合探索型任务(找资料、排障)结构清晰的复杂任务(多步业务流程)

4. Reflexion:让 Agent 自我批评 ​

1. 生成初稿 → 2. 自我检查(对照要求/事实/格式)→ 3. 发现问题就改 → 4. 最多 2 轮
1. 生成初稿 → 2. 自我检查(对照要求/事实/格式)→ 3. 发现问题就改 → 4. 最多 2 轮

要点:

  • 检查项要具体(「是否引用了资料」「数字是否来自工具」),否则模型只会说「看起来不错」;
  • 最多 1~2 轮,多了收益锐减、成本上升;
  • 适合「可验证」的任务(代码能跑、JSON 能解析、断言能过),不适合开放式写作。

5. 工作流 + 局部 Agent(生产推荐) ​

用户输入
  ↓
① 意图分类(规则或小模型,确定性强)
  ├─ 简单 FAQ   → 直接 RAG 回答(不动用 Agent)
  ├─ 查询类     → 固定 2 步工具调用(工作流)
  ├─ 需要规划   → 进入 Agent 循环(最多 5 步)
  └─ 高风险     → 转人工
  ↓
② 结果校验(格式/事实/敏感词)
  ↓
③ 输出
用户输入
  ↓
① 意图分类(规则或小模型,确定性强)
  ├─ 简单 FAQ   → 直接 RAG 回答(不动用 Agent)
  ├─ 查询类     → 固定 2 步工具调用(工作流)
  ├─ 需要规划   → 进入 Agent 循环(最多 5 步)
  └─ 高风险     → 转人工
  ↓
② 结果校验(格式/事实/敏感词)
  ↓
③ 输出

为什么要先分类:80% 的请求其实走确定流程就够,没必要付 Agent 的成本和不确定性。能用规则的地方不要用模型。

6. 编排:把它写成状态机 ​

不要用「while + if」硬写循环,用状态机/图表达:

java
// 伪代码:节点 + 边 + 终止条件
var graph = Graph.builder()
    .node("classify", this::classify)          // 意图分类
    .node("retrieve", this::retrieve)          // RAG
    .node("plan",     this::plan)              // 拆任务
    .node("act",      this::act)               // 调工具
    .node("reflect",  this::reflect)           // 自检
    .node("answer",   this::answer)
    .edge("classify", ctx -> switch (ctx.intent()) {
        case FAQ   -> "retrieve";
        case QUERY -> "act";
        case PLAN  -> "plan";
    })
    .edge("plan", "act")
    .edge("act", ctx -> ctx.needReflect() ? "reflect" : "answer")
    .edge("reflect", ctx -> ctx.passed() ? "answer" : "act")   // 有上限!
    .build();
// 伪代码:节点 + 边 + 终止条件
var graph = Graph.builder()
    .node("classify", this::classify)          // 意图分类
    .node("retrieve", this::retrieve)          // RAG
    .node("plan",     this::plan)              // 拆任务
    .node("act",      this::act)               // 调工具
    .node("reflect",  this::reflect)           // 自检
    .node("answer",   this::answer)
    .edge("classify", ctx -> switch (ctx.intent()) {
        case FAQ   -> "retrieve";
        case QUERY -> "act";
        case PLAN  -> "plan";
    })
    .edge("plan", "act")
    .edge("act", ctx -> ctx.needReflect() ? "reflect" : "answer")
    .edge("reflect", ctx -> ctx.passed() ? "answer" : "act")   // 有上限!
    .build();

好处:每个节点的输入输出可见、可单测、可观测,出问题能定位到具体节点。LangGraph 这类框架的本质就是这个。

7. 边界控制:给 Agent 装刹车 ​

刹车设多少为什么
最大步数5~10防死循环
单次 token 预算按成本倒推防烧钱
单步超时 + 总超时工具 3~10s,总 60~120s防拖死请求
工具白名单显式声明防越权
同一工具连续失败2 次即中止防无效重试
危险操作审批下单/退款/删除类要人确认人在回路(Human-in-the-loop)
幂等键每个任务一个重试不重复执行

人在回路的两种形态:

  • 阻断式:危险操作前暂停,等用户点「确认」(体验差但安全);
  • 旁路式:先执行,异步复核,异常再回滚/告警(体验好,要求业务可补偿)。

8. 失败处理 ​

失败表现处理
工具超时某步卡住超时转重试(1 次)→ 换备选工具 → 降级话术
工具返回空模型反复重试明确告诉它「没有结果,请换方式或告知用户」
幻觉调用不存在的工具报 unknown tool把可用工具清单再强调一次,或走兜底
输出不合格式解析失败带着错误信息重试 1 次
模型服务故障全部失败切备用模型 → 固定话术(见 07 工程化)

9. 怎么评估一个 Agent ​

指标含义
任务成功率端到端是否达成目标(最重要)
平均步数越少越好(成本和延迟)
单任务成本token × 价格 + 工具调用费
P95 耗时用户能不能忍
人工接管率兜底触发频率
失败归因分布选错工具 / 参数错 / 理解错 / 上游错

评估集要包含多步任务,不能只用单轮问答 —— 单轮看不出 Agent 的价值,也测不出它的坑。

10. 速查表 ​

问题一句话
Agent 和工作流的区别流程写死 = 工作流;模型自己决定下一步 = Agent
ReAct 三步Thought → Action → Observation,直到 Final Answer
Agent 必备的刹车最大步数、预算、超时、白名单、人工审批
为什么生产用「工作流 + 局部 Agent」80% 请求走确定流程就够,省钱省心
Plan-and-Execute 与 ReAct 选谁结构清晰用 Plan,探索型用 ReAct
Reflexion 适合什么可验证的任务(代码/JSON/断言),最多 1~2 轮
死循环怎么防步数上限 + 同工具连续失败 2 次中止
怎么编排写成状态机/图,节点可单测可观测
怎么衡量任务成功率 + 平均步数 + 单任务成本 + P95