agno Agent 崩溃后如何靠 checkpoint=“tool-batch“ 从最后一个检查点恢复 run?
2026/9/10 7:38:44 网站建设 项目流程

agno Agent 崩溃后如何靠 checkpoint="tool-batch" 从最后一个检查点恢复 run?

【免费下载链接】agnoBuild, run, and manage agent platforms.项目地址: https://gitcode.com/GitHub_Trending/ag/agno

长时间跑的 Agent run(多次调用工具的 research 类任务)最怕 worker 进程中途挂掉:OOM-kill、SIGKILL、断电这类崩溃不会执行任何清理逻辑。agno 的默认 checkpoint 行为只在终态写库,这种情况下工作直接丢失;把 Agent 的checkpoint设为"tool-batch"后,每个工具批次结束都会把 run 持久化到数据库,崩溃后用/continue路径(acontinue_run)就能从最后一个检查点原地恢复。

崩溃为什么会丢工作:默认 checkpoint 的写入时机

agno Agent 的checkpoint参数取值为Literal["runs", "tool-batch", "tools"](见 Agent 源码):

  • 默认checkpoint="runs":只在终态(COMPLETEDPAUSEDCANCELLEDERROR)写库。worker 在 run 中途崩溃时,session 行存在,但这个run_id从未被记录在该 session 下——工作丢失(见 Checkpointing README)。
  • checkpoint="tool-batch":在每个工具批次之后写入(post-gather barrier),而不是只在终态写入。一次 run 有 K 个工具批次加最后一个无工具回合,会得到 K + 1 次写入(K 次 run 中途 + 1 次终态)。如果进程死在第 J 批和第 J+1 批之间,数据库行里包含到第 J 批为止的全部内容,状态仍标记为RUNNING
  • checkpoint="tools"(逐工具写入)保留给 3.0,2.x 中会抛NotImplementedError

README 同时给出适用边界:这是对session.runsJSON 列的真实写放大,应当刻意选择,适合长研究类 run 和需要崩溃恢复的 workflow,不适合高频聊天的 agent。

准备条件

  • 示例使用本地 SQLite 数据库(SqliteDb),持久化状态可以用任意 SQLite 客户端检查。
  • 示例模型为OpenAIResponses(id="gpt-5.4"),运行需要有效的 OpenAI API key(02_tool_error_persistence.py 中通过OPENAI_API_KEY环境变量操作该 key)。
  • 官方示例的运行方式(见 Running 一节):
.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

复现一次真实崩溃并验证检查点存活

01_crash_recovery.py 不是模拟取消,而是真的让一个正在跑的 run 崩溃,再证明数据库里有最后一个检查点、/continue能原地恢复。它的流程是:

  1. 启动一个 worker 子进程执行 run,该 run 连续调用两个慢工具(每个约 1 秒),与父进程共享同一个 DB 文件(通过CRASH_DB环境变量传递路径);
  2. 父进程轮询数据库,直到第一个RUNNING检查点落地(至少 1 个工具批次);
  3. 父进程对 worker 执行SIGKILLworker.kill())——真崩溃,无清理逻辑;
  4. 检查数据库中的残留状态,再调用/continue恢复。

选择 SIGKILL 而不是asyncio.Task.cancel()的原因写在示例 docstring 里:cancel 会被优雅处理——run 被标记为CANCELLED并重新持久化,而cancelled run 是故意设计为不可 continue 的。真实崩溃(OOM-kill、SIGKILL、断电)不执行清理,存活下来的就是最后那个RUNNING检查点。

崩溃后,脚本通过db.get_session读取 session 并打印检查点信息(脚本输出示例):

run_id: run_xxx status: RUNNING tool batches in DB: 2 message count: 5 last_checkpoint_at_message_idx: 4

关键点:状态是RUNNING,说明循环没有走到终态清理。文档明确:对/continue而言RUNNINGERROR等价,两者都是原地恢复(in place,同一个run_id)。

如果轮询窗口内模型没产生足够的工具批次就直接答完了,脚本会打印 "Did not catch a RUNNING checkpoint before the worker finished." 并建议重跑——这是示例自己的判定,不是失败。

手动恢复一个已崩溃的 run

把上面的模式套用到你自己的服务上,恢复路径分三步。恢复用的 agent 要和崩溃的 agent 保持同样的配置(同一模型、同一 DB、同一批工具),示例中通过同一个build_agent()构造。

from agno.agent import Agent from agno.db.sqlite import SqliteDb from agno.models.openai import OpenAIResponses from agno.run.base import RunStatus DB_FILE = "tmp/checkpoint_crash_recovery.db" # 崩溃前后必须是同一个 DB 文件 SESSION_ID = "crash-demo-session" agent = Agent( name="research-agent", model=OpenAIResponses(id="gpt-5.4"), db=SqliteDb(session_table="checkpoint_demo", db_file=DB_FILE), checkpoint="tool-batch", tools=[slow_search, slow_fetch_detail], # 与崩溃 run 相同 ) # 1. 定位崩溃的 run:状态为 RUNNING 且已包含工具批次 session = agent.db.get_session(session_id=SESSION_ID, session_type="agent") run = session.runs[-1] if run.status == RunStatus.running and run.tools: crashed_run = run # 2. 原地恢复:同一个 run_id resumed = await agent.acontinue_run( run_id=crashed_run.run_id, session_id=SESSION_ID ) print(resumed.run_id, resumed.status)

acontinue_run的完整签名(含continue_fromforkregenerate等参数)见 Agent.acontinue_run;崩溃恢复只需传run_idsession_id,其余走默认值(continue_from="end")。

判定恢复成功:返回的resumed.run_id与崩溃 run 相同(in-place resume),resumed.status到达COMPLETEDresumed.tools/resumed.messages的数量不少于崩溃前检查点里的数量——即示例中"total tool batches / total messages"两个打印项,示例最终还会打印恢复后跑完的resumed.content

可选分支:通过 AgentOS 的 checkpoint 端点查看时间线

如果你的 Agent 跑在 AgentOS 服务里而不是纯 Python 进程内,03_checkpoint_endpoints.py 展示了两个 GET 端点(检查点边界是从持久化 run 推导出来的,没有独立的 checkpoint 表):

  • GET /agents/{agent_id}/runs/{run_id}/checkpoints?session_id=...:返回可供 UI 展示为恢复点的 message 边界时间线;
  • GET /agents/{agent_id}/runs/{run_id}/checkpoints/{message_index}?session_id=...:返回截断到该边界的 run 快照(只读派生,不改写存储行)。

拿到时间线里某个message_index后,可以直接作为continue_from参数回喂给POST /agents/{agent_id}/runs/{run_id}/continue,从指定检查点续跑并追加新的 input。示例用fastapi.testclient.TestClient在进程内驱动 AgentOS,无需单独起服务器。

边界与限制

  • 写放大是明确的代价"tool-batch"用额外写入换可恢复性,README 建议只对长研究类 run 和崩溃可恢复的 workflow 显式开启,不要给高频聊天 agent 默认开。
  • cancelled run 不可恢复Task.cancel()这类优雅取消会把 run 标记为CANCELLED并重新持久化,cancelled run 被设计为不可 continue;只有RUNNING(真崩溃)和ERROR走原地恢复。
  • 模型调用失败是另一条路径:02_tool_error_persistence.py 区分了工具抛异常(被模型循环内部捕获,转成tool_call_error=True的 tool 消息,run 正常完成,无数据丢失)和模型调用本身失败(异常逃逸出循环,走终态ERROR写入)两种情形。对ERRORrun 调acontinue_run不会触发 auto-fork-on-COMPLETED 规则,同样是原地重试、run_id不变。
  • checkpoint="tools"在 2.x 中不可用,会抛NotImplementedError
  • 相邻的/continue能力(重做最后一次响应、回退到更早检查点、fork 整个 session)分别位于 19_regenerate/、20_time_travel/ 和 21_fork_session/ 示例目录,不在本文的崩溃恢复范围内。

【免费下载链接】agnoBuild, run, and manage agent platforms.项目地址: https://gitcode.com/GitHub_Trending/ag/agno

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询