Every multi-agent framework eventually makes you answer the same question, and most of them bury it: who decides which agent runs next? Microsoft Agent Framework at least makes the answer explicit — it ships five orchestration patterns, and each one is just a different answer to that single question. Get the framing right and the choice stops being a menu and becomes a decision tree.

The one axis that matters: control vs. autonomy#

Line the five patterns up by who holds the routing decision and they sort themselves from most-controlled to most-autonomous:

That ordering is also, not coincidentally, the order of increasing token cost and decreasing debuggability. Every step you move toward autonomy, you hand the routing to the model — which is powerful exactly where a fixed graph can't express the path, and a liability exactly where it can.

The two you'll reach for first#

Concurrent is the workhorse and the one most teams under-use. When you want several independent perspectives on the same input — a researcher, a marketer, and a legal reviewer all reacting to one product brief — you don't need them talking to each other. You need them running at once and their outputs merged. The API is deliberately small:

import os
from agent_framework.foundry import FoundryChatClient
from agent_framework.orchestrations import ConcurrentBuilder
from agent_framework import Message
from azure.identity import AzureCliCredential
from typing import cast

chat_client = FoundryChatClient(
    project_endpoint=os.environ["FOUNDRY_PROJECT_ENDPOINT"],
    model=os.environ["FOUNDRY_MODEL"],
    credential=AzureCliCredential(),
)

researcher = chat_client.as_agent(
    instructions="Expert market and product researcher. Give concise insights, opportunities, and risks.",
    name="researcher",
)
# ...marketer and legal defined the same way

workflow = ConcurrentBuilder(participants=[researcher, marketer, legal]).build()

output: list[Message] | None = None
async for event in workflow.run("We're launching a budget e-bike for urban commuters.", stream=True):
    if event.type == "output":
        output = event.data

for i, msg in enumerate(cast(list[Message], output or []), start=1):
    name = msg.author_name or "user"
    print(f"{i:02d} [{name}]:\n{msg.text}")

Note the shape: you build with ConcurrentBuilder(participants=[...]).build() and consume event.type == "output" off a streamed workflow.run(...). The other builders — SequentialBuilder, GroupChatBuilder, HandoffBuilder, MagenticBuilder — follow the same build-then-run rhythm, which is the point: swapping patterns is a one-line change, not a rewrite.

Sequential is the other default. If you already know the order — draft, then critique, then revise — encode it. You get a fully deterministic pipeline that's trivial to trace and cheap to run, because control flow never depends on model output. Most "agentic" workflows that ship to production are Sequential wearing a fancier name.

If you can draw the graph before you run it, you don't need a model to route it. Reserve the autonomous patterns for the cases where you genuinely can't.

The three that spend tokens for adaptivity#

Group Chat puts agents in one shared transcript and lets a turn policy rotate who speaks. Use it when the collaboration itself is the product — several agents refining a document together, each seeing the others' contributions. It costs more than Concurrent because the transcript grows every round.

Handoff lets the active agent transfer control based on context — the pattern behind triage and routing. A front-line agent inspects the request and hands off to billing, or tech support, or escalation. This is the same idea as agent handoffs in LangGraph and the OpenAI/Google SDKs: the routing is data-dependent, so you let the model make it. Powerful for support-style flows; non-deterministic by nature, so instrument every hop.

Magentic is the most autonomous, drawn from Microsoft's Magentic-One research. A manager agent owns the coordination: it plans, delegates to specialist workers, and tracks progress round by round, bounded by configurable max-round and stall/reset limits so it can't spin forever. Reach for it when the task is open-ended enough that you can't pre-plan the steps — but know you're paying for the manager's reasoning on top of every worker call. It's the pattern most likely to impress in a demo and most likely to surprise you on the invoice.

The rule of thumb#

Start with the most constrained pattern that expresses your problem, and escalate only when it can't route correctly. Concrete order of preference: Sequential or Concurrent → Group Chat → Handoff → Magentic. Because all five support streaming, checkpointing, and human-in-the-loop pause/resume, you can also mix — a deterministic Sequential spine with a Magentic step in the one place that needs open-ended planning. If you're still choosing a framework at all, this orchestration surface is a good part of the broader multi-agent comparison: the patterns are similar everywhere, but MAF is unusually explicit about naming them — and that clarity is worth something at 3 a.m. when a workflow won't route.