来源:互联网 更新时间:2026-08-02 20:36
假设你正在使用一个Agent,它在帮你处理一个测试失败。
Agent读完了报错日志,顺着日志找到了相关配置文件,然后模型开始生成修改方案——回答却在半个代码块里停住了。你有点疑惑,点击重新生成,有时能得到完整结果,但更多时候它还是卡住。另一种情况更干脆:接口直接返回 529 overloaded,这一轮连半句话都没有。
如果Agent对所有失败都做同一件事,比如无脑重试,后面很容易出问题。
回答被截断时,程序需要决定那半段内容是否应该保存。比如上下文太长时,原请求重发多少次都会超限。又或者服务过载时,连续点击重试请求也照样发不出去。
s11_error_recovery 做的事情,是让Agent Loop根据失败位置选择恢复动作。它不能保证模型永远不中断,但能让一部分可恢复错误不至于直接结束整轮任务。
这一章处理三种情况:
| 现象 | 程序拿到的信息 | 恢复动作 |
|---|---|---|
| 模型输出到达长度上限 | 响应中的停止原因 | 提高输出上限,必要时续写 |
| 请求上下文过长 | 调用接口时抛出异常 | 紧急缩短消息后重试 |
| 接口限流或服务过载 | 调用接口时抛出 429、529 类错误 | 按递增间隔等待后重试 |
输出截断和接口异常的区别很大。
模型输出被截断时,程序已经拥有一份响应,只是内容还没结束。上下文超限、429 和 529 发生在请求模型的过程中,程序得不到正常响应,只能进入异常处理分支。
把这三种恢复路线放在一张图里看,会更容易分清它们改动的是输出空间、消息历史,还是请求节奏。
本章先默认允许模型输出 8000 token。
模型因为输出长度不够而停止时,程序第一次不会把这段回答写入消息历史。它先把上限提高到 64000,再用原来的任务和消息记录重新请求模型。
if response.stop_reason == "max_tokens":
if not state.has_escalated:
max_tokens = ESCALATED_MAX_TOKENS
state.has_escalated = True
continue
这段逻辑出现在回复写入消息历史之前。
这样安排和一次普通重试还不太一样。此时程序保留的是同一份输入,只给模型更多输出空间。模型有机会完整回答当前任务,不会因为读到半截旧回复,又从头补一段背景说明。
如果 64000 token 仍然不够,程序才会保存当前输出,再加入一条续写要求:
Output token limit hit. Resume directly — no apology, no recap. Pick up mid-thought.
这条提示只要求继续写,不允许模型重新解释已经说过的内容。续写最多执行三次,超过次数后循环结束。
这里的限制很有必要。模型连续多次输出不完,往往说明任务粒度太大,或者回答方式不合适。继续追加续写请求,最后很可能得到一份长度惊人、阅读体验却没有改善的回答。
上下文超限时,模型接口会直接拒绝这次请求。
教学代码中的紧急压缩没有生成摘要,只保留消息历史最后五条,这里再补一条说明:
def reactive_compact(messages: list) -> list:
tail = messages[-5:]
return [
{"role": "user", "content": "[Reactive compact] Earlier conversation trimmed. " "Continue from where you left off."},
*tail
]
压缩后的消息会替换原来的消息历史,循环随后重新调用模型。
这条路径和 s08 中的常规上下文压缩不在同一个层级。s08 会尽量保留任务目标、工具结果和已有结论,而 s11 的紧急压缩只负责让请求长度尽快降下来。
假设 Agent 前面读取了十几个文件,最近五条消息恰好只剩工具结果和模型的一句中间判断。更早的用户要求、工具调用来源和项目约束可能已经不在消息历史里。模型可以继续生成内容,却未必还知道自己为什么走到这里。
因此,本章只允许紧急压缩一次。压缩后还是超限,程序直接返回错误。继续删消息当然能让上下文变短,但任务也可能被删得只剩一个标题。
还有一个实现细节:这里直接取最后五条消息,没有像 s08 那样确认工具调用和工具结果是否保持配对。它适合说明恢复方向,不适合直接搬进需要严格维护消息格式的系统。
429 表示限流,529 表示服务暂时过载。任务内容没有变化,消息历史不需要裁剪,程序需要做的是隔一段时间再尝试。
本章使用指数退避。等待时间会逐步增加:
| 第几次失败 | 基础等待时间 |
|---|---|
| 第 1 次 | 0.5 秒 |
| 第 2 次 | 1 秒 |
| 第 3 次 | 2 秒 |
| 第 4 次 | 4 秒 |
| 后续 | 最多 32 秒 |
每次等待还会加入少量随机时间。
如果多个 Agent 在同一时刻收到 529,又严格在 0.5 秒后同时重试,服务刚恢复就会再次收到一批请求。随机抖动让重试时间错开一些,压力不会在某个时间点重新堆起来。
代码把 429 和 529 放在 with_retry() 里处理,其他异常会重新抛给外层循环。这种分工让恢复逻辑比较清楚:临时服务问题交给重试函数,长度问题交给消息压缩逻辑,无法判断的错误记录后结束任务。
连续三次 529 后,如果配置了备用模型,代码会更新当前模型名称:
state.current_model = FALLBACK_MODEL
单看这行代码,备用模型似乎已经切换成功。
问题出在调用接口时,请求函数把当前模型作为 lambda 的默认参数保存了下来:
lambda mt=max_tokens, mdl=state.current_model: client.messages.create(model=mdl, ...)
后续重试会继续调用同一个 lambda。即使恢复状态里的模型名称已经更新,mdl 仍然保持 lambda 创建时的旧值。
因此,教学代码当前会打印切换备用模型的日志,后续重试却还是使用原模型。这是 s11 里一个值得单独记下来的实现缺口。
如果希望切换立即生效,请求函数需要在每次调用时读取恢复状态:
def request():
return client.messages.create(
model=state.current_model,
system=system,
messages=messages,
tools=TOOLS,
max_tokens=max_tokens,
)
恢复逻辑里有一个常见误区:状态字段已经修改,不代表下一次操作一定会读取这个字段。中间如果缓存了参数、闭包保存了旧值,状态变化就只停留在日志里。
| 位置 | 当前做法 | 实际系统还需要补上的部分 |
|---|---|---|
| 紧急压缩 | 保留最近五条消息 | 保护工具调用与工具结果的关联 |
| 服务端建议等待时间 | 延迟函数支持该参数 | 当前调用处没有读取接口响应中的等待信息 |
| 重试次数 | 循环总共请求 10 次 | 明确区分总尝试次数和额外重试次数 |
| 备用模型 | 更新当前模型状态 | 保证下一次请求读取最新模型 |
| 输出续写 | 固定最多三次 | 根据新产生的内容判断是否还值得继续 |
这些简化并不影响理解本章的主线。s11 想展示的是,错误恢复需要调整不同的对象:有时调整输出空间,有时调整消息历史,有时只需要调整请求节奏。
这一章给 Agent Loop 补上了三种恢复动作。
模型输出不够时,程序先扩大输出空间,再考虑续写。如果消息过长的话,程序压缩消息后重试一次,但如果是接口暂时不可用,程序会按递增等待时间重试。每条路径都有自己的次数上限,避免循环在失败状态里一直打转。
这套教学实现也留下了几个需要继续完善的地方,尤其是备用模型切换和紧急压缩后的消息完整性。它们说明恢复逻辑本身同样需要测试,不能只看状态有没有更新。
下一章,我们的话题会从一次任务的结束,转向任务本身的管理。待办列表能记录当前几步,但跨会话恢复、依赖关系和长期执行,还需要更完整的任务系统。
ThinkBook系列最新价格全解析:2026年选购避坑与实时询价指南
Ondo将于今日上线股票永续合约
暗黑4S14野蛮人终局BD攻略
区块链OTC交易所有哪几家比较正规?
Binance新增15种bStocks代币化证券为杠杆抵押资产
Meme币DOGS今晚上线!开局就解锁91%代币是否带来风险?
忍者必须死3极刃血影角色介绍
晶核艾尔莎角色盘点 晶核艾尔莎强度分析与实战表现
余姚的路虎4s店在哪个位置
彩云天气怎么看分钟级降雨预报 彩云天气精准预报方法【技巧】
五千元以下的笔记本几乎消失!经销商:至少一年看不到涨价尽头
Intel喜讯连连:18A工艺良率提升到85%、CPU将涨价15%
遗忘之海密室通关教程 遗忘之海密室全关卡解谜思路与难点解析
华为Mate 70系列首发的红枫镜头下放至千元档:全员普及原色影像
合集38个项目筹集5.406亿美元 Figure融资2亿
国家养老服务消费补贴上线京东
英伟达机器人团队在京沪深招人,聚焦具身智能等四大领域
一站式PDF转Markdown解决方案PDF3MD
硬刚苹果!华为9月新品阵容出炉:Mate 90系列、全新三折叠
微软Copilot AI漏洞可致敏感数据泄露,企业用户需及时更新
手机号码测吉凶
本站所有软件,都由网友上传,如有侵犯你的版权,请发邮件haolingcc@hotmail.com 联系删除。 版权所有 Copyright@2012-2013 haoling.cc