我的 AI Agent 调工具查数据时返回了个空结果,它却当成查到了、基于这个空结果一路推理下去,最后给出一个看起来很完整其实全错的答案,我排查了大半天的复盘

用户让我的 Agent 查某用户订单并汇总,它有条理地查订单、算总额、生成报告,最后给出一份格式工整的报告说"共 0 笔订单、总额 0 元"——可这用户明明有一堆订单。查日志才倒吸凉气:第一步"查订单"工具因网络抖动失败了、返回了空,而我的 Agent 压根没检查这个返回是成功还是失败,直接把空当成"真的没订单",一本正经基于"0 笔"继续推理,生成了那份全错却看起来完全合理的报告。深挖才懂是 Agent 缺了对工具返回的校验和反思:工具调用和任何外部调用一样会失败,而 Agent 盲目信任每一步结果、错误像滚雪球一路累积放大,还全程自信、最终包装成无懈可击的报告极具欺骗性。这篇从 Agent 为何必须自我怀疑讲起,到每步校验工具返回+反思纠偏的正解、Agent 可靠性设计模式、空结果与调用失败必须分清、reflection 的几种实现、带校验反思重试的步骤封装,以及那句最戳心的——健壮系统骨子里都是悲观的,不指望不出错而追求出错也能及时发现优雅应对,预设失败为每种错误设计好检测与应对。

我的 AI Agent 调工具查数据时返回了个空结果,它却当成查到了、基于这个空结果一路推理下去,最后给出一个看起来很完整其实全错的答案,我排查了大半天的复盘

这是一个让我对 AI Agent "盲目信任"刻骨铭心的故事。我做了一个能自己调用工具、多步完成任务的 AI Agent。某次,用户让它"查一下某用户的订单、并汇总金额"。Agent 很有条理地:第一步,调用"查订单"工具;第二步,基于查到的订单,算总额;第三步,生成报告。整个过程行云流水,最后给出了一份格式工整、措辞专业的报告。可用户一看就发现不对:报告里说"该用户共 0 笔订单、总额 0 元",可这个用户明明有一堆订单!我追查日志,才倒吸一口凉气:原来第一步那个"查订单"的工具,因为一个临时的网络抖动,调用失败了,返回了一个空结果(或错误);可我的 Agent,压根没检查这个返回是成功还是失败,而是直接把这个"空"当成了"真的没有订单",然后一本正经地基于"0 笔订单"继续推理,最后自信地生成了那份"全错、却看起来完全合理"的报告。

我顺着这个现象深挖,才终于揭开真相,补上了我对 Agent 工程一个最关键的认知漏洞:问题的核心,是我的 Agent 缺少了一个至关重要的环节——对工具返回结果的"校验"和"反思(reflection)"。我一直想当然地以为,"Agent 调了工具,工具就会乖乖返回正确的结果,Agent 拿来用就行";可真相是:工具调用,和任何外部调用一样,是会失败的——网络会抖、API 会报错、数据会查空、返回格式可能不对;而我的 Agent,是"盲目信任"的:它无条件地相信每一步工具返回的结果都是正确、可用,从不停下来检查一下"这个结果到底对不对、是不是真的成功了"更致命的是,这种盲信会"累积放大":第一步拿到了一个错误的结果(空),第二步基于这个错误继续算,第三步基于第二步的错误继续生成……错误,像滚雪球一样,在 Agent 的每一步推理中,被层层传递、不断放大;而由于 Agent 全程"自信满满"、每一步都"看起来合理",这个从根上就错了的结果,最终被包装成了一份无懈可击的报告,极具欺骗性我这才痛彻地明白:一个可靠的 Agent,不能是一个"盲目乐观、一往无前"的执行者;它必须具备"自我怀疑"的能力——在每一步行动之后,都要停下来"反思"一下:"我这一步,真的成功了吗?这个结果,合理吗、可信吗?";只有对每一个中间结果都保持审视、加以校验,才能及时发现错误、纠偏止损,避免一个小小的失败,被层层累积成一场全盘皆错的灾难。Agent 的"智能",不仅在于"会一步步行动",更在于"检查自己每一步行动的结果"

故障现场:Agent 盲信工具返回,错误一路累积

我把这个"盲信导致全错"的现场,用伪代码摊开给你看:

# ✗ 灾难: Agent 盲目信任工具返回, 不校验, 错误一路累积放大
def agent_run(task):
    # 第1步: 查订单
    orders = call_tool("query_orders", user_id)   # ✗ 工具可能失败/返回空/报错
    # ✗ 没有任何校验! 直接当成"查到的订单"用
    # (实际: 网络抖动, 工具失败, orders = [] 或 {"error": "timeout"})

    # 第2步: 基于 orders 算总额(基于错误数据继续)
    total = sum(o["amount"] for o in orders)      # ✗ orders 是空 → total = 0(错!)

    # 第3步: 基于 total 生成报告(错误继续传递放大)
    report = llm.generate(f"用户共 {len(orders)} 笔订单, 总额 {total} 元, 写份报告")
    return report   # ✗ "0 笔订单, 0 元" —— 格式完美, 内容全错!

# 错误是怎么"累积放大"的?
#   第1步: 工具失败 → 拿到空/错误结果(根上的错)。
#   第2步: 基于空结果算 → 得到 0(错误传递)。
#   第3步: 基于 0 生成报告 → 一份"合理但全错"的报告(错误被包装)。
#   → 一个临时网络抖动, 最终变成一份骗过所有人的错误报告。

# 为什么这么危险?
#   - Agent 全程"自信", 每步"看起来合理" → 错误极隐蔽。
#   - 错误从源头一路传到终点, 中间没有任何"刹车/检查点"。
#   - 最终产物"形式完美"(报告工整), 极具欺骗性, 难被发现。

# 缺的是什么?
#   - 缺"校验": 没检查工具返回是否成功、结果是否合理。
#   - 缺"反思": 没在每步后停下来质疑"这步对吗?要不要重试/换路径?"
#   - 缺"防御": 把工具当成"必定成功", 而非"可能失败的外部依赖"。

# 根因: Agent 盲目信任工具返回, 不校验不反思, 单步失败被层层累积放大成全盘错误。

看着这段"错误滚雪球"的流程,我才算彻底想明白了根源。问题的核心,是我的 Agent 盲目信任工具返回、不校验:第一步 call_tool("query_orders") 因网络抖动失败了、返回空或错误,可 Agent 没做任何校验,直接当成"查到的订单"用错误是这么累积放大的:第一步工具失败拿到空结果(根上的错)→ 第二步基于空结果算出 total=0(错误传递)→ 第三步基于 0 生成一份"0 笔订单、0 元"的报告(错误被包装)——一个临时网络抖动,最终变成一份骗过所有人的错误报告为什么这么危险?因为 Agent 全程"自信"、每步"看起来合理",错误极隐蔽;错误从源头一路传到终点,中间没有任何"刹车/检查点";最终产物"形式完美"(报告工整),极具欺骗性缺的是什么?"校验"(没检查工具返回是否成功、结果是否合理)、缺"反思"(没在每步后停下来质疑"这步对吗?要不要重试")、缺"防御"(把工具当成"必定成功"、而非"可能失败的外部依赖")。归根结底:Agent 盲目信任工具返回、不校验不反思,单步失败被层层累积放大成全盘错误——这,就是根源。

第一件事:搞懂为什么 Agent 必须"自我怀疑"

定位到根源,我必须把"Agent 为什么必须校验和反思"从根上彻底搞清楚:

Agent 是"自主多步"的, 单步错误会累积 → 必须每步校验+反思

# Agent 和普通程序的关键区别:
#   - 普通程序: 流程是你写死的, 每步的输入输出可控。
#   - Agent: 自主地"决定下一步做什么", 多步串联, 高度依赖"每步结果"。
#   - 所以 Agent 对"中间结果的正确性"极其敏感: 一步错, 步步错。

# 为什么单步会出错(工具调用不可靠)?
#   - 外部工具 = 外部依赖: 网络抖、API 限流/报错、超时、查空。
#   - 返回格式可能不符预期(尤其工具自身也接了 LLM)。
#   - LLM 自己选错工具 / 传错参数 → 工具返回无意义结果。

# 错误累积放大(Agent 特有的"危险"):
#   - 第1步错 → 喂给第2步 → 第2步基于错的继续 → ... → 终点全错。
#   - 像"传话游戏": 一开始一点偏差, 传到最后面目全非。
#   - 而 Agent 全程"自信", 不会自己喊停 → 错误一路狂奔到终点。

# 所以 Agent 必须有"自我怀疑"机制:
#   1. 校验(verify): 每步工具返回后, 检查 "成功了吗? 结果合理吗?"
#   2. 反思(reflect): 阶段性停下来想 "目前进展对吗? 要不要调整/重试?"
#   3. 防御(defend): 把工具当"可能失败的", 失败要重试/换路/明确报错。

# 关键认知: 可靠的 Agent = 会行动 + 会怀疑自己的行动结果。
#   - "盲目自信、一往无前"的 Agent, 在第一个失败点就开始"带病狂奔"。

# 核心: Agent 自主多步、对中间结果敏感, 而工具调用不可靠、错误会累积放大;
#   必须每步校验工具返回 + 阶段反思 + 失败防御, 让 Agent 学会"自我怀疑"。

原理终于清晰了。Agent 和普通程序的关键区别:普通程序流程是你写死的、每步输入输出可控;Agent自主地"决定下一步做什么"、多步串联、高度依赖"每步结果"——所以它对"中间结果的正确性"极其敏感:一步错,步步错为什么单步会出错?因为工具调用不可靠:外部工具是外部依赖(网络抖、API 限流/报错、超时、查空)、返回格式可能不符预期、LLM 自己还可能选错工具/传错参数而 Agent 特有的危险,是错误累积放大:第 1 步错喂给第 2 步、第 2 步基于错的继续……终点全错,像"传话游戏",一开始一点偏差、传到最后面目全非;而 Agent 全程"自信"、不会自己喊停,错误一路狂奔到终点所以 Agent 必须有"自我怀疑"机制:校验(verify)——每步工具返回后检查"成功了吗?结果合理吗?";反思(reflect)——阶段性停下来想"目前进展对吗?要不要调整/重试?";防御(defend)——把工具当"可能失败的",失败要重试/换路/明确报错。由此,我刻下一个关键认知:可靠的 Agent = 会行动 + 会怀疑自己的行动结果;"盲目自信、一往无前"的 Agent,在第一个失败点就开始"带病狂奔"。归根结底:Agent 自主多步、对中间结果敏感,而工具调用不可靠、错误会累积放大;必须每步校验工具返回 + 阶段反思 + 失败防御,让 Agent 学会"自我怀疑"。

第二件事:正解——每步校验工具返回 + 反思纠偏

搞懂了原理,正解就清晰了:每次工具调用后,先校验返回是否成功/合理,失败就重试或明确报错;并在关键节点加入反思,让 Agent 能纠偏

# ✓ 正解: 工具调用包一层校验 + 失败处理; 关键步骤加反思
def call_tool_checked(name, *args, retries=2):
    for i in range(retries + 1):
        result = call_tool(name, *args)
        # ✓ 1. 校验"是否成功"
        if result.get("error"):
            if i < retries:
                continue                          # 失败 → 重试
            raise ToolError(f"{name} 调用失败: {result['error']}")  # ✓ 明确报错, 别装没事
        # ✓ 2. 校验"结果是否合理"(按业务规则)
        if not is_reasonable(name, result):
            raise ToolError(f"{name} 返回结果不合理: {result}")
        return result["data"]
    # 多次失败 → 不要"假装查到了空", 而要把失败如实暴露!

def agent_run(task):
    # ✓ 工具返回先校验, 失败会抛错而不是默默用空值
    orders = call_tool_checked("query_orders", user_id)

    # ✓ 业务级合理性校验: 拿到结果后, 质疑它合不合理
    if orders == [] :
        # 区分"真的没订单" vs "查询失败返回空" —— 必要时二次确认
        if not confirm_user_really_has_no_orders(user_id):
            raise AgentError("订单查询可能异常, 拒绝基于空结果继续")

    total = sum(o["amount"] for o in orders)

    # ✓ 反思(reflection): 让 LLM 回头审视中间结果是否合理
    reflection = llm.chat(f"任务是查订单汇总。我查到 {len(orders)} 笔、共 {total} 元。"
                          f"这个结果合理吗? 有没有可能是查询出错了? 只回 OK 或 RETRY+原因")
    if reflection.startswith("RETRY"):
        return agent_run(task)                    # ✓ 觉得不对 → 重来/换路径

    return generate_report(orders, total)

# 三层防御:
#   1. 校验: 工具返回检查 成功? 合理? → 失败重试或明确报错(绝不"假装成功")。
#   2. 反思: 关键节点让 Agent 回头审视 "这结果可信吗?" → 不对就纠偏。
#   3. 兜底: 拿不准的结果, 二次确认 / 标注"低置信" / 交人工, 别硬着头皮往下走。

# 核心: 工具调用包校验(成功+合理), 失败重试或明确报错不装没事;
#   关键节点加反思让 Agent 审视中间结果, 错了就纠偏, 别让错误一路狂奔。

修复的方向,是给 Agent 装上"刹车"和"后视镜"正解的核心,是把每次工具调用,都包一层"校验 + 失败处理":第一,校验"是否成功"(检查返回有没有 error,失败就重试,多次失败就明确抛错——绝不"假装查到了空");第二,校验"结果是否合理"(按业务规则判断,比如"查到空"时,要区分"真的没订单"和"查询失败返回空",必要时二次确认)。更进一步,是反思(reflection):关键节点,让 LLM 回头审视中间结果——"我查到 N 笔、共 M 元,这合理吗?会不会是查询出错了?",如果它觉得不对(RETRY),就重来或换路径归纳起来是三层防御:校验(工具返回检查成功+合理,失败重试或明确报错、绝不装成功)、反思(关键节点让 Agent 审视"这结果可信吗",不对就纠偏)、兜底(拿不准的结果二次确认/标注"低置信"/交人工,别硬着头皮往下走)。归根结底:工具调用包校验(成功+合理),失败重试或明确报错、不装没事;关键节点加反思让 Agent 审视中间结果,错了就纠偏,别让错误一路狂奔。

第三件事:Agent 可靠性设计的几个关键模式

这次踩坑,让我系统梳理了一套提升 Agent 可靠性的设计模式,校验和反思只是其中的一部分:

提升 Agent 可靠性的关键模式

# 1. 工具调用要"防御性" (本文核心)
#   - 校验返回: 成功了吗? 结果合理吗? 失败重试/明确报错。
#   - 区分"空结果"和"调用失败" —— 这俩天差地别, 别混为一谈。

# 2. 反思 / 自我批判 (Reflection)
#   - 关键步骤后, 让 Agent 回头审视: "这步对吗? 离目标更近了吗?"
#   - 可用"另一个 LLM 当评审员"打分, 不合格就重做。

# 3. 显式的"我不知道/我失败了"路径
#   - 别逼 Agent "必须给个答案" → 它会编(幻觉)。
#   - 给它"承认失败/求助"的选项: 拿不到可靠结果时, 如实说"无法完成"。

# 4. 护栏 (Guardrails)
#   - 步数上限、成本上限(防死循环/烧钱, 见护栏篇)。
#   - 危险操作(删数据/发钱)需二次确认或人工审批。

# 5. 可观测 (Observability)
#   - 记录每步: 调了什么工具、传了什么参、返回了什么、做了什么决策。
#   - 出问题能回放整条推理链, 快速定位是哪一步、哪个工具坏的。

# 6. 关键决策"人在环路"(Human-in-the-loop)
#   - 高风险/低置信的结论, 交给人确认, 别全自动。

# 关键认知: Agent 的可靠性, 不靠"模型更聪明", 靠"工程上的层层防护"。
#   - 假设每一步都可能失败, 并为失败设计好应对。

# 核心: Agent 可靠性靠防御性工具调用+反思+认错路径+护栏+可观测+人在环路;
#   核心心法是"假设每步都可能失败, 并为失败设计应对"。

这套设计模式,让我对"怎么做一个可靠的 Agent"有了体系化的认识。第一,工具调用要"防御性"(本文核心):校验返回、区分"空结果"和"调用失败"(这俩天差地别,别混为一谈)。第二,反思/自我批判:关键步骤后让 Agent 回头审视,甚至用"另一个 LLM 当评审员"打分、不合格就重做。第三,显式的"我不知道/我失败了"路径:别逼 Agent 必须给答案(那会逼它编/幻觉),给它"承认失败/求助"的选项第四,护栏(步数/成本上限、危险操作需审批);第五,可观测(记录每步调了什么工具、传了什么参、返回什么、做了什么决策,出问题能回放整条推理链);第六,关键决策"人在环路"(高风险/低置信的结论交人确认)。由此,我刻下一个关键认知:Agent 的可靠性,不靠"模型更聪明",靠"工程上的层层防护";核心是"假设每一步都可能失败,并为失败设计好应对"。归根结底:Agent 可靠性靠防御性工具调用 + 反思 + 认错路径 + 护栏 + 可观测 + 人在环路;核心心法是"假设每步都可能失败,并为失败设计应对"。

下面这张图,是这次"盲信导致全错"的成因与解法:

第四件事:"空结果"与"调用失败",必须分清

这次事故最核心的教训之一,是 Agent 把"调用失败返回的空"和"真的没有数据"混为一谈。我把这类"易混淆的返回状态"整理成一张表。

工具返回 真实含义 Agent 该怎么做
正常数据 成功, 有结果 校验合理性后使用
空数组/空对象 可能"真没有", 也可能"失败返回空" 区分! 必要时二次确认, 别直接当"没有"
error 字段/异常 调用失败 重试 / 换路径 / 明确报错, 绝不当成功
超时无返回 不确定成功还是失败 重试要幂等; 拿不准就报"不确定"
格式不符预期 工具/上游出问题 校验 schema, 不符就拒绝使用
部分成功 一部分对一部分失败 识别出失败部分, 别当全成功

这张表,把"返回了东西"≠"成功了"这件事讲透了。最致命的混淆,是"空结果":它可能是"真的没有数据",也可能是"调用失败、降级返回了个空"——这两者天差地别,但长得一模一样!本文的悲剧,正是 Agent 把"失败返回的空"当成了"真的没订单"。所以,拿到空结果时,绝不能想当然地当"没有",而要去区分(比如看有没有伴随错误、或二次确认)。其余状态也各有应对:error/异常(绝不当成功,要重试/报错)、超时(不确定成败,重试要幂等、拿不准就报"不确定")、格式不符(校验 schema、不符就拒用)、部分成功(识别出失败部分、别当全成功)。它给我的最大启发是:Agent(乃至任何调用外部依赖的代码)在处理返回值时,不能只问"有没有返回",更要问"这个返回,到底意味着什么状态";尤其要警惕那些"形式相同、含义迥异"的返回(如空结果),把它们精确地区分对待——因为很多灾难,就源于把"失败"误读成了"一种正常的成功"

第五件事:reflection(反思)模式的几种实现

反思是提升 Agent 可靠性的利器,我把它的几种实现方式也梳理了一下。

反思方式 做法 适用
自我反思 Agent 自己回头审视上一步结果对不对 轻量, 通用
评审员(Critic) 另一个 LLM 专门给结果打分/挑错 质量要求高, 用"生成+评审"分离
规则校验 用确定性代码检查结果(格式/范围/约束) 有明确规则的, 最可靠
多次采样投票 同一步跑多次, 取多数一致的结果 关键决策, 降低偶然错误
工具交叉验证 用另一个工具核对第一个的结果 事实/数据类, 互相印证
计划-执行-复盘 先规划, 执行后对照计划检查完成度 复杂多步任务

这张表,把"反思"从一个抽象概念,落成了具体的工程手段最轻量的是"自我反思"(Agent 自己回头审视);质量要求高时,用"评审员(Critic)"——让另一个 LLM 专门挑错打分,把"生成"和"评审"分离(自己评自己往往不够客观);有明确规则的,优先用"规则校验"(用确定性代码检查格式/范围/约束,这是最可靠的,因为代码不会幻觉);关键决策用"多次采样投票"(同一步跑多次取多数,降低偶然错误);事实/数据类用"工具交叉验证"(用另一个工具核对);复杂任务用"计划-执行-复盘"(先规划、执行后对照计划检查)。它给我的最大启发是:"让 Agent 检查自己",有从轻到重、从模糊到精确的一整套手段;关键是按"错误的代价"去匹配"反思的力度"——低风险步骤,自我反思一下即可;高风险决策,就要上规则校验、交叉验证、甚至多重评审而其中,"用确定性代码做规则校验",往往是性价比最高、也最可靠的一种"反思"——因为它把对 LLM 输出的检查,交给了不会犯错的代码

第六件事:设计 Agent 的一个工具步骤时,我现在会怎么决策

现在,每当我给 Agent 设计一个"调工具"的步骤,脑子里都会过一遍这张决策图——核心就一问:这一步失败了,会怎样?我怎么发现并应对?

这张图的灵魂,是那个必问的问题:这一步失败了会怎样?我怎么发现并应对?第一关,校验成功与否:失败就重试,多次失败明确报错、绝不当成功第二关,校验结果是否合理:不合理或"空但可疑",就区分空结果 vs 失败、二次确认或拒绝第三关,按风险匹配反思力度:关键/高风险步骤,上 Critic/规则/投票再校验一遍;普通步骤,轻量自我反思即可校验通过才进入下一步;不通过就纠偏/换路径/认错求助,别硬推而贯穿始终的,是全程记录日志,出问题能回放定位这套判断,让我设计的每一个 Agent 工具步骤,都不再是"调完就信"的脆弱单点,而是"调用-校验-反思-应对"的健壮闭环

我立下的几条规矩

这场"盲信导致全错"的事故,换来了我做 AI Agent 时,刻进骨子里的几条铁律:

  1. 工具调用必校验,绝不盲信。每次调完先查"成功了吗、结果合理吗",失败重试或明确报错,绝不"假装成功"。
  2. 分清"空结果"和"调用失败"。这俩长得一样、含义天差地别;拿到空别想当然当"没有",要去区分。
  3. 关键步骤加反思。让 Agent(或另一个 Critic/规则/投票)回头审视中间结果,不对就纠偏,别让错误累积狂奔。
  4. 给 Agent "认错"的路径。别逼它必须给答案(会编);拿不到可靠结果就如实说"无法完成"。
  5. 按风险匹配校验力度。低风险自我反思,高风险上规则校验/交叉验证/多重评审;规则校验最可靠。
  6. 全程可观测。记录每步调了什么、传了什么、返回什么、决策什么,出问题能回放整条推理链。
  7. 假设每步都会失败。Agent 的可靠性不靠模型聪明,靠工程上为每个失败点都设计好应对。

附:一个带校验+反思+重试的 Agent 步骤封装

把前面讲的校验、反思、重试、认错揉到一起,这是我现在封装 Agent "一个步骤"的骨架,可以直接参照:

# ✓ 一个健壮的 Agent 步骤: 调用 → 校验 → 反思 → 重试/纠偏/认错
class ToolError(Exception): ...

def robust_step(tool_name, args, *, validate, reflect=None, max_retry=2, on_fail="raise"):
    """
    validate(result) -> bool : 规则校验, 判断结果是否成功且合理(确定性代码, 最可靠)
    reflect(result) -> bool  : 可选的 LLM 反思, 判断结果是否可信
    on_fail: 'raise'(报错) / 'admit'(认错返回None) / 'fallback'(走兜底)
    """
    last_err = None
    for attempt in range(max_retry + 1):
        result = call_tool(tool_name, args)
        log_step(tool_name, args, result, attempt)     # ✓ 可观测: 每步都记录

        # 1. 失败检测(error/异常/超时)
        if isinstance(result, dict) and result.get("error"):
            last_err = result["error"]
            continue                                    # ✓ 重试

        # 2. 规则校验(成功? 合理? 区分空结果vs失败)
        if not validate(result):
            last_err = f"结果未通过校验: {result}"
            continue

        # 3. 反思(关键步骤才做, 让 Critic/LLM 再审一遍)
        if reflect and not reflect(result):
            last_err = "反思判定结果不可信"
            continue

        return result                                   # ✓ 校验+反思都过, 才采信

    # 多次都失败 → 按策略处理, 绝不"假装成功"
    if on_fail == "admit":
        log_step(tool_name, args, "ADMIT_FAIL", -1)
        return None                                     # ✓ 如实认错(上层据此处理)
    if on_fail == "fallback":
        return fallback(tool_name, args)                # ✓ 走兜底路径
    raise ToolError(f"{tool_name} 多次失败: {last_err}")  # ✓ 明确报错

# 用法: 查订单这种关键步骤, 上规则校验 + 反思 + 失败明确报错
orders = robust_step(
    "query_orders", {"user_id": uid},
    validate=lambda r: "error" not in r and isinstance(r.get("data"), list),
    reflect=None,                  # 数据类用规则校验足矣, 不必 LLM 反思
    on_fail="raise",              # 查不到就报错, 绝不当"0笔订单"继续
)

# 核心: 把 Agent 的每个工具步骤封装成"调用+校验+反思+重试+认错"的健壮单元;
#   规则校验优先(确定性最可靠), 失败按策略报错/认错/兜底, 全程记录可回放。

这个封装,把前面所有的原则,固化成了一个可复用的"健壮步骤"它把 Agent 的每一个工具调用,都从"调完就信"的脆弱单点,升级成了"调用 → 校验 → 反思 → 重试/纠偏/认错"的完整闭环。它的几个设计要点很值得品味:第一,validate 用确定性代码做规则校验(检查有没有 error、数据结构对不对——这是最可靠的一层,因为代码不会幻觉);第二,reflect 是可选的 LLM 反思(只在关键、且规则难以判断的步骤才用,数据类用规则校验就够);第三,on_fail 策略化失败处理——报错(raise)、认错返回 None(admit)、或走兜底(fallback),但无论哪种,都绝不"假装成功";第四,log_step 全程记录,保证可观测、可回放。这,正是我想用这段代码,留给每一个 Agent 开发者的最后一课:把"可靠性",从一个飘忽的口号,变成一个个具体的、可复用的工程封装;让"校验、反思、重试、认错、可观测"这些好习惯,不再依赖你每次手写时的自觉,而是内建在你的 Agent 框架里、成为每个步骤的默认行为当"做对"成为了"最省事的默认选项",可靠,才会真正地、稳定地发生

写在最后

回头看,这场由"Agent 盲信工具返回"引发的事故,真正教给我的,是一个比"加校验和反思"本身更深的道理:构建一个由"会犯错的部件"组成的系统时,系统的可靠性,不来自于"假设每个部件都不出错",而来自于"承认每个部件都会出错,并为每一种错误,都设计好检测和应对"我之前的错误,是用一种"理想化、乐观主义"的心态去构建 Agent:我默认每一步工具调用都会成功、每一个中间结果都正确,于是把它们像多米诺骨牌一样,一环扣一环地连了起来——可一旦第一张牌倒错了方向,整条链就无可挽回地、全盘崩塌。这让我深刻地领悟到:健壮的系统,骨子里都是"悲观"的:预设了失败的存在,并在每一个可能失败的环节,都埋好了"检查点"和"安全网";它不指望"不出错",而追求"出错了也能及时发现、优雅应对、不至于全盘皆输"这在 AI Agent 时代,显得尤为重要——因为 Agent 的核心部件(LLM、工具),恰恰都是"高度不确定、会犯错"的;把一堆"会犯错"的部件,组装成一个"可靠"的整体,靠的不是祈祷它们都别犯错,而是那一层层精心设计的校验、反思与防御预设失败,为每一种错误设计好检测与应对——这,是我用一次"Agent 全错"的事故,换来的、关于 AI Agent、也关于一切健壮系统的、最朴素也最深刻的领悟。如果这篇复盘,能让你在下一次给 Agent 写一个工具调用时,顺手为它的"失败"也设计好一条路,那我对着那份"完美却全错"的报告熬的这大半天,就值了。

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

我以为 TypeScript 会帮我挡住所有 undefined,结果一个标注成 string 的值运行时是 undefined、访问属性直接崩,编译器却一声不吭,我排查了大半天的复盘

2026-6-2 3:24:11

技术教程

我在 Python 里用 is 判断两个数字相不相等,小数字时一直好好的,换成大数字后判断突然全错了,我对着这个时对时错的比较排查了大半天的复盘

2026-6-2 3:37:06

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