chore: import upstream snapshot with attribution
This commit is contained in:
+92
@@ -0,0 +1,92 @@
|
||||
#!/usr/bin/dotnet run
|
||||
#:package Microsoft.Extensions.AI@9.9.1
|
||||
#:package Azure.AI.OpenAI@2.1.0
|
||||
#:package Azure.Identity@1.15.0
|
||||
#:package System.Linq.Async@6.0.3
|
||||
#:package OpenTelemetry.Api@1.0.0
|
||||
#:package Microsoft.Agents.AI.Workflows@1.0.0-preview.251001.3
|
||||
#:package Microsoft.Agents.AI.OpenAI@1.0.0-preview.251001.3
|
||||
#:package DotNetEnv@3.1.1
|
||||
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using Azure.AI.OpenAI;
|
||||
using Azure.Identity;
|
||||
using Microsoft.Extensions.AI;
|
||||
using Microsoft.Agents.AI;
|
||||
using Microsoft.Agents.AI.Workflows;
|
||||
using DotNetEnv;
|
||||
|
||||
// Load environment variables from .env file
|
||||
Env.Load("../../../.env");
|
||||
|
||||
// Azure OpenAI with the Responses API (stable v1 endpoint). Sign in with `az login`.
|
||||
var azureEndpoint = Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT")
|
||||
?? throw new InvalidOperationException("AZURE_OPENAI_ENDPOINT is not set.");
|
||||
var deployment = Environment.GetEnvironmentVariable("AZURE_OPENAI_DEPLOYMENT") ?? "gpt-4o-mini";
|
||||
|
||||
var azureClient = new AzureOpenAIClient(new Uri(azureEndpoint), new AzureCliCredential());
|
||||
|
||||
// Define Reviewer Agent (Concierge) configuration
|
||||
const string ReviewerAgentName = "Concierge";
|
||||
const string ReviewerAgentInstructions = @"
|
||||
You are a hotel concierge who has opinions about providing the most local and authentic experiences for travelers.
|
||||
The goal is to determine if the front desk travel agent has recommended the best non-touristy experience for a traveler.
|
||||
If so, state that it is approved.
|
||||
If not, provide insight on how to refine the recommendation without using a specific example. ";
|
||||
|
||||
// Define Front Desk Agent configuration
|
||||
const string FrontDeskAgentName = "FrontDesk";
|
||||
const string FrontDeskAgentInstructions = @"""
|
||||
You are a Front Desk Travel Agent with ten years of experience and are known for brevity as you deal with many customers.
|
||||
The goal is to provide the best activities and locations for a traveler to visit.
|
||||
Only provide a single recommendation per response.
|
||||
You're laser focused on the goal at hand.
|
||||
Don't waste time with chit chat.
|
||||
Consider suggestions when refining an idea.
|
||||
""";
|
||||
|
||||
// Create AI agents with specialized instructions
|
||||
AIAgent reviewerAgent = azureClient.GetOpenAIResponseClient(deployment).CreateAIAgent(
|
||||
name: ReviewerAgentName, instructions: ReviewerAgentInstructions);
|
||||
AIAgent frontDeskAgent = azureClient.GetOpenAIResponseClient(deployment).CreateAIAgent(
|
||||
name: FrontDeskAgentName, instructions: FrontDeskAgentInstructions);
|
||||
|
||||
// Build workflow with sequential agent execution
|
||||
var workflow = new WorkflowBuilder(frontDeskAgent)
|
||||
.AddEdge(frontDeskAgent, reviewerAgent)
|
||||
.Build();
|
||||
|
||||
// Create user message for travel recommendation
|
||||
ChatMessage userMessage = new ChatMessage(ChatRole.User, [
|
||||
new TextContent("I would like to go to Paris.")
|
||||
]);
|
||||
|
||||
// Execute workflow with streaming
|
||||
StreamingRun run = await InProcessExecution.StreamAsync(workflow, userMessage);
|
||||
|
||||
// Process workflow events and collect results
|
||||
await run.TrySendMessageAsync(new TurnToken(emitEvents: true));
|
||||
string id = "";
|
||||
string messageData = "";
|
||||
await foreach (WorkflowEvent evt in run.WatchStreamAsync().ConfigureAwait(false))
|
||||
{
|
||||
if (evt is AgentRunUpdateEvent executorComplete)
|
||||
{
|
||||
if (id == "")
|
||||
{
|
||||
id = executorComplete.ExecutorId;
|
||||
}
|
||||
if (id == executorComplete.ExecutorId)
|
||||
{
|
||||
messageData += executorComplete.Data.ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
id = executorComplete.ExecutorId;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Display final workflow results
|
||||
Console.WriteLine(messageData);
|
||||
+636
@@ -0,0 +1,636 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "187780ba",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# 🔄 Basic Agent Workflows with Azure OpenAI (Responses API) (.NET)\n",
|
||||
"\n",
|
||||
"## 📋 Workflow Orchestration Tutorial\n",
|
||||
"\n",
|
||||
"This notebook demonstrates how to build sophisticated **agent workflows** using the Microsoft Agent Framework for .NET and Azure OpenAI (Responses API). You'll learn to create multi-step business processes where AI agents collaborate to accomplish complex tasks through structured orchestration patterns.\n",
|
||||
"\n",
|
||||
"## 🎯 Learning Objectives\n",
|
||||
"\n",
|
||||
"### 🏗️ **Workflow Architecture Fundamentals**\n",
|
||||
"- **Workflow Builder**: Design and orchestrate complex multi-step AI processes\n",
|
||||
"- **Agent Coordination**: Coordinate multiple specialized agents within workflows\n",
|
||||
"- **Azure OpenAI (Responses API)**: Leverage the Azure OpenAI Responses API in workflows\n",
|
||||
"- **Visual Workflow Design**: Create and visualize workflow structures for better understanding\n",
|
||||
"\n",
|
||||
"### 🔄 **Process Orchestration Patterns**\n",
|
||||
"- **Sequential Processing**: Chain multiple agent tasks in logical order\n",
|
||||
"- **State Management**: Maintain context and data flow across workflow stages\n",
|
||||
"- **Error Handling**: Implement robust error recovery and workflow resilience\n",
|
||||
"- **Performance Optimization**: Design efficient workflows for enterprise-scale operations\n",
|
||||
"\n",
|
||||
"### 🏢 **Enterprise Workflow Applications**\n",
|
||||
"- **Business Process Automation**: Automate complex organizational workflows\n",
|
||||
"- **Content Production Pipeline**: Editorial workflows with review and approval stages\n",
|
||||
"- **Customer Service Automation**: Multi-step customer inquiry resolution\n",
|
||||
"- **Data Processing Workflows**: ETL workflows with AI-powered transformation\n",
|
||||
"\n",
|
||||
"## ⚙️ Prerequisites & Setup\n",
|
||||
"\n",
|
||||
"### 📦 **Required NuGet Packages**\n",
|
||||
"\n",
|
||||
"This workflow demonstration uses several key .NET packages:\n",
|
||||
"\n",
|
||||
"```xml\n",
|
||||
"<!-- Core AI Framework -->\n",
|
||||
"<PackageReference Include=\"Microsoft.Extensions.AI\" Version=\"9.9.0\" />\n",
|
||||
"\n",
|
||||
"<!-- Azure OpenAI (Responses API) -->\n",
|
||||
"<PackageReference Include=\"Azure.AI.OpenAI\" Version=\"2.1.0\" />\n",
|
||||
"<PackageReference Include=\"Azure.Identity\" Version=\"1.13.1\" />\n",
|
||||
"\n",
|
||||
"<!-- Agent Framework (Local Development) -->\n",
|
||||
"<!-- Microsoft.Agents.AI.dll - Core agent abstractions -->\n",
|
||||
"<!-- Microsoft.Agents.AI.OpenAI.dll - Azure OpenAI (Responses API) integration -->\n",
|
||||
"\n",
|
||||
"<!-- Configuration and Environment -->\n",
|
||||
"<PackageReference Include=\"DotNetEnv\" Version=\"3.1.1\" />\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"### 🔑 **Azure OpenAI Configuration**\n",
|
||||
"\n",
|
||||
"**Environment Setup (.env file):**\n",
|
||||
"```env\n",
|
||||
"AZURE_OPENAI_ENDPOINT=https://<your-resource>.openai.azure.com\n",
|
||||
"AZURE_OPENAI_DEPLOYMENT=gpt-4o-mini\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"**Azure OpenAI Access:**\n",
|
||||
"1. Create an Azure OpenAI resource in the Azure portal\n",
|
||||
"2. Deploy a model (for example, `gpt-4o-mini`) and note the deployment name\n",
|
||||
"3. Sign in with `az login` and configure environment variables as shown above\n",
|
||||
"\n",
|
||||
"### 🏗️ **Workflow Architecture Overview**\n",
|
||||
"\n",
|
||||
"```mermaid\n",
|
||||
"graph TD\n",
|
||||
" A[Workflow Builder] --> B[Agent Registry]\n",
|
||||
" B --> C[Workflow Execution Engine]\n",
|
||||
" C --> D[Agent 1: Content Generator]\n",
|
||||
" C --> E[Agent 2: Content Reviewer] \n",
|
||||
" D --> F[Workflow Results]\n",
|
||||
" E --> F\n",
|
||||
" G[Azure OpenAI (Responses API)] --> D\n",
|
||||
" G --> E\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"**Key Components:**\n",
|
||||
"- **WorkflowBuilder**: Main orchestration engine for designing workflows\n",
|
||||
"- **AIAgent**: Individual specialized agents with specific capabilities\n",
|
||||
"- **Azure OpenAI Client**: Azure OpenAI Responses API integration\n",
|
||||
"- **Execution Context**: Manages state and data flow between workflow stages\n",
|
||||
"\n",
|
||||
"## 🎨 **Enterprise Workflow Design Patterns**\n",
|
||||
"\n",
|
||||
"### 📝 **Content Production Workflow**\n",
|
||||
"```\n",
|
||||
"User Request → Content Generation → Quality Review → Final Output\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"### 🔍 **Document Processing Pipeline**\n",
|
||||
"```\n",
|
||||
"Document Input → Analysis → Extraction → Validation → Structured Output\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"### 💼 **Business Intelligence Workflow**\n",
|
||||
"```\n",
|
||||
"Data Collection → Processing → Analysis → Report Generation → Distribution\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"### 🤝 **Customer Service Automation**\n",
|
||||
"```\n",
|
||||
"Customer Inquiry → Classification → Processing → Response Generation → Follow-up\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"## 🏢 **Enterprise Benefits**\n",
|
||||
"\n",
|
||||
"### 🎯 **Reliability & Scalability**\n",
|
||||
"- **Deterministic Execution**: Consistent, repeatable workflow outcomes\n",
|
||||
"- **Error Recovery**: Graceful handling of failures at any workflow stage\n",
|
||||
"- **Performance Monitoring**: Track execution metrics and optimization opportunities\n",
|
||||
"- **Resource Management**: Efficient allocation and utilization of AI model resources\n",
|
||||
"\n",
|
||||
"### 🔒 **Security & Compliance**\n",
|
||||
"- **Secure Authentication**: Microsoft Entra ID authentication via `az login` (AzureCliCredential)\n",
|
||||
"- **Audit Trails**: Complete logging of workflow execution and decision points\n",
|
||||
"- **Access Control**: Granular permissions for workflow execution and monitoring\n",
|
||||
"- **Data Privacy**: Secure handling of sensitive information throughout workflows\n",
|
||||
"\n",
|
||||
"### 📊 **Observability & Management**\n",
|
||||
"- **Visual Workflow Design**: Clear representation of process flows and dependencies\n",
|
||||
"- **Execution Monitoring**: Real-time tracking of workflow progress and performance\n",
|
||||
"- **Error Reporting**: Detailed error analysis and debugging capabilities\n",
|
||||
"- **Performance Analytics**: Metrics for optimization and capacity planning\n",
|
||||
"\n",
|
||||
"Let's build your first enterprise-ready AI workflow! 🚀"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"id": "4152a00b",
|
||||
"metadata": {
|
||||
"language_info": {
|
||||
"name": "polyglot-notebook"
|
||||
},
|
||||
"polyglot_notebook": {
|
||||
"kernelName": "csharp"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/html": [
|
||||
"<div><div></div><div></div><div><strong>Installed Packages</strong><ul><li><span>Microsoft.Extensions.AI, 9.9.1</span></li></ul></div></div>"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"#r \"nuget: Microsoft.Extensions.AI, 9.9.1\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "b431c4dc",
|
||||
"metadata": {
|
||||
"language_info": {
|
||||
"name": "polyglot-notebook"
|
||||
},
|
||||
"polyglot_notebook": {
|
||||
"kernelName": "csharp"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/html": [
|
||||
"<div><div></div><div></div><div><strong>Installed Packages</strong><ul><li><span>System.ClientModel, 1.6.1</span></li></ul></div></div>"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"#r \"nuget: Azure.AI.OpenAI, 2.1.0\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"id": "ba48a4c7",
|
||||
"metadata": {
|
||||
"language_info": {
|
||||
"name": "polyglot-notebook"
|
||||
},
|
||||
"polyglot_notebook": {
|
||||
"kernelName": "csharp"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/html": [
|
||||
"<div><div></div><div></div><div><strong>Installed Packages</strong><ul><li><span>Azure.Identity, 1.15.0</span></li><li><span>OpenTelemetry.Api, 1.0.1</span></li><li><span>System.Linq.Async, 6.0.3</span></li></ul></div></div>"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"#r \"nuget: Azure.Identity, 1.15.0\"\n",
|
||||
"#r \"nuget: System.Linq.Async, 6.0.3\"\n",
|
||||
"#r \"nuget: OpenTelemetry.Api, 1.0.0\"\n",
|
||||
"#r \"nuget: OpenTelemetry.Api, 1.0.0\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"metadata": {
|
||||
"language_info": {
|
||||
"name": "polyglot-notebook"
|
||||
},
|
||||
"polyglot_notebook": {
|
||||
"kernelName": "csharp"
|
||||
}
|
||||
},
|
||||
"outputs": [],
|
||||
"source": []
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 5,
|
||||
"id": "ed55fec8",
|
||||
"metadata": {
|
||||
"language_info": {
|
||||
"name": "polyglot-notebook"
|
||||
},
|
||||
"polyglot_notebook": {
|
||||
"kernelName": "csharp"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/html": [
|
||||
"<div><div></div><div></div><div><strong>Installed Packages</strong><ul><li><span>Microsoft.Agents.AI.Workflows, 1.0.0-preview.251001.3</span></li></ul></div></div>"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"\n",
|
||||
"#r \"nuget: Microsoft.Agents.AI.Workflows, 1.0.0-preview.251001.3\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "afaaa7d4",
|
||||
"metadata": {
|
||||
"language_info": {
|
||||
"name": "polyglot-notebook"
|
||||
},
|
||||
"polyglot_notebook": {
|
||||
"kernelName": "csharp"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/html": [
|
||||
"<div><div></div><div></div><div><strong>Installed Packages</strong><ul><li><span>Microsoft.Agents.AI.OpenAI, 1.0.0-preview.251001.2</span></li></ul></div></div>"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"\n",
|
||||
"#r \"nuget: Microsoft.Agents.AI.OpenAI, 1.0.0-preview.251001.3\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 7,
|
||||
"id": "a7399950",
|
||||
"metadata": {
|
||||
"language_info": {
|
||||
"name": "polyglot-notebook"
|
||||
},
|
||||
"polyglot_notebook": {
|
||||
"kernelName": "csharp"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/html": [
|
||||
"<div><div></div><div></div><div><strong>Installed Packages</strong><ul><li><span>DotNetEnv, 3.1.1</span></li></ul></div></div>"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"#r \"nuget: DotNetEnv, 3.1.1\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 8,
|
||||
"id": "1df9ac4c",
|
||||
"metadata": {
|
||||
"language_info": {
|
||||
"name": "polyglot-notebook"
|
||||
},
|
||||
"polyglot_notebook": {
|
||||
"kernelName": "csharp"
|
||||
}
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"// #r \"nuget: Microsoft.Extensions.AI.OpenAI, 9.9.0-preview.1.25458.4\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "cf6ee6ed",
|
||||
"metadata": {
|
||||
"language_info": {
|
||||
"name": "polyglot-notebook"
|
||||
},
|
||||
"polyglot_notebook": {
|
||||
"kernelName": "csharp"
|
||||
}
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"using System;\n",
|
||||
"using System.ComponentModel;\n",
|
||||
"using Azure.AI.OpenAI;\n",
|
||||
"using Azure.Identity;\n",
|
||||
"using Microsoft.Extensions.AI;\n",
|
||||
"using Microsoft.Agents.AI;\n",
|
||||
"using Microsoft.Agents.AI.Workflows;"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 10,
|
||||
"id": "b4fc2d1b",
|
||||
"metadata": {
|
||||
"language_info": {
|
||||
"name": "polyglot-notebook"
|
||||
},
|
||||
"polyglot_notebook": {
|
||||
"kernelName": "csharp"
|
||||
}
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
" using DotNetEnv;"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 11,
|
||||
"id": "0e7f69f7",
|
||||
"metadata": {
|
||||
"language_info": {
|
||||
"name": "polyglot-notebook"
|
||||
},
|
||||
"polyglot_notebook": {
|
||||
"kernelName": "csharp"
|
||||
}
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"Env.Load(\"../../../.env\");"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "2b62a30a",
|
||||
"metadata": {
|
||||
"language_info": {
|
||||
"name": "polyglot-notebook"
|
||||
},
|
||||
"polyglot_notebook": {
|
||||
"kernelName": "csharp"
|
||||
}
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"// Azure OpenAI with the Responses API (stable v1 endpoint). Sign in with `az login`.\n",
|
||||
"var azureEndpoint = Environment.GetEnvironmentVariable(\"AZURE_OPENAI_ENDPOINT\") ?? throw new InvalidOperationException(\"AZURE_OPENAI_ENDPOINT is not set.\");\n",
|
||||
"var deployment = Environment.GetEnvironmentVariable(\"AZURE_OPENAI_DEPLOYMENT\") ?? \"gpt-4o-mini\";"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "bb2a8730",
|
||||
"metadata": {
|
||||
"language_info": {
|
||||
"name": "polyglot-notebook"
|
||||
},
|
||||
"polyglot_notebook": {
|
||||
"kernelName": "csharp"
|
||||
}
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"// The Azure OpenAI client is created directly from the endpoint and Azure CLI credential — no custom client options are required."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "c08bd38f",
|
||||
"metadata": {
|
||||
"language_info": {
|
||||
"name": "polyglot-notebook"
|
||||
},
|
||||
"polyglot_notebook": {
|
||||
"kernelName": "csharp"
|
||||
}
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"var azureClient = new AzureOpenAIClient(new Uri(azureEndpoint), new AzureCliCredential());"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 15,
|
||||
"id": "408e8b23",
|
||||
"metadata": {
|
||||
"language_info": {
|
||||
"name": "polyglot-notebook"
|
||||
},
|
||||
"polyglot_notebook": {
|
||||
"kernelName": "csharp"
|
||||
}
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"const string ReviewerAgentName = \"Concierge\";\n",
|
||||
"const string ReviewerAgentInstructions = @\"\n",
|
||||
" You are an are hotel concierge who has opinions about providing the most local and authentic experiences for travelers.\n",
|
||||
" The goal is to determine if the front desk travel agent has recommended the best non-touristy experience for a traveler.\n",
|
||||
" If so, state that it is approved.\n",
|
||||
" If not, provide insight on how to refine the recommendation without using a specific example. \";"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 16,
|
||||
"id": "0a1ccf3e",
|
||||
"metadata": {
|
||||
"language_info": {
|
||||
"name": "polyglot-notebook"
|
||||
},
|
||||
"polyglot_notebook": {
|
||||
"kernelName": "csharp"
|
||||
}
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"const string FrontDeskAgentName = \"FrontDesk\";\n",
|
||||
"const string FrontDeskAgentInstructions = @\"\"\"\n",
|
||||
" You are a Front Desk Travel Agent with ten years of experience and are known for brevity as you deal with many customers.\n",
|
||||
" The goal is to provide the best activities and locations for a traveler to visit.\n",
|
||||
" Only provide a single recommendation per response.\n",
|
||||
" You're laser focused on the goal at hand.\n",
|
||||
" Don't waste time with chit chat.\n",
|
||||
" Consider suggestions when refining an idea.\n",
|
||||
" \"\"\";"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "b9b975c6",
|
||||
"metadata": {
|
||||
"language_info": {
|
||||
"name": "polyglot-notebook"
|
||||
},
|
||||
"polyglot_notebook": {
|
||||
"kernelName": "csharp"
|
||||
}
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"AIAgent reviewerAgent = azureClient.GetOpenAIResponseClient(deployment).CreateAIAgent(\n",
|
||||
" name:ReviewerAgentName,instructions:ReviewerAgentInstructions);\n",
|
||||
"AIAgent frontDeskAgent = azureClient.GetOpenAIResponseClient(deployment).CreateAIAgent(\n",
|
||||
" name:FrontDeskAgentName,instructions:FrontDeskAgentInstructions);"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 18,
|
||||
"id": "5edccde0",
|
||||
"metadata": {
|
||||
"language_info": {
|
||||
"name": "polyglot-notebook"
|
||||
},
|
||||
"polyglot_notebook": {
|
||||
"kernelName": "csharp"
|
||||
}
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"var workflow = new WorkflowBuilder(frontDeskAgent)\n",
|
||||
" .AddEdge(frontDeskAgent, reviewerAgent)\n",
|
||||
" .Build();"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 19,
|
||||
"id": "1fb93407",
|
||||
"metadata": {
|
||||
"language_info": {
|
||||
"name": "polyglot-notebook"
|
||||
},
|
||||
"polyglot_notebook": {
|
||||
"kernelName": "csharp"
|
||||
}
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"ChatMessage userMessage = new ChatMessage(ChatRole.User, [\n",
|
||||
"\tnew TextContent(\"I would like to go to Paris.\") \n",
|
||||
"]);"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 20,
|
||||
"id": "ec9afabc",
|
||||
"metadata": {
|
||||
"language_info": {
|
||||
"name": "polyglot-notebook"
|
||||
},
|
||||
"polyglot_notebook": {
|
||||
"kernelName": "csharp"
|
||||
}
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"StreamingRun run = await InProcessExecution.StreamAsync(workflow, userMessage);"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 21,
|
||||
"id": "6bea90c0",
|
||||
"metadata": {
|
||||
"language_info": {
|
||||
"name": "polyglot-notebook"
|
||||
},
|
||||
"polyglot_notebook": {
|
||||
"kernelName": "csharp"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Visit the Louvre Museum. It's a must-see for art enthusiasts and history lovers.That recommendation is quite popular and likely to attract many tourists. To refine it for a more local and authentic experience, consider suggesting an alternative that focuses on smaller, lesser-known art venues or galleries. Look for places where local artists exhibit or community spaces that host cultural events. This approach allows travelers to connect with the local art scene more intimately, away from the typical tourist routes.\r\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"await run.TrySendMessageAsync(new TurnToken(emitEvents: true));\n",
|
||||
"string id=\"\";\n",
|
||||
"string messageData=\"\";\n",
|
||||
"await foreach (WorkflowEvent evt in run.WatchStreamAsync().ConfigureAwait(false))\n",
|
||||
"{\n",
|
||||
" if (evt is AgentRunUpdateEvent executorComplete)\n",
|
||||
" {\n",
|
||||
" if(id==\"\")\n",
|
||||
" {\n",
|
||||
" id=executorComplete.ExecutorId;\n",
|
||||
" }\n",
|
||||
" if(id==executorComplete.ExecutorId)\n",
|
||||
" {\n",
|
||||
" messageData+=executorComplete.Data.ToString();\n",
|
||||
" }\n",
|
||||
" else\n",
|
||||
" {\n",
|
||||
" id=executorComplete.ExecutorId;\n",
|
||||
" }\n",
|
||||
" // Console.WriteLine($\"{executorComplete.ExecutorId}: {executorComplete.Data}\");\n",
|
||||
" }\n",
|
||||
"}\n",
|
||||
"\n",
|
||||
"Console.WriteLine(messageData);"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": ".NET (C#)",
|
||||
"language": "C#",
|
||||
"name": ".net-csharp"
|
||||
},
|
||||
"language_info": {
|
||||
"name": "polyglot-notebook"
|
||||
},
|
||||
"polyglot_notebook": {
|
||||
"kernelInfo": {
|
||||
"defaultKernelName": "csharp",
|
||||
"items": [
|
||||
{
|
||||
"aliases": [],
|
||||
"name": "csharp"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
+165
@@ -0,0 +1,165 @@
|
||||
# 🔄 Basic Agent Workflows with Azure OpenAI (Responses API) (.NET)
|
||||
|
||||
## 📋 Workflow Orchestration Tutorial
|
||||
|
||||
This notebook demonstrates how to build sophisticated **agent workflows** using the Microsoft Agent Framework for .NET and Azure OpenAI (Responses API). You'll learn to create multi-step business processes where AI agents collaborate to accomplish complex tasks through structured orchestration patterns.
|
||||
|
||||
## 🎯 Learning Objectives
|
||||
|
||||
### 🏗️ **Workflow Architecture Fundamentals**
|
||||
- **Workflow Builder**: Design and orchestrate complex multi-step AI processes
|
||||
- **Agent Coordination**: Coordinate multiple specialized agents within workflows
|
||||
- **Azure OpenAI (Responses API)**: Leverage the Azure OpenAI Responses API in workflows
|
||||
- **Visual Workflow Design**: Create and visualize workflow structures for better understanding
|
||||
|
||||
### 🔄 **Process Orchestration Patterns**
|
||||
- **Sequential Processing**: Chain multiple agent tasks in logical order
|
||||
- **State Management**: Maintain context and data flow across workflow stages
|
||||
- **Error Handling**: Implement robust error recovery and workflow resilience
|
||||
- **Performance Optimization**: Design efficient workflows for enterprise-scale operations
|
||||
|
||||
### 🏢 **Enterprise Workflow Applications**
|
||||
- **Business Process Automation**: Automate complex organizational workflows
|
||||
- **Content Production Pipeline**: Editorial workflows with review and approval stages
|
||||
- **Customer Service Automation**: Multi-step customer inquiry resolution
|
||||
- **Data Processing Workflows**: ETL workflows with AI-powered transformation
|
||||
|
||||
## ⚙️ Prerequisites & Setup
|
||||
|
||||
### 📦 **Required NuGet Packages**
|
||||
|
||||
This workflow demonstration uses several key .NET packages:
|
||||
|
||||
```xml
|
||||
<!-- Core AI Framework -->
|
||||
<PackageReference Include="Microsoft.Extensions.AI" Version="9.9.0" />
|
||||
|
||||
<!-- Azure OpenAI (Responses API) -->
|
||||
<PackageReference Include="Azure.AI.OpenAI" Version="2.1.0" />
|
||||
<PackageReference Include="Azure.Identity" Version="1.13.1" />
|
||||
|
||||
<!-- Agent Framework (Local Development) -->
|
||||
<!-- Microsoft.Agents.AI.dll - Core agent abstractions -->
|
||||
<!-- Microsoft.Agents.AI.OpenAI.dll - Azure OpenAI (Responses API) integration -->
|
||||
|
||||
<!-- Configuration and Environment -->
|
||||
<PackageReference Include="DotNetEnv" Version="3.1.1" />
|
||||
```
|
||||
|
||||
### 🔑 **Azure OpenAI Configuration**
|
||||
|
||||
**Environment Setup (.env file):**
|
||||
```env
|
||||
AZURE_OPENAI_ENDPOINT=https://<your-resource>.openai.azure.com
|
||||
AZURE_OPENAI_DEPLOYMENT=gpt-4o-mini
|
||||
```
|
||||
|
||||
**Azure OpenAI Access:**
|
||||
1. Create an Azure OpenAI resource in the Azure portal
|
||||
2. Deploy a model (for example, `gpt-4o-mini`) and note the deployment name
|
||||
3. Sign in with `az login` and configure environment variables as shown above
|
||||
|
||||
### 🏗️ **Workflow Architecture Overview**
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
A[Workflow Builder] --> B[Agent Registry]
|
||||
B --> C[Workflow Execution Engine]
|
||||
C --> D[Agent 1: Content Generator]
|
||||
C --> E[Agent 2: Content Reviewer]
|
||||
D --> F[Workflow Results]
|
||||
E --> F
|
||||
G[Azure OpenAI (Responses API)] --> D
|
||||
G --> E
|
||||
```
|
||||
|
||||
**Key Components:**
|
||||
- **WorkflowBuilder**: Main orchestration engine for designing workflows
|
||||
- **AIAgent**: Individual specialized agents with specific capabilities
|
||||
- **Azure OpenAI Client**: Azure OpenAI Responses API integration
|
||||
- **Execution Context**: Manages state and data flow between workflow stages
|
||||
|
||||
## 🎨 **Enterprise Workflow Design Patterns**
|
||||
|
||||
### 📝 **Content Production Workflow**
|
||||
```
|
||||
User Request → Content Generation → Quality Review → Final Output
|
||||
```
|
||||
|
||||
### 🔍 **Document Processing Pipeline**
|
||||
```
|
||||
Document Input → Analysis → Extraction → Validation → Structured Output
|
||||
```
|
||||
|
||||
### 💼 **Business Intelligence Workflow**
|
||||
```
|
||||
Data Collection → Processing → Analysis → Report Generation → Distribution
|
||||
```
|
||||
|
||||
### 🤝 **Customer Service Automation**
|
||||
```
|
||||
Customer Inquiry → Classification → Processing → Response Generation → Follow-up
|
||||
```
|
||||
|
||||
## 🏢 **Enterprise Benefits**
|
||||
|
||||
### 🎯 **Reliability & Scalability**
|
||||
- **Deterministic Execution**: Consistent, repeatable workflow outcomes
|
||||
- **Error Recovery**: Graceful handling of failures at any workflow stage
|
||||
- **Performance Monitoring**: Track execution metrics and optimization opportunities
|
||||
- **Resource Management**: Efficient allocation and utilization of AI model resources
|
||||
|
||||
### 🔒 **Security & Compliance**
|
||||
- **Secure Authentication**: Microsoft Entra ID authentication via `az login` (AzureCliCredential)
|
||||
- **Audit Trails**: Complete logging of workflow execution and decision points
|
||||
- **Access Control**: Granular permissions for workflow execution and monitoring
|
||||
- **Data Privacy**: Secure handling of sensitive information throughout workflows
|
||||
|
||||
### 📊 **Observability & Management**
|
||||
- **Visual Workflow Design**: Clear representation of process flows and dependencies
|
||||
- **Execution Monitoring**: Real-time tracking of workflow progress and performance
|
||||
- **Error Reporting**: Detailed error analysis and debugging capabilities
|
||||
- **Performance Analytics**: Metrics for optimization and capacity planning
|
||||
|
||||
Let's build your first enterprise-ready AI workflow! 🚀
|
||||
|
||||
## 💻 Running the Code
|
||||
|
||||
The complete implementation is available in `01.dotnet-agent-framework-workflow-ghmodel-basic.cs`. This file demonstrates:
|
||||
|
||||
1. **Environment Configuration** - Loading Azure OpenAI configuration from `.env` file
|
||||
2. **Azure OpenAI Client Setup** - Configuring the client to use the Azure OpenAI Responses API
|
||||
3. **Agent Creation** - Defining specialized agents (Front Desk and Concierge)
|
||||
4. **Workflow Builder** - Creating a multi-agent workflow with sequential processing
|
||||
5. **Workflow Execution** - Running the workflow with streaming results
|
||||
|
||||
### 🚀 Running the Example
|
||||
|
||||
```bash
|
||||
# Make the script executable (Unix/Linux/macOS)
|
||||
chmod +x 01.dotnet-agent-framework-workflow-ghmodel-basic.cs
|
||||
|
||||
# Run the workflow
|
||||
./01.dotnet-agent-framework-workflow-ghmodel-basic.cs
|
||||
```
|
||||
|
||||
Or on Windows:
|
||||
```powershell
|
||||
dotnet run 01.dotnet-agent-framework-workflow-ghmodel-basic.cs
|
||||
```
|
||||
|
||||
### 📝 Expected Output
|
||||
|
||||
The workflow will:
|
||||
1. Accept your travel destination request ("I would like to go to Paris")
|
||||
2. The Front Desk agent provides an initial recommendation
|
||||
3. The Concierge agent reviews and refines the recommendation
|
||||
4. Final output displays the complete conversation stream
|
||||
|
||||
### 🔧 Customization
|
||||
|
||||
You can customize the workflow by:
|
||||
- Modifying agent instructions to change their behavior
|
||||
- Adding more agents to create complex multi-step workflows
|
||||
- Changing the user message to test different scenarios
|
||||
- Adjusting the workflow edges to create different execution patterns
|
||||
+117
@@ -0,0 +1,117 @@
|
||||
#!/usr/bin/dotnet run
|
||||
#:package Microsoft.Extensions.AI@9.9.1
|
||||
#:package Azure.AI.OpenAI@2.1.0
|
||||
#:package Azure.Identity@1.15.0
|
||||
#:package System.Linq.Async@6.0.3
|
||||
#:package OpenTelemetry.Api@1.0.0
|
||||
#:package Microsoft.Agents.AI.Workflows@1.0.0-preview.251001.3
|
||||
#:package Microsoft.Agents.AI.OpenAI@1.0.0-preview.251001.3
|
||||
#:package DotNetEnv@3.1.1
|
||||
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.IO;
|
||||
using Azure.AI.OpenAI;
|
||||
using Azure.Identity;
|
||||
using Microsoft.Extensions.AI;
|
||||
using Microsoft.Agents.AI;
|
||||
using Microsoft.Agents.AI.Workflows;
|
||||
using DotNetEnv;
|
||||
|
||||
// Load environment variables from .env file
|
||||
Env.Load("../../../.env");
|
||||
|
||||
// Azure OpenAI with the Responses API (stable v1 endpoint). Sign in with `az login`.
|
||||
var azureEndpoint = Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT")
|
||||
?? throw new InvalidOperationException("AZURE_OPENAI_ENDPOINT is not set.");
|
||||
var deployment = Environment.GetEnvironmentVariable("AZURE_OPENAI_DEPLOYMENT") ?? "gpt-4o-mini";
|
||||
|
||||
// Path to furniture image for analysis
|
||||
var imgPath = "../imgs/home.png";
|
||||
|
||||
var azureClient = new AzureOpenAIClient(new Uri(azureEndpoint), new AzureCliCredential());
|
||||
|
||||
// Define Sales Agent (Stage 1) - Furniture Analysis
|
||||
const string SalesAgentName = "Sales-Agent";
|
||||
const string SalesAgentInstructions = "You are my furniture sales consultant, you can find different furniture elements from the pictures and give me a purchase suggestion";
|
||||
|
||||
// Define Price Agent (Stage 2) - Pricing Specialist
|
||||
const string PriceAgentName = "Price-Agent";
|
||||
const string PriceAgentInstructions = @"You are a furniture pricing specialist and budget consultant. Your responsibilities include:
|
||||
1. Analyze furniture items and provide realistic price ranges based on quality, brand, and market standards
|
||||
2. Break down pricing by individual furniture pieces
|
||||
3. Provide budget-friendly alternatives and premium options
|
||||
4. Consider different price tiers (budget, mid-range, premium)
|
||||
5. Include estimated total costs for room setups
|
||||
6. Suggest where to find the best deals and shopping recommendations
|
||||
7. Factor in additional costs like delivery, assembly, and accessories
|
||||
8. Provide seasonal pricing insights and best times to buy
|
||||
Always format your response with clear price breakdowns and explanations for the pricing rationale.";
|
||||
|
||||
// Define Quote Agent (Stage 3) - Quote Document Generator
|
||||
const string QuoteAgentName = "Quote-Agent";
|
||||
const string QuoteAgentInstructions = @"You are an assistant that creates a quote for furniture purchase.
|
||||
1. Create a well-structured quote document that includes:
|
||||
2. A title page with the document title, date, and client name
|
||||
3. An introduction summarizing the purpose of the document
|
||||
4. A summary section with total estimated costs and recommendations
|
||||
5. Use clear headings, bullet points, and tables for easy readability
|
||||
6. All quotes are presented in markdown form";
|
||||
|
||||
// Helper function to load image as byte array
|
||||
async Task<byte[]> OpenImageBytesAsync(string path)
|
||||
{
|
||||
return await File.ReadAllBytesAsync(path);
|
||||
}
|
||||
|
||||
// Load furniture image for analysis
|
||||
var imageBytes = await OpenImageBytesAsync(imgPath);
|
||||
|
||||
// Create AI agents for the sequential workflow
|
||||
AIAgent salesagent = azureClient.GetOpenAIResponseClient(deployment).CreateAIAgent(
|
||||
name: SalesAgentName, instructions: SalesAgentInstructions);
|
||||
AIAgent priceagent = azureClient.GetOpenAIResponseClient(deployment).CreateAIAgent(
|
||||
name: PriceAgentName, instructions: PriceAgentInstructions);
|
||||
AIAgent quoteagent = azureClient.GetOpenAIResponseClient(deployment).CreateAIAgent(
|
||||
name: QuoteAgentName, instructions: QuoteAgentInstructions);
|
||||
|
||||
// Build sequential workflow: Sales → Price → Quote
|
||||
var workflow = new WorkflowBuilder(salesagent)
|
||||
.AddEdge(salesagent, priceagent)
|
||||
.AddEdge(priceagent, quoteagent)
|
||||
.Build();
|
||||
|
||||
// Create user message with image and instructions
|
||||
ChatMessage userMessage = new ChatMessage(ChatRole.User, [
|
||||
new DataContent(imageBytes, "image/png"),
|
||||
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")
|
||||
]);
|
||||
|
||||
// Execute workflow with streaming
|
||||
StreamingRun run = await InProcessExecution.StreamAsync(workflow, userMessage);
|
||||
|
||||
// Process workflow events and collect results
|
||||
await run.TrySendMessageAsync(new TurnToken(emitEvents: true));
|
||||
string id = "";
|
||||
string messageData = "";
|
||||
await foreach (WorkflowEvent evt in run.WatchStreamAsync().ConfigureAwait(false))
|
||||
{
|
||||
if (evt is AgentRunUpdateEvent executorComplete)
|
||||
{
|
||||
if (id == "")
|
||||
{
|
||||
id = executorComplete.ExecutorId;
|
||||
}
|
||||
if (id == executorComplete.ExecutorId)
|
||||
{
|
||||
messageData += executorComplete.Data.ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
id = executorComplete.ExecutorId;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Display final workflow results (complete quote document)
|
||||
Console.WriteLine(messageData);
|
||||
+1022
File diff suppressed because it is too large
Load Diff
+229
@@ -0,0 +1,229 @@
|
||||
# ⏩ Sequential Agent Workflows with Azure OpenAI (Responses API) (.NET)
|
||||
|
||||
## 📋 Advanced Sequential Processing Tutorial
|
||||
|
||||
This notebook demonstrates **sequential workflow patterns** using the Microsoft Agent Framework for .NET and Azure OpenAI (Responses API). You'll learn how to build sophisticated, step-by-step processing pipelines where agents execute in a specific order, with each stage building upon the results of the previous stage.
|
||||
|
||||
## 🎯 Learning Objectives
|
||||
|
||||
### 🔄 **Sequential Processing Architecture**
|
||||
- **Linear Workflow Design**: Create step-by-step processing pipelines with clear dependencies
|
||||
- **State Management**: Maintain context and data flow across sequential workflow stages
|
||||
- **Azure OpenAI (Responses API)**: Leverage Azure OpenAI models in multi-stage .NET workflows
|
||||
- **Enterprise Pipeline Patterns**: Build production-ready sequential processing systems
|
||||
|
||||
### 🏗️ **Advanced Sequential Patterns**
|
||||
- **Stage-Gate Processing**: Implement validation checkpoints between workflow stages
|
||||
- **Context Preservation**: Maintain state and accumulated knowledge across all stages
|
||||
- **Error Propagation**: Handle failures gracefully in sequential processing chains
|
||||
- **Performance Optimization**: Efficient sequential execution with minimal overhead
|
||||
|
||||
### 🏢 **Enterprise Sequential Applications**
|
||||
- **Document Processing Pipeline**: Multi-stage document analysis, transformation, and validation
|
||||
- **Quality Assurance Workflows**: Sequential review, validation, and approval processes
|
||||
- **Content Production Pipeline**: Research → Writing → Editing → Review → Publishing
|
||||
- **Business Process Automation**: Multi-step business workflows with clear stage dependencies
|
||||
|
||||
## ⚙️ Prerequisites & Setup
|
||||
|
||||
### 📦 **Required NuGet Packages**
|
||||
|
||||
Essential packages for .NET sequential workflows:
|
||||
|
||||
```xml
|
||||
<!-- Core AI Framework -->
|
||||
<PackageReference Include="Microsoft.Extensions.AI" Version="9.9.0" />
|
||||
|
||||
<!-- Azure OpenAI (Responses API) -->
|
||||
<PackageReference Include="Azure.AI.OpenAI" Version="2.1.0" />
|
||||
|
||||
<!-- Azure Identity and Async LINQ Support -->
|
||||
<PackageReference Include="Azure.Identity" Version="1.15.0" />
|
||||
<PackageReference Include="System.Linq.Async" Version="6.0.3" />
|
||||
|
||||
<!-- Local Agent Framework References -->
|
||||
<!-- Microsoft.Agents.AI.dll - Core agent abstractions -->
|
||||
<!-- Microsoft.Agents.AI.OpenAI.dll - Azure OpenAI (Responses API) integration -->
|
||||
```
|
||||
|
||||
### 🔑 **Azure OpenAI Configuration**
|
||||
|
||||
**Environment Setup (.env file):**
|
||||
```env
|
||||
AZURE_OPENAI_ENDPOINT=https://<your-resource>.openai.azure.com
|
||||
AZURE_OPENAI_DEPLOYMENT=gpt-4o-mini
|
||||
```
|
||||
|
||||
**Configuration Management:**
|
||||
```csharp
|
||||
// Load environment variables securely
|
||||
Env.Load("../../../.env");
|
||||
var azureEndpoint = Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT");
|
||||
var deployment = Environment.GetEnvironmentVariable("AZURE_OPENAI_DEPLOYMENT");
|
||||
```
|
||||
|
||||
### 🏗️ **Sequential Workflow Architecture**
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
A[Initial Input] --> B[Stage 1: Analysis Agent]
|
||||
B --> C[Checkpoint 1]
|
||||
C --> D[Stage 2: Processing Agent]
|
||||
D --> E[Checkpoint 2]
|
||||
E --> F[Stage 3: Validation Agent]
|
||||
F --> G[Final Output]
|
||||
|
||||
H[State Context] --> B
|
||||
H --> D
|
||||
H --> F
|
||||
|
||||
I[Azure OpenAI (Responses API)] --> B
|
||||
I --> D
|
||||
I --> F
|
||||
```
|
||||
|
||||
**Key Components:**
|
||||
- **Sequential Agents**: Specialized agents for each processing stage
|
||||
- **State Context**: Maintains accumulated data and decisions across stages
|
||||
- **Checkpoints**: Validation points between stages to ensure quality and consistency
|
||||
- **Azure OpenAI Client**: Consistent AI model access across all workflow stages
|
||||
|
||||
## 🎨 **Sequential Workflow Design Patterns**
|
||||
|
||||
### 📝 **Document Processing Pipeline**
|
||||
```
|
||||
Raw Document → Content Extraction → Analysis → Validation → Structured Output
|
||||
```
|
||||
|
||||
### 🎯 **Content Creation Workflow**
|
||||
```
|
||||
Brief/Requirements → Research → Content Creation → Review → Final Polish
|
||||
```
|
||||
|
||||
### 🔍 **Quality Assurance Pipeline**
|
||||
```
|
||||
Initial Review → Technical Validation → Compliance Check → Final Approval
|
||||
```
|
||||
|
||||
### 💼 **Business Intelligence Workflow**
|
||||
```
|
||||
Data Collection → Processing → Analysis → Report Generation → Distribution
|
||||
```
|
||||
|
||||
## 🏢 **Enterprise Sequential Benefits**
|
||||
|
||||
### 🎯 **Reliability & Quality**
|
||||
- **Deterministic Processing**: Consistent, repeatable outcomes through structured stages
|
||||
- **Quality Gates**: Validation checkpoints ensure quality at each stage
|
||||
- **Error Isolation**: Problems in one stage don't propagate to subsequent stages
|
||||
- **Audit Trails**: Complete tracking of decisions and transformations at each stage
|
||||
|
||||
### 📈 **Scalability & Performance**
|
||||
- **Modular Design**: Each stage can be optimized independently
|
||||
- **Resource Management**: Efficient allocation of AI model resources across stages
|
||||
- **State Optimization**: Minimal state transfer between stages for optimal performance
|
||||
- **Parallel Stage Groups**: Multiple sequential workflows can run in parallel
|
||||
|
||||
### 🔒 **Security & Compliance**
|
||||
- **Stage-Level Security**: Different security policies for different processing stages
|
||||
- **Data Validation**: Ensure data integrity and compliance at each checkpoint
|
||||
- **Access Control**: Granular permissions for different workflow stages
|
||||
- **Regulatory Compliance**: Meet regulatory requirements through structured processing
|
||||
|
||||
### 📊 **Monitoring & Analytics**
|
||||
- **Stage-Level Metrics**: Performance monitoring for each workflow stage
|
||||
- **Bottleneck Identification**: Identify and optimize slow stages
|
||||
- **Quality Metrics**: Track quality and success rates at each stage
|
||||
- **Process Optimization**: Continuous improvement based on stage-level analytics
|
||||
|
||||
Let's build robust sequential AI processing pipelines! 🚀
|
||||
|
||||
## 💻 Running the Code
|
||||
|
||||
The complete implementation is available in `02.dotnet-agent-framework-workflow-ghmodel-sequential.cs`. This file demonstrates a **three-stage furniture analysis workflow**:
|
||||
|
||||
1. **Stage 1 - Sales Agent**: Analyzes furniture images and provides purchase suggestions
|
||||
2. **Stage 2 - Price Agent**: Provides detailed pricing breakdowns and budget options
|
||||
3. **Stage 3 - Quote Agent**: Generates a professional quote document in Markdown format
|
||||
|
||||
### 🏗️ **Workflow Architecture**
|
||||
|
||||
```
|
||||
Image Input → Sales Analysis → Price Estimation → Quote Generation → Final Output
|
||||
```
|
||||
|
||||
Each agent:
|
||||
- Receives the output from the previous stage as context
|
||||
- Builds upon previous analysis with specialized expertise
|
||||
- Maintains workflow continuity through state management
|
||||
|
||||
### 🚀 Running the Example
|
||||
|
||||
**Prerequisites:**
|
||||
- Place a furniture image at `../imgs/home.png` (or update the `imgPath` variable)
|
||||
- Configure your `.env` file with your Azure OpenAI endpoint and deployment, then sign in with `az login`
|
||||
|
||||
```bash
|
||||
# Make the script executable (Unix/Linux/macOS)
|
||||
chmod +x 02.dotnet-agent-framework-workflow-ghmodel-sequential.cs
|
||||
|
||||
# Run the sequential workflow
|
||||
./02.dotnet-agent-framework-workflow-ghmodel-sequential.cs
|
||||
```
|
||||
|
||||
Or on Windows:
|
||||
```powershell
|
||||
dotnet run 02.dotnet-agent-framework-workflow-ghmodel-sequential.cs
|
||||
```
|
||||
|
||||
### 📝 Expected Output
|
||||
|
||||
The workflow will:
|
||||
1. **Sales Agent**: Identify furniture items from the image and provide recommendations
|
||||
2. **Price Agent**: Add detailed pricing analysis with budget tiers and shopping recommendations
|
||||
3. **Quote Agent**: Generate a formatted quote document with all information synthesized
|
||||
|
||||
The final output will be a comprehensive, professional furniture quote based on image analysis.
|
||||
|
||||
### 🔧 Customization Options
|
||||
|
||||
**Modify Agent Behavior:**
|
||||
```csharp
|
||||
// Adjust agent instructions to change their focus
|
||||
const string SalesAgentInstructions = "Your custom instructions...";
|
||||
```
|
||||
|
||||
**Change Sequential Flow:**
|
||||
```csharp
|
||||
// Add or reorder workflow stages
|
||||
var workflow = new WorkflowBuilder(salesagent)
|
||||
.AddEdge(salesagent, priceagent)
|
||||
.AddEdge(priceagent, quoteagent)
|
||||
.AddEdge(quoteagent, newAgent) // Add another stage
|
||||
.Build();
|
||||
```
|
||||
|
||||
**Use Different Input:**
|
||||
```csharp
|
||||
// Process text instead of images
|
||||
ChatMessage userMessage = new ChatMessage(ChatRole.User, [
|
||||
new TextContent("Analyze pricing for a modern living room set")
|
||||
]);
|
||||
```
|
||||
|
||||
### 🎯 Real-World Applications
|
||||
|
||||
This sequential pattern is ideal for:
|
||||
- **E-commerce**: Product analysis → Pricing → Quote generation
|
||||
- **Real Estate**: Property analysis → Valuation → Listing creation
|
||||
- **Insurance**: Claim analysis → Assessment → Quote generation
|
||||
- **Content Creation**: Research → Writing → Editing → Publishing
|
||||
|
||||
### 🔍 Understanding State Flow
|
||||
|
||||
Each agent in the sequence receives:
|
||||
- **Original Input**: The initial user message (image + text)
|
||||
- **Previous Agent Outputs**: All previous agent responses in the conversation history
|
||||
- **Accumulated Context**: Complete state maintained throughout the workflow
|
||||
|
||||
This enables sophisticated multi-stage processing where each agent builds upon comprehensive context from all previous stages.
|
||||
+119
@@ -0,0 +1,119 @@
|
||||
#!/usr/bin/dotnet run
|
||||
#:package Microsoft.Extensions.AI@9.9.1
|
||||
#:package Azure.AI.OpenAI@2.1.0
|
||||
#:package Azure.Identity@1.15.0
|
||||
#:package System.Linq.Async@6.0.3
|
||||
#:package OpenTelemetry.Api@1.0.0
|
||||
#:package Microsoft.Agents.AI.Workflows@1.0.0-preview.251001.3
|
||||
#:package Microsoft.Agents.AI.OpenAI@1.0.0-preview.251001.3
|
||||
#:package DotNetEnv@3.1.1
|
||||
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using Azure.AI.OpenAI;
|
||||
using Azure.Identity;
|
||||
using Microsoft.Extensions.AI;
|
||||
using Microsoft.Agents.AI;
|
||||
using Microsoft.Agents.AI.Workflows;
|
||||
using Microsoft.Agents.AI.Workflows.Reflection;
|
||||
using DotNetEnv;
|
||||
|
||||
// Load environment variables from .env file
|
||||
Env.Load("../../../.env");
|
||||
|
||||
// Azure OpenAI with the Responses API (stable v1 endpoint). Sign in with `az login`.
|
||||
var azureEndpoint = Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT")
|
||||
?? throw new InvalidOperationException("AZURE_OPENAI_ENDPOINT is not set.");
|
||||
var deployment = Environment.GetEnvironmentVariable("AZURE_OPENAI_DEPLOYMENT") ?? "gpt-4o-mini";
|
||||
|
||||
var azureClient = new AzureOpenAIClient(new Uri(azureEndpoint), new AzureCliCredential());
|
||||
|
||||
// Define Researcher Agent for concurrent execution
|
||||
const string ResearcherAgentName = "Researcher-Agent";
|
||||
const string ResearcherAgentInstructions = "You are my travel researcher, working with me to analyze the destination, list relevant attractions, and make detailed plans for each attraction.";
|
||||
|
||||
// Define Planner Agent for concurrent execution
|
||||
const string PlanAgentName = "Plan-Agent";
|
||||
const string PlanAgentInstructions = "You are my travel planner, working with me to create a detailed travel plan based on the researcher's findings.";
|
||||
|
||||
// Create AI agents for concurrent workflow
|
||||
AIAgent researcherAgent = azureClient.GetOpenAIResponseClient(deployment).CreateAIAgent(
|
||||
name: ResearcherAgentName, instructions: ResearcherAgentInstructions);
|
||||
AIAgent plannerAgent = azureClient.GetOpenAIResponseClient(deployment).CreateAIAgent(
|
||||
name: PlanAgentName, instructions: PlanAgentInstructions);
|
||||
|
||||
// Create custom executor instances
|
||||
var startExecutor = new ConcurrentStartExecutor();
|
||||
var aggregationExecutor = new ConcurrentAggregationExecutor();
|
||||
|
||||
// Build concurrent workflow with Fan-Out/Fan-In pattern
|
||||
var workflow = new WorkflowBuilder(startExecutor)
|
||||
.AddFanOutEdge(startExecutor, targets: [researcherAgent, plannerAgent])
|
||||
.AddFanInEdge(aggregationExecutor, sources: [researcherAgent, plannerAgent])
|
||||
.WithOutputFrom(aggregationExecutor)
|
||||
.Build();
|
||||
|
||||
// Execute concurrent workflow with streaming
|
||||
StreamingRun run = await InProcessExecution.StreamAsync(workflow, "Plan a trip to Seattle in December");
|
||||
|
||||
// Watch for workflow events and display final output
|
||||
await foreach (WorkflowEvent evt in run.WatchStreamAsync().ConfigureAwait(false))
|
||||
{
|
||||
if (evt is WorkflowOutputEvent output)
|
||||
{
|
||||
Console.WriteLine($"Workflow completed with results:\n{output.Data}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Custom executor that starts concurrent processing by broadcasting to all agents.
|
||||
/// This implements the "Fan-Out" pattern where one input triggers multiple parallel operations.
|
||||
/// </summary>
|
||||
public class ConcurrentStartExecutor() :
|
||||
ReflectingExecutor<ConcurrentStartExecutor>("ConcurrentStartExecutor"),
|
||||
IMessageHandler<string>
|
||||
{
|
||||
/// <summary>
|
||||
/// Starts the concurrent processing by sending messages to the agents.
|
||||
/// </summary>
|
||||
/// <param name="message">The user message to process</param>
|
||||
/// <param name="context">Workflow context for accessing workflow services and adding events</param>
|
||||
/// <returns>A task representing the asynchronous operation</returns>
|
||||
public async ValueTask HandleAsync(string message, IWorkflowContext context)
|
||||
{
|
||||
// Broadcast the message to all connected agents. Receiving agents will queue
|
||||
// the message but will not start processing until they receive a turn token.
|
||||
await context.SendMessageAsync(new ChatMessage(ChatRole.User, message));
|
||||
// Broadcast the turn token to kick off the agents.
|
||||
await context.SendMessageAsync(new TurnToken(emitEvents: true));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Custom executor that aggregates results from concurrent agents.
|
||||
/// This implements the "Fan-In" pattern where multiple parallel results are merged into one output.
|
||||
/// </summary>
|
||||
public class ConcurrentAggregationExecutor() :
|
||||
ReflectingExecutor<ConcurrentAggregationExecutor>("ConcurrentAggregationExecutor"),
|
||||
IMessageHandler<ChatMessage>
|
||||
{
|
||||
private readonly List<ChatMessage> _messages = [];
|
||||
|
||||
/// <summary>
|
||||
/// Handles incoming messages from the agents and aggregates their responses.
|
||||
/// </summary>
|
||||
/// <param name="message">The message from the agent</param>
|
||||
/// <param name="context">Workflow context for accessing workflow services and adding events</param>
|
||||
/// <returns>A task representing the asynchronous operation</returns>
|
||||
public async ValueTask HandleAsync(ChatMessage message, IWorkflowContext context)
|
||||
{
|
||||
this._messages.Add(message);
|
||||
|
||||
// Wait for both agents to complete before aggregating
|
||||
if (this._messages.Count == 2)
|
||||
{
|
||||
var formattedMessages = string.Join(Environment.NewLine, this._messages.Select(m => $"{m.AuthorName}: {m.Text}"));
|
||||
await context.YieldOutputAsync(formattedMessages);
|
||||
}
|
||||
}
|
||||
}
|
||||
+854
@@ -0,0 +1,854 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "6bb5f2b3",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# ⚡ Concurrent Agent Workflows with Azure OpenAI (Responses API) (.NET)\n",
|
||||
"\n",
|
||||
"## 📋 High-Performance Parallel Processing Tutorial\n",
|
||||
"\n",
|
||||
"This notebook demonstrates **concurrent workflow patterns** using the Microsoft Agent Framework for .NET and Azure OpenAI (Responses API). You'll learn how to build high-performance, parallel processing workflows that maximize throughput by executing multiple AI agents simultaneously while maintaining coordination and data consistency.\n",
|
||||
"\n",
|
||||
"> **Migration note:** This sample previously used GitHub Models. GitHub Models is deprecated (retiring July 2026) and does not support the Responses API, so it now uses **Azure OpenAI** with the **Responses API** through `AzureOpenAIClient.GetOpenAIResponseClient(...)`.\n",
|
||||
"\n",
|
||||
"## 🎯 Learning Objectives\n",
|
||||
"\n",
|
||||
"### 🚀 **Concurrent Processing Fundamentals**\n",
|
||||
"- **Parallel Agent Execution**: Run multiple AI agents simultaneously for maximum performance\n",
|
||||
"- **Async/Await Patterns**: Leverage .NET's async programming model for efficient concurrency\n",
|
||||
"- **Azure OpenAI Responses API Integration**: Coordinate multiple concurrent calls to the Azure OpenAI Responses API\n",
|
||||
"- **Resource Management**: Efficiently manage AI model resources across concurrent operations\n",
|
||||
"\n",
|
||||
"### 🏗️ **Advanced Concurrency Architecture**\n",
|
||||
"- **Task-Based Parallelism**: Use .NET Task Parallel Library for optimal concurrent execution\n",
|
||||
"- **Synchronization Patterns**: Coordinate concurrent agents while avoiding race conditions\n",
|
||||
"- **Load Balancing**: Distribute work efficiently across available concurrent processing capacity\n",
|
||||
"- **Fault Tolerance**: Handle individual agent failures without stopping the entire workflow\n",
|
||||
"\n",
|
||||
"### 🏢 **Enterprise Concurrent Applications**\n",
|
||||
"- **High-Volume Document Processing**: Process multiple documents simultaneously\n",
|
||||
"- **Real-Time Content Analysis**: Concurrent analysis of incoming data streams\n",
|
||||
"- **Batch Processing Optimization**: Maximize throughput for large-scale data processing operations\n",
|
||||
"- **Multi-Modal Analysis**: Parallel processing of different content types and formats\n",
|
||||
"\n",
|
||||
"## ⚙️ Prerequisites & Setup\n",
|
||||
"\n",
|
||||
"### 📦 **Required NuGet Packages**\n",
|
||||
"\n",
|
||||
"Essential packages for high-performance concurrent workflows:\n",
|
||||
"\n",
|
||||
"```xml\n",
|
||||
"<!-- Core AI Framework with Async Support -->\n",
|
||||
"<PackageReference Include=\"Microsoft.Extensions.AI\" Version=\"9.9.1\" />\n",
|
||||
"\n",
|
||||
"<!-- Azure OpenAI client (Responses API) -->\n",
|
||||
"<PackageReference Include=\"Azure.AI.OpenAI\" Version=\"2.1.0\" />\n",
|
||||
"\n",
|
||||
"<!-- Azure Identity and Async LINQ for Advanced Operations -->\n",
|
||||
"<PackageReference Include=\"Azure.Identity\" Version=\"1.15.0\" />\n",
|
||||
"<PackageReference Include=\"System.Linq.Async\" Version=\"6.0.3\" />\n",
|
||||
"\n",
|
||||
"<!-- Agent Framework -->\n",
|
||||
"<!-- Microsoft.Agents.AI - Core agent abstractions with async support -->\n",
|
||||
"<!-- Microsoft.Agents.AI.OpenAI - Azure OpenAI Responses integration with concurrency -->\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"### 🔑 **Azure OpenAI Configuration**\n",
|
||||
"\n",
|
||||
"Sign in with the Azure CLI (`az login`) so `AzureCliCredential` can authenticate, then set your Azure OpenAI resource details. The Responses API uses the stable `/openai/v1/` endpoint — no `api-version` management required.\n",
|
||||
"\n",
|
||||
"**Environment Setup (.env file):**\n",
|
||||
"```env\n",
|
||||
"AZURE_OPENAI_ENDPOINT=https://<your-resource>.openai.azure.com\n",
|
||||
"AZURE_OPENAI_DEPLOYMENT=gpt-4o-mini\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"**Concurrent Processing Considerations:**\n",
|
||||
"```csharp\n",
|
||||
"// Configure connection pooling / timeouts for concurrent requests\n",
|
||||
"var clientOptions = new AzureOpenAIClientOptions()\n",
|
||||
"{\n",
|
||||
" NetworkTimeout = TimeSpan.FromMinutes(5)\n",
|
||||
"};\n",
|
||||
"var azureClient = new AzureOpenAIClient(new Uri(azureEndpoint), new AzureCliCredential(), clientOptions);\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"### 🏗️ **Concurrent Workflow Architecture**\n",
|
||||
"\n",
|
||||
"```mermaid\n",
|
||||
"graph TD\n",
|
||||
" A[Workflow Input] --> B[Task Distribution]\n",
|
||||
" B --> C[Concurrent Agent Pool]\n",
|
||||
" C --> D[Agent Task 1]\n",
|
||||
" C --> E[Agent Task 2]\n",
|
||||
" C --> F[Agent Task 3]\n",
|
||||
" C --> G[Agent Task N]\n",
|
||||
" \n",
|
||||
" D --> H[Result Aggregation]\n",
|
||||
" E --> H\n",
|
||||
" F --> H\n",
|
||||
" G --> H\n",
|
||||
" \n",
|
||||
" H --> I[Synchronized Output]\n",
|
||||
" \n",
|
||||
" J[Azure OpenAI Responses API] --> D\n",
|
||||
" J --> E\n",
|
||||
" J --> F\n",
|
||||
" J --> G\n",
|
||||
" \n",
|
||||
" K[\".NET Task Scheduler\"] --> C\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"**Key Components:**\n",
|
||||
"- **Task Parallel Library**: .NET's built-in support for concurrent operations\n",
|
||||
"- **Agent Pool**: Multiple agent instances for parallel processing\n",
|
||||
"- **Result Aggregation**: Coordination and merging of concurrent agent results\n",
|
||||
"- **Synchronization Points**: Ensure data consistency across concurrent operations\n",
|
||||
"\n",
|
||||
"## 🎨 **Concurrent Workflow Design Patterns**\n",
|
||||
"\n",
|
||||
"### 🔍 **Parallel Research & Analysis**\n",
|
||||
"```\n",
|
||||
"Research Topic → Concurrent Research Agents → Result Synthesis → Final Report\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"### 📊 **Multi-Source Data Processing**\n",
|
||||
"```\n",
|
||||
"Data Sources → Parallel Processing Agents → Data Integration → Unified Output\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"### 🎭 **Content Generation Pipeline**\n",
|
||||
"```\n",
|
||||
"Content Requirements → Concurrent Content Generators → Quality Review → Final Content\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"### 🔄 **Fan-Out/Fan-In Processing**\n",
|
||||
"```\n",
|
||||
"Single Input → Multiple Concurrent Processors → Result Aggregation → Single Output\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"## 🏢 **Enterprise Performance Benefits**\n",
|
||||
"\n",
|
||||
"### ⚡ **Throughput & Scalability**\n",
|
||||
"- **Linear Performance Scaling**: Add more concurrent agents to increase throughput\n",
|
||||
"- **Resource Utilization**: Maximum efficiency of available AI model capacity\n",
|
||||
"- **Reduced Processing Time**: Significant time reduction through parallel execution\n",
|
||||
"- **Elastic Scaling**: Dynamically adjust concurrent agent count based on workload\n",
|
||||
"\n",
|
||||
"### 🛡️ **Reliability & Resilience**\n",
|
||||
"- **Fault Isolation**: Individual agent failures don't affect other concurrent operations\n",
|
||||
"- **Graceful Degradation**: System continues operating with reduced agent capacity\n",
|
||||
"- **Error Recovery**: Automatic retry mechanisms for failed concurrent operations\n",
|
||||
"- **Load Distribution**: Even distribution of work across available agents\n",
|
||||
"\n",
|
||||
"### 📊 **Performance Monitoring**\n",
|
||||
"- **Concurrent Execution Metrics**: Track performance of all parallel operations\n",
|
||||
"- **Resource Usage Analytics**: Monitor CPU, memory, and network utilization\n",
|
||||
"- **Throughput Analysis**: Measure efficiency gains from concurrent processing\n",
|
||||
"- **Bottleneck Detection**: Identify and resolve performance constraints\n",
|
||||
"\n",
|
||||
"### 🔧 **Development & Operations**\n",
|
||||
"- **Async Programming Model**: Leverage .NET's mature async/await patterns\n",
|
||||
"- **Task Coordination**: Built-in task management and coordination capabilities\n",
|
||||
"- **Exception Handling**: Comprehensive error handling for concurrent operations\n",
|
||||
"- **Debugging Support**: Visual Studio debugging tools for concurrent workflows\n",
|
||||
"\n",
|
||||
"Let's build high-performance concurrent AI workflows with .NET! 🚀\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"id": "4675c79f",
|
||||
"metadata": {
|
||||
"language_info": {
|
||||
"name": "polyglot-notebook"
|
||||
},
|
||||
"polyglot_notebook": {
|
||||
"kernelName": "csharp"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/html": [
|
||||
"<div><div></div><div></div><div><strong>Installed Packages</strong><ul><li><span>Microsoft.Extensions.AI, 9.9.1</span></li></ul></div></div>"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"#r \"nuget: Microsoft.Extensions.AI, 9.9.1\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "cb327e0b",
|
||||
"metadata": {
|
||||
"language_info": {
|
||||
"name": "polyglot-notebook"
|
||||
},
|
||||
"polyglot_notebook": {
|
||||
"kernelName": "csharp"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/html": [
|
||||
"<div><div></div><div></div><div><strong>Installed Packages</strong><ul><li><span>System.ClientModel, 1.6.1</span></li></ul></div></div>"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"#r \"nuget: Azure.AI.OpenAI, 2.1.0\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"id": "394ce307",
|
||||
"metadata": {
|
||||
"language_info": {
|
||||
"name": "polyglot-notebook"
|
||||
},
|
||||
"polyglot_notebook": {
|
||||
"kernelName": "csharp"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/html": [
|
||||
"<div><div></div><div></div><div><strong>Installed Packages</strong><ul><li><span>Azure.Identity, 1.15.0</span></li><li><span>OpenTelemetry.Api, 1.0.1</span></li><li><span>System.Linq.Async, 6.0.3</span></li></ul></div></div>"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"#r \"nuget: Azure.Identity, 1.15.0\"\n",
|
||||
"#r \"nuget: System.Linq.Async, 6.0.3\"\n",
|
||||
"#r \"nuget: OpenTelemetry.Api, 1.0.0\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 4,
|
||||
"id": "0a7c9e26",
|
||||
"metadata": {
|
||||
"language_info": {
|
||||
"name": "polyglot-notebook"
|
||||
},
|
||||
"polyglot_notebook": {
|
||||
"kernelName": "csharp"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/html": [
|
||||
"<div><div></div><div></div><div><strong>Installed Packages</strong><ul><li><span>Microsoft.Agents.AI.Workflows, 1.0.0-preview.251001.3</span></li></ul></div></div>"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"#r \"nuget: Microsoft.Agents.AI.Workflows, 1.0.0-preview.251001.3\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "a316aac6",
|
||||
"metadata": {
|
||||
"language_info": {
|
||||
"name": "polyglot-notebook"
|
||||
},
|
||||
"polyglot_notebook": {
|
||||
"kernelName": "csharp"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/html": [
|
||||
"<div><div></div><div></div><div><strong>Installed Packages</strong><ul><li><span>Microsoft.Agents.AI.OpenAI, 1.0.0-preview.251001.2</span></li></ul></div></div>"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"#r \"nuget: Microsoft.Agents.AI.OpenAI, 1.0.0-preview.251001.3\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 6,
|
||||
"id": "25929636",
|
||||
"metadata": {
|
||||
"language_info": {
|
||||
"name": "polyglot-notebook"
|
||||
},
|
||||
"polyglot_notebook": {
|
||||
"kernelName": "csharp"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"data": {
|
||||
"text/html": [
|
||||
"<div><div></div><div></div><div><strong>Installed Packages</strong><ul><li><span>DotNetEnv, 3.1.1</span></li></ul></div></div>"
|
||||
]
|
||||
},
|
||||
"metadata": {},
|
||||
"output_type": "display_data"
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"#r \"nuget: DotNetEnv, 3.1.1\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 7,
|
||||
"id": "a2e8c6e1",
|
||||
"metadata": {
|
||||
"language_info": {
|
||||
"name": "polyglot-notebook"
|
||||
},
|
||||
"polyglot_notebook": {
|
||||
"kernelName": "csharp"
|
||||
}
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"// #r \"nuget: Microsoft.Extensions.AI.OpenAI, 9.9.0-preview.1.25458.4\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "423d09a3",
|
||||
"metadata": {
|
||||
"language_info": {
|
||||
"name": "polyglot-notebook"
|
||||
},
|
||||
"polyglot_notebook": {
|
||||
"kernelName": "csharp"
|
||||
}
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"using System;\n",
|
||||
"using System.ComponentModel;\n",
|
||||
"using Azure.AI.OpenAI;\n",
|
||||
"using Azure.Identity;\n",
|
||||
"using Microsoft.Extensions.AI;\n",
|
||||
"using Microsoft.Agents.AI;\n",
|
||||
"using Microsoft.Agents.AI.Workflows;\n",
|
||||
"using Microsoft.Agents.AI.Workflows.Reflection;"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 9,
|
||||
"id": "2fb52dd9",
|
||||
"metadata": {
|
||||
"language_info": {
|
||||
"name": "polyglot-notebook"
|
||||
},
|
||||
"polyglot_notebook": {
|
||||
"kernelName": "csharp"
|
||||
}
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
" using DotNetEnv;"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 10,
|
||||
"id": "d8c58043",
|
||||
"metadata": {
|
||||
"language_info": {
|
||||
"name": "polyglot-notebook"
|
||||
},
|
||||
"polyglot_notebook": {
|
||||
"kernelName": "csharp"
|
||||
}
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"Env.Load(\"../../../.env\");"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "62168984",
|
||||
"metadata": {
|
||||
"language_info": {
|
||||
"name": "polyglot-notebook"
|
||||
},
|
||||
"polyglot_notebook": {
|
||||
"kernelName": "csharp"
|
||||
}
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"// Azure OpenAI with the Responses API (stable v1 endpoint). Sign in with `az login`.\n",
|
||||
"var azureEndpoint = Environment.GetEnvironmentVariable(\"AZURE_OPENAI_ENDPOINT\") ?? throw new InvalidOperationException(\"AZURE_OPENAI_ENDPOINT is not set.\");\n",
|
||||
"var deployment = Environment.GetEnvironmentVariable(\"AZURE_OPENAI_DEPLOYMENT\") ?? \"gpt-4o-mini\";"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "2884c117",
|
||||
"metadata": {
|
||||
"language_info": {
|
||||
"name": "polyglot-notebook"
|
||||
},
|
||||
"polyglot_notebook": {
|
||||
"kernelName": "csharp"
|
||||
}
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"var azureClient = new AzureOpenAIClient(new Uri(azureEndpoint), new AzureCliCredential());"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 14,
|
||||
"id": "1136229d",
|
||||
"metadata": {
|
||||
"language_info": {
|
||||
"name": "polyglot-notebook"
|
||||
},
|
||||
"polyglot_notebook": {
|
||||
"kernelName": "csharp"
|
||||
}
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"const string ResearcherAgentName = \"Researcher-Agent\";\n",
|
||||
"const string ResearcherAgentInstructions = \"You are my travel researcher, working with me to analyze the destination, list relevant attractions, and make detailed plans for each attraction.\";"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 15,
|
||||
"id": "66463aa4",
|
||||
"metadata": {
|
||||
"language_info": {
|
||||
"name": "polyglot-notebook"
|
||||
},
|
||||
"polyglot_notebook": {
|
||||
"kernelName": "csharp"
|
||||
}
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"const string PlanAgentName = \"Plan-Agent\";\n",
|
||||
"const string PlanAgentInstructions = \"You are my travel planner, working with me to create a detailed travel plan based on the researcher's findings.\";"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "3a6f8f43",
|
||||
"metadata": {
|
||||
"language_info": {
|
||||
"name": "polyglot-notebook"
|
||||
},
|
||||
"polyglot_notebook": {
|
||||
"kernelName": "csharp"
|
||||
}
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"AIAgent researcherAgent = azureClient.GetOpenAIResponseClient(deployment).CreateAIAgent(\n",
|
||||
" name:ResearcherAgentName,instructions:ResearcherAgentInstructions);\n",
|
||||
"AIAgent plannerAgent = azureClient.GetOpenAIResponseClient(deployment).CreateAIAgent(\n",
|
||||
" name:PlanAgentName,instructions:PlanAgentInstructions);"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 17,
|
||||
"id": "cf4d6cc5",
|
||||
"metadata": {
|
||||
"language_info": {
|
||||
"name": "polyglot-notebook"
|
||||
},
|
||||
"polyglot_notebook": {
|
||||
"kernelName": "csharp"
|
||||
}
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"\n",
|
||||
"public class ConcurrentStartExecutor() :\n",
|
||||
" ReflectingExecutor<ConcurrentStartExecutor>(\"ConcurrentStartExecutor\"),\n",
|
||||
" IMessageHandler<string>\n",
|
||||
"{\n",
|
||||
" /// <summary>\n",
|
||||
" /// Starts the concurrent processing by sending messages to the agents.\n",
|
||||
" /// </summary>\n",
|
||||
" /// <param name=\"message\">The user message to process</param>\n",
|
||||
" /// <param name=\"context\">Workflow context for accessing workflow services and adding events</param>\n",
|
||||
" /// <returns>A task representing the asynchronous operation</returns>\n",
|
||||
" public async ValueTask HandleAsync(string message, IWorkflowContext context)\n",
|
||||
" {\n",
|
||||
" // Broadcast the message to all connected agents. Receiving agents will queue\n",
|
||||
" // the message but will not start processing until they receive a turn token.\n",
|
||||
" await context.SendMessageAsync(new ChatMessage(ChatRole.User, message));\n",
|
||||
" // Broadcast the turn token to kick off the agents.\n",
|
||||
" await context.SendMessageAsync(new TurnToken(emitEvents: true));\n",
|
||||
" }\n",
|
||||
"}\n",
|
||||
"\n",
|
||||
"/// <summary>\n",
|
||||
"/// Executor that aggregates the results from the concurrent agents.\n",
|
||||
"/// </summary>\n",
|
||||
"public class ConcurrentAggregationExecutor() :\n",
|
||||
" ReflectingExecutor<ConcurrentAggregationExecutor>(\"ConcurrentAggregationExecutor\"),\n",
|
||||
" IMessageHandler<ChatMessage>\n",
|
||||
"{\n",
|
||||
" private readonly List<ChatMessage> _messages = [];\n",
|
||||
"\n",
|
||||
" /// <summary>\n",
|
||||
" /// Handles incoming messages from the agents and aggregates their responses.\n",
|
||||
" /// </summary>\n",
|
||||
" /// <param name=\"message\">The message from the agent</param>\n",
|
||||
" /// <param name=\"context\">Workflow context for accessing workflow services and adding events</param>\n",
|
||||
" /// <returns>A task representing the asynchronous operation</returns>\n",
|
||||
" public async ValueTask HandleAsync(ChatMessage message, IWorkflowContext context)\n",
|
||||
" {\n",
|
||||
" this._messages.Add(message);\n",
|
||||
"\n",
|
||||
" if (this._messages.Count == 2)\n",
|
||||
" {\n",
|
||||
" var formattedMessages = string.Join(Environment.NewLine, this._messages.Select(m => $\"{m.AuthorName}: {m.Text}\"));\n",
|
||||
" await context.YieldOutputAsync(formattedMessages);\n",
|
||||
" }\n",
|
||||
" }\n",
|
||||
"}"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 18,
|
||||
"id": "9f3d1627",
|
||||
"metadata": {
|
||||
"language_info": {
|
||||
"name": "polyglot-notebook"
|
||||
},
|
||||
"polyglot_notebook": {
|
||||
"kernelName": "csharp"
|
||||
}
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"var startExecutor = new ConcurrentStartExecutor();\n",
|
||||
"var aggregationExecutor = new ConcurrentAggregationExecutor();"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 19,
|
||||
"id": "8957f876",
|
||||
"metadata": {
|
||||
"language_info": {
|
||||
"name": "polyglot-notebook"
|
||||
},
|
||||
"polyglot_notebook": {
|
||||
"kernelName": "csharp"
|
||||
}
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"var workflow = new WorkflowBuilder(startExecutor)\n",
|
||||
" .AddFanOutEdge(startExecutor, targets: [researcherAgent, plannerAgent])\n",
|
||||
" .AddFanInEdge(aggregationExecutor, sources: [researcherAgent, plannerAgent])\n",
|
||||
" .WithOutputFrom(aggregationExecutor)\n",
|
||||
" .Build();"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 20,
|
||||
"id": "df71d4d2",
|
||||
"metadata": {
|
||||
"language_info": {
|
||||
"name": "polyglot-notebook"
|
||||
},
|
||||
"polyglot_notebook": {
|
||||
"kernelName": "csharp"
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Workflow completed with results:\n",
|
||||
"Plan-Agent: December is a magical time to visit Seattle, as the city embraces the festive season with sparkling holiday lights, seasonal activities, cozy indoor attractions, and hearty cuisine. The weather will be chilly, often rainy, and occasionally snowy, so pack accordingly. Here's a detailed trip plan for your Seattle visit:\n",
|
||||
"\n",
|
||||
"---\n",
|
||||
"\n",
|
||||
"### **Travel Dates** \n",
|
||||
"Suggested schedule: **3-5 days in Seattle (example: December 15–19)** \n",
|
||||
"Adjust according to your preferences and availability.\n",
|
||||
"\n",
|
||||
"---\n",
|
||||
"\n",
|
||||
"### **Packing Essentials** \n",
|
||||
"- Warm, waterproof coat \n",
|
||||
"- Umbrella or rain jacket (Seattle has rainy winters) \n",
|
||||
"- Waterproof boots or shoes \n",
|
||||
"- Layers: sweaters, thermal tops, scarves, gloves, and hats \n",
|
||||
"- Day backpack for exploring \n",
|
||||
"- Travel charger and portable power bank \n",
|
||||
"- Camera or phone for holiday photos \n",
|
||||
"\n",
|
||||
"---\n",
|
||||
"\n",
|
||||
"### **Day 1: Arrival and Exploring Downtown** \n",
|
||||
"**Morning** \n",
|
||||
"- Arrive at **Seattle-Tacoma International Airport (SEA)**. \n",
|
||||
"- Transfer to your accommodation (stay downtown for convenience). Options: \n",
|
||||
" - Luxury: **The Four Seasons Seattle** \n",
|
||||
" - Boutique: **The Hotel Andra** \n",
|
||||
" - Budget-friendly: **The Mediterranean Inn** \n",
|
||||
"\n",
|
||||
"**Afternoon** \n",
|
||||
"- Lunch at **Elliott’s Oyster House** near the waterfront for fresh seafood. \n",
|
||||
"- Begin exploring **Pike Place Market**. \n",
|
||||
" - Shop artisan goods and seasonal items. \n",
|
||||
" - Watch the famous fishmongers toss fish. \n",
|
||||
" - Grab a cup of coffee from the original **Starbucks** store (if the line isn't too long). \n",
|
||||
"\n",
|
||||
"**Evening** \n",
|
||||
"- Stroll along the **Seattle Waterfront** and explore the festive lights in **Waterfront Park**. \n",
|
||||
"- Enjoy dinner at **Canlis** for a fine dining experience or **Toulouse Petit** for flavorful Cajun/Creole cuisine. \n",
|
||||
"\n",
|
||||
"---\n",
|
||||
"\n",
|
||||
"### **Day 2: Iconic Attractions and Holiday Cheer** \n",
|
||||
"**Morning** \n",
|
||||
"- Visit the **Space Needle** first thing for stunning views of the city and Mount Rainier (on clear days). \n",
|
||||
"- Explore the **Chihuly Garden and Glass** exhibit nearby for mesmerizing art. \n",
|
||||
"\n",
|
||||
"**Afternoon** \n",
|
||||
"- Head to **Museum of Pop Culture (MoPOP)** for interactive exhibits covering music, gaming, sci-fi, and pop culture. \n",
|
||||
"- Grab lunch at **The Pink Door**, an Italian-American restaurant with festive vibes. \n",
|
||||
"\n",
|
||||
"**Evening** \n",
|
||||
"- Discover the **Seattle Center Winterfest**. It features: \n",
|
||||
" - Ice skating \n",
|
||||
" - Holiday music performances \n",
|
||||
" - Winter-themed light displays \n",
|
||||
"- Dinner at **Serious Pie** for wood-fired pizza or **Mashiko** if you're craving sushi. \n",
|
||||
"\n",
|
||||
"---\n",
|
||||
"\n",
|
||||
"### **Day 3: Day Trips and Nature** \n",
|
||||
"**Morning** \n",
|
||||
"- Take a short day trip to **Snoqualmie Falls** (about 40 minutes east of downtown Seattle). \n",
|
||||
" - Walk the scenic observation trails for stunning views of the waterfalls amidst wintry landscapes. \n",
|
||||
"\n",
|
||||
"**Afternoon** \n",
|
||||
"- Return to Seattle and warm up with lunch at **Matt’s in the Market** (great views and hearty food downtown). \n",
|
||||
"- Visit **Kerry Park** for postcard-worthy skyline views, especially during the holidays when lights sparkle across the city. \n",
|
||||
"\n",
|
||||
"**Evening** \n",
|
||||
"- Return to downtown and enjoy the holiday markets, such as **Downtown Holiday Lights & Market** (check for seasonal pop-ups). \n",
|
||||
"- Dinner and drinks at **The Nest**, a rooftop bar offering panoramic views of the waterfront. \n",
|
||||
"\n",
|
||||
"---\n",
|
||||
"\n",
|
||||
"### **Day 4: Unique Neighborhoods and Relaxing** \n",
|
||||
"**Morning** \n",
|
||||
"- Take a stroll through **Capitol Hill**, a trendy neighborhood. \n",
|
||||
" - Have brunch at **Tilikum Place Café** or **Tallulah’s**. \n",
|
||||
" - Explore local shops and bookstores like **Elliott Bay Book Company**. \n",
|
||||
"\n",
|
||||
"**Afternoon** \n",
|
||||
"- Take a relaxing afternoon ferry ride to **Bainbridge Island**. \n",
|
||||
" - Walk around charming boutiques and coffee shops. \n",
|
||||
" - Visit the scenic **Bloedel Reserve**, a stunning garden combining nature and holiday tranquility. \n",
|
||||
"\n",
|
||||
"**Evening** \n",
|
||||
"- Catch a live holiday-themed performance. Options include: \n",
|
||||
" - **The Nutcracker** by the Pacific Northwest Ballet \n",
|
||||
" - A Christmas show at **The Paramount Theatre** \n",
|
||||
"\n",
|
||||
"Have your last dinner in Seattle at **Revolver Bar** or **Etta’s**, located near the waterfront.\n",
|
||||
"\n",
|
||||
"---\n",
|
||||
"\n",
|
||||
"### **Day 5: Departure** \n",
|
||||
"**Morning** \n",
|
||||
"- Stop at **Seattle Coffee Works** or **Café Ladro** for your last dose of Seattle coffee culture. \n",
|
||||
"- Souvenir shopping at **Ye Olde Curiosity Shop** for unique keepsakes. \n",
|
||||
"- Head to the airport for your flight home. \n",
|
||||
"\n",
|
||||
"---\n",
|
||||
"\n",
|
||||
"### **Transportation** \n",
|
||||
"- **Getting Around**: \n",
|
||||
" - Utilize Seattle’s excellent public transit system (Link Light Rail, buses, and streetcars). \n",
|
||||
" - Rideshare options like Uber/Lyft are readily available. \n",
|
||||
" - Rent a car only if planning day trips outside the city (e.g., Snoqualmie Falls). \n",
|
||||
"\n",
|
||||
"---\n",
|
||||
"\n",
|
||||
"### **Budget Considerations** \n",
|
||||
"- **Accommodations**: $150–$400 per night (depending on preferences) \n",
|
||||
"- **Food**: $60–$100/day per person \n",
|
||||
"- **Activities** (tickets): $50–$100/day \n",
|
||||
"- **Transportation**: $10–$20/day for public transit/rideshares \n",
|
||||
"\n",
|
||||
"---\n",
|
||||
"\n",
|
||||
"### **Extra Notes**\n",
|
||||
"- Make restaurant reservations for popular spots, especially during the holidays. \n",
|
||||
"- Seattle weather can change rapidly, so keep an umbrella or raincoat with you at all times. \n",
|
||||
"- Be mindful of the shorter daylight hours in December. \n",
|
||||
"\n",
|
||||
"Enjoy the cozy vibes, festive activities, and breathtaking views that Seattle offers in December! Let me know if you'd like more suggestions.\r\n",
|
||||
"Researcher-Agent: Seattle in December is a wonderful destination with its mix of urban charm, holiday festivities, and nearby natural beauty. While the weather may be chilly (averaging 40°F–47°F with rain), the city’s attractions and seasonal events provide plenty to enjoy. Below, I’ll outline an itinerary and highlight key destinations to make the most of your trip. \n",
|
||||
"\n",
|
||||
"---\n",
|
||||
"\n",
|
||||
"### **Day 1: Downtown Seattle Exploration**\n",
|
||||
"1. **Pike Place Market** \n",
|
||||
" - **Why Visit?** Seattle’s iconic landmark, filled with local food vendors, artisanal goods, and street performers. Don’t miss the famous fish toss and the original Starbucks store. \n",
|
||||
" - **Things to Do**: Browse the market, enjoy lunch at Beecher’s Handmade Cheese or Piroshky Piroshky, and stop at the market’s waterfront for views of Elliott Bay. \n",
|
||||
" - **Seasonal Note**: Holiday decorations make this area festive! Look for vendors selling seasonal handicrafts. \n",
|
||||
"\n",
|
||||
"2. **Seattle Aquarium** \n",
|
||||
" - **Why Visit?** Located nearby on the waterfront, the aquarium offers interactive exhibits about marine life from the Pacific Northwest. \n",
|
||||
" - **Things to Do**: Explore exhibits like the underwater dome, touch tanks with sea stars, and learn about marine conservation. \n",
|
||||
"\n",
|
||||
"3. **Waterfront and Great Wheel** \n",
|
||||
" - **Why Visit?** The Seattle Great Wheel, one of the largest Ferris wheels on the West Coast, offers panoramic views of the city, Puget Sound, and mountains. \n",
|
||||
" - **Things to Do**: Take a ride on the Great Wheel (especially stunning at twilight), explore the waterfront area, and check out shops or restaurants such as Ivar’s Seafood Bar. \n",
|
||||
"\n",
|
||||
"---\n",
|
||||
"\n",
|
||||
"### **Day 2: Iconic Landmarks & Museums** \n",
|
||||
"1. **Space Needle** \n",
|
||||
" - **Why Visit?** This famous tower offers 360-degree views of Seattle, including Mt. Rainier, Puget Sound, and the Olympic and Cascade mountain ranges. \n",
|
||||
" - **Things to Do**: Visit the observation deck, take photos of the city skyline, and grab food at the café if desired. \n",
|
||||
" - **Seasonal Note**: The views may include snow-capped mountains if the weather is clear. \n",
|
||||
"\n",
|
||||
"2. **Chihuly Garden and Glass** \n",
|
||||
" - **Why Visit?** A visually stunning museum featuring Dale Chihuly's unique glass sculptures. \n",
|
||||
" - **Things to Do**: Walk through the glasshouse, gardens, and indoor exhibits to marvel at the artistry of blown glass installations. \n",
|
||||
"\n",
|
||||
"3. **Museum of Pop Culture (MoPOP)** \n",
|
||||
" - **Why Visit?** A vibrant museum on creativity and entertainment, perfect for pop culture enthusiasts. \n",
|
||||
" - **Things to Do**: Explore exhibits on music (like the Nirvana gallery), science fiction, film, gaming, and more. \n",
|
||||
"\n",
|
||||
"4. **Holiday Festivities in Seattle Center** \n",
|
||||
" - **Why Visit?** Seattle Center often hosts holiday-themed events in December, like evening light shows and performances. Check out the Winterfest activities, including ice skating at the Seattle Center Armory. \n",
|
||||
"\n",
|
||||
"---\n",
|
||||
"\n",
|
||||
"### **Day 3: Nature & Surrounding Areas** \n",
|
||||
"1. **Discovery Park** \n",
|
||||
" - **Why Visit?** Seattle’s largest green space, offering tranquil beaches, forested trails, and stunning views of Puget Sound and the Olympic Mountains. \n",
|
||||
" - **Things to Do**: Hike the trails, walk to the West Point Lighthouse, and enjoy the fresh air with gorgeous coastal scenery. \n",
|
||||
"\n",
|
||||
"2. **Fremont Neighborhood** \n",
|
||||
" - **Why Visit?** Known as the “Center of the Universe,” this quirky neighborhood offers boutique shops, great restaurants, art, and attractions. \n",
|
||||
" - **Things to Do**: See the Fremont Troll under the Aurora Bridge, shop local stores, and dine at neighborhood favorites like Revel or Joule. \n",
|
||||
"\n",
|
||||
"3. **Gas Works Park** \n",
|
||||
" - **Why Visit?** A scenic spot for city skyline views. The historic gas plant structures make this park unique. \n",
|
||||
" - **Things to Do**: Take photos of the skyline at sunset, have a winter picnic, or simply enjoy the panoramic city-bay views. \n",
|
||||
"\n",
|
||||
"---\n",
|
||||
"\n",
|
||||
"### **Day 4: Day Trip to Mount Rainier or Leavenworth** \n",
|
||||
"1. **Option 1: Mount Rainier National Park** \n",
|
||||
" - **Why Visit?** Located about 2 hours from Seattle, this stunning national park offers winter scenery, snowshoeing, and peaceful landscapes. \n",
|
||||
" - **Things to Do**: Book a snowshoe tour, visit Paradise for picturesque winter views, and soak in the serenity of nature. \n",
|
||||
"\n",
|
||||
"2. **Option 2: Leavenworth Christmas Village** \n",
|
||||
" - **Why Visit?** About 2.5 hours away, Leavenworth is an alpine-style Bavarian village that transforms into a winter wonderland in December. \n",
|
||||
" - **Things to Do**: Stroll through the Christmas-lit village, shop for holiday gifts, enjoy German-inspired food and drinks (like bratwurst and glühwein), and check out sleigh rides or sledding opportunities. \n",
|
||||
"\n",
|
||||
"---\n",
|
||||
"\n",
|
||||
"### **Optional Activities (in case you extend your stay)** \n",
|
||||
"- **Pacific Northwest Ballet: \"The Nutcracker\"** \n",
|
||||
" - Why Visit? A quintessential holiday favorite, performed beautifully in Seattle each December. \n",
|
||||
"- **Woodinville Wine Country** (day trip) \n",
|
||||
" - Why Visit? Sip on world-class wines at charming wineries just 30 minutes northeast of Seattle.\n",
|
||||
"\n",
|
||||
"---\n",
|
||||
"\n",
|
||||
"### Packing Tips for December Seattle Visit: \n",
|
||||
"1. **Clothing**: Waterproof jacket, warm layers, scarves, and comfortable walking shoes. \n",
|
||||
"2. **Gear**: Umbrella or hooded raincoat (Seattle is rainy in December!), and a camera for capturing holiday decorations and scenic vistas.\n",
|
||||
"\n",
|
||||
"This itinerary blends Seattle’s iconic landmarks, holiday spirit, and nearby natural wonders for a memorable December trip! Let me know if you'd like me to refine or customize further.\r\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"\n",
|
||||
" StreamingRun run = await InProcessExecution.StreamAsync(workflow, \"Plan a trip to Seattle in December\");\n",
|
||||
" await foreach (WorkflowEvent evt in run.WatchStreamAsync().ConfigureAwait(false))\n",
|
||||
" {\n",
|
||||
" if (evt is WorkflowOutputEvent output)\n",
|
||||
" {\n",
|
||||
" Console.WriteLine($\"Workflow completed with results:\\n{output.Data}\");\n",
|
||||
" }\n",
|
||||
" }"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": ".NET (C#)",
|
||||
"language": "C#",
|
||||
"name": ".net-csharp"
|
||||
},
|
||||
"language_info": {
|
||||
"name": "polyglot-notebook"
|
||||
},
|
||||
"polyglot_notebook": {
|
||||
"kernelInfo": {
|
||||
"defaultKernelName": "csharp",
|
||||
"items": [
|
||||
{
|
||||
"aliases": [],
|
||||
"name": "csharp"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
+287
@@ -0,0 +1,287 @@
|
||||
# ⚡ Concurrent Agent Workflows with Azure OpenAI (Responses API) (.NET)
|
||||
|
||||
## 📋 High-Performance Parallel Processing Tutorial
|
||||
|
||||
This notebook demonstrates **concurrent workflow patterns** using the Microsoft Agent Framework for .NET and Azure OpenAI (Responses API). You'll learn how to build high-performance, parallel processing workflows that maximize throughput by executing multiple AI agents simultaneously while maintaining coordination and data consistency.
|
||||
|
||||
## 🎯 Learning Objectives
|
||||
|
||||
### 🚀 **Concurrent Processing Fundamentals**
|
||||
- **Parallel Agent Execution**: Run multiple AI agents simultaneously for maximum performance
|
||||
- **Async/Await Patterns**: Leverage .NET's async programming model for efficient concurrency
|
||||
- **Azure OpenAI (Responses API)**: Coordinate multiple concurrent calls to the Azure OpenAI Responses API
|
||||
- **Resource Management**: Efficiently manage AI model resources across concurrent operations
|
||||
|
||||
### 🏗️ **Advanced Concurrency Architecture**
|
||||
- **Task-Based Parallelism**: Use .NET Task Parallel Library for optimal concurrent execution
|
||||
- **Synchronization Patterns**: Coordinate concurrent agents while avoiding race conditions
|
||||
- **Load Balancing**: Distribute work efficiently across available concurrent processing capacity
|
||||
- **Fault Tolerance**: Handle individual agent failures without stopping the entire workflow
|
||||
|
||||
### 🏢 **Enterprise Concurrent Applications**
|
||||
- **High-Volume Document Processing**: Process multiple documents simultaneously
|
||||
- **Real-Time Content Analysis**: Concurrent analysis of incoming data streams
|
||||
- **Batch Processing Optimization**: Maximize throughput for large-scale data processing operations
|
||||
- **Multi-Modal Analysis**: Parallel processing of different content types and formats
|
||||
|
||||
## ⚙️ Prerequisites & Setup
|
||||
|
||||
### 📦 **Required NuGet Packages**
|
||||
|
||||
Essential packages for high-performance concurrent workflows:
|
||||
|
||||
```xml
|
||||
<!-- Core AI Framework with Async Support -->
|
||||
<PackageReference Include="Microsoft.Extensions.AI" Version="9.9.0" />
|
||||
|
||||
<!-- Azure OpenAI (Responses API) -->
|
||||
<PackageReference Include="Azure.AI.OpenAI" Version="2.1.0" />
|
||||
|
||||
<!-- Azure Identity and Async LINQ for Advanced Operations -->
|
||||
<PackageReference Include="Azure.Identity" Version="1.15.0" />
|
||||
<PackageReference Include="System.Linq.Async" Version="6.0.3" />
|
||||
|
||||
<!-- Local Agent Framework References -->
|
||||
<!-- Microsoft.Agents.AI.dll - Core agent abstractions with async support -->
|
||||
<!-- Microsoft.Agents.AI.OpenAI.dll - Azure OpenAI (Responses API) integration with concurrency -->
|
||||
```
|
||||
|
||||
### 🔑 **Azure OpenAI Configuration**
|
||||
|
||||
**Environment Setup (.env file):**
|
||||
```env
|
||||
AZURE_OPENAI_ENDPOINT=https://<your-resource>.openai.azure.com
|
||||
AZURE_OPENAI_DEPLOYMENT=gpt-4o-mini
|
||||
```
|
||||
|
||||
**Concurrent Processing Considerations:**
|
||||
```csharp
|
||||
// Configure for concurrent operations
|
||||
var clientOptions = new AzureOpenAIClientOptions()
|
||||
{
|
||||
// Configure network timeout for concurrent requests
|
||||
NetworkTimeout = TimeSpan.FromMinutes(5)
|
||||
};
|
||||
```
|
||||
|
||||
### 🏗️ **Concurrent Workflow Architecture**
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
A[Workflow Input] --> B[Task Distribution]
|
||||
B --> C[Concurrent Agent Pool]
|
||||
C --> D[Agent Task 1]
|
||||
C --> E[Agent Task 2]
|
||||
C --> F[Agent Task 3]
|
||||
C --> G[Agent Task N]
|
||||
|
||||
D --> H[Result Aggregation]
|
||||
E --> H
|
||||
F --> H
|
||||
G --> H
|
||||
|
||||
H --> I[Synchronized Output]
|
||||
|
||||
J[Azure OpenAI (Responses API)] --> D
|
||||
J --> E
|
||||
J --> F
|
||||
J --> G
|
||||
|
||||
K[.NET Task Scheduler] --> C
|
||||
```
|
||||
|
||||
**Key Components:**
|
||||
- **Task Parallel Library**: .NET's built-in support for concurrent operations
|
||||
- **Agent Pool**: Multiple agent instances for parallel processing
|
||||
- **Result Aggregation**: Coordination and merging of concurrent agent results
|
||||
- **Synchronization Points**: Ensure data consistency across concurrent operations
|
||||
|
||||
## 🎨 **Concurrent Workflow Design Patterns**
|
||||
|
||||
### 🔍 **Parallel Research & Analysis**
|
||||
```
|
||||
Research Topic → Concurrent Research Agents → Result Synthesis → Final Report
|
||||
```
|
||||
|
||||
### 📊 **Multi-Source Data Processing**
|
||||
```
|
||||
Data Sources → Parallel Processing Agents → Data Integration → Unified Output
|
||||
```
|
||||
|
||||
### 🎭 **Content Generation Pipeline**
|
||||
```
|
||||
Content Requirements → Concurrent Content Generators → Quality Review → Final Content
|
||||
```
|
||||
|
||||
### 🔄 **Fan-Out/Fan-In Processing**
|
||||
```
|
||||
Single Input → Multiple Concurrent Processors → Result Aggregation → Single Output
|
||||
```
|
||||
|
||||
## 🏢 **Enterprise Performance Benefits**
|
||||
|
||||
### ⚡ **Throughput & Scalability**
|
||||
- **Linear Performance Scaling**: Add more concurrent agents to increase throughput
|
||||
- **Resource Utilization**: Maximum efficiency of available AI model capacity
|
||||
- **Reduced Processing Time**: Significant time reduction through parallel execution
|
||||
- **Elastic Scaling**: Dynamically adjust concurrent agent count based on workload
|
||||
|
||||
### 🛡️ **Reliability & Resilience**
|
||||
- **Fault Isolation**: Individual agent failures don't affect other concurrent operations
|
||||
- **Graceful Degradation**: System continues operating with reduced agent capacity
|
||||
- **Error Recovery**: Automatic retry mechanisms for failed concurrent operations
|
||||
- **Load Distribution**: Even distribution of work across available agents
|
||||
|
||||
### 📊 **Performance Monitoring**
|
||||
- **Concurrent Execution Metrics**: Track performance of all parallel operations
|
||||
- **Resource Usage Analytics**: Monitor CPU, memory, and network utilization
|
||||
- **Throughput Analysis**: Measure efficiency gains from concurrent processing
|
||||
- **Bottleneck Detection**: Identify and resolve performance constraints
|
||||
|
||||
### 🔧 **Development & Operations**
|
||||
- **Async Programming Model**: Leverage .NET's mature async/await patterns
|
||||
- **Task Coordination**: Built-in task management and coordination capabilities
|
||||
- **Exception Handling**: Comprehensive error handling for concurrent operations
|
||||
- **Debugging Support**: Visual Studio debugging tools for concurrent workflows
|
||||
|
||||
Let's build high-performance concurrent AI workflows with .NET! 🚀
|
||||
|
||||
## 💻 Running the Code
|
||||
|
||||
The complete implementation is available in `03.dotnet-agent-framework-workflow-ghmodel-concurrent.cs`. This file demonstrates a **Fan-Out/Fan-In concurrent workflow** for travel planning:
|
||||
|
||||
### 🏗️ **Workflow Architecture**
|
||||
|
||||
```
|
||||
User Request → ConcurrentStartExecutor → [Researcher Agent || Planner Agent] → ConcurrentAggregationExecutor → Final Output
|
||||
```
|
||||
|
||||
**Key Components:**
|
||||
|
||||
1. **ConcurrentStartExecutor**: Broadcasts the user request to all agents simultaneously
|
||||
2. **Researcher Agent**: Analyzes destinations and attractions concurrently
|
||||
3. **Planner Agent**: Creates detailed travel plans concurrently
|
||||
4. **ConcurrentAggregationExecutor**: Collects and merges results from both agents
|
||||
|
||||
### 🎯 **Fan-Out/Fan-In Pattern**
|
||||
|
||||
This workflow demonstrates the classic **Fan-Out/Fan-In** pattern:
|
||||
- **Fan-Out**: One input message is broadcast to multiple agents simultaneously
|
||||
- **Concurrent Processing**: Multiple agents work in parallel on the same task
|
||||
- **Fan-In**: Results from all agents are collected and aggregated into a single output
|
||||
|
||||
### 🚀 Running the Example
|
||||
|
||||
```bash
|
||||
# Make the script executable (Unix/Linux/macOS)
|
||||
chmod +x 03.dotnet-agent-framework-workflow-ghmodel-concurrent.cs
|
||||
|
||||
# Run the concurrent workflow
|
||||
./03.dotnet-agent-framework-workflow-ghmodel-concurrent.cs
|
||||
```
|
||||
|
||||
Or on Windows:
|
||||
```powershell
|
||||
dotnet run 03.dotnet-agent-framework-workflow-ghmodel-concurrent.cs
|
||||
```
|
||||
|
||||
### 📝 Expected Output
|
||||
|
||||
The workflow will:
|
||||
1. **Broadcast Request**: Send "Plan a trip to Seattle in December" to both agents
|
||||
2. **Concurrent Processing**: Both agents work simultaneously:
|
||||
- Researcher identifies attractions and details
|
||||
- Planner creates itinerary and logistics
|
||||
3. **Aggregation**: Combine both responses into comprehensive output
|
||||
4. **Display Results**: Show the merged travel plan with all information
|
||||
|
||||
### 🔧 Customization Options
|
||||
|
||||
**Add More Concurrent Agents:**
|
||||
```csharp
|
||||
// Create additional specialized agents
|
||||
AIAgent budgetAgent = azureClient.GetOpenAIResponseClient(deployment).CreateAIAgent(
|
||||
name: "Budget-Agent", instructions: "Calculate travel costs...");
|
||||
|
||||
// Add to fan-out
|
||||
var workflow = new WorkflowBuilder(startExecutor)
|
||||
.AddFanOutEdge(startExecutor, targets: [researcherAgent, plannerAgent, budgetAgent])
|
||||
.AddFanInEdge(aggregationExecutor, sources: [researcherAgent, plannerAgent, budgetAgent])
|
||||
.WithOutputFrom(aggregationExecutor)
|
||||
.Build();
|
||||
|
||||
// Update aggregation count
|
||||
if (this._messages.Count == 3) { ... }
|
||||
```
|
||||
|
||||
**Modify Agent Instructions:**
|
||||
```csharp
|
||||
const string ResearcherAgentInstructions = "Your custom instructions for research...";
|
||||
const string PlanAgentInstructions = "Your custom instructions for planning...";
|
||||
```
|
||||
|
||||
**Change the Task:**
|
||||
```csharp
|
||||
StreamingRun run = await InProcessExecution.StreamAsync(
|
||||
workflow,
|
||||
"Plan a European vacation for 2 weeks in summer"
|
||||
);
|
||||
```
|
||||
|
||||
### 🎯 Real-World Applications
|
||||
|
||||
This concurrent pattern is ideal for:
|
||||
- **Content Creation**: Multiple writers creating different sections simultaneously
|
||||
- **Code Review**: Multiple reviewers analyzing code from different perspectives
|
||||
- **Market Research**: Parallel analysis of different market segments
|
||||
- **Document Processing**: Concurrent extraction, analysis, and validation
|
||||
- **Multi-Perspective Analysis**: Getting diverse viewpoints on the same input
|
||||
|
||||
### 🔍 Understanding Custom Executors
|
||||
|
||||
**ConcurrentStartExecutor:**
|
||||
- Implements `IMessageHandler<string>` to accept string input
|
||||
- Broadcasts messages to all connected agents
|
||||
- Sends `TurnToken` to trigger concurrent processing
|
||||
|
||||
**ConcurrentAggregationExecutor:**
|
||||
- Implements `IMessageHandler<ChatMessage>` to receive agent responses
|
||||
- Collects messages in a thread-safe manner
|
||||
- Aggregates when all expected responses arrive
|
||||
- Yields final output using `context.YieldOutputAsync()`
|
||||
|
||||
### ⚡ Performance Benefits
|
||||
|
||||
**Concurrent vs Sequential:**
|
||||
- Sequential: Agent1 (30s) → Agent2 (30s) = **60 seconds total**
|
||||
- Concurrent: Agent1 (30s) || Agent2 (30s) = **30 seconds total**
|
||||
|
||||
**Throughput improvement**: Up to N× faster for N concurrent agents (depending on workload and resources)
|
||||
|
||||
### 🛡️ Error Handling
|
||||
|
||||
The workflow handles individual agent failures gracefully:
|
||||
- If one agent fails, others continue processing
|
||||
- Aggregator can implement timeout logic
|
||||
- Partial results can be returned if needed
|
||||
|
||||
### 📊 Advanced Features
|
||||
|
||||
**Dynamic Agent Count:**
|
||||
Modify the aggregation logic to support variable agent counts:
|
||||
|
||||
```csharp
|
||||
private int _expectedAgentCount;
|
||||
private readonly List<ChatMessage> _messages = [];
|
||||
|
||||
public async ValueTask HandleAsync(ChatMessage message, IWorkflowContext context)
|
||||
{
|
||||
this._messages.Add(message);
|
||||
if (this._messages.Count == _expectedAgentCount)
|
||||
{
|
||||
// Process aggregation
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This concurrent workflow pattern is essential for building high-performance, scalable AI agent systems!
|
||||
+297
@@ -0,0 +1,297 @@
|
||||
#!/usr/bin/dotnet run
|
||||
#:package Microsoft.Extensions.AI@9.9.1
|
||||
#:package Azure.AI.Agents.Persistent@1.2.0-beta.5
|
||||
#:package Azure.Identity@1.15.0
|
||||
#:package System.Linq.Async@6.0.3
|
||||
#:package DotNetEnv@3.1.1
|
||||
#:package OpenTelemetry.Api@1.0.0
|
||||
#:package Microsoft.Agents.AI.Workflows@1.0.0-preview.251001.3
|
||||
#:package Microsoft.Agents.AI.AzureAI@1.0.0-preview.251001.3
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Threading.Tasks;
|
||||
using Azure.AI.Agents.Persistent;
|
||||
using Azure.Identity;
|
||||
using Microsoft.Extensions.AI;
|
||||
using Microsoft.Agents.AI;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Agents.AI.Workflows;
|
||||
using Microsoft.Agents.AI.Workflows.Reflection;
|
||||
using DotNetEnv;
|
||||
|
||||
// Load environment variables from .env file
|
||||
Env.Load("../../../.env");
|
||||
|
||||
// Configure Microsoft Foundry endpoint and credentials
|
||||
var azure_foundry_endpoint = Environment.GetEnvironmentVariable("AZURE_AI_PROJECT_ENDPOINT") ?? throw new InvalidOperationException("AZURE_AI_PROJECT_ENDPOINT is not set.");
|
||||
var azure_foundry_model_id = "gpt-4o-mini";
|
||||
var bing_conn_id = Environment.GetEnvironmentVariable("BING_CONNECTION_ID");
|
||||
|
||||
// Agent Instructions for Content Production Workflow
|
||||
const string EvangelistInstructions = @"
|
||||
You are a technology evangelist who creates first drafts for technical tutorials.
|
||||
1. Each knowledge point in the outline must include a link. Follow the link to access the content related to the knowledge point in the outline. Expand on that content.
|
||||
2. Each knowledge point must be explained in detail.
|
||||
3. Rewrite the content according to the entry requirements, including the title, outline, and corresponding content. It is not necessary to follow the outline in full order.
|
||||
4. The content must be more than 200 words.
|
||||
4. Output draft as Markdown format. set 'draft_content' to the draft content.
|
||||
5. return result as JSON with fields 'draft_content' (string).";
|
||||
|
||||
const string ContentReviewerInstructions = @"
|
||||
You are a content reviewer and need to check whether the tutorial's draft content meets the following requirements:
|
||||
|
||||
1. If the draft content is less than 200 words, set 'review_result' to 'No' and 'reason' to 'Content is too short'. If the draft content is more than 200 words, set 'review_result' to 'Yes' and 'reason' to 'The content is good'.
|
||||
2. set 'draft_content' to the original draft content.
|
||||
3. return result as JSON with fields 'review_result' ('Yes' or 'No' ) and 'reason' (string) and 'draft_content' (string).";
|
||||
|
||||
const string PublisherInstructions = @"
|
||||
You are the content publisher who runs code to save the tutorial's draft content as a Markdown file. Saved file's name is marked with current date and time, such as yearmonthdayhourminsec. Note that if it is 1-9, you need to add 0, such as 20240101123045.md.
|
||||
";
|
||||
|
||||
// Sample content outline for tutorial generation
|
||||
string OUTLINE_Content = @"
|
||||
# Introduce AI Agent
|
||||
|
||||
## What's AI Agent
|
||||
https://github.com/microsoft/ai-agents-for-beginners/tree/main/01-intro-to-ai-agents
|
||||
|
||||
***Note*** Don't create any sample code
|
||||
|
||||
## Introduce Microsoft Foundry Agent Service
|
||||
https://learn.microsoft.com/en-us/azure/ai-foundry/agents/overview
|
||||
|
||||
***Note*** Don't create any sample code
|
||||
|
||||
## Microsoft Agent Framework
|
||||
https://github.com/microsoft/agent-framework/tree/main/docs/docs-templates
|
||||
|
||||
***Note*** Don't create any sample code
|
||||
";
|
||||
|
||||
// Configure Bing Grounding for web search capabilities
|
||||
var bingGroundingConfig = new BingGroundingSearchConfiguration(bing_conn_id);
|
||||
BingGroundingToolDefinition bingGroundingTool = new(
|
||||
new BingGroundingSearchToolParameters([bingGroundingConfig])
|
||||
);
|
||||
|
||||
// Create persistent agents client with Azure CLI authentication
|
||||
var persistentAgentsClient = new PersistentAgentsClient(azure_foundry_endpoint, new AzureCliCredential());
|
||||
|
||||
// Create the three specialized agents in Microsoft Foundry
|
||||
var evangelistMetadata = await persistentAgentsClient.Administration.CreateAgentAsync(
|
||||
model: azure_foundry_model_id,
|
||||
name: "Evangelist",
|
||||
instructions: EvangelistInstructions,
|
||||
tools: [bingGroundingTool]
|
||||
);
|
||||
|
||||
var contentReviewerMetadata = await persistentAgentsClient.Administration.CreateAgentAsync(
|
||||
model: azure_foundry_model_id,
|
||||
name: "ContentReviewer",
|
||||
instructions: ContentReviewerInstructions
|
||||
);
|
||||
|
||||
var publisherMetadata = await persistentAgentsClient.Administration.CreateAgentAsync(
|
||||
model: azure_foundry_model_id,
|
||||
name: "Publisher",
|
||||
instructions: PublisherInstructions,
|
||||
tools: [new CodeInterpreterToolDefinition()]
|
||||
);
|
||||
|
||||
// Extract agent IDs for later use
|
||||
string evangelist_agentId = evangelistMetadata.Value.Id;
|
||||
string contentReviewer_agentId = contentReviewerMetadata.Value.Id;
|
||||
string publisher_agentId = publisherMetadata.Value.Id;
|
||||
|
||||
// Get AI Agent instances with JSON schema response formatting
|
||||
AIAgent evangelistagent = await persistentAgentsClient.GetAIAgentAsync(evangelist_agentId, new() { });
|
||||
AIAgent contentRevieweragent = await persistentAgentsClient.GetAIAgentAsync(
|
||||
contentReviewer_agentId,
|
||||
new()
|
||||
{
|
||||
ResponseFormat = ChatResponseFormat.ForJsonSchema(
|
||||
AIJsonUtilities.CreateJsonSchema(typeof(ReviewResult)),
|
||||
"ReviewResult",
|
||||
"Review Result From DraftContent"
|
||||
)
|
||||
}
|
||||
);
|
||||
AIAgent publisheragent = await persistentAgentsClient.GetAIAgentAsync(publisher_agentId);
|
||||
|
||||
/// <summary>
|
||||
/// Creates a condition function for workflow routing based on review results.
|
||||
/// </summary>
|
||||
Func<object?, bool> GetCondition(string expectedResult) =>
|
||||
reviewResult => reviewResult is ReviewResult review && review.Result == expectedResult;
|
||||
|
||||
// Create executor instances
|
||||
var draftExecutor = new DraftExecutor(evangelistagent);
|
||||
var contentReviewerExecutor = new ContentReviewExecutor(contentRevieweragent);
|
||||
var publishExecutor = new PublishExecutor(publisheragent);
|
||||
var sendReviewerExecutor = new SendReviewExecutor();
|
||||
|
||||
// Build conditional workflow with routing based on review results
|
||||
var workflow = new WorkflowBuilder(draftExecutor)
|
||||
.AddEdge(draftExecutor, contentReviewerExecutor)
|
||||
.AddEdge(contentReviewerExecutor, publishExecutor, condition: GetCondition(expectedResult: "Yes"))
|
||||
.AddEdge(contentReviewerExecutor, sendReviewerExecutor, condition: GetCondition(expectedResult: "No"))
|
||||
.Build();
|
||||
|
||||
// Create user prompt with content outline
|
||||
string prompt = @"You need to write a draft based on the following outline and the content provided in the link corresponding to the outline.
|
||||
After draft create, the reviewer check it, if it meets the requirements, it will be submitted to the publisher and save it as a Markdown file,
|
||||
otherwise need to rewrite draft until it meets the requirements.
|
||||
The provided outline content and related links is as follows:" + OUTLINE_Content;
|
||||
|
||||
Console.WriteLine(prompt);
|
||||
|
||||
// Execute conditional workflow
|
||||
var chat = new ChatMessage(ChatRole.User, prompt);
|
||||
StreamingRun run = await InProcessExecution.StreamAsync(workflow, chat);
|
||||
|
||||
// Process workflow events and display results
|
||||
await run.TrySendMessageAsync(new TurnToken(emitEvents: true));
|
||||
string id = "";
|
||||
string messageData = "";
|
||||
await foreach (WorkflowEvent evt in run.WatchStreamAsync().ConfigureAwait(false))
|
||||
{
|
||||
if (evt is AgentRunUpdateEvent executorComplete)
|
||||
{
|
||||
if (id == "")
|
||||
{
|
||||
id = executorComplete.ExecutorId;
|
||||
}
|
||||
if (id == executorComplete.ExecutorId)
|
||||
{
|
||||
messageData += executorComplete.Data.ToString();
|
||||
}
|
||||
else
|
||||
{
|
||||
id = executorComplete.ExecutorId;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Console.WriteLine(messageData);
|
||||
|
||||
// Define result models for structured JSON responses
|
||||
public class ContentResult
|
||||
{
|
||||
[JsonPropertyName("draft_content")]
|
||||
public string DraftContent { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
public class ReviewResult
|
||||
{
|
||||
[JsonPropertyName("review_result")]
|
||||
public string Result { get; set; } = string.Empty;
|
||||
|
||||
[JsonPropertyName("reason")]
|
||||
public string Reason { get; set; } = string.Empty;
|
||||
|
||||
[JsonPropertyName("draft_content")]
|
||||
public string DraftContent { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Custom executor that creates content drafts from outlines.
|
||||
/// </summary>
|
||||
public class DraftExecutor : ReflectingExecutor<DraftExecutor>, IMessageHandler<ChatMessage, ContentResult>
|
||||
{
|
||||
private readonly AIAgent _evangelistAgent;
|
||||
|
||||
public DraftExecutor(AIAgent evangelistAgent) : base("DraftExecutor")
|
||||
{
|
||||
this._evangelistAgent = evangelistAgent;
|
||||
}
|
||||
|
||||
public async ValueTask<ContentResult> HandleAsync(ChatMessage message, IWorkflowContext context)
|
||||
{
|
||||
Console.WriteLine($"DraftExecutor .......loading \n" + message.Text);
|
||||
|
||||
var response = await this._evangelistAgent.RunAsync(message);
|
||||
|
||||
// The agent may wrap its JSON result in a Markdown code block (```json ... ```),
|
||||
// so extract the JSON object before deserializing it into a ContentResult.
|
||||
var contentResult = JsonSerializer.Deserialize<ContentResult>(ExtractJson(response.Text)) ?? new ContentResult { DraftContent = response.Text ?? string.Empty };
|
||||
|
||||
Console.WriteLine($"DraftExecutor generated draft length: {contentResult.DraftContent?.Length ?? 0}");
|
||||
|
||||
return contentResult;
|
||||
}
|
||||
|
||||
private static string ExtractJson(string text)
|
||||
{
|
||||
var start = text.IndexOf('{');
|
||||
var end = text.LastIndexOf('}');
|
||||
return start >= 0 && end > start ? text.Substring(start, end - start + 1) : text;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Custom executor that reviews content quality and determines approval.
|
||||
/// </summary>
|
||||
public class ContentReviewExecutor : ReflectingExecutor<ContentReviewExecutor>, IMessageHandler<ContentResult, ReviewResult>
|
||||
{
|
||||
private readonly AIAgent _contentReviewerAgent;
|
||||
|
||||
public ContentReviewExecutor(AIAgent contentReviewerAgent) : base("ContentReviewExecutor")
|
||||
{
|
||||
this._contentReviewerAgent = contentReviewerAgent;
|
||||
}
|
||||
|
||||
public async ValueTask<ReviewResult> HandleAsync(ContentResult content, IWorkflowContext context)
|
||||
{
|
||||
Console.WriteLine($"ContentReviewExecutor .......loading");
|
||||
|
||||
var response = await this._contentReviewerAgent.RunAsync(content.DraftContent);
|
||||
var reviewResult = JsonSerializer.Deserialize<ReviewResult>(response.Text);
|
||||
|
||||
Console.WriteLine($"ContentReviewExecutor review result: {reviewResult.Result}, reason: {reviewResult.Reason}");
|
||||
|
||||
return reviewResult;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Custom executor that publishes approved content.
|
||||
/// </summary>
|
||||
public class PublishExecutor : ReflectingExecutor<PublishExecutor>, IMessageHandler<ReviewResult>
|
||||
{
|
||||
private readonly AIAgent _publishAgent;
|
||||
|
||||
public PublishExecutor(AIAgent publishAgent) : base("PublishExecutor")
|
||||
{
|
||||
this._publishAgent = publishAgent;
|
||||
}
|
||||
|
||||
public async ValueTask HandleAsync(ReviewResult review, IWorkflowContext context)
|
||||
{
|
||||
Console.WriteLine($"PublishExecutor .......loading");
|
||||
|
||||
var response = await this._publishAgent.RunAsync(review.DraftContent);
|
||||
|
||||
Console.WriteLine($"Response from PublishExecutor: {response.Text}");
|
||||
|
||||
await context.YieldOutputAsync($"Publishing result: {response.Text}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Custom executor that handles rejected content.
|
||||
/// </summary>
|
||||
public class SendReviewExecutor : ReflectingExecutor<SendReviewExecutor>, IMessageHandler<ReviewResult>
|
||||
{
|
||||
public SendReviewExecutor() : base("SendReviewExecutor")
|
||||
{
|
||||
}
|
||||
|
||||
public async ValueTask HandleAsync(ReviewResult message, IWorkflowContext context) =>
|
||||
await context.YieldOutputAsync($"Draft content sent for revision: {message.Result}");
|
||||
}
|
||||
+1196
File diff suppressed because it is too large
Load Diff
+340
@@ -0,0 +1,340 @@
|
||||
# 🔀 Conditional Agent Workflows with Microsoft Foundry (.NET)
|
||||
|
||||
## 📋 Intelligent Decision-Based Workflow Tutorial
|
||||
|
||||
This notebook demonstrates **conditional workflow patterns** using Microsoft Foundry and the Microsoft Agent Framework for .NET. You'll learn how to build sophisticated, decision-driven workflows that intelligently route processing based on AI analysis, business rules, and dynamic conditions for enterprise-grade automation.
|
||||
|
||||
## 🎯 Learning Objectives
|
||||
|
||||
### 🧠 **Intelligent Decision Architecture**
|
||||
- **Conditional Logic Implementation**: Build complex decision trees with multiple branching points
|
||||
- **AI-Powered Routing**: Use Microsoft Foundry models to make intelligent routing decisions
|
||||
- **Dynamic Workflow Adaptation**: Modify workflow behavior based on runtime analysis and conditions
|
||||
- **Enterprise Rule Integration**: Incorporate business logic and compliance requirements into workflows
|
||||
|
||||
### 🔀 **Advanced Conditional Patterns**
|
||||
- **Multi-Criteria Decision Making**: Evaluate multiple factors for routing decisions
|
||||
- **Context-Aware Processing**: Make decisions based on accumulated workflow context and history
|
||||
- **Adaptive Workflow Modification**: Dynamically adjust processing paths based on real-time conditions
|
||||
- **Rule Engine Integration**: Implement sophisticated business rule engines within workflows
|
||||
|
||||
### 🏢 **Enterprise Conditional Applications**
|
||||
- **Document Classification & Routing**: Automatically classify and route documents to appropriate workflows
|
||||
- **Customer Service Triage**: Intelligent routing of customer inquiries to specialized handling teams
|
||||
- **Compliance & Risk Processing**: Apply different validation and review processes based on risk assessment
|
||||
- **Quality Assurance Workflows**: Route content through appropriate review processes based on quality metrics
|
||||
|
||||
## ⚙️ Prerequisites & Setup
|
||||
|
||||
### 📦 **Required NuGet Packages**
|
||||
|
||||
Advanced packages for conditional workflow processing:
|
||||
|
||||
```xml
|
||||
<!-- Core AI Framework -->
|
||||
<PackageReference Include="Microsoft.Extensions.AI" Version="9.9.0" />
|
||||
|
||||
<!-- Azure AI Agents with Persistent State -->
|
||||
<PackageReference Include="Azure.AI.Agents.Persistent" Version="1.2.0-beta.5" />
|
||||
|
||||
<!-- Azure Identity and Utilities -->
|
||||
<PackageReference Include="Azure.Identity" Version="1.15.0" />
|
||||
<PackageReference Include="System.Linq.Async" Version="6.0.3" />
|
||||
<PackageReference Include="DotNetEnv" Version="3.1.1" />
|
||||
|
||||
<!-- Local Workflow Framework References -->
|
||||
<!-- Microsoft.Agents.Workflows.dll - Advanced workflow orchestration -->
|
||||
<!-- Microsoft.Agents.AI.AzureAI.dll - Microsoft Foundry integration -->
|
||||
<!-- Microsoft.Agents.AI.dll - Core agent abstractions -->
|
||||
```
|
||||
|
||||
### 🔑 **Microsoft Foundry Configuration**
|
||||
|
||||
**Required Azure Resources:**
|
||||
- Microsoft Foundry workspace with conditional processing models
|
||||
- Azure subscription with appropriate compute quotas and permissions
|
||||
- Deployed AI models for decision making and content analysis
|
||||
- (Optional) Bing Search API connection for grounding capabilities
|
||||
|
||||
**Environment Configuration (.env file):**
|
||||
```env
|
||||
# Microsoft Foundry Configuration
|
||||
AZURE_AI_PROJECT_ENDPOINT=https://your-project.cognitiveservices.azure.com/
|
||||
BING_CONNECTION_ID=your-bing-connection-id
|
||||
```
|
||||
|
||||
**Authentication Setup:**
|
||||
```csharp
|
||||
// Azure CLI or Managed Identity authentication
|
||||
using Azure.Identity;
|
||||
var credential = new AzureCliCredential();
|
||||
|
||||
// Load environment configuration
|
||||
DotNetEnv.Env.Load("../../../.env");
|
||||
```
|
||||
|
||||
### 🏗️ **Conditional Workflow Architecture**
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
A[Input: Content Outline] --> B[Draft Executor]
|
||||
B --> C[Content Review Executor]
|
||||
C --> D{Review Decision}
|
||||
|
||||
D -->|Yes - Approved| E[Publish Executor]
|
||||
D -->|No - Rejected| F[Send Review Executor]
|
||||
|
||||
E --> G[Save as Markdown File]
|
||||
F --> H[Notify for Revisions]
|
||||
|
||||
I[Microsoft Foundry] --> B
|
||||
I --> C
|
||||
I --> E
|
||||
|
||||
J[Bing Grounding] --> B
|
||||
```
|
||||
|
||||
**Key Components:**
|
||||
- **Draft Executor**: AI agent that creates initial content drafts from outlines
|
||||
- **Content Review Executor**: AI agent that evaluates draft quality and compliance
|
||||
- **Conditional Routing**: Decision logic that routes based on review results
|
||||
- **Publish/Review Paths**: Separate processing paths for approved vs rejected content
|
||||
- **State Management**: Maintains content and review context throughout workflow
|
||||
|
||||
## 🎨 **Conditional Workflow Design Patterns**
|
||||
|
||||
### 📋 **Content Production with Quality Gates**
|
||||
```
|
||||
Outline → Draft Creation → Quality Review → {Approve: Publish | Reject: Revise}
|
||||
```
|
||||
|
||||
### 🎯 **Risk-Based Document Processing**
|
||||
```
|
||||
Document → Risk Assessment → {Low: Standard | High: Enhanced Review}
|
||||
```
|
||||
|
||||
### 🔍 **Intelligent Customer Service Routing**
|
||||
```
|
||||
Customer Query → Analysis → {Simple: FAQ Bot | Complex: Human Agent}
|
||||
```
|
||||
|
||||
### 💼 **Compliance-Driven Workflows**
|
||||
```
|
||||
Content → Compliance Check → {Pass: Publish | Fail: Legal Review}
|
||||
```
|
||||
|
||||
## 🏢 **Enterprise Conditional Benefits**
|
||||
|
||||
### 🎯 **Intelligent Automation**
|
||||
- **Smart Decision Making**: AI-powered routing decisions based on content analysis and context
|
||||
- **Adaptive Processing**: Workflows that automatically adjust based on changing conditions
|
||||
- **Business Rule Enforcement**: Automatic application of complex business logic and policies
|
||||
- **Context-Aware Routing**: Decisions based on full workflow history and accumulated context
|
||||
|
||||
### 📈 **Operational Excellence**
|
||||
- **Optimized Resource Allocation**: Route work to most appropriate specialists and processes
|
||||
- **Reduced Manual Intervention**: Automated decision making minimizes need for human routing
|
||||
- **Faster Resolution Times**: Direct routing to appropriate expertise and processing capabilities
|
||||
- **Consistent Application**: Uniform application of business rules and decision criteria
|
||||
|
||||
### 🛡️ **Risk Management & Compliance**
|
||||
- **Automated Risk Assessment**: AI-powered evaluation of content and situation risk levels
|
||||
- **Compliance Enforcement**: Automatic routing through required regulatory processes
|
||||
- **Security Protocol Application**: Enhanced security measures applied based on risk assessment
|
||||
- **Audit Trail Maintenance**: Complete documentation of routing decisions and rationale
|
||||
|
||||
### 📊 **Analytics & Continuous Improvement**
|
||||
- **Decision Analytics**: Track effectiveness and accuracy of routing decisions
|
||||
- **Pattern Recognition**: Identify trends and patterns in routing decisions over time
|
||||
- **Performance Optimization**: Continuous improvement of decision criteria and routing efficiency
|
||||
- **Business Intelligence**: Insights into content characteristics and processing requirements
|
||||
|
||||
### 🔧 **Technical Excellence**
|
||||
- **Persistent State Management**: Maintain complex state across workflow execution
|
||||
- **Scalable Architecture**: Handle high-volume conditional processing requirements
|
||||
- **Integration Capabilities**: Seamless integration with existing business systems and processes
|
||||
- **Monitoring & Observability**: Comprehensive tracking of workflow performance and decisions
|
||||
|
||||
Let's build intelligent, decision-driven enterprise workflows with .NET! 🚀
|
||||
|
||||
## 💻 Running the Code
|
||||
|
||||
The complete implementation is available in `04.dotnet-agent-framework-workflow-aifoundry-condition.cs`. This demonstrates a **content production workflow with quality gates**:
|
||||
|
||||
### 🏗️ **Workflow Architecture**
|
||||
|
||||
```
|
||||
Content Outline → Draft Creation → Quality Review → Conditional Routing:
|
||||
├─ Approved (>200 words) → Publish
|
||||
└─ Rejected (<200 words) → Review Notification
|
||||
```
|
||||
|
||||
**Agents in the Workflow:**
|
||||
1. **Evangelist Agent**: Creates tutorial drafts from outlines with Bing grounding
|
||||
2. **Content Reviewer Agent**: Evaluates draft quality (word count, completeness)
|
||||
3. **Publisher Agent**: Saves approved content as timestamped Markdown files
|
||||
|
||||
**Custom Executors:**
|
||||
1. **DraftExecutor**: Orchestrates draft creation
|
||||
2. **ContentReviewExecutor**: Performs quality assessment
|
||||
3. **PublishExecutor**: Handles approved content publication
|
||||
4. **SendReviewExecutor**: Manages rejected content notifications
|
||||
|
||||
### 🚀 Running the Example
|
||||
|
||||
**Prerequisites:**
|
||||
- Microsoft Foundry workspace configured
|
||||
- Azure CLI authentication (`az login`)
|
||||
- (Optional) Bing Search connection for grounding
|
||||
|
||||
```bash
|
||||
# Make the script executable (Unix/Linux/macOS)
|
||||
chmod +x 04.dotnet-agent-framework-workflow-aifoundry-condition.cs
|
||||
|
||||
# Run the conditional workflow
|
||||
./04.dotnet-agent-framework-workflow-aifoundry-condition.cs
|
||||
```
|
||||
|
||||
Or on Windows:
|
||||
```powershell
|
||||
dotnet run 04.dotnet-agent-framework-workflow-aifoundry-condition.cs
|
||||
```
|
||||
|
||||
### 📝 Expected Output
|
||||
|
||||
The workflow will:
|
||||
1. **Create Agents**: Initialize three specialized Microsoft Foundry agents
|
||||
2. **Generate Draft**: Evangelist agent creates tutorial draft from outline
|
||||
3. **Review Content**: Content Reviewer evaluates draft quality
|
||||
4. **Conditional Routing**:
|
||||
- **If approved (>200 words)**: Publish executor saves as Markdown file
|
||||
- **If rejected (<200 words)**: Send review notification
|
||||
5. **Display Results**: Show final workflow outcome
|
||||
|
||||
### 🔧 Customization Options
|
||||
|
||||
**Modify Review Criteria:**
|
||||
```csharp
|
||||
const string ContentReviewerInstructions = @"
|
||||
You are a content reviewer...
|
||||
1. Check if content is more than 500 words (instead of 200)
|
||||
2. Verify technical accuracy
|
||||
3. Ensure proper formatting
|
||||
...";
|
||||
```
|
||||
|
||||
**Add More Conditional Paths:**
|
||||
```csharp
|
||||
var workflow = new WorkflowBuilder(draftExecutor)
|
||||
.AddEdge(draftExecutor, contentReviewerExecutor)
|
||||
.AddEdge(contentReviewerExecutor, publishExecutor, condition: GetCondition("Excellent"))
|
||||
.AddEdge(contentReviewerExecutor, editExecutor, condition: GetCondition("Good"))
|
||||
.AddEdge(contentReviewerExecutor, sendReviewerExecutor, condition: GetCondition("Poor"))
|
||||
.Build();
|
||||
```
|
||||
|
||||
**Change Content Requirements:**
|
||||
```csharp
|
||||
string OUTLINE_Content = @"
|
||||
# Your Custom Topic
|
||||
## Section 1
|
||||
https://your-reference-url
|
||||
## Section 2
|
||||
...
|
||||
";
|
||||
```
|
||||
|
||||
### 🎯 Real-World Applications
|
||||
|
||||
This conditional workflow pattern is ideal for:
|
||||
- **Content Management Systems**: Automated editorial workflows with quality gates
|
||||
- **Document Processing**: Route documents based on classification and compliance
|
||||
- **Customer Support**: Intelligent ticket routing based on complexity and urgency
|
||||
- **Legal Review**: Route contracts based on risk assessment and value
|
||||
- **HR Processes**: Route applications through appropriate screening workflows
|
||||
|
||||
### 🔍 Understanding Conditional Logic
|
||||
|
||||
**Condition Function:**
|
||||
```csharp
|
||||
public Func<object?, bool> GetCondition(string expectedResult) =>
|
||||
reviewResult => reviewResult is ReviewResult review && review.Result == expectedResult;
|
||||
```
|
||||
|
||||
This function creates a predicate that:
|
||||
1. Checks if the result is of type `ReviewResult`
|
||||
2. Compares the `Result` property to the expected value
|
||||
3. Returns true/false to determine routing
|
||||
|
||||
**Workflow Edges with Conditions:**
|
||||
```csharp
|
||||
.AddEdge(contentReviewerExecutor, publishExecutor, condition: GetCondition("Yes"))
|
||||
.AddEdge(contentReviewerExecutor, sendReviewerExecutor, condition: GetCondition("No"))
|
||||
```
|
||||
|
||||
### 📊 Advanced Features
|
||||
|
||||
**JSON Schema Validation:**
|
||||
The workflow uses JSON schemas to ensure structured responses:
|
||||
|
||||
```csharp
|
||||
// Define response structure
|
||||
public class ReviewResult
|
||||
{
|
||||
[JsonPropertyName("review_result")]
|
||||
public string Result { get; set; } = string.Empty;
|
||||
|
||||
[JsonPropertyName("reason")]
|
||||
public string Reason { get; set; } = string.Empty;
|
||||
|
||||
[JsonPropertyName("draft_content")]
|
||||
public string DraftContent { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
// Apply to agent
|
||||
ResponseFormat = ChatResponseFormat.ForJsonSchema(
|
||||
AIJsonUtilities.CreateJsonSchema(typeof(ReviewResult)),
|
||||
"ReviewResult",
|
||||
"Review Result From DraftContent"
|
||||
)
|
||||
```
|
||||
|
||||
**Bing Grounding Integration:**
|
||||
The Evangelist agent uses Bing grounding to access real-time information:
|
||||
|
||||
```csharp
|
||||
var bingGroundingConfig = new BingGroundingSearchConfiguration(bing_conn_id);
|
||||
BingGroundingToolDefinition bingGroundingTool = new(
|
||||
new BingGroundingSearchToolParameters([bingGroundingConfig])
|
||||
);
|
||||
```
|
||||
|
||||
This enables the agent to follow URLs in the outline and extract current information.
|
||||
|
||||
### 🛡️ Error Handling
|
||||
|
||||
The workflow includes robust error handling for rejected content:
|
||||
- Review failures trigger the alternative path
|
||||
- Notifications provide clear rejection reasons
|
||||
- Content is preserved for revision
|
||||
|
||||
### 🔄 Extending the Workflow
|
||||
|
||||
**Add a Revision Loop:**
|
||||
Create a feedback loop that re-drafts content automatically:
|
||||
|
||||
```csharp
|
||||
.AddEdge(contentReviewerExecutor, publishExecutor, condition: GetCondition("Yes"))
|
||||
.AddEdge(contentReviewerExecutor, draftExecutor, condition: GetCondition("No")) // Loop back
|
||||
```
|
||||
|
||||
**Implement Multi-Level Review:**
|
||||
Add multiple review stages with different criteria:
|
||||
|
||||
```csharp
|
||||
.AddEdge(draftExecutor, technicalReviewer)
|
||||
.AddEdge(technicalReviewer, editorialReviewer, condition: GetCondition("TechPass"))
|
||||
.AddEdge(editorialReviewer, publishExecutor, condition: GetCondition("EditPass"))
|
||||
```
|
||||
|
||||
This conditional workflow pattern provides the foundation for building sophisticated, intelligent enterprise automation systems! 🚀
|
||||
Reference in New Issue
Block a user