Harness Engineering 笔记(三):工具调用与错误恢复——Architectural Constraints 的运行时体现

0 阅读4分钟

系列第三篇。在 Harness Engineering 的官方三支柱中,Architectural Constraints 强调"用确定性规则强制约束 Agent 行为"。在运行时层面,这最集中地体现在工具调用的容错机制上——当 Agent 出错时,Harness 用确定性的代码逻辑来防止错误扩散。

为什么错误恢复是最重要的课题?

因为模型的输出是有概率性的,实际一个在生产环境跑的 Agent,大概率每几轮就会遇到一次某种类型的失败,当遇到失败的时候,怎么去处理失败进行错误恢复很重要,Agent 的可靠性,80% 取决于它怎么处理失败,而不是怎么处理成功。

通常来说,有下面几类常见的失败,从轻到重,处理策略完全不同:

  • L1 瞬时错误(最常见):网络超时、API 限流 429、服务不可用 503。几秒后重试大概率成功。

  • L2 参数错误(常见):LLM 传了不存在的工具名、参数类型不对。需要错误回注让 LLM 自我修正。

  • L3 工具执行失败(偶发):文件不存在、权限不足、SQL 语法错误。工具可用但执行失败。

  • L4 逻辑死循环(最隐蔽):没有技术错误,但 LLM 反复用相似关键词搜索、反复生成相同代码。需要有手段能够检测出模型的执行是否会陷入死循环了,可以工程上介入进行修正。

  • L5 LLM 自身故障(罕见):服务崩溃、返回空内容、输出格式完全异常。

针对上面提到的几种常见的错误情况,有四种常见的容错策略:

  1. 策略一:指数退避重试(对付 L1)

每次重试等待时间翻倍 + 随机抖动,加上随机抖动可以避免"重试风暴",即一下子所有的流量都一起重试了。关键:区分可重试错误(超时)和不可重试错误(参数错)。 这本身就是一种 Architectural Constraint——确定性地区分错误类型。参考代码:

class RetryPolicy:
    def execute(self, func):
        for attempt in range(self.max_retries + 1):
            try:
                return func()
            except (TimeoutError, RateLimitError): // 超时或者限流等网络抖动
                delay = min(base * (2 ** attempt) + random.uniform(0, 1), max_delay) // 加上一些随机抖动的超时时间
                time.sleep(delay)
            except InvalidArgError:
                raise  # 不可重试,立即失败
  1. 策略二:错误回注(对付 L2、L3)

把错误信息当作 tool result 回传给 LLM,让它自己修复。好的错误消息 = "出了什么错 + 可以怎么修":

# 差的回注
"Error: File not found"

# 好的回注
"文件 /data/report.csv 不存在。建议用 list_files('/data/') 查看可用文件。"

LLM 看到后者,下一步就会调 list_files() 自己找到正确路径。错误信息的质量直接决定了 Agent 的自愈能力。

  1. 策略三:循环检测(对付 L4)

三种检测方法:相似调用计数、输出相似度检测、定期进展审计。

检测到后不是直接终止,而是注入干预消息——要明确告诉 LLM "基于已有结果行动"而不只是"重新思考"。

  1. 策略四:优雅降级(对付 L5)

逐步降低服务质量但不崩溃。永远不返回空结果——部分结果 + 诚实解释永远比裸错误好。

Claude Code 的实际做法

我们在使用 Claude Code 的时候实际上很少看到错误——其实这并不是不出错,是大部分错误在底层被自动处理了:

首先在我们看不到的地方,Claude Code 的 API 会进行重试(11 次指数退避),命令失败后模型自己换路径、测试失败后自己修复再跑。

在我们能看到的地方,Claude Code 支持了 Checkpoint/Rewind(改崩了可以回退)、fix-the-fix spiral 需要人工叫停。

核心启示: 最好的错误恢复是让用户感知不到错误发生过。但自动化有极限——当模型陷入"越改越烂"的循环时,最有效的干预者还是人类。好的 Harness 要让人类容易介入

这和 OpenAI 的 Harness Engineering 理念一致:他们把 Linter 的错误信息设计为直接注入 Agent 上下文的修复指令——反馈循环是 Harness 的核心机制。

小结

  1. 失败是常态,不是异常——分层防御是关键
  2. 五类失败,四种策略——重试、回注、循环检测、降级各司其职
  3. 错误信息是工程产品——它的质量直接决定 Agent 的自愈能力
  4. 容错机制是 Architectural Constraints 在运行时的体现——用确定性代码防止 Agent 的错误无限扩散

下一篇讲可观测性——怎么"看见" Agent 在做什么。