In my previous post, I showed you how to build a single C# AI agent with the Microsoft Agent Framework (MAF) — streaming, function tools, and multi-turn memory — using a free model through OpenRouter.

A single agent is a great start. But the real reason frameworks like MAF exist is the next step: getting multiple agents to work together. In this post, I’ll show you two ways to do that, building on the same project:

  • A sequential workflow — two agents in a pipeline, where you decide the order.
  • An orchestrator agent — a top-level agent that decides for itself which specialists to call.

As before, everything runs on the same free NVIDIA model via OpenRouter — no paid keys required.

The full source is on GitHub: MicrosoftAgentFrameworkDemo (see samples/02-multi-agent-sequential and samples/03-orchestrator-agent).

Why multi-agent?

Before any code, let’s talk about why you’d want more than one agent — because this is where the real value is, and it’s easy to miss if you jump straight to the API.

Imagine you want an AI to write a marketing tagline and critique it. You could cram everything into one giant agent:

“You are a copywriter AND an editor. Write a tagline, then put on your editor hat, review your own work, fix it, and explain what you changed…”

That works for a demo, but it has real problems:

  • One bloated prompt doing several jobs — hard to read, hard to tune.
  • Mixed concerns — the “writer” voice and the “editor” voice fight inside one set of instructions.
  • No real second opinion — an agent grading its own homework rarely pushes back on itself.

The multi-agent approach flips this. You create small, focused specialist agents — each with one job and its own tight instructions:

  • Writer that only knows how to draft a punchy tagline.
  • Reviewer that only knows how to sharpen a draft and say what it changed.

The benefits are the kind you feel as a developer:

  • Separation of concerns — each agent’s instructions stay short and clear.
  • A genuine review step — a separate Reviewer actually critiques the Writer’s output.
  • Easier to reason about, test, and evolve — you can tweak one agent without touching the other, or even point each agent at a different model.

So the question becomes: once you have specialist agents, how do you coordinate them? MAF gives you two answers.

Two ways to coordinate agents

PatternWho decides the order?When to reach for it
Sequential workflow (Sample 02)You, in C# codeThe steps are known and fixed (draft → review)
Orchestrator agent (Sample 03)The LLMThe path can vary — let the model plan the work

Let’s build both.

Prerequisites

Both samples reuse the exact OpenRouter client setup from Sample 01 — OpenRouter is OpenAI-compatible, so we point the OpenAI SDK at OpenRouter’s endpoint and wrap it as an IChatClient. One small note on packages:

  • Sample 02 adds one NuGet package: Microsoft.Agents.AI.Workflows (for the workflow builder).
  • Sample 03 needs no new package — agents-as-tools lives in the core Microsoft.Agents.AI.

Part 1 — Sample 02: a sequential multi-agent workflow

Our scenario is a tiny content pipeline: you type a product or topic, the Writer drafts a tagline, and the Reviewer sharpens it. The Writer’s output flows into the Reviewer automatically.

It starts with two ordinary agents — exactly like Sample 01, nothing special:

AIAgent writer = chatClient.AsAIAgent(
instructions: """
You are a concise copywriter. Given a product or topic, write ONE punchy
marketing tagline (max ~12 words). Output only the tagline no preamble.
""",
name: "Writer");
AIAgent reviewer = chatClient.AsAIAgent(
instructions: """
You are a sharp marketing editor. You will be given a draft tagline.
Rewrite it to be punchier and clearer, then on a new line add exactly:
Changed: <one short sentence on what you changed and why>
""",
name: "Reviewer");

Now the one line that turns those two agents into a pipeline:

Key MAF Concept — AgentWorkflowBuilder.BuildSequential Composes agents into a pipeline. The Writer’s output automatically becomes the Reviewer’s input, in the order you list them. You don’t write any “now call the reviewer” routing code.

Workflow workflow = AgentWorkflowBuilder.BuildSequential([writer, reviewer]);

To run it, MAF executes the whole workflow in-process and streams events back as each agent works:

var messages = new List<ChatMessage> { new(ChatRole.User, userInput) };
await using StreamingRun run = await InProcessExecution.RunStreamingAsync(workflow, messages);
await run.TrySendMessageAsync(new TurnToken(emitEvents: true));
string? lastExecutorId = null;
await foreach (WorkflowEvent evt in run.WatchStreamAsync())
{
if (evt is AgentResponseUpdateEvent update) // a streamed text chunk from an agent
{
if (update.ExecutorId != lastExecutorId) // a new agent started talking
{
lastExecutorId = update.ExecutorId;
Console.Write($"\n[{update.ExecutorId}]: ");
}
Console.Write(update.Update.Text);
}
else if (evt is WorkflowOutputEvent) // the pipeline finished
{
break;
}
}

The key thing to notice is the event stream: each AgentResponseUpdateEvent tells you which agent (ExecutorId) is producing text. (One small detail: the workflow gives each agent an ExecutorId like Writer_a1b2c3…, so in the repo I trim the suffix to print a clean [Writer] label.) When you run it:

The real value here: the Reviewer never sees “you are also a writer.” It only ever receives “improve this draft”.

Part 2 — Sample 03: an orchestrator agent

The sequential workflow is clean, but notice its limitation: the order is hardcoded. BuildSequential([writer, reviewer]) will always run the Writer once and the Reviewer once, in that order — because I wrote it that way.

But what if I want the agent to decide? Draft once, maybe review twice, maybe skip the review if the draft is already great? For that, I don’t want a fixed pipeline — I want an orchestrator agent that’s smart enough to plan the work itself.

The trick is in MAF, an agent can be turned into a tool, and (from Sample 01) we know agents can call tools.

Key MAF Concept — AsAIFunction()agent.AsAIFunction() turns an entire agent into a callable tool. So you can hand the Writer and Reviewer to another agent as its tools — and let that agent decide when to use each one.

// Turn each specialist agent into a tool:
AITool writerTool = writer.AsAIFunction();
AITool reviewerTool = reviewer.AsAIFunction();
// The Orchestrator is itself an agent — and its "tools" are agents.
// The LLM decides when to draft, when to review, and when it's done.
AIAgent orchestrator = chatClient.AsAIAgent(
instructions: """
You produce a polished marketing tagline by delegating never write one yourself.
Steps you must follow:
1. Call the Writer tool to create a first-draft tagline.
2. Call the Reviewer tool to improve that draft.
3. Reply with one line: Final: <the improved tagline>
""",
name: "Orchestrator",
description: "Coordinates the Writer and Reviewer agents.",
tools: [writerTool, reviewerTool]);

That’s the whole idea — but there’s one problem: when the orchestrator delegates, it happens inside the model, so you can’t see it. MAF lets us peek in with middleware:

Key MAF Concept — function-invocation middleware :

agent.AsBuilder().Use(...) wraps the agent so you can observe (or modify) every tool call. We use it to log each delegation — which also reassures you the model is working.

AIAgent orchestrator = chatClient.AsAIAgent( /* ...as above... */ )
.AsBuilder()
.Use(async (innerAgent, context, next, cancellationToken) =>
{
Console.WriteLine($"\n [🔧 Orchestrator → {context.Function.Name}]");
return await next(context, cancellationToken);
})
.Build();

Now run it and you can watch the orchestrator think:

Sequential vs Orchestrator — when to use which

Both patterns coordinate the same two agents. The difference is who’s in charge of the flow.

Sequential workflow (02)Orchestrator agent (03)
Who decides the order?Your code (BuildSequential)The orchestrator’s LLM
Writer & Reviewer are…pipeline stagestools the orchestrator can call
Can it skip or repeat a step?No — fixedYes — the model decides
PredictabilityDeterministic, easy to testFlexible, but depends on the model
Best forKnown, fixed stepsVariable paths, “let the model plan”

Rule of thumb: if the steps are known and always the same, use a sequential workflow. If the path can vary and you want the agent to figure it out, reach for an orchestrator agent.

🙂

Advertisements
Advertisements

Leave a comment

Visitors

2,181,432 hits

Top Posts