.NETMicrosoft.Extensions.AIC#Architecture

Microsoft.Extensions.AI: The .NET AI Abstraction, Explained

Microsoft.Extensions.AI gives .NET one common interface for every AI provider. What IChatClient and IEmbeddingGenerator are, why they matter, and how to use them.

If you’ve read other guides on this site, one type keeps appearing: IChatClient. It comes from Microsoft.Extensions.AI, and it’s arguably the most important building block in the .NET AI stack — the layer that stops you from coupling your app to a single AI vendor. This article explains what it is and why it matters.

The problem it solves

Without an abstraction, calling OpenAI, Azure OpenAI, Claude, Gemini, or a local model each means a different client, different method names, and vendor-specific types threaded through your code. Switching providers — or A/B testing two — becomes a rewrite. That’s the problem Microsoft.Extensions.AI removes.

The two core interfaces

Microsoft.Extensions.AI defines provider-agnostic interfaces, the same way Microsoft.Extensions.Logging gave .NET one logging API over many providers:

  • IChatClient — send messages, get responses (streaming or not), with tools and structured output. Every chat provider implements it.
  • IEmbeddingGenerator — turn text into embedding vectors, provider-agnostically.

Your code depends on the interface; a provider package supplies the implementation.

What using it looks like

// Your code only knows about IChatClient — not which vendor is behind it.
IChatClient chat = /* injected: OpenAI, Azure, Claude, Gemini, or Ollama */;

var response = await chat.GetResponseAsync("Explain CQRS in two sentences.");
Console.WriteLine(response);

// Streaming works the same way, regardless of provider:
await foreach (var update in chat.GetStreamingResponseAsync("Now give an example."))
    Console.Write(update);

Swap the provider in one place (usually your DI registration) and everything downstream is unchanged.

Why it’s a big deal

  • No vendor lock-in. Switch models with a config change, not a refactor.
  • Easy benchmarking. Run the same code against several providers and compare on your eval set (choosing a model).
  • Testability. Substitute a fake IChatClient in unit tests — no real API calls, fast and free.
  • Middleware. Because it’s an interface, you can wrap it: add caching, logging, telemetry, or rate-limiting as decorators around any provider.
  • It’s the foundation. The Microsoft Agent Framework and most .NET AI tooling build on these interfaces — learn them once, use them everywhere.

Middleware in practice

The decorator pattern is where it shines. Want to cache responses, add OpenTelemetry observability, or enforce a rate limit? You wrap the IChatClient in a pipeline — the same idea as ASP.NET Core middleware — so those concerns are provider-independent and composable.

Note: method names (GetResponseAsync, GetStreamingResponseAsync) are still stabilizing; verify against the current .NET AI docs. The design — provider-agnostic interfaces with pluggable implementations and middleware — is the durable core of .NET’s AI story.

Takeaway

Microsoft.Extensions.AI is to AI providers what Microsoft.Extensions.Logging is to loggers: one interface, many implementations. Depend on IChatClient and IEmbeddingGenerator, and you get no vendor lock-in, trivial provider swapping and benchmarking, easy testing, and composable middleware for caching, telemetry, and rate-limiting. It’s the layer that makes every other .NET AI decision reversible — which is exactly why it shows up in nearly every guide here.


Have a correction or a topic you want covered? Email mani.bc72@gmail.com.