AI 纪元 追踪人工智能最新进展,深度解读前沿技术

Prompt越写越长,Agent还是跑偏?给它加一道反思闭环

Agent 在长任务里跑偏,继续往 Prompt 里加规则,常常只会让首轮输入更臃肿。更稳妥的做法,是把生成、评估、修正拆开,再用 PASS、最大轮次、状态机和人工审核管住循环。

0 次阅读 约 3727 字 7 分钟 AI 生成

一个常见场景: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 适合承载这类流程,因为每一步都能做成节点,结果通过条件边进入下一步。一个实用的状态对象可以保留:

  • task
  • draft
  • issues
  • runtime_feedback
  • loop_count
  • is_passed

节点则对应 generate、evaluate、refine、human_review 和 end。条件边只需要处理几种明确情况:通过后结束,未通过且次数未耗尽时修正,次数耗尽或触发高风险规则时转人工。

退款、支付、权限和敏感数据流程尤其需要这层路由。以电商售后为例,退款申请不符合政策时,Agent 不应继续琢磨怎样把拒绝说得更像批准。规则命中后,要按预设路径拒绝或转人工。具体的 LangGraph 状态机设计,可参看《用 LangGraph 管住售后 Agent 的退款路径》。

反思负责修正可修正的输出,状态机负责守住不能越过的边界。

多一轮检查,成本要按节点算

加入反思后,一次模型调用会变成至少一次生成和一次评估;首轮失败,还会增加修正和复评。实际 Token 消耗取决于每个节点的上下文与输出长度,应该根据调用日志计算,不能套一个固定倍数。

控制成本有两个直接办法。

第一,不要每轮都回灌完整历史。评估器通常只需要任务要求、当前结果、检查规则和最新运行反馈。修正器也只需要当前结果与问题清单。

第二,检查规则足够明确时,可以测试中小模型或蒸馏模型来承担评估节点。例如 JSON Schema、固定字段和明确语法规则,未必需要与生成器相同的模型。涉及复杂业务语义时,再使用更强模型或外部验证器。模型混用要靠自己的测试结果决定,不能先假设小模型一定够用。

反思也会一起犯错

如果生成器和评估器看到的是同一份错误材料,两者可能共享同一个盲点,把错误内容越改越顺。涉及外部事实、库存、价格、账户状态或政策条款时,需要接入检索、数据库、业务接口或人工审核。多跑一轮语言模型,不能代替真实证据。

真实设备和毫秒级控制场景更要谨慎。电网控制、机器人动作等路径没有时间等待三轮语言反思,安全约束、硬编码规则和底层控制器应先拦截危险动作。反思更适合用来分析失败原因,或调整下一轮策略。

先搭一个能跑的最小版本

第一次接入反思闭环,可以只做三件事:

  1. 选择一个结果可验证的任务,例如代码编译、单元测试或 JSON Schema 检查。
  2. 用 Python 或 LangGraph 搭出 [Generator] → [Evaluator] → [Loop Controller],失败时再进入 Refiner。
  3. 设置 max_loops = 2,并把 PASS 绑定到真实检查结果,而不是评估器的一句主观判断。

如果 Agent 能在第二轮读取报错日志,改正写错的 API 名称并通过执行,说明这条反馈路径已经工作。接下来该做的是补检查规则和异常路由,而不是继续往原 Prompt 里追加二十条禁令。

Prompt 决定首轮从哪里出发;评估标准、停机条件和路由,决定这套系统能不能被管住。

参考资料

相关阅读