Skip to content

Commit 85c8867

Browse files
authored
Merge pull request #401 from microsoft/08-multi-agent-dotnet
feat: Chapter 08 Migrate .NET Multi-Agent Workflow Notebooks to Single File App Format
2 parents b203e59 + 9fb726e commit 85c8867

8 files changed

+1664
-0
lines changed
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
#!/usr/bin/dotnet run
2+
#:package Microsoft.Extensions.AI@9.9.1
3+
#:package System.ClientModel@1.6.1.0
4+
#:package Azure.Identity@1.15.0
5+
#:package System.Linq.Async@6.0.3
6+
#:package OpenTelemetry.Api@1.0.0
7+
#:package Microsoft.Agents.AI.Workflows@1.0.0-preview.251001.3
8+
#:package Microsoft.Agents.AI.OpenAI@1.0.0-preview.251001.3
9+
#:package DotNetEnv@3.1.1
10+
11+
using System;
12+
using System.ComponentModel;
13+
using System.ClientModel;
14+
using OpenAI;
15+
using Azure.Identity;
16+
using Microsoft.Extensions.AI;
17+
using Microsoft.Agents.AI;
18+
using Microsoft.Agents.AI.Workflows;
19+
using DotNetEnv;
20+
21+
// Load environment variables from .env file
22+
Env.Load("../../../.env");
23+
24+
// Configure GitHub Models endpoint and credentials
25+
var github_endpoint = Environment.GetEnvironmentVariable("GITHUB_ENDPOINT") ?? throw new InvalidOperationException("GITHUB_ENDPOINT is not set.");
26+
var github_model_id = Environment.GetEnvironmentVariable("GITHUB_MODEL_ID") ?? "gpt-4o-mini";
27+
var github_token = Environment.GetEnvironmentVariable("GITHUB_TOKEN") ?? throw new InvalidOperationException("GITHUB_TOKEN is not set.");
28+
29+
// Configure OpenAI client options with GitHub Models endpoint
30+
var openAIOptions = new OpenAIClientOptions()
31+
{
32+
Endpoint = new Uri(github_endpoint)
33+
};
34+
35+
// Create OpenAI client with API key credential
36+
var openAIClient = new OpenAIClient(new ApiKeyCredential(github_token), openAIOptions);
37+
38+
// Define Reviewer Agent (Concierge) configuration
39+
const string ReviewerAgentName = "Concierge";
40+
const string ReviewerAgentInstructions = @"
41+
You are a hotel concierge who has opinions about providing the most local and authentic experiences for travelers.
42+
The goal is to determine if the front desk travel agent has recommended the best non-touristy experience for a traveler.
43+
If so, state that it is approved.
44+
If not, provide insight on how to refine the recommendation without using a specific example. ";
45+
46+
// Define Front Desk Agent configuration
47+
const string FrontDeskAgentName = "FrontDesk";
48+
const string FrontDeskAgentInstructions = @"""
49+
You are a Front Desk Travel Agent with ten years of experience and are known for brevity as you deal with many customers.
50+
The goal is to provide the best activities and locations for a traveler to visit.
51+
Only provide a single recommendation per response.
52+
You're laser focused on the goal at hand.
53+
Don't waste time with chit chat.
54+
Consider suggestions when refining an idea.
55+
""";
56+
57+
// Create AI agents with specialized instructions
58+
AIAgent reviewerAgent = openAIClient.GetChatClient(github_model_id).CreateAIAgent(
59+
name: ReviewerAgentName, instructions: ReviewerAgentInstructions);
60+
AIAgent frontDeskAgent = openAIClient.GetChatClient(github_model_id).CreateAIAgent(
61+
name: FrontDeskAgentName, instructions: FrontDeskAgentInstructions);
62+
63+
// Build workflow with sequential agent execution
64+
var workflow = new WorkflowBuilder(frontDeskAgent)
65+
.AddEdge(frontDeskAgent, reviewerAgent)
66+
.Build();
67+
68+
// Create user message for travel recommendation
69+
ChatMessage userMessage = new ChatMessage(ChatRole.User, [
70+
new TextContent("I would like to go to Paris.")
71+
]);
72+
73+
// Execute workflow with streaming
74+
StreamingRun run = await InProcessExecution.StreamAsync(workflow, userMessage);
75+
76+
// Process workflow events and collect results
77+
await run.TrySendMessageAsync(new TurnToken(emitEvents: true));
78+
string id = "";
79+
string messageData = "";
80+
await foreach (WorkflowEvent evt in run.WatchStreamAsync().ConfigureAwait(false))
81+
{
82+
if (evt is AgentRunUpdateEvent executorComplete)
83+
{
84+
if (id == "")
85+
{
86+
id = executorComplete.ExecutorId;
87+
}
88+
if (id == executorComplete.ExecutorId)
89+
{
90+
messageData += executorComplete.Data.ToString();
91+
}
92+
else
93+
{
94+
id = executorComplete.ExecutorId;
95+
}
96+
}
97+
}
98+
99+
// Display final workflow results
100+
Console.WriteLine(messageData);
Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
# 🔄 Basic Agent Workflows with GitHub Models (.NET)
2+
3+
## 📋 Workflow Orchestration Tutorial
4+
5+
This notebook demonstrates how to build sophisticated **agent workflows** using the Microsoft Agent Framework for .NET and GitHub Models. You'll learn to create multi-step business processes where AI agents collaborate to accomplish complex tasks through structured orchestration patterns.
6+
7+
## 🎯 Learning Objectives
8+
9+
### 🏗️ **Workflow Architecture Fundamentals**
10+
- **Workflow Builder**: Design and orchestrate complex multi-step AI processes
11+
- **Agent Coordination**: Coordinate multiple specialized agents within workflows
12+
- **GitHub Models Integration**: Leverage GitHub's AI model inference service in workflows
13+
- **Visual Workflow Design**: Create and visualize workflow structures for better understanding
14+
15+
### 🔄 **Process Orchestration Patterns**
16+
- **Sequential Processing**: Chain multiple agent tasks in logical order
17+
- **State Management**: Maintain context and data flow across workflow stages
18+
- **Error Handling**: Implement robust error recovery and workflow resilience
19+
- **Performance Optimization**: Design efficient workflows for enterprise-scale operations
20+
21+
### 🏢 **Enterprise Workflow Applications**
22+
- **Business Process Automation**: Automate complex organizational workflows
23+
- **Content Production Pipeline**: Editorial workflows with review and approval stages
24+
- **Customer Service Automation**: Multi-step customer inquiry resolution
25+
- **Data Processing Workflows**: ETL workflows with AI-powered transformation
26+
27+
## ⚙️ Prerequisites & Setup
28+
29+
### 📦 **Required NuGet Packages**
30+
31+
This workflow demonstration uses several key .NET packages:
32+
33+
```xml
34+
<!-- Core AI Framework -->
35+
<PackageReference Include="Microsoft.Extensions.AI" Version="9.9.0" />
36+
37+
<!-- Agent Framework (Local Development) -->
38+
<!-- Microsoft.Agents.AI.dll - Core agent abstractions -->
39+
<!-- Microsoft.Agents.AI.OpenAI.dll - OpenAI/GitHub Models integration -->
40+
41+
<!-- Configuration and Environment -->
42+
<PackageReference Include="DotNetEnv" Version="3.1.1" />
43+
```
44+
45+
### 🔑 **GitHub Models Configuration**
46+
47+
**Environment Setup (.env file):**
48+
```env
49+
GITHUB_TOKEN=your_github_personal_access_token
50+
GITHUB_ENDPOINT=https://models.inference.ai.azure.com
51+
GITHUB_MODEL_ID=gpt-4o-mini
52+
```
53+
54+
**GitHub Models Access:**
55+
1. Sign up for GitHub Models (currently in preview)
56+
2. Generate a personal access token with model access permissions
57+
3. Configure environment variables as shown above
58+
59+
### 🏗️ **Workflow Architecture Overview**
60+
61+
```mermaid
62+
graph TD
63+
A[Workflow Builder] --> B[Agent Registry]
64+
B --> C[Workflow Execution Engine]
65+
C --> D[Agent 1: Content Generator]
66+
C --> E[Agent 2: Content Reviewer]
67+
D --> F[Workflow Results]
68+
E --> F
69+
G[GitHub Models API] --> D
70+
G --> E
71+
```
72+
73+
**Key Components:**
74+
- **WorkflowBuilder**: Main orchestration engine for designing workflows
75+
- **AIAgent**: Individual specialized agents with specific capabilities
76+
- **GitHub Models Client**: AI model inference service integration
77+
- **Execution Context**: Manages state and data flow between workflow stages
78+
79+
## 🎨 **Enterprise Workflow Design Patterns**
80+
81+
### 📝 **Content Production Workflow**
82+
```
83+
User Request → Content Generation → Quality Review → Final Output
84+
```
85+
86+
### 🔍 **Document Processing Pipeline**
87+
```
88+
Document Input → Analysis → Extraction → Validation → Structured Output
89+
```
90+
91+
### 💼 **Business Intelligence Workflow**
92+
```
93+
Data Collection → Processing → Analysis → Report Generation → Distribution
94+
```
95+
96+
### 🤝 **Customer Service Automation**
97+
```
98+
Customer Inquiry → Classification → Processing → Response Generation → Follow-up
99+
```
100+
101+
## 🏢 **Enterprise Benefits**
102+
103+
### 🎯 **Reliability & Scalability**
104+
- **Deterministic Execution**: Consistent, repeatable workflow outcomes
105+
- **Error Recovery**: Graceful handling of failures at any workflow stage
106+
- **Performance Monitoring**: Track execution metrics and optimization opportunities
107+
- **Resource Management**: Efficient allocation and utilization of AI model resources
108+
109+
### 🔒 **Security & Compliance**
110+
- **Secure Authentication**: GitHub token-based authentication for API access
111+
- **Audit Trails**: Complete logging of workflow execution and decision points
112+
- **Access Control**: Granular permissions for workflow execution and monitoring
113+
- **Data Privacy**: Secure handling of sensitive information throughout workflows
114+
115+
### 📊 **Observability & Management**
116+
- **Visual Workflow Design**: Clear representation of process flows and dependencies
117+
- **Execution Monitoring**: Real-time tracking of workflow progress and performance
118+
- **Error Reporting**: Detailed error analysis and debugging capabilities
119+
- **Performance Analytics**: Metrics for optimization and capacity planning
120+
121+
Let's build your first enterprise-ready AI workflow! 🚀
122+
123+
## 💻 Running the Code
124+
125+
The complete implementation is available in `01.dotnet-agent-framework-workflow-ghmodel-basic.cs`. This file demonstrates:
126+
127+
1. **Environment Configuration** - Loading GitHub Models credentials from `.env` file
128+
2. **OpenAI Client Setup** - Configuring the client to use GitHub Models endpoint
129+
3. **Agent Creation** - Defining specialized agents (Front Desk and Concierge)
130+
4. **Workflow Builder** - Creating a multi-agent workflow with sequential processing
131+
5. **Workflow Execution** - Running the workflow with streaming results
132+
133+
### 🚀 Running the Example
134+
135+
```bash
136+
# Make the script executable (Unix/Linux/macOS)
137+
chmod +x 01.dotnet-agent-framework-workflow-ghmodel-basic.cs
138+
139+
# Run the workflow
140+
./01.dotnet-agent-framework-workflow-ghmodel-basic.cs
141+
```
142+
143+
Or on Windows:
144+
```powershell
145+
dotnet run 01.dotnet-agent-framework-workflow-ghmodel-basic.cs
146+
```
147+
148+
### 📝 Expected Output
149+
150+
The workflow will:
151+
1. Accept your travel destination request ("I would like to go to Paris")
152+
2. The Front Desk agent provides an initial recommendation
153+
3. The Concierge agent reviews and refines the recommendation
154+
4. Final output displays the complete conversation stream
155+
156+
### 🔧 Customization
157+
158+
You can customize the workflow by:
159+
- Modifying agent instructions to change their behavior
160+
- Adding more agents to create complex multi-step workflows
161+
- Changing the user message to test different scenarios
162+
- Adjusting the workflow edges to create different execution patterns
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
#!/usr/bin/dotnet run
2+
#:package Microsoft.Extensions.AI@9.9.1
3+
#:package System.ClientModel@1.6.1.0
4+
#:package Azure.Identity@1.15.0
5+
#:package System.Linq.Async@6.0.3
6+
#:package OpenTelemetry.Api@1.0.0
7+
#:package Microsoft.Agents.AI.Workflows@1.0.0-preview.251001.3
8+
#:package Microsoft.Agents.AI.OpenAI@1.0.0-preview.251001.3
9+
#:package DotNetEnv@3.1.1
10+
11+
using System;
12+
using System.ComponentModel;
13+
using System.ClientModel;
14+
using System.IO;
15+
using OpenAI;
16+
using Azure.Identity;
17+
using Microsoft.Extensions.AI;
18+
using Microsoft.Agents.AI;
19+
using Microsoft.Agents.AI.Workflows;
20+
using DotNetEnv;
21+
22+
// Load environment variables from .env file
23+
Env.Load("../../../.env");
24+
25+
// Configure GitHub Models endpoint and credentials
26+
var github_endpoint = Environment.GetEnvironmentVariable("GITHUB_ENDPOINT") ?? throw new InvalidOperationException("GITHUB_ENDPOINT is not set.");
27+
var github_model_id = "gpt-4o"; // Using GPT-4o for vision capabilities
28+
var github_token = Environment.GetEnvironmentVariable("GITHUB_TOKEN") ?? throw new InvalidOperationException("GITHUB_TOKEN is not set.");
29+
30+
// Path to furniture image for analysis
31+
var imgPath = "../imgs/home.png";
32+
33+
// Configure OpenAI client options with GitHub Models endpoint
34+
var openAIOptions = new OpenAIClientOptions()
35+
{
36+
Endpoint = new Uri(github_endpoint)
37+
};
38+
39+
// Create OpenAI client with API key credential
40+
var openAIClient = new OpenAIClient(new ApiKeyCredential(github_token), openAIOptions);
41+
42+
// Define Sales Agent (Stage 1) - Furniture Analysis
43+
const string SalesAgentName = "Sales-Agent";
44+
const string SalesAgentInstructions = "You are my furniture sales consultant, you can find different furniture elements from the pictures and give me a purchase suggestion";
45+
46+
// Define Price Agent (Stage 2) - Pricing Specialist
47+
const string PriceAgentName = "Price-Agent";
48+
const string PriceAgentInstructions = @"You are a furniture pricing specialist and budget consultant. Your responsibilities include:
49+
1. Analyze furniture items and provide realistic price ranges based on quality, brand, and market standards
50+
2. Break down pricing by individual furniture pieces
51+
3. Provide budget-friendly alternatives and premium options
52+
4. Consider different price tiers (budget, mid-range, premium)
53+
5. Include estimated total costs for room setups
54+
6. Suggest where to find the best deals and shopping recommendations
55+
7. Factor in additional costs like delivery, assembly, and accessories
56+
8. Provide seasonal pricing insights and best times to buy
57+
Always format your response with clear price breakdowns and explanations for the pricing rationale.";
58+
59+
// Define Quote Agent (Stage 3) - Quote Document Generator
60+
const string QuoteAgentName = "Quote-Agent";
61+
const string QuoteAgentInstructions = @"You are an assistant that creates a quote for furniture purchase.
62+
1. Create a well-structured quote document that includes:
63+
2. A title page with the document title, date, and client name
64+
3. An introduction summarizing the purpose of the document
65+
4. A summary section with total estimated costs and recommendations
66+
5. Use clear headings, bullet points, and tables for easy readability
67+
6. All quotes are presented in markdown form";
68+
69+
// Helper function to load image as byte array
70+
async Task<byte[]> OpenImageBytesAsync(string path)
71+
{
72+
return await File.ReadAllBytesAsync(path);
73+
}
74+
75+
// Load furniture image for analysis
76+
var imageBytes = await OpenImageBytesAsync(imgPath);
77+
78+
// Create AI agents for the sequential workflow
79+
AIAgent salesagent = openAIClient.GetChatClient(github_model_id).CreateAIAgent(
80+
name: SalesAgentName, instructions: SalesAgentInstructions);
81+
AIAgent priceagent = openAIClient.GetChatClient(github_model_id).CreateAIAgent(
82+
name: PriceAgentName, instructions: PriceAgentInstructions);
83+
AIAgent quoteagent = openAIClient.GetChatClient(github_model_id).CreateAIAgent(
84+
name: QuoteAgentName, instructions: QuoteAgentInstructions);
85+
86+
// Build sequential workflow: Sales → Price → Quote
87+
var workflow = new WorkflowBuilder(salesagent)
88+
.AddEdge(salesagent, priceagent)
89+
.AddEdge(priceagent, quoteagent)
90+
.Build();
91+
92+
// Create user message with image and instructions
93+
ChatMessage userMessage = new ChatMessage(ChatRole.User, [
94+
new DataContent(imageBytes, "image/png"),
95+
new TextContent("Please find the relevant furniture according to the image and give the corresponding price for each piece of furniture. Finally output generates a quotation")
96+
]);
97+
98+
// Execute workflow with streaming
99+
StreamingRun run = await InProcessExecution.StreamAsync(workflow, userMessage);
100+
101+
// Process workflow events and collect results
102+
await run.TrySendMessageAsync(new TurnToken(emitEvents: true));
103+
string id = "";
104+
string messageData = "";
105+
await foreach (WorkflowEvent evt in run.WatchStreamAsync().ConfigureAwait(false))
106+
{
107+
if (evt is AgentRunUpdateEvent executorComplete)
108+
{
109+
if (id == "")
110+
{
111+
id = executorComplete.ExecutorId;
112+
}
113+
if (id == executorComplete.ExecutorId)
114+
{
115+
messageData += executorComplete.Data.ToString();
116+
}
117+
else
118+
{
119+
id = executorComplete.ExecutorId;
120+
}
121+
}
122+
}
123+
124+
// Display final workflow results (complete quote document)
125+
Console.WriteLine(messageData);

0 commit comments

Comments
 (0)