我做的 AI Agent 干活又快又利索、可交出来的东西总在一些低级地方出错:算术算错、漏掉任务明确要求的一个环节、格式不符规定,而它对这些错误浑然不觉,排查很久才意识到它从生成完那一刻起就再没回头看过自己的产出、压根没拿结果对照过最初目标的深度复盘

我做的 AI Agent 干活又快又利索,接到任务一口气就做完、把结果交上来,看起来很专业。可交出来的东西总在一些让人无语的低级地方出错:汇总报告里的总额把几个分项加错了少加一项、任务白纸黑字要 Top3 它只列了 Top2 就收尾、要求输出 JSON 它输出了带 Markdown 包裹的文本。这些错都不隐蔽,但凡拿结果回头对一遍任务要求就能发现,可 Agent 浑然不觉、信心十足地把带错的结果当最终答案交付。我以为是模型能力不行,换了更强的模型低级错少了点但偶尔漏项偶尔格式错却毫不自知的毛病依旧。直到把执行轨迹一步步看下来才看清根因:它的流程里从来就没有生成之后、交付之前拿产出对照目标自查一遍这个环节,它把生成出一个答案直接等同于交付一个正确答案了。根因是大模型的一次生成本质是产出一个看起来合理、读起来通顺、大概率正确的结果,它优化的是表面合理性、不保证逐条满足任务的每项硬性要求(环节齐不齐、数字经不经得起复算、格式结构合不合规、有没有跑题);生成出一个答案和这个答案正确是两件事、中间永远隔着一道拿产出对照目标逐条核对的验证工序,人做事会本能补上这道闸(算完再核、写完再读、交付前对清单打勾),而 Agent 不会自发做、除非显式设计进流程。正解是在生成与交付之间插入一个显式的反思/自我验证环节,形成生成→验证→不过则修正→再验证的闭环,把硬性要求拆成可检查项,能用确定性手段(代码复算、schema 校验、清单核对)验的绝不只靠模型自评、确定性覆盖不到的语义层面再用独立 critic 补上,并设轮数上限、几轮仍不过就标记人工介入而非自信地交付错误结果。这篇复盘从故障现场讲到生成与做对之间缺了验证、无验证与有闭环对照、怎么诊断,再到生成-验证-修正闭环的完整正解与骨架,以及工具返回不检查/多步不校验/代码不跑测试/检索不核实等同类坑,和区分做完与做对、在产出和交付之间永远补一道验证闸的认知。

我做的 AI Agent 干活又快又利索、可交出来的东西总在一些低级地方出错:算术算错、漏掉任务明确要求的一个环节、格式不符规定,而它对这些错误浑然不觉,排查很久才意识到它从生成完那一刻起就再没回头看过自己的产出、压根没拿结果对照过最初的目标

这是一次让我把 AI Agent 的工作流,从"让它把活干完",重新理解成"让它把活干完、再回头验一遍才算数"的事故。我做的 Agent 干活又快又利索,接到任务一口气就做完、把结果交了上来。可交出来的东西,总在一些让人无语的低级地方出错:一份汇总报告里的数字加错了、任务里白纸黑字要求的某个环节它直接漏掉了、输出格式跟规定的不一样。更让我不解的是,它对这些错误浑然不觉,信心十足地把带着错的结果当成最终答案交付。我排查了很久才意识到一件关键的事:它从"生成完"那一刻起,就再也没有回头看过自己的产出,压根没拿结果对照过最初的目标和要求。这篇就把这次"Agent 做完了却没做对、还不自知"的事故,从头到尾复盘一遍。

故障现场:结果又快又自信,却带着自己毫不知情的错

我的 Agent 流程很直接:接收任务 → 理解 → 调工具/生成内容 → 输出结果。比如"根据这份销售数据,生成一份包含总额、环比、和 Top3 产品的月报",它会读数据、算一算、写成一段报告输出。流程跑得飞快,看起来很专业。

可问题反复出现:有一次它报告里的"总额"把几个分项加错了(少加了一项);有一次任务明确要"Top3 产品",它只列了 Top2 就收尾了;还有一次要求输出 JSON,它输出了一段带 Markdown 包裹的文本。这些错误都不隐蔽,但凡拿结果回头对一遍任务要求就能发现。可 Agent 没有发现——它生成完报告,就直接当成最终答案交了,中间没有任何"我再核对一下"的动作。我一开始以为是模型能力不行,换了更强的模型,低级错误是少了点,但"偶尔漏一项、偶尔格式错、却毫不自知"的毛病依旧。直到我把它的执行轨迹一步步看下来,才看清根因——它的流程里,从来就没有"生成之后、交付之前,拿产出对照目标自查一遍"这个环节;它把"生成出一个答案"直接等同于"交付一个正确答案"了。

# 我最初的 Agent: 生成即交付, 中间没有任何自我验证
def run_agent(task):
    plan = understand(task)
    result = generate(plan)      # 生成出一个"看起来合理"的结果
    return result                # ★ 直接交付! 没有回头对照 task 检查对不对

# 问题:
#   - generate 的产出是"差不多对", 不是"核对过确实对"
#   - 算术错、漏环节、格式不符 —— 这些只要拿 result 对一遍 task 就能发现
#   - 但流程里压根没有"对一遍"这一步, 错误就这样原样交付了
#   - Agent 对自己的错"毫不知情", 因为它从没被要求回头看

# 我的错误假设: "模型生成出来的, 就是对的" —— 把"做完"当成了"做对"

问题被钉死在这个缺失的环节上:我的 Agent 流程里只有"生成",没有"验证";而大模型的一次生成,本质是"产出一个看起来合理、大概率对"的结果,它不保证这个结果真的满足了任务的每一条要求。"生成出一个答案"和"这个答案正确"之间,隔着一道"拿答案对照要求逐条核对"的工序;而我把这道工序完全省掉了,默认"它既然生成出来了,那就是对的"。于是那些只要回头看一眼就能逮住的错误——加错的数、漏掉的 Top3、错误的格式——全都毫无阻拦地交付了出去。我让 Agent "做完了",却从没让它"检查自己做得对不对"。

第一件事:想明白"生成"和"做对"之间,缺了"验证"这一步

把这次事故彻底想清楚,关键是理解大模型的"生成"是一个"尽力产出一个合理答案"的过程,它优化的是"看起来对、读起来顺",而不是"逐条满足了任务的硬性要求";要让产出真的可靠,必须在"生成"之后补上一个独立的"验证/反思"环节——拿产出对照原始目标和要求,逐条核对、挑错、若有错就修正,通过了才交付。

人做复杂的事,天然会有"做完再检查一遍"的习惯:算完账会再核一遍数、写完报告会回头读一遍看有没有漏项、交东西前会对着要求清单打勾。这个"回头自查"的动作,是质量的最后一道闸。但 Agent 不会自发地做这件事——除非你显式地把它设计进流程里。它的一次生成,就像人"凭着感觉一口气写完",写的时候自信满满,但没回头检查,就难免有自己没察觉的疏漏。"生成"解决的是"有没有产出",而"验证"解决的是"产出对不对";这是两个不同的目标,需要两个独立的步骤,不能指望一次生成就把两件事都包圆了。我的 Agent 缺的,正是这后一步。

# 关键认知: "生成" 和 "验证" 是两个独立的目标, 需要两个步骤

# 一次 generate 内部, 模型在优化的是:
#   "产出一段看起来合理、符合语言习惯、大概率正确的内容"
# 它【没有】在专门优化:
#   "逐条核对任务的每一个硬性要求是否都被满足了"

# 所以需要把流程从 [生成→交付] 改成 [生成→验证→(不过则修正)→交付]:
def run_agent(task):
    plan = understand(task)
    result = generate(plan)

    # ★ 补上验证环节: 拿 result 对照 task, 逐条核对
    issues = verify(result, task)     # 算术对吗? 要求的环节齐吗? 格式对吗?
    while issues:                      # 有问题就修正, 再验证, 直到通过
        result = revise(result, issues, task)
        issues = verify(result, task)
    return result                      # 验证通过了, 才交付

# verify 在问什么(本质是把"做对"显式地检查出来):
#   - 任务要求的每一项, result 里都有吗? (漏环节?)
#   - 数字/计算 经得起复算吗?               (算错?)
#   - 输出格式/结构 符合规定吗?             (格式不符?)
#   - 有没有偏离最初的目标?                 (跑题?)

想通这一层,我才明白自己错在哪:我把 Agent 的"一次生成",当成了一个"既负责产出、又负责保证正确"的全能步骤,但它其实只负责前者。"做完"和"做对"之间,永远隔着"检查"这一步;人会本能地补上它,Agent 不会,除非我把它明确地设计进流程。我省掉这一步,等于让 Agent 凭着第一感觉交活、从不复核——再强的模型,在"没人(包括它自己)回头看一眼"的流程里,也一定会把那些"一查就出"的错,原样交到用户手上。产出不等于正确,中间那道"验证"的闸,省不得。

第二件事:正解——加一个显式的"反思/自我验证"闭环

找到根因,正解就清晰了:在 Agent 的"生成"和"交付"之间,插入一个显式的"验证/反思"环节(generate → verify → revise → 再 verify 的闭环)——让它(或一个独立的 critic 角色)拿产出对照原始任务的每一条要求逐项核对,把硬性约束写成可检查的清单,发现问题就带着问题去修正、再验证,直到通过才交付。能用确定性手段(代码、规则、schema)验的,就别只靠模型自评。

# 正解: generate-verify-revise 闭环, 把"做对"显式地兜住
def run_agent(task, max_rounds=3):
    plan = understand(task)
    result = generate(plan)

    for _ in range(max_rounds):
        issues = verify(result, task)   # 逐条核对要求
        if not issues:
            return result               # 验证通过, 交付
        result = revise(result, issues, task)  # 带着问题去修正
    # 几轮仍不过 → 别硬交, 标记需人工介入或返回最佳努力+已知问题
    return finalize_with_warnings(result, issues)

# verify 的两种实现, 优先用确定性的:
def verify(result, task):
    issues = []
    # ① 确定性检查(最可靠): 能用代码/规则/schema 验的, 绝不只靠模型
    if task.want_json and not is_valid_json(result):
        issues.append("输出不是合法 JSON")
    if task.required_sections:
        for sec in task.required_sections:        # 要求的环节是否齐全
            if sec not in result:
                issues.append(f"缺少要求的环节: {sec}")
    if task.has_numbers:
        if not recompute_matches(result, task.data):  # 数字复算核对
            issues.append("数字与源数据复算不一致")
    # ② 模型自评/独立 critic(补确定性检查覆盖不到的语义层面)
    issues += llm_critic(result, task)   # "对照目标, 找出问题; 没问题就回 OK"
    return issues

这套做法的精髓,是把"生成"和"验证"拆成两个独立的职责,并用一个"不通过就修正、修正完再验"的闭环,把质量真正兜住。验证环节优先用确定性手段(能跑代码复算的就复算、能用 schema 校验格式的就校验、能列清单核对环节齐不齐的就核对)——这些比模型自评可靠得多;确定性手段覆盖不到的语义层面(论证是否站得住、是否跑题),再用模型自评或一个独立的 critic 角色补上。关键是让"对照目标自查"成为流程里一个雷打不动的步骤,而不是可有可无的运气。不是寄望于一次生成就完美,而是承认第一版常有疏漏、用验证闭环把疏漏在交付前逮住并修掉。

【给 Agent 加质量闭环, 我现在认死的几条】

1. 生成 ≠ 正确: "做完"和"做对"是两步, 中间隔着"验证"

2. 在 生成 和 交付 之间, 必须有一个显式的 验证/反思 环节

3. 验证 = 拿产出逐条对照任务的硬性要求(环节齐?算对?格式合?跑题?)

4. 能用确定性手段验的(代码复算/schema/清单), 绝不只靠模型自评

5. 不通过就 修正 再 验证, 形成闭环; 但要有轮数上限防死循环

6. 几轮仍不过别硬交: 标记人工介入, 或返回结果+已知问题清单

7. 独立 critic 比"自己夸自己"更可靠: 让验证角色带着挑刺的视角去看

第三件事:其他"只管产出、不管验证产出对不对"的同类坑

顺着"产出不等于正确、缺了验证这一步"这条线,我把 Agent 系统里同类的坑都排查了一遍,它们都源于"把'生成了/做了'当成了'做对了'":

第一个,调用工具后不检查工具的返回是否成功/合理。Agent 调了个工具拿到返回就往下用,可那个返回可能是报错、是空、是不合预期的格式;不验证就用,错误会一路传染下去。

第二个,多步任务每步不校验就进入下一步。前一步的产出有问题,后一步基于它继续做,错误层层放大,最后整个结果崩坏,却很难定位是哪一步先错的。

第三个,生成代码不跑测试就当完成。Agent 写完代码直接说"完成了",但没编译、没跑测试;能不能运行、对不对,全靠猜——而这恰恰是最容易确定性验证的。

第四个,检索到信息不核实就直接采信RAG/搜索拿到的内容可能不相关、过时、甚至矛盾,Agent 不加判断就拿来生成答案,把垃圾输入变成自信的错误输出。

第四件事:无验证 vs 有验证闭环——一张对照表

我把"生成即交付"和"生成→验证→修正闭环"摆在一起对比,核心看"错误能不能在交付前被逮住":

维度 生成即交付(无验证) 生成→验证→修正(有闭环)
对待第一版产出 当成最终正确答案 当成待核对的草稿
低级错误(算错/漏项/格式) 原样交付, 毫不自知 验证时被逮住并修正
错误暴露的时机 用户使用时才发现 交付前自己先发现
对模型的依赖 全押在"一次生成就对" 承认会错, 用闭环兜住
失败时的行为 自信地交付错误结果 几轮不过则标记人工介入
质量稳定性 靠运气, 时好时坏 有下限, 硬性要求被保证

看清这张表,设计就有谱了:把第一版产出当"草稿"而非"定稿",在交付前用验证闭环逐条核对硬性要求、不过就修正,能确定性验证的就别靠模型自评。我这次踩坑,就是把第一版直接当定稿交付,押注"一次生成就对",而模型恰恰不保证这件事。验证闭环不是不信任模型,而是承认"任何一次生成都可能有疏漏"这个事实,并为它准备好一道兜底的闸。

第五件事:我曾经对 Agent"生成即正确"想当然的几个误区

这次事故也把我对 Agent 产出的一堆"想当然"照了个底朝天:

我以为 实际上
模型生成出来的结果就是对的 生成优化的是"看起来合理", 不保证逐条满足硬性要求
换更强的模型就不会出低级错 能力上限高了, 但没人回头查, 偶发疏漏照样原样交付
Agent 会自己发现明显的错误 除非显式设计验证环节, 它生成完就不再回头看
让模型"自己说对不对"就够了 能确定性验的(算术/格式)用代码更可靠, 自评会漏会偏
加验证太麻烦, 多数时候没必要 正是"多数对、偶尔错且不自知"最坑, 闭环才能保下限

这些误区的根子是同一个:我把"Agent 产出了一个结果"默认成了"这个结果是正确的",而没意识到"产出"和"正确"之间,缺了"验证"这道必经的工序。当我让 Agent 一口气生成完就交付时,我其实是在赌"它这一次没出错";而对一个偶尔会算错、会漏项、会格式跑偏的生成过程来说,这个赌注迟早会输,输的代价就是用户收到一个 Agent 自己都不知道错在哪的结果。给产出补上一道验证的闸,本质是把质量从"靠运气"变成"有保证"。

第六件事:设计 Agent、排查"产出有低级错却不自知"时,我现在的自检习惯

现在每当我设计 Agent 流程、或排查"Agent 交付的结果带着它自己不知道的错",我都会先按这张图问自己:

这张图的精髓,是"生成不等于正确;在生成和交付之间,必须有一个对照目标逐条核对的验证环节,能确定性验的别只靠自评"设计就把流程做成 生成→验证→修正 的闭环、把硬性要求拆成可检查清单、优先用代码/schema 做确定性验证、排查就先看流程里到底有没有"交付前回头对照目标自查"这一步这套习惯,让我从"让 Agent 把活干完"变成了"让 Agent 干完再验过才算数"——核心始终是:大模型的一次"生成"本质是产出一个"看起来合理、读起来通顺、大概率正确"的结果,它优化的是表面的合理性,而不保证逐条满足了任务的每一项硬性要求(要求的环节是否齐全、数字计算是否经得起复算、输出格式结构是否符合规定、有没有偏离最初目标);所以"生成出一个答案"和"这个答案正确"是两件事,中间永远隔着一道"拿产出对照原始目标和要求逐条核对"的验证工序——人做事会本能地补上这道闸(算完再核、写完再读、交付前对清单打勾),而 Agent 不会自发地做、除非你把它显式地设计进流程;正解是在生成与交付之间插入一个显式的反思/自我验证环节,形成 generate→verify→(不过则)revise→再 verify 的闭环,把硬性要求拆成可检查项,能用确定性手段(代码复算、schema 校验、清单核对)验的绝不只靠模型自评、确定性覆盖不到的语义层面再用独立 critic 补上,并设轮数上限、几轮仍不过就标记人工介入而非自信地交付错误结果。

我立下的几条规矩

这场"Agent 做完了却没做对、还不自知"的事故,换来了我设计 Agent 时,刻进骨子里的几条铁律:

  1. 生成 ≠ 正确:"做完"和"做对"是两步,中间必须隔着"验证"。
  2. 在生成和交付之间,放一个雷打不动的"对照目标自查"环节。
  3. 把任务的硬性要求拆成可检查清单:环节齐?算对?格式合?跑题没?
  4. 能用代码/schema/复算确定性验证的,绝不只靠模型自己说对不对。
  5. 不通过就带着问题修正、再验证,形成闭环;但设轮数上限防死循环。
  6. 几轮仍不过别硬交:标记人工介入,或返回结果+已知问题清单。
  7. 把第一版产出当草稿而非定稿;独立 critic 比自己夸自己更可靠。

附:我现在给 Agent 落地"生成-验证-修正"质量闭环的骨架

这是我现在给 Agent 加质量闭环固定套的骨架——把这次踩坑的教训(生成与验证分离、确定性验证优先、不过则修正、设上限)固化成一套结构,让"做完没做对还不自知"那种坑再不会埋进流程:

from dataclasses import dataclass, field

@dataclass
class Check:
    name: str
    fn: callable          # 返回 None 表示通过, 返回字符串表示问题描述
    deterministic: bool   # 是不是确定性检查(代码/schema), 优先级更高

class VerifiedAgent:
    def __init__(self, checks, max_rounds=3):
        # 确定性检查排在前面, 优先暴露硬错误
        self.checks = sorted(checks, key=lambda c: not c.deterministic)
        self.max_rounds = max_rounds

    def run(self, task):
        result = self.generate(task)
        for round_no in range(1, self.max_rounds + 1):
            issues = [msg for c in self.checks
                      if (msg := c.fn(result, task)) is not None]
            if not issues:
                return {"ok": True, "result": result, "rounds": round_no}
            # 带着具体问题去修正, 而不是重新瞎生成
            result = self.revise(result, issues, task)
        # 几轮仍不过: 不硬交, 交还人工 + 暴露已知问题
        return {"ok": False, "result": result, "issues": issues,
                "need_human": True}

# 用法: 把任务的硬性要求, 写成一条条可执行的检查
checks = [
    Check("合法JSON", lambda r, t: None if is_json(r) else "输出非合法JSON", True),
    Check("环节齐全", lambda r, t: missing_sections(r, t), True),
    Check("数字复算", lambda r, t: None if recompute_ok(r, t) else "数字对不上", True),
    Check("未跑题",  lambda r, t: llm_critic_offtopic(r, t), False),  # 语义层靠 critic
]
agent = VerifiedAgent(checks)
out = agent.run(task)
if not out["ok"]:
    escalate_to_human(out)   # 验证没过, 宁可交人工, 不自信地交付错的

这套骨架把我这次的教训钉死在了结构里:每一条硬性要求都写成一个可执行的检查、确定性检查(JSON 合法、环节齐全、数字复算)排在前面优先暴露、语义层面才交给 critic;生成出的结果先当草稿过验证、不通过就带着具体问题去修正再验、几轮仍不过就交还人工而非硬着头皮交付这样,那些"一查就出"的低级错(漏 Top3、加错总额、格式不符),在交付前就被这道闸逐条逮住,而不再是当初那个"生成完就自信交付、错了也不自知"的裸奔流程。把"区分做完与做对、永远在产出和交付之间补一道验证"这个道理,沉淀成 Agent 的固定骨架,这是我对这次"带病交付"最实在的交代——毕竟,真正决定用户拿到的东西对不对的,不是 Agent 生成得多流畅,而是那道交付前认真回头核对的闸。

写在最后

回头看,这场由"缺少自我验证"引发的"Agent 自信地交付带错结果"事故,真正教给我的,远不止"加一个 verify 步骤"这一个技巧。它让我对"'把一件事做出来'和'把一件事做对',从来都不是同一件事;在'产出'和'正确'之间,永远横着一道叫'检查/验证'的工序——而这道工序,恰恰是最容易在'看起来已经做完了'的成就感里、被悄悄省略掉的一步",有了一次刻骨的体会。我栽跟头,是因为我把"Agent 产出了一个结果"默认等同于了"这个结果是对的"——我被它"又快又利索、自信满满"的样子骗了,以为流畅的产出就意味着可靠的质量;我没意识到,它的"生成"追求的是"产出一个看起来合理的东西",而不是"逐条核对过、确认满足了每条要求";这两个目标之间,差的正是"回头拿结果对照一遍目标"这道工序;而我的流程里压根没有这道工序,于是 Agent 就像一个"凭感觉一口气写完、从不回头检查就交卷"的人,那些一查就出的低级错,自然原样落在了卷面上、还浑然不觉这让我领悟到一个关于"产出与正确、做完与做对"的深刻认知:任何创造性的产出过程(生成、制造、执行、表达),其本身都只对"产出一个东西"负责,而不天然对"这个东西正确无误、满足了全部要求"负责;后者需要一道独立的、专门的"验证"工序——拿产出去对照最初的目标和约束,逐条核对、挑错、修正;这道验证工序是质量的最后一道闸,也是最容易被省略的一道:因为"东西已经做出来了"带来的完成感,会强烈地诱使人(和 Agent)直接交付,跳过那个"再回头看一遍"的、看似多余实则关键的步骤;而真正决定产出可靠性的,往往不是"生成得多漂亮",而是"有没有一道认真的验证把疏漏挡在交付之前"——尤其当产出者自己对疏漏毫无察觉时,这道外部于"生成"的检查,就是唯一的防线这给了我一种看待"一切'产出/交付'之事"时的清醒:每当我(或我的系统)产出了一个东西、准备交付时,要追问"我只是把它'做出来了',还是真的拿它对照过要求、确认它'做对了'?在产出和交付之间,有没有一道认真的验证?那些一查就能发现的硬性要求(齐不齐、对不对、合不合规),我核对过了吗"——把"生成"和"验证"当成两个独立的步骤,绝不让完成的成就感诱使我跳过回头自查那一步;"区分'做完'与'做对'、在产出和交付之间永远补上一道验证的闸",是做对 Agent、也是做对一切产出之事的关键认清生成不等于正确、做完和做对中间隔着验证、要把自查显式设计进流程——这,是我用一次 Agent 自信交付带错结果的事故,换来的、关于 AI Agent、也关于如何对待自己每一份产出的、最朴素也最深刻的领悟。如果这篇复盘,能让你下次设计 Agent、或自己交付一份东西前,先停一下问"我验证过它真的对了吗,还是只是把它做完了?",并补上那道回头核对的工序,那我对着那些 Agent 自信交付、却带着低级错的结果挠头的许多个夜晚,就值了。

—— 别看了 · 2026
声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理 邮箱1846861578@qq.com。
技术教程

我在 TypeScript 里到处用感叹号非空断言把编译器的红线消掉、它不报错我就以为安全了,结果线上照样满屏 Cannot read properties of undefined 的崩溃,排查很久才彻底想通那个感叹号根本不会在运行时做任何检查、它只是我对编译器单方面许下的一个空头承诺的深度复盘

2026-6-3 7:33:44

技术教程

我在 Python 类里直接写了个空列表当属性、想让每个对象都有自己独立的一份,结果给一个对象的列表追加元素、所有对象的列表里竟然都冒出了同一个元素,我对着代码看了半天都不敢相信,最后才搞懂那个列表根本不属于任何一个对象而是被全体实例共用的同一个的深度复盘

2026-6-3 7:45:46

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索