写在前面

上一篇聊了意图识别——把用户想干嘛搞清楚。但搞清楚意图只是起点,接下来这一步更让我头疼:Agent 到底怎么把一件事一步步做完。

说实话,刚开始做 Agent 的时候,我觉得执行能有多难?让大模型拆个步骤列表,然后照着跑不就行了。结果真正上线才发现,这玩意儿比意图识别还折磨人。用户的输入会变、工具会挂、中间结果会过期、长任务还会越跑越偏。你把执行理解成”跑步骤列表”,那你的 Agent 大概也就是 demo 能看看,真放到多轮、长任务里立马露馅。

这篇文章是”AI Agent 系统设计”系列的第二篇,把自己在规划、纠偏、执行循环上踩过的坑整理下来。Plan、Replan、失败回溯、TAO、Action 选择——这些东西看起来零散,但其实是一条线:怎么让 Agent 在充满不确定性的执行里,一步步受控地走到目标。


从一个让我头疼的场景说起

我做过一个帮团队做技术选型的 Agent——用户把业务背景和技术需求丢给它,它出一份缓存方案/消息队列/数据库选型方案。

第一版做法特别朴素:让大模型输出一串步骤——“分析需求 → 收集现状 → 评估方案 → 输出推荐”,然后照着走。结果跑起来全是问题:

  • 用户中途补一句”Redis Cluster 别推了,运维搞不定”,前面那套计划直接废了
  • 某个查线上服务性能的工具挂了,Agent 卡在那不知道怎么办
  • Agent 推荐了一个运维团队完全没接触过的方案,还一本正经地说”建议引入 Kafka Connect”
  • 跑到第三轮,它已经忘了用户的核心约束是”运维能 hold 住”,开始闷头研究分布式缓存的一致性哈希算法

每一个都是单独的小问题,但叠在一起,整个执行就崩了。

我后来才想明白:执行的问题,根子上出在”计划”这两个字上。


Plan 不是步骤列表

我一开始对 Plan 的理解就是”步骤列表”。但做了一阵发现,这玩意儿回答不了几个关键问题:

  • 用户目标到底是什么?什么叫成功?
  • 当前已知什么、还缺什么?哪些是事实、哪些是推测?
  • 为什么步骤要这样安排?还有没有别的走法?
  • 执行中出问题了,怎么知道、怎么救?

所以我自己总结了一个理解:Plan 不是步骤列表,而是一个可检查、可纠偏、可执行的运行时对象。

Plan 的本质是解决执行中的不确定性。没有 Plan,Agent 从 A 到 B 会跑出各种幺蛾子;有个 Plan,哪怕质量再烂,至少能在 A、B 之间划一条相对清晰的线。

五大不确定性

我把踩过的坑归了五类:

不确定性 含义 缺失后果
目标 要达成什么?什么叫成功? 南辕北辙,越努力偏越远
上下文 已知什么?还缺什么?哪些可信? 凭空 Plan、无中生有、幻觉
路径 有哪几条路?为什么选这条? 生成机械步骤,没法根据情况调整
过程 运行中是否”合法”?怎么判定? 无法及时纠偏,只能一路跑到错
失败 失败有多少种?各自怎么处理? 出错即崩,没有恢复手段

这里有个点特别重要:“为什么选这条路径”比路径本身更重要。 排查问题的时候,极度依赖这个”为什么”。

好 Plan 的五要素

我把一个好 Plan 要回答的问题归成五类(Goal / Context / Choice / Checkpoint / Correction,叫啥都行,名字不重要):

  • Goal:要去哪?什么叫成功?
  • Context:现在啥情况?还缺啥?
  • Choice:怎么走?还有别的路吗?
  • Checkpoint:怎么知道走偏了?
  • Correction:走偏了怎么拉回来?

举我那个技术选型 Agent 的例子,Goal 大概长这样:

1
2
3
4
5
6
7
8
9
10
11
{
"goal": {
"user_goal": "为订单服务选型缓存方案",
"success_criteria": [
"P99 < 10ms",
"运维团队能独立运维",
"成本在预算范围内",
"不推荐用户明确排除的方案"
]
}
}

这里有个我反复栽过的坑:很多形容词都是幻觉的来源。 “高可用”是多可用?”性能好”好到什么程度?”运维能 hold 住”怎么定义?Agent 输出不稳定,很多时候就栽在这些没定义清楚的主观词上。我的做法是把这些标准尽量量化——“P99 < 10ms”比”性能好”靠谱一百倍。实在没法量化的,就丢进知识库让模型检索后再定义。

约束要分硬约束和软约束,独立维护。 上一篇意图识别也提过,这里一样适用。硬约束必须满足(”不能推荐运维不支持的技术栈”),软约束尽量满足、不满足要告知用户(”最好是开源的”)。我把它们放在 System Prompt 里,保证不被长上下文削弱。还有一条铁律:除非用户主动输入新约束,Agent 自己不能改约束——每次改都得有用户输入作证据。

Checkpoint 最容易被忽略

五要素里我最想单独拎出来说的是 Checkpoint。它两个作用:执行中防偏离,以及给后面的纠偏留路标。

1
2
3
4
5
6
{
"checkpoint": [
{ "step_id": "recommend_solution",
"checks": ["方案是否匹配实际 QPS 需求", "运维团队是否有能力运维", "是否排除了用户禁用方案", "成本是否超预算"] }
]
}

Checkpoint 的粒度我一般这么把握:业务逻辑到了新状态(里程碑)、关键中间步骤完成、易出错步骤之后。不能每步都查,太贵;也不能隔太久,查了也白查。

Correction:出错了还能不能挣扎一下

发现偏差后,我给了五种手段:

手段 适用
Retry 重试 工具偶发失败、超时、格式错
Replan 重计划 认定 Plan 本身有问题
Clarify 澄清 缺关键信息,先问用户
Rollback 回滚 数据/状态有错,回某步前
Interrupt 中断 不可挽回,交给用户

这里埋了条线:Correction 里的 action,其实就是后面要讲的 TAO 循环里的 Action,后面会串起来。

高级方案:让 Plan 更靠谱

前面是基础形态。如果想让 Plan 更稳,我试过两个进阶做法。

一是迭代式 Plan 生成。 Plan 生成后别急着执行,先过一道”审查”——我引入了一个 Plan Verifier,对生成的 Plan 打分、挑毛病,类似代码写完做 Code Review。它会指出 Context 漏了啥、Choice 有没有虚构风险、Checkpoint 缺哪类检查、Correction 没覆盖什么场景,然后让大模型据此修正,改完再审,过线了才执行。

1
2
3
4
5
6
7
{
"score": 0.78,
"context_issues": ["没有采集用户当前线上架构信息"],
"choice_issues": ["直接推荐具体方案存在虚构风险,应先确认运维能力边界"],
"checkpoint_issues": ["缺少运维可行性检查"],
"suggestions": ["先追问运维团队技术栈和规模", "增加运维可行性检查点", "增加 Replan 触发条件"]
}

我会监控”平均循环次数”——这个数越高,说明 Plan 生成机制本身越有问题,该回头修生成 Prompt 了。

二是 DAG 式 Plan。 不把 Plan 当线性步骤列表,而是组织成有向无环图,显式标注每个步骤依赖哪些前置步骤——既能识别依赖关系,也方便并行执行。

1
2
3
4
5
6
{
"nodes": [
{ "id": "evaluate_solution",
"depends_on": ["query_metrics", "query_team_capability"] }
]
}

Prompt 里补上依赖识别规则和反常规例子,但大模型识别循环依赖又慢又容易错,最终一定要用代码再检查一遍。这个还能叠加微调——把真实正确的 Plan 数据导出来微调生成模型,效果再上一层。


计划赶不上变化:Replan

Plan 再好,执行中也一定会变。用户会补充信息、工具会挂、假设会失效。这时候就需要 Replan。

我最早的 Replan 特别粗暴——失败 → 把上下文丢给大模型重生成 → 从头跑。有用吗?有一点点。但缺点太明显:已完成步骤、已验证事实全丢了(浪费);重生成时引入新目标新路径,越改越偏(漂移);明明只错了一步却重生成整份计划,杀鸡用牛刀(不可控)。

后来我把 Replan 重新理解为:在执行过程中,基于新的 Goal、Context、Choice、Checkpoint 结果,对原计划进行受控修正。 三个关键词:执行中、新信息、受控修正。

它其实是前面 Correction 的一种实现,和 Retry、Clarify、Rollback 并列。

触发时机和粒度

什么时候触发 Replan?工具失败、上下文变化(多轮里用户补了约束)、违反假设。但要注意:工具成功、各步没问题,也不代表 Plan 能继续——可能数据/状态不对导致推不动。

还有个实践细节:从”发现要 Replan”到”执行 Replan”至少分两步,别在一次调用里同时判定和执行,混在一起表现会变差。

Replan 的粒度我分三种:当前步骤 / 局部 / 全局。好的做法是追求最小化范围 + 尽可能复用已有结果。但代价是——太强调复用,大模型会扭曲已有结果去适配错误结论。

双重判定 + Prompt 要点

触发时机不等于必然 Replan(偶发超时直接重试就行)。我中间加了个判定:代码判定(过滤掉可重试、不需要 Replan 的)+ 大模型判定,再执行。代码判定稳定、快、省 token,基本就是一堆 if-else。

Replan 的 Prompt 我踩过不少坑,后来总结了几个要点:

  • 带上五要素:原目标、目标有没有变;新增/变化了啥;哪个 Checkpoint 没过 + 证据
  • 再次强调约束:硬/软约束丢 System Prompt,防偶发违背
  • 分类输出 + 全部带证据:保留哪些、改了哪些、取消哪些,各自理由

这条我必须单独说:每条 Replan 判断必须基于证据,没有证据不允许声称 Goal/Context/硬约束改变。 我在 Prompt 里加了这句话之后,幻觉问题改善非常明显。这个思路在 Plan 阶段、回溯阶段、Action 选择阶段全都管用。

什么时候问用户我也写在 Prompt 里兜底:涉及强约束必问、参数缺失会致失败就问默认值、关键工具失败无替代就问、权限敏感操作用前先征同意。再加个控制信息防失控:

1
{ "replan_info": { "max_replan_total": 3, "used_replan_total": 2 } }

TCC:借鉴分布式事务的进阶做法

我还试过借鉴分布式事务 TCC(Try/Confirm/Cancel)的思路——先说清楚,这玩意儿局限性强,高失败成本、高外部依赖、高副作用风险才上,普通 Replan 不必搞。

核心想法是:一个看起来合理的 Plan 不一定能执行下去,所以新 Plan 出来后先试运行。

阶段 做什么
Try 找计划里最脆弱、失败代价最高的部分做最小验证(dry-run、查工具可用性、验核心假设),必须低成本、低/无副作用
Confirm 正式执行 + 把 Try 结果写入上下文可复用
Cancel 回滚 Try 临时状态 + 标记失败假设/不可用工具 + 再 Replan 或中断

判定还能不能 Replan,就看还有没有替代的可行方案——路都走完了就无路可走。Try 优先验证”单点故障”——DAG 里被多个后续节点依赖的那个节点。


失败点不等于根因点:回溯

Replan 说着说着就会碰到一个更要命的问题:你定位的”出错的地方”,往往不是真正出错的地方。

这是我琢磨比较多的一块。四个概念先理清:

概念 定义
失败点 错误暴露的位置(工具报错、Checkpoint 没过)——只是表象
根因点 最初引入错误事实/假设/路径的位置——可能离失败点很远
回滚点 状态要恢复到的位置(一般是某 Checkpoint)
Replan 起点 新 Plan 从哪个节点重新生成——可和回滚点重合,也可更早

失败点不等于根因点。 把两者等同,Replan 就会持续失败——你对着表象下刀,只治表症。

一个让我记忆犹新的快照坑

举个缓存选型的例子。用户说”帮我看看订单服务用什么缓存”,Agent 的 A 步查线上服务性能数据,拿到”峰值 QPS 5 万,P99 RT 200ms”,标 Available,基于此判断 Redis 单机方案够用。B 步查当前架构,发现还在用本地缓存。C 步沿用 A 步的 QPS 数据做容量规划,推荐了 3 节点哨兵方案。

结果用户说:”上周刚上线了个活动,QPS 飙到 15 万了。”C 步的容量规划差了 3 倍。

这时候你只看当前步骤,会误判 C 步的容量计算逻辑错了。但真正的根因是:A 步基于旧状态产出的 QPS 数据已经过期,却没被识别出来。

快照的价值就在这——告诉我们每步决策当时看到的状态,从而判断到底是当前步错了,还是上游基于旧状态的结果失效了。

给中间结果标记可信状态

我给每个中间结果标了可信状态:Verified(已验证可信)/ Available(孤证可暂用)/ Suspicious(可能有问题)/ Invalid(确认错误)/ Dirty(自己未必错,但依赖了 Invalid)。实践里简化成三个就够:Verified / Available / Invalid。

配合证据链:每条推理都同步输出证据。一旦某个事实切到 Invalid,大模型能顺着证据链找到根因。

1
2
3
4
peak_qps: 5万,Available
缓存方案推荐:
- 推荐 Redis 哨兵模式,3 节点,Based:peak_qps(5 万 QPS 单机够用)
- 预估内存需求 16GB,Based:peak_qps + 数据集大小估算

一旦 peak_qps 切到 Invalid,大模型能从结构里找到根因。

反向排查 + 候选路径

从失败点反向排查,我整理了个检查清单(可以在迭代里不断补):

  • 当前步骤本身是否执行错误?
  • 当前步骤输入是否正确?
  • 上游中间结果是否仍可信?
  • 上游结果依赖的事实是否正确?
  • 原计划依赖的假设是否仍成立?
  • 用户目标和约束是否变化?

还有一个我觉得特别有用的做法:保留候选路径。不必等失败才重想,把候选路径记下来,失败后回到岔路口换条路。但必须记失败路径,否则 A 失败 → 再选 A → 失败 → 无限循环。

1
2
3
4
5
6
7
8
9
{
"decision_id": "cache_product_data",
"selected": "redis_sentinel",
"candidates": [
{ "path": "redis_cluster", "status": "failed", "reason": "运维不支持 Cluster 运维" },
{ "path": "redis_sentinel", "status": "available" },
{ "path": "memcached", "status": "available" }
]
}

例外:失败原因已修复时,可重选失败路径——所以要存失败原因 + 运行中检测有没有修好。

代码和大模型怎么分工

我有条原则:能用代码就别用大模型。 代码稳定性和性能都更好。

代码干确定性的:遍历 DAG、查上下游、标记 Invalid/Dirty、找最近 Checkpoint、检查循环依赖、控制次数、执行回滚。大模型干语义的:错误现象对应哪类业务根因、用户目标有没有变、新约束影响哪些步骤、中间结果能不能复用、生成候选路径、解释为啥选某 Replan 点。

进阶我做了两件事:

1
2
3
4
5
渐进式扩大回溯(像异常处理,先便宜后扩大)
Replan(根因级) ──失败──→ 回溯一个 Checkpoint ──失败──→ 再扩大 ...(每次配合 TCC 判可行性)

跳跃式回溯(从线性变检索)
{ 问题类型(key) → 回溯位置/新计划(value) } 靠离线分析/向量库积累规律

后者这思路和上一篇意图识别的向量兜底同构——都是把已知案例/方案放进向量库,后续检索出来给大模型参考。

回溯怎么评估

这块我也理了几个指标:根因定位准确率、Replan 起点准确率、已有结果复用率、Replan 恢复成功率、Replan 振荡率。振荡率听着高级其实就是——Agent 在几个相似计划间反复横跳,基本是上下文管理没做好(没记失败路径/原因/控制信息)。

一个实践感受:把成功 Replan 结果拿去微调,效果不明显;但把原 Plan + 成功 Replan 当 few-shot 塞进 Plan Prompt,能显著提升特定场景的 Plan 质量。


走一步看一步,但不是瞎走:TAO

前面讲的 Plan 和 Replan,解决的是”整体怎么走”和”路不通怎么改”。但还有个绕不开的范式:TAO(Think / Action / Observation),本质上就是 ReAct 换了个名字。它解决的是”眼前这一步怎么走”。

和 Plan 的关系

Plan 和 TAO 不是二选一。我最常用的搭配是:Plan 定大方向,TAO 定眼前这一步。 Plan 里有一步”收集线上服务现状”,但具体怎么收集——从监控系统取?从上次对话召回?查架构文档?问用户补充?——这些是 TAO 要决定的。

反过来说,只有 TAO 没 Plan 也有问题:做着做着忘了目标、在局部细节打转、短视合理长期不合理、重复查询、越走越偏。这基本都是长任务的坑。

而且 TAO 和 Plan 的五要素能对上:

五要素 在 TAO 中的体现
Goal Think 时确认逼近哪个目标
Context Think 时确认知道啥、缺啥
Choice Think 从候选 Action 选下一步
Checkpoint 根据 Observation 判断是否符合预期
Correction Think 决定 Retry/Clarify/Rollback/Replan/Interrupt

核心是状态循环

做 TAO 最容易跑偏的地方,是去抠 T 的 Prompt 怎么写、A 怎么设计、O 怎么实现。但我的体会是:

TAO 的核心不是 T/A/O 各自怎么搞,而是你怎么维护一个 TAO 的状态循环。

TAO 本质是个不断推进的状态机,引擎是大模型(普通状态机用代码推,TAO 用大模型推)。所以问题就变成:一轮 TAO 要维护哪些状态?

我维护这么几个:Goal(防目标偏移,是锚点)、Action(做过啥)、Observation(不是原始返回值,是解读结果)、Fact(最重要,单独拎出来)。

1
读取当前状态 → Think → 选 Action → 执行 Action → 生成 Observation → 更新状态 → 判断下一步

Goal 是锚——没有它,大模型很容易陷局部最优。比如搜到一堆 Redis Cluster 性能对比资料就沉迷继续搜,忘了用户的核心约束是”运维能 hold 住”。每轮 Think 都得重新检查:当前 Action 能不能推进目标、和目标差啥、成功标准满足没、能不能停。

Fact State 我必须单独强调。 缺少结构化维护,大模型就会把推测当事实、忘用户强调的东西(”别推 Redis Cluster”结果推了)。尤其长任务,关键事实不能只靠上下文摘要——摘要会压缩,压缩就丢细节。我的做法是关键事实单独提取、单独存储,Prompt 里单独一块。

你就这么理解:Agent 的长期记忆能力很差,你得在每一轮都把关键事实显式喂给它,不然它就忘。

Think / Action / Observation

Think 要做四类判断:

  • 目标判断:逼近哪个目标(方向不对,搜到再多技术资料也是白费)
  • 状态判断:已知什么、缺什么——简化成”缺啥补啥”
  • 路径判断:有哪些候选 Action、用哪个
  • 停止判断:信息够不够做判断——防两个极端:停太早 vs 停不下来

Action 我有个比较抽象的看法:万物皆 Action。工具 ≠ Action,接口更 ≠ Action——Action 是二次封装产物,可封装外部工具、内部接口,也能聚合多个。用户交互也是 Action(比如让用户补充压测数据或者确认业务高峰期时间窗口)。

Observation 我想强调一句:解释数据比存储数据重要得多。 Action 执行后不能把原始结果直接塞回大模型,得先整理成结构化 Observation:真成功没?获得哪些新事实(带证据)?符合预期不?还缺啥?有无异常/违约?推翻原假设没?取得实际进展没?

1
2
3
4
5
6
7
8
{
"action_id": "query_service_metrics",
"execution_status": "success",
"new_facts": ["订单服务峰值 QPS: 5 万", "P99 RT: 150ms"],
"missing_information": ["大促期间峰值 QPS 未知"],
"state_changes": ["性能需求已初步量化"],
"suggested_next_action": "query_current_architecture"
}

最难的是判定”实际进展”——我引入了 Slot Filling,每个槽位被填 = 新进展。连续多次搜索都没新内容,就该记录 { "progress": false, "information_gain": "low" },然后换路径/问用户/Replan。

六个出口 + 双层循环

一轮 TAO 结束有六个出口:Continue(还能推进)、Finish(成功标准满足)、Clarify(缺关键信息)、Retry(偶发失败)、Replan(路径本身有问题)、Error/Interrupt(兜底,防一直思考)。

长任务我用了双层 TAO 循环:内层管”下一步怎么走”,外层管”走得还对不对”(监督 Goal 漂移、约束违反)。外层可以异步,也可以每 N 轮或到 Checkpoint 同步跑一次。这玩意儿实现不难,但特别治长任务漂移——长任务最大的问题不是某步偶错,而是小错误不断累积,第 1 轮漏约束 → 第 2 轮基于错状态选动作 → 第 3 轮基于错结果更新状态,最后每步看着都合理,整体偏到十万八千里。

一句话总结:TAO 循环的本质 = 不断缩小当前状态和目标状态之间的差距。走一步看一步,但不是瞎看,也不是瞎走。


选对 Action 比选多 Action 更重要

TAO 里如果说什么最重要,我认为是选对 Action,没有之一。

粒度、可用性、权限

Action 的粒度标准:一个业务上完整的操作。 内部可调一个工具、多个工具,甚至启动子 Agent,但业务上是一个独立完整的步骤。子 Agent 作 Action 是我特别爱用的——主 Agent 把上下文完整传过去,子 Agent 自决用哪部分。

尽量保持 Action 正交(职责边界清晰不重合)。但实践里没法完全正交:查服务性能指标 vs 查服务依赖拓扑都涉及”查服务信息”,职责有重合,容易选错。所以”尽量正交”——边界清晰比数量少更重要

可用性上我的原则是:提供者自保高可用,别寄望 Agent 容错。 Action 内部把能处理的错误自己处理掉(重试/降级/互为替代封装),降低大模型负担。

权限控制其实不复杂:判断有无权限 + 记录授权信息(含时限)+ 审计。两种做法——封装(每 Action 自己管,可控但重复)和通用 AOP 装饰器(统一管理,扩展性稍差)。Action 看作资源、执行 Action 看作操作,纳入传统 RBAC/ABAC 就行。

Action 怎么描述 + 怎么选

每个 Action 我让它带这些:name、description、applicable_scenarios、inapplicable_scenarios(正反定义边界)、required_params(参数越少越好、默认值最好内部解决)、返回值最小化(别拿到啥暴露啥)。

选择规则我总结了五条:

  1. 只能选候选 Action:名字定义成枚举 + 代码检查。容易错的点是——本轮没提供 Action1,大模型从上下文得知有它就选了,所以检查不能只查”存不存在”,要查”是不是本轮候选”
  2. 前置检查用代码:结合权限/候选/参数合法性,极端上规则引擎
  3. 结合 Replan 排除错误选项:记录已试 Action,重试时排除结果不好的(网络/数据同步类的例外,之前不好用的可能突然好用了)
  4. 输出决策理由 + 证据:减幻觉 + 排查依据 + 沉淀正反例拿去微调
  5. 结合 few-shot 正反案例:Action 名作 key,例子作 value

海量 Action 怎么办

Action 一多就头大。我的思路是把”选出最终 Action”看成一条流水线,最后一环基本是大模型筛选,前面每环要么代码要么大模型:

  • 基于意图 / 基于标签(意图关联或打标签筛选)
  • 规则引擎(上下文描述作规则,比如没加载用户当前架构就不放”方案评估”的 Action)
  • 大模型多次粗筛(海量 Action + 少量上下文[目标+缺失数据] 粗筛,不用太准)
  • 向量召回(Action 描述/时机/正反例入向量库)
  • 前置条件过滤(没有当前服务 QPS 数据就不放”容量规划”的 Action)
  • 权限过滤、历史成功率过滤

这些不互斥,自由组合。

还有一个改 Prompt 的思路:从”选最可能完成任务的 Action”改成”选能最大程度降低不确定性的 Action”。两者大多一致,但部分不一致——优先选能补足信息的 Action,防止信息缺失就直接做最终决策。

候选数量上,行业里通常建议 3-5 个,但我的实践是只要筛选准确度够高,多放几个也没问题。正交的多放无妨,边界模糊的少放也掉准确率。


怎么评估效果

做 Agent 不能只做不评。这一套下来我主要看几类指标:

Plan / Replan 相关:

  • Plan 完成率、步骤成功率、重 Plan 触发率、用户纠正率、最终任务成功率
  • 回溯五指标:根因定位准确率、Replan 起点准确率、已有结果复用率、Replan 恢复成功率、Replan 振荡率

TAO 相关:

  • Think:动作选择准确率(最重要)、动作参数准确率、目标判断准确率、信息缺口识别准确率、停止判断准确率
  • Action:执行成功率、响应时间(传统工程范畴)
  • Observation:事实提取准确率、证据绑定准确率、工具结果误读率
  • 整体:最终任务成功率、平均 TAO 轮数、平均工具调用次数、平均 Token 消耗、任务平均延迟

大多数指标离不开 LLM as Judge,只有少数能代码直接采集。但能把这套评估体系讲清楚,说明你真的在做 Agent 而不是 demo。


示例展示

说了这么多,还是用我那个技术选型 Agent 走一遍,把这些串起来。

第一轮:生成 Plan + 开始执行

用户输入:

“帮我看下订单服务用什么缓存方案好,运维人手不多,不能瞎推荐”

Agent 先做意图识别(上一篇聊过),进入规划。生成的 Plan(五要素)节选:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
{
"goal": { "user_goal": "为订单服务选型缓存方案",
"success_criteria": ["运维团队能独立运维","满足性能要求","不推荐用户排除的方案"] },
"context": { "known_facts": ["订单服务","运维团队人手有限"],
"missing_info": ["当前 QPS","当前架构","运维技术栈","预算"] },
"choice": { "selected_path": "采集现状→追问缺失→评估方案→输出推荐",
"steps": [
{ "id": "query_metrics", "objective": "查询线上服务性能数据" },
{ "id": "query_architecture", "objective": "查询当前架构和技术栈" },
{ "id": "ask_missing", "objective": "追问缺失关键信息" },
{ "id": "evaluate", "objective": "评估候选方案" },
{ "id": "recommend", "objective": "输出最终推荐" }
] }
}

进入 TAO 循环,第一步 Think:目标=查询服务现状,缺=QPS/架构/运维能力,候选 Action=查监控工具/查架构文档/问用户。选了”查监控工具”。执行后 Observation:{ "execution_status": "success", "new_facts": ["峰值 QPS 5 万", "P99 RT 150ms"], "missing_information": ["大促期间峰值 QPS"], "progress": true }。Fact State 里峰值 QPS 标 Available。

第二轮:用户补约束 → 触发 Replan

用户补了一句:

“对了,Redis Cluster 别推了,运维那边搞不定”

这是上下文变化(新增硬约束)。触发时机命中,但先过双重判定:代码判定这是”用户新增约束”非偶发错误 → 大模型判定需要局部 Replan。Replan 输出(带证据):

1
2
3
4
5
6
{ "replan": {
"kept": [{ "step": "query_metrics", "reason": "性能数据已验证" }],
"modified":[{ "step": "evaluate", "change": "排除 Redis Cluster 方案",
"reason": "用户新增硬约束:运维不支持 Cluster" }],
"cancelled": []
}, "replan_info": { "max_replan_total": 3, "used_replan_total": 1 } }

约束再次强调进 System Prompt,继续执行。

第三轮:工具失败 → 回溯找根因

执行到”评估方案”时,调用容量计算工具失败。失败点在这。 但我不急着 Replan——先反向排查。

记的快照显示:A 步(查询性能)当时基于”峰值 QPS 5 万”生成了一些中间判断,标 Available。继续排查发现,容量计算工具需要”大促期间峰值 QPS”这个参数,而这个参数从未被采集到——根因点其实在”追问缺失信息”那步漏问了大促峰值。

失败点(评估方案时工具失败)≠ 根因点(追问步骤漏了大促峰值)。

回滚到 ask_missing 步,复用 query_metrics 的可信结果(标 Verified 的保留),局部 Replan:补一个”追问大促峰值 QPS”的动作。候选路径表里记下容量计算工具 failed(原因:缺参数),等参数补齐后可重选。

第四轮:Action 选择 + 纠偏

参数补齐后,Think 重新选 Action。候选 Action 有:容量计算工具、方案知识库检索、问用户补充。这次代码前置检查发现容量计算工具的失败原因(缺参数)已修复,允许重选。大模型输出决策理由 + 证据:

选容量计算工具。理由:参数已补齐,且该工具能直接基于实际 QPS 计算所需节点数,信息增益最大。证据:ask_missing 已采集到大促峰值 QPS 数据(Available)。

执行成功,Observation 标注取得实际进展,Fact State 里大促峰值从 missing 切到 Verified。

到 Checkpoint(recommend 步之前)校验:方案是否匹配实际 QPS?是。运维能否独立运维?是。是否排除了 Redis Cluster?是。通过,继续。

示例小结

走下来能看到这一整套是怎么咬合的:

  1. Plan(五要素) 给了整体路径和检查点
  2. TAO 状态循环 推进每一步,Fact State 单独维护防幻觉
  3. Replan 在用户补约束时做受控局部修正,而非推倒重来
  4. 回溯 在工具失败时找到真正的根因(漏问大促峰值),而不是对着失败点瞎改
  5. Action 选择 用候选路径 + 证据 + 信息增益,选对了推进状态的下一步
  6. evidence-based 贯穿全程——Checkpoint 带证据、Replan 分类输出带理由、Action 选择输出依据

写在最后

规划、纠偏、执行循环这事,说简单也简单——让大模型拆个步骤列表就能跑起来;说难也难——要扛住多轮、长任务、工具失败、用户变卦,得在 Plan、Replan、回溯、TAO、Action 上下不少功夫。

核心就两句话:状态管理是 Action 选择的基石,Action 选择准确是推动状态前进的抓手;而证据约束,是防止大模型幻觉最有效的手段。

说到底,Agent 执行得好不好,不在于模型多强,而在于你能不能把”当前状态”和”目标状态”之间的差距,一步步受控地缩小。

如果你也在做 Agent,我的建议和上一篇一样:先跑起来,再逐步优化。先有效果,再谈效率。状态管理和证据约束这两件事,值得从第一天就埋进去。


本站由 sswfive 使用 Stellar 1.44.0 主题创建。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。

本站总访问量