In my earlier article, “Your First AI Application in .NET: A Step-by-Step Guide“: https://wisecodes.venuthomas.in/2025/09/21/your-first-ai-application-in-net-a-step-by-step-guide/ , I explored different ways to build AI-powered solutions—including Azure OpenAI, Semantic Kernel, and custom approaches. At that time, Microsoft Agent Framework wasn’t available, it launched publicly in October 2025. These concepts gave developers a solid foundation, but each approach required mixing and matching features for context handling, extensibility, and multi-step logic.
Now, Microsoft Agent Framework (MAF) brings these capabilities together in one unified, production-grade SDK. MAF blends the strengths of Semantic Kernel and AutoGen, providing streamlined development with native context management, powerful modular workflows, deep tool integration, enterprise-grade observability, and direct support for Azure AI Foundry and GitHub Models.
This comprehensive guide will help you build your first AI agent using MAF—with clear, step-by-step code samples, commentary, and practical comparisons to Semantic Kernel.

What is Microsoft Agent Framework?
The Microsoft Agent Framework (MAF) is a unified SDK for building conversational and autonomous AI agents in .NET and Python.
It enables developers to create intelligent agents that can reason, remember, use tools, perform multi-step logic, and collaborate—all within a secure, production-ready environment.
Why a New Approach for AI Agents?
As “agents” have become a buzzword in the AI world, most tools have remained fragmented.
True agents can plan, call APIs, collaborate, and adapt, but deploying these prototypes into production has often required stitching together multiple incomplete frameworks—usually without robust observability, security, or scalability.
To solve this, Microsoft combined two of its strongest foundations:
- Semantic Kernel (SK): provided enterprise-grade connectors and orchestration.
- AutoGen: contributed advanced multi-agent reasoning and collaboration.
The result is the Microsoft Agent Framework (MAF) bringing the best of both worlds into a single, coherent platform.
Introducing Microsoft Agent Framework
MAF is a developer toolkit and runtime that allows agents to run locally, scale to the cloud, and operate reliably in production.
Think of it this way:
- Semantic Kernel gave the enterprise strength
- AutoGen gave the research-level intelligence
- MAF delivers the unified, practical solution
Core Features
- Rapid agent creation for chat or task automation
- Multi-turn conversations with persistent context and memory
- Real-time streaming of agent responses
- Workflow builder for multi-step, logic-driven tasks
- Native observability and logging for robust monitoring
- Seamless integration with Azure AI Foundry and GitHub Models
- Structured outputs and strong typing for reliable automation
- Enterprise features for security, compliance, and scalability
- https://learn.microsoft.com/en-us/agent-framework/overview/agent-framework-overview
- https://devblogs.microsoft.com/foundry/introducing-microsoft-agent-framework-the-open-source-engine-for-agentic-ai-apps/
Prerequisites
Before starting, ensure you have:
- .NET 8.0 SDK or newer installed
- Access to Azure OpenAI or GitHub Models (such as gpt-4o or gpt-4o-mini)
- Azure CLI installed and logged in using
az login
Install Dependencies
For Azure OpenAI:
dotnet add package Azure.Identity
dotnet add package Azure.AI.OpenAI
dotnet add package Microsoft.Agents.AI.OpenAI --prerelease
For GitHub Models:
dotnet add package OpenAI
dotnet add package Microsoft.Extensions.AI.OpenAI --prerelease
dotnet add package Microsoft.Extensions.AI
dotnet add package Microsoft.Agents.AI --prerelease
Simple Agent Example
Let’s create a geography agent using Azure OpenAI that answers capital city questions.
using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;
using Azure.AI.OpenAI;
using Azure.Identity;
using OpenAI;
// Step 1: Create an Azure OpenAI client using your Azure endpoint and credentials.
// This client will allow you to communicate with the GPT-4o model hosted on Azure.
AIAgent agent = new AzureOpenAIClient(
new Uri("https://your-resource.openai.azure.com"), // Replace with your Azure OpenAI endpoint
new DefaultAzureCredential() // Automatically uses credentials from 'az login' or environment
)
.GetChatClient("gpt-4o") // Specify the model deployment name (e.g., "gpt-4o")
.CreateAIAgent("You are a helpful geography expert."); // Create an agent with a system prompt
// Step 2: Send a question to the agent and print its response
Console.WriteLine("User: What's the capital of Kerala?");
var response = await agent.RunAsync("What's the capital of Kerala?");
Console.WriteLine($"Agent: {response}");
// Step 3: Ask another question and print the response
Console.WriteLine("User: What's the capital of India?");
response = await agent.RunAsync("What's the capital of India?");Multi-Turn Conversation (Stateful Context)
Agents built with MAF can maintain context across exchanges with the AgentThread class. This enables natural, contextual dialogue.
// Step 1: Create a new conversation thread to maintain context across multiple turns
var thread = agent.GetNewThread(); // This keeps track of the conversation history
// Step 2: Ask the first question
Console.WriteLine("User: What's the capital of Kerala?");
var response1 = await agent.RunAsync("What's the capital of Kerala?", thread); // Pass the thread to preserve context
Console.WriteLine($"Agent: {response1}");
// Step 3: Ask a second question in the same thread
Console.WriteLine("User: What's the capital of India?");
var response2 = await agent.RunAsync("What's the capital of India?", thread); // Still using the same thread
Console.WriteLine($"Agent: {response2}");
// Step 4: Ask a follow-up question that depends on previous answers
Console.WriteLine("User: Which has a larger population?");
var response3 = await agent.RunAsync("Which has a larger population?", thread); // Agent uses previous answers for reasoning
Console.WriteLine($"Agent: {response3}");Streaming Responses
MAF supports streaming, where agent answers appear in real time—perfect for chat UIs.
Console.WriteLine("User: What's the capital of Kerala?");
Console.Write("Agent: ");
// Stream each token as it's generated by the model
await foreach (var update in agent.RunStreamingAsync("What's the capital of Kerala?"))
{
Console.Write(update); // Print each token immediately for smoother UX
}
Interactive Console Chat
Combine streaming and state to create a conversational chatbot that maintains context:
// Step: Create a new conversation thread to maintain context across multiple turns
var thread = agent.GetNewThread();
Console.WriteLine("Geography Agent — Type your questions! ('exit' to quit)");
while (true)
{
Console.Write("You: ");
var input = Console.ReadLine();
// Exit the loop if the user types 'exit' or submits an empty line
if (string.IsNullOrWhiteSpace(input) || input.ToLower() == "exit")
break;
// Stream the agent's response in real-time for a smoother experience
Console.Write("Agent: ");
await foreach (var update in agent.RunStreamingAsync(input, thread))
{
Console.Write(update); // Print each token as it's generated
}
Console.WriteLine(); // Move to the next line after response is complete
}Workflow Builder Example
Workflows allow you to connect multiple reasoning or processing steps, where the output of one step becomes the input to the next.
This is useful for building multi-step tasks such as research pipelines, text summarization, or other automated agent workflows.
To use workflows, add this MAF package to your project:
dotnet add package Microsoft.Agents.AI.Workflows --prerelease
using Microsoft.Agents.AI;
using Azure.AI.OpenAI;
using Azure.Identity;
using Microsoft.Agents.AI.Workflows;
using OpenAI;
// Step 1: Connect to Azure OpenAI
// This sets up a client that can talk to Azure-hosted GPT models.
// DefaultAzureCredential uses your Azure login (via CLI or environment).
var agent = new AzureOpenAIClient(
new Uri("https://your-resource.openai.azure.com"), // Replace with your Azure OpenAI endpoint
new DefaultAzureCredential()
);
// Step 2: Create the first agent to find capital cities
// This agent is specialized to answer questions about Indian state capitals.
var capitalAgent = agent
.GetChatClient("gpt-4o") // Use the GPT-4o model
.CreateAIAgent(
name: "CapitalFinder", // Agent name
instructions: "You are a geography expert. Given an Indian state, return only its capital city."
);
// Step 3: Create the second agent to find population data
// This agent is focused on returning population estimates for cities.
var populationAgent = agent
.GetChatClient("gpt-4o")
.CreateAIAgent(
name: "PopulationFinder",
instructions: "You are a data expert. Given a city, return its latest estimated population."
);
// Step 4: Build a sequential workflow
// This chains the two agents so that the output of CapitalFinder becomes the input for PopulationFinder.
Workflow workflow = AgentWorkflowBuilder.BuildSequential(capitalAgent, populationAgent);
// Step 5: Convert the workflow into a single callable agent
// This wraps the workflow so you can interact with it like a normal agent.
AIAgent workflowAgent = await workflow.AsAgentAsync();
// Step 6: Run the workflow with a user prompt
// The workflow will first find the capital of Kerala, then get its population.
Console.WriteLine("User: What's the capital of Kerala and its population?");
var response = await workflowAgent.RunAsync("Find the capital of Kerala and its population.");
Console.WriteLine($"Agent: {response.Text}");Tool Integration — Example with GeographyTool
Tools enable agents to call C# methods automatically when relevant to a user’s question.
In Semantic Kernel (SK), this behavior was implemented using the [KernelFunction] attribute.
In the Microsoft Agent Framework (MAF), it’s achieved through the AIFunctionFactory.Create() API, which turns any static or instance C# method into a callable AI function.
This allows the model to invoke your business logic dynamically, without manually writing conditions or explicit function calls.
The agent decides when to use the tool based on the user’s intent and context.
using System.ComponentModel;
namespace ExampleAIProject;
public class GeographyTool
{
[Description("Retrieves the capital city name for a specified country or state.")]
[return: Description("The name of the capital city.")]
public static string GetCapital(
[Description("The country or state name.")] string location)
{
// Normalize input for consistent matching
return location.ToLower() switch
{
"india" => "New Delhi",
"kerala" => "Thiruvananthapuram",
"karnataka" => "Bengaluru",
"tamil nadu" => "Chennai",
"maharashtra" => "Mumbai",
_ => "Unknown" // Default response if location is not recognized
};
}
}Using GeographyTool with an Agent
using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;
using Azure.AI.OpenAI;
using Azure.Identity;
using ExampleAIProject; // Namespace where GeographyTool is defined
using OpenAI;
// Step 1: Connect to Azure OpenAI
// This sets up the client to communicate with GPT-4o hosted on Azure
AIAgent agent = new AzureOpenAIClient(
new Uri("https://your-resource.openai.azure.com"), // Replace with your Azure endpoint
new DefaultAzureCredential() // Uses Azure CLI credentials (az login)
)
.GetChatClient("gpt-4o") // Use GPT-4o model
.CreateAIAgent(
instructions: "You are a helpful geography expert.", // Agent's role
tools: new[] { AIFunctionFactory.Create(GeographyTool.GetCapital) } // Register the tool
);
// Step 2: Ask a question — the agent may choose to use the GeographyTool
Console.WriteLine("User: What is the capital of Kerala?");
var response1 = await agent.RunAsync("What is the capital of Kerala?");
Console.WriteLine($"Agent: {response1}");
// Step 3: Ask another question — the agent can reuse the tool
Console.WriteLine("User: What is the capital of India?");
var response2 = await agent.RunAsync("What is the capital of India?");
Console.WriteLine($"Agent: {response2}");Approval Integration — Example with GeographyTool
The ApprovalRequiredAIFunction feature in Microsoft Agent Framework adds human-in-the-loop control to AI tools.
When an agent decides to use a tool, it first pauses and requests user approval before executing it.
This ensures safer handling of sensitive or high-impact actions.
In Semantic Kernel, such approvals required custom logic; in MAF, they’re built-in through the ApprovalRequiredAIFunction wrapper,
which can be applied to any AIFunction created with AIFunctionFactory.Create().
#pragma warning disable MEAI001
using System.Text.Json;
using Azure.AI.OpenAI;
using Azure.Identity;
using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;
using ExampleAIProject;
using OpenAI;
// Step 1: Create an Azure OpenAI client.
// This connects your app to the Azure OpenAI service using Azure CLI credentials.
var client = new AzureOpenAIClient(
new Uri("https://your-resource.openai.azure.com"),
new AzureCliCredential()
).GetChatClient("gpt-4o-mini");
// Step 2: Create an AI agent.
// This agent is configured to ask for approval before using any external tools.
AIAgent agent = client.CreateAIAgent(
instructions: "You are a helpful geography assistant. You must ask for approval before calling any tools.",
tools: [new ApprovalRequiredAIFunction(AIFunctionFactory.Create(GeographyTool.GetCapital))]
);
// Step 3: Create a conversation thread to keep track of the session.
AgentThread thread = agent.GetNewThread();
// Step 4: Send the first user question.
Console.WriteLine("User: What is the capital of Kerala?");
AgentRunResponse firstResponse = await agent.RunAsync("What is the capital of Kerala?", thread);
// Step 5: Check if the agent requested approval before running the tool.
var approvalRequests = firstResponse.Messages
.SelectMany(message => message.Contents)
.OfType<FunctionApprovalRequestContent>()
.ToList();
// Step 6: Handle approval if required.
if (approvalRequests.Count > 0)
{
// The agent is asking for permission to run a function.
var approvalRequest = approvalRequests.First();
Console.WriteLine($"Agent wants to call tool: {approvalRequest.FunctionCall.Name}");
// Display arguments as readable JSON.
string argsJson = JsonSerializer.Serialize(
approvalRequest.FunctionCall.Arguments,
new JsonSerializerOptions { WriteIndented = true }
);
Console.WriteLine($"Arguments: {argsJson}");
// Ask the user for approval through the console.
Console.Write($"Do you approve executing {approvalRequest.FunctionCall.Name}? (yes/no): ");
string userInput = Console.ReadLine()?.Trim().ToLowerInvariant() ?? "";
bool approve = userInput == "yes" || userInput == "y";
// Step 7: Create a response message for the agent with the approval decision.
var approvalResponse = approvalRequest.CreateResponse(approve);
var approvalMessage = new ChatMessage(ChatRole.User, [approvalResponse]);
// Step 8: Send the approval message to the agent so it can continue.
AgentRunResponse finalResponse = await agent.RunAsync(approvalMessage, thread);
// Display the agent’s final answer.
Console.WriteLine($"Agent: {finalResponse.Text}");
}
else
{
// If no approval was requested, display the agent’s direct response.
Console.WriteLine($"Agent: {firstResponse.Text}");
}
Screenshot of output will be like this:

Structured Output
Structured output enables agents to return results as strongly typed C# objects instead of plain text.
This eliminates the need for manual JSON parsing and provides more reliable automation.
Create a model class
namespace ExampleAIProject;
// Step 1: Define a record type to represent structured data returned by the agent
public record CityInfo(string Name, string Country, int Population);using Microsoft.Agents.AI;
using Azure.AI.OpenAI;
using Azure.Identity;
using ExampleAIProject; // Namespace where CityInfo is defined
using OpenAI;
// Step 2: Connect to Azure OpenAI
// This client allows communication with the GPT-4o model hosted on Azure
var client = new AzureOpenAIClient(
new Uri("https://your-resource.openai.azure.com"), // Replace with your Azure endpoint
new DefaultAzureCredential() // Uses Azure CLI credentials (az login)
);
// Step 3: Create an agent using the GPT-4o model
// The agent is instructed to extract structured data from user input
ChatClientAgent agent = client
.GetChatClient("gpt-4o")
.CreateAIAgent(new ChatClientAgentOptions(
instructions: "You are a helpful geography expert. Extract city name, country, and population from user input."
));
// Step 4: Send a prompt and expect a structured response of type CityInfo
// The agent will parse the input and return a strongly typed object
AgentRunResponse<CityInfo> info = await agent.RunAsync<CityInfo>(
"The city of Delhi is in India and has around 35 million people."
);
// Step 5: Use the structured response in your application
// This demonstrates how structured AI output can be used directly in logic
Console.WriteLine($"Name: {info.Result.Name}, Country: {info.Result.Country}, Population: {info.Result.Population}");
More samples can be found in Microsoft’s official GitHub repository: https://github.com/microsoft/agent-framework/tree/main/dotnet/samples
If You’ve Used Semantic Kernel (SK): What’s Different, What’s Better?
Is Agent Framework the same as SK/OpenAI code?
Yes, Agent Framework is strikingly familiar in its core code structure: agent creation, maintaining stateful dialog, tool integration, and step chaining all follow the patterns introduced in Semantic Kernel and improved for clarity and scalability.
You can migrate most Semantic Kernel code directly, with only minor changes to namespaces or class names.
For migration details, review Microsoft’s official migration guide:
https://learn.microsoft.com/en-us/agent-framework/migration-guide/from-semantic-kernel/?pivots=programming-language-csharp
Major Advantages Over My Previous Approaches
- Unified, production-ready SDK without needing to blend multiple libraries or custom plugins
- Improved state management and native multi-turn context handling
- Fluid APIs for streaming and logical workflow creation
- Reduced boilerplate and more expressive, readable code
- Enterprise observability, durability, security, and compliance, ready for cloud deployment
- Streamlined migration for Semantic Kernel users—core logic remains compatible
- Full scalability and deployment support for Azure AI Foundry and other enterprise platforms
- Structured outputs and type-safe data exchanges for robust automation
All these enhancements help accelerate agentic AI development, reduce maintenance, and raise reliability—while keeping the learning curve gentle for experienced .NET developers.
Additional Agent Framework Highlights
- Function tools: Direct invocation of C# and external APIs as part of agent reasoning
- Schema-driven responses: Strongly typed outputs and validation of structured results
- Multi-agent orchestration: Build sophisticated workflows across specialized agents
- Enterprise observability: Out-of-the-box logging, tracing, and metrics
- Security and compliance: Integrated controls for privacy, auditing, and identity
- Durable workflows: Support for persistent state and human-in-the-loop handoff
Conclusion
Previously, you learned how to build AI applications using Semantic Kernel and OpenAI.
With Microsoft Agent Framework, you now gain a unified, modern SDK for building powerful, context-aware agents in .NET.
The same .NET syntax now supports multi-turn memory, native tool integration, multi-agent workflows, structured outputs, and enterprise-grade observability.
Start building intelligent, agentic applications in .NET today—and take advantage of the simplicity, extensibility, and scalability now available with Microsoft Agent Framework.