ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

agno Agent Checkpointing 与崩溃恢复实战:`checkpoint=“tool-batch“` 源码级解析

agno Agent Checkpointing 与崩溃恢复实战:`checkpoint=“tool-batch“` 源码级解析 agno Agent Checkpointing 与崩溃恢复实战checkpointtool-batch源码级解析【免费下载链接】agnoBuild, run, and manage agent platforms.项目地址: https://gitcode.com/GitHub_Trending/ag/agnocheckpointing 是 agno 持久化体系的基石默认情况下一次 run 只在终端状态落库一旦 worker 中途崩溃整段工作就会丢失。本指南以仓库中 18_checkpointing 目录 的文档与三个可运行示例为主体结合 agno 核心源码深入讲解checkpointtool-batch的中途落库机制、崩溃后/continue原地续跑的原理、工具异常与模型调用失败的差异处理以及 AgentOS 暴露的 checkpoint HTTP 端点帮助你为长时间研究类 Agent 构建可恢复、可续跑、可审计的持久化基础。为什么需要中途落库从终端态写入到每批工具写入一个没有 checkpointing 的 run 只在终端状态COMPLETED、PAUSED、CANCELLED、ERROR时把结果写入数据库——这就是checkpointruns的默认行为。它带来的问题非常具体如果 worker 在两次工具批次之间崩溃session 行虽然存在但这条run_id从未被记录进去中途产生的所有工作全部丢失。checkpointtool-batch改变了写入时机它在一个post-gather barrier工具批次结束后的汇合点落库而不是等到终态。也就是说运行中每完成一批工具调用就写入一次。文档给出了一个精确的写入次数模型对于一个包含 K 批工具调用、外加最后一批无工具回合的 run你会得到 K 1 次写入K 次中途写入 1 次终端写入。正是这种中途持久化让一个 run 在崩溃后具备可恢复性也构成了/continue系列能力的地基。checkpoint参数的取值定义在 Agent 构造函数中位于 libs/agno/agno/agent/agent.pycheckpoint: Optional[Literal[runs, tool-batch, tools]] None从源码注释可以确认三个取值当前的语义与边界runs默认仅在终端状态写入崩溃即丢数据tool-batch每完成一批工具调用就写入本次主题tools按单次工具调用逐个写入预留给 3.0 版本在 2.x 中传入会抛出NotImplementedError。中途 checkpoint 到底写入了什么消息边界与RUNNING状态要理解中途落库的可靠性需要看清楚一次中途写入包含哪些字段。核心实现在 libs/agno/agno/agent/_run.py 的checkpoint_run/acheckpoint_run异步版本中逻辑非常清晰if agent.checkpoint ! tool-batch: return # 非 tool-batch 模式直接 no-op run_response.status RunStatus.running run_response.last_checkpoint_at_message_index len(run_response.messages or []) _mark_checkpoint_message(run_response) persist_run_in_session(agent, run_response, session, run_context)也就是说每次中途写入会做三件事把 run 状态置为RUNNING——这正是崩溃恢复时数据库里能看到的关键信号记录last_checkpoint_at_message_index指向当前消息序列的长度标记进度写到哪了标记消息边界_mark_checkpoint_message会把最后一条消息标记上checkpoint_status与checkpoint_created_atUnix 时间戳这是后面 HTTP timeline 端点推导 checkpoint 列表的数据来源。写入前_sync_run_response_with_model_response会把进行中的model_response/run_messages状态镜像到run_response上确保快照反映截至最近一批工具的完整会话同步与异步两种路径都会执行这段重复的收尾工作——注释明确说明这种重复是有意为之目的是拿到准确的中间快照。RUNNING状态的定义可以在 libs/agno/agno/run/base.py 的RunStatus枚举中看到完整的状态集合class RunStatus(str, Enum): pending PENDING running RUNNING completed COMPLETED paused PAUSED cancelled CANCELLED error ERROR regenerated REGENERATED # /continue?regeneratetrue 产生的旁支 run 标记这里有一个对理解崩溃恢复至关重要的细节为什么/continue可以把一个RUNNING的 run 原样续跑下去因为RUNNING和ERROR对/continue而言是等价的——run 尚未完成数据库里留着的是最后一次成功的 checkpoint/continue在同一run_id上原地继续。而CANCELLED则是刻意不可续跑的取消是被优雅处理的路径run 会被标记并重新落库。一个 run 崩溃后的生命周期SIGKILL 实验要亲眼验证上面的机制仓库提供了第一个示例 01_crash_recovery.py。它的做法很硬核不是用asyncio.Task.cancel()模拟取消那会被优雅处理为CANCELLED并重新持久化反而不符合真崩溃而是启动一个 worker 子进程在 run 进行到一半时用 SIGKILL 直接杀死它精确复现 OOM-kill、进程被强杀、断电这类无清理路径的真实崩溃场景。示例的完整流程分五步启动 worker 子进程通过subprocess.Popen([sys.executable, __file__, --worker])启动父子进程通过环境变量共享同一个 SQLite 数据库文件DB_FILEAgent 配置为checkpointtool-batch并挂上两个各耗时约 1 秒的慢速 mock 工具slow_search与slow_fetch_detail给中断留出时间窗口轮询数据库直到第一个 checkpoint 落库父进程每隔 0.5 秒读取 session等待出现status RUNNING且已产生工具批次的 run——注意它等待的是真实 checkpoint 而不是固定 sleep因此健壮性更好SIGKILL workerworker.kill()之后worker.wait()模拟进程被强杀、无任何清理代码执行检查数据库此时读取 session可以看到那条 run 仍标记为RUNNING但messages、tools、last_checkpoint_at_message_index都保留了崩溃前最后一个工具批次的状态——部分状态在崩溃后存活了原地续跑用agent.acontinue_run(run_id..., session_id...)恢复恢复后的run_id与崩溃前完全相同原地续跑而非新开 runAgent 拿到剩余上下文继续完成研究并输出最终答案。Agent 的构造方式值得注意——复用的build_agent()用SqliteDb(session_tablecheckpoint_demo, db_fileDB_FILE)让所有环节共享同一持久化层def build_agent() - Agent: return Agent( nameresearch-agent, modelOpenAIResponses(idgpt-5.4), dbSqliteDb(session_tablecheckpoint_demo, db_fileDB_FILE), checkpointtool-batch, tools[slow_search, slow_fetch_detail], instructions( Use slow_search to find results, then call slow_fetch_detail on EACH result one at a time. Summarize what you learned at the end. ), )两种失败的截然不同命运工具异常 vs 模型调用失败并非所有失败都会把工作丢掉。第二个示例 02_tool_error_persistence.py 刻意构造了两个看起来相似、结局却迥异的场景来验证对话在失败后是否幸存。场景 A工具抛出普通 Python 异常。broken_tool无条件抛出ValueError。模型循环会内部捕获这个工具错误把它转成一条tool_call_errorTrue的 tool-role 消息触发 checkpoint hook然后模型继续执行——run 正常完成错误可见地留在消息里零数据丢失。场景 B模型调用本身失败模拟替换成非法 API key。这类 provider 鉴权错误发生在任何工具批次之前异常逃逸出模型循环按批次的 checkpoint hook 从未执行update_run_response也来不及把消息灌入run_response.messages。如果没有兜底逻辑终端ERROR写入会持久化一条空消息的 run 记录导致失败前的那句用户消息随之丢失。场景 B 的救命逻辑是flush_in_flight_messages_on_error实现在 libs/agno/agno/agent/_run.py。它的定位是每个except Exception块在调用cleanup_and_store之前的最后一步把进行中的run_messages拷入run_response.messages从而让失败前的那段对话随ERROR行一起存活事后排障才不至于面对一片空白。它有两个谨慎的守卫条件仅当run_response.messages仍为空时才写入——如果中途 checkpoint hook 已经捕获了部分状态就不覆盖它可能比run_messages更完整过滤条件m.add_to_agent_memory与 checkpoint hook 保持一致保证无论哪条路径捕获持久化的消息形态都一致。场景 C对失败的 run 调用/continue。示例随后用恢复的真实 API key 对那个ERROR的 run 执行acontinue_run。这里有个值得记住的规则auto-fork-on-COMPLETED 只在状态为COMPLETED时触发ERROR状态不触发 fork因此/continue是原地续跑run_id不变。由于场景 B 的 flush 逻辑保留了[system, user]消息模型这次有完整上下文可用能真正答出结果run 变为COMPLETED——这正是重试一个 ERROR run的标准路径失败对话被保留 →/continue拾起 → 用合法凭据重新调用模型 → 同一逻辑回合完成。示例还贴心地给出了验证方式把脚本连跑两遍对比——原样运行时场景 B 会保留消息对 flush helper 的改动执行git stash后再跑场景 B 就会持久化空的 messages 列表。通过 HTTP 端点观察 checkpointtimeline、snapshot 与/continue接力第三个示例 03_checkpoint_endpoints.py 演示了如何在 AgentOS HTTP 层面消费 checkpoint。它用fastapi.testclient.TestClient在进程内启动一个AgentOS无需独立服务器、无需端口绑定自包含地演示两个 GET 端点。值得强调的是这两个端点返回的 checkpoint 边界不是来自独立的 checkpoint 表而是从已持久化的 run 中推导出来的——依据是消息级标记checkpoint_status、checkpoint_created_at加上转录的终端结尾。对应的实现函数在 libs/agno/agno/os/checkpoints.pylist_run_checkpoints(run_output)推导出前端可用的 checkpoint 时间线。每个 checkpoint 带有 1 基的展示序号checkpoint_id、真实可用的message_index、status与created_atbuild_run_checkpoint_snapshot(run_output, message_index)构造截断到该边界的一条 run 快照。示例演示的完整闭环如下先驱动一个产生多批工具调用的 run旅行 Agent 用get_population工具对比巴黎、东京、拉各斯三城人口每批工具调用都会在边界消息上写下 checkpoint 标记GET 时间线GET /agents/{agent_id}/runs/{run_id}/checkpoints?session_id...返回 checkpoint 列表UI 可以把这些边界展示为续跑点GET 快照从时间线中挑一个非终端边界is_latest为假的内部 checkpoint取出它的message_index再请求GET /agents/{agent_id}/runs/{run_id}/checkpoints/{message_index}?session_id...返回的snapshot是从持久化 run 推导出的截断副本——存储行不会被修改snapshot.messages已按边界截断、snapshot.tools只保留仍被引用的那些。快照的checkpoint_id会与时间线保持一致方便 UI 对照展示message_index直接回填/continuePOST /agents/{agent_id}/runs/{run_id}/continue Content-Type: application/x-www-form-urlencoded session_id...continue_from{message_index}inputActually, just tell me about Paris.streamfalse响应里可以看到新的run_id以及forked_from_run_id/forked_from_message_index两个元数据字段——这说明指定continue_from的续跑走的是fork 语义从那个历史边界克隆出一条新 run。fork 的底层实现同样在 libs/agno/agno/agent/_run.py 的_fork_run与_truncate_run_to_checkpoint中_fork_run深拷贝原 run、生成全新的 UUID4run_id、写入 fork 元数据、重置RunMetrics与created_atfork 是新 run不应继承父 run 的计时与 token 数_truncate_run_to_checkpoint负责把消息截断到message_index并用safe_truncation_index做一次安全校正——绝不把截断点切在 assistant 的 tool_call 与其结果之间孤立调用会被大多数 provider 拒绝同时只保留仍被消息引用的 tools 与 requirements。这就是时间旅行功能能够在任意历史 checkpoint 续跑的机制基础。什么时候该用checkpointtool-batch文档给出了清晰的取舍建议可以概括为一张决策对照场景建议原因短对话、闲聊型 Agentcheckpointruns默认终端写一次就够避免写放大长时间研究型 run、可崩溃恢复的工作流checkpointtool-batch中途掉电/被杀也能从最后 checkpoint 续跑需要逐工具细粒度写入暂不可用checkpointtools预留给 3.0当前会抛NotImplementedError必须诚实认识它的代价这是对session.runsJSON 列真实的写放大——每次工具批次结束都产生一次完整 run 落库。因此文档明确建议刻意地、有针对性地启用它用于长研究 run 和崩溃可恢复工作流而不是无脑套在对话频繁的 Agent 上。运行方式与前置条件三个示例在仓库根目录下分别执行运行目录中展示了基于 venv 的运行路径可按你实际环境调整解释器.venvs/demo/bin/python cookbook/02_agents/18_checkpointing/01_crash_recovery.py .venvs/demo/bin/python cookbook/02_agents/18_checkpointing/02_tool_error_persistence.py .venvs/demo/bin/python cookbook/02_agents/18_checkpointing/03_checkpoint_endpoints.py需要提前了解的运行前提API Key三个示例都使用OpenAIResponses(idgpt-5.4)需要可用的OPENAI_API_KEY。02会在场景 B 临时替换成非法 key 制造鉴权失败、随后在finally中恢复原 key因此请勿手动中断它本地 SQLite每个示例都使用独立的本地 SQLite 文件如tmp/checkpoint_crash_recovery_*.db、tmp/tool_error_persist_*.db、tmp/checkpoint_endpoints.db数据库路径可用CRASH_DB环境变量覆盖01持久化结果可用任意 SQLite 客户端直接检查01的输出不确定性脚本依赖模型真实执行足够多的工具批次才能抓到RUNNINGcheckpoint若模型在捕获前就自行收尾脚本会提示重新运行——这是模型行为导致的正常现象03的时间线稠密度单轮无工具调用时时间线可能没有内部边界示例会提示换一个多工具 prompt 让 timeline 更丰富。每个示例目录下都有对应的 TEST_LOG.md 记录测试情况可以作为运行结果的参照。与周边能力的关系checkpointing 是三条/continue系能力的共同地基它们分别位于本目录的兄弟文件夹中处理的是对一个已持久化 run 的三种后续操作cookbook/02_agents/19_regenerate/——重做最后一条响应cookbook/02_agents/20_time_travel/——回退到更早的时间点continue_from、forkcookbook/02_agents/21_fork_session/——复制整个 session。理解中途落库 →RUNNING存活 →/continue原地续跑这条链路是打通 crash recovery、error retry 与 time-travel 三套高级能力的前提。无论你的目标是让研究型 Agent 扛住 OOM 重启还是为用户提供可回放的对话续跑体验checkpointtool-batch加上它背后的消息边界标记与 flush-on-error 兜底都是这套持久化方案最核心的构建块。【免费下载链接】agnoBuild, run, and manage agent platforms.项目地址: https://gitcode.com/GitHub_Trending/ag/agno创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表