In module T1 you set up a local model and asked it questions with small file-based apps. Now the Kladde gets its own access to language models. It should do three things: Today it talks to the model on your machine, and later, without a code change, to a model in the cloud. It can be tested without a model. And if it’s set up wrong, you notice at startup and not at a user’s first click.
The tool for this is Microsoft.Extensions.AI, a Microsoft library with one common interface for many providers. In this module you
learn its core: the IChatClient in this lesson, streamed responses in the next, structured responses after that, and finally the
middleware that measures every call. The examples ran with these packages:
| Package | Version |
|---|---|
Microsoft.Extensions.AI |
10.11.0 |
Microsoft.Extensions.AI.OpenAI |
10.11.0 |
OpenAI |
2.15.0 |
Microsoft.Extensions.Configuration.Binder, Microsoft.Extensions.Hosting, and in the tests Microsoft.Extensions.Configuration and Microsoft.Extensions.DependencyInjection |
10.0.14 |
Azure.Identity (only for the cloud part) |
1.21.0 |
xunit.v3.mtp-v2 |
4.0.2 |
One interface for all models
Every provider of language models has its own library with its own classes. If you program directly against one of them, you rewrite your code as soon as you change providers, and it’s hard to test. So Microsoft.Extensions.AI puts a layer in between. It has three parts:
Microsoft.Extensions.AI.Abstractionscontains the interfaces and the data types:IChatClient,ChatMessage,ChatRole,ChatOptions,ChatResponse. You write your code against these types.Microsoft.Extensions.AIbrings everything that builds on the interface: registration in the container, structured responses, and the middleware for logging, telemetry and caching. It pulls in the abstractions.- One package per provider translates between the interface and the provider’s library. For everything that speaks OpenAI’s
interface, that’s
Microsoft.Extensions.AI.OpenAI. It turns a client from theOpenAIlibrary into anIChatClientwithAsIChatClient().
The interface itself is small. It has two methods you ask with and two for housekeeping:
GetResponseAsyncsends messages and waits for the whole answer.GetStreamingResponseAsyncsends the same messages and delivers the answer in pieces as they’re produced (next lesson).GetServiceasks for services that stand behind the client, for example for its metadata.Disposereleases what the client holds.
Everything else, including GetResponseAsync("a question") with a plain text, is an extension method around these four.