If you're building AI agents in .NET and want to run them on Microsoft's cloud infrastructure, understanding azure ai foundry agents with Microsoft Agent Framework in C# is the combination that matters. Using azure ai foundry agents with microsoft agent framework in C# gives you a clear path from model deployment to running intelligent agents in production. Azure AI Foundry provides the model deployment and management platform on the Azure side, while the Microsoft Agent Framework (MAF) -- in public preview at version 1.0.0-rc1 -- gives you a lightweight .NET SDK for turning those model endpoints into working agents. This article breaks down how these two pieces connect, which authentication path to choose for each environment, how to wire the Azure client into ASP.NET Core's DI container, and what to think about when it comes to deployment targets and cost management.
One important note upfront: MAF is in public preview (1.0.0-rc1). Everything here reflects the current RC, but APIs may shift before general availability. Check the Microsoft.Agents.AI NuGet page and the Azure AI Foundry documentation for any updates before building on it in production.
What Is Azure AI Foundry?
Azure AI Foundry is Microsoft's unified platform for discovering, deploying, and evaluating AI models in Azure. It organizes resources around a hub and project model: a hub is the organizational boundary that owns shared infrastructure, and projects live inside hubs to hold individual deployments, connection configurations, and experiment history.
The model catalog is one of Foundry's most useful features. It hosts hundreds of models -- from OpenAI's GPT-4o family to Meta's Llama, Mistral, Cohere, and Microsoft's own Phi models. You can deploy any catalog model to a managed inference endpoint, and Foundry generates the endpoint URL and API key you need to connect from code. This catalog access is a key reason to use Foundry rather than just a standalone Azure OpenAI resource: it opens up non-OpenAI model options without requiring you to manage separate services.
Foundry also includes evaluation tooling for measuring model output quality. You can run evaluation passes against deployed models to score groundedness, coherence, relevance, and safety -- which matters when you're deciding between models for a specific use case. That decision framework is separate from your agent code, which is the right separation.
Understanding what Foundry provides on the cloud side makes it easier to see what MAF expects from it on the code side. MAF doesn't depend on Foundry specifically -- it works with any Azure AI backend that can be wrapped as an IChatClient. Foundry is the recommended way to manage your Azure deployments, but from MAF's perspective, it just needs a valid endpoint URL and credentials.
How MAF Connects to Azure AI Backends
Microsoft Agent Framework is a lightweight .NET SDK built around the IChatClient interface from Microsoft.Extensions.AI. The pattern is simple: you build an IChatClient pointing at your Azure backend, then call .AsAIAgent() to get an agent. The agent code itself doesn't care whether the model is GPT-4o or Llama-3 -- that distinction lives entirely in how you configure the client.
There are two distinct client paths for Azure:
- AzureOpenAIClient (from
Azure.AI.OpenAI) -- connects to OpenAI-family models deployed through Azure OpenAI Service (GPT-4o, GPT-4o mini, o1, and similar) - ChatCompletionsClient (from
Azure.AI.Inference) -- connects to the broader Foundry model catalog, including Llama, Mistral, Cohere, and Phi models deployed as managed inference endpoints
Both paths produce an IChatClient. Once you have that, the agent construction is identical regardless of which path you took. This abstraction makes it practical to swap models without rewriting agent logic -- a principle that also applies when you're comparing different model backends with Multi-Model Support in GitHub Copilot SDK.
If you've already explored Building AI Agents with Semantic Kernel or the broader Semantic Kernel in C# complete guide, MAF will feel familiar in its goal but lighter in its footprint. Where Semantic Kernel offers a full plugin and orchestration system, MAF focuses on the agent construction layer and delegates model integration to Microsoft.Extensions.AI.
Connecting to Azure OpenAI -- Azure AI Foundry Agents with Microsoft Agent Framework in C#
The most common scenario for azure ai foundry agents is connecting to an Azure OpenAI deployment. Foundry -- or the Azure portal -- gives you an endpoint URL and a deployment name. You have two authentication options: API key or managed identity.
using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;
using Azure.AI.OpenAI;
using Azure.Core;
using Azure.Identity;
// Option 1: API key -- straightforward for local development and testing
IChatClient apiKeyClient = new AzureOpenAIClient(
new Uri("https://your-resource.openai.azure.com/"),
new ApiKeyCredential("your-api-key-here"))
.GetChatClient("gpt-4o") // use your deployment name, not the base model name
.AsIChatClient();
var agentWithKey = apiKeyClient.AsAIAgent(
instructions: "You are a helpful assistant specialized in Azure architecture.");
// Option 2: Managed Identity via DefaultAzureCredential
// Recommended for production -- no secrets stored in config files or environment variables
IChatClient managedIdentityClient = new AzureOpenAIClient(
new Uri("https://your-resource.openai.azure.com/"),
new DefaultAzureCredential())
.GetChatClient("gpt-4o")
.AsIChatClient();
var agentWithMI = managedIdentityClient.AsAIAgent(
instructions: "You are a helpful assistant specialized in Azure architecture.");
The DefaultAzureCredential path is the right choice for anything beyond local development. It chains through multiple credential sources -- managed identity when running on Azure, the Azure CLI when developing locally, and environment variables as a fallback. You don't change code between environments; you just ensure the appropriate credential is available in each context.
A common mistake worth calling out: passing the model name (like "gpt-4o") to .GetChatClient() when your Azure deployment is named something different (like "gpt4o-prod"). The string you pass here must match your deployment name in Azure, not the base model name.
Connecting to Non-OpenAI Models via Azure AI Inference
When you want to use a model from the Foundry catalog that isn't in the OpenAI family -- Llama, Mistral, Phi, Cohere, and others -- you use the Azure.AI.Inference package instead. The ChatCompletionsClient connects to the serverless or managed inference endpoint Foundry creates when you deploy from the catalog.
using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;
using Azure.AI.Inference;
using Azure;
// Azure AI Inference -- for non-OpenAI models in the Foundry catalog
// Works with Llama, Mistral, Cohere, Phi, and any catalog model
IChatClient inferenceClient = new ChatCompletionsClient(
new Uri("https://your-project.inference.ai.azure.com"),
new AzureKeyCredential("your-inference-api-key"))
.AsChatClient("meta-llama-3-70b-instruct"); // your Foundry deployment name
var llamaAgent = inferenceClient.AsAIAgent(
instructions: "You are an expert at summarizing technical documents.");
// Invoke the agent -- same API regardless of which model backs it
AgentResponse response = await llamaAgent.RunAsync(
"Summarize the following architecture document in three bullet points...");
The endpoint URL comes from your Foundry project's deployment detail page. After deploying a catalog model, Foundry generates an inference endpoint URL specific to that deployment. Copy that URL along with the API key, and the ChatCompletionsClient handles the REST protocol.
This is the pattern that makes azure ai foundry agents with microsoft agent framework in C# practical for multi-model architectures: deploy multiple models in Foundry, point different ChatCompletionsClient instances at each, wrap each with .AsAIAgent(), and let your application logic decide which agent handles which task. The agent code itself stays entirely consistent.
Azure AI Project Connections vs Direct API Keys
When you work with Foundry, you have two broad approaches to consuming your deployment configuration in application code.
Direct API keys are the simpler path. You copy the endpoint URL and API key from the Foundry deployment page, store them in Azure Key Vault or environment variables, and pass them directly to the client constructor. This works well and is easy to reason about, but it means you're managing key rotation and endpoint configuration manually across all services that consume the deployment.
Project connection strings are Foundry's way of centralizing that configuration. A project connection string looks like eastus.api.azureml.ms;{subscription-id};{resource-group};{project-name}. The intent is to let you look up named connections from code via the Azure.AI.Projects SDK, so your application references a connection name rather than a hardcoded URL.
For most teams building with MAF in the 1.0.0-rc1 release, the direct approach is more practical -- the project SDK integration is still evolving alongside the MAF preview. The connection string pattern becomes the better answer when you need to centralize endpoint configuration across multiple services or manage connections through Foundry's governance layer. Here's how to structure the environment-variable-based approach, which works cleanly whether you populate those variables from Key Vault or from a Foundry project:
using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;
using Azure.AI.OpenAI;
using Azure.Identity;
// Read endpoint and deployment from config
// Populated from Azure Key Vault, App Configuration, or environment variables
string azureOpenAIEndpoint =
Environment.GetEnvironmentVariable("AZURE_OPENAI_ENDPOINT")
?? throw new InvalidOperationException("AZURE_OPENAI_ENDPOINT is not configured");
string deploymentName =
Environment.GetEnvironmentVariable("AZURE_OPENAI_DEPLOYMENT") ?? "gpt-4o";
// DefaultAzureCredential resolves managed identity in Azure,
// Azure CLI credentials locally -- no code changes between environments
IChatClient client = new AzureOpenAIClient(
new Uri(azureOpenAIEndpoint),
new DefaultAzureCredential())
.GetChatClient(deploymentName)
.AsIChatClient();
var agent = client.AsAIAgent(
instructions: "You are a helpful agent deployed via Azure AI Foundry.");
Storing the endpoint and deployment name in environment variables (backed by Key Vault in production) keeps secrets out of code and lets you rotate or swap endpoints without redeploying application code.
Registering the Azure IChatClient with DI in ASP.NET Core
When you deploy a MAF agent inside an ASP.NET Core application, you want the Azure client and the agent both registered with the DI container. This keeps all Azure-specific wiring in one place and lets controllers and services consume IAgent without knowing anything about the underlying model or endpoint.
using Microsoft.Agents.AI;
using Microsoft.Extensions.AI;
using Azure.AI.OpenAI;
using Azure.Identity;
var builder = WebApplication.CreateBuilder(args);
// Register the Azure OpenAI IChatClient as a singleton
builder.Services.AddSingleton<IChatClient>(sp =>
{
string endpoint = builder.Configuration["AzureOpenAI:Endpoint"]
?? throw new InvalidOperationException("AzureOpenAI:Endpoint not configured");
string deployment =
builder.Configuration["AzureOpenAI:DeploymentName"] ?? "gpt-4o";
// DefaultAzureCredential: managed identity in Azure, CLI credentials locally
return new AzureOpenAIClient(
new Uri(endpoint),
new DefaultAzureCredential())
.GetChatClient(deployment)
.AsIChatClient();
});
// Register the agent -- depends only on IChatClient, not on Azure specifics
builder.Services.AddSingleton<IAIAgent>(sp =>
{
var chatClient = sp.GetRequiredService<IChatClient>();
return chatClient.AsAIAgent(
instructions: "You are an AI agent for our customer support system.");
});
var app = builder.Build();
// ... configure middleware and map routes
The DI registration owns all Azure-specific wiring. Any service that injects IAgent gets a fully configured agent without any Azure SDK knowledge leaking into business logic. For a similar DI-centered pattern applied to a full API, Build an ASP.NET Core AI Assistant API walks through a comparable approach using a different backing SDK.
For systems that need multiple specialized agents, registering additional agents via IKeyedService<IAgent, string> or a factory pattern lets you route tasks to the right agent by role. Build a Multi-Agent Analysis System covers orchestration strategies you can adapt once your agents are registered and ready.
Deploying MAF Agents to Azure
Once your agent code is ready, three main deployment targets suit different workload profiles.
Azure App Service is the simplest option for web-based agents. Package your ASP.NET Core application normally, deploy via GitHub Actions or Azure DevOps, and configure the service's managed identity in the portal. Enable system-assigned managed identity on the App Service resource, then assign the "Cognitive Services OpenAI User" role on your Azure OpenAI resource to that identity. This is the lowest-friction path from code to running agent.
Azure Container Apps gives you more control over scaling and isolation. This is a strong choice when you're running multiple agents as separate services or need per-agent scaling rules. The managed identity setup follows the same pattern -- enable it on the Container App environment and assign RBAC roles on the resources each agent needs. Container Apps also works well if you're wrapping agents in a microservices architecture where individual services need independent scaling.
Azure Functions suits event-driven agents -- those that respond to queue messages, HTTP triggers, or scheduled tasks. The Flex Consumption plan scales to zero, which is cost-effective for agents that run infrequently. The main consideration is cold start latency with larger .NET dependency trees, so keep the Function package lean. Configure DefaultAzureCredential in your Function app settings and assign the same RBAC roles you would for App Service.
Across all three targets, the principle is the same: use managed identity with DefaultAzureCredential and assign the minimum RBAC permissions your agent requires. This eliminates key rotation complexity and keeps credentials off the hosting platform entirely.
Cost Management with Azure
Token consumption is the primary cost driver for azure ai foundry agents. A few deliberate practices keep costs predictable without requiring architectural changes.
Azure Monitor metrics -- Azure OpenAI writes token usage metrics automatically. In the Azure portal, the Metrics blade on your Azure OpenAI resource shows prompt tokens, completion tokens, and total tokens broken down by deployment. You can build dashboards here or export to Log Analytics for richer querying across multiple deployments.
Budget alerts -- Azure Cost Management lets you set spending thresholds with notification rules. Setting alerts at 80% and 100% of your monthly budget gives early warning before costs become a problem. This is especially important during development, when it's easy to accidentally trigger expensive loops.
Model selection tradeoffs -- GPT-4o is more capable but costs more per token than GPT-4o mini or the Phi family. For high-volume, lower-stakes tasks -- classification, extraction, structured summarization -- routing to a cheaper model via a second IChatClient registration can cut costs significantly without meaningful quality loss. The multi-model approach explored in Multi-Model Support in GitHub Copilot SDK applies equally here.
Deployment quotas -- Foundry lets you cap tokens-per-minute (TPM) on individual deployments. This rate limit protects you from runaway costs if an agent loop misbehaves. Setting a TPM quota that reflects expected production volume plus a reasonable buffer is a straightforward safeguard.
Tool definition overhead -- agents that use tool-calling include tool manifests in every prompt, which adds tokens per request. Keep tool descriptions concise and only register tools that a given agent actually needs. Custom AI Tools with AIFunctionFactory covers tool design patterns where token efficiency is equally relevant.
Azure AI Evaluation -- What Foundry Brings to the Table
Azure AI Foundry includes a built-in evaluation framework that sits on top of your deployed models. From the Foundry portal or via the azure-ai-evaluation SDK, you can run evaluation passes that score model outputs against a test dataset using metrics like groundedness, coherence, relevance, and safety.
The practical value here is in model selection decisions. When you're choosing between two models from the catalog -- say, GPT-4o mini versus a Llama variant -- running the same test dataset through both and comparing evaluation scores gives you an objective basis for the decision. Gut feel and published benchmarks rarely reflect real workload performance as well as evaluation on your own data does.
MAF itself doesn't add evaluation-specific APIs in the current preview. Evaluation happens at the Azure deployment level, not the agent SDK level. You evaluate the model, then wire the chosen deployment into your MAF agent. This separation is intentional and likely to hold as MAF moves toward GA.
For teams building retrieval-augmented agents, Foundry's evaluation tooling pairs naturally with Azure AI Search. Semantic Kernel Vector Store covers integrating Azure AI Search into a .NET AI stack, and Build a Semantic Search Engine with Semantic Kernel shows how to combine vector search with language model calls -- both patterns remain relevant even when MAF provides the agent layer.
Evaluating the Approach
The azure ai foundry agents with Microsoft Agent Framework in C# approach reflects a clear division of responsibilities. Foundry manages the cloud side -- model catalog, deployment endpoints, evaluation, and quota management. MAF manages the .NET side -- IChatClient abstraction, agent construction, and the call interface your application code uses. Neither tries to own the other's domain, and that's a healthy design.
Where this combination stands out is flexibility. Swapping between an OpenAI model and a catalog model, adding managed identity for production, or moving from App Service to Container Apps all involve changes at the configuration and infrastructure layer -- not in the agent logic itself. For teams where model choices and infrastructure details are expected to evolve, that separation is valuable.
The preview status of MAF is the main factor to weigh before committing. Building on a 1.0.0-rc1 package for production workloads is reasonable if your team can absorb API changes before GA. If stability is a hard requirement, the Semantic Kernel in C# complete guide covers a production-ready orchestration approach on the same Azure backends. Evaluate which option fits your release timeline and tolerance for preview-stage churn.
Frequently Asked Questions
What is Azure AI Foundry and how does it relate to MAF?
Azure AI Foundry is Microsoft's unified platform for deploying and evaluating AI models in Azure. It provides the hub-and-project resource model, a catalog of hundreds of models, managed deployment endpoints, and evaluation tooling. MAF (Microsoft Agent Framework) is the .NET SDK that turns those endpoints into agents in C# code. MAF doesn't require Foundry -- it works with any Azure AI backend that exposes a compatible interface -- but Foundry is the recommended way to manage and govern your Azure deployments at scale.
Do I need an Azure AI Foundry project to use MAF with Azure?
No. You can connect MAF to a plain Azure OpenAI resource without creating a Foundry project. A Foundry project adds value through the model catalog (for non-OpenAI models), centralized connection management, and evaluation tooling. If you're only working with Azure OpenAI deployments, a Foundry project isn't strictly required -- you just need the endpoint URL and credentials from the Azure portal.
What is the difference between AzureOpenAIClient and ChatCompletionsClient in MAF?
AzureOpenAIClient (from Azure.AI.OpenAI) targets OpenAI-family models deployed through Azure OpenAI Service -- GPT-4o, GPT-4o mini, o1, and similar. ChatCompletionsClient (from Azure.AI.Inference) supports the broader Azure AI model catalog, including Llama, Mistral, Cohere, and Phi models deployed as Foundry inference endpoints. Both produce an IChatClient that MAF wraps with .AsAIAgent(), so the agent code is identical regardless of which client you used.
How do I use managed identity instead of an API key for a MAF agent?
Replace new ApiKeyCredential(...) with new DefaultAzureCredential() in your client constructor. In the Azure portal, enable system-assigned managed identity on your hosting resource (App Service, Container App, or Function), then grant that identity the "Cognitive Services OpenAI User" role on your Azure OpenAI resource. DefaultAzureCredential automatically detects and uses the managed identity when running in Azure, and falls back to Azure CLI credentials or environment variables during local development.
Is MAF stable enough for production use with Azure AI Foundry?
MAF is in public preview at version 1.0.0-rc1, so APIs may change before general availability. It is technically usable in production environments, but teams should be prepared to absorb breaking changes before GA. The underlying Azure AI backends -- Azure OpenAI and Azure AI Inference -- are production-stable regardless of MAF's preview status. Weigh the preview risk against your team's capacity to adapt before committing to MAF for critical workloads.
How do I monitor token costs for an azure ai foundry agents deployment?
Azure OpenAI writes token usage metrics to Azure Monitor automatically. In the Azure portal, navigate to your Azure OpenAI resource and open the Metrics blade to view prompt tokens, completion tokens, and total tokens per deployment. Set up budget alerts in Azure Cost Management to receive notifications before spending hits a defined threshold. For application-level telemetry, integrate Application Insights into your ASP.NET Core or Azure Functions app to correlate token usage with specific user sessions or request paths.
Can I use multiple models with different MAF agents in the same application?
Yes. Register multiple IChatClient instances in DI -- each pointing at a different Azure deployment -- and wrap each with .AsAIAgent(). Use IKeyedService<IAgent, string> or a factory pattern to distinguish agents by role or task type. This lets you route high-stakes tasks to a more capable model while handling routine tasks with a lighter, lower-cost model -- all within the same application and without changing the business logic that calls the agents.

