Build a Multi-Agent Workflow
A single agent works well for focused tasks. But real-world problems often require multiple perspectives or sequential processing stages. LM-Kit.NET ships three orchestration patterns that let you coordinate multiple agents without writing glue code: parallel execution, sequential pipelines, and supervisor-driven delegation.
This tutorial builds all three patterns so you can pick the one that fits your use case.
When to Use Each Pattern
| Pattern | Orchestrator | How It Works | Use Case |
|---|---|---|---|
| Parallel | ParallelOrchestrator |
Runs all agents simultaneously on the same input, then merges results | Document review from multiple angles, consensus gathering, multi-perspective analysis |
| Pipeline | PipelineOrchestrator |
Chains agents in sequence; each stage's output becomes the next stage's input | Content creation, data processing, quality assurance chains |
| Supervisor | SupervisorOrchestrator |
A supervisor agent reads the user's request and delegates to the best worker | Help desks, smart routing, heterogeneous task handling |
Prerequisites
| Requirement | Minimum |
|---|---|
| .NET SDK | 8.0+ |
| VRAM | 4+ GB (all agents share the same model instance) |
All agents in this tutorial share one loaded model, so VRAM requirements do not multiply per agent.
Step 1: Create the Project
dotnet new console -n MultiAgentQuickstart
cd MultiAgentQuickstart
dotnet add package LM-Kit.NET
Pattern A: Parallel Agents (Multi-Perspective Analysis)
Multiple agents analyze the same input simultaneously. Useful when you need independent viewpoints merged into a single summary.
What this builds: three reviewers (technical, business, security) that analyze a software proposal in parallel and produce a consolidated review.
using System.Text;
using LMKit.Model;
using LMKit.Agents;
using LMKit.Agents.Orchestration;
LMKit.Licensing.LicenseManager.SetLicenseKey("");
Console.InputEncoding = Encoding.UTF8;
Console.OutputEncoding = Encoding.UTF8;
// 1. Load model (shared by all agents)
Console.WriteLine("Loading model...");
using LM model = LM.LoadFromModelID("qwen3:4b",
downloadingProgress: (_, len, read) =>
{
if (len.HasValue) Console.Write($"\r Downloading: {(double)read / len.Value * 100:F1}% ");
return true;
},
loadingProgress: p => { Console.Write($"\r Loading: {p * 100:F0}% "); return true; });
Console.WriteLine("\n");
// 2. Create specialized agents
var technicalReviewer = new Agent(
new AgentIdentity(
persona: "Senior Software Architect",
instruction: "Review the proposal focusing on technical feasibility, architecture quality, " +
"scalability concerns, and technology choices. Be specific and actionable."
), model);
var businessAnalyst = new Agent(
new AgentIdentity(
persona: "Business Analyst",
instruction: "Review the proposal focusing on ROI, market fit, resource requirements, " +
"timeline realism, and business risks. Quantify impact where possible."
), model);
var securityReviewer = new Agent(
new AgentIdentity(
persona: "Security Engineer",
instruction: "Review the proposal focusing on security implications, data privacy, " +
"compliance requirements, and attack surface. Flag any red flags."
), model);
// 3. Wire them into a parallel orchestrator
var orchestrator = new ParallelOrchestrator()
.AddAgent("Technical", technicalReviewer)
.AddAgent("Business", businessAnalyst)
.AddAgent("Security", securityReviewer);
// 4. Execute
string proposal =
"We propose building a customer-facing chatbot that accesses our internal CRM database " +
"to answer account questions. The chatbot will use a cloud-hosted LLM API, store conversation " +
"logs in a new PostgreSQL database, and integrate with our existing SSO system. " +
"Estimated timeline: 8 weeks with 2 developers.";
Console.WriteLine("Submitting proposal to 3 reviewers in parallel...\n");
var result = await orchestrator.ExecuteAsync(proposal);
// 5. Display individual reviews
foreach (var agentResult in result.AgentResults)
{
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine($"=== {agentResult.AgentName} ===");
Console.ResetColor();
Console.WriteLine(agentResult.Content);
Console.WriteLine();
}
// 6. Display aggregated summary
Console.ForegroundColor = ConsoleColor.Cyan;
Console.WriteLine("=== Consolidated Summary ===");
Console.ResetColor();
Console.WriteLine(result.Content);
Console.WriteLine($"\nCompleted in {result.Duration.TotalSeconds:F1}s");
Pattern B: Pipeline Agents (Sequential Processing)
Each stage processes the previous stage's output. Useful for workflows where order matters: draft, then refine, then verify.
What this builds: a content pipeline that outlines, writes, and edits an article in sequence.
using System.Text;
using LMKit.Model;
using LMKit.Agents;
using LMKit.Agents.Orchestration;
LMKit.Licensing.LicenseManager.SetLicenseKey("");
Console.InputEncoding = Encoding.UTF8;
Console.OutputEncoding = Encoding.UTF8;
// 1. Load model
Console.WriteLine("Loading model...");
using LM model = LM.LoadFromModelID("qwen3:4b",
loadingProgress: p => { Console.Write($"\r Loading: {p * 100:F0}% "); return true; });
Console.WriteLine("\n");
// 2. Create pipeline stages
var outliner = new Agent(
new AgentIdentity(
persona: "Content Strategist",
instruction: "Create a structured outline with 4-5 sections for the given topic. " +
"Include a brief description of what each section should cover."
), model);
var writer = new Agent(
new AgentIdentity(
persona: "Technical Writer",
instruction: "Take the outline provided and write a complete article. " +
"Use clear language, practical examples, and keep paragraphs short."
), model);
var editor = new Agent(
new AgentIdentity(
persona: "Editor",
instruction: "Review and improve the article. Fix grammar, tighten prose, " +
"ensure logical flow, and verify factual claims are reasonable. " +
"Output the final polished version."
), model);
// 3. Chain into a pipeline
var pipeline = new PipelineOrchestrator()
.AddStage("Outline", outliner)
.AddStage("Draft", writer)
.AddStage("Edit", editor);
// 4. Execute
Console.WriteLine("Starting content pipeline...\n");
var result = await pipeline.ExecuteAsync("Getting Started with Local AI in .NET Applications");
// 5. Show each stage's output
foreach (var stageResult in result.AgentResults)
{
Console.ForegroundColor = ConsoleColor.Yellow;
Console.WriteLine($"--- Stage: {stageResult.AgentName} ---");
Console.ResetColor();
if (stageResult.IsSuccess)
{
// Show first 300 chars as preview
string preview = stageResult.Content.Length > 300
? stageResult.Content.Substring(0, 300) + "..."
: stageResult.Content;
Console.WriteLine(preview);
}
else
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine($"Failed: {stageResult.Error?.Message}");
Console.ResetColor();
}
Console.WriteLine();
}
// 6. Final article
Console.ForegroundColor = ConsoleColor.Cyan;
Console.WriteLine("=== Final Article ===");
Console.ResetColor();
Console.WriteLine(result.Content);
Console.WriteLine($"\nPipeline completed in {result.Duration.TotalSeconds:F1}s");
Pattern C: Supervisor Agent (Intelligent Routing)
A supervisor agent reads each request and delegates to the most appropriate worker. Useful when incoming requests vary in type and you want automatic routing.
What this builds: a help desk where a supervisor routes requests to a code expert, a documentation writer, or a data analyst.
using System.Text;
using LMKit.Model;
using LMKit.Agents;
using LMKit.Agents.Orchestration;
LMKit.Licensing.LicenseManager.SetLicenseKey("");
Console.InputEncoding = Encoding.UTF8;
Console.OutputEncoding = Encoding.UTF8;
// 1. Load model
Console.WriteLine("Loading model...");
using LM model = LM.LoadFromModelID("qwen3:4b",
loadingProgress: p => { Console.Write($"\r Loading: {p * 100:F0}% "); return true; });
Console.WriteLine("\n");
// 2. Create specialist workers
var codeExpert = new Agent(
new AgentIdentity(
persona: "Senior Developer",
instruction: "You are an expert C# and .NET developer. Answer coding questions with " +
"working code examples. Explain your reasoning step by step."
), model);
var docWriter = new Agent(
new AgentIdentity(
persona: "Technical Writer",
instruction: "You write clear, concise documentation. When asked about a topic, " +
"produce well-structured documentation with headings and examples."
), model);
var dataAnalyst = new Agent(
new AgentIdentity(
persona: "Data Analyst",
instruction: "You analyze data and provide insights. When given data or a question " +
"about data, provide statistical reasoning and clear conclusions."
), model);
// 3. Create supervisor
var supervisorAgent = new Agent(
new AgentIdentity(
persona: "Team Lead",
instruction: "You manage a team of specialists. Route each request to the best worker. " +
"If a request spans multiple domains, delegate to the most relevant expert."
), model);
var supervisor = new SupervisorOrchestrator(supervisorAgent)
.AddWorker(codeExpert)
.AddWorker(docWriter)
.AddWorker(dataAnalyst);
// 4. Optional: observe routing decisions
supervisor.BeforeAgentExecution += (sender, e) =>
{
Console.ForegroundColor = ConsoleColor.DarkGray;
Console.WriteLine($" [Routing to agent...]");
Console.ResetColor();
};
supervisor.AfterAgentExecution += (sender, e) =>
{
Console.ForegroundColor = ConsoleColor.DarkGray;
Console.WriteLine($" [Agent completed: {e.Result.Status}]");
Console.ResetColor();
};
// 5. Interactive loop
Console.WriteLine("Help desk ready. Type a question (or 'quit' to exit):\n");
while (true)
{
Console.ForegroundColor = ConsoleColor.Green;
Console.Write("You: ");
Console.ResetColor();
string? input = Console.ReadLine();
if (string.IsNullOrWhiteSpace(input) || input.Equals("quit", StringComparison.OrdinalIgnoreCase))
break;
var result = await supervisor.ExecuteAsync(input);
Console.ForegroundColor = ConsoleColor.Cyan;
Console.WriteLine($"\nResponse: {result.Content}");
Console.ResetColor();
Console.WriteLine($" [Agents involved: {result.AgentResults.Count}, Duration: {result.Duration.TotalSeconds:F1}s]\n");
}
Choosing the Right Pattern
Use this decision table:
| Question | If Yes | If No |
|---|---|---|
| Do agents need to see each other's output? | Pipeline or Supervisor | Parallel |
| Is order important? | Pipeline | Parallel |
| Are tasks heterogeneous (different types of requests)? | Supervisor | Pipeline or Parallel |
| Do you need consensus from multiple viewpoints? | Parallel | Pipeline or Supervisor |
| Is latency critical? | Parallel (fastest wall-clock time) | Pipeline (sequential) |
You can also nest orchestrators. For example, a supervisor that delegates to a pipeline:
// A supervisor routes to either a quick-answer agent or a full pipeline
var quickAnswer = new Agent(new AgentIdentity(
persona: "Quick Responder",
instruction: "Give brief, direct answers to simple questions."
), model);
var researchPipeline = new PipelineOrchestrator()
.AddStage("Research", researchAgent)
.AddStage("Synthesize", synthesisAgent);
// The supervisor chooses between quick answer and deep research
Performance Considerations
Shared model instance. All agents in this tutorial share one LM instance. This means:
- VRAM usage stays constant regardless of agent count.
- Agents in a
ParallelOrchestratortake turns on the model internally (they do not run on separate GPU threads). - Parallel orchestration reduces wall-clock time by batching, but throughput is still bounded by the single model.
Model size tradeoff. Smaller models (1B-4B) run faster per agent but may produce lower-quality reasoning. For orchestration workflows where each agent has a narrow role, 4B models often perform well because each agent's task is tightly scoped.
MaxIterations. If your agents use tools (via WithPlanning(PlanningStrategy.ReAct)), set MaxIterations appropriately. A pipeline with 3 tool-using stages at 10 iterations each could take significant time.
Common Issues
| Problem | Cause | Fix |
|---|---|---|
| Supervisor always picks the same worker | Supervisor persona too vague | Make the supervisor instruction explicitly list each worker's specialty |
| Pipeline stage ignores previous output | Stage instruction doesn't mention "use the provided input" | Explicitly tell each stage to build on the input it receives |
| Parallel results are inconsistent | Agents interpreting the prompt differently | Add a shared preamble to the input describing the expected analysis format |
| Slow execution | Model too large, or too many tool iterations | Use a 4B model for orchestrated agents; reduce MaxIterations |
Next Steps
- Create an AI Agent with Tools: add tool-calling capabilities to your agents before orchestrating them.
- Build a RAG Pipeline Over Your Own Documents: ground agent responses in your own data.
- Samples: Multi-Agent Document Review: full parallel review demo.
- Samples: Content Creation Pipeline: full pipeline demo.
- Samples: Smart Task Router: full supervisor delegation demo.