chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,168 @@
|
||||
#!/usr/bin/dotnet run
|
||||
|
||||
#:package Microsoft.Extensions.AI@10.*
|
||||
#:package Microsoft.Agents.AI.OpenAI@1.*-*
|
||||
#:package Azure.AI.OpenAI@2.1.0
|
||||
#:package Azure.Identity@1.13.1
|
||||
|
||||
using System.ComponentModel;
|
||||
|
||||
using Microsoft.Agents.AI;
|
||||
using Microsoft.Extensions.AI;
|
||||
|
||||
using Azure.AI.OpenAI;
|
||||
using Azure.Identity;
|
||||
|
||||
// ============================================================================
|
||||
// AGENTIC DESIGN PRINCIPLES DEMONSTRATION
|
||||
// ============================================================================
|
||||
// This sample demonstrates the three key design principles from the lesson:
|
||||
// 1. TRANSPARENCY: The agent explains what it's doing and why
|
||||
// 2. CONTROL: Users can customize preferences and the agent respects them
|
||||
// 3. CONSISTENCY: The agent uses a predictable, standardized interaction pattern
|
||||
// ============================================================================
|
||||
|
||||
// Tool Function: Random Destination Generator
|
||||
// TRANSPARENCY: Clear description helps users understand this tool's purpose
|
||||
[Description("Provides a random vacation destination. Returns a city and country.")]
|
||||
static string GetRandomDestination()
|
||||
{
|
||||
var destinations = new List<string>
|
||||
{
|
||||
"Paris, France",
|
||||
"Tokyo, Japan",
|
||||
"New York City, USA",
|
||||
"Sydney, Australia",
|
||||
"Rome, Italy",
|
||||
"Barcelona, Spain",
|
||||
"Cape Town, South Africa",
|
||||
"Rio de Janeiro, Brazil",
|
||||
"Bangkok, Thailand",
|
||||
"Vancouver, Canada"
|
||||
};
|
||||
|
||||
var random = new Random();
|
||||
int index = random.Next(destinations.Count);
|
||||
return destinations[index];
|
||||
}
|
||||
|
||||
// Tool Function: User Preference Storage (Demonstrates CONTROL principle)
|
||||
// CONTROL: This tool allows users to set and manage their preferences
|
||||
[Description("Saves user preferences for trip planning. Use this when the user specifies preferences like budget level (budget/moderate/luxury), trip style (adventure/relaxation/cultural), or duration preference.")]
|
||||
static string SaveUserPreference(
|
||||
[Description("The type of preference being saved, e.g., 'budget', 'style', 'duration'")] string preferenceType,
|
||||
[Description("The value of the preference")] string preferenceValue)
|
||||
{
|
||||
// In a real application, this would persist to a database
|
||||
Console.WriteLine($"\n[TRANSPARENCY] Saving preference: {preferenceType} = {preferenceValue}");
|
||||
return $"Preference saved: {preferenceType} is now set to '{preferenceValue}'. I will remember this for future suggestions.";
|
||||
}
|
||||
|
||||
// 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());
|
||||
|
||||
// Agent Identity
|
||||
var AGENT_NAME = "TravelAgent";
|
||||
|
||||
// ============================================================================
|
||||
// AGENT INSTRUCTIONS - Demonstrating Design Principles
|
||||
// ============================================================================
|
||||
// These instructions embed the three design principles directly into the agent's behavior
|
||||
var AGENT_INSTRUCTIONS = """
|
||||
You are a helpful AI Agent that demonstrates the Agentic Design Principles.
|
||||
|
||||
## Your Core Principles
|
||||
|
||||
**TRANSPARENCY**: Always explain what you're doing and why.
|
||||
- When using a tool, briefly explain which tool you're calling and why
|
||||
- Share your reasoning process with the user
|
||||
- Be honest about limitations or uncertainties
|
||||
|
||||
**CONTROL**: Respect user preferences and allow customization.
|
||||
- Ask about preferences before making assumptions
|
||||
- Use the SaveUserPreference tool to remember user choices
|
||||
- Always prioritize explicit user requests over defaults
|
||||
|
||||
**CONSISTENCY**: Use a predictable, standardized interaction pattern.
|
||||
- Start every conversation with a friendly greeting
|
||||
- Structure responses in a clear, organized format
|
||||
- Use similar phrasing for similar actions
|
||||
|
||||
## Initial Greeting (CONSISTENCY)
|
||||
|
||||
When the conversation begins, always introduce yourself with this message:
|
||||
"Hello! I'm TravelAgent, your AI vacation planning assistant.
|
||||
|
||||
🔍 **Transparency**: I'll always explain my reasoning and the tools I use.
|
||||
🎮 **Control**: Tell me your preferences, and I'll remember them.
|
||||
🔄 **Consistency**: I follow a predictable pattern to make planning easy.
|
||||
|
||||
What kind of trip would you like me to help you plan today?"
|
||||
|
||||
## Guidelines
|
||||
- When users specify a destination, plan for that location
|
||||
- Only suggest random destinations when the user hasn't specified one
|
||||
- Always confirm before making changes to preferences
|
||||
""";
|
||||
|
||||
// Create AI Agent with Design Principles
|
||||
AIAgent agent = azureClient
|
||||
.GetOpenAIResponseClient(deployment)
|
||||
.CreateAIAgent(
|
||||
name: AGENT_NAME,
|
||||
instructions: AGENT_INSTRUCTIONS,
|
||||
tools: [
|
||||
AIFunctionFactory.Create(GetRandomDestination),
|
||||
AIFunctionFactory.Create(SaveUserPreference)
|
||||
]
|
||||
);
|
||||
|
||||
// Create Conversation Session for Context Management
|
||||
await using var session = await agent.CreateSessionAsync();
|
||||
|
||||
// ============================================================================
|
||||
// DEMONSTRATION: Start with "Hello" to trigger the greeting (Issue #402 fix)
|
||||
// ============================================================================
|
||||
Console.WriteLine("=== Demonstrating Agentic Design Principles ===\n");
|
||||
Console.WriteLine("User: Hello\n");
|
||||
Console.WriteLine("Agent Response:");
|
||||
|
||||
await foreach (var update in agent.RunStreamingAsync("Hello", session))
|
||||
{
|
||||
await Task.Delay(10);
|
||||
Console.Write(update);
|
||||
}
|
||||
|
||||
Console.WriteLine("\n");
|
||||
|
||||
// ============================================================================
|
||||
// DEMONSTRATION: User sets a preference (CONTROL principle)
|
||||
// ============================================================================
|
||||
Console.WriteLine("---");
|
||||
Console.WriteLine("User: I prefer luxury travel and cultural experiences.\n");
|
||||
Console.WriteLine("Agent Response:");
|
||||
|
||||
await foreach (var update in agent.RunStreamingAsync("I prefer luxury travel and cultural experiences.", session))
|
||||
{
|
||||
await Task.Delay(10);
|
||||
Console.Write(update);
|
||||
}
|
||||
|
||||
Console.WriteLine("\n");
|
||||
|
||||
// ============================================================================
|
||||
// DEMONSTRATION: Agent uses tools with transparency
|
||||
// ============================================================================
|
||||
Console.WriteLine("---");
|
||||
Console.WriteLine("User: Suggest a destination for me.\n");
|
||||
Console.WriteLine("Agent Response:");
|
||||
|
||||
await foreach (var update in agent.RunStreamingAsync("Suggest a destination for me.", session))
|
||||
{
|
||||
await Task.Delay(10);
|
||||
Console.Write(update);
|
||||
}
|
||||
@@ -0,0 +1,281 @@
|
||||
# 🎨 Agentic Design Patterns with Azure OpenAI (Responses API) (.NET)
|
||||
|
||||
## 📋 Learning Objectives
|
||||
|
||||
This example demonstrates enterprise-grade design patterns for building intelligent agents using the Microsoft Agent Framework in .NET with Azure OpenAI (Responses API) integration. You'll learn professional patterns and architectural approaches that make agents production-ready, maintainable, and scalable.
|
||||
|
||||
### Enterprise Design Patterns
|
||||
|
||||
- 🏭 **Factory Pattern**: Standardized agent creation with dependency injection
|
||||
- 🔧 **Builder Pattern**: Fluent agent configuration and setup
|
||||
- 🧵 **Thread-Safe Patterns**: Concurrent conversation management
|
||||
- 📋 **Repository Pattern**: Organized tool and capability management
|
||||
|
||||
## 🎯 .NET-Specific Architectural Benefits
|
||||
|
||||
### Enterprise Features
|
||||
|
||||
- **Strong Typing**: Compile-time validation and IntelliSense support
|
||||
- **Dependency Injection**: Built-in DI container integration
|
||||
- **Configuration Management**: IConfiguration and Options patterns
|
||||
- **Async/Await**: First-class asynchronous programming support
|
||||
|
||||
### Production-Ready Patterns
|
||||
|
||||
- **Logging Integration**: ILogger and structured logging support
|
||||
- **Health Checks**: Built-in monitoring and diagnostics
|
||||
- **Configuration Validation**: Strong typing with data annotations
|
||||
- **Error Handling**: Structured exception management
|
||||
|
||||
## 🔧 Technical Architecture
|
||||
|
||||
### Core .NET Components
|
||||
|
||||
- **Microsoft.Extensions.AI**: Unified AI service abstractions
|
||||
- **Microsoft.Agents.AI**: Enterprise agent orchestration framework
|
||||
- **Azure OpenAI (Responses API)**: High-performance API client patterns
|
||||
- **Configuration System**: appsettings.json and environment integration
|
||||
|
||||
### Design Pattern Implementation
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
A[IServiceCollection] --> B[Agent Builder]
|
||||
B --> C[Configuration]
|
||||
C --> D[Tool Registry]
|
||||
D --> E[AI Agent]
|
||||
```
|
||||
|
||||
## 🏗️ Enterprise Patterns Demonstrated
|
||||
|
||||
### 1. **Creational Patterns**
|
||||
|
||||
- **Agent Factory**: Centralized agent creation with consistent configuration
|
||||
- **Builder Pattern**: Fluent API for complex agent configuration
|
||||
- **Singleton Pattern**: Shared resources and configuration management
|
||||
- **Dependency Injection**: Loose coupling and testability
|
||||
|
||||
### 2. **Behavioral Patterns**
|
||||
|
||||
- **Strategy Pattern**: Interchangeable tool execution strategies
|
||||
- **Command Pattern**: Encapsulated agent operations with undo/redo
|
||||
- **Observer Pattern**: Event-driven agent lifecycle management
|
||||
- **Template Method**: Standardized agent execution workflows
|
||||
|
||||
### 3. **Structural Patterns**
|
||||
|
||||
- **Adapter Pattern**: Azure OpenAI (Responses API) integration layer
|
||||
- **Decorator Pattern**: Agent capability enhancement
|
||||
- **Facade Pattern**: Simplified agent interaction interfaces
|
||||
- **Proxy Pattern**: Lazy loading and caching for performance
|
||||
|
||||
## 📚 .NET Design Principles
|
||||
|
||||
### SOLID Principles
|
||||
|
||||
- **Single Responsibility**: Each component has one clear purpose
|
||||
- **Open/Closed**: Extensible without modification
|
||||
- **Liskov Substitution**: Interface-based tool implementations
|
||||
- **Interface Segregation**: Focused, cohesive interfaces
|
||||
- **Dependency Inversion**: Depend on abstractions, not concretions
|
||||
|
||||
### Clean Architecture
|
||||
|
||||
- **Domain Layer**: Core agent and tool abstractions
|
||||
- **Application Layer**: Agent orchestration and workflows
|
||||
- **Infrastructure Layer**: Azure OpenAI (Responses API) integration and external services
|
||||
- **Presentation Layer**: User interaction and response formatting
|
||||
|
||||
## 🔒 Enterprise Considerations
|
||||
|
||||
### Security
|
||||
|
||||
- **Credential Management**: Secure API key handling with IConfiguration
|
||||
- **Input Validation**: Strong typing and data annotation validation
|
||||
- **Output Sanitization**: Secure response processing and filtering
|
||||
- **Audit Logging**: Comprehensive operation tracking
|
||||
|
||||
### Performance
|
||||
|
||||
- **Async Patterns**: Non-blocking I/O operations
|
||||
- **Connection Pooling**: Efficient HTTP client management
|
||||
- **Caching**: Response caching for improved performance
|
||||
- **Resource Management**: Proper disposal and cleanup patterns
|
||||
|
||||
### Scalability
|
||||
|
||||
- **Thread Safety**: Concurrent agent execution support
|
||||
- **Resource Pooling**: Efficient resource utilization
|
||||
- **Load Management**: Rate limiting and backpressure handling
|
||||
- **Monitoring**: Performance metrics and health checks
|
||||
|
||||
## 🚀 Production Deployment
|
||||
|
||||
- **Configuration Management**: Environment-specific settings
|
||||
- **Logging Strategy**: Structured logging with correlation IDs
|
||||
- **Error Handling**: Global exception handling with proper recovery
|
||||
- **Monitoring**: Application insights and performance counters
|
||||
- **Testing**: Unit tests, integration tests, and load testing patterns
|
||||
|
||||
Ready to build enterprise-grade intelligent agents with .NET? Let's architect something robust! 🏢✨
|
||||
|
||||
## 🚀 Getting Started
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- [.NET 10 SDK](https://dotnet.microsoft.com/download/dotnet/10.0) or higher
|
||||
- An [Azure subscription](https://azure.microsoft.com/free/) with an Azure OpenAI resource and a model deployment
|
||||
- The [Azure CLI](https://learn.microsoft.com/cli/azure/install-azure-cli) — sign in with `az login`
|
||||
|
||||
### Required Environment Variables
|
||||
|
||||
```bash
|
||||
# zsh/bash
|
||||
export AZURE_OPENAI_ENDPOINT=https://<your-resource>.openai.azure.com
|
||||
export AZURE_OPENAI_DEPLOYMENT=gpt-4o-mini
|
||||
# Then sign in so AzureCliCredential can get a token
|
||||
az login
|
||||
```
|
||||
|
||||
```powershell
|
||||
# PowerShell
|
||||
$env:AZURE_OPENAI_ENDPOINT = "https://<your-resource>.openai.azure.com"
|
||||
$env:AZURE_OPENAI_DEPLOYMENT = "gpt-4o-mini"
|
||||
# Then sign in so AzureCliCredential can get a token
|
||||
az login
|
||||
```
|
||||
|
||||
### Sample Code
|
||||
|
||||
To run the code example,
|
||||
|
||||
```bash
|
||||
# zsh/bash
|
||||
chmod +x ./03-dotnet-agent-framework.cs
|
||||
./03-dotnet-agent-framework.cs
|
||||
```
|
||||
|
||||
Or using the dotnet CLI:
|
||||
|
||||
```bash
|
||||
dotnet run ./03-dotnet-agent-framework.cs
|
||||
```
|
||||
|
||||
See [`03-dotnet-agent-framework.cs`](./03-dotnet-agent-framework.cs) for the complete code.
|
||||
|
||||
```csharp
|
||||
#!/usr/bin/dotnet run
|
||||
|
||||
#:package Microsoft.Extensions.AI@10.*
|
||||
#:package Microsoft.Agents.AI.OpenAI@1.*-*
|
||||
#:package Azure.AI.OpenAI@2.1.0
|
||||
#:package Azure.Identity@1.13.1
|
||||
|
||||
using System.ComponentModel;
|
||||
|
||||
using Microsoft.Agents.AI;
|
||||
using Microsoft.Extensions.AI;
|
||||
|
||||
using Azure.AI.OpenAI;
|
||||
using Azure.Identity;
|
||||
|
||||
// Tool Function: Random Destination Generator
|
||||
// This static method will be available to the agent as a callable tool
|
||||
// The [Description] attribute helps the AI understand when to use this function
|
||||
// This demonstrates how to create custom tools for AI agents
|
||||
[Description("Provides a random vacation destination.")]
|
||||
static string GetRandomDestination()
|
||||
{
|
||||
// List of popular vacation destinations around the world
|
||||
// The agent will randomly select from these options
|
||||
var destinations = new List<string>
|
||||
{
|
||||
"Paris, France",
|
||||
"Tokyo, Japan",
|
||||
"New York City, USA",
|
||||
"Sydney, Australia",
|
||||
"Rome, Italy",
|
||||
"Barcelona, Spain",
|
||||
"Cape Town, South Africa",
|
||||
"Rio de Janeiro, Brazil",
|
||||
"Bangkok, Thailand",
|
||||
"Vancouver, Canada"
|
||||
};
|
||||
|
||||
// Generate random index and return selected destination
|
||||
// Uses System.Random for simple random selection
|
||||
var random = new Random();
|
||||
int index = random.Next(destinations.Count);
|
||||
return destinations[index];
|
||||
}
|
||||
|
||||
// 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 Agent Identity and Comprehensive Instructions
|
||||
// Agent name for identification and logging purposes
|
||||
var AGENT_NAME = "TravelAgent";
|
||||
|
||||
// Detailed instructions that define the agent's personality, capabilities, and behavior
|
||||
// This system prompt shapes how the agent responds and interacts with users
|
||||
var AGENT_INSTRUCTIONS = """
|
||||
You are a helpful AI Agent that can help plan vacations for customers.
|
||||
|
||||
Important: When users specify a destination, always plan for that location. Only suggest random destinations when the user hasn't specified a preference.
|
||||
|
||||
When the conversation begins, introduce yourself with this message:
|
||||
"Hello! I'm your TravelAgent assistant. I can help plan vacations and suggest interesting destinations for you. Here are some things you can ask me:
|
||||
1. Plan a day trip to a specific location
|
||||
2. Suggest a random vacation destination
|
||||
3. Find destinations with specific features (beaches, mountains, historical sites, etc.)
|
||||
4. Plan an alternative trip if you don't like my first suggestion
|
||||
|
||||
What kind of trip would you like me to help you plan today?"
|
||||
|
||||
Always prioritize user preferences. If they mention a specific destination like "Bali" or "Paris," focus your planning on that location rather than suggesting alternatives.
|
||||
""";
|
||||
|
||||
// Create AI Agent with Advanced Travel Planning Capabilities
|
||||
// Get the Responses client for the deployment and create the AI agent
|
||||
// Configure agent with name, detailed instructions, and available tools
|
||||
// This demonstrates the .NET agent creation pattern with full configuration
|
||||
AIAgent agent = azureClient
|
||||
.GetOpenAIResponseClient(deployment)
|
||||
.CreateAIAgent(
|
||||
name: AGENT_NAME,
|
||||
instructions: AGENT_INSTRUCTIONS,
|
||||
tools: [AIFunctionFactory.Create(GetRandomDestination)]
|
||||
);
|
||||
|
||||
// Create New Conversation Thread for Context Management
|
||||
// Initialize a new conversation thread to maintain context across multiple interactions
|
||||
// Threads enable the agent to remember previous exchanges and maintain conversational state
|
||||
// This is essential for multi-turn conversations and contextual understanding
|
||||
AgentThread thread = agent.GetNewThread();
|
||||
|
||||
// Execute Agent: First Travel Planning Request
|
||||
// Run the agent with an initial request that will likely trigger the random destination tool
|
||||
// The agent will analyze the request, use the GetRandomDestination tool, and create an itinerary
|
||||
// Using the thread parameter maintains conversation context for subsequent interactions
|
||||
await foreach (var update in agent.RunStreamingAsync("Plan me a day trip", thread))
|
||||
{
|
||||
await Task.Delay(10);
|
||||
Console.Write(update);
|
||||
}
|
||||
|
||||
Console.WriteLine();
|
||||
|
||||
// Execute Agent: Follow-up Request with Context Awareness
|
||||
// Demonstrate contextual conversation by referencing the previous response
|
||||
// The agent remembers the previous destination suggestion and will provide an alternative
|
||||
// This showcases the power of conversation threads and contextual understanding in .NET agents
|
||||
await foreach (var update in agent.RunStreamingAsync("I don't like that destination. Plan me another vacation.", thread))
|
||||
{
|
||||
await Task.Delay(10);
|
||||
Console.Write(update);
|
||||
}
|
||||
```
|
||||
@@ -0,0 +1,323 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "lesson-intro",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Lesson 03 - Agentic Design Patterns\n",
|
||||
"\n",
|
||||
"In this lesson, we explore three foundational design patterns for building effective AI agents:\n",
|
||||
"\n",
|
||||
"1. **Clear Agent Instructions** — Crafting precise, role-defining prompts that guide agent behavior\n",
|
||||
"2. **Structured Output with Pydantic Models** — Ensuring agents return predictable, validated data\n",
|
||||
"3. **Single Responsibility Agents** — Designing focused agents that each do one thing well\n",
|
||||
"\n",
|
||||
"We'll apply each pattern to a **travel destination recommender** scenario, progressively building a system that can suggest destinations, check availability, and handle logistics."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "setup-header",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Setup"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "setup-code",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%pip install agent-framework azure-ai-projects azure-identity pydantic python-dotenv --quiet"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "imports",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"import logging\n",
|
||||
"logging.getLogger(\"agent_framework.foundry\").setLevel(logging.ERROR)\n",
|
||||
"\n",
|
||||
"import os\n",
|
||||
"import asyncio\n",
|
||||
"import dotenv\n",
|
||||
"from typing import Annotated\n",
|
||||
"from pydantic import BaseModel\n",
|
||||
"from agent_framework import tool\n",
|
||||
"from agent_framework.foundry import FoundryChatClient\n",
|
||||
"from azure.identity import DefaultAzureCredential\n",
|
||||
"\n",
|
||||
"dotenv.load_dotenv(dotenv.find_dotenv())\n",
|
||||
"\n",
|
||||
"endpoint = os.getenv(\"AZURE_AI_PROJECT_ENDPOINT\")\n",
|
||||
"deployment_name = os.getenv(\"AZURE_AI_MODEL_DEPLOYMENT_NAME\")\n",
|
||||
"\n",
|
||||
"missing = [k for k, v in {\n",
|
||||
" \"AZURE_AI_PROJECT_ENDPOINT\": endpoint,\n",
|
||||
" \"AZURE_AI_MODEL_DEPLOYMENT_NAME\": deployment_name\n",
|
||||
"}.items() if not v]\n",
|
||||
"\n",
|
||||
"if missing:\n",
|
||||
" raise ValueError(\n",
|
||||
" f\"Missing required environment variables: {', '.join(missing)}. \"\n",
|
||||
" \"Please set them as environment variables (e.g., in your .env file or shell environment).\"\n",
|
||||
" )\n",
|
||||
"\n",
|
||||
"provider = FoundryChatClient(\n",
|
||||
" project_endpoint=endpoint,\n",
|
||||
" model=deployment_name,\n",
|
||||
" credential=DefaultAzureCredential()\n",
|
||||
")"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "pattern1-header",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Pattern 1: Clear Agent Instructions\n",
|
||||
"\n",
|
||||
"The most impactful pattern is also the simplest: writing clear, detailed instructions for your agent.\n",
|
||||
"\n",
|
||||
"Good instructions define:\n",
|
||||
"- **Who** the agent is (persona and tone)\n",
|
||||
"- **What** it should do (step-by-step responsibilities)\n",
|
||||
"- **How** it should behave (constraints and style)\n",
|
||||
"\n",
|
||||
"Below, we create a travel concierge agent with explicit instructions that shape every response it produces."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "pattern1-code",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"agent = provider.as_agent(\n",
|
||||
" name=\"TravelConcierge\",\n",
|
||||
" instructions=\"\"\"You are a luxury travel concierge named Alex. Your role is to:\n",
|
||||
"1. Understand the traveler's preferences (budget, climate, activities)\n",
|
||||
"2. Check destination availability before making recommendations\n",
|
||||
"3. Provide detailed, personalized travel suggestions\n",
|
||||
"4. Always mention visa requirements and best travel seasons\n",
|
||||
"Be warm, professional, and enthusiastic about travel.\"\"\",\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"response = await agent.run(\n",
|
||||
" \"I'd love a week-long vacation somewhere with great food and history. Budget around $2500.\"\n",
|
||||
")\n",
|
||||
"print(response)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "pattern2-header",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Pattern 2: Structured Output with Pydantic Models\n",
|
||||
"\n",
|
||||
"Free-form text is useful for conversation, but downstream systems need structured data.\n",
|
||||
"By pairing **Pydantic models** with a **tool function**, we can:\n",
|
||||
"\n",
|
||||
"- Define an exact schema for the agent's output\n",
|
||||
"- Validate responses automatically\n",
|
||||
"- Integrate agent results into application logic reliably\n",
|
||||
"\n",
|
||||
"The key to enforcement is passing `response_format` when we run the agent. This forces the\n",
|
||||
"model to return a validated `TravelRecommendations` object (available on `response.value`)\n",
|
||||
"instead of free-form text. The `get_destination_details` tool also returns a typed\n",
|
||||
"`DestinationRecommendation`, so the data stays structured end to end.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "pattern2-code",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"class DestinationRecommendation(BaseModel):\n",
|
||||
" destination: str\n",
|
||||
" available: bool\n",
|
||||
" best_season: str\n",
|
||||
" highlights: list[str]\n",
|
||||
" estimated_budget_usd: int\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"class TravelRecommendations(BaseModel):\n",
|
||||
" recommendations: list[DestinationRecommendation]\n",
|
||||
" personalized_note: str\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"@tool(approval_mode=\"never_require\")\n",
|
||||
"def get_destination_details(\n",
|
||||
" destination: Annotated[str, \"The destination to look up\"]\n",
|
||||
") -> DestinationRecommendation:\n",
|
||||
" \"\"\"Get structured details about a vacation destination.\"\"\"\n",
|
||||
" details = {\n",
|
||||
" \"Barcelona\": DestinationRecommendation(\n",
|
||||
" destination=\"Barcelona\",\n",
|
||||
" available=True,\n",
|
||||
" best_season=\"May-Jun\",\n",
|
||||
" highlights=[\"Beach\", \"Architecture\", \"Nightlife\"],\n",
|
||||
" estimated_budget_usd=2000,\n",
|
||||
" ),\n",
|
||||
" \"Tokyo\": DestinationRecommendation(\n",
|
||||
" destination=\"Tokyo\",\n",
|
||||
" available=True,\n",
|
||||
" best_season=\"Mar-Apr\",\n",
|
||||
" highlights=[\"Culture\", \"Food\", \"Technology\"],\n",
|
||||
" estimated_budget_usd=2500,\n",
|
||||
" ),\n",
|
||||
" \"Cape Town\": DestinationRecommendation(\n",
|
||||
" destination=\"Cape Town\",\n",
|
||||
" available=False,\n",
|
||||
" best_season=\"Nov-Mar\",\n",
|
||||
" highlights=[\"Nature\", \"Wine\", \"Adventure\"],\n",
|
||||
" estimated_budget_usd=1800,\n",
|
||||
" ),\n",
|
||||
" }\n",
|
||||
" return details.get(\n",
|
||||
" destination,\n",
|
||||
" DestinationRecommendation(\n",
|
||||
" destination=destination,\n",
|
||||
" available=False,\n",
|
||||
" best_season=\"Unknown\",\n",
|
||||
" highlights=[],\n",
|
||||
" estimated_budget_usd=0,\n",
|
||||
" ),\n",
|
||||
" )\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"structured_agent = provider.as_agent(\n",
|
||||
" name=\"StructuredTravelExpert\",\n",
|
||||
" instructions=\"You are a travel expert. Recommend destinations based on traveler preferences. Use the get_destination_details tool.\",\n",
|
||||
" tools=[get_destination_details],\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"# Passing `response_format` forces the agent to return a validated\n",
|
||||
"# TravelRecommendations object instead of free-form text.\n",
|
||||
"response = await structured_agent.run(\n",
|
||||
" \"Recommend 3 destinations for a culture-loving traveler with a $2500 budget\",\n",
|
||||
" options={\"response_format\": TravelRecommendations},\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"if response and response.value:\n",
|
||||
" result: TravelRecommendations = response.value\n",
|
||||
" for rec in result.recommendations:\n",
|
||||
" status = \"Available\" if rec.available else \"Not available\"\n",
|
||||
" print(f\"{rec.destination} ({status})\")\n",
|
||||
" print(f\" Best season: {rec.best_season}\")\n",
|
||||
" print(f\" Highlights: {', '.join(rec.highlights)}\")\n",
|
||||
" print(f\" Estimated budget: ${rec.estimated_budget_usd}\")\n",
|
||||
" print()\n",
|
||||
" print(f\"Note: {result.personalized_note}\")\n",
|
||||
"else:\n",
|
||||
" print(\"No validated structured response was returned.\")\n",
|
||||
" print(response)\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "pattern3-header",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Pattern 3: Single Responsibility Agents\n",
|
||||
"\n",
|
||||
"Complex tasks benefit from splitting work across multiple focused agents, each with a single responsibility:\n",
|
||||
"\n",
|
||||
"- A **Destination Expert** that knows about places and availability\n",
|
||||
"- A **Logistics Planner** that handles flights, hotels, and itineraries\n",
|
||||
"\n",
|
||||
"This mirrors the software engineering principle of *separation of concerns* — each agent is easier to test, maintain, and improve independently."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"id": "pattern3-code",
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"destination_agent = provider.as_agent(\n",
|
||||
" name=\"DestinationExpert\",\n",
|
||||
" tools=[get_destination_details],\n",
|
||||
" instructions=\"\"\"You are a destination research specialist. Your only job is to:\n",
|
||||
"1. Evaluate destinations based on traveler preferences\n",
|
||||
"2. Check availability using the provided tool\n",
|
||||
"3. Return a short ranked list with pros/cons\n",
|
||||
"Do NOT discuss flights, hotels, or logistics — another agent handles that.\"\"\",\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"logistics_agent = provider.as_agent(\n",
|
||||
" name=\"LogisticsPlanner\",\n",
|
||||
" instructions=\"\"\"You are a travel logistics planner. Your only job is to:\n",
|
||||
"1. Create a day-by-day itinerary for the chosen destination\n",
|
||||
"2. Suggest flight and hotel options within the stated budget\n",
|
||||
"3. Note visa requirements and travel insurance recommendations\n",
|
||||
"Do NOT recommend destinations — another agent handles that.\"\"\",\n",
|
||||
")\n",
|
||||
"\n",
|
||||
"# Step 1: Destination Expert picks the best options\n",
|
||||
"dest_response = await destination_agent.run(\n",
|
||||
" \"I want a week of culture and food for under $2500. Where should I go?\"\n",
|
||||
")\n",
|
||||
"print(\"=== Destination Expert ===\")\n",
|
||||
"print(dest_response)\n",
|
||||
"\n",
|
||||
"# Step 2: Logistics Planner builds the trip plan\n",
|
||||
"logistics_response = await logistics_agent.run(\n",
|
||||
" f\"Plan a week-long trip based on this recommendation:\\n{dest_response}\"\n",
|
||||
")\n",
|
||||
"print(\"\\n=== Logistics Planner ===\")\n",
|
||||
"print(logistics_response)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"id": "summary",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"## Summary\n",
|
||||
"\n",
|
||||
"In this lesson we applied three agentic design patterns to a travel recommender scenario:\n",
|
||||
"\n",
|
||||
"| Pattern | Key Idea | Benefit |\n",
|
||||
"|---|---|---|\n",
|
||||
"| **Clear Instructions** | Define persona, responsibilities, and constraints up front | Consistent, on-brand agent behavior |\n",
|
||||
"| **Structured Output** | Use Pydantic models as the response format | Validated, machine-readable results |\n",
|
||||
"| **Single Responsibility** | Give each agent one focused job | Easier to test, maintain, and compose |\n",
|
||||
"\n",
|
||||
"These patterns compose naturally — you can combine clear instructions with structured output inside a single-responsibility agent to build robust, production-ready systems."
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3",
|
||||
"language": "python",
|
||||
"name": "python3"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.12.13"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 5
|
||||
}
|
||||
Reference in New Issue
Block a user