lolspider / notes
Clipping · 6 分钟

Agents Are Going Async

Imagine a chief of staff who disappears every time you hand them a big project and only comes back once it's done. You'd probably fire them ...

x.com @sydneyrunkle

📝 摘要

文章用一个「幕僚长」的类比说明智能体必须具备两种属性:响应性(responsive)——随时接收新指令并保留此前全部上下文;生产力(productive)——同时推进多项大型任务。传统 ReAct 循环中,每个长时间工具调用都会阻塞循环,其他任务只能排队,无法同时满足这两点。作者观察到生态正在收敛到「一个常驻用户侧的 orchestrator + 若干后台 async subagents」的拆分:Claude Code 默认在后台运行子智能体,OpenAI 的 dots 把工作交给后台 worker,DeepSeek Harness 的 super agent 也采用 router 与并行后台 worker 的架构。LangChain 将这一模式引入 Deep Agents,推出 async subagents。

核心概念: 把子智能体当作 asyncio.create_task 或一个尚未 await 的 Promise——调用立即返回,工作在后台独立进行,结果稍后回传。这样 agent 能承担的工作量随后台 worker 数量增长,而不是受限于单个循环的长度。

关键技术栈 / 关键要点:

  1. 五个管理工具 — start_async_task 立即返回;check_async_task 取状态与结果;update_async_task 向运行中任务追加指令;cancel_async_task 终止;list_async_tasks 列出全部任务。
  2. update_strategy 语义 — "interrupt"(默认)停止当前运行并以新指令重启,适合纠正(如「改用 Postgres」);"enqueue" 等当前运行结束后再执行,适合追加(如「跑完顺便跑测试」)。
  3. 结果回投机制 — 所有未完成任务列在 orchestrator 的 system prompt 中;orchestrator 忙碌时在每次模型调用前主动收取结果,空闲时由子智能体唤醒它开新一轮,等待审批时则保留结果直到用户答复。
  4. 审批隔离 — 需要审批的子智能体显示为 waiting,用户在其自己的线程中答复,不打断 orchestrator;Slack 场景下审批请求回帖到原始线程。
  5. 接入方式 — Deep Agents 提供 Python/JavaScript 版本,Managed Deep Agents 只需给子智能体加 async: True;每个 served agent 还自带一个通用子智能体的异步副本,可在运行时决定前台或后台执行。OpenAI 的 async tool calling 预示该模式会从子智能体推广到所有工具。

关键结论 / 实践建议: 异步子智能体把 agent 架构的扩展维度从「单循环长度」换成「后台 worker 数量」,是长任务与多任务并发的关键架构转变。任务通知目前仍是 beta、API 可能变化,生产采用时需预留兼容成本;可用官方 async-deep-agents 仓库(Python/TypeScript 的 supervisor + researcher/coder 示例)快速验证。


Imagine a chief of staff who disappears every time you hand them a big project and only comes back once it's done. You'd probably fire them immediately. A good chief of staff keeps projects moving in the background while staying reachable and keeping you updated along the way. As we ask agents to work toward bigger goals, they need the same two properties. An agent has to be responsive, acting on a new instruction right away with the context of everything before it, and productive, making progress on many large tasks at once.

The architecture we've used to build agents for a while can't meet both requirements. In a standard ReAct loop, each long tool call blocks the loop and every other task queues behind it. Instead, we're seeing the ecosystem converge on a split between one agent that stays with the user and background workers that do the long work. Claude Code runs subagents in the background by default, OpenAI's dots hand work to background workers to make progress on several things at once, and DeepSeek Harness built its super agent around a router that talks to people and background workers that run tasks in parallel.

We're bringing this pattern to Deep Agents with async subagents. An orchestrator stays available to the user and keeps the conversation's context organized, while async subagents run as background workers and report back when they finish. The amount of work the agent can take on then grows with the number of background workers instead of the length of one loop.

How async subagents work

An agent runs in a loop. The model calls a tool, waits for the result, and decides what to do next. Historically, tools and subagents blocked that loop until they returned, like code that awaits each slow call in turn. An async subagent works like a task started with asyncio.create_task or a Promise you don't await yet. The call returns right away, the work runs independently in the background, and the result comes back later.

The orchestrator hands work to async subagents and stays free to talk to the user.

Async work depends on two properties of the system:

  • The user can reach the orchestrator. The orchestrator is the agent the user interacts directly with. Subagents no longer hold its loop, so the user can reach it whenever its own loop isn't busy, instead of waiting for every subagent to finish.
  • Tasks run in parallel without blocking. The orchestrator starts subagents as work comes in, instead of waiting for a whole batch to return.

The orchestrator manages async subagents with five tools:

  • start_async_task starts a subagent on its own thread and returns right away.
  • check_async_task gets a task's status and, once it finishes, its result.
  • update_async_task sends a running task new instructions.
  • cancel_async_task stops a running task.
  • list_async_tasks lists every task and its status.

Steering a running subagent is separate from reaching the orchestrator. When the orchestrator sends a follow-up with update_async_task, the update_strategy field on that subagent's definition decides what happens:

  • "interrupt" (the default) stops the current run and restarts the subagent with the new instruction. Use it for a correction like "use Postgres instead."
  • "enqueue" holds the follow-up until the current run finishes. Use it for an addition like "run the tests when you're done."

How notifications work

Every unfinished task is listed in the orchestrator's system prompt, so it always knows what's in flight. It can poll with check_async_task or tasks can report back on their own:

  • If the orchestrator is busy, it checks its unfinished tasks before each model call and picks up the result mid-run.
  • If it's idle, the subagent wakes it with a new run.
  • If it's paused on an approval, the approval is left alone, and the result arrives once the user answers.

An async subagent reports back whether the orchestrator is busy, idle, or paused on an approval.

A subagent that needs approval shows up as waiting, and the user answers on the subagent's own thread without interrupting the orchestrator. In Managed Deep Agents on Slack, the request posts back to the original thread.

We expect this pattern to generalize beyond subagents to tools across the board. OpenAI recently added support for async tool calling, where the model keeps working after it calls a tool and your application sends the result back in a later request.

Use async subagents

Async subagents are available in Deep Agents for Python and JavaScript, and in Managed Deep Agents, where making a subagent async takes one field:

python
from managed_deepagents import define_deep_agent

agent = define_deep_agent(
    name="research-assistant",
    model="openai:gpt-5.5",
    subagents=[
        {
            "name": "researcher",
            "description": "Researches a topic in the background.",
            "system_prompt": "Research the topic and report your findings.",
            "async": True,
        },
    ],
)

In Managed Deep Agents, every served agent also gets an async copy of the general-purpose subagent, so it can decide at runtime whether to run delegated work in the foreground or the background.

Task notifications are in beta, so the API may still change. The async-deep-agents repo has a working supervisor with researcher and coder subagents in Python and TypeScript.

Give async subagents a try, and let us know what you think in GitHub issues or on the forum.