ARTICLE DETAIL

资讯详情

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

Agno AgentOS 运行生命周期全解析:后台任务、取消、SSE 断线重连、检查点与后台 Hook 的实战与验证

Agno AgentOS 运行生命周期全解析:后台任务、取消、SSE 断线重连、检查点与后台 Hook 的实战与验证 Agno AgentOS 运行生命周期全解析后台任务、取消、SSE 断线重连、检查点与后台 Hook 的实战与验证【免费下载链接】agnoBuild, run, and manage agent platforms.项目地址: https://gitcode.com/GitHub_Trending/ag/agno导读本文围绕 Agno 开源仓库cookbook/05_agent_os/04_run_lifecycle这一课的完整运行生命周期Run Lifecycle展开从后台任务的提交与轮询、运行取消、SSE 事件流的断线恢复、持久化检查点续跑到后台化 Hook 与上传文件预处理逐一拆解其 HTTP 契约、状态机与源码实现。文中六份可直接运行的示例都经过了 LIVE 模式实测测试记录见 TEST_LOG.md因此你既能拿到可直接复制的代码与命令也能看到真实服务器上观测到的状态流转与事件序号读完即可在自己的 AgentOS 服务上复现同样的后台运行与恢复能力。一、这一课在讲什么AgentOS 运行生命周期的六个侧面Agno 的 AgentOS 把一次 Agent 的调用建模为一个可持久化、可追踪、可中断、可恢复的run。围绕它的完整 HTTP API04_run_lifecycle目录给出了六个互相独立的示例每个示例都对应生命周期中的一个关键能力示例文件教学重点TEST_LOG 实测状态background_run.py提交数据库支撑的后台运行接收 HTTP 202/PENDING轮询嵌套 run 路由直到终态PASScancel_run.py取消一个已受理的后台运行并观测其持久化的终止状态PASSsse_reconnect.py用裸httpx追踪event_index断线后对新任务/续跑任务分别执行 resumePASScheckpoints.py列出tool-batch检查点并从选定的message_index续跑PASShooks_in_background.py全局后台 Hook 开关或按 Hook / 按 Eval 精细指定后台执行PASSunpack_archives.py在模型调用前的pre_hook中把上传的.zip替换为其内部文件PASS这份 TEST_LOG.md 记录了 2026-07-24 对 Agno 源码提交6412940的实测结果六个脚本全部以 LIVE 模式、使用 OpenAI Responsesgpt-5.5跑通并在文章各节中作为真实行为的佐证。环境准备在仓库根目录执行./scripts/demo_setup.sh export OPENAI_API_KEYyour-key每个服务器示例都监听7777端口同一时间只能启动其中一个。示例本身不带--demo运行的文件负责把 AgentOS 应用以 FastAPI/uvicorn 方式serve起来另一个终端用--demo运行同一脚本即可扮演 HTTP 客户端见各脚本文件顶部的注释。二、Run 状态机七个RunStatus成员与正确的读取位置所有生命周期操作最终都要落到状态上。RunStatus枚举定义于 libs/agno/agno/run/base.py共有七个成员PENDING、RUNNING、PAUSED、COMPLETED、CANCELLED、ERROR以及用于标记被 regenerate 覆盖的旧 run的REGENERATED。其中REGENERATED是新版本中的特殊标记当通过/continue?regeneratetrue生成替代回答时新 run 作为兄弟 runsibling经由 fork 机制落在旧 run 旁边旧 run 被打上该状态以便历史构建器跳过它——传入replace_originalfalse可以保留原 run 的COMPLETED可见状态源码注释见 agent/_run.py。与状态机相关、最容易踩坑的两个事实run event事件流本身不携带status字段只有WorkflowPaused事件例外。要读状态请读取持久化的 run 输出——即轮询GET /agents/{agent_id}/runs/{run_id}返回的 JSON这正是后台轮询示例每次循环去读的那个run[status]。取消不是流终止在 cancelled 事件上。一次取消会依次发出(cancelled, completed)这一对事件因此被取消 run 的流最终收在completed事件上。客户端若以遇到 cancelled 就认为流结束的逻辑处理会在已完成事件上出现误判。另外被取消的 run 会保留它已完成的工作Agent/Team 已产出的内容仍在content中Workflow 的结果仍在step_results中轮询结果仍然可读。从源码看后台执行的核心机制是把 PENDING 状态的 run先持久化这样轮询能立刻找到它随后再spawn一个 asyncio 任务真正去执行任务真正开始时才进入RUNNING参见 agent/_run.py 的run_background路径与 L2056 附近后台流的注释。这也是后台模式必须有数据库的根因。三、后台提交与轮询HTTP 202 / PENDING 契约background_run.pybackground_run.py演示了 AgentOS 中最基本的生命周期用法不流式地提交一个后台运行观察 HTTP 202/PENDING 契约再轮询持久化的 run 直到终态。服务端要点Agent 必须挂一个数据库示例用SqliteDbdb_filetmp/agent_os_background_run.db因为分离出的后台任务与轮询请求都要读持久化的 run 状态。该模式不支持 remote agent远程代理无法在此模式工作。AgentOS 对象通过AgentOS(id..., agents[...])组装app agent_os.get_app()得到可 serve 的 FastAPI 应用。客户端要点POST 创建 run 时显式发送三个字段backgroundtrue、streamfalse以及一个session_idresponse await client.post( f/agents/{AGENT_ID}/runs, data{ message: Explain why persisted background runs are useful., background: true, stream: false, session_id: SESSION_ID, }, ) if response.status_code ! 202: # 后台 run 必须返回 202 raise RuntimeError(...) accepted response.json() if accepted[status] ! PENDING: # 初始状态必须是 PENDING raise RuntimeError(...)随后从 202 响应中取出run_id与session_id循环轮询嵌套路由response await client.get( f/agents/{AGENT_ID}/runs/{run_id}, params{session_id: session_id}, ) run response.json() status run[status] # 唯一可信的状态来源 if status in {CANCELLED, COMPLETED, ERROR}: # 终态判定 return run轮询间隔为 0.5 秒带 120 秒超时兜底。注意示例的TERMINAL_STATUSES {CANCELLED, COMPLETED, ERROR}——PAUSED、RUNNING都不算结束。LIVE 实测结果来自 TEST_LOG.md创建路由返回 HTTP 202 PENDING嵌套轮询路由依次观测到RUNNING、COMPLETED客户端打印出持久化的模型结果返回的 session 是预设的background-run-session。四、取消运行nested cancel 路由与 CANCELLED 终态cancel_run.pycancel_run.py与后台示例共用同一套 HTTP 202/PENDING 流程区别是先取消再轮询提交一个长篇写作型的长耗时请求随即 POST 到取消路由再轮询直到观测到CANCELLED。核心调用只有一步cancel_response await client.post( f/agents/{AGENT_ID}/runs/{run_id}/cancel, params{session_id: session_id}, # session_id 通过 query 传 ) cancel_response.raise_for_status() print(fCancellation accepted: HTTP {cancel_response.status_code})之后循环轮询GET /agents/{agent_id}/runs/{run_id}?session_id...与后台示例唯一的差别是轮询间隔更短0.25 秒并以status CANCELLED作为成功断言。LIVE 实测结果创建路由返回 HTTP 202 PENDING嵌套 cancel 路由返回 HTTP 200轮询观测到RUNNING之后跟随CANCELLED最终 run ID 为1fa2c79e-...。这证实取消不是瞬时的——请求可能已经进入执行阶段RUNNING取消只是把它终止并落库为终态。五、SSE 断线重连用 event_index 做断点续传sse_reconnect.pybackgroundtruestreamtrue意味着任务在后台跑、事件以 SSE 推给客户端同时事件带单调递增的event_index。如果客户端掉线可以带着最后收到的event_index重新接上并补齐错过的所有事件——这是该示例要演示的能力。为什么用裸 httpx源码文件顶部的说明写得很清楚AgentOSClient目前尚未暴露 resume 方法因此该示例刻意使用裸httpx同时处理最初的 SSE 响应与 resume 请求。关键机制客户端自己解析 SSE逐行读event:/data:/ 空行分隔把 JSON 载荷收进事件字典并持续追踪run_id、session_id、last_event_index见iter_sse/disconnect_after_events。为演示断线客户端读满EVENTS_BEFORE_DISCONNECT 2个事件后就主动break断开连接。断线后带着游标 POST 到 resume 路由data {session_id: session_id} if last_event_index is not None: data[last_event_index] str(last_event_index) async with client.stream( POST, f/agents/{AGENT_ID}/runs/{run_id}/resume, datadata, ) as response: # 从 resume 响应中继续消费事件resume 会回放last_event_index之后错过的全部事件客户端打完收工前打印实际收到的event_index区间用于核对。两条 demo 路径--demo run新起一个后台 SSE run断开后 resume。--demo continue先让 run 在确认型工具reserve_triptool(requires_confirmationTrue)处暂停收到RunPaused事件后把tools数组中待确认的工具标记confirmed: true回传给 nested/continue携带backgroundtrue, streamtrue在续跑流中断开再 resume。LIVE 实测结果含关键佐证新 run 流在event_index1之后断开resume 时收到catch_up与subscribed两条元数据事件随后回放了编号 2..46 的全部事件最后收于RunCompleted。续跑流观测到RunPaused→ 批准待决工具 → 断开时已收到RunContinued、ToolCallStarted→ resume 回放事件 2..14 →ToolCallCompleted后以RunCompleted收尾。这里catch_up元数据证实了resume 是一段追赶catch-up再订阅subscribe的服务端设计回放区间 2..46 / 2..14 直接验证了事件游标从断开点精确续传。六、持久化检查点列出边界并从 message_index 续跑checkpoints.pycheckpoints.py演示的是fork式续跑run 在tool-batch粒度下会留下持久化检查点边界HTTP 客户端可以列出它们、选中一个靠内的边界从那里长出一个继承了源 run 全部上下文的新 run。配置与流程Agent 开启检查点checkpointtool-batch该值表示每个工具调用批处理后形成检查点。客户端流程分三步正常跑一个含多次工具调用的 run消息要求模型对 Paris 和 Kyoto 各调用一次get_city_fact拿到run_id、session_id。列出检查点时间线checkpoints_response client.get( f/agents/{AGENT_ID}/runs/{run_id}/checkpoints, params{session_id: session_id}, ) checkpoints checkpoints_response.json()[checkpoints] for checkpoint in checkpoints: print(f- message_index{checkpoint[message_index]} freason{checkpoint[reason]} status{checkpoint[status]})每个检查点有message_index、reason、status还有一个is_latest布尔标记用于区分靠内边界与最新边界。 3. 挑一个非最新的 interior 边界POST 到/continuecontinue_response client.post( f/agents/{AGENT_ID}/runs/{run_id}/continue, data{ session_id: session_id, continue_from: str(message_index), # 续跑的坐标是 message_index input: Continue from here, but discuss only Paris., stream: false, }, ) continued continue_response.json() print(fNew run ID: {continued[run_id]}) print(fSource run ID: {continued.get(forked_from_run_id)})两个必须牢记的细节checkpoint_id只是展示用的序号display ordinal不是续跑坐标续跑坐标一律是message_index。续跑产生的是兄弟 run新 run 用自己的run_id并在forked_from_run_id字段里回填源 run ID。LIVE 实测结果模型确实为 Paris 与 Kyoto 调用了get_city_factnested checkpoint 端点返回了一个靠内的message_index5检查点状态RUNNING和一个终态message_index6边界以continue_from5提交后创建了完成态的兄弟 run源 run ID 出现在forked_from_run_id最终返回了只讨论 Paris 的回答。从源码看continue_from除了整数索引还支持end与last_user两种字面量_resolve_continue_from于 agent/_run.py。示例选择整数边界是因为它要精确演示回到某次工具调用之后重新分叉。七、后台 Hook全局开关与按 Hook 细粒度控制hooks_in_background.py长耗时 LLM 调用之外的旁路工作记日志、发通知、跑 Agent 评测如果同步执行会拖慢响应。hooks_in_background.py给出两层控制且刻意用两种 server 模式区分二者的语义。模式一--mode global—— AgentOS 级全局开关global_agent_os AgentOS( idglobal-background-hooks-os, agents[global_hooks_agent], run_hooks_in_backgroundTrue, # 全局开关 )AgentOS(run_hooks_in_backgroundTrue)会把所有非 guardrail 的 pre/post hook 调度为 FastAPI 后台任务。源码侧的实现证据在 agent/_hooks.py 等处agent._run_hooks_in_background is True且存在后台任务集合时hook 被投递到后台执行。关键例外guardrail 始终同步执行以保证它仍能在不安全输入/输出抵达模型或用户之前完成拦截。文档用一行 curl 即可验证streamfalse、附带session_idcurl -X POST http://localhost:7777/agents/global-hooks-agent/runs \ -F messageExplain background hooks in one sentence. \ -F streamfalse \ -F session_idglobal-hooks-demo模式二--mode mixed—— 保留阻塞项、按 Hook 精细化mixed 模式把run_hooks_in_background留在默认值因此普通 hook 与第一个 eval 会阻塞响应只有显式标记的项在响应返回后被调度record_blocking_result普通 post hook同步执行。blocking_eval第一个AgentAsJudgeEval默认同步阻塞型完整性检查。send_notification用装饰器hook(run_in_backgroundTrue)标记的通知 hook异步执行函数体内await asyncio.sleep(1)模拟耗时。background_eval第二个AgentAsJudgeEval(..., run_in_backgroundTrue)评测也后台化。curl -X POST http://localhost:7777/agents/mixed-hooks-agent/runs \ -F messageExplain mixed hook execution in one sentence. \ -F streamfalse \ -F session_idmixed-hooks-demoREADME 明确全局开关与 per-hook 控制同样适用于 AgentOS 的 Team 与 Workflow因此这套心智模型可以平移到三种组件。LIVE 实测结果来自 TEST_LOG两种 server 模式的 HTTP run 都以COMPLETED返回。mixed 模式下阻塞的完整性评测在 run 响应返回之前结束并报告 100% 通过率随后响应返回而通知与后台清晰度评测仍在继续执行——后台评测同样以 100% 通过率完成并把 eval run 持久化。这直观证明了阻塞项在前、后台项在后的执行时序。八、上传预处理pre_hook 把 .zip 替换成内部文件unpack_archives.py最后一个示例回答一个真实痛点AgentOS 接受.zip上传但没有任何模型提供方会解压它——压缩字节原样被转发给模型模型看到的是一个 blob 而不是其中的文件。unpack_archives.py的方案是不要求 AgentOS 解压而是用 pre_hook 在上传落地后、模型调用前改写run_input.files。Hook 的实现逻辑def unpack_archives(run_input: RunInput) - None: if not run_input.files: return unpacked: list[File] [] for uploaded in run_input.files: if uploaded.mime_type ! application/zip or not uploaded.content: unpacked.append(uploaded) continue with zipfile.ZipFile(io.BytesIO(uploaded.content)) as archive: for entry in archive.infolist(): if entry.is_dir() or entry.filename.startswith(__MACOSX/): continue # 跳过 Finder 元数据伴随项 name entry.filename.rsplit(/, 1)[-1] if name.startswith(._): continue mime_type, _ mimetypes.guess_type(name) if mime_type not in File.valid_mime_types(): mime_type None # File 会校验 mime_type超出白名单置空 unpacked.append(File( contentarchive.read(entry), filenamename, formatname.rsplit(., 1)[-1].lower(), mime_typemime_type, )) run_input.files unpacked值得注意的工程细节macOS Finder 兼容Finder 写的 zip 会为每个文件附带一个隐藏的__MACOSX/._name元数据项这里按目录项与__MACOSX/前缀双重跳过._前缀也单独兜底。MIME 校验File类会校验mime_type因此 hook 逐条目用mimetypes.guess_type解析并只在白名单内保留白名单外的置None见File.valid_mime_types()。Hook 本身只操作run_input.files完成后模型拿到的就是 zip 内的真实文件清单。Agent 端配置就是把普通函数挂到pre_hooksunpack_agent Agent( idunpack-agent, nameUnpack Agent, modelOpenAIResponses(idgpt-5.5), dbdb, pre_hooks[unpack_archives], instructionsAnswer only from the attached files and quote the exact values you read., )上传方式为 multipart POST 到/agents/unpack-agent/runs也可从 AgentOS UI 上传 zip 后直接询问内容。LIVE 实测结果测试覆盖了两种压缩包——一个 DEFLATE zip内含invoice.txt、notes.md与一个 macOS Finder zip单个 PDF 加__MACOSX伴随项。两个 run 都返回COMPLETEDpre-hook 在模型调用前把每个 zip 替换成其内容Agent 引用了只存在于压缩包内部的值AGNO-9193、4242.00 EUR、Acme Corp、ZEBRA-7Finder 包正确解析出 PDF 并跳过__MACOSX边车项。作为对照去掉 pre-hook 后同样的上传会在模型提供方处以不支持的 MIME 类型失败——因为没有任何 provider 会解压归档。九、跨组件差异continue 契约并不统一README 特别提醒Agent、Team、Workflow 三种组件并不共享同一条 continue 契约这是客户端最容易写错的地方。三个差异点必须区分AgentTeamWorkflow/continue上携带决议的字段toolsrequirementsstep_requirements同时接受input、continue_from、fork、regenerate、replace_original、additional_instructions、session_id、user_id、stream、background与 Agent 相同session_id、user_id、stream、background、factory_input出错事件RunErrorTeamRunErrorWorkflowError续跑的操作要诀把收到的决议数组原样回传并补充新的决议数组里既带已决议项也带新待决项因此只处理仍处于等待状态awaiting decision的条目即可。一次 continue 之后 run可能再次暂停下一个工具调用或步骤仍可能需审批所以要以 status 为循环条件反复 continue不要认为/continue的响应就是终点。run_id与session_id在/continue后都保持不变——它是同一个 run唯一例外是regeneratetrue保留session_id返回新的run_id旧 run 被打上REGENERATED标记见第二节而 Workflow 没有 regenerate 能力。另外暂停 → 继续的 HTTP 全流程还可在 Team 的 human-in-the-loop 示例中看到跨 HTTP 的完整驱动方式见cookbook/05_agent_os/05_human_in_the_loop目录相关示例。后台模式的所有接口都要求被服务的 Agent 挂载数据库如SqliteDb因为后台任务、轮询与 resume 全部依赖持久化的 run 状态。十、可验证性与测试结论该目录的验证不仅是文档式的。TEST_LOG 的 Validation 一节给出了多层自动化检查结果库级模式校验pytest cookbook/scripts/tests/test_check_cookbook_pattern.py -q→3 passed递归模式校验本课共检查 5 个 Python 文件0 违规五个应用全部成功导入并构建出 OpenAPI 文档嵌套的 poll、cancel、resume、checkpoint、continue 路由均存在定向 Ruff 检查通过陈旧模型、废弃 checkpoint、emoji 与旧 background 文件夹扫描均无命中git diff --check通过。结合源码交叉核对状态枚举定义在 run/base.py后台 run 先持久化 PENDING、再以 asyncio 任务执行、最后返回 202 的实现位于 agent/_run.py全局后台 Hook 的投递判断在 agent/_hooks.py。由此可以把本文所有行为断言都追溯到代码层便于你在自己的集成中对照排查。小结一条可落地的运行生命周期心智模型把这六份示例连起来看AgentOS 的运行生命周期是一条清晰的主线后台提交backgroundtrue 数据库支撑 → HTTP 202/PENDING → 轮询嵌套路由读终态取消nested/cancel路由把 run 落为CANCELLED且保留已完成内容断线续传SSE 事件带event_index断线后用/resumelast_event_index追赶错过的区间检查点续跑tool-batch粒度留下message_index边界continue_from长出带forked_from_run_id的兄弟 run后台 Hook全局run_hooks_in_backgroundTrue或 per-hookhook(run_in_backgroundTrue)/AgentAsJudgeEval(run_in_backgroundTrue)guardrail 始终同步预处理pre_hook 改写run_input.files把模型提供方做不了的事解压 zip在调用前完成。需要再次强调的硬性约定是状态只从持久化 run 输出读取、取消的流收在 completed 事件上、三个组件的 continue 契约字段各不相同。掌握这些之后你就能在自己的 AgentOS 部署里安全地实现长任务后台化 断线可恢复 关键节点人工审批的完整运行治理方案。【免费下载链接】agnoBuild, run, and manage agent platforms.项目地址: https://gitcode.com/GitHub_Trending/ag/agno创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表