using Azure.AI.OpenAI;using Azure.Identity;using Microsoft.Agents.AI;using OpenAI.Chat;var endpoint = Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT") ?? throw new InvalidOperationException("AZURE_OPENAI_ENDPOINT is not set.");var deploymentName = Environment.GetEnvironmentVariable("AZURE_OPENAI_DEPLOYMENT_NAME") ?? "gpt-4o-mini";// WARNING: DefaultAzureCredential is convenient for development but requires careful consideration in production.// In production, consider using a specific credential (e.g., ManagedIdentityCredential) to avoid// latency issues, unintended credential probing, and potential security risks from fallback mechanisms.AIAgent agent = new AzureOpenAIClient( new Uri(endpoint), new DefaultAzureCredential()) .GetChatClient(deploymentName) .AsAIAgent(instructions: "You are good at telling jokes.", name: "Joker");// Invoke the agent and output the text resultConsole.WriteLine(await agent.RunAsync("Tell me a joke about a pirate."));
var endpoint = Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT") ?? throw new InvalidOperationException("AZURE_OPENAI_ENDPOINT is not set.");var deploymentName = Environment.GetEnvironmentVariable("AZURE_OPENAI_DEPLOYMENT_NAME") ?? "gpt-4o-mini";
Environment variables keep secrets out of source code and provide flexibility across environments.
3
Create the agent
AIAgent agent = new AzureOpenAIClient( new Uri(endpoint), new DefaultAzureCredential()) // Azure authentication .GetChatClient(deploymentName) // Get chat client for model .AsAIAgent( // Convert to AIAgent instructions: "You are good at telling jokes.", name: "Joker");
The fluent API chains: Authentication → Chat Client → AI Agent
4
Run the agent
Console.WriteLine(await agent.RunAsync("Tell me a joke about a pirate."));
RunAsync sends a message and returns the complete response as a string.
Streaming provides real-time feedback as the agent generates responses:
Program.cs
using Azure.AI.OpenAI;using Azure.Identity;using Microsoft.Agents.AI;using OpenAI.Chat;var endpoint = Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT") ?? throw new InvalidOperationException("AZURE_OPENAI_ENDPOINT is not set.");var deploymentName = Environment.GetEnvironmentVariable("AZURE_OPENAI_DEPLOYMENT_NAME") ?? "gpt-4o-mini";AIAgent agent = new AzureOpenAIClient( new Uri(endpoint), new DefaultAzureCredential()) .GetChatClient(deploymentName) .AsAIAgent(instructions: "You are good at telling jokes.", name: "Joker");// Non-streaming responseConsole.WriteLine("=== Non-Streaming ===");Console.WriteLine(await agent.RunAsync("Tell me a joke about a pirate."));Console.WriteLine();// Streaming responseConsole.WriteLine("=== Streaming ===");await foreach (var update in agent.RunStreamingAsync("Tell me a joke about a pirate.")){ Console.Write(update); // Write without newline to show progressive output}Console.WriteLine();
// Waits for complete response, then returnsstring response = await agent.RunAsync("Tell me a joke.");Console.WriteLine(response);
Use streaming for user-facing applications to provide immediate feedback. Use non-streaming for background processing or when you need the complete response before proceeding.
Tools allow agents to call functions and access external data:
Program.cs
using System.ComponentModel;using Azure.AI.OpenAI;using Azure.Identity;using Microsoft.Agents.AI;using Microsoft.Extensions.AI;using OpenAI.Chat;var endpoint = Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT") ?? throw new InvalidOperationException("AZURE_OPENAI_ENDPOINT is not set.");var deploymentName = Environment.GetEnvironmentVariable("AZURE_OPENAI_DEPLOYMENT_NAME") ?? "gpt-4o-mini";[Description("Get the weather for a given location.")]static string GetWeather([Description("The location to get the weather for.")] string location) => $"The weather in {location} is cloudy with a high of 15°C.";// Create the chat client and agent, and provide the function tool to the agentAIAgent agent = new AzureOpenAIClient( new Uri(endpoint), new DefaultAzureCredential()) .GetChatClient(deploymentName) .AsAIAgent( instructions: "You are a helpful assistant", tools: [AIFunctionFactory.Create(GetWeather)]);// Non-streaming agent interaction with function toolsConsole.WriteLine("=== Non-Streaming with Tools ===");Console.WriteLine(await agent.RunAsync("What is the weather like in Amsterdam?"));Console.WriteLine();// Streaming agent interaction with function toolsConsole.WriteLine("=== Streaming with Tools ===");await foreach (var update in agent.RunStreamingAsync("What is the weather like in Amsterdam?")){ Console.Write(update);}Console.WriteLine();
[Description("Get the weather for a given location.")]static string GetWeather( [Description("The location to get the weather for.")] string location) => $"The weather in {location} is cloudy with a high of 15°C.";
Key points:
Use [Description] attribute on the function and parameters
Descriptions help the agent understand when to call the function
Keep function names and descriptions clear and specific
2
Register the tool
using Microsoft.Extensions.AI;AIAgent agent = chatClient.AsAIAgent( instructions: "You are a helpful assistant", tools: [AIFunctionFactory.Create(GetWeather)]);
AIFunctionFactory.Create() converts your function into an AIFunction that the agent can call.
3
The agent decides when to call
When you ask “What is the weather like in Amsterdam?”, the agent:
Recognizes it needs weather information
Calls the GetWeather function with location: "Amsterdam"
Here’s a more complex tool with multiple parameters:
using System.ComponentModel;[Description("Search for flights between two cities.")]static string SearchFlights( [Description("Departure city")] string from, [Description("Destination city")] string to, [Description("Departure date in YYYY-MM-DD format")] string date){ // In a real application, this would call an API return $"Found 3 flights from {from} to {to} on {date}. Prices start at $299.";}[Description("Get the current time in a specific timezone.")]static string GetTime( [Description("Timezone (e.g., America/New_York, Europe/London)")] string timezone){ // In a real application, use TimeZoneInfo return $"Current time in {timezone}: 14:30";}AIAgent agent = new AzureOpenAIClient(new Uri(endpoint), new DefaultAzureCredential()) .GetChatClient(deploymentName) .AsAIAgent( instructions: "You are a travel assistant.", tools: [ AIFunctionFactory.Create(SearchFlights), AIFunctionFactory.Create(GetTime) ]);Console.WriteLine(await agent.RunAsync( "Find me flights from Seattle to Tokyo on 2026-04-15. What time is it there now?"));
The agent can call multiple tools in a single turn to gather all necessary information.
Use AgentSession to maintain conversation context:
Program.cs
using Azure.AI.OpenAI;using Azure.Identity;using Microsoft.Agents.AI;using OpenAI.Chat;var endpoint = Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT") ?? throw new InvalidOperationException("AZURE_OPENAI_ENDPOINT is not set.");var deploymentName = Environment.GetEnvironmentVariable("AZURE_OPENAI_DEPLOYMENT_NAME") ?? "gpt-4o-mini";AIAgent agent = new AzureOpenAIClient( new Uri(endpoint), new DefaultAzureCredential()) .GetChatClient(deploymentName) .AsAIAgent(instructions: "You are good at telling jokes.", name: "Joker");// Create a session to preserve conversation historyAgentSession session = await agent.CreateSessionAsync();Console.WriteLine("=== Turn 1 ===");Console.WriteLine(await agent.RunAsync("Tell me a joke about a pirate.", session));Console.WriteLine();Console.WriteLine("=== Turn 2 ===");Console.WriteLine(await agent.RunAsync( "Now add some emojis to the joke and tell it in the voice of a pirate's parrot.", session));Console.WriteLine();
Building conversational interfaces (chatbots, assistants)
The agent needs to remember previous interactions
You’re implementing follow-up questions or clarifications
Context from earlier messages affects later responses
Session lifecycle
// Create a new sessionAgentSession session = await agent.CreateSessionAsync();// Use the session across multiple turnsawait agent.RunAsync("First message", session);await agent.RunAsync("Follow-up question", session);// Session automatically maintains history// Dispose if needed (implements IDisposable if resources are held)
Multiple concurrent sessions
// Different users or conversationsvar userSession1 = await agent.CreateSessionAsync();var userSession2 = await agent.CreateSessionAsync();// Each session has independent historyawait agent.RunAsync("Hello, I'm Alice", userSession1);await agent.RunAsync("Hello, I'm Bob", userSession2);// Sessions don't interfere with each otherawait agent.RunAsync("What's my name?", userSession1); // "Alice"await agent.RunAsync("What's my name?", userSession2); // "Bob"
AgentSession session = await agent.CreateSessionAsync();Console.WriteLine("User: Tell me a joke about a pirate.");await foreach (var update in agent.RunStreamingAsync("Tell me a joke about a pirate.", session)){ Console.Write(update);}Console.WriteLine("\n");Console.WriteLine("User: Now make it funnier.");await foreach (var update in agent.RunStreamingAsync("Now make it funnier.", session)){ Console.Write(update);}Console.WriteLine();
Here’s a complete, production-ready weather assistant:
Program.cs
using System.ComponentModel;using Azure.AI.OpenAI;using Azure.Identity;using Microsoft.Agents.AI;using Microsoft.Extensions.AI;using OpenAI.Chat;// Configurationvar endpoint = Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT") ?? throw new InvalidOperationException("AZURE_OPENAI_ENDPOINT is not set.");var deploymentName = Environment.GetEnvironmentVariable("AZURE_OPENAI_DEPLOYMENT_NAME") ?? "gpt-4o-mini";// Tool: Get current weather[Description("Get the current weather for a location.")]static string GetWeather([Description("The city name")] string location){ // In production, call a real weather API var weatherData = new Dictionary<string, string> { ["Seattle"] = "Rainy, 12°C", ["Amsterdam"] = "Cloudy, 15°C", ["Tokyo"] = "Sunny, 22°C", ["London"] = "Foggy, 10°C" }; return weatherData.TryGetValue(location, out var weather) ? $"The weather in {location} is {weather}." : $"Weather data not available for {location}.";}// Tool: Get weather forecast[Description("Get the 3-day weather forecast for a location.")]static string GetForecast([Description("The city name")] string location){ return $"Forecast for {location}:\n" + $"Today: Partly cloudy, 15°C\n" + $"Tomorrow: Sunny, 18°C\n" + $"Day 3: Rainy, 12°C";}// Create the agent with toolsAIAgent agent = new AzureOpenAIClient( new Uri(endpoint), new DefaultAzureCredential()) .GetChatClient(deploymentName) .AsAIAgent( instructions: "You are a helpful weather assistant. Provide friendly, accurate weather information.", name: "WeatherBot", tools: [ AIFunctionFactory.Create(GetWeather), AIFunctionFactory.Create(GetForecast) ]);// Interactive conversation loopConsole.WriteLine("Weather Assistant (type 'exit' to quit)");Console.WriteLine("========================================\n");AgentSession session = await agent.CreateSessionAsync();while (true){ Console.Write("You: "); var input = Console.ReadLine(); if (string.IsNullOrWhiteSpace(input) || input.ToLower() == "exit") break; Console.Write("Assistant: "); try { await foreach (var update in agent.RunStreamingAsync(input, session)) { Console.Write(update); } Console.WriteLine("\n"); } catch (Exception ex) { Console.WriteLine($"\nError: {ex.Message}\n"); }}Console.WriteLine("Goodbye!");