写在前面

learn-claude-code 项目目前有两条教程线,一条是之前的 s12 章节的,另一条是最近更新的 s20 章节的,大家如果刚学习这个项目的话推荐直接看最新的 s20 章节的教程即可,由于博主之前学习过 s12 章节的内容,因此打算把 s20 章节中新增章节的内容给补充学习,内容重复的章节博主这边就跳过了。

下面是旧版到新版的对应关系:

Legacy 12-lesson track Current 20-lesson track Topic
old s01 new s01 Agent Loop
old s02 new s02 Tool Use
old s03 new s05 TodoWrite
old s04 new s06 Subagent
old s05 new s07 Skill Loading
old s06 new s08 Context Compact
old s07 new s12 Task System
old s08 new s13 Background Tasks
old s09 new s15 Agent Teams
old s10 new s16 Team Protocols
old s11 new s17 Autonomous Agents
old s12 new s18 Worktree Isolation
new only s03, s04, s09, s10, s11, s14, s19, s20 Permission, Hooks, Memory, System Prompt, Error Recovery, Cron, MCP, Comprehensive Agent

从上表中我们可以看出我们需要补充的内容包括 s03(已补充)s04(已补充)s09(已补充)s10(已补充)、s11、s14、s19 以及 s20 八个章节的内容。

新版学习路径如下:

主线:能动手 → 能做复杂任务 → 能记住和恢复 → 能长期运行 → 能协作 → 能扩展并合体

在这里插入图片描述

前言

在上篇文章 Learn-Claude-Code | 笔记 | Planning & Coordination | s10_new System Prompt 中,我们介绍了开源项目 learn-claude-code 新版第十个章节 s10_new: System Prompt 的内容,这篇文章我们继续跟着教程文档来学习规划与拆解相关内容,记录下个人学习笔记,和大家一起分享交流😄

Note:本篇文章主要学习记录 新版教程 第二部分 Planning & Coordination 中 s11: Error Recovery 章节的内容。

githubhttps://github.com/shareAI-lab/learn-claude-code

referencehttps://chatgpt.com/

1. s11: Error Recovery

在前面的 s10 中,我们已经把 System Prompt 从一段硬编码字符串,升级成了由运行时状态动态组装出来的提示词系统。也就是说,Agent 在每一轮调用 LLM 之前,不再只是简单地把 messages 丢给模型,而是会先根据当前 workspace、工具列表、memory 内容等上下文,组装出一个更稳定、更可追踪的 system prompt。

但是到这里为止,Agent Loop 仍然有一个非常明显的问题:只要 LLM 调用过程中出现异常,整个 Agent 就会直接中断

真实生产环境中的 Agent 不可能永远运行在理想条件下。模型可能输出到一半触发 max_tokens,上下文可能因为多轮对话、工具结果、记忆加载而超出窗口限制,API 服务也可能因为限流、过载、网络抖动而返回 429 或 529。如果这些错误都让主循环直接崩溃,那么这个 Agent 只能算是一个 Demo,而不是一个可以长期运行的工程系统。

所以 s11 的核心任务,就是给 Agent Loop 加上一层错误恢复能力。

它并没有推翻前面已经建立起来的结构。s10 的 prompt assembly 仍然保留,s08/s09 的压缩和记忆加载仍然保留,工具执行逻辑也没有变化。s11 真正新增的是:把 LLM 调用包进 try/except 中,并根据不同错误类型选择不同的恢复路径

换句话说,s11 让 Agent 从 “出错即退出” 变成了 “出错先分类,分类后恢复,恢复后回到 loop 继续执行”。

2. 问题

在一个最简单的 Agent Loop 中,LLM 调用通常长这样:

response = client.messages.create(
    model=MODEL,
    system=system,
    messages=messages,
    tools=TOOLS,
    max_tokens=8000,
)

如果这次调用成功,Agent 就继续判断 stop_reason,要么输出最终回答,要么执行工具,再把工具结果追加回 messages,进入下一轮循环。

但是如果这里报错,比如:

Error: 529 overloaded

或者:

prompt_too_long

或者模型虽然没有抛异常,但是返回了:

response.stop_reason == "max_tokens"

那么原来的 Agent Loop 就没有任何处理能力。

这三类错误在 Agent 系统中非常常见。第一类是输出被截断,说明模型还没说完就达到了输出 token 上限;第二类是上下文超限,说明当前 messages、system prompt、tool results、memory 等信息合起来已经超过模型可接受的上下文窗口;第三类是临时故障,例如 429 限流、529 过载,这类错误并不代表任务本身失败,而是服务端暂时不可用。

因此,s11 的工程目标不是让错误消失,而是让 Agent 面对错误时具备 “韧性”:能识别错误、选择恢复策略、限制恢复次数,并在恢复失败时干净退出。

3. 解决方案

本节的整体架构可以用下面这张图概括:

在这里插入图片描述

从主流程上看,s11 仍然延续了前面几节的 Agent Loop:

messages → prompt assembly → compress + load → LLM → TOOL_HANDLERS → messages → 下一轮

这里的 messages 仍然是对话历史,prompt assembly 来自 s10,compress + load 对应 s08 和 s09 中的压缩与记忆加载,TOOL_HANDLERS 仍然负责执行 bash、read_file、write_file 等工具。

唯一关键变化是:LLM 调用不再是裸调用,而是被错误恢复机制包裹起来

当 LLM 正常返回时,Agent 继续原来的工具执行流程;当 LLM 返回 max_tokens 时,Agent 会尝试扩大输出预算或注入续写提示;当 API 抛出 prompt too long 错误时,Agent 会触发 reactive compact;当遇到 429 或 529 这类临时故障时,Agent 会进行指数退避重试,必要时切换 fallback model。

这就是 s11 的核心思想:恢复逻辑是 Agent Loop 的外壳,而不是 Agent Loop 的替代品

s11 的教程版主要实现了三条最常见的恢复路径。

第一条路径是 max_tokens。这不是 API 异常,而是模型正常返回了响应,但响应被输出 token 上限截断了。也就是说,模型还能继续说,只是当前 max_tokens=8000 不够用。对于这种情况,s11 不会立刻把截断内容追加到 messages 中,而是先把输出预算从 8K 升级到 64K,然后用同一个请求重新调用一次模型。

第二条路径是 prompt_too_long。这类错误说明上下文太长,模型根本接收不了当前请求。这时继续重试没有意义,因为请求内容本身没有变。s11 的做法是触发一次 reactive_compact,也就是紧急压缩上下文。教学版中为了简化,只保留最后 5 条消息;真实系统中通常会调用 LLM 生成 compact summary,再用压缩后的上下文重试。

第三条路径是 429 / 529。这类错误不是任务逻辑错误,而是服务端临时状态问题。429 表示请求被限流,529 表示模型服务过载。s11 对这类错误采用指数退避加随机抖动:第一次等 0.5 秒,第二次等 1 秒,第三次等 2 秒,后面继续指数增长,但有最大等待上限。同时,如果连续多次遇到 529,并且配置了备用模型,系统可以切换到 fallback model 继续执行。

这三条路径对应三种不同的工程判断:

  • max_tokens → 输出空间不够,所以扩大输出预算或续写
  • prompt_too_long → 输入上下文太长,所以压缩上下文
  • 429 / 529 → 服务暂时不可用,所以等待后重试或切换模型

这也是错误恢复设计中最重要的一点:不要盲目 retry,而是先判断错误类型,再选择最小恢复动作

4. Error Recovery Paths 流程图分析

Web 教程中的 Error Recovery Paths 示例图,把 s11 的恢复路径拆成了更加直观的状态面板:左侧是 Failure inbox,中间是 RecoveryState,右侧是 Recovery action。

在这里插入图片描述

第一张图展示的是正常情况。LLM 调用成功,没有错误,也不需要恢复,Agent 直接进入正常的 tool loop。这一点很重要,因为错误恢复机制不应该干扰正常路径。正常路径必须仍然是最快、最简单、最低成本的路径。

在这里插入图片描述

第二张图展示 max_tokens 的恢复路径。模型输出被截断后,系统不会立刻生成续写提示,而是先把输出预算从 8K 提升到 64K,然后用相同请求重试。这个设计避免了过早把截断内容写入对话历史,也避免了模型在下一轮中对半截输出产生误解。

在这里插入图片描述

第三张图展示 prompt_too_long 的恢复路径。上下文超限时,继续原样重试没有任何意义,所以系统会执行 reactive compact,压缩 messages 后再重试一次。如果压缩后仍然太长,就干净退出,而不是无限压缩、无限重试。

在这里插入图片描述

第四张图展示 429 的恢复路径。429 的本质是限流,说明服务端不是不能处理这个任务,而是当前请求频率太高。因此最合理的恢复动作不是修改 prompt,也不是切换任务,而是等待一段时间再重试。这里采用指数退避和抖动,让重试行为对服务端更友好。

在这里插入图片描述

第五张图展示 529 的恢复路径。529 表示服务过载,和 429 一样也可以先退避重试。但如果连续多次发生 529,就说明当前模型可能持续不可用。这时系统可以切换到 fallback model,把任务继续推进下去。

在这里插入图片描述

第六张图把所有恢复路径合在一起:max_tokens、prompt_too_long、429、529 都进入同一个 Failure inbox,但它们不会被同一种方式处理。每一种错误都对应 RecoveryState 中的某些字段,也对应右侧的一种恢复动作。最终,要么恢复成功回到正常循环,要么达到限制后干净退出。

这组图非常好地说明了 s11 的核心理念:错误恢复不是 “失败后重跑一次”,而是对失败进行分类、记录状态、执行有限恢复动作

完整动画演示如下图所示:

在这里插入图片描述

5. 工作原理(代码分析)

OK,下面我们就来看看代码具体是如何实现的:

1. RecoveryState:把恢复状态显式保存下来

s11 首先新增了一个 RecoveryState 类,用来记录当前 Agent 在错误恢复过程中的状态:

class RecoveryState:
    """Track recovery attempts across the loop."""
    def __init__(self):
        self.has_escalated = False
        self.recovery_count = 0
        self.consecutive_529 = 0
        self.has_attempted_reactive_compact = False
        self.current_model = PRIMARY_MODEL

这里每个字段都对应一类恢复控制。

has_escalated 表示是否已经把 max_tokens 从 8K 升级到 64K。这个动作只能做一次,因为如果无限升级输出预算,本质上是在掩盖模型输出过长的问题。

recovery_count 表示 max_tokens 触发后,续写提示已经使用了几次。代码中限制最多续写 3 次,避免模型一直 “接着说”,但没有真正完成任务。

consecutive_529 用来记录连续发生 529 过载的次数。如果连续过载达到阈值,并且配置了 FALLBACK_MODEL_ID,系统就会切换备用模型。

has_attempted_reactive_compact 表示是否已经做过一次紧急压缩。上下文超限的压缩也只给一次机会,因为如果压缩后仍然超限,说明当前任务已经无法在现有上下文窗口中继续推进。

current_model 则是当前使用的模型。默认是 PRIMARY_MODEL,在连续 529 时可以切换为 fallback model。

这个设计很关键:错误恢复不是 “遇到错误就临时写几行 if”,而是需要有状态地管理恢复过程。否则 Agent 无法知道某个恢复动作是否已经尝试过,也无法避免无限重试。

2. retry_delay:指数退避加随机抖动

针对 429 / 529 这类临时故障,s11 使用 retry_delay 计算重试等待时间:

def retry_delay(attempt, retry_after=None):
    """Exponential backoff with jitter. Retry-After takes priority."""
    if retry_after:
        return retry_after
    base = min(BASE_DELAY_MS * (2 ** attempt), 32000) / 1000
    jitter = random.uniform(0, base * 0.25)
    return base + jitter

这里的基础延迟是 500ms × 2^attempt,并且最多不超过 32000ms,也就是 32 秒。随后再加上 0 到 25% 的随机抖动。

抖动的意义在于避免大量请求在同一时间重试。如果很多 Agent 同时遇到服务过载,然后都严格按照 0.5s、1s、2s 的固定间隔重试,就会再次形成流量尖峰。加入 jitter 后,每个请求的重试时间会略微错开,这样对服务端更友好。

如果服务端返回了 Retry-After,则优先听服务端的建议,而不是自己计算等待时间。

3. with_retry:把 429 / 529 收拢到统一重试逻辑

s11 中专门实现了一个 with_retry 函数,用来包裹真正的 LLM 调用:

def with_retry(fn, state: RecoveryState):
    """Exponential backoff for transient errors (429/529).
    Non-transient errors are re-raised for the outer handler."""
    for attempt in range(MAX_RETRIES):
        try:
            result = fn()
            state.consecutive_529 = 0
            return result
        except Exception as e:
            name = type(e).__name__
            msg = str(e).lower()

这里传入的 fn 实际上就是一次 LLM API 调用。with_retry 的职责不是处理所有错误,而是只处理 “瞬态错误”,也就是 429 和 529。

当错误信息中包含 429 或 RateLimit 时,系统会打印限流日志,等待一段时间,然后继续重试:

if "ratelimit" in name.lower() or "429" in msg:
    delay = retry_delay(attempt)
    print(f"  \033[33m[429 rate limit] retry {attempt+1}/{MAX_RETRIES},"
          f" wait {delay:.1f}s\033[0m")
    time.sleep(delay)
    continue

当错误信息中包含 529 或 overloaded 时,系统会记录连续 529 的次数。如果连续过载次数达到阈值,并且配置了 fallback model,就切换模型:

if "overloaded" in name.lower() or "529" in msg or "overloaded" in msg:
    state.consecutive_529 += 1
    if state.consecutive_529 >= MAX_CONSECUTIVE_529:
        if FALLBACK_MODEL:
            state.current_model = FALLBACK_MODEL
            state.consecutive_529 = 0
            print(f"  \033[31m[529 x{MAX_CONSECUTIVE_529}]"
                  f" switching to {FALLBACK_MODEL}\033[0m")

这段代码体现了一个很典型的工程分层:with_retry 只处理可以通过等待恢复的错误;如果不是 429 / 529,就重新抛出,让外层的 agent_loop 去处理。

也就是说,错误恢复并不是一个大而全的 except Exception,而是分层分类:

  • with_retry → 处理 429 / 529 这类临时错误
  • agent_loop → 处理 prompt_too_long 这类上下文错误
  • stop_reason → 处理 max_tokens 这类模型返回状态

4. is_prompt_too_long_error:识别上下文超限

对于上下文超限,s11 提供了一个判断函数:

def is_prompt_too_long_error(e: Exception) -> bool:
    """Check whether an API error indicates prompt/context too long."""
    msg = str(e).lower()
    return (("prompt" in msg and "long" in msg)
            or "prompt_is_too_long" in msg
            or "context_length_exceeded" in msg
            or "max_context_window" in msg)

这里没有依赖某一个固定的异常类型,而是通过错误信息中的关键词来判断。这是因为不同模型供应商、不同 SDK、不同兼容接口返回的错误字段可能并不完全一致。有的叫 prompt_too_long,有的叫 context_length_exceeded,有的可能描述为超过最大上下文窗口。

这种写法虽然不如强类型异常优雅,但在多模型、多供应商接入的 Agent 工程中非常实用。

5. reactive_compact:上下文超限后的紧急压缩

当检测到 prompt too long 后,s11 会触发 reactive_compact

def reactive_compact(messages: list) -> list:
    """Emergency compact — teaching version keeps last N messages."""
    print("  \033[31m[reactive compact] trimming to last 5 messages\033[0m")
    tail = messages[-5:]
    return [{"role": "user",
             "content": "[Reactive compact] Earlier conversation trimmed. "
                        "Continue from where you left off."}, *tail]

这里教学版做了一个简化:直接保留最后 5 条消息,并在前面插入一条提示,说明早期对话已经被裁剪,让模型继续当前任务。

这和 s08 中的普通压缩不同。普通压缩更像是预防性维护:当上下文变长时,提前做 budget、snip、micro、autoCompact 等处理。而 reactive compact 是事故发生后的紧急恢复:API 已经明确告诉你上下文太长了,这时必须立刻缩短 messages,否则下一次请求还会失败。

所以两者的区别可以理解为:

  • 普通 compact → 主动压缩,避免超限
  • reactive compact → 被动恢复,超限后紧急裁剪

在真实系统中,reactive compact 通常不会只是简单保留最后几条消息,而是会调用模型生成一个更高质量的 compact summary,把关键任务状态、已执行操作、未完成目标保留下来,然后再重试。

6. agent_loop:三种恢复路径合并到主循环

s11 的主循环从结构上看仍然很熟悉:

def agent_loop(messages: list, context: dict):
    """Main loop with error recovery wrapping LLM calls."""
    system = get_system_prompt(context)
    state = RecoveryState()
    max_tokens = DEFAULT_MAX_TOKENS

    while True:
        try:
            response = with_retry(
                lambda mt=max_tokens, mdl=state.current_model:
                    client.messages.create(
                        model=mdl, system=system, messages=messages,
                        tools=TOOLS, max_tokens=mt),
                state)

这里有几个关键点。

第一,system = get_system_prompt(context) 仍然来自 s10。也就是说,s11 没有改变 system prompt 组装逻辑,只是在调用模型时增加了恢复能力。

第二,state = RecoveryState() 只在本次 agent loop 中创建一次,用来跟踪这一次任务执行过程中的恢复状态。

第三,真正调用 LLM 的地方被 with_retry 包起来,因此 429 / 529 会在这里先被处理。如果重试成功,response 正常返回;如果不是瞬态错误,异常会继续抛给外层。

外层首先处理 prompt too long:

except Exception as e:
    if is_prompt_too_long_error(e):
        if not state.has_attempted_reactive_compact:
            messages[:] = reactive_compact(messages)
            state.has_attempted_reactive_compact = True
            continue
        print("  \033[31m[unrecoverable] still too long after compact\033[0m")
        messages.append({"role": "assistant", "content": [
            {"type": "text",
             "text": "[Error] Context too large, cannot continue."}]})
        return

如果这是第一次上下文超限,就进行 reactive compact,然后 continue 回到 while 循环开头,重新调用 LLM。注意这里用的是:

messages[:] = reactive_compact(messages)

这表示原地修改 messages 列表,而不是创建一个新的局部变量。这一点很重要,因为外层的 history 引用的仍然是同一个列表。如果只是写成 messages = reactive_compact(messages),就可能导致外部历史和内部消息列表脱节。

如果已经做过一次 reactive compact 后仍然超限,Agent 就不再继续重试,而是追加一条错误消息并退出。这体现了 s11 的另一个原则:恢复必须有边界

7. max_tokens:先升级,再续写

LLM 成功返回后,s11 会先检查 response.stop_reason

if response.stop_reason == "max_tokens":
    if not state.has_escalated:
        max_tokens = ESCALATED_MAX_TOKENS
        state.has_escalated = True
        print(f"  \033[33m[max_tokens] escalating"
              f" {DEFAULT_MAX_TOKENS} -> {ESCALATED_MAX_TOKENS}\033[0m")
        continue

这里最值得注意的是:第一次触发 max_tokens 时,不会把截断输出追加到 messages 中

原因很简单:如果模型输出被截断了,这段输出可能是不完整的。直接把不完整内容追加进上下文,可能会污染后续推理。所以第一次恢复策略是扩大输出预算,然后用同一个 messages 重试一次。

如果升级到 64K 后仍然被截断,说明输出确实非常长。这时才把截断输出保留下来,并追加一个续写提示:

messages.append({"role": "assistant", "content": response.content})
if state.recovery_count < MAX_RECOVERY_RETRIES:
    messages.append({"role": "user", "content": CONTINUATION_PROMPT})
    state.recovery_count += 1
    print(f"  \033[33m[max_tokens] continuation"
          f" {state.recovery_count}/{MAX_RECOVERY_RETRIES}\033[0m")
    continue

续写提示是:

CONTINUATION_PROMPT = (
    "Output token limit hit. Resume directly — "
    "no apology, no recap. Pick up mid-thought."
)

这条提示的目标很明确:不要道歉,不要复述,不要总结,直接从中断处继续。

最多续写 3 次。如果 3 次之后仍然触发 max_tokens,就停止恢复:

print("  \033[31m[max_tokens] recovery limit reached\033[0m")
return

这就是 s11 对输出截断的完整策略:

  • 第一次 max_tokens → 不保存截断输出,8K 升级到 64K,重试
  • 64K 后仍 max_tokens → 保存截断输出,追加续写提示
  • 连续续写超过 3 次 → 停止恢复,退出

8. 工具执行逻辑保持不变

如果模型没有触发 max_tokens,就正常追加 assistant response:

messages.append({"role": "assistant", "content": response.content})

if response.stop_reason != "tool_use":
    return

如果 stop_reason == "tool_use",说明模型要调用工具,后续逻辑和前面几节基本一致:

results = []
for block in response.content:
    if block.type != "tool_use":
        continue
    print(f"\033[36m> {block.name}\033[0m")
    handler = TOOL_HANDLERS.get(block.name)
    output = handler(**block.input) if handler else f"Unknown: {block.name}"
    print(str(output)[:200])
    results.append({"type": "tool_result",
                    "tool_use_id": block.id, "content": output})
messages.append({"role": "user", "content": results})

工具执行完成后,工具结果仍然作为 user 消息追加回 messages,然后更新上下文并重新组装 system prompt:

context = update_context(context, messages)
system = get_system_prompt(context)

这说明 s11 的改造是非常克制的。它没有把工具执行、上下文更新、system prompt 组装全部打散重写,而是在 LLM 调用边界处加入恢复能力。

这也是本节最值得学习的工程方法:好的错误恢复机制不应该让主循环变得混乱,而应该像一层外壳一样包住不稳定的调用边界

OK,以上就是 s11 Error Recovery 工作原理的完整分析了。

由于本章节内容不太好调试展示,大家可以自己试试看能不能触发 Error Recovery:

1. 让 Agent 生成一段很长的代码,观察截断后是否自动续写(看 [max_tokens] escalating 日志)

2. 连续读取大量文件撑大上下文,观察 reactive compact

3. 如果遇到 429/529,观察指数退避的日志输出

6. 相对 s10 的变更

组件 之前 (s10) 之后 (s11)
错误处理 无(一碰就崩溃) 三种恢复模式 + 指数退避
新常量 ESCALATED_MAX_TOKENS=64000, MAX_RETRIES=10, BASE_DELAY_MS=500, FALLBACK_MODEL
新函数 with_retry, retry_delay, reactive_compact, is_prompt_too_long_error, RecoveryState
工具 bash, read_file, write_file (3) bash, read_file, write_file (3) — 不变
循环 裸调用 LLM try/except 包裹 + continue 重试

7. 小结

在 s10 中,Agent 已经可以根据运行时状态动态组装 system prompt;到了 s11,这条主循环本身仍然没有被推翻,只是在调用 LLM 的位置外面包了一层更可靠的恢复机制。正常情况下,模型调用成功,流程继续进入工具执行;一旦出现异常,系统会先判断错误属于哪一类,再选择最小代价的恢复动作,而不是盲目重试。

这里最核心的三条路径分别对应三种常见问题:如果是 max_tokens,说明模型输出被截断,优先通过提升输出预算来恢复;如果是 prompt_too_long,说明上下文已经超限,就触发更激进的 reactive compact;如果是 429 或 529 这类临时服务错误,则通过指数退避、抖动以及必要时切换备用模型来降低失败影响。

因此,s11 真正补上的不是一个 “报错处理工具”,而是 Agent Harness 的韧性层。它让 Agent 在面对截断、超限、限流、过载这些生产环境中非常常见的问题时,不会立刻崩溃,而是能够有边界、有状态、有策略地恢复。每一种恢复路径都有明确触发条件、最大次数和退出条件,这一点非常重要:可靠的 Agent 不是无限重试,而是知道什么时候继续、什么时候降级、什么时候干净地退出。

OK,以上就是本期想要分享的全部内容了。

结语

本篇文章我们围绕 s11 Error Recovery 这一节,从问题出发,结合流程图与代码实现,完整梳理了 Agent 在面对输出截断、上下文超限以及服务端故障时,是如何通过分类恢复机制维持系统持续运行的。

相比前面的章节,s11 最本质的变化并不是新增了某种能力,而是第一次正式回答了一个工程系统必须面对的问题:当事情出错时,系统应该怎么办。

在前面的 Agent Loop、Tool Use、Memory、System Prompt 等章节中,我们一直在为 Agent 增加能力。但能力越强,运行时间越长,遇到异常的概率也就越高。如果每一次 max_tokensprompt_too_long、429 或 529 都直接导致主循环退出,那么系统拥有再多能力,也很难真正应用到真实场景之中。

s11 给出的解法非常克制:它没有修改 Agent Loop 的核心结构,也没有重写工具执行流程,而是在 LLM 调用边界之外增加了一层恢复外壳。对于不同类型的错误,系统选择不同的最小恢复动作——输出不够就扩容或续写,上下文过长就压缩,服务暂时不可用就退避重试或切换模型。整个过程始终围绕同一个原则展开:先理解失败原因,再执行恢复动作。

从工程视角来看,这一节真正补上的并不是几个 try/except,而是 Agent Runtime 中长期缺失的一块能力:可靠性。系统开始具备区分错误类型、跟踪恢复状态、限制恢复次数以及安全退出的能力。恢复过程不再是无边界的重试,而是一个有状态、有策略、有终点的受控流程。

进一步来看,s11 的意义甚至超出了错误恢复本身。因为从这一节开始,Agent 不再只是一个能够执行任务的系统,而开始逐渐演化为一个能够在不确定环境中持续运行的系统。面对失败,它不再立即崩溃,而是尝试恢复;面对无法恢复的情况,也能够明确终止并保留一致状态。

如果说 s10 建立的是 Agent 的 “运行时配置能力”,那么 s11 建立的,就是 Agent 的 “运行时韧性”。而这一步,也正是 Agent 从 Demo 迈向生产级系统过程中不可或缺的一环。

下篇文章我们将来学习新版教程 s14 Cron Scheduler 章节的内容,敬请期待🤗

参考

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐