agno AgentOS 怎么提交后台 run 轮询状态、取消任务,并在断线后用 SSE 续接?
【免费下载链接】agnoBuild, run, and manage agent platforms.项目地址: https://gitcode.com/GitHub_Trending/ag/agno
当你通过 HTTP 调用 agno AgentOS 服务时,会碰到三类实际问题:长任务不想让请求一直挂着,希望提交后就拿到一个 run 标识再去轮询;任务跑偏了,需要主动取消并确认它确实停了;流式客户端中途断线,希望能从断点把 SSE 事件补回来。agno 的 cookbook 中cookbook/05_agent_os/04_run_lifecycle/目录提供了这三个能力的完整可运行示例:background_run.py(后台提交 + 轮询)、cancel_run.py(取消 + 确认终态)、sse_reconnect.py(断线后用/resume续接)。本文按这三条路径逐一演示提交、轮询、取消与续接的完整 HTTP 契约。
前提条件(来自 README):
- 已按仓库
scripts/demo_setup.sh初始化 cookbook 环境,并设置export OPENAI_API_KEY=your-key(your-key替换为你自己的 OpenAI 密钥,示例代码用OpenAIResponses(id="gpt-5.5")作为模型); - 后台 run 依赖数据库持久化 run 状态:被服务的 Agent 上必须配置数据库(示例用
SqliteDb),否则轮询和取消读不到持久化状态。后台模式不支持 remote agents; - 每个示例文件都是一个 FastAPI 服务,都监听
http://localhost:7777,同一时间只能启动一个。
启动服务端:一个文件既是服务又是客户端
三个示例结构一致:不带参数运行时启动 AgentOS 服务,带--demo参数时切换为调用已运行服务的客户端。以 background_run.py 为例,终端 1 启动服务端:
.venvs/demo/bin/python cookbook/05_agent_os/04_run_lifecycle/background_run.py服务端的 Agent 定义保留了后台 run 的关键前提——挂在Agent上的db参数:
db = SqliteDb( id="background-run-db", db_file="tmp/agent_os_background_run.db", ) background_run_agent = Agent( id="background-run-agent", name="Background Run Agent", model=OpenAIResponses(id="gpt-5.5"), db=db, instructions="Answer clearly and keep the final response under three paragraphs.", ) agent_os = AgentOS(id="background-run-os", agents=[background_run_agent]) app = agent_os.get_app()agent_os.serve(app=app)默认在localhost:7777上监听(serve的host/port默认值为localhost和7777,也可被环境变量AGENT_OS_HOST、AGENT_OS_PORT覆盖)。
提交后台 run 并轮询到终态
终端 2 运行客户演示:
.venvs/demo/bin/python cookbook/05_agent_os/04_run_lifecycle/background_run.py --demo契约分三步,示例代码(httpx.AsyncClient,base_url="http://localhost:7777")逐一对应:
1. 提交。POST /agents/{agent_id}/runs,表单字段带background=true、stream=false、session_id:
response = 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, }, )成功判定:HTTP 状态码必须是202,响应体status必须是PENDING;示例代码对这两个条件不满足就直接抛RuntimeError。从响应体里取出run_id和session_id,二者是后续轮询、取消、续接的全部凭据。
2. 轮询嵌套 run 路由。GET /agents/{agent_id}/runs/{run_id},用查询参数带session_id,循环读取status字段直到进入终态集合{CANCELLED, COMPLETED, ERROR}(示例每 0.5 秒轮询一次,总超时 120 秒):
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"}: break await asyncio.sleep(0.5)注意 README 强调的一个细节:RunStatus有七个成员PENDING、RUNNING、PAUSED、COMPLETED、CANCELLED、ERROR、REGENERATED,status 要从持久化的 run output 里读,run 事件流中除了WorkflowPaused之外没有事件携带status字段——所以轮询嵌套路由是正确姿势,而不是解析事件。
3. 判定完成。示例最后断言completed["status"] == "COMPLETED",并打印completed.get("content")作为 run 的结果。
RunStatus的完整定义见 run/base.py,其中REGENERATED是/continue?regenerate=true留下的标记状态。
取消一个已接受的后台 run
cancel_run.py 的前半段与上面完全相同:同样是background=true、stream=false提交,同样等待 HTTP 202 /PENDING。差别在提交之后、轮询之前,多一步取消调用:
.venvs/demo/bin/python cookbook/05_agent_os/04_run_lifecycle/cancel_run.py .venvs/demo/bin/python cookbook/05_agent_os/04_run_lifecycle/cancel_run.py --democancel_response = await client.post( f"/agents/{AGENT_ID}/runs/{run_id}/cancel", params={"session_id": session_id}, ) cancel_response.raise_for_status()即POST /agents/{agent_id}/runs/{run_id}/cancel,用查询参数带session_id。随后沿用同一个轮询函数读持久化状态,直到观察到CANCELLED,示例以cancelled["status"] != "CANCELLED"抛错作为失败判定。
两条需要写进客户端逻辑的边界:
- 取消不等于丢弃已完成的输出。README 说明被取消的 run 会保留已做完的工作:agents 和 teams 保留在
content里,workflow 保留在step_results里; - 取消后流式端点的收尾事件是 completed,不是 cancelled。取消会发出成对事件(先 cancelled、再 completed),所以如果你用 SSE 观察取消,流的结束信号是 completed 事件;真正可靠的终态仍以轮询到的持久化
CANCELLED为准。
断线后用 SSE 续接:跟踪 event_index,再打 /resume
第三条路径用 sse_reconnect.py。它有一个重要前提:AgentOSClient目前没有暴露 resume 方法,所以示例刻意用裸httpx处理原始 SSE 响应和续接请求。
.venvs/demo/bin/python cookbook/05_agent_os/04_run_lifecycle/sse_reconnect.py .venvs/demo/bin/python cookbook/05_agent_os/04_run_lifecycle/sse_reconnect.py --demo run .venvs/demo/bin/python cookbook/05_agent_os/04_run_lifecycle/sse_reconnect.py --demo continue--demo run演示新后台流的续接,--demo continue演示「先暂停、后台继续、再断线续接」的更复杂路径。两者的共同机制如下。
1. 消费流时持续记录坐标。提交时用background=true、stream=true打开 SSE 流,客户端逐事件记录三类状态:事件里的run_id、session_id,以及最大的event_index。示例刻意只读前 2 个事件就断开(EVENTS_BEFORE_DISCONNECT = 2),模拟网络断开:
state["run_id"] = event.get("run_id") or state["run_id"] state["session_id"] = event.get("session_id") or state["session_id"] if event.get("event_index") is not None: state["last_event_index"] = event["event_index"]SSE 解析本身是标准的event:/data:行协议,[DONE]作为结束标记,不解析为事件。
2. 重连。用run_id、session_id和断点前收到的最后event_index调POST /agents/{agent_id}/runs/{run_id}/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", data=data, ) as response: response.raise_for_status() async for event in iter_sse(response): ...resume 流会补齐断线期间错过的剩余事件,直到 run 结束。验证方式示例给得很直接:resume 必须返回至少一个事件(否则抛The resume endpoint returned no events),然后打印本次收到的event_index范围(Resumed event_index range: min..max),你可以用它核对断点前后的事件没有丢、没有乱。
3.continue路径的额外一步。--demo continue场景里 Agent 带一个requires_confirmation=True的工具,初次运行会在RunPaused事件处停住。RunPaused事件携带run_id、session_id和待确认的tools数组;客户端把其中requires_confirmation的条目加上confirmed=True后,原样连同新决定一起提交到嵌套/continue路由(agent 的字段名是tools),并带background=true、stream=true,之后断线再 resume 的流程与上面一致。README 提醒:continue 后 run 仍可能再次暂停,应基于 status 循环处理,不要认为一次/continue就是终态;且同一个 run 在/continue后run_id和session_id都保持不变。
验证清单与限制汇总
三条路径的成功判据都来自示例代码的断言,可直接作为你自己客户端的验收条件:
| 路径 | 关键请求 | 成功判据 |
|---|---|---|
| 后台提交 + 轮询 | POST /agents/{id}/runs(background=true)→GET /agents/{id}/runs/{run_id}?session_id=... | 提交返回 HTTP 202 且status=PENDING;轮询到COMPLETED,结果在 run output 的content |
| 取消 | POST /agents/{id}/runs/{run_id}/cancel?session_id=... | 取消调用raise_for_status()通过;轮询到CANCELLED;已完成的输出仍保留在content |
| SSE 续接 | 记录event_index→POST /agents/{id}/runs/{run_id}/resume(带session_id与last_event_index) | resume 流返回非空事件;打印的event_index范围覆盖断点之后 |
限制方面,README 明确了两条硬性约束:后台 run 要求被服务的 Agent 配置数据库(因为 detached task 和 poll 都读持久化状态),且该模式不支持 remote agents。端口方面,三个示例都固定监听 7777,启动多个示例前必须先停掉上一个。
如果你想接着做暂停/继续(human-in-the-loop)场景,README 指向了同目录体系下的 user_input.py 演示 team 的 pause/continue;而 checkpoint(tool-batch断点续跑)、后台 hooks 等相邻能力则分别在同目录的checkpoints.py和hooks_in_background.py中,不在本文范围内。
【免费下载链接】agnoBuild, run, and manage agent platforms.项目地址: https://gitcode.com/GitHub_Trending/ag/agno
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考