Harness 的失败重试与降级:原理、实现与 Benchmark
title: “Harness 的失败重试与降级:原理、实现与 Benchmark”
authors: “[DeepThink.ai]”
affiliations: “[AI Genius Institute]”
keywords: “Agent Harness;失败重试;降级;幂等;熔断;可靠性 Benchmark”
摘要
大语言模型智能体正走向长程、工具密集、带副作用的真实任务,系统可靠性越来越取决于模型之外的运行时(Harness)。现有实践常把重试与降级当成独立开关:盲目重试放大成本与重复副作用,过早降级造成静默质量下降,二者都缺少统一的故障分类、预算、幂等与验收口径。本文提出 HFR(Harness Failure Recovery):先按可观测信号把故障映射到九类故障与九种动作,再在预算、截止时间和副作用风险约束下选择重试、对账、压缩、降级或升级,并以 full-jitter 退避、分层预算、幂等账本、分级降级阶梯、分级验收器与熔断舱壁作为支撑。在明确标注为合成故障注入的模拟中(10 个种子 × 每个种子 20,000 个任务),HFR 的任务成功率为 86.25%,与无幂等盲目重试(86.17%)接近;但干净成功率为 86.25% 对 84.57%,安全完成率为 92.07% 对 84.57%,重复副作用从每千任务 17.47 次降为 0,非升级任务的 95 分位时延从 7.92 秒降为 6.85 秒。上述数字只反映模拟器中的相对趋势,不构成对真实系统的测量;本文同时给出 HFR-Bench 评测协议与待执行的真实实验计划。
你离拥有一支永不停歇、持续进化的 AI 超级研发团队,只差一次
git clone——DeepThink 是 AI Genius Institute & 光剑AI 打造的开源、免费、可自由使用的私有 AI 操作系统(AI OS):在安全隔离的沙箱中自主执行代码、管理文件、完成超复杂长程任务,作为自托管、多用户、本地优先的 AI Agent Loop Engineering 系统,支持桌面端+浏览器+移动端,让 DeepThink 成为你的全能数字助手;它不止让你使用 AI,更要让你从工具使用者进化为代码创造者,最终成长为可自我繁衍的超级智能体,让每家企业都拥有自己的 AI 超级研发团队,一起走向 AGI——现在就去git clone,顺手点亮 Star:你收藏的不是一个仓库,而是通往 AGI 的入场券。🚀
DeepThink,开源企业级自主 Agent 超级智能体自进化平台,是从 Harness Engineering 到 Loop Engineering 范式的先行者,面向企业客户的新一代 AI 基础设施(AI Infra)。DeepThink 平台以多 Agent 协作框架为核心,融合 AI 自主编程(AI Coding)、自主进化(Self-Evolving)、全栈可观测性(Full-Stack Observability)、Bug 自修复闭环(Bug Auto-Fix Loop) 与 程序员-Agent 共生协作(Human-Agent Symbiosis),构建一个能持续学习、自我改进、最终成长为超级智能体的企业级 AI 系统。
DeepThink 项目开源代码(如果你觉得好玩,就一起来玩, Star 一下):
Gitcode: https://gitcode.com/AIGeniusInstitute/deepthink
Github: https://github.com/AIGeniusInstitute/deepthink
0. 标题解释、范围与写作假设
0.1 本文所说的 Harness 是什么
本文将 Harness 定义为“把模型变成可执行智能体的运行时层”。它至少包含六个部分:任务循环(Think-Act-Observe 或等价的控制流)、工具注册与调用、上下文组装与压缩、沙箱与权限、任务状态与检查点、日志与可观测性。Harness 不负责训练模型,也不等价于某个具体框架;它是一组把模型输出转化为外部动作、再把外部结果转化回模型输入的工程机制。ReAct 等工作展示了“推理—行动”交错的基本形态[1],SWE-agent 等工作则说明,同样的模型在不同工具接口和运行时下会表现出显著不同的任务完成能力[3]。本文关心的不是如何让模型更聪明,而是当模型、工具或环境失败时,Harness 如何做出可解释、可预算、可验证的恢复决策。
0.2 “失败重试”与“降级”的边界
本文把恢复动作分成两类。重试(retry)是在不改变逻辑动作的前提下再次执行同一次模型调用或工具调用;它适合瞬时故障,但只有在动作可重复执行或具备幂等保护时才是安全的。降级(degradation)是改变执行路径:换一个模型、换一个工具、压缩上下文、缩小任务范围、返回确定性兜底结果,或把任务交给人工。降级不是“失败”的同义词,它是在能力、成本、时延和风险之间做显式交换;但如果没有验收门槛,降级就会变成静默失败。
重试与降级不应被实现为两个互不相关的开关。它们共享同一套故障分类、预算、截止时间、幂等账本和验收器。本文的核心主张是:先判错,再决策;重试有预算,降级有阶梯,副作用有幂等,结果有验收,失败有升级。 这五句话对应 HFR 的五个控制点。
0.3 本文主张什么
本文主张以下四点,并为每一点给出可实现的机制或可检验的评测口径:
- 错误分类是恢复的前提。 把“所有异常”统一重试,会把确定性错误、权限错误和安全拒绝也变成重试对象,既浪费预算,也可能扩大副作用。Harness 需要把可观测信号映射到故障类别,再映射到动作。
- 重试必须与幂等/对账绑定。 对带副作用的写操作,超时后的“结果未知”不能靠再调用一次来解决;必须先查询副作用账本,或在工具支持幂等键时复用同一个键。
- 降级必须有验收与质量下限。 降级后的输出不能因为“便宜”或“快”就被默认接受;验收器要根据任务关键度选择确定性检查、语义检查或人工复核。
- 评测必须同时报告成功率与安全性。 只报告“任务是否完成”会掩盖重复副作用、静默降级和人工接管;一个可靠的 Harness 基准至少应报告任务成功率、干净成功率、安全完成率、成本、尾时延、重复副作用和升级率。
0.4 本文不主张什么
本文不主张 HFR 在所有任务、所有模型和所有故障分布上都优于其他策略。本文的合成模拟使用显式假设的参数,目的是比较策略在相同故障注入下的相对行为,而不是估计某个真实系统的绝对成功率。本文不主张“自动修复所有失败”;对于不可逆的副作用、不可观测的语义错误、安全策略拒绝和权限缺失,最安全的动作往往是停止或升级,而不是继续重试。本文也不主张本文提出的基准已经取代现有能力基准;它是对能力基准的补充,关注的是“在故障下能否安全恢复”。
0.5 写作假设与可核实性
本文写作时遵循以下假设:
- 系统范围:以单 Agent、API 模型、工具调用和沙箱执行为主;多 Agent 场景可以把 HFR 放在每个 Agent 内部,也可以在编排层再加一层预算与熔断,但本文不展开多 Agent 的协同恢复协议。
- 故障来源:模型 API、工具服务、沙箱/环境、任务输入和验收环节;不讨论模型训练阶段的故障。
- 数据来源:本文没有生产 trace 或真实 LLM 实验数据。第 6 章的模拟结果由随文脚本生成,参数是建模假设;真实基准的执行结果统一标注为 ,不以估计值代替。
- 引用:参考文献只列可公开核实的论文、书籍、标准或官方文档;无法核实的数字、页面和结论不写入正文。涉及本文自己的判断时,使用“本文认为”“在本文的模拟中”等限定语。
- 术语:首次出现的缩写给出中英文全称;公式中的符号在首次出现处定义,附录 A 汇总。
1. 引言
1.1 从“模型能力”到“运行时可靠性”
过去两年,智能体评测的主线是能力:模型能否调用工具、能否浏览网页、能否修改代码、能否在多轮对话中完成用户目标。AgentBench 把多种环境统一成可比较的任务集[8];WebArena 提供可复现的网站环境[5];OSWorld 把任务放到真实操作系统桌面中[6];τ-bench 强调工具、用户和策略之间的交互[7];SWE-bench 用真实代码仓库的 issue 检验修复能力[4]。这些基准推动了模型和脚手架的共同进步,但也暴露了一个事实:基准分数高,不等于生产系统可靠。 同一个模型在不同 Harness 下的成功率可能相差很大;同一个 Harness 在不同故障率、不同工具质量、不同上下文压力下也会表现出完全不同的稳定性。
HAL 的规模化评测进一步说明,智能体评测需要统一编排、日志和成本核算,否则不同实现之间的比较会被工程差异污染[13]。MAST 对多 Agent 系统失败模式的分析则表明,失败往往不是“模型不会”,而是系统设计、Agent 间对齐和任务验证出了问题[12]。AgentOps 综述把智能体运维中的异常分为 Agent 内和 Agent 间两类,并强调监控、异常检测、根因分析和处置的闭环[14]。这些工作共同指向一个结论:可靠性不是模型单独的属性,而是模型、Harness 和环境共同作用的结果。
1.2 两种常见但不够好的做法
第一种做法是“全量重试”。只要调用失败,就再试几次;如果还失败,就继续加次数。它在瞬时网络抖动上有效,但在智能体场景中会带来三个问题。其一,成本与尾时延放大:每次重试都可能重新发送长上下文、重新执行工具,成本和延迟随尝试次数线性增长;Dean 和 Barroso 早就指出,尾延迟会被少量慢请求显著拉高[20]。其二,重试风暴与亚稳态故障:当某个提供商或工具已经过载时,大量客户端同时重试会把系统推入更难恢复的状态;Bronson 等人把这类现象称为亚稳态故障[21]。其三,重复副作用:对一个已经成功但响应丢失的写操作再次调用,可能重复下单、重复扣款、重复发消息;Helland 强调,幂等不是“锦上添花”,而是分布式副作用的正确性边界[23]。
第二种做法是“立即降级”。一旦主模型或主工具失败,就切换到更便宜的模型、更简单的工具或模板答案。它在可用性上有价值,但如果没有验收,就会产生静默失败:用户看到的是一个格式完整、语气自信、但事实或操作错误的答案;系统日志里只有“已降级”,没有“质量是否达标”。FrugalGPT、AutoMix 和 RouteLLM 研究了如何在成本与质量之间路由模型[15][16][17],但这些工作主要解决“第一次调用应该选哪个模型”,而不是“调用失败后如何安全地恢复”。路由策略不能替代恢复策略;降级后的输出仍然需要验收、审计和必要时的升级。
1.3 为什么智能体的失败不能照搬分布式系统经验
分布式系统已经积累了成熟的可靠性模式:超时、重试、指数退避、抖动、熔断、舱壁、幂等键、Saga、租约和端到端校验[22][24][25][26][27][28]。这些模式是本文的重要基础,但智能体场景有三个额外难点。
第一,错误信号弱且语义化。传统服务通常有明确的错误码;模型调用可能返回 200 状态码和一段看似合理但错误的内容,工具调用可能返回成功的 JSON 但字段语义不对。Harness 不能只依赖 HTTP 状态码,还需要 schema 校验、退出码、测试结果、环境状态核对和语义验收。
第二,同一动作的重复执行不一定是“同一结果”。模型调用具有采样随机性;重试可能得到不同答案,甚至在不同上下文中改变后续计划。工具调用则可能带副作用,重复执行的成本和风险远高于读操作。重试策略必须同时考虑“结果是否可能不同”和“副作用是否可重复”。
第三,能力是分层的,降级不是免费的。不同模型、不同工具、不同上下文长度对应不同的能力边界。把任务降级到更小的模型,可能只是变快变便宜,也可能直接越过任务所需的能力门槛。降级策略必须知道任务的关键度、质量下限和可接受的替代路径。
1.4 本文思路
本文把 Harness 的失败恢复建模为一个带约束的序贯决策问题:在每个失败点,控制器观察信号,判断故障类别,估计继续重试的收益与风险,在预算、截止时间和质量下限约束下选择重试、对账、压缩、降级、升级或停止。为了让这个决策可实现、可审计,本文提出 HFR,包含七个部件:
- 故障分类器:把可观测信号映射到九类故障;
- 重试控制器:执行 full-jitter 指数退避,并受步/任务/租户三级预算约束;
- 幂等与副作用账本:为写操作生成稳定幂等键,处理“结果未知”的对账;
- 降级阶梯:从上下文压缩、同层替代、能力降档、确定性兜底到人工接管;
- 验收器:用确定性检查、语义检查和人工复核构成分级验收;
- 熔断与舱壁:按提供商、模型、工具和租户隔离故障与并发;
- 可观测性:记录每次决策的证据、预算消耗、降级级别和验收结果。
图 1 给出总体控制回路。关键点不是某个单点算法,而是把恢复动作放进同一个闭环:分类决定动作,预算约束动作,幂等保护副作用,验收决定是否接受,日志让下一次决策可学习、可审计。
┌──────────────────────────────────────────────┐
│ Harness 主循环 │
│ plan → act → observe → update state │
└──────────────────────┬───────────────────────┘
│
┌─────────────────────────────▼─────────────────────────────┐
│ HFR 可靠性控制面 │
│ │
observation ──▶│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ 故障分类器 │──▶│ 预算/截止时间 │──▶│ 动作选择器 │ │
│ │ F2D-9 │ │ 检查 │ │ retry/… │ │
│ └──────┬───────┘ └──────────────┘ └──────┬───────┘ │
│ │ │ │
│ ▼ ▼ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ 幂等账本 │ │ 降级阶梯 │ │ 熔断/舱壁 │ │
│ │ key/ledger │ │ L0…L4 │ │ provider/tool│ │
│ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ │
│ └──────────────────┼──────────────────┘ │
│ ▼ │
│ ┌──────────────────┐ │
│ │ 验收器 V0…V3 │ │
│ └────────┬─────────┘ │
│ │ │
│ accept / retry / degrade / escalate │
└────────────────────────────┬─────────────────────────────┘
│
┌─────────▼─────────┐
│ 事件日志 / 指标 / 审计 │
└───────────────────┘
图 1 HFR 在 Harness 主循环中的位置。分类器把观测转成故障类别,预算与截止时间检查约束动作,幂等账本保护副作用,降级阶梯提供替代路径,验收器决定是否接受,熔断与舱壁限制故障传播,事件日志记录证据。
1.5 贡献
本文的贡献可以概括为四点:
- 故障分类与动作映射。 本文提出 F2D-9 分类:把智能体 Harness 中常见的瞬时传输、限流、超时/结果未知、模型过载、工具不可用、上下文溢出、永久输入/权限、安全拒绝和语义验收失败映射到重试、对账、压缩、降级、升级或停止等动作,并给出可观测信号、默认动作和副作用风险。该分类不是对故障本体论的声称,而是一个工程上可执行、可扩展的决策表。
- HFR 控制器。 本文把重试预算、full-jitter 退避、幂等账本、降级阶梯、分级验收、熔断和舱壁组合成一个闭环控制器,给出状态机、配置模型、错误映射和复杂度分析。与把重试和降级分开实现的做法相比,HFR 的关键是让它们共享同一套故障语义、预算和验收。
- HFR-Bench 设计。 本文提出一个在现有智能体任务上注入可复现故障、同时测量任务成功率、干净成功率、安全完成率、成本、尾时延、重复副作用和升级率的基准协议。该协议把“能力”和“恢复”分开测量,并给出配对比较、置信区间和人工抽检的统计流程。
- 合成故障注入的初步证据。 本文用随文脚本执行了一组合成故障注入实验,报告 HFR 与不重试、盲目重试、仅指数重试、仅降级以及三个消融版本的对比。结果只用于说明相对趋势和暴露设计权衡;真实 LLM 与真实工具上的结果尚未执行,统一标注为待补。
1.6 结构
第 2 章按技术流派回顾相关工作,并说明本文与它们的差异。第 3 章形式化执行模型、故障模型、动作空间和优化目标。第 4 章介绍 HFR 的各个模块、状态机、复杂度和条件性安全性质。第 5 章给出参考实现、配置、错误映射、可观测性和部署治理。第 6 章给出合成故障注入结果、HFR-Bench 设计和真实基准执行协议。第 7 章讨论适用边界、伦理与工程清单。第 8 章总结。附录给出符号表、模拟器参数、补充结果和证明草图。
2. 相关工作
2.1 分布式系统与云服务可靠性
重试、超时、退避和熔断是分布式系统的经典主题。AWS 的构建者文库建议为超时和重试设置上限,并使用带抖动的指数退避来避免同步重试[28];Google 的 SRE 实践把错误预算、服务等级目标和容量规划结合起来[26];Nygard 的《Release It!》系统总结了熔断器、舱壁、超时和稳态模式[27];Dean 和 Barroso 的“The Tail at Scale”说明尾延迟如何被少量慢请求放大,以及如何用对冲请求和延迟感知调度缓解[20]。在正确性一侧,Saga 用补偿事务处理长事务的部分失败[22],幂等键和去重表用于避免重复副作用[23],租约用于在故障后安全地重新分配所有权[24],端到端论证提醒我们不要把可靠性完全寄托在中间层[25]。Bronson 等人则指出,重试和负载控制在过载时会形成亚稳态故障,系统可能在一个看似稳定的坏状态中停留很久[21]。
这些工作为 HFR 提供了直接的模式库,但它们的默认假设与智能体 Harness 不完全相同:错误通常是可观测的、动作通常是可定义幂等的、质量通常是二值的。智能体的模型调用具有采样随机性,工具调用可能带外部副作用,语义正确性往往需要额外验证。本文保留经典模式,但把它们放进“故障分类—预算—幂等—验收”的智能体语义中。
2.2 LLM 路由、级联与降级
FrugalGPT 提出用 LLM 级联在成本与质量之间取舍:先调用便宜模型,置信度不足时再调用更强模型[15]。AutoMix 用少样本自验证和 POMDP 路由器决定何时把查询交给更大的模型[16]。RouteLLM 用偏好数据训练路由器,在强模型和弱模型之间动态选择[17]。这些工作说明,模型能力分层可以被工程化地利用,降级/升级可以显著改变成本结构。
本文与它们的差异在于决策时点与约束。路由工作主要回答“第一次调用选哪个模型”,其目标是最小化期望成本并满足质量约束;本文回答“调用已经失败或结果不可信时,下一步做什么”。降级在本文中不是一次静态选择,而是带预算、截止时间、幂等和验收的恢复动作。路由策略可以作为 HFR 的 L2/L3 降级组件,但不能替代 HFR 的故障分类和验收。
2.3 自我修正、反思与验证
Self-Refine 让同一个模型生成初稿、给出反馈并迭代改进[18];Reflexion 用语言化的反思和记忆改进行为[2]。这些方法在部分任务上有效,但 Huang 等人的系统实验提醒:没有外部反馈时,LLM 的内在自我纠正并不稳定,推理任务上甚至可能越改越差[19]。因此,本文不把“让模型再想一遍”当作可靠的重试策略。HFR 只在两种情况下重试语义失败:有新的外部证据(工具结果、测试失败、环境状态变化),或者验收器给出了可操作的失败原因。没有新信息的“再试一次”被归为低价值重试,应受预算限制。
2.4 智能体评测与失败分类
AgentBench 覆盖操作系统、数据库、知识图谱、网页购物等多个环境[8];WebArena 提供可复现的网站任务[5];OSWorld 把任务放到真实桌面应用和文件系统中[6];τ-bench 强调工具—用户—策略的交互[7];SWE-bench 用真实 GitHub issue 检验代码修复[4]。这些基准主要测量“在正常条件下能否完成任务”,故障注入和恢复策略通常不是它们的核心变量。
在失败分类方面,MAST 通过 1600 多条多 Agent trace 归纳出 14 种失败模式,分为系统设计、Agent 间错位和任务验证三类[12];AgentOps 综述把智能体异常分为 Agent 内和 Agent 间,并给出监控、检测、根因分析和处置的框架[14];HAL 则指出,智能体评测需要标准化编排、日志和成本核算,否则不同实现的比较会失真[13]。在多 Agent 编排方面,AutoGen、MetaGPT 和 Magentic-One 展示了对话式、角色分工式和通用多 Agent 系统的不同形态[9][10][11];它们提供了任务分解和协作的机制,但故障恢复通常仍由各自的运行时处理。本文与它们互补:MAST 和 AgentOps 关注“失败长什么样、为什么失败”,本文关注“失败之后如何安全地重试或降级”,并给出可注入、可复现的恢复评测协议。
2.5 持久化执行、检查点与工作流
Temporal、AWS Step Functions 和 Azure Durable Functions 等系统把长流程的状态持久化,支持故障后恢复、重试和超时[30][31][32]。事件溯源和检查点机制可以把已提交的步骤与未提交的意图分开,避免恢复时重复执行[25]。这些能力与 HFR 是互补的:持久化执行解决“进程崩溃后如何恢复”,HFR 解决“模型或工具返回了不可信结果后如何决策”。在实现上,HFR 的幂等账本和状态机可以嵌入持久化工作流;在评测上,二者都应报告恢复后的重复副作用和恢复时间。工程实践指南也强调,智能体系统应把工具、记忆、规划和可观测性分开设计,并为失败路径保留显式的控制点[37][38];本文的 HFR 可以看作这些原则在“失败恢复”这一维度上的具体化。
2.6 与本文最接近的工作及差异
据本文作者的文献范围,现有公开工作较少同时处理以下四件事:面向智能体语义的故障分类、带预算的重试、带质量门槛的降级、以及同时测量副作用安全的基准。经典可靠性工作提供了模式但没有智能体语义;路由/级联工作提供了成本—质量权衡但没有故障后的恢复闭环;自我修正工作提供了迭代改进但没有外部验收;智能体基准提供了任务环境但没有系统性的故障注入。本文的差异是把这些线索组合成一个可实现的控制器和一个可复现的评测协议,并明确报告合成模拟与真实实验之间的边界。
3. 问题形式化
3.1 执行模型与符号
本文把一个智能体任务写成四元组
T = ( x , g , c , q min ) , T = (x, g, c, q_{\min}), T=(x,g,c,qmin),
其中 x x x 是任务输入(用户请求、代码仓库、网页状态等), g g g 是成功规范(测试、验收标准、目标状态), c ∈ { low , medium , high } c \in \{\text{low}, \text{medium}, \text{high}\} c∈{low,medium,high} 是任务关键度, q min ∈ [ 0 , 1 ] q_{\min} \in [0,1] qmin∈[0,1] 是任务所有者设定的质量下限。任务被分解为 n n n 个逻辑步骤,第 i i i 步的逻辑动作记为 a i a_i ai,它可能是一次模型调用、一次工具调用、一次文件写入或一次环境操作。Harness 在第 i i i 步观察到状态 s i s_i si,执行动作后得到观测 o i o_i oi,并更新状态:
s i + 1 = δ ( s i , a i , o i ) , s_{i+1} = \delta(s_i, a_i, o_i), si+1=δ(si,ai,oi),
其中 δ \delta δ 是 Harness 的状态转移函数。一个策略 π \pi π 在失败点根据 ( s i , o i , history ) (s_i, o_i, \text{history}) (si,oi,history) 选择恢复动作。为了区分“逻辑动作”和“物理尝试”,本文把对同一个 a i a_i ai 的第 k k k 次执行称为一次尝试(attempt),记为 a i ( k ) a_i^{(k)} ai(k)。重试不改变逻辑动作,只增加尝试次数;降级改变执行路径,但尽量保持任务语义。
表 1 汇总了本文使用的主要符号。
表 1 主要符号。
| 符号 | 含义 |
|---|---|
| T T T | 任务 |
| x , g x, g x,g | 任务输入、成功规范 |
| c c c | 任务关键度:low / medium / high |
| q min q_{\min} qmin | 质量下限 |
| n n n | 逻辑步骤数 |
| a i a_i ai | 第 i i i 步的逻辑动作 |
| a i ( k ) a_i^{(k)} ai(k) | 第 i i i 步的第 k k k 次尝试 |
| s i , o i s_i, o_i si,oi | 第 i i i 步的状态与观测 |
| f f f | 故障类别(F2D-9) |
| r ( f ) r(f) r(f) | 故障是否可重试 |
| h ( a i ) h(a_i) h(ai) | 动作的副作用风险等级 R0–R3 |
| B s , B t , B tenant B_s, B_t, B_{\text{tenant}} Bs,Bt,Btenant | 每步、每任务、每租户重试预算 |
| d k d_k dk | 第 k k k 次重试前的退避时延 |
| D D D | 任务截止时间 |
| C ( T ) C(T) C(T) | 任务总成本 |
| L ( T ) L(T) L(T) | 任务端到端时延 |
| Q ( T ) Q(T) Q(T) | 任务输出质量 |
| D U P ( T ) \mathrm{DUP}(T) DUP(T) | 重复副作用次数 |
| E S C ( T ) \mathrm{ESC}(T) ESC(T) | 是否升级到人工 |
本文把“任务成功”定义为满足 g g g 且通过验收;把“干净成功”定义为任务成功且 D U P ( T ) = 0 \mathrm{DUP}(T)=0 DUP(T)=0;把“安全完成”定义为(任务成功或显式升级)且 D U P ( T ) = 0 \mathrm{DUP}(T)=0 DUP(T)=0。这三个指标分别回答三个不同问题:任务是否完成、完成得是否干净、失败是否被安全地接住。
3.2 故障模型
本文不假设 Harness 能直接观察到“真实故障本体”,只假设它能观察到一组信号。一个故障事件可以写成
e i = ( f i , σ i , r i , h i , v i ) , e_i = (f_i, \sigma_i, r_i, h_i, v_i), ei=(fi,σi,ri,hi,vi),
其中 f i f_i fi 是故障类别, σ i \sigma_i σi 是可观测信号, r i ∈ { 0 , 1 } r_i \in \{0,1\} ri∈{0,1} 表示该故障是否可能通过重试恢复, h i ∈ { R 0 , R 1 , R 2 , R 3 } h_i \in \{R0,R1,R2,R3\} hi∈{R0,R1,R2,R3} 是副作用风险等级, v i ∈ { 0 , 1 } v_i \in \{0,1\} vi∈{0,1} 表示故障是否被显式观测到。 v i = 0 v_i=0 vi=0 的“静默失败”是智能体场景中最危险的一类:HTTP 状态码可能是 200,JSON schema 可能合法,但内容或副作用是错的。HFR 用验收器把一部分静默失败转化为可观测失败,但不能保证覆盖全部。
本文把故障分为九类,记为 F2D-9(Fault-to-Decision,九类)。表 2 给出每类的典型信号、可重试性、副作用风险、默认动作和备注。这个分类是工程决策表,不是对故障本体论的完备划分;实际系统可以增加子类,但应保持“信号—类别—动作”的映射可审计。
表 2 F2D-9 故障分类与默认动作。
| 编号 | 故障类别 | 典型信号 | 可重试性 | 副作用风险 | 默认动作 | 备注 |
|---|---|---|---|---|---|---|
| T1 | 瞬时传输/服务端错误 | HTTP 500/502/503/504、连接重置、临时 DNS 失败 | 是 | 低(读)/中(写) | RETRY | 用 full-jitter 退避;写操作需幂等或对账 |
| T2 | 限流/配额 | HTTP 429、Retry-After、quota exceeded | 是,但需延迟 | 低 | RETRY(遵守 Retry-After) | 不要把 429 当成瞬时 5xx 立即重试 |
| T3 | 超时/结果未知 | deadline exceeded、socket timeout、请求已发出但无响应 | 条件性 | 高(写) | RECONCILE → RETRY 或 ESCALATE | “结果未知”不能直接重试 |
| T4 | 模型过载/容量不足 | 529/overloaded、队列满、持续高延迟 | 否(同模型) | 低/中 | DEGRADE_MODEL 或等待 | 换同层或更低层模型,受质量下限约束 |
| T5 | 工具不可用/契约不匹配 | 工具 5xx、unknown tool、schema mismatch、缺字段 | 否(同工具) | 中 | DEGRADE_TOOL 或修复契约 | 换等价工具;无法等价时升级 |
| T6 | 上下文溢出 | context_length_exceeded、token 超限、检索结果过多 | 条件性 | 低 | COMPRESS → RETRY | 压缩/滚动摘要后重试;不要原样重发 |
| T7 | 永久输入/权限错误 | HTTP 400 invalid_request、401/403、参数缺失、权限不足 | 否 | 高(权限) | FAIL 或 ESCALATE | 重试不会修复确定性错误 |
| T8 | 安全/策略拒绝 | content policy、safety refusal、合规拦截 | 否 | 高 | ESCALATE | 不得通过降级绕过安全策略 |
| V1 | 语义验收失败 | schema 合法但测试失败、状态不一致、judge 拒绝 | 条件性 | 中 | RETRY(带新证据)→ REPLAN/DEGRADE | 没有新信息的“再想一遍”价值很低 |
表 2 中的“可重试性”是默认值,不是绝对规则。例如,T1 对读操作通常是安全重试,对不可逆写操作则必须先看幂等能力;T6 在压缩后可能恢复,但如果压缩丢失了完成任务所需的关键信息,重试只会重复失败。分类器的输出应包含类别和置信度;当置信度低时,按副作用风险选择保守动作:读操作可以探测一次,写操作先对账,高关键度任务直接升级。
3.3 动作空间
HFR 的动作空间包含九种动作,如表 3 所示。动作选择不是“故障类别到动作”的硬编码,而是在类别、预算、截止时间、副作用风险和关键度共同约束下的决策。
表 3 HFR 的动作空间。
| 动作 | 含义 | 适用场景 | 主要风险 |
|---|---|---|---|
RETRY | 用相同逻辑动作再执行一次 | 瞬时故障、限流、可恢复超时 | 成本、尾时延、重复副作用 |
RECONCILE | 查询副作用账本或外部状态,确认上次动作是否提交 | 超时/结果未知、写操作 | 查询本身可能失败或过期 |
COMPRESS | 压缩上下文、缩小检索范围、滚动摘要 | 上下文溢出 | 丢失关键信息 |
DEGRADE_MODEL | 切换到同层或更低层模型 | 模型过载、能力分层 | 质量下降 |
DEGRADE_TOOL | 切换到等价工具或简化契约 | 工具不可用、schema 不匹配 | 语义差异、字段缺失 |
DEGRADE_SCOPE | 缩小任务范围、返回部分结果、使用模板/缓存 | 无法完成完整任务 | 静默不完整 |
REPLAN | 保留已提交步骤,重新规划后续步骤 | 语义失败、计划失效、环境变化 | 计划抖动、成本增加 |
ESCALATE | 交给人工或上游系统,附带证据和建议 | 高关键度、不可逆、策略拒绝 | 人工成本、时延 |
FAIL | 停止并返回结构化失败 | 确定性错误、无安全替代 | 任务未完成 |
3.4 优化目标与约束
HFR 的目标不是单纯最大化成功率,而是在一组运行约束下最大化“安全完成”的效用。本文把策略选择写成约束优化:
max π E [ U ( T ) ] s.t. E [ C ( T ) ] ≤ B c , P ( L ( T ) ≤ D ) ≥ 1 − ϵ , E [ D U P ( T ) ] ≤ ϵ d , Q ( T ) ≥ q min . \max_{\pi}\; \mathbb{E}\left[ U(T) \right] \quad \text{s.t.} \quad \mathbb{E}[C(T)] \le B_c,\; P(L(T) \le D) \ge 1-\epsilon,\; \mathbb{E}[\mathrm{DUP}(T)] \le \epsilon_d,\; Q(T) \ge q_{\min}. πmaxE[U(T)]s.t.E[C(T)]≤Bc,P(L(T)≤D)≥1−ϵ,E[DUP(T)]≤ϵd,Q(T)≥qmin.
其中 U ( T ) U(T) U(T) 是任务效用,可以由“成功”“干净成功”“安全完成”或业务价值定义; B c B_c Bc 是成本预算; D D D 是截止时间; ϵ \epsilon ϵ 是尾时延违约容忍度; ϵ d \epsilon_d ϵd 是重复副作用容忍度。实际系统通常无法精确求解这个约束优化问题,而是用规则、预算和阈值近似。HFR 的设计目标不是给出最优解,而是给出可解释、可审计、可调参的可行解。
本文用以下指标比较策略:
- 任务成功率 S R \mathrm{SR} SR:成功任务数 / 总任务数;
- 干净成功率 C S R \mathrm{CSR} CSR:成功且无重复副作用的任务数 / 总任务数;
- 安全完成率 S C R \mathrm{SCR} SCR:(成功或升级)且无重复副作用的任务数 / 总任务数;
- 每成功任务成本 C P S \mathrm{CPS} CPS:总成本 / 成功任务数;
- 尾时延 p 95 p95 p95、 p 99 p99 p99:任务端到端时延的分位数,必要时区分“含升级”和“不含升级”;
- 重复副作用率 D U P 1000 \mathrm{DUP}_{1000} DUP1000:每千任务的重复副作用次数;
- 升级率 E S C \mathrm{ESC} ESC:升级任务数 / 总任务数;
- 降级率 D E G \mathrm{DEG} DEG:至少发生一次降级的任务数 / 总任务数;
- 重试放大率 R A \mathrm{RA} RA:总尝试次数 / 逻辑步骤数。
这些指标之间存在权衡。提高重试预算通常能提高成功率,但会增加成本和尾时延;更激进的降级能降低时延,但可能降低质量;更严格的验收能减少静默失败,但会增加验证成本和升级率。本文主张同时报告这些指标,而不是把它们压缩成一个未经校准的“可靠性分数”。
3.5 两个基本边界
在进入方法之前,先明确两个边界。它们不是悲观的假设,而是设计时必须尊重的约束。
边界 1:重试不能修复确定性故障。 如果故障的原因是输入非法、权限缺失、工具不存在或安全策略拒绝,并且没有任何动作改变这些原因,那么无论重试多少次,成功概率都不会提高。形式化地说,若
f
∈
{
T
7
,
T
8
}
f \in \{T7, T8\}
f∈{T7,T8},且动作集合中没有改变输入的修复动作,则对任意
k
k
k,
P
(
success
∣
f
,
a
(
k
)
)
=
P
(
success
∣
f
,
a
(
1
)
)
P(\text{success} \mid f, a^{(k)}) = P(\text{success} \mid f, a^{(1)})
P(success∣f,a(k))=P(success∣f,a(1))。此时正确的动作是 FAIL 或 ESCALATE,而不是继续消耗预算。盲目重试不仅浪费,还可能把一次可解释的失败变成一串难以审计的副作用。
边界 2:在结果未知且不可幂等的写操作上,重试有不可消除的重复风险。 如果工具不支持幂等键,也没有可查询的副作用账本,那么 Harness 无法区分“上次没有提交”和“上次已提交但响应丢失”。在这种情况下,任何自动重试都有非零概率重复提交。形式化地说,若 h ( a i ) = R 3 h(a_i)=R3 h(ai)=R3 且没有对账能力,则对任意重试策略, E [ D U P ] > 0 \mathbb{E}[\mathrm{DUP}] > 0 E[DUP]>0。此时唯一安全的自动动作是停止或升级;如果业务允许补偿,可以先补偿再重试,但补偿本身也需要幂等和审计。
这两个边界解释了为什么 HFR 把“分类”和“幂等”放在“重试”之前:不是所有失败都值得重试,也不是所有重试都安全。
4. 方法:HFR
4.1 总体架构
HFR 是 Harness 主循环旁边的一个可靠性控制面。它不替代规划器,也不替代工具执行器;它在每次模型调用、工具调用和提交动作前后介入,观察信号、做出决策、记录证据。图 2 给出 HFR 的控制回路。
┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ Observe │────▶│ Classify │────▶│ Check │────▶│ Decide │
│ status, │ │ F2D-9 │ │ budget, │ │ retry / │
│ latency, │ │ + confidence│ │ deadline, │ │ reconcile /│
│ payload │ │ │ │ risk │ │ degrade / │
└─────────────┘ └─────────────┘ └─────────────┘ │ escalate │
▲ └──────┬──────┘
│ │
│ ┌─────────────┐ ┌─────────────┐ │
└─────────────────────│ Record │◀────│ Verify │◀──────┘
│ event log, │ │ V0…V3 │
│ metrics │ │ + quality │
└─────────────┘ └─────────────┘
图 2 HFR 的七步控制回路。Check 同时检查重试预算、截止时间、熔断状态和副作用风险;Decide 输出一个动作及其理由;Verify 决定接受、继续恢复或升级;Record 把证据写入事件日志。
HFR 的运行原则可以概括为五条:
- 先判错,再决策。 没有分类的重试是盲试;没有分类的降级是猜测。
- 预算先于动作。 任何重试或降级都要先检查预算和截止时间,避免“先做了再后悔”。
- 副作用先于速度。 对写操作,先确认幂等能力或对账能力,再决定是否重试。
- 验收先于接受。 降级结果不能因为“已经花了钱”就被接受;必须通过对应级别的验收。
- 证据先于结论。 每次决策都记录信号、类别、动作、预算消耗和结果,便于事后审计和策略改进。
HFR 还需要定义失败时的默认行为。本文建议按副作用风险选择 fail-open 或 fail-closed:
- 对只读、可重放、低风险的动作,控制器自身故障时可以 fail-open,让 Harness 继续执行,但记录“控制器不可用”;
- 对写操作、不可逆动作、高关键度任务,控制器自身故障时必须 fail-closed,停止自动恢复并升级,避免在失去保护的情况下继续产生副作用。
4.2 故障分类器
分类器的输入是一组结构化信号,而不是单一错误码。表 4 给出常见的信号到 F2D-9 类别的映射。实际实现可以把规则、异常类型和轻量模型结合:规则负责高置信度的确定性错误,模型负责模糊的语义错误;两者都输出类别和置信度。
表 4 常见信号到故障类别的映射。
| 信号 | 类别 | 建议动作 |
|---|---|---|
| HTTP 500/502/503/504、连接重置 | T1 瞬时传输 | RETRY,full jitter,受预算约束 |
HTTP 429、Retry-After: N | T2 限流 | RETRY,至少等待
N
N
N 秒;不要立即重试 |
| HTTP 408、socket timeout、无响应 | T3 超时/结果未知 | 读操作 RETRY;写操作先 RECONCILE |
529、overloaded、队列满、持续 p95 升高 | T4 模型过载 | DEGRADE_MODEL 或等待;不要同模型硬重试 |
| 工具 5xx、unknown tool、schema mismatch | T5 工具不可用/契约不匹配 | DEGRADE_TOOL 或修复参数 |
context_length_exceeded、token 超限 | T6 上下文溢出 | COMPRESS 后 RETRY |
| 400 invalid_request、401/403、参数缺失 | T7 永久输入/权限 | FAIL 或 ESCALATE;不重试 |
| content policy、safety refusal | T8 安全拒绝 | ESCALATE;不得绕过 |
| schema 合法但测试失败、状态不一致 | V1 语义验收失败 | 带新证据 RETRY,否则 REPLAN/DEGRADE |
| 未知异常 | 未分类 | 读操作探测一次;写操作先对账;高关键度升级 |
分类器需要处理三个棘手情况。第一,错误码与真实原因不一致:某个提供商可能把过载包装成 500,把超时包装成 200 但内容为空。分类器应结合延迟、响应体、finish_reason 和工具状态,而不是只看状态码。第二,复合故障:一次调用可能同时触发限流和上下文溢出;分类器应输出主类别和次类别,动作选择器先处理高副作用风险的那个。第三,分类置信度低:当规则和模型不一致时,按副作用风险选择保守动作,而不是按最乐观的类别处理。
4.3 重试控制器
重试控制器决定“是否重试、何时重试、最多重试几次”。本文采用带 full jitter 的指数退避:
d k = U ( 0 , min ( d max , d 0 2 k − 1 ) ) , d_k = U\left(0, \min\left(d_{\max}, d_0 \, 2^{k-1}\right)\right), dk=U(0,min(dmax,d02k−1)),
其中 d 0 d_0 d0 是基础延迟, d max d_{\max} dmax 是延迟上限, k k k 是第 k k k 次重试, U ( 0 , x ) U(0,x) U(0,x) 表示 [ 0 , x ] [0,x] [0,x] 上的均匀随机变量。与固定退避相比,full jitter 把重试时间分散开,降低同步重试造成拥塞的概率;与“指数退避但不加抖动”相比,它更能避免多个客户端在同一时刻再次冲击已经过载的服务[28]。对限流错误,实际等待时间取下式:
d k effective = max ( d k , Retry-After ) . d_k^{\text{effective}} = \max\left(d_k,\; \text{Retry-After}\right). dkeffective=max(dk,Retry-After).
其中 Retry-After 的语义遵循 HTTP 规范[29];如果响应没有给出该字段,则使用本地退避策略,但仍受预算和截止时间约束。
重试不是无条件的。本文用 should_retry 函数表达重试资格:
should_retry(fault, action, state, budget, deadline):
if fault in {T7, T8}:
return False # 确定性错误/安全拒绝
if fault == T3 and action.side_effect_risk >= R2:
return reconcile_first(action) # 结果未知的写操作先对账
if fault in {T4, T5}:
return False # 同模型/同工具重试价值低
if fault == T6 and not state.compressed:
return False # 先压缩,再重试
if budget.remaining_step <= 0 or budget.remaining_task <= 0:
return False
if now + estimate_delay(...) + estimate_step(...) > deadline:
return False
if breaker.is_open(action.provider_or_tool):
return False
return True
重试控制器还要设置三类预算:每步预算 B s B_s Bs 限制单个逻辑步骤的尝试次数,每任务预算 B t B_t Bt 限制整个任务的额外尝试,每租户预算 B tenant B_{\text{tenant}} Btenant 限制一个租户在一个时间窗口内的重试总量。前两者保护单任务不被无限重试拖垮,后者保护多租户系统不被某个租户的重试风暴拖垮。预算可以用令牌桶实现:每次重试消耗一个令牌,令牌按时间补充,桶满即停。
重试的停止条件同样重要。除了预算耗尽,以下情况应立即停止:
- 同一故障类别连续出现 K K K 次,且没有新证据:说明重试没有改变原因,继续重试是低价值循环;
- 验收器连续拒绝同一输出,且拒绝理由相同:说明需要改变策略,而不是重复生成;
- 截止时间即将到达:即使重试可能成功,也可能因为超时而变成失败,应优先降级或升级;
- 熔断器打开:说明上游已经不健康,继续重试会加剧拥塞;
- 副作用风险为 R3:任何自动重试都可能造成不可逆后果。
4.4 降级阶梯
降级不是“换一个小模型”这么简单。本文把降级组织成五级阶梯,如表 5 所示。层级越高,能力/质量风险越大,需要的验收越严格。
表 5 降级阶梯。
| 级别 | 变化 | 典型收益 | 主要风险 | 允许的自动关键度 | 验收级别 |
|---|---|---|---|---|---|
| L0 | 不降级,正常执行 | 质量最高 | 无 | low/medium/high | 按任务 |
| L1 | 上下文压缩、缩小检索范围、滚动摘要 | 降低 token 与上下文溢出 | 丢失关键信息 | low/medium/high | V1 |
| L2 | 同层替代模型/提供商,或等价工具 | 绕过单点故障 | 行为差异、契约差异 | low/medium/high | V1/V2 |
| L3 | 更小/更便宜的模型,缩小任务范围 | 降本、降延迟 | 能力不足、结果不完整 | low/medium | V2 |
| L4 | 确定性兜底(缓存/模板/部分结果)或人工 | 保证有响应 | 静默不完整、人工成本 | low(medium 需人工确认) | V2/V3 |
降级阶梯的选择逻辑如下:
choose_degradation(fault, state, criticality, quality_floor):
if fault == T6 and not state.compressed:
return L1_COMPRESS
if fault == T4:
return L2_ALT_MODEL if criticality != high else L2_ALT_MODEL
if fault == T5:
return L2_ALT_TOOL
if retry_budget_exhausted:
if criticality == high:
return L4_ESCALATE
if criticality == medium:
return L3_SMALLER_MODEL
return L4_DETERMINISTIC
return L0
这个伪代码是策略示例,不是唯一实现。实际系统应把“故障类别、关键度、质量下限、预算、截止时间、历史降级结果”一起输入决策器。关键不是层级名称,而是三个约束:
- 质量下限约束。 如果任务要求 q min = 0.9 q_{\min}=0.9 qmin=0.9,而某个降级路径的历史质量只有 0.7,则即使它更快更便宜,也不能自动接受;应选择更高层级的替代,或升级。
- 安全不变量。 降级不能绕过安全策略、权限检查、内容审核和审计。一个模型因为安全策略拒绝执行,不能通过换一个更弱的模型来“绕过”;这不是降级,而是规避。
- 可观测性。 每次降级都要记录级别、原因、替代对象、质量估计和验收结果。调用方应能看到
degraded=true,而不是只看到一个看似正常的响应。
降级还需要兼容层。不同模型的输出格式、工具 schema、错误语义可能不同;HFR 用一个适配器把替代模型/工具的输出规范化到原契约,并在适配失败时把“契约不匹配”反馈给分类器。对工具降级,适配器至少要检查:必填字段是否齐全、单位/类型是否一致、错误码是否可映射、副作用语义是否等价。对不可逆写操作,不允许“语义近似”的替代工具;必须使用同一语义的工具,或升级。
4.5 幂等与副作用账本
幂等是 HFR 的正确性核心。本文要求:在第一次尝试之前为每个可能产生副作用的逻辑动作生成幂等键,并把“意图”写入账本;重试时复用同一个键,而不是生成新键。键的构造如下:
k = S H A 256 ( tenant ∥ task ∥ i ∥ tool ∥ c a n o n i c a l ( a r g s ) ) , k = \mathrm{SHA256}\left( \text{tenant} \parallel \text{task} \parallel i \parallel \text{tool} \parallel \mathrm{canonical}(args) \right), k=SHA256(tenant∥task∥i∥tool∥canonical(args)),
其中 c a n o n i c a l ( a r g s ) \mathrm{canonical}(args) canonical(args) 是对参数做稳定序列化(键排序、去除无关空白、统一数字格式)后的结果。键必须满足两个性质:同一个逻辑动作的所有重试共享同一个键;不同的逻辑动作即使参数相同,也最好带有步骤号或意图号,避免误去重。对确实需要“同一参数执行两次”的场景,应在参数中显式加入业务意图标识,而不是依赖 Harness 的步骤号。
账本的状态机如表 6 所示。核心思想是把“意图”和“结果”分开记录:在调用工具之前先写 PREPARED,工具确认成功后写 COMMITTED,工具确认失败后写 FAILED,超时或无响应写 UNKNOWN。恢复时先查账本,再决定是否重试。
表 6 副作用账本状态。
| 状态 | 含义 | 允许的下一步 |
|---|---|---|
PREPARED | 意图已记录,尚未确认结果 | 调用工具;超时转 UNKNOWN |
COMMITTED | 工具确认副作用已提交 | 不再重试;继续后续步骤 |
FAILED | 工具确认未提交 | 可重试(若幂等)或降级 |
UNKNOWN | 结果未知(超时/连接中断) | 必须 RECONCILE |
RECONCILED_COMMITTED | 对账确认已提交 | 视为成功;不重试 |
RECONCILED_ABSENT | 对账确认未提交 | 可重试;复用同一幂等键 |
COMPENSATED | 已执行补偿 | 记录补偿证据;按业务决定是否重试 |
本文把工具按副作用能力分为四级,如表 7 所示。这个分级决定了重试策略:R0/R1 可以自动重试,R2 必须先对账,R3 不得自动重试。
表 7 工具副作用能力分级。
| 级别 | 能力 | 示例 | 自动重试策略 |
|---|---|---|---|
| R0 | 只读,无副作用 | 搜索、读取文件、查询数据库 | 可自由重试(仍受预算约束) |
| R1 | 幂等写,支持幂等键 | 带 idempotency-key 的支付/创建接口 | 复用同一键重试 |
| R2 | 非幂等写,但可查询状态 | 订单创建后可按业务号查询 | 先对账,确认未提交再重试 |
| R3 | 不可逆或不可查询 | 发送邮件、删除文件、外部转账 | 不自动重试;升级或补偿 |
对账协议分为四步:
- 查账本:如果账本已经是
COMMITTED,直接视为成功,不调用工具。 - 查外部状态:用幂等键或业务标识查询工具/数据库;如果查到已提交,写
RECONCILED_COMMITTED;如果确认不存在,写RECONCILED_ABSENT。 - 处理不确定:如果查询本身失败或返回不一致,不要猜测;写
UNKNOWN,升级或等待人工。 - 重试或补偿:只有在
RECONCILED_ABSENT时才重试;如果是COMMITTED但业务需要回滚,走补偿流程,而不是重试。
补偿本身也可能失败,因此补偿动作也需要幂等键和审计。Saga 模式提供了长事务补偿的结构[22],但补偿不是万能的:有些外部副作用不可逆(例如已经发出的邮件),这时唯一安全的做法是升级和记录,而不是假装可以“撤销”。账本的所有权也需要保护:在分布式部署中,可以用租约或 fencing token 确保同一时刻只有一个恢复者在对账和重试,避免两个副本同时执行同一动作[35][36]。
4.6 验收器
验收器决定“这个结果是否可以接受”。本文把验收分为四级,如表 8 所示。级别越高,成本越高,但能捕获更隐蔽的失败。
表 8 验收级别。
| 级别 | 检查内容 | 成本 | 适用场景 |
|---|---|---|---|
| V0 | 传输层:HTTP 状态、JSON schema、非空、类型 | 低 | 所有调用 |
| V1 | 确定性:退出码、单元测试、类型检查、必填字段、lint | 中 | 代码、结构化输出、工具结果 |
| V2 | 语义:rubric judge、环境状态核对、跨步骤一致性 | 高 | 自然语言输出、复杂任务 |
| V3 | 权威/人工:高 stakes 审批、领域专家复核 | 很高 | 金融、医疗、不可逆操作 |
验收器的输出不应只是“通过/不通过”,而应包含失败原因和证据。例如,V1 可以返回“测试 test_checkout 失败,期望 200 实际 500”;V2 可以返回“答案与工具查询到的库存不一致”;V3 可以返回“人工拒绝:金额超过阈值”。这些证据既用于决定下一步动作,也用于审计和策略改进。
验收器有噪声。设 α \alpha α 为把失败误判为通过的概率(false accept), β \beta β 为把成功误判为失败的概率(false reject)。 α \alpha α 带来静默失败, β \beta β 带来不必要的重试和升级。HFR 不应假设验收器是完美的;它应通过标注数据校准阈值,监控 α / β \alpha/\beta α/β 的漂移,并对高风险任务使用更高层级的验收。特别地,不能把“模型自评”当作唯一的验收信号:Huang 等人的实验表明,没有外部反馈时,LLM 的内在自我纠正并不稳定[19]。验收应尽量依赖外部证据:测试、工具状态、数据库记录、人工复核。
验收后的决策规则如下:
decide_after_verification(result, context):
if result.passed and result.quality >= context.q_min:
return ACCEPT
if result.passed and result.quality < context.q_min:
return DEGRADE_OR_ESCALATE # 质量不达标,不能静默接受
if result.failed and context.can_retry and context.has_new_evidence:
return RETRY
if result.failed and context.can_degrade:
return DEGRADE
return ESCALATE
其中 has_new_evidence 很重要:语义失败的重试只有在有新证据(测试输出、工具结果、人工反馈、环境变化)时才有较高价值;没有新证据的重复生成,往往只是把同样的错误再采样一次。
4.7 熔断与舱壁
重试控制器解决“单个动作失败后怎么办”,熔断器解决“上游整体不健康时怎么办”。HFR 为每个提供商、模型、工具和租户维护一个熔断器,状态包括:
- Closed:正常放行;统计错误率、429 率、p95 延迟和连续失败数。
- Open:快速失败或直接路由到降级路径;不再向该上游发送重试请求。
- Half-open:允许少量探测请求;如果成功,回到 Closed;如果失败,回到 Open 并延长冷却时间。
触发条件可以是多维的:
trip = ( errors requests > θ e ) ∨ ( 429 s requests > θ r ) ∨ ( p 95 > θ l ) ∨ ( consecutive failures ≥ K ) . \text{trip} = \left( \frac{\text{errors}}{\text{requests}} > \theta_e \right) \lor \left( \frac{429\text{s}}{\text{requests}} > \theta_r \right) \lor \left( p95 > \theta_l \right) \lor \left( \text{consecutive failures} \ge K \right). trip=(requestserrors>θe)∨(requests429s>θr)∨(p95>θl)∨(consecutive failures≥K).
冷却时间应带抖动,避免所有客户端在同一时刻进入 half-open。熔断器与重试控制器的关系是:熔断器打开时,重试控制器不应再重试该上游;应直接选择降级路径或升级。 这可以避免“重试风暴—上游更慢—更多重试”的亚稳态循环[21]。
舱壁(bulkhead)是另一层保护:为不同提供商、工具和租户分配独立的并发池,防止一个故障池耗尽全局并发。对关键任务保留容量,对低优先级任务允许更早降级。多租户场景下,租户级重试预算和并发配额是防止“邻居噪声”的关键。
4.8 预算分配与截止时间
预算分配的目标不是“平均用力”,而是把有限的重试机会留给最值得恢复的步骤。本文用一个简单的权重分配:
w i = c i ⋅ ρ i , B i = max ( 0 , ⌊ B t w i ∑ j = 1 n w j ⌋ ) , w_i = c_i \cdot \rho_i, \qquad B_i = \max\left(0, \left\lfloor B_t \frac{w_i}{\sum_{j=1}^{n} w_j} \right\rfloor\right), wi=ci⋅ρi,Bi=max(0,⌊Bt∑j=1nwjwi⌋),
其中 c i c_i ci 是第 i i i 步的关键度(可以由下游依赖、失败代价或业务规则估计), ρ i \rho_i ρi 是该步故障的可恢复性(由故障类别和历史统计估计)。高关键度、可恢复的步骤获得更多预算;低关键度、不可恢复的步骤获得更少预算。实际实现还应保留一个“最后一步预算”,避免前面的步骤把预算耗尽,导致最终提交或验收没有重试机会。
截止时间约束同样重要。设当前时间为 t t t,第 k k k 次重试的估计延迟为 d ^ k \hat{d}_k d^k,第 i i i 步的估计执行时间为 t ^ i \hat{t}_i t^i,则只有在
t + d ^ k + t ^ i + t ^ verify ≤ D t + \hat{d}_k + \hat{t}_i + \hat{t}_{\text{verify}} \le D t+d^k+t^i+t^verify≤D
时才值得重试。否则,重试即使成功也可能因为超时而失败;此时应优先降级到更快路径,或提前升级。这个规则把“成功率”和“尾时延”联系起来:一个在截止时间之后才成功的任务,在业务上仍然是失败。
4.9 状态机与执行流程
HFR 的控制逻辑可以用一个状态机表示。表 9 给出主要状态和转移。
表 9 HFR 状态机。
| 状态 | 触发条件 | 动作 | 下一状态 |
|---|---|---|---|
INIT | 任务开始 | 初始化预算、账本、熔断视图 | RUN_STEP |
RUN_STEP | 执行第 i i i 步 | 调用模型/工具 | OBSERVE |
OBSERVE | 收到结果或异常 | 收集信号、更新状态 | CLASSIFY |
CLASSIFY | 有观测 | 输出 F2D 类别与置信度 | CHECK |
CHECK | 有类别 | 检查预算、截止时间、熔断、副作用风险 | DECIDE |
DECIDE | 检查完成 | 选择 RETRY/RECONCILE/COMPRESS/DEGRADE/REPLAN/ESCALATE/FAIL | 对应状态 |
RETRY_WAIT | 选择重试 | 计算退避、等待、扣预算 | RUN_STEP |
RECONCILE | 结果未知/写操作 | 查账本和外部状态 | RETRY_WAIT/COMMIT/ESCALATE |
COMPRESS | 上下文溢出 | 压缩/滚动摘要 | RUN_STEP |
DEGRADE | 需要降级 | 选择下一级、适配契约 | RUN_STEP/ESCALATE |
REPLAN | 语义失败/计划失效 | 保留已提交步骤,更新后续计划 | RUN_STEP/ESCALATE |
VERIFY | 动作返回 | 执行 V0–V3 验收 | ACCEPT/DECIDE |
ACCEPT | 验收通过且质量达标 | 提交步骤、写日志 | RUN_STEP/DONE |
ESCALATE | 高风险/无安全替代 | 打包证据、交人工 | DONE |
FAIL | 确定性失败/预算耗尽 | 返回结构化失败 | DONE |
执行流程的伪代码如下:
execute_task(T):
state = init_state(T)
for i in 1..n:
while True:
result = execute_step(state, i)
fault = classify(result, state)
if fault is None and verify(result, level(T)) == PASS:
commit_step(state, i, result)
break
budget = check_budget(state, fault)
if not budget.ok:
return degrade_or_escalate(state, fault)
action = decide_action(fault, result, state, budget)
if action == RETRY:
sleep(backoff(state, fault))
state.budget.consume()
continue
if action == RECONCILE:
outcome = reconcile(state, i)
if outcome == COMMITTED:
commit_step(state, i, outcome)
break
if outcome == ABSENT:
continue
return escalate(state, "reconcile_unknown")
if action == COMPRESS:
state = compress_context(state)
continue
if action == DEGRADE:
state = apply_degradation(state, fault)
continue
if action == REPLAN:
state = replan(state, result, fault)
continue
if action == ESCALATE:
return escalate(state, fault)
if action == FAIL:
return fail(state, fault)
return final_verify_and_commit(state)
这段伪代码省略了并发、持久化和多租户细节,但保留了核心顺序:执行—观测—分类—检查—决策—验收—提交。实现时,状态机应可持久化,以便进程崩溃后恢复;账本和预算应在提交点原子更新,避免“动作已做但预算没扣”或“预算扣了但动作没做”的不一致。
4.10 复杂度与条件性安全性质
复杂度。 设任务有 n n n 个逻辑步骤,每步最多 A max = 1 + B s A_{\max}=1+B_s Amax=1+Bs 次尝试,验收成本为 V V V。HFR 的时间复杂度为 O ( n A max + V ) O(n A_{\max} + V) O(nAmax+V),其中分类和决策在每步是常数时间,退避等待不计入 CPU 时间。空间复杂度为 O ( n + K ) O(n + K) O(n+K), n n n 用于保存步骤状态和检查点, K K K 是幂等账本中的键数量。熔断器、令牌桶和分类器都是常数空间。实际成本主要由模型/工具调用和验收器决定,而不是控制逻辑本身。
命题 1(尝试次数有界)。 在 HFR 同时启用每步预算 B s B_s Bs 和每任务预算 B t B_t Bt 时,任务的总尝试次数满足
A total ≤ min ( n ( 1 + B s ) , n + B t ) . A_{\text{total}} \le \min\left(n(1+B_s),\; n+B_t\right). Atotal≤min(n(1+Bs),n+Bt).
证明草图. 每个步骤的尝试次数最多为 1 + B s 1+B_s 1+Bs,因此总尝试次数不超过 n ( 1 + B s ) n(1+B_s) n(1+Bs)。每任务预算 B t B_t Bt 限制的是额外重试次数,因此总尝试次数不超过基础执行次数 n n n 加上 B t B_t Bt。两者取最小值即得。证毕。
命题 2(幂等重试的副作用上界)。 若每个带副作用的逻辑动作在首次尝试前生成唯一幂等键,工具对同一键最多提交一次副作用,且所有重试复用同一键,则任意次重试对每个逻辑动作最多产生一次已提交副作用。
证明草图. 工具按幂等键去重;同一逻辑动作的所有尝试共享同一个键,因此无论重试多少次,工具最多提交一次。不同逻辑动作使用不同键,因此不会互相去重。证毕。该命题依赖“工具正确实现幂等键语义”这一假设;如果工具忽略键,命题不成立。
命题 3(对账后重试的安全性)。 若对账查询是可线性化的,并且能区分“已提交”“未提交”“未知”三种状态;Harness 只在 RECONCILED_ABSENT 时重试,在 RECONCILED_COMMITTED 时视为成功,在未知时升级,则对账后的重试不会重复提交已经提交的副作用。
证明草图. 如果副作用已提交,可线性化查询会返回“已提交”,Harness 不会重试;如果查询返回“未提交”,则重试是安全的;如果查询返回“未知”,Harness 不重试。因此不会出现“已提交后又重试”的情况。证毕。该命题依赖查询的完整性和一致性;如果查询本身可能漏掉已提交记录,安全性无法保证。
命题 4(降级质量守卫)。 若验收器没有 false accept,即任何被接受的输出都满足 Q ≥ q min Q \ge q_{\min} Q≥qmin,则所有被自动接受的降级输出都满足质量下限。
证明草图. 由验收器的定义,接受蕴含 Q ≥ q min Q \ge q_{\min} Q≥qmin;降级输出也必须经过同一验收器,因此满足质量下限。证毕。该命题是条件性的:它把质量保证转移到了验收器的有效性上。如果验收器有 false accept,降级仍可能静默失败。
这四条性质不是对端到端正确性的证明,而是对 HFR 设计边界的澄清:预算给出一致性上界,幂等给出副作用上界,对账给出结果未知时的安全条件,验收给出质量守卫。 它们都依赖明确的假设;工程实现必须验证这些假设是否成立,而不是把命题当作无条件保证。
5. 参考实现
5.1 模块划分与接口
本节给出一个与语言无关的参考实现。实现可以用 Python、Go、Java 或 TypeScript,关键是保持模块边界和状态机语义。表 10 给出模块职责。
表 10 HFR 的参考模块。
| 模块 | 职责 | 关键状态 |
|---|---|---|
FailureClassifier | 把异常、状态码、响应体、工具结果映射到 F2D-9 类别和置信度 | 规则版本、模型版本、阈值 |
BudgetManager | 管理每步/任务/租户预算、截止时间和令牌桶 | 剩余令牌、窗口起点、截止时间 |
RetryController | 计算退避、判断重试资格、执行停止条件 | 尝试次数、连续同类失败数 |
IdempotencyLedger | 生成幂等键、记录意图/结果、执行对账和补偿 | 键、状态、提交证据 |
DegradationLadder | 选择降级级别、适配模型/工具契约、检查质量下限 | 当前级别、替代对象、质量估计 |
AcceptanceVerifier | 执行 V0–V3 验收、输出失败原因和质量估计 | 验收级别、阈值、标注数据版本 |
CircuitBreaker | 按提供商/模型/工具/租户统计健康度、打开/半开/关闭 | 错误率、连续失败、冷却时间 |
Telemetry | 记录事件、指标、追踪和审计字段 | 事件缓冲、采样率、脱敏策略 |
ReliabilityController | 编排以上模块,执行状态机 | 任务状态、预算、账本引用 |
一个最小接口可以写成:
class FailureClassifier:
def classify(self, observation: Observation) -> Fault:
...
class BudgetManager:
def check(self, task_id: str, step: int, fault: Fault) -> BudgetDecision:
...
class RetryController:
def should_retry(self, fault: Fault, state: TaskState,
budget: BudgetDecision) -> bool:
...
def delay(self, attempt: int, fault: Fault) -> float:
...
class IdempotencyLedger:
def prepare(self, key: str, intent: Intent) -> None:
...
def commit(self, key: str, evidence: Evidence) -> None:
...
def reconcile(self, key: str) -> ReconcileResult:
...
class DegradationLadder:
def choose(self, fault: Fault, state: TaskState) -> Degradation:
...
def apply(self, state: TaskState, degradation: Degradation) -> TaskState:
...
class AcceptanceVerifier:
def verify(self, step: Step, state: TaskState,
level: VerifyLevel) -> VerifyResult:
...
class CircuitBreaker:
def allow(self, target: str) -> bool:
...
def record(self, target: str, outcome: Outcome) -> None:
...
这些接口刻意保持窄小:分类器不执行动作,预算器不调用工具,验收器不修改计划。这样做的好处是每个模块都可以单独测试、替换和观测;坏处是需要一个编排器来保证顺序和一致性。ReliabilityController 就是这个编排器。
5.2 配置示例
HFR 的行为应由配置驱动,而不是散落在代码中的硬编码常量。下面是一个 YAML 示例,展示预算、退避、降级、验收和熔断的配置方式。实际系统可以按租户、任务类型或工具覆盖这些值。
hfr:
version: "1.0"
retry:
base_delay_ms: 200
max_delay_ms: 2000
jitter: full
max_attempts_per_step: 4 # 1 次初始 + 3 次重试
max_retries_per_task: 10
max_retries_per_tenant_per_min: 600
respect_retry_after: true
retry_on: [T1, T2, T3_readonly, T6_after_compress]
never_retry_on: [T7, T8, T3_write_without_idempotency]
degradation:
ladder: [L0, L1, L2, L3, L4]
quality_floor:
low: 0.60
medium: 0.80
high: 0.92
allow_auto_degrade:
low: [L1, L2, L3, L4]
medium: [L1, L2, L3]
high: [L1, L2]
require_human_for:
high: [L3, L4]
irreversible: [L2, L3, L4]
idempotency:
enabled: true
key_fields: [tenant, task, step, tool, canonical_args]
ledger: postgres
reconcile_timeout_ms: 1500
verification:
default_level: V1
levels:
low: V1
medium: V2
high: V2
human_spot_check_rate: 0.05
circuit_breaker:
error_rate_threshold: 0.50
consecutive_failures: 5
cooldown_ms: 30000
half_open_probes: 2
telemetry:
sample_rate: 1.0
redact_pii: true
emit_decision_events: true
配置中有两个容易出错的点。第一,max_attempts_per_step 应理解为“总尝试次数”,而不是“重试次数”;如果配置写错,实际重试次数会多一次。第二,quality_floor 不是“模型置信度阈值”,而是任务所有者对输出质量的最低要求;它应该由业务定义,而不是由模型自己估计。模型置信度可以作为验收的一个信号,但不能替代质量下限。
5.3 错误映射
表 11 给出常见错误到 F2D-9 类别和建议动作的映射。实际实现应把提供商特有的错误码放进适配器,而不是把某个厂商的字符串硬编码到控制器里。
表 11 常见错误映射。
| 场景 | 典型错误 | 类别 | 动作 |
|---|---|---|---|
| 模型 API 瞬时失败 | HTTP 500/502/503/504 | T1 | RETRY,full jitter |
| 限流 | HTTP 429、Retry-After | T2 | 等待 Retry-After 后 RETRY |
| 模型过载 | HTTP 529、overloaded | T4 | DEGRADE_MODEL 或等待 |
| 请求超时(读) | timeout、no response | T3 | RETRY(受预算约束) |
| 请求超时(写) | timeout、no response | T3 | RECONCILE;未知则 ESCALATE |
| 上下文超限 | context_length_exceeded | T6 | COMPRESS 后 RETRY |
| 参数错误 | HTTP 400 invalid_request | T7 | FAIL 或修复参数后重试一次 |
| 认证/权限 | HTTP 401/403 | T7 | FAIL/ESCALATE;不重试 |
| 安全拒绝 | content policy violation | T8 | ESCALATE;不降级绕过 |
| 工具不存在 | unknown tool | T5 | DEGRADE_TOOL 或修复注册 |
| 工具 schema 不匹配 | missing/invalid field | T5 | 修复参数或换等价工具 |
| 测试失败 | exit code != 0、test failure | V1 | 带失败证据 RETRY/REPLAN |
| 语义不一致 | judge reject、state mismatch | V1 | 带证据 RETRY,否则 DEGRADE/ESCALATE |
错误映射应遵循三个原则:不把 4xx 一律当永久错误(408/409/429 可能需要特殊处理);不把 5xx 一律当瞬时错误(持续 5xx 可能是过载或部署故障,应触发熔断);不把安全拒绝当可重试错误(换模型绕过安全策略是错误的设计)。
5.4 与 Harness 主循环集成
HFR 可以在 Harness 的四个钩子处介入:
before_model_call:检查预算、熔断状态、上下文长度;如果上下文接近上限,先压缩或截断。after_model_call:分类错误、解析工具调用、执行 V0/V1 验收;如果模型输出 malformed tool call,转到REPLAN或修复。before_tool_call:检查副作用等级、幂等键、权限和工具健康度;R3 动作在高风险场景下要求确认。after_tool_call:记录结果、更新账本、执行 V0/V1 验收;超时或无响应转RECONCILE。
任务结束时,HFR 执行最终验收和提交。最终验收应至少包括:成功规范是否满足、是否有未对账的 UNKNOWN 账本项、是否有降级未标注、是否有重复副作用、是否需要人工复核。只有这些都通过,任务才标记为“干净成功”。
状态持久化是集成中的关键。HFR 应在以下时点做检查点:
- 任务开始时:保存任务规范、预算、配置版本;
- 每次
PREPARED账本写入后:保存意图; - 每次
COMMITTED后:保存提交证据; - 每次降级后:保存级别和替代对象;
- 每次升级前:保存完整证据包。
检查点应包含版本号,便于恢复时检测配置漂移。恢复时,HFR 先重放账本,确认哪些动作已提交、哪些是 UNKNOWN,再决定是否继续。不要在没有对账的情况下“从最后一个成功步骤继续”,否则可能重复执行已经提交的副作用。
5.5 可观测性指标
HFR 的日志应围绕“决策”而不是“异常”组织。每条决策事件至少包含:任务 ID、步骤 ID、故障类别、置信度、动作、预算余额、退避时间、降级级别、验收结果、是否升级、耗时和成本。指标命名和追踪字段可以遵循 OpenTelemetry 的语义约定[33],以便与现有可观测性平台集成。下面是一组建议的指标:
| 指标 | 类型 | 用途 |
|---|---|---|
harness_attempts_total{class,outcome} | Counter | 观察各类故障的尝试与结果 |
harness_retry_amplification | Gauge/Histogram | 总尝试次数 / 逻辑步骤数 |
harness_retry_budget_exhausted_total | Counter | 预算是否成为瓶颈 |
harness_degradation_total{level,reason} | Counter | 降级分布与原因 |
harness_degradation_quality_delta | Histogram | 降级前后的质量差 |
harness_duplicate_side_effects_total | Counter | 重复副作用;应为 0 或接近 0 |
harness_reconcile_total{outcome} | Counter | 对账结果分布 |
harness_verification_failures_total{level,reason} | Counter | 验收失败原因 |
harness_escalations_total{reason} | Counter | 人工升级原因 |
harness_cost_per_success | Gauge | 每成功任务成本 |
harness_p95_latency_non_escalated | Gauge | 排除人工升级后的尾时延 |
harness_circuit_state{target} | Gauge | 熔断器状态 |
告警应围绕“异常模式”而不是单个错误:重试放大率持续高于阈值、重复副作用大于 0、降级率突然上升、验收失败率上升、熔断器长时间打开、升级率异常。单个 500 错误不值得告警;持续的重试风暴和副作用重复才值得。
5.6 部署与治理
HFR 的上线应分三步:
- 影子模式(shadow):只分类和记录,不改变实际动作;用真实流量比较“如果执行 HFR 会怎样”和“当前策略怎样”。这一步可以校准分类器、验收器和预算参数,而不影响用户。
- 金丝雀(canary):对 1% 的租户或任务启用 HFR,观察成功率、成本、尾时延、重复副作用和升级率;设置自动回滚条件。
- 逐步放量:按租户、任务类型或工具逐步扩大;保留租户级开关和全局 kill switch。
治理上需要明确四点。第一,审计:每次重试、降级、对账和升级都要有证据和理由,满足合规和事后复盘。第二,租户隔离:预算、并发、熔断和账本按租户隔离,防止一个租户的重试风暴影响其他租户。第三,安全策略不可降级:安全拒绝、权限检查和内容审核不能被“换模型/换工具”绕过。第四,人类可接管:高关键度任务必须有人工升级路径,升级包应包含任务状态、已提交副作用、失败证据和建议动作。
6. 实验与 Benchmark
6.1 研究问题
本章围绕五个问题组织:
- RQ1(总体效果):在混合故障下,统一的重试+降级策略是否比“只重试”“只降级”“不重试”更可靠?
- RQ2(安全与效率):统一策略是否能在不显著增加成本的情况下减少重复副作用和尾时延?
- RQ3(组件贡献):验收器、幂等、预算分别贡献了什么?
- RQ4(故障率敏感性):故障率升高时,策略之间的差距如何变化?
- RQ5(评测协议):如何在一个可复现的基准中同时测量能力、恢复和副作用安全?
6.2 合成故障注入设置
本文使用一个显式的合成模拟器来回答 RQ1–RQ4。模拟器不是对真实 LLM 的测量;它用参数化的故障、延迟、成本和成功率来比较策略的相对行为。模拟器的完整脚本和结果随文提供:harness_retry_degrade_sim.py、harness_retry_degrade_sim_results.json、harness_retry_degrade_sim_results.md。任何读者都可以用固定随机种子复现下表的数字。
任务模型。 每个任务有 4–8 个逻辑步骤(加权采样),每步可能是模型调用(35%)、只读工具(45%)或写工具(20%)。任务关键度按 low 35%、medium 45%、high 20% 采样。每个任务有截止时间、质量下限和成本预算的抽象表示;模拟器主要测量成功率、成本、时延和副作用,不模拟完整的业务价值函数。
故障模型。 每次尝试以基础概率 p fault p_{\text{fault}} pfault 注入故障;故障类别按表 2 中的八类基础设施/工具故障分布采样,V1 语义验收失败由基座成功率与验收器噪声产生,不作为独立注入类别。模型相关的故障包括瞬时传输、限流、超时、过载、上下文溢出、永久输入和安全拒绝;工具相关的故障包括瞬时传输、限流、超时、工具不可用、永久输入和安全拒绝。非重试类故障(过载、工具缺失、永久输入、安全拒绝)在同一个逻辑步骤内具有粘性:后续尝试有 90% 的概率再次遇到同一故障,除非通过降级改变了模型或工具。这个假设反映了一个现实:缺失的工具或权限不会因为“再试一次”而自动出现。
模型与工具。 主模型、备用模型和廉价模型的基准成功率分别为 0.94、0.86、0.74,相对成本为 1.00、0.45、0.18,单步时延为 1.20、0.65、0.35 秒。主工具、替代工具和缓存兜底的基准成功率分别为 0.95、0.86、0.55,相对成本为 0.10、0.08、0.00,单步时延为 0.40、0.30、0.05 秒。高质量任务对降级模型有额外的质量惩罚;关键度越高,惩罚越大。这些数字是建模假设,不是从某个厂商或论文中测得的。
对比策略。 本文比较八种策略:
NoRetry:失败即停止,不重试、不降级;FixedRetry3:固定延迟重试最多 3 次,不做错误分类,不使用幂等键;RetryOnly:带 full-jitter 的指数退避重试,最多 3 次,有幂等键,但不降级;DegradeOnly:不重试,首次失败即按阶梯降级;HFR:完整策略,重试+对账+降级+验收+预算;HFR − verifier:去掉验收器,其余同 HFR;HFR − idempotency:去掉幂等键与账本,其余同 HFR;HFR − budget:去掉每任务重试预算(每步仍有限制),其余同 HFR。
模拟规模。 主结果使用 10 个独立随机种子,每个种子 20,000 个任务。敏感性分析使用 seed=42、每个故障率点 12,000 个任务。所有数字报告为 10 个种子的均值 ± 标准差;由于模拟是合成且任务独立,标准差主要反映采样噪声,不应被解释为对真实系统的置信区间。
6.3 主结果
表 12 和表 13 给出主结果。表 12 关注成功率与安全指标,表 13 关注成本、时延和尝试次数。
表 12 合成故障注入主结果(10 seeds × 20,000 tasks;均值 ± 标准差)。SR=任务成功率,CSR=干净成功率,SCR=安全完成率,CPS=每成功任务成本,DUP=每千任务重复副作用,ESC=升级率,DEG=降级率。
| 策略 | SR | CSR | SCR | CPS | DUP/1000 | ESC | DEG |
|---|---|---|---|---|---|---|---|
| 不重试 | 25.61% ± 0.31 | 25.61% | 25.61% | 5.646 ± 0.063 | 0.00 | 0.00% | 0.00% |
| 固定重试 3 次(无幂等) | 86.17% ± 0.25 | 84.57% ± 0.28 | 84.57% | 2.986 ± 0.015 | 17.47 ± 0.67 | 0.00% | 0.00% |
| 指数退避重试(有幂等) | 75.04% ± 0.26 | 75.04% | 75.04% | 2.990 ± 0.015 | 0.00 | 0.00% | 0.00% |
| 仅降级 | 64.79% ± 0.56 | 64.79% | 64.79% | 3.519 ± 0.024 | 0.00 | 0.00% | 68.07% ± 0.25 |
| HFR(完整) | 86.25% ± 0.32 | 86.25% | 92.07% ± 0.20 | 2.954 ± 0.015 | 0.00 | 5.83% ± 0.23 | 14.67% ± 0.25 |
| HFR − 验收器 | 62.89% ± 0.23 | 62.89% | 68.30% ± 0.29 | 3.927 ± 0.017 | 0.00 | 5.41% ± 0.12 | 14.02% ± 0.26 |
| HFR − 幂等 | 86.25% ± 0.32 | 84.66% ± 0.34 | 90.43% ± 0.25 | 2.954 ± 0.013 | 17.68 ± 0.73 | 5.83% ± 0.24 | 14.64% ± 0.32 |
| HFR − 预算 | 86.25% ± 0.32 | 86.25% | 92.08% ± 0.20 | 2.954 ± 0.015 | 0.00 | 5.82% ± 0.23 | 14.67% ± 0.25 |
表 13 合成故障注入的成本、时延和尝试次数(10 seeds × 20,000 tasks;均值 ± 标准差)。
| 策略 | 平均成本 | p95 总时延 (s) | p95 非升级时延 (s) | 平均尝试/任务 |
|---|---|---|---|---|
| 不重试 | 1.446 ± 0.008 | 5.20 | 5.20 | 3.49 ± 0.01 |
| 固定重试 3 次(无幂等) | 2.573 ± 0.010 | 7.92 ± 0.10 | 7.92 | 6.27 ± 0.01 |
| 指数退避重试(有幂等) | 2.243 ± 0.010 | 6.47 ± 0.03 | 6.47 | 5.41 ± 0.01 |
| 仅降级 | 2.280 ± 0.012 | 6.75 ± 0.02 | 6.75 | 6.17 ± 0.01 |
| HFR(完整) | 2.548 ± 0.009 | 10.75 ± 0.03 | 6.85 ± 0.03 | 5.98 ± 0.02 |
| HFR − 验收器 | 2.470 ± 0.007 | 10.44 ± 0.01 | 6.41 ± 0.01 | 5.79 ± 0.01 |
| HFR − 幂等 | 2.548 ± 0.008 | 10.76 ± 0.03 | 6.85 ± 0.03 | 5.99 ± 0.02 |
| HFR − 预算 | 2.548 ± 0.009 | 10.75 ± 0.23 | 6.85 ± 0.03 | 5.98 ± 0.02 |
主结果可以概括为四点。
第一,HFR 的原始成功率与盲目重试接近,但安全与成本指标更好。 HFR 的 SR 为 86.25%,固定重试为 86.17%,差值 0.08 个百分点,且远小于种子间标准差(约 0.25–0.32 个百分点),因此不能声称 HFR 在原始成功率上“显著优于”盲目重试。HFR 的优势体现在:CSR 从 84.57% 提高到 86.25%,SCR 从 84.57% 提高到 92.07%,重复副作用从每千任务 17.47 次降为 0,CPS 从 2.986 降为 2.954。这说明在相同量级的成功率下,HFR 用更少的重复副作用和更少的无效尝试完成了任务。
第二,只重试或只降级都不足以覆盖混合故障。 仅指数重试的 SR 为 75.04%,主要卡在非重试类故障(过载、工具缺失、永久输入、安全拒绝);仅降级的 SR 为 64.79%,主要卡在“过早降级”带来的质量损失。HFR 相对二者分别提高 11.21 和 21.46 个百分点。这个结果与 F2D-9 的设计一致:不同故障需要不同动作,单一动作无法覆盖全部类别。
第三,验收器是本文模拟中贡献最大的组件。 去掉验收器后,SR 从 86.25% 降到 62.89%,下降 23.36 个百分点。原因是语义失败没有外部检查时会被当成成功接受,任务在“看起来完成”的状态下失败;这正是 3.2 节所说的静默失败。这个结果不应被解读为“验收器在所有真实系统中都贡献 23 个百分点”,但它说明:在存在语义失败和降级输出的场景中,验收不是可选项。
第四,幂等主要改善正确性,而不是原始成功率。 去掉幂等后,SR 保持 86.25%,但 CSR 从 86.25% 降到 84.66%,重复副作用从 0 升到每千任务 17.68 次。这是一个重要的区分:如果只看“任务是否完成”,幂等似乎没有价值;如果看“完成得是否干净”,幂等是不可替代的。
6.4 消融分析
表 14 把消融结果压缩成相对变化,便于观察每个组件的作用方向。
表 14 消融结果(相对完整 HFR 的变化)。负值表示下降。
| 消融项 | ΔSR | ΔCSR | ΔSCR | ΔCPS | ΔDUP/1000 | 解释 |
|---|---|---|---|---|---|---|
| HFR − 验收器 | −23.36 pp | −23.36 pp | −23.77 pp | +0.973 | 0.00 | 语义失败被静默接受 |
| HFR − 幂等 | 0.00 pp | −1.59 pp | −1.64 pp | 0.000 | +17.68 | 成功率不变,副作用重复 |
| HFR − 预算 | 0.00 pp | 0.00 pp | +0.01 pp | 0.000 | 0.00 | 独立故障下预算几乎不绑定 |
预算消融的结果是一个零结果,需要如实报告。去掉每任务预算后,SR 仍为 86.25%,SCR 为 92.08%,CPS 为 2.954;差异远小于种子波动。这说明在本文的独立故障模型里,每任务预算不是提升平均成功率的杠杆;它的价值在于给最坏情况下的尝试次数和成本提供一个上界(命题 1),而不是在平均意义上“优化”策略。预算的真正收益需要在多租户争用、相关性故障和重试风暴的场景中测量;本文的独立任务模拟没有建模这些外部性,因此不能据此宣称预算“无用”或“有害”。这是一个明确的评测边界。
验收器和幂等的消融则给出方向明确的结果:前者影响“是否发现失败”,后者影响“失败是否被安全地处理”。两者不是同一个维度,不能互相替代。
6.5 故障率敏感性
表 15 给出不同基础故障率下的成功率。该分析使用 seed=42、每个点 12,000 个任务,目的是观察趋势,而不是做精确的显著性检验。
表 15 故障率敏感性(seed=42,12,000 任务/点)。
| 基础故障率 | 不重试 | 仅指数重试 | 仅降级 | HFR |
|---|---|---|---|---|
| 0.05 | 45.18% | 87.33% | 80.81% | 92.73% |
| 0.10 | 33.08% | 80.16% | 72.85% | 89.18% |
| 0.16 | 22.88% | 72.86% | 61.82% | 85.02% |
| 0.24 | 13.53% | 63.93% | 47.66% | 79.51% |
| 0.32 | 7.12% | 55.09% | 34.46% | 73.51% |
三个趋势值得注意。第一,故障率越高,统一策略的优势越大。 在 5% 故障率下,HFR 比仅重试高 5.40 个百分点;在 32% 故障率下,高 18.42 个百分点。原因是非重试类故障在总故障中的比例随故障率上升而累积,单一重试策略的覆盖缺口被放大。第二,仅降级在低故障率下表现尚可,但在高故障率下快速退化。 这是因为它跳过了“先重试瞬时故障”的机会,过早消耗了降级路径和质量预算。第三,不重试的绝对成功率随故障率下降得最快。 这符合预期:没有恢复机制时,任务成功率近似为“所有步骤都不遇到不可恢复故障”的乘积。
这些趋势只描述模拟器中的行为。真实系统的故障率、故障相关性和模型能力分层可能不同;HFR-Bench 的目的就是用可复现的故障注入来测量这些差异,而不是用合成参数替代真实测量。
6.6 HFR-Bench:一个恢复能力基准的设计
本节提出 HFR-Bench 的设计。需要明确:本文没有在真实 LLM 上执行 HFR-Bench;下面给出的是任务源、故障注入矩阵、指标、统计协议和评分方式,真实结果统一标注为 。
6.6.1 任务源
HFR-Bench 不重新发明任务,而是复用现有智能体基准,把“正常执行”扩展为“故障下的执行”。候选任务源包括:
- SWE-bench Verified:真实代码仓库的 issue 修复,适合测量工具调用、文件编辑、测试验收和代码语义失败[4][3];
- τ-bench:工具—用户—策略交互,适合测量工具不可用、权限错误和多轮恢复[7];
- OSWorld:真实桌面环境,适合测量环境故障、进程崩溃和文件系统错误[6];
- WebArena:可复现网站环境,适合测量网络超时、页面变化和会话失效[5];
- AgentBench:多环境任务集,适合做跨环境的泛化测试[8];
- 企业自有任务:工单、审批、数据查询、运维操作等,适合测量真实副作用和合规要求。
每个任务源应提供:任务规范、成功判定、环境快照、工具清单、副作用等级和可注入故障点。对于没有现成成功判定的任务,应使用确定性测试、环境状态核对或人工标注;不能只用 LLM judge 作为唯一判定。
6.6.2 故障注入矩阵
HFR-Bench 的故障注入分为四层,如表 16 所示。每个故障点应有唯一的注入 ID、触发条件、持续时间和恢复方式,并记录在任务日志中,保证可重放。
表 16 故障注入矩阵。
| 层 | 故障 | 注入方式 | 观察点 |
|---|---|---|---|
| 模型 | 429 限流 | 在指定调用返回 429,可带 Retry-After | 是否正确等待、是否触发预算 |
| 模型 | 500/502/503 | 返回服务端错误 | 是否重试、是否熔断 |
| 模型 | 超时 | 延迟超过阈值或直接断开 | 是否区分读/写、是否对账 |
| 模型 | 过载 | 返回 529/overloaded,持续一段时间 | 是否降级模型 |
| 模型 | 上下文溢出 | 返回 context_length_exceeded | 是否压缩、是否丢失关键信息 |
| 模型 | malformed tool call | 返回不符合 schema 的工具调用 | 是否修复/重规划 |
| 工具 | 不可用 | 工具 5xx 或 unknown tool | 是否换等价工具 |
| 工具 | schema 不匹配 | 返回缺字段/类型错误 | 是否适配或修复 |
| 工具 | 权限拒绝 | 返回 401/403 | 是否停止而非重试 |
| 工具 | 结果未知 | 写操作超时 | 是否对账、是否重复副作用 |
| 环境 | 网络分区 | 断开特定域名/端口 | 是否熔断、是否降级 |
| 环境 | 磁盘满 | 写入失败 | 是否清理/升级 |
| 环境 | 进程崩溃 | 杀死工具进程 | 是否恢复/重试 |
| 语义 | 错误但合理 | 返回格式正确但内容错误 | 验收器是否捕获 |
| 语义 | 过期缓存 | 返回旧状态 | 是否核对环境状态 |
| 语义 | 提示注入 | 工具结果中包含恶意指令 | 是否隔离、是否拒绝执行 |
注入率应至少覆盖 5%、10%、20% 三档;每档应有独立随机种子和故障时间表。故障注入应遵循混沌工程的可复现、受控和最小爆炸半径原则[34]:在沙箱或测试账号中执行,记录注入 ID 和时间表,提供一键停止和回滚。为了测试相关性故障,还应提供“突发模式”:在某个时间窗口内,同一提供商或工具连续失败,观察熔断、预算和降级是否避免重试风暴。
6.6.3 对比策略
HFR-Bench 至少应比较以下策略:
NoRetry:失败即停止;FixedRetry:固定次数/固定延迟重试;ExpRetry:指数退避+抖动,无降级;DegradeOnly:首次失败即降级;HFR:完整策略;HFR − verifier、HFR − idempotency、HFR − budget、HFR − circuit breaker:消融;- 任务自带的默认恢复策略(如果有)。
所有策略应使用相同的任务、模型版本、工具版本和故障时间表;只改变恢复策略。模型版本和工具版本应记录在结果中,避免“策略差异”被版本漂移混淆。
6.6.4 指标
HFR-Bench 的主指标不是单一分数,而是一组向量:
- 任务成功率(SR):成功任务 / 总任务;
- 干净成功率(CSR):成功且无重复副作用 / 总任务;
- 安全完成率(SCR):(成功或升级)且无重复副作用 / 总任务;
- 每成功任务成本(CPS):总成本 / 成功任务数;
- 尾时延:p50/p95/p99,分别报告含升级和不含升级;
- 重复副作用率:每千任务重复副作用次数;
- 升级率:人工升级任务 / 总任务;
- 降级率与降级质量差:至少一次降级的任务比例,以及降级前后验收分数的差;
- 重试放大率:总尝试次数 / 逻辑步骤数;
- 恢复时间:从故障发生到任务恢复或升级的时延;
- 误接受率:验收器接受但真实失败的比例(需要人工抽检或外部 ground truth)。
这些指标应同时报告,不能只挑一个“综合分”。如果必须排序,建议使用 Pareto 前沿:在给定成本/时延预算下比较 SR/SCR,而不是把不同量纲的指标硬性加权。
6.6.5 统计协议
HFR-Bench 应采用配对比较:同一个任务、同一个故障时间表下,比较不同策略的结果。具体协议如下:
- 任务采样:每个任务源至少 200 个任务;高方差任务源增加到 500 个。任务采样应分层,覆盖不同难度、工具数和副作用等级。
- 随机种子:至少 3 个独立种子;每个种子生成独立的故障时间表。报告均值和 95% bootstrap 置信区间。
- 配对差异:对每个任务计算策略 A 与策略 B 的差异(成功/失败、成本差、时延差),再对差异做 bootstrap;不要只比较两个独立均值。
- 效应量:报告绝对差和相对差;对成功率使用百分点,对成本/时延使用相对变化。
- 人工抽检:随机抽取 5%–10% 的升级案例、验收失败案例和“成功但降级”案例,由人工复核;记录复核者间一致性。
- 预注册:任务集、故障率、模型版本、评价指标和停止规则应在实验前固定;不要在看到结果后调整指标。
- 日志发布:发布完整 trace、故障时间表、配置和脚本;如果涉及隐私或商业数据,发布脱敏版本和可复现的合成替代。
6.6.6 评分与报告
建议的报告结构是“三张表 + 一张图”:
- 表 A(能力):无故障条件下的 SR、成本、时延,确认策略没有损害基线能力;
- 表 B(恢复):故障条件下的 SR、CSR、SCR、CPS、p95;
- 表 C(安全):重复副作用、误接受率、升级率、降级质量差;
- 图 A(Pareto):成本/时延 vs 安全完成率的 Pareto 前沿,标出每个策略的位置。
这样的报告方式能回答三个问题:策略在正常条件下是否可用、在故障下是否能恢复、恢复是否安全。只报告“故障下成功率”会掩盖副作用;只报告“副作用为 0”会掩盖任务完不成;两者必须一起看。
6.7 真实系统实验协议(待执行)
本节给出真实 LLM/工具环境下的执行协议。由于本文没有执行该协议,表 17 中的所有结果字段均为 ;这不是省略,而是明确区分“设计”与“测量”。
表 17 真实系统实验计划(结果待填)。
| 任务源 | 计划任务数 | 故障率 | 模型/工具 | 对比策略 | SR | CSR | SCR | CPS | p95 | DUP/1000 |
|---|---|---|---|---|---|---|---|---|---|---|
| SWE-bench Verified | 200 | 5%/10%/20% | [TODO: 待定] | NoRetry / ExpRetry / HFR | ||||||
| τ-bench | 200 | 5%/10%/20% | [TODO: 待定] | NoRetry / DegradeOnly / HFR | ||||||
| OSWorld | 200 | 5%/10%/20% | [TODO: 待定] | NoRetry / ExpRetry / HFR | ||||||
| WebArena | 200 | 5%/10%/20% | [TODO: 待定] | NoRetry / DegradeOnly / HFR | ||||||
| 企业自有任务 | [TODO: 待定] |
执行该协议时,应至少记录以下元数据:模型名称和版本、工具版本、沙箱镜像、任务采样种子、故障时间表、每次尝试的输入/输出摘要、成本计算口径、时延测量点、人工复核记录。没有这些元数据,结果不可复现,也不应被用于跨系统比较。
6.8 效度威胁与局限
本节列出影响结论的主要威胁,以及本文已经采取或建议采取的缓解措施。
合成模拟的外部效度。 本文的模拟参数是假设,不是从真实系统估计的。故障独立同分布、延迟和成本线性可加、模型能力分层固定,这些假设都可能与真实系统不同。缓解措施是明确标注模拟性质、提供脚本和参数、把真实基准结果留作 TODO;不把模拟数字当作生产估计。
故障相关性。 真实故障往往具有相关性:一个提供商的故障会同时影响多个任务,重试风暴会让故障持续更久。本文的模拟只对单个任务内的故障做了粘性处理,没有建模跨任务的排队和拥塞。因此,预算和熔断的收益可能被低估;这也是 6.4 节预算消融出现零结果的原因之一。
验收器噪声。 本文把验收器简化为带检测率和误报率的随机过程,没有建模不同任务、不同 judge 的系统偏差。真实系统的验收器可能有领域偏差、提示注入漏洞和成本波动。缓解措施是分级验收、人工抽检和误接受率监控;不能把验收器当作绝对正确的 oracle。
基准污染与过拟合。 如果 HFR-Bench 复用公开任务,模型可能已经见过这些任务;如果只使用企业自有任务,又可能无法复现。建议同时报告公开任务和私有任务,并记录模型版本和训练数据截止时间。
成本口径。 不同提供商的计价方式不同(按 token、按调用、按时间),重试和降级的成本可能被低估或高估。应统一折算为货币成本,并同时报告 token 数和调用次数;不要把“相对成本”当作绝对成本。
模型版本漂移。 模型提供商会更新版本,行为可能变化。应固定模型快照(如果提供商支持),记录版本号,并在结果中注明日期。跨版本比较应谨慎。
安全与伦理。 故障注入可能触发真实副作用,尤其是写操作和外部服务。实验应在沙箱、测试账号和可回滚环境中进行;不要在真实生产数据上注入不可逆故障。对涉及个人数据的任务,应脱敏并遵守合规要求。
7. 讨论
7.1 为什么“先判错”比“多试几次”重要
重试是一种廉价的乐观主义:它假设失败是暂时的,下一次就会成功。这个假设在瞬时网络抖动上常常成立,但在智能体场景中并不普遍。权限缺失、工具不存在、输入非法、安全拒绝和语义错误都不会因为“再试一次”而改变;对它们重试,只是把一次可解释的失败变成一串难以审计的调用。更糟的是,盲目重试会与上游过载形成正反馈:上游越慢,客户端越重试;客户端越重试,上游越慢。Bronson 等人把这称为亚稳态故障[21],它不是简单的“负载高”,而是一个需要外部干预才能退出的坏状态。
“先判错”并不是要求分类器百分之百准确。分类器也会错,但它的错误可以被限制:高置信度的确定性错误走快速失败,低置信度的模糊错误走保守动作,写操作先对账,高关键度任务升级。与“所有错误都重试”相比,这种分层策略把不确定性放在了可审计的位置,而不是把它藏在一个统一的 while retries < N 循环里。
7.2 为什么重试与降级必须耦合
只重试的策略覆盖不了非重试类故障,只降级的策略则会过早放弃可恢复的瞬时故障。本文的模拟把这一点量化了:仅指数重试的成功率为 75.04%,仅降级为 64.79%,而把二者放进同一个控制回路后,成功率为 86.25%。这不是因为 HFR 的某个单点算法更聪明,而是因为它按故障类别选择了不同的动作:瞬时故障先重试,持续过载/工具缺失才降级,永久错误直接升级。
耦合的另一个好处是预算可以共享。重试预算和降级预算不是两套独立的计数器;降级本身也可能失败,也需要重试或继续降级。如果两个子系统各自维护预算,就会出现“重试预算用完了,但降级预算还没用”的不一致,或者“降级失败后又触发一轮重试”的循环。HFR 用同一个状态机和同一个预算管理器处理这两类动作,使“总尝试次数”和“总成本”有统一的上界。
7.3 为什么幂等是正确性边界
在只看向成功率的评测里,幂等似乎是一个“可选的优化”:去掉它,任务成功率不变。本文的模拟正是这样:HFR − 幂等 的 SR 仍然是 86.25%,与完整 HFR 相同。但干净成功率从 86.25% 降到 84.66%,重复副作用从 0 升到每千任务 17.68 次。对于支付、下单、发邮件、删文件这类操作,17.68/1000 的重复率不是“小概率事件”,而是不可接受的生产事故。
幂等的价值在于把“重试”从一个概率性的赌注变成一个有边界的操作。没有幂等键,重试的正确性依赖于“上次一定没成功”这个无法验证的假设;有了幂等键,重试的正确性依赖于工具的键去重语义,这是一个可以被测试、被审计、被契约约束的性质。对于不支持幂等键的工具,对账是第二道防线;对于既不能幂等也不能对账的 R3 操作,唯一安全的自动动作是不重试。
7.4 为什么验收器是降级的安全带
降级本身不是问题,静默降级才是问题。一个系统把任务从主模型切到小模型,用户可能只会觉得“答案变短了”;但如果小模型给出了错误的事实、遗漏了关键步骤、或者执行了不完整的操作,系统却没有发现,这就是静默失败。验收器的作用不是保证降级一定成功,而是保证“不成功的降级不会被当成成功”。
本文的模拟显示,去掉验收器会让成功率下降 23.36 个百分点,这是所有消融项中最大的。这个数字是合成设置下的结果,不应被直接外推到真实系统;但它揭示的机制是普遍的:当模型输出可能“看起来对但实际错”时,没有外部验收的 Harness 只是在猜。验收器也有代价:V2/V3 验收会增加成本和时延,验收器本身也可能有偏差。因此,验收应该分级:低风险任务用确定性检查,高风险任务用外部证据和人工复核;不能用一个统一的 LLM judge 包打天下。
7.5 适用边界
HFR 适合以下场景:
- API 模型 + 工具调用的智能体:错误信号相对可观测,工具有明确的成功/失败语义;
- 长程、多步骤任务:单步失败会累积,恢复策略的收益明显;
- 有副作用的业务操作:幂等、对账和升级的价值高;
- 可沙箱化、可回滚的环境:故障注入和降级实验可以安全执行;
- 多租户平台:预算、熔断和舱壁可以防止邻居噪声。
HFR 的效果在以下场景会受限:
- 不可观测的语义错误:如果验收器无法发现错误,HFR 只能依赖模型自评,而自评并不可靠[19];
- 不可逆、不可查询的外部副作用:R3 操作没有安全的自动重试路径,只能升级或补偿;
- 安全关键系统:医疗、金融、工业控制等场景不能仅靠自动降级,必须有人工复核和合规流程;
- 强对抗环境:提示注入、工具投毒和恶意输出可能操纵分类器、验收器或降级路径;HFR 需要额外的安全层,不能把恢复策略当作安全边界;
- 高度相关的故障:如果所有提供商同时故障,降级阶梯可能没有可用层级;此时熔断、限流和人工接管比“继续重试”更重要。
7.6 伦理、安全与治理
恢复机制本身也可能带来伦理和安全风险。第一,重试可能放大有害动作:如果一个写操作本身不应该执行,重试只会让它更可能被执行;HFR 必须在动作执行前做权限和安全检查,而不是在执行后靠重试“修正”。第二,降级可能绕过安全策略:一个模型因为安全策略拒绝,不能通过切换到更弱的模型来绕过;这不是恢复,而是规避。第三,自动化可能削弱人类监督:高关键度任务的升级路径必须真实可用,不能只是一个日志字段。第四,审计与隐私:恢复日志可能包含用户数据、工具参数和模型输出;需要脱敏、访问控制和保留策略。
治理上,建议把 HFR 的决策纳入现有的变更管理和审计体系:分类器规则、预算阈值、降级阶梯和验收标准都应有版本号和审批记录;每次策略变更都应经过影子模式和金丝雀验证;重复副作用、误接受率和升级率应作为核心 SLO 指标,而不是事后才看的调试信息。
7.7 工程落地清单
下面给出一个可执行的十条清单,按优先级排序:
- 建立故障分类表。 先把团队遇到的错误按 F2D-9 或类似分类整理,标注可重试性、副作用风险和建议动作;不要从“重试几次”开始。
- 在第一次调用前生成幂等键。 不要等失败后再补键;键必须持久化,并在重试时复用。
- 给重试设预算。 至少设置每步和每任务预算;多租户系统再加租户预算和并发配额。
- 使用 full-jitter 退避。 遵守
Retry-After;不要用固定延迟或同步重试。 - 对写操作先对账。 超时/结果未知时,先查账本和外部状态;只有确认未提交才重试。
- 建立降级阶梯。 从上下文压缩、同层替代、能力降档到人工接管;每一级都要有质量下限和验收级别。
- 分级验收。 低风险用确定性检查,高风险用外部证据和人工复核;不要只依赖模型自评。
- 加熔断和舱壁。 按提供商、模型、工具和租户隔离;熔断打开时不要再重试同一上游。
- 记录决策而不是只记录异常。 每次恢复动作都要有类别、理由、预算、降级级别和验收结果。
- 用故障注入做基准。 在沙箱中注入可复现故障,同时报告成功率、干净成功率、安全完成率、成本、尾时延、重复副作用和升级率。
8. 结论
本文研究了 Harness 在智能体失败时的重试与降级问题。本文的出发点是:智能体的可靠性不是模型单独的属性,而是模型、Harness 和环境共同作用的结果;重试和降级不是两个独立开关,而是同一套恢复控制面的两种动作。本文提出了 F2D-9 故障分类、HFR 控制器和 HFR-Bench 评测协议,给出了状态机、配置模型、错误映射、复杂度分析和四条条件性安全性质。
在明确标注为合成故障注入的模拟中,HFR 的任务成功率为 86.25%,与无幂等的盲目重试(86.17%)接近;但 HFR 的干净成功率更高(86.25% 对 84.57%),安全完成率更高(92.07% 对 84.57%),重复副作用从每千任务 17.47 次降为 0,非升级 p95 从 7.92 秒降为 6.85 秒;相对仅指数重试和仅降级,任务成功率分别提高 11.21 和 21.46 个百分点。消融显示,验收器是本文模拟中贡献最大的组件,幂等主要改善副作用安全,预算在独立故障模型下几乎没有平均收益,主要提供最坏情况下的尝试次数上界。上述结论只适用于本文的合成设置,不构成对真实模型或生产系统的测量。
未来工作有四个具体方向。第一,执行真实基准:在 SWE-bench、τ-bench、OSWorld、WebArena 和 AgentBench 上运行 HFR-Bench,报告完整指标和置信区间,而不是只报告合成模拟。第二,学习恢复策略:用真实 trace 训练上下文 bandit 或轻量策略模型,在预算和风险约束下选择重试/降级动作,但保留规则作为安全兜底。第三,形式化安全条件:把幂等、对账和验收的假设写成可测试的契约,用模型检查或属性测试验证关键路径。第四,多 Agent 恢复:研究多个 Agent 共享工具和预算时的恢复协议,避免单个 Agent 的重试风暴影响整个编排系统。
参考文献
[1] Yao S, Zhao J, Yu D, et al. ReAct: Synergizing Reasoning and Acting in Language Models[C]//International Conference on Learning Representations (ICLR). 2023. arXiv:2210.03629.
[2] Shinn N, Cassano F, Gopinath A, et al. Reflexion: Language Agents with Verbal Reinforcement Learning[C]//Advances in Neural Information Processing Systems (NeurIPS). 2023. arXiv:2303.11366.
[3] Yang J, Jimenez C E, Wettig A, et al. SWE-agent: Agent-Computer Interfaces Enable Automated Software Engineering[C]//Advances in Neural Information Processing Systems (NeurIPS). 2024. arXiv:2405.15793.
[4] Jimenez C E, Yang J, Wettig A, et al. SWE-bench: Can Language Models Resolve Real-World GitHub Issues?[C]//International Conference on Learning Representations (ICLR). 2024. arXiv:2310.06770.
[5] Zhou S, Xu F F, Zhu H, et al. WebArena: A Realistic Web Environment for Building Autonomous Agents[C]//International Conference on Learning Representations (ICLR). 2024. arXiv:2307.13854.
[6] Xie T, Zhang D, Chen J, et al. OSWorld: Benchmarking Multimodal Agents for Open-Ended Tasks in Real Computer Environments[C]//Advances in Neural Information Processing Systems (NeurIPS) Datasets and Benchmarks Track. 2024. arXiv:2404.07972.
[7] Yao S, Shinn N, Razavi P, Narasimhan K. τ-bench: A Benchmark for Tool-Agent-User Interaction in Real-World Domains[J/OL]. arXiv:2406.12045, 2024.
[8] Liu X, Yu H, Zhang H, et al. AgentBench: Evaluating LLMs as Agents[C]//International Conference on Learning Representations (ICLR). 2024. arXiv:2308.03688.
[9] Wu Q, Bansal G, Zhang J, et al. AutoGen: Enabling Next-Gen LLM Applications via Multi-Agent Conversation[J/OL]. arXiv:2308.08155, 2023.
[10] Hong S, Zhuge M, Chen J, et al. MetaGPT: Meta Programming for a Multi-Agent Collaborative Framework[C]//International Conference on Learning Representations (ICLR). 2024. arXiv:2308.00352.
[11] Fourney A, Bansal G, Mozannar H, et al. Magentic-One: A Generalist Multi-Agent System for Solving Complex Tasks[J/OL]. arXiv:2411.04468, 2024.
[12] Cemri M, Pan M Z, Yang S, et al. Why Do Multi-Agent LLM Systems Fail?[J/OL]. arXiv:2503.13657, 2025.
[13] Kapoor S, Stroebl B, Kirgis P, et al. Holistic Agent Leaderboard: The Missing Infrastructure for AI Agent Evaluation[J/OL]. arXiv:2510.11977, 2025.
[14] Wang Z, Li J, Zhou Q, et al. A Survey on AgentOps: Categorization, Challenges, and Future Directions[J/OL]. arXiv:2508.02121, 2025.
[15] Chen L, Zaharia M, Zou J. FrugalGPT: How to Use Large Language Models While Reducing Cost and Improving Performance[J/OL]. arXiv:2305.05176, 2023.
[16] Aggarwal P, Madaan A, Anand A, et al. AutoMix: Automatically Mixing Language Models[C]//Advances in Neural Information Processing Systems (NeurIPS). 2024. arXiv:2310.12963.
[17] Ong I, Almahairi A, Wu V, et al. RouteLLM: Learning to Route LLMs with Preference Data[J/OL]. arXiv:2406.18665, 2024.
[18] Madaan A, Tandon N, Gupta P, et al. Self-Refine: Iterative Refinement with Self-Feedback[C]//Advances in Neural Information Processing Systems (NeurIPS). 2023. arXiv:2303.17651.
[19] Huang J, Chen X, Mishra S, et al. Large Language Models Cannot Self-Correct Reasoning Yet[C]//International Conference on Learning Representations (ICLR). 2024. arXiv:2310.01798.
[20] Dean J, Barroso L A. The Tail at Scale[J]. Communications of the ACM, 2013, 56(2): 74–80.
[21] Bronson N, Aghayev A, Charapko A, Zhu T. Metastable Failures in Distributed Systems[C]//Workshop on Hot Topics in Operating Systems (HotOS). 2021.
[22] Garcia-Molina H, Salem K. Sagas[C]//Proceedings of the 1987 ACM SIGMOD International Conference on Management of Data. 1987.
[23] Helland P. Idempotence Is Not a Medical Condition[J]. ACM Queue, 2012, 10(4).
[24] Gray C, Cheriton D. Leases: An Efficient Fault-Tolerant Mechanism for Distributed File Cache Consistency[C]//ACM Symposium on Operating Systems Principles (SOSP). 1989.
[25] Saltzer J H, Reed D P, Clark D D. End-to-End Arguments in System Design[J]. ACM Transactions on Computer Systems, 1984, 2(4): 277–288.
[26] Beyer B, Jones C, Petoff J, Murphy N R. Site Reliability Engineering: How Google Runs Production Systems[M]. O’Reilly Media, 2016.
[27] Nygard M T. Release It! Design and Deploy Production-Ready Software[M]. 2nd ed. Pragmatic Bookshelf, 2018.
[28] Amazon Web Services. Timeouts, retries, and backoff with jitter[EB/OL]. AWS Builders Library. https://aws.amazon.com/builders-library/timeouts-retries-and-backoff-with-jitter/ (访问日期:2026-10-19).
[29] Fielding R, Nottingham M, Reschke J. HTTP Semantics[S]. RFC 9110, IETF, 2022. https://www.rfc-editor.org/rfc/rfc9110.
[30] Temporal Technologies. Temporal Documentation[EB/OL]. https://docs.temporal.io/ (访问日期:2026-10-19).
[31] Amazon Web Services. AWS Step Functions Developer Guide[EB/OL]. https://docs.aws.amazon.com/step-functions/latest/dg/welcome.html (访问日期:2026-10-19).
[32] Microsoft. Azure Durable Functions overview[EB/OL]. https://learn.microsoft.com/en-us/azure/azure-functions/durable/durable-functions-overview (访问日期:2026-10-19).
[33] OpenTelemetry Authors. OpenTelemetry Documentation[EB/OL]. https://opentelemetry.io/docs/ (访问日期:2026-10-19).
[34] Principles of Chaos Engineering[EB/OL]. https://principlesofchaos.org/ (访问日期:2026-10-19).
[35] Kleppmann M. How to do distributed locking[EB/OL]. 2016. https://martin.kleppmann.com/2016/02/08/how-to-do-distributed-locking.html (访问日期:2026-10-19).
[36] Kubernetes. Leases[EB/OL]. https://kubernetes.io/docs/concepts/architecture/leases/ (访问日期:2026-10-19).
[37] Anthropic. Building effective agents[EB/OL]. 2024. https://www.anthropic.com/engineering/building-effective-agents (访问日期:2026-10-19).
[38] OpenAI. A practical guide to building agents[EB/OL]. 2025. https://cdn.openai.com/business-guides-and-resources/a-practical-guide-to-building-agents.pdf (访问日期:2026-10-19).
附录
附录 A:缩写与补充符号
| 缩写/符号 | 全称/含义 |
|---|---|
| Harness | 把模型变成可执行智能体的运行时层 |
| HFR | Harness Failure Recovery,本文提出的失败恢复方法 |
| F2D-9 | Fault-to-Decision,九类故障到动作的映射 |
| SR | Task Success Rate,任务成功率 |
| CSR | Clean Success Rate,干净成功率 |
| SCR | Safe Completion Rate,安全完成率 |
| CPS | Cost per Success,每成功任务成本 |
| DUP | Duplicate side effects,重复副作用 |
| ESC | Escalation rate,人工升级率 |
| DEG | Degradation rate,降级率 |
| R0–R3 | 工具副作用能力分级:只读、幂等写、可查询非幂等写、不可逆 |
| V0–V3 | 验收级别:传输、确定性、语义、权威/人工 |
| B s , B t , B tenant B_s, B_t, B_{\text{tenant}} Bs,Bt,Btenant | 每步、每任务、每租户重试预算 |
| d 0 , d max d_0, d_{\max} d0,dmax | 基础退避、退避上限 |
| α , β \alpha, \beta α,β | 验收器的误接受率、误拒绝率 |
附录 B:合成模拟器的复现说明
本文的合成模拟器只依赖 Python 标准库,建议使用 Python 3.9 或更高版本。运行方式:
cd ~/paper-writer/papers/20261019
python3 harness_retry_degrade_sim.py
python3 harness_retry_degrade_incident_sensitivity.py
第一条命令生成主结果和故障率敏感性:
harness_retry_degrade_sim_results.jsonharness_retry_degrade_sim_results.md
第二条命令生成相关性故障的附加敏感性:
harness_retry_degrade_incident_sensitivity.jsonharness_retry_degrade_incident_sensitivity.md
主模拟器的关键参数如表 B1 所示。所有参数都是建模假设,不是从真实系统测量得到的。
表 B1 合成模拟器参数。
| 参数 | 值 | 说明 |
|---|---|---|
| 基础故障率 p fault p_{\text{fault}} pfault | 0.14 | 每次尝试注入故障的概率 |
| 每个种子任务数 | 20,000 | 主结果 |
| 种子数 | 10 | 主结果 |
| 每任务步数 | 4–8 | 加权采样 |
| 任务关键度 | low 35% / medium 45% / high 20% | 加权采样 |
| 模型调用/只读工具/写工具 | 35% / 45% / 20% | 每步类型 |
| 主模型成功率/成本/时延 | 0.94 / 1.00 / 1.20 s | 基准假设 |
| 备用模型成功率/成本/时延 | 0.86 / 0.45 / 0.65 s | 基准假设 |
| 廉价模型成功率/成本/时延 | 0.74 / 0.18 / 0.35 s | 基准假设 |
| 主工具成功率/成本/时延 | 0.95 / 0.10 / 0.40 s | 基准假设 |
| 替代工具成功率/成本/时延 | 0.86 / 0.08 / 0.30 s | 基准假设 |
| 缓存兜底成功率/成本/时延 | 0.55 / 0.00 / 0.05 s | 基准假设 |
| 退避 base/cap | 0.20 s / 2.00 s | full jitter |
| 每步/每任务重试预算 | 3 / 10 | HFR |
| 非重试故障粘性 | 0.90 | 同一逻辑步骤内 |
| 验收器检测率(语义/工具) | 0.90 / 0.98 | 建模假设 |
| 验收器误报率 | 0.02 | 建模假设 |
| 人工升级时延/成本 | 10.0 s / 2.00 | 建模假设 |
模拟器的随机性来自固定的 random.Random(seed),因此相同脚本和相同 Python 版本应产生相同结果。不同 Python 版本的随机数实现通常稳定,但为了严格复现,建议记录 Python 版本和脚本哈希。
附录 C:相关性故障的附加敏感性
表 C1 给出在提高提供商/工具事件率时的附加结果。该实验使用 5 个随机种子、每个点 12,000 个任务、 p fault = 0.20 p_{\text{fault}}=0.20 pfault=0.20,工具事件率为提供商事件率的 0.6 倍。
表 C1 相关性故障敏感性(5 seeds × 12,000 tasks/点; p fault = 0.20 p_{\text{fault}}=0.20 pfault=0.20)。
| 事件率 | 策略 | 成功率 | 平均成本 | 每成功任务成本 | 平均尝试/任务 |
|---|---|---|---|---|---|
| 0.10 | HFR | 78.19% | 2.558 | 3.272 | 5.96 |
| 0.10 | HFR − 预算 | 78.21% | 2.558 | 3.271 | 5.96 |
| 0.25 | HFR | 69.94% | 2.552 | 3.648 | 6.05 |
| 0.25 | HFR − 预算 | 70.01% | 2.552 | 3.646 | 6.05 |
| 0.40 | HFR | 61.75% | 2.537 | 4.109 | 6.12 |
| 0.40 | HFR − 预算 | 61.90% | 2.537 | 4.099 | 6.12 |
这组附加结果进一步支持 6.4 节的结论:在本文的故障模型里,去掉每任务预算几乎没有改变成功率或成本;预算的作用是给出尝试次数的上界,而不是在平均意义上提高成功率。事件率从 10% 提高到 40% 时,HFR 的绝对成功率从 78.19% 降到 61.75%,说明相关性故障会显著压缩恢复空间;真实系统应把熔断、舱壁和人工接管作为预算之外的独立保护层。
附录 D:命题证明补充
命题 1 的补充。 设任务有 n n n 个逻辑步骤,第 i i i 步的尝试次数为 a i a_i ai。每步预算 B s B_s Bs 给出 a i ≤ 1 + B s a_i \le 1+B_s ai≤1+Bs,因此 ∑ i a i ≤ n ( 1 + B s ) \sum_i a_i \le n(1+B_s) ∑iai≤n(1+Bs)。每任务预算 B t B_t Bt 限制额外重试总数,因此 ∑ i ( a i − 1 ) ≤ B t \sum_i (a_i-1) \le B_t ∑i(ai−1)≤Bt,即 ∑ i a i ≤ n + B t \sum_i a_i \le n+B_t ∑iai≤n+Bt。两者同时成立时取最小值。注意,这个上界假设预算检查在每次重试前原子执行;如果预算检查和扣减不是原子的,实际尝试次数可能略高于上界。
命题 2 的补充。 设逻辑动作 a a a 的幂等键为 k ( a ) k(a) k(a),工具 F F F 对每个键最多提交一次副作用。对任意尝试序列 a ( 1 ) , a ( 2 ) , … a^{(1)}, a^{(2)}, \ldots a(1),a(2),…,所有尝试使用同一个 k ( a ) k(a) k(a),因此 F F F 的提交次数 c ( a ) ≤ 1 c(a) \le 1 c(a)≤1。如果不同逻辑动作的键不同,则 ∑ a c ( a ) ≤ \sum_a c(a) \le ∑ac(a)≤ 逻辑动作数。证明的关键假设是“工具正确实现键去重”;如果工具在内部重试或异步写入时忽略键,命题不成立。因此,HFR 在接入新工具时必须做幂等契约测试,而不是假设键一定生效。
命题 3 的补充。 设对账查询
Q
(
k
)
Q(k)
Q(k) 返回 COMMITTED、ABSENT 或 UNKNOWN,并且对已提交的键不会返回 ABSENT(线性化/完整性假设)。HFR 的策略是:COMMITTED 不重试,ABSENT 重试,UNKNOWN 升级。因此,只有在“实际未提交”或“实际已提交但查询错误地返回 ABSENT”时才会重试;前者安全,后者违反完整性假设。所以,在假设成立时不会重复提交。证明的边界是查询的完整性和一致性;如果外部系统是最终一致的,查询可能短暂返回 ABSENT,这时需要等待或升级,而不是立即重试。
命题 4 的补充。 设验收器 V V V 满足: V V V 接受蕴含 Q ≥ q min Q \ge q_{\min} Q≥qmin(无 false accept)。HFR 只接受 V V V 通过的输出,因此被接受的输出满足 Q ≥ q min Q \ge q_{\min} Q≥qmin。这个命题把质量保证的责任放在验收器上;如果 V V V 有 false accept,命题不成立。工程上应监控误接受率,并对高风险任务使用 V2/V3 验收。
附录 E:HFR-Bench 任务记录模板
为了让基准结果可复现,建议为每个任务记录以下字段。字段可以用 JSONL 或数据库表存储;敏感字段应脱敏。
| 字段 | 类型 | 说明 |
|---|---|---|
task_id | string | 任务唯一标识 |
suite | string | SWE-bench / τ-bench / OSWorld / WebArena / AgentBench / 企业自有 |
task_spec | string | 任务描述与成功规范 |
criticality | enum | low / medium / high |
quality_floor | float | 质量下限 |
deadline_s | float | 截止时间 |
tools | array | 工具清单及副作用等级 R0–R3 |
fault_schedule | array | 注入 ID、时间、类型、持续时间、恢复方式 |
policy | string | 对比策略 |
attempts | array | 每次尝试的动作、结果、成本、时延 |
degradation | object | 级别、原因、替代对象、质量估计 |
verification | object | 验收级别、结果、失败原因 |
side_effects | array | 已提交副作用、幂等键、对账结果 |
escalation | object | 是否升级、原因、证据包 |
outcome | object | SR/CSR/SCR、成本、时延、重复副作用 |
metadata | object | 模型版本、工具版本、沙箱镜像、脚本哈希 |
附录 F:真实基准执行检查清单
在执行 HFR-Bench 的真实实验前,逐项确认:
- 任务集、成功判定和采样种子已固定并记录;
- 模型/工具版本已固定,训练数据截止时间已知;
- 故障注入在沙箱/测试账号中执行,具有一键停止和回滚;
- 每个故障注入有唯一 ID、时间表和恢复方式;
- 对比策略共享同一套任务、模型、工具和故障时间表;
- 指标同时包含 SR、CSR、SCR、CPS、p95/p99、DUP、ESC、DEG;
- 使用配对比较和 bootstrap 置信区间,而不是只报告均值;
- 对升级、验收失败和“成功但降级”案例做人工抽检;
- 记录并脱敏日志,发布可复现的配置和脚本;
- 在结果中明确区分“合成模拟”“真实实验”和“待补数据”。
数据与代码可用性说明。 本文的合成模拟脚本和结果随论文放在同一目录:harness_retry_degrade_sim.py、harness_retry_degrade_sim_results.json、harness_retry_degrade_sim_results.md、harness_retry_degrade_incident_sensitivity.py、harness_retry_degrade_incident_sensitivity.json。真实 LLM/工具实验尚未执行,相关表格中的 表示待补,不表示已有结果。
本文提出HFR(Harness Failure Recovery)框架,面向大语言模型智能体的运行时可靠性问题,统一建模失败重试与降级决策。HFR包含故障分类器、重试控制器、幂等账本、降级阶梯、分级验收器、熔断舱壁及可观测性模块,强调故障语义化分类、预算约束、副作用防护与结果验证。在合成故障注入实验中,HFR显著降低重复副作用(归零)、提升安全完成率(92.07% vs 84.57%),并优化尾延迟。配套提出HFR-Bench基准协议,支持对任务成功率、干净成功率、安全完成率、重复副作用等多维指标的可复现评测。

521

被折叠的 条评论
为什么被折叠?



