Parallel / Swarm / Networked Architectures
No central decider. Agents read a shared event bus, pick up work asynchronously, and write results back. LangGraph explicitly supports a "Swarm Architecture" for decentralized, dynamic environments, and Matrix (arXiv:2511.21686) carries both control and data flow as serialized messages on distributed queues to remove the orchestrator bottleneck. The tradeoff is explicit: you give up determinism and traceability for scalability. Swarm fits tasks with many independent sub-problems and does not fit tasks that need a single coherent plan.
Learning Objectives
- Explain why a supervisor becomes a bottleneck at scale and how a shared queue removes the central decider.
- Decide whether a task fits a swarm or a supervisor from its independence, duration variance, ordering needs, and debuggability needs.
- Run the three-strategy demo and explain why pull-based scheduling beats a bad fixed assignment on variable-duration tasks.
- Describe starvation and hot-spotting, and name the mitigations: priority queues with aging, worker specialization, and back-pressure.
- Apply the Ship It checklist (durable queue, idempotent workers, per-task trace IDs, back-pressure) to a production swarm design.
Problem
A supervisor handles a few workers fine. Hundreds is another matter. Every decision about who does what funnels through one agent, so the supervisor becomes the bottleneck, and one slow planning step stalls the whole system.
Swarm architectures flip the design. Workers pick tasks off a shared queue instead of waiting for a planner to dispatch them, and the coordination lives in the semantics of the event bus. There is no orchestrator, so the system scales until the queue stops scaling.
Concept
The shape
┌──── shared queue ────┐
│ │
┌────────┼────────┐ ◄──────┬───┘
▼ ▼ ▼ │
Worker Worker Worker Worker
A B C D
│ │ │ │
└────────┴────────┴─────────┘
│
▼
results pool
There is no orchestrator. A worker loops: pull a task, process it, write the result, and optionally enqueue follow-ups.
When swarm fits
- Many independent tasks. Scraping, transforming, classifying. The tasks do not depend on each other.
- Variable-duration work. If some tasks take 100ms and others take 10s, a swarm balances load on its own because fast workers pull the next job sooner. A supervisor has to predict durations up front.
- Throughput over determinism. You care about total completion time, not strict ordering.
When swarm fails
- Ordered workflows. If step 3 needs step 2's output, a swarm can start step 3 before step 2 is done.
- Global-plan tasks. Complex research questions need a planner. A swarm of researchers produces independent facts, not a coherent report.
- Debugging. Without a central log, and with asynchronous work, reproducing a bug is expensive.
Matrix (arXiv:2511.21686)
Matrix is the 2025 paper that takes swarm to its conclusion. Both control flow and data flow are serialized messages on distributed queues, with no central coordinator. Fault tolerance comes from message durability, and scalability becomes the message broker's problem rather than the system's.
Its contribution is a programming model where coordination means asking "what message topic does this agent subscribe to?" instead of "which agent does the supervisor pick next?" The system ends up looking like a pub/sub event mesh.
LangGraph's Swarm Architecture
The LangGraph 2025 docs list "Swarm Architecture" as one of the multi-agent patterns. Agents are nodes, the edges form a directed graph with cycles, and a node can be activated from the pool. A worker picks from the available work by condition, not by supervisor assignment.
Failure mode: starvation and hot-spotting
If workers prefer the fastest available task, long-running tasks can sit in the queue until nothing else is left. That is classic queue starvation.
Three mitigations:
- Priority queues with explicit aging (increase priority with wait time).
- Worker specialization: some workers only take "long" tasks.
- Back-pressure: limit how many fast tasks enter the queue.
The content-based routing link
Swarm pairs well with content-based routing (Lesson 22). Instead of one generic queue, keep a queue per message type and let specialist workers subscribe only to their type. Message-bus architectures that scale to thousands of agents are built on this.
Build It
code/main.py runs three scheduling strategies on the same eight tasks: four slow ones (0.4s each) and four fast ones (0.1s each).
- Sequential baseline: one worker processes the tasks serially.
- Fixed assignment: each task is pre-assigned to a specific worker, the way a supervisor would do it. The assignment is deliberately bad. Worker 0 gets all four slow tasks plus one fast one, and the other three workers get one fast task each.
- Swarm: four worker threads pull from a shared
queue.Queueuntilget_nowaitraisesqueue.Empty.
Fixed assignment leaves three workers idle while worker 0 grinds through its slow tasks. In the swarm, the slow tasks sit at the front of the queue, so each worker grabs one, and the fast tasks get picked up as workers free up. Threads are enough here because the tasks are time.sleep calls, which release the GIL.
Run:
python3 code/main.py
The output prints wall-clock time and per-worker task counts for each strategy. From the sleep durations alone, expect roughly 2.0s sequential, 1.7s fixed (worker 0 does 4 x 0.4s + 0.1s), and 0.5s swarm. The swarm counts depend on thread timing, but with this task order they should land near two per worker.
Use It
outputs/skill-swarm-fit.md decides whether a task should use a swarm or a supervisor. It takes four inputs: task independence, duration variance, ordering requirements, and how much debuggability you need.
Ship It
Checklist:
- Priority queue with aging. Keeps long tasks from starving.
- Worker idempotency. A task may be pulled more than once if a worker crashes mid-run, so reprocessing it has to produce the same result.
- Durable queue. Use Kafka, Redis Streams, or a database-backed queue in production.
queue.Queuelives in memory only. - Observability per task. Give each task a trace ID, and have workers log start and end against it.
- Back-pressure. If the queue grows faster than workers drain it, slow the producer.
I'd run main.py first and read the three wall-clock times before anything else. The workload is eight tasks, four at 0.4s and four at 0.1s, so the sleeps alone put sequential near 2.0s, fixed assignment near 1.7s, and swarm near 0.5s. Numbers far from those are worth a look at the machine's load before you trust the comparison.
My bet is that the fixed-assignment baseline is the part to read closely. It stands in for a supervisor, and it is built to be bad: worker 0 holds all four slow tasks. The speedup says more about that hand-picked split than about swarms in general. A supervisor that knew the durations would not split the work that way, and the swarm's win is that it does not need to know.
I'd also keep the toy in proportion. Workers exit when the queue is empty, nothing enqueues follow-up work, and queue.Queue is plain FIFO, so starvation, priorities, crashes, and idempotency do not come up. Those are the Ship It items. The exercises add priority queues and routing, but crash handling and idempotency are left for you to build.
Exercises
- Run
code/main.py. How much faster is swarm than sequential on the variable-duration workload? How much faster than fixed assignment? - Add a priority queue variant (use
queue.PriorityQueue). Assign priority by task "importance" field. Observe whether low-priority tasks ever starve under continuous load. - Implement a hot-spot detector: log when any worker processes 3× more tasks than the slowest worker. What does that indicate about task-duration distribution?
- Read the Matrix paper (arXiv:2511.21686) abstract and Section 3. Identify one specific tradeoff Matrix accepts (scalability gain) and one it gives up (traceability, determinism).
- Convert the swarm demo to use a
queue.Queueof (task_type, payload) tuples, with workers subscribing only to specific types. What routing rules make sense when tasks are heterogeneous?
Key Terms
| Term | What people say | What it actually means |
|---|---|---|
| Swarm architecture | "Decentralized agents" | Workers pull from shared queue; no central orchestrator. |
| Event bus | "Agents subscribe to topics" | Message broker that routes tasks to workers by type or content. |
| Starvation | "Task never runs" | Low-priority task never gets picked because higher-priority work arrives continuously. |
| Hot-spotting | "One worker drowns" | Load imbalance where one worker gets most tasks. |
| Back-pressure | "Slow down the producer" | Mechanism that signals upstream to stop producing when the queue fills up. |
| Idempotent worker | "Safe to re-run" | A task processed twice produces the same result. Required because workers may crash mid-run. |
| Durable queue | "Survives crashes" | Queue backed by disk or replicated storage; tasks are not lost when a worker crashes. |
| Matrix framework | "Full message-passing swarm" | Both data and control flow are serialized messages on distributed queues. |
Further Reading
- LangGraph workflows and agents (Swarm Architecture): explicit swarm support
- Matrix: A Decentralized Framework for Multi-Agent Systems: full message-passing swarm
- Anthropic engineering: why supervisor not swarm in Research: why a specific production system explicitly chose supervisor over swarm
- AutoGen v0.4 actor-model docs: the event-driven actor rewrite, closer to swarm than v0.2's GroupChat
Code
- main.py (python, 136 lines)