The pattern
Most agent setups hand work to a subagent and wait. The async version runs the other way round. The orchestrator starts a subagent on its own thread, gets a task ID back straight away, and carries on talking to the user. When the subagent finishes, it notifies the orchestrator itself. Nothing sits in a polling loop.
LangChain shipped this in Managed Deep Agents v0.10 on 29 October: you add async to a subagent definition and the agent "can keep talking to the user while the subagent(s) run(s)", it says. Two days earlier the team described its own design agent, which uses the same pattern in production. On a 52-slide reskin, it says, "the main agent ran for about an hour while its subagents collectively worked for more than six hours", and the conversation was never blocked.
You don't need LangChain to build this. The pattern comes down to a task registry, a notify-on-complete hook and a rule for when a result is allowed to interrupt the orchestrator.
When to use it and when not
Use it for:
Long jobs that would otherwise block the chat. Research sweeps, batch rendering, multi-file rewrites, anything over a minute or two.
Fan-out. Several workers on independent parts of one job.
Chat surfaces where people redirect mid-job. Slack, Discord, a support inbox. The user can say "drop the pricing section" while workers run, and the orchestrator can steer or cancel the relevant task.
Skip it for:
Quick lookups. If the answer comes back in a few seconds, a normal blocking subagent is simpler and easier to debug.
Work that needs strict isolation. In Managed Deep Agents an async subagent "shares the agent's sandbox, so it picks up the files the agent already wrote". That's convenient, and it also means a worker can read everything the orchestrator can. Anything touching customer secrets or untrusted input belongs in its own sandbox.
Jobs without clear file ownership. Two workers editing the same file at once will overwrite each other. If you can't divide the output into files each worker owns, run them in sequence.
Anything you can't afford to debug blind. The managed version is in public beta, and the published material says little about retries, cost caps or concurrency limits. The Deep Agents docs note only that each active run takes a worker slot and launches queue when you run out.
How it works (input → step → output)
Input: a user request big enough to split, for example "Reskin this 52-slide deck to our new brand."
Step 1, plan and assign. The orchestrator splits the job into tasks and writes a short brief for each: role, context, which files it owns, and how to check its own work. The design agent writes exactly this kind of profile for every subagent.
Step 2, start in the background. For each task the orchestrator calls a start tool and gets an ID back immediately. It tells the user what's running and stays available.
Step 3, workers run and report. Each worker writes only its own files and saves progress to disk. It can send progress updates mid-job and must send a final report.
Step 4, deliver by state. This is the core of the pattern. What happens to a finished result depends on what the orchestrator is doing at that moment:
Orchestrator state | What happens to the result |
|---|---|
Busy (mid-run) | Checked before its next model call, so the result lands mid-run |
Idle | The subagent wakes it with a new run |
Waiting on a user approval | The approval is left alone; the result arrives after the user answers |
Output: merged reports, flagged gaps, and follow-up tasks if needed.
Components
Task registry. A table of
task_id, owner_files, status, brief, last_update, result. LangChain's statuses are a sensible set:success,error,cancelled,timeout,waiting, plusrunningfor in-progress work.Task tools for the orchestrator. Deep Agents exposes five: start, check, update (send new instructions to a running task), cancel and list. The design agent adds
resume_task,report_progressfor workers, andschedule_wakeup, which gives the main agent a timer to start another run and keep going.Notification inbox. Where workers drop results. Each result should be delivered exactly once; the LangSmith docs say the same of their implementation.
Pre-model-call check. A hook that runs before every orchestrator model call, drains the inbox and appends results as messages. LangChain caps this check at 5 seconds so it can't stall the agent.
Wake trigger. If the orchestrator is idle, a new result starts a fresh run.
Approval gate. If the orchestrator is waiting on the user, results queue until the user answers.
File ownership map. Each worker writes only to its own paths in a shared project folder, and reads anything.
Minimal implementation
Framework-agnostic pseudo-code. A queue (Redis, a database table, or a folder of JSON files) is enough.
registry = {} # task_id -> {brief, owns, status, result}
inbox = Queue()
def start_task(brief, owns):
id = new_id()
registry[id] = {brief, owns, status: "running"}
spawn(worker, id, brief, owns) # thread, job queue, or n8n sub-workflow
return id # return immediately
def worker(id, brief, owns):
try:
result = run_agent(brief, write_allowlist=owns, timeout=30*60)
inbox.put({id, status: "success", result})
except Timeout:
inbox.put({id, status: "timeout"})
except Exception as e:
inbox.put({id, status: "error", error: str(e)})
def before_model_call(messages):
for item in inbox.drain(max_wait=5): # each item delivered once
registry[item.id].update(item)
messages.append(system_note(item))
return messages
def on_inbox_item(item):
state = orchestrator.state
if state == "idle":
orchestrator.start_run() # wake it
# "busy": before_model_call picks it up
# "awaiting_approval": leave queued until the user answersThe n8n version: one main chat workflow, plus one sub-workflow per task started with Execute Workflow and "wait for completion" switched off. Each sub-workflow ends by writing a row to a results table and calling a webhook on the main workflow. The webhook checks a state field you keep per conversation: if idle, it posts the result into the chat and starts the next LLM step; otherwise it leaves the row for the next LLM step to read.
Enforce owns in code: a write tool that rejects paths outside the allowlist does more than any prompt instruction.
Failure modes and evals
Silent hangs. A worker dies and never reports. Give every task a timeout that writes a
timeoutresult, and have the orchestrator's list tool show tasks that have gone quiet for too long. Pair this with a durable step journal so a resumed worker doesn't redo finished steps.Duplicate delivery. Retries push the same result twice and the orchestrator summarises it twice. Mark inbox items consumed by ID. Eval: replay one result twice and check the user sees it once.
Write collisions. Two workers touch the same file. Eval: give two tasks overlapping ownership and confirm the second write is rejected.
Interrupted approvals. A result arrives while the user is answering a yes/no question and the orchestrator changes the subject. Eval: start a task, trigger an approval, finish the task mid-approval, and check the approval prompt is unchanged.
Stale steering. The user changes the brief but a worker keeps the old one. Eval: update a running task and confirm its next progress report reflects the change. Note that in Deep Agents' fork mode, later parent messages are not forwarded to the child.
Runaway cost. Six hours of worker time is cheap only if you meant it. Log tokens per task and set a budget per job. Track cost per acted-on finding to see which workers earn their keep.
Eval gaps. LangChain's own
mda evalcan't evaluate an agent that declares async subagents, the docs say. Budget for writing your own end-to-end test.
Keep the orchestrator itself small and predictable, as in the thin orchestrator pattern: its job is to route, track and merge, while the workers do the long thinking.
Build-it-this-weekend exercise
Build a "research brief" bot with one orchestrator and three async workers.
Set up the registry. A SQLite table or Airtable base with the columns above.
Write three briefs for a topic you care about: competitors, pricing pages, recent customer complaints. Each worker owns one file:
competitors.md,pricing.md,complaints.md.Wire start and notify. Background job or n8n sub-workflow per worker; each writes its file, then a result row, then pings the orchestrator.
Add the pre-call check that drains new rows before every orchestrator LLM call.
Test the three states. Chat with the orchestrator while workers run (busy). Go quiet and confirm a finished worker wakes it (idle). Ask it to confirm something, let a worker finish mid-question, and check the question survives (waiting).
Break it on purpose. Kill one worker, push a duplicate result, and point two workers at one file. Each should fail loudly.
When all six pass, point it at your real long jobs.
Sources
LangChain, "Managed Deep Agents v0.10: Browser use and asynchronous subagents", 29 October 2026: langchain.com/blog/managed-deep-agents-browser-use-and-asynchronous-subagents
LangChain, "How We Built Our Design Agent", 27 October 2026: langchain.com/blog/design-agent
LangChain Deep Agents docs, Async subagents (accessed 31 October 2026): docs.langchain.com/oss/python/deepagents/async-subagents
LangSmith docs, Managed Deep Agents subagents (accessed 31 October 2026): docs.langchain.com/langsmith/python/managed-deep-agents-subagents

