如何实现 Claude Code 和 Codex 等 Agent CLI 的自动重试自动重试这个词看着像是个小开关真落到工程现场里完全不是那么回事。全民制作人们大家好我是 HagiCode 制作人俞坤。今天这篇我们不聊空话就聊 Claude Code、Codex 这类 Agent CLI 的自动重试到底该怎么做才能既接得住异常又不把系统带进无休止的重复执行里。背景如果你最近也在折腾 AI 编程那这类问题你大概率已经碰到过了任务不是一上来就挂而是跑到一半断掉。这事儿放到普通 HTTP 请求里很多时候就是重发一下顶多补个指数退避。可是 Agent CLI 不一样。Claude Code、Codex 这类工具通常是流式执行的输出是一段一段往外推过程中还会绑定 thread、session 或 resume token。换句话说它不是“这一请求失败了没有”而是前面已经吐出来的内容还算不算数当前上下文还能不能接着跑这次失败该不该自动恢复如果要恢复多久再试试的时候发什么原上下文还要不要复用很多团队第一次做这里都会下意识写一个最朴素的版本报错了就再试一次。你说得非常正确这个想法很自然可是真进项目里问题就一个接一个冒出来了。有些错误明明是暂时故障却被当成最终失败有些错误根本不值得重试却被系统反复重放有 thread 的请求和没有 thread 的请求被一把梭地一视同仁退避策略没边界后台请求自己把自己打爆HagiCode 在接多种 Agent CLI 的过程中也踩过这些坑。尤其是 Codex 这一侧最初暴露出来的问题就是某类 reconnect 报文没有被识别成可重试终态结果原本已有的恢复机制根本没机会生效。说白了不是系统没有自动重试而是系统没把“这次值得重试”认出来。所以这篇文章想讲的核心点很明确自动重试不是一个按钮而是一套分层设计。关于 HagiCode本文分享的方案来自我们在 HagiCode (https://hagicode.com) 项目里的真实实践。HagiCode 要做的事情不是把某一个模型接上就完事而是把多种 Agent CLI 的流式消息、工具调用、失败恢复、会话上下文统一成一套能长期维护的执行模型。我平时最关心的事情之一就是怎么让 AI 编程这件事真正落到工程现场。写 Demo 不难难的是把 Demo 变成团队真的愿意长期使用的东西。HagiCode 之所以认真做自动重试不是因为这个功能看起来高级而是因为长链路、流式、可续跑的 CLI 执行如果接不稳用户看到的就不是智能助手而是一个动不动半路掉线的命令包装器。如果你想先看看项目入口这里先放两个GitHub: github.com/HagiCode-org/site (https://github.com/HagiCode-org/site)官网: hagicode.com (https://hagicode.com)再往前走一步讲HagiCode 现在也已经上架 Steam 了有 Steam 的朋友可以先加个愿望单Steam 商店页加入愿望单 / 查看详情 (https://store.steampowered.com/app/4625540/Hagicode/)为什么 Agent CLI 的自动重试比普通重试更难这个问题提得很实在我们直接上结论Agent CLI 的自动重试难点不在“隔几秒再试一次”而在“还能不能在原上下文里继续”。你可以把它理解成一次长对话。普通 API 重试更像电话占线再拨一遍而 Agent CLI 重试更像对方刚讲到一半信号断了你得先判断要不要回拨回拨以后要不要从头说对方还记不记得刚刚聊到哪。谁说这两者是一回事呢它们压根不是一个工程问题。具体看有四个难点最典型。1. 它是流式的一旦输出已经发给用户你就不能像处理普通请求那样把失败偷偷吞掉然后悄悄重来。因为前面那部分内容已经被看到了再次重放时如果策略不对前端很容易看到重复文本、错乱状态工具调用生命周期也会一起乱套。这波不是玄学是工程。2. 它通常绑定会话上下文Codex 这类 provider 会绑定 threadClaude Code 一类实现也会有 continuation target 或等价的续跑上下文。真正能自动重试的前提不只是“这个错误长得像暂时故障”还包括“这次执行还有没有继续下去的载体”。3. 它不是所有错误都值得重试网络抖动、SSE idle timeout、上游临时故障这些通常可以试一试。可如果你遇到的是认证失败、上下文已经丢了或者 provider 根本没有 resume 能力那继续重试多数不是恢复而是在制造噪音。4. 它需要边界无限自动重试几乎总是错的。技术趋势可以热闹一阵子工程规律往往会稳定很多年其中一条就是失败恢复一定要有边界。系统必须知道自己最多试几次、每次隔多久、什么时候该停手承认这回真不行了。也正因为这几个特点HagiCode 最后没有把自动重试写成某个 provider 里的几行try/catch而是把它提炼成一层共享能力。说到底工程问题还是要回到工程方法里解决。HagiCode 的做法把重试从 Provider 里拿出来HagiCode 当前这套真实实现可以压缩成一句话共享层统一管理重试流程具体 Provider 只负责回答两个问题这个终态值不值得重试当前上下文还能不能继续这件事不复杂可是很关键。因为一旦把职责切开Claude Code、Codex甚至其他 Agent CLI 都能复用同一个骨架。模型会说工具会变工作流会升级但工程上的基本盘一直都在那里。第一层用统一协调器管理重试循环项目中的核心实现片段大概是下面这样csharp internal staticclassProviderErrorAutoRetryCoordinator { publicstaticasync IAsyncEnumerableCliMessage ExecuteAsync( string prompt, ProviderErrorAutoRetrySettings? settings, Funcstring, IAsyncEnumerableCliMessage executeAttemptAsync, Funcbool canRetryInSameContext, FuncTimeSpan, CancellationToken, Task delayAsync, FuncCliMessage, bool isRetryableTerminalMessage, [EnumeratorCancellation] CancellationToken cancellationToken) { var normalizedSettings ProviderErrorAutoRetrySettings.Normalize(settings); var retrySchedule normalizedSettings.Enabled ? normalizedSettings.GetRetrySchedule() : []; for (var attempt 0; ; attempt) { var attemptPrompt attempt 0 ? prompt : ProviderErrorAutoRetrySettings.ContinuationPrompt; CliMessage? terminalFailure null; awaitforeach (var message inexecuteAttemptAsync(attemptPrompt) .WithCancellation(cancellationToken)) { if (isRetryableTerminalMessage(message)) { terminalFailure message; break; } yieldreturn message; } if (terminalFailure isnull) { yieldbreak; } if (attempt retrySchedule.Count || !canRetryInSameContext()) { yieldreturn terminalFailure; yieldbreak; } await delayAsync(retrySchedule[attempt], cancellationToken); } } }这段代码干的事情其实非常朴素但很有力。中间失败先不直接透传协调器先判断能不能恢复只有重试预算耗尽最终失败才真正回到上层第二轮开始不再发送原始 prompt而是统一发送 continuation prompt这也就是为什么我前面一直强调自动重试不是简单的“再请求一次”。它不是在补一个异常分支而是在管理一条执行生命周其。听起来有点像产品经理但工程上确实如此。第二层把重试策略快照化另一个很容易被忽略的问题是谁来决定这次请求是否开启自动重试HagiCode 的答案是不要依赖某个“此刻的全局配置”而是把策略做成 snapshot跟着这次请求一起走。这样一来会话排队、消息持久化、执行转发、provider 适配都不会把策略弄丢。一次成功不叫体系持续成功才叫体系。核心结构可以简化成这样csharp public sealedrecordProviderErrorAutoRetrySnapshot { publicconststring DefaultStrategy default; publicbool Enabled { get; init; } publicstring Strategy { get; init; } DefaultStrategy; publicstatic ProviderErrorAutoRetrySnapshot Normalize(bool? enabled, string? strategy) { returnnew ProviderErrorAutoRetrySnapshot { Enabled enabled ?? true, Strategy string.IsNullOrWhiteSpace(strategy) ? DefaultStrategy : strategy.Trim() }; } }然后在执行侧再映射成 provider 真正消费的设置对象。这个做法的价值很直接业务层决定“该不该重试”运行时决定“怎么重试”两边各管一摊互相不打架。很多问题不是不能做只是没把代价算明白。把策略快照化本质上就是在提前把代价算清楚。第三层Provider 只做终态判定和上下文判定到了具体的 Claude Code 或 Codex provider这里的职责反而很薄。你可以把它理解成增强不要把它误会成代替。以 Codex 为例它最终接入共享协调器时本质上只需要提供三样东西csharp await foreach (var message in ProviderErrorAutoRetryCoordinator.ExecuteAsync( prompt, options.ProviderErrorAutoRetry, retryPrompt ExecuteCodexAttemptAsync(...), () !string.IsNullOrWhiteSpace(resolvedThreadId), DelayAsync, IsRetryableTerminalFailure, cancellationToken)) { yield return message; }你会发现真正属于 Provider 自己的判断只有两个IsRetryableTerminalFailurecanRetryInSameContextCodex 看的是 thread 还能不能续上Claude Code 看的是 continuation target 还在不在。退避策略、重试次数、后续 prompt这些通通不该让 Provider 自己重新发明一遍。这一层拆出来以后HagiCode 接更多 CLI 的成本就低很多了。你不用复制一整套重试状态机只要把“这个 provider 的边界条件”接进来就行。写得快不等于写得稳接得住不等于接得好能跑起来也不等于能长期维护。一个很容易做错的点别把所有报错都当可重试这次分析里我觉得最值得单拎出来讲的不是“怎么实现重试”而是“怎么避免错误重试”。最开始的问题切入口是 Codex 少识别了一条 reconnect 报文。按直觉很多人会选一个最小修法往白名单里再加一条字符串前缀。这个思路不能说错只是它更像 Demo 时期的解法不太像长期维护的解法。从当前 HagiCode 的落地来看系统已经往更稳的方向走了一步。它不再只盯着某个字面字符串而是把可恢复的终态统一交给共享协调器处理。这样做的好处很明显不容易因为某条文案的小改动就彻底失效测试覆盖可以围绕“终态 envelope”展开而不是单条硬编码文本同一个 provider 的重试逻辑会更一致当然这里要立一个边界更通用不等于更宽松。只要当前上下文不能继续哪怕报错看起来很像暂时故障也不应该盲目 replay。这点很关键。真正让人安心的不是它偶尔灵一次而是它大多数时候都靠谱。如果一个流程只能靠高手维持那它离普及还差得远。实践里最值得保留的三条经验文章写到这里差不多可以往实践层收一收了。如果你准备在自己的项目里实现类似能力我最建议先守住下面三条。1. 重试预算必须有边界HagiCode 当前默认的退避节奏是10 秒20 秒60 秒这个节奏不一定适合所有系统但“有边界”这件事必须保留。要不然自动重试很快就会从恢复机制变成事故放大器。别急着把名字起得太大先看看这东西能不能在团队里活过两个迭代。2. continuation prompt 要统一项目里使用的是固定 continuation prompt让后续 attempt 明确走“继续当前上下文”的路径而不是重新发起一轮完整请求。这个能力不花哨可是你真做项目时离不开。很多能力看起来像魔法拆开以后不过是一套被打磨过的工程流程。3. 共享库和适配层都要有镜像测试这点我很想多说一句。很多团队会在共享运行时里写一层测试然后觉得差不多了。其实不够。HagiCode 这边之所以让我比较放心是因为两层都补了测试共享 Provider 测“是否真的发生了自动续跑”适配层测“最终错误和流式消息有没有被整理坏”我这次也额外补跑了两组相关测试结果都是 31 个用例全部通过。这个结果本身说明不了设计一定完美可它至少能说明一件事当前这套自动重试不是纸面方案而是已经被代码和测试共同约束住的能力。Talk is cheap. Show me the code. 放到这里恰好合适。总结如果把整篇文章压缩成一句话那就是Claude Code、Codex 等 Agent CLI 的自动重试最好不要做成某个 Provider 内部的局部技巧而应该做成共享协调器 策略快照 上下文判定 镜像测试的组合。这样做带来的收益其实非常实在逻辑只写一遍多个 Provider 都能复用请求是否允许重试可以稳定地跟着执行链路走有上下文时继续跑没上下文时及时停手前端最终看到的是稳定的完成态或失败态而不是一堆半途而废的中间噪音这套方案是 HagiCode 在真实接入多种 Agent CLI 的过程中一点点打磨出来的。谁说 AI 辅助编程就不是新时代的结对编程呢模型帮你起步、补全、发散可真正决定体验上限的往往还是上下文、流程和约束。如果本文对你有帮助也欢迎顺手看看 HagiCode 的公开入口GitHub: github.com/HagiCode-org/site (https://github.com/HagiCode-org/site)官网: hagicode.com (https://hagicode.com)30 分钟实战演示: www.bilibili.com/video/BV1pirZBuEzq/ (https://www.bilibili.com/video/BV1pirZBuEzq/)Desktop 安装入口: hagicode.com/desktop/ (https://hagicode.com/desktop/)Steam: Steam 商店页加入愿望单 / 查看详情 (https://store.steampowered.com/app/4625540/Hagicode/)HagiCode 现在已经上架 Steam 了这不是画饼链接也给你放这儿了。有 Steam 的朋友可以先加个愿望单自己点进去看一眼比我在这儿多说十句都来得直接。先把这件事讲到这里剩下的我们继续在真实项目里见。参考资料HagiCode 项目主页: https://hagicode.comHagiCode GitHub 仓库: https://github.com/HagiCode-org/site官方演示视频: https://www.bilibili.com/video/BV1pirZBuEzq/Desktop 安装说明: https://hagicode.com/desktop/原文与版权说明感谢您的阅读,如果您觉得本文有用,欢迎点赞、收藏和分享支持。 本内容采用人工智能辅助协作,最终内容由作者审核并确认。本文作者: newbe36524 (https://www.newbe.pro)原文链接: https://docs.hagicode.com/go?platformwechattarget%2Fblog%2F2026-02-11-agent-cli-automatic-retry%2F (https://docs.hagicode.com/go?platformwechattarget%2Fblog%2F2026-02-11-agent-cli-automatic-retry%2F)版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!