一个常见场景:Prompt 已经写到 3000 字,里面塞满 Only output JSON、Do not... 和各种例外规则。每遇到一次错误,就补一条禁令。已知样例暂时稳住了,换一个边缘输入,Agent 又从中间某个步骤开始跑偏。
继续加 Prompt,解决的多半是已经见过的问题。复杂任务真正缺少的,是首轮输出之后的检查和纠错。
Prompt 能约束首轮,兜不住长链路
Prompt 仍然有用:定义目标、输入、格式和禁区。可一旦任务包含规划、工具调用、代码执行和多步判断,所有稳定性都压在一次生成上,风险会沿着链路往后传。
传统软件开发不会要求程序员一次写出 1000 行无 Bug 代码。Agent 也一样。即便用 GPT-5 处理长上下文,生成结算、支付等业务代码后,编译、测试和边界检查仍然不能省。模型名不能替代验证环节。
代码补全中的这类问题,可参看《AI 代码补全看着很对,为什么一运行就错》。从 PRD 生成测试脚本也有相同特征:输出看起来完整,不等于脚本真的能跑,执行反馈和分段评审需要进入流程,相关做法见《从 PRD 到测试脚本:AI 端到端测试流怎么搭》。
这两类任务都有明确反馈:编译错误、测试结果、运行日志。与其出错后由人手动复制给模型,不如直接把反馈接进 Agent 的下一轮。
先分清反思和盲目重试
把错误输出原样发回去,再补一句“你写错了,重新生成”,只是重试。模型没有检查标准,第二轮可能修好一个问题,又改坏原本正确的部分。
《Agentic AI Guide》对术语做了区分:广义的 reflection 指模型审视并修正自身输出;狭义的 Reflexion 通常指带语言记忆的试错学习框架。日常项目里的“生成—评估—改进”,多数属于广义 reflection。ReAct 更偏向执行过程中根据观察即时调整,反思则常发生在一轮完成之后。
最小闭环可以画成这样:
任务 → Generator → Evaluator ── PASS → 交付
└─ FAIL → Refiner → 再评估
其中有三类内容节点:
Generator:生成首版结果或执行第一次动作。Evaluator:按照业务规则、测试结果或运行反馈找问题。Refiner:只处理评估器指出的问题,避免无目标重写。
工程上还要加一个 Loop Controller,记录循环次数,并决定通过、重试、失败还是转人工。
评估器可以与生成器使用同一个模型,但 Prompt、输入和输出格式要分开。是否换用不同模型,取决于成本和检查准确率;职责分离才是关键。CSDN 的反思机制介绍也强调,评估和改进应由两个 Prompt 分工。
PASS 要真正接进路由
小林面试笔记在讲反思机制时特别提醒:评估器需要给出 PASS,让系统在结果够好时停止。否则模型会持续挑毛病,甚至把已经正确的内容改错。
PASS 在系统里是路由信号,不能只写在一段自然语言评语里。至少需要两个字段:
is_passed:是否通过。issues:未通过时,列出可定位的问题。
循环也要有上限。可以先设置 max_loops = 2;任务允许 3 轮时,也要提前规定第三轮结束后的去向,例如转人工或明确返回失败。
一个框架无关的 Python 伪代码如下:
max_loops = 2
draft = generator(task)
for _ in range(max_loops):
runtime_feedback = run_checks(draft)
review = evaluator(task, draft, runtime_feedback)
if review["is_passed"]:
return draft
draft = refiner(draft, review["issues"])
return handoff_or_fail(draft)
这里最重要的不是循环本身,而是 run_checks 和退出路径。没有测试,也没有失败出口,循环只会多消耗几次调用。
评估器要指出问题坐标
“这段 SQL 不太对”没有修复价值。评估结果至少要说明位置、违反的规则和修改方向。例如:
{
"is_passed": false,
"issues": [
{
"location": "SQL 第 5 行",
"rule": "NULL 值处理",
"suggestion": "增加 COALESCE"
}
]
}
评估 Prompt 也不必写得很长,边界清楚更重要:
你只负责检查,不重写答案。
按照给定规则逐项判断。
发现问题时,输出位置、违反的规则和修复建议。
没有阻断问题时,返回 is_passed: true。
能用程序验证的项目,优先运行程序。代码先编译、跑单元测试;结构化输出先检查 JSON Schema;工具调用先看真实返回和报错日志。模型适合解释这些结果并提出修改方向,不该凭空猜测“应该已经通过”。
评估项也不宜无限扩张。生成 SQL 时,就检查语法、字段、NULL 值和业务条件;生成接口代码时,就检查编译结果、API 名称和测试失败项。让评估器泛泛地“找出所有可以改进的地方”,很容易得到一堆不影响交付的风格建议。
用 LangGraph 把循环变成可见路由
LangGraph 适合承载这类流程,因为每一步都能做成节点,结果通过条件边进入下一步。一个实用的状态对象可以保留:
taskdraftissuesruntime_feedbackloop_countis_passed
节点则对应 generate、evaluate、refine、human_review 和 end。条件边只需要处理几种明确情况:通过后结束,未通过且次数未耗尽时修正,次数耗尽或触发高风险规则时转人工。
退款、支付、权限和敏感数据流程尤其需要这层路由。以电商售后为例,退款申请不符合政策时,Agent 不应继续琢磨怎样把拒绝说得更像批准。规则命中后,要按预设路径拒绝或转人工。具体的 LangGraph 状态机设计,可参看《用 LangGraph 管住售后 Agent 的退款路径》。
反思负责修正可修正的输出,状态机负责守住不能越过的边界。
多一轮检查,成本要按节点算
加入反思后,一次模型调用会变成至少一次生成和一次评估;首轮失败,还会增加修正和复评。实际 Token 消耗取决于每个节点的上下文与输出长度,应该根据调用日志计算,不能套一个固定倍数。
控制成本有两个直接办法。
第一,不要每轮都回灌完整历史。评估器通常只需要任务要求、当前结果、检查规则和最新运行反馈。修正器也只需要当前结果与问题清单。
第二,检查规则足够明确时,可以测试中小模型或蒸馏模型来承担评估节点。例如 JSON Schema、固定字段和明确语法规则,未必需要与生成器相同的模型。涉及复杂业务语义时,再使用更强模型或外部验证器。模型混用要靠自己的测试结果决定,不能先假设小模型一定够用。
反思也会一起犯错
如果生成器和评估器看到的是同一份错误材料,两者可能共享同一个盲点,把错误内容越改越顺。涉及外部事实、库存、价格、账户状态或政策条款时,需要接入检索、数据库、业务接口或人工审核。多跑一轮语言模型,不能代替真实证据。
真实设备和毫秒级控制场景更要谨慎。电网控制、机器人动作等路径没有时间等待三轮语言反思,安全约束、硬编码规则和底层控制器应先拦截危险动作。反思更适合用来分析失败原因,或调整下一轮策略。
先搭一个能跑的最小版本
第一次接入反思闭环,可以只做三件事:
- 选择一个结果可验证的任务,例如代码编译、单元测试或 JSON Schema 检查。
- 用 Python 或 LangGraph 搭出
[Generator] → [Evaluator] → [Loop Controller],失败时再进入Refiner。 - 设置
max_loops = 2,并把PASS绑定到真实检查结果,而不是评估器的一句主观判断。
如果 Agent 能在第二轮读取报错日志,改正写错的 API 名称并通过执行,说明这条反馈路径已经工作。接下来该做的是补检查规则和异常路由,而不是继续往原 Prompt 里追加二十条禁令。
Prompt 决定首轮从哪里出发;评估标准、停机条件和路由,决定这套系统能不能被管住。