Mesterséges intelligencia a .NET-ben (előzetes verzió)
A mesterséges intelligencia (AI) egyre több szolgáltatása érhető el, így a fejlesztőknek módot kell biztosítaniuk arra, hogy integrálják és használják ezeket a szolgáltatásokat a .NET-alkalmazásaikban. A Microsoft.Extensions.AI
kódtár egységes megközelítést biztosít a generatív AI-összetevők ábrázolására, amely zökkenőmentes integrációt és együttműködést tesz lehetővé a különböző AI-szolgáltatásokkal. Ez a cikk bemutatja a kódtárat, és telepítési utasításokat és használati példákat tartalmaz az első lépésekhez.
A csomag telepítése
A 📦 Microsoft.Extensions.AI NuGet-csomag telepítéséhez használja a .NET CLI-t, vagy adjon hozzá egy csomaghivatkozást közvetlenül a C#-projektfájlhoz:
dotnet add package Microsoft.Extensions.AI --prerelease
További információ: dotnet add package vagy Csomagfüggőségek kezelése .NET alkalmazásokban.
Használati példák
A IChatClient felület egy ügyfél absztrakciót határoz meg, amely a csevegési képességeket biztosító AI-szolgáltatásokkal való interakcióért felel. Ez magában foglalja a több modális tartalommal (például szöveggel, képpel és hanggal) rendelkező üzenetek küldésének és fogadásának módszereit, akár teljes készletként, akár növekményesen streamelve. Emellett metaadat-információkat is biztosít az ügyfélről, és lehetővé teszi az erősen gépelt szolgáltatások lekérését.
Fontos
További használati példák és valós forgatókönyvek: AI .NET-fejlesztőknek.
Ebben a szakaszban
A IChatClient
felület
Az alábbi minta IChatClient
valósít meg az általános struktúra megjelenítéséhez.
using System.Runtime.CompilerServices;
using Microsoft.Extensions.AI;
public sealed class SampleChatClient(Uri endpoint, string modelId) : IChatClient
{
public ChatClientMetadata Metadata { get; } = new(nameof(SampleChatClient), endpoint, modelId);
public async Task<ChatCompletion> CompleteAsync(
IList<ChatMessage> chatMessages,
ChatOptions? options = null,
CancellationToken cancellationToken = default)
{
// Simulate some operation.
await Task.Delay(300, cancellationToken);
// Return a sample chat completion response randomly.
string[] responses =
[
"This is the first sample response.",
"Here is another example of a response message.",
"This is yet another response message."
];
return new([new ChatMessage()
{
Role = ChatRole.Assistant,
Text = responses[Random.Shared.Next(responses.Length)],
}]);
}
public async IAsyncEnumerable<StreamingChatCompletionUpdate> CompleteStreamingAsync(
IList<ChatMessage> chatMessages,
ChatOptions? options = null,
[EnumeratorCancellation] CancellationToken cancellationToken = default)
{
// Simulate streaming by yielding messages one by one.
string[] words = ["This ", "is ", "the ", "response ", "for ", "the ", "request."];
foreach (string word in words)
{
// Simulate some operation.
await Task.Delay(100, cancellationToken);
// Yield the next message in the response.
yield return new StreamingChatCompletionUpdate
{
Role = ChatRole.Assistant,
Text = word,
};
}
}
public object? GetService(Type serviceType, object? serviceKey) => this;
public TService? GetService<TService>(object? key = null)
where TService : class => this as TService;
void IDisposable.Dispose() { }
}
A IChatClient
egyéb konkrét implementációit a következő NuGet-csomagokban találja:
- 📦 Microsoft.Extensions.AI.AzureAIInference: Implementáció, amelyet a Azure AI Model Inference APItámogat.
- 📦 Microsoft.Extensions.AI.Ollama: Az implementáció, amelyet Ollamatámogat.
- 📦 Microsoft.Extensions.AI.OpenAI: Az Implementációt OpenAI vagy OpenAI-kompatibilis végpontok (például Azure OpenAI) támogatja.
Csevegés befejezésének kérése
A befejezés kéréséhez hívja meg a IChatClient.CompleteAsync metódust. A kérés egy vagy több üzenetből áll, amelyek mindegyike egy vagy több tartalomból áll. A gyorsító módszerek a gyakori esetek egyszerűsítése érdekében léteznek, például egyetlen szöveges tartalomra vonatkozó kérelem létrehozására.
using Microsoft.Extensions.AI;
IChatClient client = new SampleChatClient(
new Uri("http://coolsite.ai"), "target-ai-model");
var response = await client.CompleteAsync("What is AI?");
Console.WriteLine(response.Message);
Az alapvető IChatClient.CompleteAsync
metódus elfogadja az üzenetek listáját. Ez a lista a beszélgetés részét képező összes üzenet előzményeit jelöli.
using Microsoft.Extensions.AI;
IChatClient client = new SampleChatClient(
new Uri("http://coolsite.ai"), "target-ai-model");
Console.WriteLine(await client.CompleteAsync(
[
new(ChatRole.System, "You are a helpful AI assistant"),
new(ChatRole.User, "What is AI?"),
]));
Az előzmények minden üzenetét egy ChatMessage objektum jelöli. A ChatMessage
osztály egy ChatMessage.Role tulajdonságot biztosít, amely az üzenet szerepét jelzi. Alapértelmezés szerint a ChatRole.User van használatban. A következő szerepkörök érhetők el:
- ChatRole.Assistant: Utasítja vagy beállítja az asszisztens viselkedését.
- ChatRole.System: Választ ad a rendszer által utasított, felhasználó által megkérdezett bemenetre.
- ChatRole.Tool: További információkat és hivatkozásokat biztosít a csevegés befejezéséhez.
- ChatRole.User: Bemenetet biztosít a csevegés befejezéséhez.
A rendszer minden chatüzenetet példányosít azáltal, hogy új Contents-et rendel hozzá a TextContent tulajdonsághoz. Különböző tartalomtípusokat lehet ábrázolni, például egy egyszerű sztringet vagy egy összetettebb objektumot, amely szöveggel, képekkel és hanggal ellátott, több modális üzenetet jelöl:
- AudioContent
- DataContent
- FunctionCallContent
- FunctionResultContent
- ImageContent
- TextContent
- UsageContent
Csevegés befejezésének kérése streameléssel
A IChatClient.CompleteStreamingAsync bemenetei megegyeznek a CompleteAsync
bemenetével. Ahelyett azonban, hogy a teljes választ egy ChatCompletion objektum részeként adja vissza, a metódus egy olyan IAsyncEnumerable<T> ad vissza, amelyben T
StreamingChatCompletionUpdate, és egy olyan frissítési adatfolyamot biztosít, amely együttesen alkotja az egyetlen választ.
using Microsoft.Extensions.AI;
IChatClient client = new SampleChatClient(
new Uri("http://coolsite.ai"), "target-ai-model");
await foreach (var update in client.CompleteStreamingAsync("What is AI?"))
{
Console.Write(update);
}
Borravaló
A streamelési API-k szinte szinonimák az AI felhasználói élményével. A C# IAsyncEnumerable<T>
támogatásával lenyűgöző forgatókönyveket tesz lehetővé, így természetes és hatékony módon streamelheti az adatokat.
Eszközhívási funkció
Egyes modellek és szolgáltatások támogatják az eszközök használatát, ahol a kérések olyan eszközöket is tartalmazhatnak, amelyekkel a modell funkciókat hívhat meg további információk megszerzéséhez. A végső válasz küldése helyett a modell függvényhívást kér adott argumentumokkal. Az ügyfél ezután meghívja a függvényt, és visszaküldi az eredményeket a modellnek a beszélgetési előzményekkel együtt. A Microsoft.Extensions.AI
kódtár absztrakciókat tartalmaz a különböző üzenettartalmakhoz, beleértve a függvényhívási kérelmeket és az eredményeket. Bár a felhasználók közvetlenül is kezelhetik ezt a tartalmat, Microsoft.Extensions.AI
automatizálják ezeket az interakciókat, és a következőkre szolgálnak:
- AIFunction: Egy AI-szolgáltatásnak leírható és meghívható függvényt jelöl.
-
AIFunctionFactory: Gyári metódusokat biztosít a
AIFunction
gyakran használt implementációinak létrehozásához. -
FunctionInvokingChatClient: Egy
IChatClient
körbefuttatása automatikus függvényhívási képességek hozzáadásához.
Vegye figyelembe az alábbi példát, amely egy véletlenszerű függvényhívást mutat be:
using System.ComponentModel;
using Microsoft.Extensions.AI;
[Description("Gets the current weather")]
string GetCurrentWeather() => Random.Shared.NextDouble() > 0.5
? "It's sunny"
: "It's raining";
IChatClient client = new ChatClientBuilder(
new OllamaChatClient(new Uri("http://localhost:11434"), "llama3.1"))
.UseFunctionInvocation()
.Build();
var response = client.CompleteStreamingAsync(
"Should I wear a rain coat?",
new() { Tools = [AIFunctionFactory.Create(GetCurrentWeather)] });
await foreach (var update in response)
{
Console.Write(update);
}
A megelőző példa a 📦 Microsoft.Extensions.AI.Ollama NuGet-csomagtól függ.
Az előző kód:
- Egy
GetCurrentWeather
nevű függvényt definiál, amely véletlenszerű időjárás-előrejelzést ad vissza.- Ezt a függvényt egy DescriptionAttributedíszíti, amely a függvény leírásának megadására szolgál az AI-szolgáltatás számára.
- Létrehoz egy ChatClientBuilder-t egy OllamaChatClient-gyel, és konfigurálja a függvényhívás használatára.
- Meghívja
CompleteStreamingAsync
az ügyfélen, és átad egy parancssort és egy olyan eszközlistát, amely tartalmazza a Createáltal létrehozott függvényt. - Átfut a válaszon, és az egyes frissítéseket a konzolra nyomtatja.
Gyorsítótár-válaszok
Ha ismeri a .NET-IChatClient
, amely egy másik IChatClient
tetszőleges példánya köré rétegezi a gyorsítótárazást. Ha egy egyedi csevegési előzményt küld a DistributedCachingChatClient
-hoz, továbbítja azt a mögöttes ügyfélnek, majd gyorsítótárazza a választ, mielőtt visszaküldené a felhasználónak. Amikor legközelebb ugyanazt a kérést küldi el, úgy, hogy a gyorsítótárban megtalálható a tárolt válasz, a DistributedCachingChatClient
a tárolt választ adja vissza, ahelyett hogy a kérést végig kellene küldenie a folyamaton.
using Microsoft.Extensions.AI;
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Options;
var sampleChatClient = new SampleChatClient(
new Uri("http://coolsite.ai"), "target-ai-model");
IChatClient client = new ChatClientBuilder(sampleChatClient)
.UseDistributedCache(new MemoryDistributedCache(
Options.Create(new MemoryDistributedCacheOptions())))
.Build();
string[] prompts = ["What is AI?", "What is .NET?", "What is AI?"];
foreach (var prompt in prompts)
{
await foreach (var update in client.CompleteStreamingAsync(prompt))
{
Console.Write(update);
}
Console.WriteLine();
}
Az előző példa a Microsoft.Extensions.Caching.Memory NuGet-csomag
Telemetria használata
Egy másik példa a delegáló csevegőalkalmazásra a OpenTelemetryChatClient. Ez a megvalósítás megfelel a generatív mesterséges intelligencia rendszerek OpenTelemetry szemantikai konvencióinak. A többi IChatClient
delegálóhoz hasonlóan a metrikákat és spanokat rétegezi az alapul szolgáló IChatClient
implementáció köré, ami fokozott megfigyelhetőséget biztosít.
using Microsoft.Extensions.AI;
using OpenTelemetry.Trace;
// Configure OpenTelemetry exporter
var sourceName = Guid.NewGuid().ToString();
var tracerProvider = OpenTelemetry.Sdk.CreateTracerProviderBuilder()
.AddSource(sourceName)
.AddConsoleExporter()
.Build();
var sampleChatClient = new SampleChatClient(
new Uri("http://coolsite.ai"), "target-ai-model");
IChatClient client = new ChatClientBuilder(sampleChatClient)
.UseOpenTelemetry(
sourceName: sourceName,
configure: static c => c.EnableSensitiveData = true)
.Build();
Console.WriteLine((await client.CompleteAsync("What is AI?")).Message);
Az előző példa az 📦 OpenTelemetry.Exporter.Console NuGet-csomagtól függ.
Beállítások megadása
A CompleteAsync vagy CompleteStreamingAsync hívásai opcionálisan megadhatnak egy ChatOptions példányt, amely további paramétereket tartalmaz a művelethez. Az AI-modellek és -szolgáltatások leggyakoribb paraméterei erősen beírt tulajdonságokként jelennek meg a típuson, például ChatOptions.Temperature. Más paramétereket a ChatOptions.AdditionalProperties szótáron keresztül, név alapján, gyengén gépelt módon lehet megadni.
Opciókat is megadhat a IChatClient
létrehozásakor a fluent ChatClientBuilder API-val és amikor láncolja a hívást a ConfigureOptions
bővítménymetódushoz. Ez a delegált ügyfél egy másik ügyfelet burkol, és meghívja a megadott meghatalmazottat, hogy minden híváshoz feltöltsön egy ChatOptions
-példányt. Ha például azt szeretné, hogy a ChatOptions.ModelId tulajdonság alapértelmezés szerint egy adott modellnév legyen, az alábbihoz hasonló kódot használhat:
using Microsoft.Extensions.AI;
IChatClient client = new ChatClientBuilder(
new OllamaChatClient(new Uri("http://localhost:11434")))
.ConfigureOptions(options => options.ModelId ??= "phi3")
.Build();
// will request "phi3"
Console.WriteLine(await client.CompleteAsync("What is AI?"));
// will request "llama3.1"
Console.WriteLine(await client.CompleteAsync(
"What is AI?", new() { ModelId = "llama3.1" }));
A megelőző példa a 📦 Microsoft.Extensions.AI.Ollama NuGet-csomagtól függ.
Funkcionalitási csővezetékek
IChatClient
példányok rétegezhetők az összetevők láncának létrehozásához, amelyek mindegyike adott funkciókat ad hozzá. Ezek az összetevők Microsoft.Extensions.AI
, más NuGet-csomagokból vagy egyéni implementációkból származhatnak. Ez a megközelítés lehetővé teszi, hogy a IChatClient
viselkedését különböző módokon bővítse az ön igényeinek megfelelően. Tekintse meg az alábbi példakódot, amely elosztott gyorsítótárat, függvényhívást és OpenTelemetry-nyomkövetést rétegez egy minta csevegőügyfél köré:
using Microsoft.Extensions.AI;
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Options;
using OpenTelemetry.Trace;
// Configure OpenTelemetry exporter
var sourceName = Guid.NewGuid().ToString();
var tracerProvider = OpenTelemetry.Sdk.CreateTracerProviderBuilder()
.AddSource(sourceName)
.AddConsoleExporter()
.Build();
// Explore changing the order of the intermediate "Use" calls to see that impact
// that has on what gets cached, traced, etc.
IChatClient client = new ChatClientBuilder(
new OllamaChatClient(new Uri("http://localhost:11434"), "llama3.1"))
.UseDistributedCache(new MemoryDistributedCache(
Options.Create(new MemoryDistributedCacheOptions())))
.UseFunctionInvocation()
.UseOpenTelemetry(
sourceName: sourceName,
configure: static c => c.EnableSensitiveData = true)
.Build();
ChatOptions options = new()
{
Tools =
[
AIFunctionFactory.Create(
() => Random.Shared.NextDouble() > 0.5 ? "It's sunny" : "It's raining",
name: "GetCurrentWeather",
description: "Gets the current weather")
]
};
for (int i = 0; i < 3; ++i)
{
List<ChatMessage> history =
[
new ChatMessage(ChatRole.System, "You are a helpful AI assistant"),
new ChatMessage(ChatRole.User, "Do I need an umbrella?")
];
Console.WriteLine(await client.CompleteAsync(history, options));
}
Az előző példa a következő NuGet-csomagoktól függ:
- 📦 Microsoft.Extensions.Caching.Memory
- 📦 Microsoft.Extensions.AI.Ollama
- 📦 OpenTelemetry.Exporter.Console
Egyéni IChatClient
közbenső szoftver
További funkciók hozzáadásához közvetlenül implementálhatja IChatClient
, vagy használhatja a DelegatingChatClient osztályt. Ez az osztály olyan csevegési ügyfelek létrehozására szolgál, amelyek műveleteket delegálnak egy másik IChatClient
-példányba. Leegyszerűsíti a több ügyfél láncolását, így a hívások továbbítva lesznek egy mögöttes ügyfélnek.
A DelegatingChatClient
osztály alapértelmezett implementációkat biztosít olyan metódusokhoz, mint a CompleteAsync
, a CompleteStreamingAsync
és a Dispose
, amelyek a belső ügyfélnek továbbítják a hívásokat. Ebből az osztályból származhat, és csak azokat a metódusokat bírálhatja felül, amelyekre szüksége van a viselkedés javításához, miközben más hívásokat delegál az alap implementációba. Ez a megközelítés segít rugalmas és moduláris csevegési ügyfeleket létrehozni, amelyek könnyen bővíthetőek és összeállíthatók.
Az alábbi példaosztály a DelegatingChatClient
-ból van származtatva, hogy terheléskorlátozó funkciókat biztosítson, a RateLimiterfelhasználásával.
using Microsoft.Extensions.AI;
using System.Runtime.CompilerServices;
using System.Threading.RateLimiting;
public sealed class RateLimitingChatClient(
IChatClient innerClient, RateLimiter rateLimiter)
: DelegatingChatClient(innerClient)
{
public override async Task<ChatCompletion> CompleteAsync(
IList<ChatMessage> chatMessages,
ChatOptions? options = null,
CancellationToken cancellationToken = default)
{
using var lease = await rateLimiter.AcquireAsync(permitCount: 1, cancellationToken)
.ConfigureAwait(false);
if (!lease.IsAcquired)
{
throw new InvalidOperationException("Unable to acquire lease.");
}
return await base.CompleteAsync(chatMessages, options, cancellationToken)
.ConfigureAwait(false);
}
public override async IAsyncEnumerable<StreamingChatCompletionUpdate> CompleteStreamingAsync(
IList<ChatMessage> chatMessages,
ChatOptions? options = null,
[EnumeratorCancellation] CancellationToken cancellationToken = default)
{
using var lease = await rateLimiter.AcquireAsync(permitCount: 1, cancellationToken)
.ConfigureAwait(false);
if (!lease.IsAcquired)
{
throw new InvalidOperationException("Unable to acquire lease.");
}
await foreach (var update in base.CompleteStreamingAsync(chatMessages, options, cancellationToken)
.ConfigureAwait(false))
{
yield return update;
}
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
rateLimiter.Dispose();
}
base.Dispose(disposing);
}
}
Az előző példa a 📦 System.Threading.RateLimiting NuGet-csomagon alapszik. A RateLimitingChatClient
kombinációja egy másik ügyféllel egyszerű:
using Microsoft.Extensions.AI;
using System.Threading.RateLimiting;
var client = new RateLimitingChatClient(
new SampleChatClient(new Uri("http://localhost"), "test"),
new ConcurrencyLimiter(new()
{
PermitLimit = 1,
QueueLimit = int.MaxValue
}));
await client.CompleteAsync("What color is the sky?");
Az ilyen összetevők másokkal való összetételének egyszerűsítése érdekében az összetevő-szerzőknek létre kell hozniuk egy Use*
bővítménymetódust az összetevő folyamatba való regisztrálásához. Vegyük például a következő bővítménymetódust:
namespace Example.One;
// <one>
using Microsoft.Extensions.AI;
using System.Threading.RateLimiting;
public static class RateLimitingChatClientExtensions
{
public static ChatClientBuilder UseRateLimiting(
this ChatClientBuilder builder, RateLimiter rateLimiter) =>
builder.Use(innerClient => new RateLimitingChatClient(innerClient, rateLimiter));
}
// </one>
Az ilyen bővítmények a DI-tárolóból is lekérdezhetik a releváns szolgáltatásokat; a csővezeték által használt IServiceProvider opcionális paraméterként kerül átadásra.
namespace Example.Two;
// <two>
using Microsoft.Extensions.AI;
using Microsoft.Extensions.DependencyInjection;
using System.Threading.RateLimiting;
public static class RateLimitingChatClientExtensions
{
public static ChatClientBuilder UseRateLimiting(
this ChatClientBuilder builder, RateLimiter? rateLimiter = null) =>
builder.Use((innerClient, services) =>
new RateLimitingChatClient(
innerClient,
rateLimiter ?? services.GetRequiredService<RateLimiter>()));
}
// </two>
A fogyasztó ezután egyszerűen használhatja ezt a csővezetékben, például:
using Microsoft.Extensions.AI;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
var builder = Host.CreateApplicationBuilder(args);
builder.Services.AddChatClient(services =>
new SampleChatClient(new Uri("http://localhost"), "test")
.AsBuilder()
.UseDistributedCache()
.UseRateLimiting()
.UseOpenTelemetry()
.Build(services));
using var app = builder.Build();
// Elsewhere in the app
var chatClient = app.Services.GetRequiredService<IChatClient>();
Console.WriteLine(await chatClient.CompleteAsync("What is AI?"));
app.Run();
Ez a példa bemutatja a fogadott forgatókönyv, ahol a fogyasztó a függőségi injekcióra támaszkodik a RateLimiter
példány biztosítása érdekében. Az előző bővítménymetódusok bemutatják egy Use
metódus használatát ChatClientBuilder-n. A ChatClientBuilder
Use túlterheléseket is biztosít, amelyek megkönnyítik az ilyen delegáló kezelők írását.
- Use(AnonymousDelegatingChatClient+CompleteSharedFunc)
- Use(Func<IChatClient,IChatClient>)
- Use(Func<IChatClient,IServiceProvider,IChatClient>)
- Use(Func<IList<ChatMessage>,ChatOptions,IChatClient,CancellationToken, Task<ChatCompletion>>, Func<IList<ChatMessage>,ChatOptions,IChatClient, CancellationToken,IAsyncEnumerable<StreamingChatCompletionUpdate>>)
A korábbi RateLimitingChatClient
példában például a CompleteAsync
és CompleteStreamingAsync
felülbírálásainak csak a folyamat következő ügyfélére való delegálás előtt és után kell működnie. Ha ugyanazt szeretné elérni anélkül, hogy egyéni osztályt írna, használhatja a Use
túlterhelését, amely elfogad egy delegáltat, amely mind a CompleteAsync
, mind a CompleteStreamingAsync
számára használatos, a szükséges sablonkódot csökkentve.
using Microsoft.Extensions.AI;
using System.Threading.RateLimiting;
RateLimiter rateLimiter = new ConcurrencyLimiter(new()
{
PermitLimit = 1,
QueueLimit = int.MaxValue
});
var client = new SampleChatClient(new Uri("http://localhost"), "test")
.AsBuilder()
.UseDistributedCache()
.Use(async (chatMessages, options, nextAsync, cancellationToken) =>
{
using var lease = await rateLimiter.AcquireAsync(permitCount: 1, cancellationToken)
.ConfigureAwait(false);
if (!lease.IsAcquired)
{
throw new InvalidOperationException("Unable to acquire lease.");
}
await nextAsync(chatMessages, options, cancellationToken);
})
.UseOpenTelemetry()
.Build();
// Use client
**
Az előző túlterhelés belsőleg használ egy AnonymousDelegatingChatClient
-t, amely lehetővé teszi bonyolultabb minták használatát, csupán kevés plusz kóddal. Ha például ugyanazt az eredményt szeretné elérni, de a DI-ből visszakeresett RateLimiter:
using System.Threading.RateLimiting;
using Microsoft.Extensions.AI;
using Microsoft.Extensions.DependencyInjection;
var client = new SampleChatClient(new Uri("http://localhost"), "test")
.AsBuilder()
.UseDistributedCache()
.Use(static (innerClient, services) =>
{
var rateLimiter = services.GetRequiredService<RateLimiter>();
return new AnonymousDelegatingChatClient(
innerClient, async (chatMessages, options, nextAsync, cancellationToken) =>
{
using var lease = await rateLimiter.AcquireAsync(permitCount: 1, cancellationToken)
.ConfigureAwait(false);
if (!lease.IsAcquired)
{
throw new InvalidOperationException("Unable to acquire lease.");
}
await nextAsync(chatMessages, options, cancellationToken);
});
})
.UseOpenTelemetry()
.Build();
Azokban az esetekben, amikor a fejlesztő közvetlenül szeretné megadni a CompleteAsync
és CompleteStreamingAsync
delegált implementációit, és fontos, hogy mindegyikhez eltérő implementációt lehessen írni a különleges visszatérési típusok kezeléséhez, létezik a Use
egy másik túlterhelése, amely mindegyikhez fogad egy delegáltat.
Függőséginjektálás
IChatClient implementációkat általában függőséginjektálás (DI)keresztül biztosítják az alkalmazásoknak. Ebben a példában egy IDistributedCache kerül hozzáadásra a DI-konténerbe, csakúgy mint egy IChatClient
. A IChatClient
regisztrációja egy olyan építőt alkalmaz, amely létrehoz egy folyamatot, amely egy gyorsítótárazási ügyfelet tartalmaz (amely ezután a DI-ből lekért IDistributedCache
-et használja) és a mintaügyfelet. Az IChatClient
injektált elem lekérhető és felhasználható az alkalmazás más részein is.
using Microsoft.Extensions.AI;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
// App setup
var builder = Host.CreateApplicationBuilder();
builder.Services.AddDistributedMemoryCache();
builder.Services.AddChatClient(new SampleChatClient(
new Uri("http://coolsite.ai"), "target-ai-model"))
.UseDistributedCache();
using var app = builder.Build();
// Elsewhere in the app
var chatClient = app.Services.GetRequiredService<IChatClient>();
Console.WriteLine(await chatClient.CompleteAsync("What is AI?"));
app.Run();
Az előző példa a következő NuGet-csomagoktól függ:
A beszúrt példány és konfiguráció az alkalmazás aktuális igényeitől függően eltérő lehet, és több folyamat is injektálható különböző kulcsokkal.
A IEmbeddingGenerator
felület
A IEmbeddingGenerator<TInput,TEmbedding> felület a beágyazások általános generátorát jelöli. Itt TInput
a beágyazott bemeneti értékek típusa, TEmbedding
pedig a generált beágyazás típusa, amely a Embedding osztálytól öröklődik.
A Embedding
osztály egy IEmbeddingGenerator
által létrehozott beágyazások alaposztályaként szolgál. A beágyazásokhoz társított metaadatok és adatok tárolására és kezelésére szolgál. Az olyan származtatott típusok, mint a Embedding<T>
, konkrét beágyazási vektoradatokat szolgáltatnak. A beágyazás például egy Embedding<T>.Vector tulajdonságot tesz elérhetővé a beágyazási adatok eléréséhez.
A IEmbeddingGenerator
felület meghatároz egy metódust, amellyel aszinkron módon generálhat beágyazást a bemeneti értékek gyűjteményéhez, opcionális konfigurációs és lemondási támogatással. Metaadatokat biztosít, amelyek leírják a generátort, és lehetővé teszi az erősen típusos szolgáltatások lekérését, amelyeket a generátor vagy annak alapjául szolgáló szolgáltatások nyújthatnak.
Minta implementáció
Fontolja meg egy IEmbeddingGenerator
alábbi mintaalkalmazását az általános struktúra megjelenítéséhez, de ez csak véletlenszerű beágyazási vektorokat hoz létre.
using Microsoft.Extensions.AI;
public sealed class SampleEmbeddingGenerator(
Uri endpoint, string modelId)
: IEmbeddingGenerator<string, Embedding<float>>
{
public EmbeddingGeneratorMetadata Metadata { get; } =
new(nameof(SampleEmbeddingGenerator), endpoint, modelId);
public async Task<GeneratedEmbeddings<Embedding<float>>> GenerateAsync(
IEnumerable<string> values,
EmbeddingGenerationOptions? options = null,
CancellationToken cancellationToken = default)
{
// Simulate some async operation
await Task.Delay(100, cancellationToken);
// Create random embeddings
return
[
.. from value in values
select new Embedding<float>(
Enumerable.Range(0, 384)
.Select(_ => Random.Shared.NextSingle())
.ToArray())
];
}
public object? GetService(Type serviceType, object? serviceKey) => this;
public TService? GetService<TService>(object? key = null)
where TService : class => this as TService;
void IDisposable.Dispose() { }
}
Az előző kód:
- Definiál egy
SampleEmbeddingGenerator
nevű osztályt, amely implementálja aIEmbeddingGenerator<string, Embedding<float>>
felületet. - Rendelkezik egy elsődleges konstruktorral, amely elfogadja a végpontot és a modellazonosítót, amely a generátor azonosítására szolgál.
- Egy
Metadata
tulajdonságot tesz elérhetővé, amely metaadatokat biztosít a generátorról. - Implementálja a
GenerateAsync
metódust a bemeneti értékek gyűjteményéhez tartozó beágyazások létrehozásához:- Aszinkron műveletet szimulál 100 ezredmásodperc késleltetésével.
- Véletlenszerű beágyazásokat ad vissza az egyes bemeneti értékekhez.
A tényleges konkrét megvalósításokat a következő csomagokban találja:
Beágyazások létrehozása
Az IEmbeddingGenerator<TInput,TEmbedding> által végrehajtott elsődleges művelet a beágyazás, amely a GenerateAsync metódusával történik.
using Microsoft.Extensions.AI;
IEmbeddingGenerator<string, Embedding<float>> generator =
new SampleEmbeddingGenerator(
new Uri("http://coolsite.ai"), "target-ai-model");
foreach (var embedding in await generator.GenerateAsync(["What is AI?", "What is .NET?"]))
{
Console.WriteLine(string.Join(", ", embedding.Vector.ToArray()));
}
Egyéni IEmbeddingGenerator
közbenső szoftver
A IChatClient
-hez hasonlóan IEmbeddingGenerator
implementációk rétegezhetők. Ahogyan a Microsoft.Extensions.AI
biztosít delegáló implementációkat a IChatClient
számára gyorsítótárazáshoz és telemetriához, úgy nyújt implementációt a IEmbeddingGenerator
számára is.
using Microsoft.Extensions.AI;
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Options;
using OpenTelemetry.Trace;
// Configure OpenTelemetry exporter
var sourceName = Guid.NewGuid().ToString();
var tracerProvider = OpenTelemetry.Sdk.CreateTracerProviderBuilder()
.AddSource(sourceName)
.AddConsoleExporter()
.Build();
// Explore changing the order of the intermediate "Use" calls to see that impact
// that has on what gets cached, traced, etc.
var generator = new EmbeddingGeneratorBuilder<string, Embedding<float>>(
new SampleEmbeddingGenerator(new Uri("http://coolsite.ai"), "target-ai-model"))
.UseDistributedCache(
new MemoryDistributedCache(
Options.Create(new MemoryDistributedCacheOptions())))
.UseOpenTelemetry(sourceName: sourceName)
.Build();
var embeddings = await generator.GenerateAsync(
[
"What is AI?",
"What is .NET?",
"What is AI?"
]);
foreach (var embedding in embeddings)
{
Console.WriteLine(string.Join(", ", embedding.Vector.ToArray()));
}
A IEmbeddingGenerator
lehetővé teszi az egyéni köztes szoftver készítését, amely kibővíti a IEmbeddingGenerator
funkcióit. A DelegatingEmbeddingGenerator<TInput,TEmbedding> osztály a IEmbeddingGenerator<TInput, TEmbedding>
felület implementálása, amely alaposztályként szolgál olyan beágyazási generátorok létrehozásához, amelyek a műveleteket egy másik IEmbeddingGenerator<TInput, TEmbedding>
-példányba delegálják. Lehetővé teszi több generátor bármilyen sorrendben történő láncolását, és a hívásokat átengedi egy mögöttes generátornak. Az osztály alapértelmezett implementációkat biztosít az olyan metódusokhoz, mint a GenerateAsync és a Dispose
, amelyek továbbítják a hívásokat a belső generátorpéldánynak, lehetővé téve a rugalmas és moduláris beágyazási generációt.
Az alábbi példa egy ilyen delegáló beágyazási generátor implementációja, amely korlátozza a beágyazási generálási kérések gyakoriságát.
using Microsoft.Extensions.AI;
using System.Threading.RateLimiting;
public class RateLimitingEmbeddingGenerator(
IEmbeddingGenerator<string, Embedding<float>> innerGenerator, RateLimiter rateLimiter)
: DelegatingEmbeddingGenerator<string, Embedding<float>>(innerGenerator)
{
public override async Task<GeneratedEmbeddings<Embedding<float>>> GenerateAsync(
IEnumerable<string> values,
EmbeddingGenerationOptions? options = null,
CancellationToken cancellationToken = default)
{
using var lease = await rateLimiter.AcquireAsync(permitCount: 1, cancellationToken)
.ConfigureAwait(false);
if (!lease.IsAcquired)
{
throw new InvalidOperationException("Unable to acquire lease.");
}
return await base.GenerateAsync(values, options, cancellationToken);
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
rateLimiter.Dispose();
}
base.Dispose(disposing);
}
}
Ez ezután egy tetszőleges IEmbeddingGenerator<string, Embedding<float>>
körül rétegzhető, amely korlátozza az összes végrehajtott beágyazási létrehozási műveletet.
using Microsoft.Extensions.AI;
using System.Threading.RateLimiting;
IEmbeddingGenerator<string, Embedding<float>> generator =
new RateLimitingEmbeddingGenerator(
new SampleEmbeddingGenerator(new Uri("http://coolsite.ai"), "target-ai-model"),
new ConcurrencyLimiter(new()
{
PermitLimit = 1,
QueueLimit = int.MaxValue
}));
foreach (var embedding in await generator.GenerateAsync(["What is AI?", "What is .NET?"]))
{
Console.WriteLine(string.Join(", ", embedding.Vector.ToArray()));
}
Ilyen módon a RateLimitingEmbeddingGenerator
más IEmbeddingGenerator<string, Embedding<float>>
példányokkal is összeállítható a sebességkorlátozó funkció biztosítása érdekében.