⚠️ This blog post was created with the help of AI tools. Yes, I used a bit of magic from language models to organize my thoughts and automate the boring parts, but the geeky fun and the 🤖 in C# are 100% mine.

🎥 Video coming soon!
I’m preparing a short walkthrough video where I’ll run this sample live, explain the design decisions, and show how everything fits together step by step. But hey, it’s christmas time, so I’m taking this easy 😉


When building AI-powered applications, the moment you move beyond a single “chatbot”, things get interesting very quickly.

You start asking questions like:

  • How do I split responsibilities across agents?
  • How do I avoid hard-coding routing logic?
  • How do I keep agent creation simple and consistent?

In this post, I’ll show a clean and practical pattern using the Microsoft Agent Framework (MAF) in .NET that answers all of those questions using two key concepts:

  • AgentFactory – to create agents consistently and with minimal boilerplate
  • Handoff workflows – to let agents transfer control between each other instead of routing in code

We’ll do this with a small but realistic “Mini Concierge” example.


The scenario: a Mini Concierge with specialists

Our app has four agents:

  • Triage agent – decides who should handle the request
  • General agent – handles normal Q&A
  • Travel agent – handles travel questions and can call a weather tool
  • Vision agent – analyzes images (multimodal)

The key idea is simple:

The triage agent does not answer questions.
It only decides who should own the task and hands it off.

No if/else.
No routing methods.
No orchestration logic in our app code.


Why AgentFactory matters

Without a factory, agent creation quickly turns into repeated setup code:

  • chat client
  • tools
  • defaults
  • configuration

With AgentFactory, we define all shared configuration once, then create as many agents as we want by only changing:

  • name
  • instructions

In this sample, the factory is the backbone of the entire solution.

You can find the complete code here:
https://github.com/microsoft/Generative-AI-for-beginners-dotnet/tree/main/samples/AgentFx/AgentFx-MultiAgents-Factory-01


Step-by-step overview

1. Shared chat client

We start with a single chat client. In this case, I’m using Ollama running locally, but this could just as easily be Microsoft Foundry or another provider.

IChatClient chatClient = new OllamaApiClient(
    new Uri("http://localhost:11434/"),
    "ministral-3");

2. Tools once, reused everywhere

The travel agent can answer weather questions using a simple tool.
Tools are registered once and reused by all agents created by the factory.

AIFunction[] tools = [
    AIFunctionFactory.Create(GetWeather, "GetWeather")
];

3. Create the AgentFactory

This is the most important line in the whole sample.

var agentFactory = new ChatClientPromptAgentFactory(chatClient, tools);

From here on, every agent is created the same way, with no duplicated wiring.


4. Define agents by intent, not infrastructure

Each agent is defined only by:

  • a name
  • a role
  • clear instructions

For example, the triage agent:

var triageAgent = await agentFactory.CreateAsync(
    promptAgent: new GptComponentMetadata(
        name: "triage_agent",
        instructions: ToInstructions("""
            You are a triage agent for a mini concierge.

            Decide who should own the task, then HANDOFF to exactly ONE agent:
            - travel_agent: travel planning, destinations, weather
            - vision_agent: anything that requires looking at an image
            - general_agent: everything else

            Do not answer the user yourself. Always handoff.
        """)));

The same factory creates the travel, vision, and general agents with different instructions.


Handoff workflows: no routing code

Instead of routing logic in C#, we define handoff rules declaratively using a workflow.

Func<Workflow> workflowFactory = () =>
    AgentWorkflowBuilder.CreateHandoffBuilderWith(triageAgent)
        .WithHandoffs(triageAgent, [travelAgent, visionAgent, generalAgent])
        .WithHandoff(travelAgent, triageAgent)
        .WithHandoff(visionAgent, triageAgent)
        .WithHandoff(generalAgent, triageAgent)
        .Build();

What this means:

  • The triage agent can hand off to any specialist
  • Specialists can optionally return control to triage
  • The runtime manages ownership and execution flow

If you want to dive deeper into this concept, this is the official documentation:
https://learn.microsoft.com/en-us/agent-framework/user-guide/workflows/orchestrations/handoff?pivots=programming-language-csharp


Running the demos

We run three simple demos:

Demo 1 – General Q&A

What is the capital of France?

Output:

[AGENT: triage_agent]
[AGENT: general_agent]
Final Answer: The capital of France is Paris.

Demo 2 – Tool calling

I'm going to Amsterdam tomorrow. What's the weather in celsius?

Output:

[AGENT: triage_agent]
[AGENT: travel_agent]
Final Answer: ...weather response...

Demo 3 – Multimodal vision

What do you see in this image?

Output:

[AGENT: triage_agent]
[AGENT: vision_agent]
Final Answer: ...image analysis...

Notice how:

  • The app never decides who answers
  • Agent ownership is explicit and visible
  • Each response is clean and readable

Why this pattern scales

This approach scales naturally because:

  • AgentFactory centralizes creation and configuration
  • Handoff workflows remove routing logic from your app
  • Adding a new agent is just:
    • define instructions
    • add a handoff rule

What’s next?

  • 🎥 A short video walkthrough of this exact sample (coming soon)
  • A follow-up post showing how to:
    • persist conversations
    • add background responses
    • connect this to Microsoft Foundry

If you want to experiment now, grab the code here:
https://github.com/microsoft/Generative-AI-for-beginners-dotnet/tree/main/samples/AgentFx/AgentFx-MultiAgents-Factory-01

And as always—feedback welcome. This pattern is powerful, simple, and very easy to grow with.

Happy coding!

Greetings

El Bruno

More posts in my blog ElBruno.com.

More info in https://beacons.ai/elbruno


Leave a comment

Discover more from El Bruno

Subscribe now to keep reading and get access to the full archive.

Continue reading