Part 7 of the Microsoft Agent Framework Series
Complex problems often require specialized expertise working together. Just as human teams have different roles, multi-agent systems combine specialized agents to tackle challenges no single agent could handle alone.
Microsoft Agent Framework provides built-in orchestration patterns for coordinating multiple agents. Let’s explore each pattern and when to use it.
The Five Orchestration Patterns
| Pattern | Description | Best For |
|---|---|---|
| Sequential | Agents execute one after another | Pipelines, review chains |
| Concurrent | Agents work in parallel | Independent data gathering |
| Handoff | Agents pass control based on expertise | Specialized support tiers |
| Group Chat | Agents collaborate on one task | Brainstorming, reviews |
| Magentic | Manager coordinates specialists | Complex project management |
1. Sequential Orchestration
Agents execute in a defined order, each building on the previous output:
from agent_framework.orchestration import SequentialOrchestrator
from agent_framework.azure import AzureOpenAIResponsesClient
from azure.identity import AzureCliCredential
import asyncio
async def create_content_pipeline():
client = AzureOpenAIResponsesClient(credential=AzureCliCredential())
# Create specialized agents
researcher = client.create_agent(
name="Researcher",
instructions="""
You are a research specialist. Given a topic:
1. Identify key subtopics to cover
2. Find relevant facts and statistics
3. Note important sources and references
4. Compile a research brief for the writer
"""
)
writer = client.create_agent(
name="Writer",
instructions="""
You are a professional content writer. Given research:
1. Create an engaging article structure
2. Write clear, compelling prose
3. Include relevant examples
4. Maintain consistent tone and style
"""
)
editor = client.create_agent(
name="Editor",
instructions="""
You are an expert editor. Review the draft for:
1. Grammar and spelling errors
2. Clarity and readability
3. Logical flow and structure
4. Factual accuracy
Provide the final polished version.
"""
)
# Create sequential orchestrator
orchestrator = SequentialOrchestrator(
agents=[researcher, writer, editor]
)
return orchestrator
async def main():
orchestrator = await create_content_pipeline()
print("Starting content pipeline...")
print("=" * 50)
# Execute pipeline: researcher -> writer -> editor
result = await orchestrator.run(
"Create an article about the benefits of AI agents in enterprise software development"
)
print(f"\nFinal Article:\n{result}")
if __name__ == "__main__":
asyncio.run(main()).NET / C# Implementation
using Microsoft.Agents.AI;
using Microsoft.Agents.AI.Orchestration;
using Azure.Identity;
using OpenAI;
namespace MAF.Part07.Orchestration;
///
/// Part 7: Sequential Orchestration Pattern in .NET
///
public class SequentialOrchestration
{
public static async Task Main(string[] args)
{
var client = new AzureOpenAIClient(
new Uri(Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT")!),
new DefaultAzureCredential());
var responseClient = client.GetOpenAIResponseClient("gpt-4o");
// Create specialized agents for content pipeline
var researcher = responseClient.CreateAIAgent(
name: "Researcher",
instructions: @"
You are a research specialist. Given a topic:
1. Identify key subtopics to cover
2. Find relevant facts and statistics
3. Note important sources
4. Compile a research brief for the writer");
var writer = responseClient.CreateAIAgent(
name: "Writer",
instructions: @"
You are a professional content writer. Given research:
1. Create an engaging article structure
2. Write clear, compelling prose
3. Include relevant examples
4. Maintain consistent tone and style");
var editor = responseClient.CreateAIAgent(
name: "Editor",
instructions: @"
You are an expert editor. Review the draft for:
1. Grammar and spelling errors
2. Clarity and readability
3. Logical flow and structure
4. Factual accuracy
Provide the final polished version.");
// Create sequential orchestrator
var orchestrator = new SequentialOrchestrator(
agents: new[] { researcher, writer, editor });
Console.WriteLine("Starting content pipeline...");
Console.WriteLine(new string('=', 50));
// Execute pipeline: researcher -> writer -> editor
var result = await orchestrator.RunAsync(
"Create an article about the benefits of AI agents in enterprise software development");
Console.WriteLine($"\nFinal Article:\n{result}");
}
}
2. Concurrent Orchestration
Agents work simultaneously on independent subtasks:
from agent_framework.orchestration import ConcurrentOrchestrator
from agent_framework.azure import AzureOpenAIResponsesClient
from azure.identity import AzureCliCredential
import asyncio
async def create_analysis_team():
client = AzureOpenAIResponsesClient(credential=AzureCliCredential())
# Create parallel analysis agents
market_analyst = client.create_agent(
name="MarketAnalyst",
instructions="""
Analyze market conditions for the given company/topic:
- Market size and growth trends
- Competitive landscape
- Market opportunities and threats
Format as a structured market analysis section.
"""
)
tech_analyst = client.create_agent(
name="TechAnalyst",
instructions="""
Analyze technical aspects:
- Technology stack and architecture
- Innovation and R&D capabilities
- Technical risks and opportunities
Format as a structured technical analysis section.
"""
)
financial_analyst = client.create_agent(
name="FinancialAnalyst",
instructions="""
Analyze financial health:
- Revenue and growth metrics
- Profitability and margins
- Financial risks and opportunities
Format as a structured financial analysis section.
"""
)
# Aggregator function to combine results
def aggregate_analysis(results: list) -> str:
combined = "# Comprehensive Analysis Report\n\n"
sections = ["## Market Analysis", "## Technical Analysis", "## Financial Analysis"]
for i, (section, result) in enumerate(zip(sections, results)):
combined += f"{section}\n{result}\n\n"
combined += "## Summary\nAnalysis compiled from market, technical, and financial perspectives."
return combined
orchestrator = ConcurrentOrchestrator(
agents=[market_analyst, tech_analyst, financial_analyst],
aggregator=aggregate_analysis
)
return orchestrator
async def main():
orchestrator = await create_analysis_team()
print("Starting parallel analysis (3 agents working simultaneously)...")
print("=" * 50)
# All agents work in parallel
result = await orchestrator.run(
"Analyze Microsoft for potential investment opportunity"
)
print(f"\nCombined Report:\n{result}")
if __name__ == "__main__":
asyncio.run(main()).NET / C# Implementation
using Microsoft.Agents.AI;
using Microsoft.Agents.AI.Orchestration;
using Azure.Identity;
using OpenAI;
namespace MAF.Part07.Orchestration;
///
/// Part 7: Concurrent Orchestration Pattern in .NET
///
public class ConcurrentOrchestration
{
public static async Task Main(string[] args)
{
var client = new AzureOpenAIClient(
new Uri(Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT")!),
new DefaultAzureCredential());
var responseClient = client.GetOpenAIResponseClient("gpt-4o");
// Create parallel analysis agents
var marketAnalyst = responseClient.CreateAIAgent(
name: "MarketAnalyst",
instructions: @"
Analyze market conditions:
- Market size and growth trends
- Competitive landscape
- Opportunities and threats
Format as structured market analysis.");
var techAnalyst = responseClient.CreateAIAgent(
name: "TechAnalyst",
instructions: @"
Analyze technical aspects:
- Technology stack
- Innovation capabilities
- Technical risks
Format as structured technical analysis.");
var financialAnalyst = responseClient.CreateAIAgent(
name: "FinancialAnalyst",
instructions: @"
Analyze financial health:
- Revenue and growth
- Profitability
- Financial risks
Format as structured financial analysis.");
// Aggregator function
static string AggregateResults(string[] results)
{
var combined = "# Comprehensive Analysis Report\n\n";
var sections = new[] { "## Market Analysis", "## Technical Analysis", "## Financial Analysis" };
for (int i = 0; i < Math.Min(results.Length, sections.Length); i++)
{
combined += $"{sections[i]}\n{results[i]}\n\n";
}
return combined;
}
// Create concurrent orchestrator
var orchestrator = new ConcurrentOrchestrator(
agents: new[] { marketAnalyst, techAnalyst, financialAnalyst },
aggregator: AggregateResults);
Console.WriteLine("Starting parallel analysis (3 agents working simultaneously)...");
Console.WriteLine(new string('=', 50));
// All agents work in parallel
var result = await orchestrator.RunAsync(
"Analyze Microsoft for potential investment opportunity");
Console.WriteLine($"\nCombined Report:\n{result}");
}
}
3. Handoff Orchestration
Agents transfer control based on expertise needed:
from agent_framework.orchestration import HandoffOrchestrator
from agent_framework.azure import AzureOpenAIResponsesClient
from azure.identity import AzureCliCredential
import asyncio
async def create_support_system():
client = AzureOpenAIResponsesClient(credential=AzureCliCredential())
# Tiered support agents
tier1 = client.create_agent(
name="Tier1Support",
instructions="""
You are a Tier 1 support agent. Handle basic inquiries:
- Password resets
- Account information
- FAQ questions
- Basic troubleshooting
If the issue is technical or complex, say "HANDOFF:Tier2Support"
If the issue is about billing, say "HANDOFF:BillingAgent"
Otherwise, resolve the issue directly.
"""
)
tier2 = client.create_agent(
name="Tier2Support",
instructions="""
You are a Tier 2 technical support agent. Handle:
- Complex technical issues
- Bug reports
- Integration problems
- Performance issues
If the issue requires engineering, say "HANDOFF:EngineeringEscalation"
Otherwise, resolve the technical issue.
"""
)
billing = client.create_agent(
name="BillingAgent",
instructions="""
You are a billing specialist. Handle:
- Invoice questions
- Payment issues
- Refund requests
- Subscription changes
For refunds over $500, say "HANDOFF:BillingManager"
Otherwise, resolve the billing issue.
"""
)
engineering = client.create_agent(
name="EngineeringEscalation",
instructions="""
You are an engineering escalation agent. Handle:
- Critical bugs
- System outages
- Security issues
Create a detailed ticket for the engineering team.
"""
)
# Create handoff orchestrator
orchestrator = HandoffOrchestrator(
initial_agent=tier1,
agents={
"Tier2Support": tier2,
"BillingAgent": billing,
"EngineeringEscalation": engineering
},
handoff_pattern=r"HANDOFF:(\w+)" # Regex to detect handoff
)
return orchestrator
async def main():
orchestrator = await create_support_system()
test_cases = [
"I forgot my password",
"I have a question about my invoice from last month",
"The API is returning 500 errors consistently"
]
for query in test_cases:
print(f"\nCustomer: {query}")
print("-" * 40)
result = await orchestrator.run(query)
print(f"Resolution: {result}")
if __name__ == "__main__":
asyncio.run(main()).NET / C# Implementation
using Microsoft.Agents.AI;
using Microsoft.Agents.AI.Orchestration;
using Azure.Identity;
using OpenAI;
using System.Text.RegularExpressions;
namespace MAF.Part07.Orchestration;
///
/// Part 7: Handoff Orchestration Pattern in .NET
///
public class HandoffOrchestration
{
public static async Task Main(string[] args)
{
var client = new AzureOpenAIClient(
new Uri(Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT")!),
new DefaultAzureCredential());
var responseClient = client.GetOpenAIResponseClient("gpt-4o");
// Tiered support agents
var tier1 = responseClient.CreateAIAgent(
name: "Tier1Support",
instructions: @"
You are a Tier 1 support agent. Handle basic inquiries:
- Password resets
- Account information
- FAQ questions
If the issue is technical, say 'HANDOFF:Tier2Support'
If about billing, say 'HANDOFF:BillingAgent'
Otherwise, resolve directly.");
var tier2 = responseClient.CreateAIAgent(
name: "Tier2Support",
instructions: @"
You are a Tier 2 technical support agent. Handle:
- Complex technical issues
- Bug reports
- Integration problems
If requires engineering, say 'HANDOFF:EngineeringEscalation'
Otherwise, resolve the issue.");
var billing = responseClient.CreateAIAgent(
name: "BillingAgent",
instructions: @"
You are a billing specialist. Handle:
- Invoice questions
- Payment issues
- Refund requests
For refunds over $500, say 'HANDOFF:BillingManager'
Otherwise, resolve the billing issue.");
var engineering = responseClient.CreateAIAgent(
name: "EngineeringEscalation",
instructions: @"
You are an engineering escalation agent. Handle:
- Critical bugs
- System outages
- Security issues
Create a detailed ticket for engineering.");
// Create handoff orchestrator
var orchestrator = new HandoffOrchestrator(
initialAgent: tier1,
agents: new Dictionary
{
["Tier2Support"] = tier2,
["BillingAgent"] = billing,
["EngineeringEscalation"] = engineering
},
handoffPattern: new Regex(@"HANDOFF:(\w+)"));
var testCases = new[]
{
"I forgot my password",
"I have a question about my invoice from last month",
"The API is returning 500 errors consistently"
};
foreach (var query in testCases)
{
Console.WriteLine($"\nCustomer: {query}");
Console.WriteLine(new string('-', 40));
var result = await orchestrator.RunAsync(query);
Console.WriteLine($"Resolution: {result}");
}
}
}
4. Group Chat Orchestration
Agents collaborate in a shared conversation:
from agent_framework.orchestration import GroupChatOrchestrator
from agent_framework.azure import AzureOpenAIResponsesClient
from azure.identity import AzureCliCredential
import asyncio
async def create_design_team():
client = AzureOpenAIResponsesClient(credential=AzureCliCredential())
# Collaborative team members
product_manager = client.create_agent(
name="ProductManager",
instructions="""
You are a Product Manager. In discussions:
- Focus on user needs and business value
- Prioritize features based on impact
- Consider timelines and resources
- Make final decisions on scope
Keep responses concise (2-3 sentences).
"""
)
engineer = client.create_agent(
name="Engineer",
instructions="""
You are a Senior Engineer. In discussions:
- Evaluate technical feasibility
- Suggest implementation approaches
- Identify potential challenges
- Estimate complexity
Keep responses concise (2-3 sentences).
"""
)
designer = client.create_agent(
name="Designer",
instructions="""
You are a UX Designer. In discussions:
- Focus on user experience
- Suggest interface improvements
- Consider accessibility
- Propose design patterns
Keep responses concise (2-3 sentences).
"""
)
qa_lead = client.create_agent(
name="QALead",
instructions="""
You are a QA Lead. In discussions:
- Identify testing requirements
- Note potential edge cases
- Consider quality metrics
- Suggest test strategies
Keep responses concise (2-3 sentences).
"""
)
# Create group chat with PM as moderator
orchestrator = GroupChatOrchestrator(
agents=[product_manager, engineer, designer, qa_lead],
moderator=product_manager, # PM controls the conversation
max_rounds=5, # Limit discussion rounds
summary_agent=product_manager # PM summarizes decisions
)
return orchestrator
async def main():
orchestrator = await create_design_team()
print("Starting design discussion...")
print("=" * 50)
result = await orchestrator.run(
"Design a new feature: Allow users to schedule AI agent tasks to run at specific times"
)
print(f"\nFinal Decision:\n{result}")
if __name__ == "__main__":
asyncio.run(main()).NET / C# Implementation
// Group Chat pattern is handled via Orchestration libraries in .NET.
// See documentation for IGroupChatOrchestrator usage.
5. Magentic Orchestration
A manager agent dynamically coordinates specialists:
from agent_framework.orchestration import MagenticOrchestrator
from agent_framework.azure import AzureOpenAIResponsesClient
from azure.identity import AzureCliCredential
import asyncio
async def create_project_team():
client = AzureOpenAIResponsesClient(credential=AzureCliCredential())
# Manager agent that coordinates everything
manager = client.create_agent(
name="ProjectManager",
instructions="""
You are a Project Manager coordinating a team of specialists.
Your responsibilities:
1. Break down complex tasks into subtasks
2. Assign subtasks to appropriate specialists
3. Maintain a task ledger tracking progress
4. Synthesize results from specialists
5. Make decisions when specialists disagree
Available specialists:
- Researcher: For gathering information
- Analyst: For data analysis and insights
- Writer: For content creation
- Reviewer: For quality review
Format task assignments as: @SpecialistName: [task description]
Track progress and coordinate until the goal is achieved.
"""
)
# Specialist agents
researcher = client.create_agent(
name="Researcher",
instructions="""
You are a Research Specialist. When assigned a task:
1. Gather relevant information
2. Identify key facts and data
3. Compile sources and references
Return structured research findings.
"""
)
analyst = client.create_agent(
name="Analyst",
instructions="""
You are a Data Analyst. When assigned a task:
1. Analyze provided data and research
2. Identify patterns and insights
3. Create data-driven recommendations
Return structured analysis with conclusions.
"""
)
writer = client.create_agent(
name="Writer",
instructions="""
You are a Content Writer. When assigned a task:
1. Create clear, engaging content
2. Structure information logically
3. Maintain professional tone
Return polished written content.
"""
)
reviewer = client.create_agent(
name="Reviewer",
instructions="""
You are a Quality Reviewer. When assigned a task:
1. Review content for accuracy
2. Check for completeness
3. Suggest improvements
Return review feedback and final approval.
"""
)
# Create magentic orchestrator
orchestrator = MagenticOrchestrator(
manager=manager,
specialists=[researcher, analyst, writer, reviewer],
max_iterations=10, # Max coordination cycles
allow_human_input=True # Can pause for human guidance
)
return orchestrator
async def main():
orchestrator = await create_project_team()
print("Starting managed project...")
print("=" * 50)
result = await orchestrator.run(
"""Create a competitive analysis report for AI agent frameworks,
comparing Microsoft Agent Framework, LangChain, and CrewAI.
Include market positioning, technical capabilities, and recommendations."""
)
print(f"\nFinal Deliverable:\n{result}")
if __name__ == "__main__":
asyncio.run(main()).NET / C# Implementation
// Magentic Orchestration: Use new MagenticOrchestrator(planner, agents);
// Requires 'Microsoft.Agents.AI.Planning' package.
Agent-to-Agent (A2A) Protocol
For agents across different systems or frameworks:
from agent_framework.a2a import A2AAgent, AgentCard
from agent_framework.azure import AzureOpenAIResponsesClient
from azure.identity import AzureCliCredential
import asyncio
async def discover_external_agent(url: str) -> AgentCard:
"""Discover an external agent's capabilities via A2A protocol."""
async with aiohttp.ClientSession() as session:
# Fetch agent card from well-known endpoint
async with session.get(f"{url}/.well-known/agent.json") as response:
if response.status == 200:
data = await response.json()
return AgentCard(
name=data["name"],
description=data["description"],
url=data["url"],
capabilities=data.get("capabilities", []),
authentication=data.get("authentication", {})
)
raise Exception(f"Could not discover agent at {url}")
async def create_cross_system_workflow():
client = AzureOpenAIResponsesClient(credential=AzureCliCredential())
# Local agent
local_processor = client.create_agent(
name="LocalProcessor",
instructions="Process and prepare data for external analysis."
)
# Discover and connect to external A2A agent
external_card = await discover_external_agent("https://external-service.com")
external_agent = A2AAgent(
name=external_card.name,
url=external_card.url,
agent_card=external_card,
auth_token=os.getenv("EXTERNAL_API_TOKEN")
)
# Another local agent for final processing
result_formatter = client.create_agent(
name="ResultFormatter",
instructions="Format and present the final results clearly."
)
# Use in sequential workflow
from agent_framework.orchestration import SequentialOrchestrator
orchestrator = SequentialOrchestrator(
agents=[local_processor, external_agent, result_formatter]
)
return orchestrator
async def main():
try:
orchestrator = await create_cross_system_workflow()
print("Running cross-system workflow...")
result = await orchestrator.run("Analyze customer sentiment from Q4 feedback")
print(f"Result: {result}")
except Exception as e:
print(f"A2A connection failed: {e}")
print("Falling back to local-only processing...")
if __name__ == "__main__":
asyncio.run(main()).NET / C# Implementation
// Agent to Agent communication is natively supported via IAgent interfaces.
Choosing the Right Pattern
| Scenario | Recommended Pattern |
|---|---|
| Content creation pipeline | Sequential |
| Multi-source data gathering | Concurrent |
| Customer support escalation | Handoff |
| Team brainstorming | Group Chat |
| Complex project management | Magentic |
📦 Source Code
All code examples from this article series are available on GitHub:
👉 https://github.com/nithinmohantk/microsoft-agent-framework-series-examples
Clone the repository to follow along:
git clone https://github.com/nithinmohantk/microsoft-agent-framework-series-examples.git
cd microsoft-agent-framework-series-examples
Group Chat Pattern (C#)
Series Navigation
- Part 1: Introduction
- Part 2: First Agent (.NET)
- Part 3: First Agent (Python)
- Part 4: Tools & Function Calling
- Part 5: Multi-Turn Conversations
- Part 6: Workflows
- Part 7: Multi-Agent Patterns ← You are here
- Part 8: Production-Ready Agents — Coming next
References
- Microsoft Agent Framework GitHub
- Multi-Agent Orchestration Documentation
- AI Agent Design Patterns - Azure Architecture
Discover more from C4: Container, Code, Cloud & Context
Subscribe to get the latest posts sent to your email.