Jump to content

Connect Leeroopedia MCP: Equip your AI agents to search best practices, build plans, verify code, diagnose failures, and look up hyperparameter defaults.

Implementation:Microsoft Semantic kernel Orchestration Patterns

From Leeroopedia

Overview

Semantic Kernel provides three built-in orchestration classes for coordinating multiple agents: ConcurrentOrchestration, GroupChatOrchestration, and HandoffOrchestration. Each implements a distinct collaboration pattern -- parallel execution, managed group conversation, or dynamic agent-to-agent handoff -- and all share a common invocation model through the InProcessRuntime.

Source files:

  • ConcurrentOrchestration.cs:L18-82
  • GroupChatOrchestration.cs:L15-97
  • HandoffOrchestration.cs:L17-114

Principle page: Multi-Agent Orchestration

Principle:Microsoft_Semantic_kernel_Multi_Agent_Orchestration

Code Reference

ConcurrentOrchestration

public class ConcurrentOrchestration : AgentOrchestration<string[]>
{
    public ConcurrentOrchestration(params ChatCompletionAgent[] agents);

    public Task<OrchestrationResult<string[]>> InvokeAsync(
        string input,
        InProcessRuntime runtime,
        CancellationToken cancellationToken = default);
}

All agents receive the same input in parallel. Results are collected as a string[] with one entry per agent.

GroupChatOrchestration

public class GroupChatOrchestration : AgentOrchestration<string>
{
    public GroupChatOrchestration(
        GroupChatManager manager,
        params ChatCompletionAgent[] agents);

    public Task<OrchestrationResult<string>> InvokeAsync(
        string input,
        InProcessRuntime runtime,
        CancellationToken cancellationToken = default);
}

Agents take turns in a managed conversation. The GroupChatManager controls turn order and termination.

RoundRobinGroupChatManager

public class RoundRobinGroupChatManager : GroupChatManager
{
    public int MaximumInvocationCount { get; set; }
}

Cycles through agents in the order they were provided, stopping after MaximumInvocationCount total turns.

HandoffOrchestration

public class HandoffOrchestration : AgentOrchestration<string>
{
    public HandoffOrchestration(
        OrchestrationHandoffs handoffs,
        params ChatCompletionAgent[] agents);

    public Task<OrchestrationResult<string>> InvokeAsync(
        string input,
        InProcessRuntime runtime,
        CancellationToken cancellationToken = default);
}

Agents dynamically hand off control based on conversation context and defined handoff rules.

OrchestrationHandoffs Builder

public class OrchestrationHandoffs
{
    public static OrchestrationHandoffs StartWith(ChatCompletionAgent startAgent);
    public OrchestrationHandoffs Add(
        ChatCompletionAgent fromAgent,
        ChatCompletionAgent[] toAgents);
}

A fluent builder that defines the starting agent and the directed graph of permitted handoff transitions.

I/O Contract

ConcurrentOrchestration

Input:
├── agents: ChatCompletionAgent[] → All agents to run in parallel
├── input: string                 → The message sent to all agents
└── runtime: InProcessRuntime     → Must be started before invocation

Output: OrchestrationResult<string[]>
└── GetValueAsync() → string[]
    ├── results[0]: Response from first agent
    ├── results[1]: Response from second agent
    └── results[N]: Response from Nth agent

GroupChatOrchestration

Input:
├── manager: GroupChatManager     → Controls turn order and termination
├── agents: ChatCompletionAgent[] → Participants in the group chat
├── input: string                 → Initial message to start the conversation
└── runtime: InProcessRuntime     → Must be started before invocation

Output: OrchestrationResult<string>
└── GetValueAsync() → string
    └── The final message from the last agent to speak

HandoffOrchestration

Input:
├── handoffs: OrchestrationHandoffs → Defines start agent and handoff graph
├── agents: ChatCompletionAgent[]   → All participating agents
├── input: string                   → Initial message routed to start agent
└── runtime: InProcessRuntime       → Must be started before invocation

Output: OrchestrationResult<string>
└── GetValueAsync() → string
    └── The final response from whichever agent last handled the conversation

Usage Examples

Concurrent Orchestration

// Create specialized agents
ChatCompletionAgent writer = new()
{
    Name = "Writer",
    Instructions = "Write a short story on the given topic.",
    Kernel = kernel
};

ChatCompletionAgent reviewer = new()
{
    Name = "Reviewer",
    Instructions = "Write a critical review of the given topic.",
    Kernel = kernel
};

// Set up runtime and orchestration
InProcessRuntime runtime = new();
await runtime.StartAsync();

ConcurrentOrchestration orchestration = new(writer, reviewer);
OrchestrationResult<string[]> result = await orchestration.InvokeAsync(
    "Write a story about a brave knight", runtime);

// Collect results
string[] results = await result.GetValueAsync(TimeSpan.FromSeconds(300));
await runtime.RunUntilIdleAsync();

Console.WriteLine($"Writer: {results[0]}");
Console.WriteLine($"Reviewer: {results[1]}");

Group Chat Orchestration

ChatCompletionAgent writer = new()
{
    Name = "Writer",
    Instructions = "Write or revise content based on feedback.",
    Kernel = kernel
};

ChatCompletionAgent reviewer = new()
{
    Name = "Reviewer",
    Instructions = "Review the content and provide constructive feedback.",
    Kernel = kernel
};

InProcessRuntime runtime = new();
await runtime.StartAsync();

GroupChatOrchestration groupChat = new(
    new RoundRobinGroupChatManager { MaximumInvocationCount = 5 },
    writer, reviewer);

OrchestrationResult<string> result = await groupChat.InvokeAsync(
    "Write a haiku about autumn", runtime);

string finalResponse = await result.GetValueAsync(TimeSpan.FromSeconds(300));
await runtime.RunUntilIdleAsync();

Console.WriteLine($"Final: {finalResponse}");

Handoff Orchestration

ChatCompletionAgent triageAgent = new()
{
    Name = "Triage",
    Instructions = "Assess the customer request. Hand off to Billing for payment issues or Refund for return requests.",
    Kernel = kernel
};

ChatCompletionAgent billingAgent = new()
{
    Name = "Billing",
    Instructions = "Handle billing and payment inquiries. Hand back to Triage if the issue is not billing-related.",
    Kernel = kernel
};

ChatCompletionAgent refundAgent = new()
{
    Name = "Refund",
    Instructions = "Process refund and return requests.",
    Kernel = kernel
};

InProcessRuntime runtime = new();
await runtime.StartAsync();

HandoffOrchestration handoff = new(
    OrchestrationHandoffs.StartWith(triageAgent)
        .Add(triageAgent, [billingAgent, refundAgent])
        .Add(billingAgent, [triageAgent]),
    triageAgent, billingAgent, refundAgent);

OrchestrationResult<string> result = await handoff.InvokeAsync(
    "I was charged twice for my order #12345", runtime);

string finalResponse = await result.GetValueAsync(TimeSpan.FromSeconds(300));
await runtime.RunUntilIdleAsync();

Console.WriteLine($"Resolution: {finalResponse}");

Related Pages

Uses Heuristic

Page Connections

Double-click a node to navigate. Hold to expand connections.
Principle
Implementation
Heuristic
Environment