Microsoft.Extensions.AI Free code examples in C#
The .NET abstraction over every chat provider — DI, middleware and telemetry included.
WHAT THIS PAGE COVERS
Swapping OpenAI for a local model by changing one registration.
gpt-5.4-mini
Microsoft.Extensions.AI
Model ids change. If a sample returns a 404 on the model, that is the first thing to check against the official docs.
Three packages: the abstractions, the middleware, and one provider. Microsoft.Extensions.AI pulls in the abstractions on its own, so applications reference it and libraries reference only the abstractions.
dotnet add package Microsoft.Extensions.AI
dotnet add package OpenAI
dotnet add package Microsoft.Extensions.AI.OpenAI --prerelease
setx OPENAI_API_KEY "sk-your-key" # Windows, then open a new shell
export OPENAI_API_KEY="sk-your-key" # macOS / Linux
AsIChatClient() is the adapter. From here nothing in your code names OpenAI — the provider is a detail of the line that built the client.
using Microsoft.Extensions.AI;
using OpenAI;
var apiKey = Environment.GetEnvironmentVariable("OPENAI_API_KEY")
?? throw new InvalidOperationException("OPENAI_API_KEY is not set.");
IChatClient client = new OpenAIClient(apiKey)
.GetChatClient("gpt-5.4-mini")
.AsIChatClient();
List<ChatMessage> history =
[
new(ChatRole.System, "You are a concise technical assistant."),
new(ChatRole.User, "Explain a database index in two sentences."),
];
ChatResponse response = await client.GetResponseAsync(history);
Console.WriteLine(response.Text);
GetStreamingResponseAsync yields ChatResponseUpdate. Append the text to your history yourself — the SDK does not close the loop for you, and forgetting it makes the model repeat itself.
history.Add(new ChatMessage(ChatRole.User, "Now explain B-trees."));
var assistant = new System.Text.StringBuilder();
await foreach (ChatResponseUpdate update in
client.GetStreamingResponseAsync(history))
{
Console.Write(update.Text);
assistant.Append(update.Text);
}
// The turn is not finished until it is back in the history.
history.Add(new ChatMessage(ChatRole.Assistant, assistant.ToString()));
UseFunctionInvocation() is the whole tool-calling loop — call, execute, feed back, call again — as one line. The stages compose like ASP.NET Core middleware, and ORDER MATTERS: telemetry outermost, so it measures everything inside it.
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Options;
using System.ComponentModel;
[Description("Gets the current stock level for a product code.")]
static int GetStock([Description("The product code")] string code) => 42;
IDistributedCache cache = new MemoryDistributedCache(
Options.Create(new MemoryDistributedCacheOptions()));
IChatClient pipeline = new ChatClientBuilder(client)
.UseDistributedCache(cache) // identical prompts cost nothing
.UseFunctionInvocation() // the tool loop, in one line
.Build();
ChatOptions options = new()
{
Tools = [AIFunctionFactory.Create(GetStock)],
};
var answer = await pipeline.GetResponseAsync(
"How many of product X-17 are in stock?", options);
Console.WriteLine(answer.Text);
In DI the whole pipeline is one registration, and swapping OpenAI for a local model is one line — which is the claim this library is built on and the reason to use it over an SDK directly.
// Program.cs
builder.Services.AddDistributedMemoryCache();
builder.Services
.AddChatClient(services => new OpenAIClient(
builder.Configuration["OPENAI_API_KEY"]!)
.GetChatClient("gpt-5.4-mini")
.AsIChatClient())
.UseDistributedCache()
.UseFunctionInvocation()
.UseOpenTelemetry(configure: o => o.EnableSensitiveData = false);
// Swapping to a local model is THIS LINE and nothing else:
// new OpenAIClient(new ApiKeyCredential("ollama"),
// new OpenAIClientOptions { Endpoint = new Uri("http://localhost:11434/v1") })
// .GetChatClient("llama3.2").AsIChatClient();
// Anywhere downstream:
app.MapPost("/ask", async (string question, IChatClient chat) =>
(await chat.GetResponseAsync(question)).Text);
QUESTIONS
Which languages are the Microsoft.Extensions.AI examples in?
C#. Every sample runs as pasted and reads its credentials from an environment variable — no key is ever written into the code.
Which package do I install for Microsoft.Extensions.AI?
The samples use Microsoft.Extensions.AI. The install step on each language tab gives the exact command.
Which Microsoft.Extensions.AI model do these examples use?
gpt-5.4-mini, checked against the official documentation on 26 September 2026. Model ids change often; if a call returns a model-not-found error, check the current list in the official docs.
Where is the official Microsoft.Extensions.AI documentation?
https://learn.microsoft.com/dotnet/ai/ — it is linked at the bottom of this page, and it is the authority whenever it disagrees with a sample here.
ALSO IN FRAMEWORKS & SDKS
The authority
Official Microsoft.Extensions.AI documentation
Model names, pricing and rate limits change faster than any page here can. When this page and the official docs disagree, the official docs are right.
https://learn.microsoft.com/dotnet/ai/