A IChatClient felület használata

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 lehetővé teszi a kliens vagy annak mögöttes szolgáltatásai által biztosított, szigorúan típusosított szolgáltatások lekérését is.

A nyelvi modellekhez és szolgáltatásokhoz ügyfeleket biztosító .NET-kódtárak biztosítják a felület implementálását IChatClient . A felület felhasználói ezután zökkenőmentesen együttműködhetnek ezekkel a modellekkel és szolgáltatásokkal az absztrakciókon keresztül. Példákat az Implementálási példák szakaszban talál.

Csevegési válasz kérése

Egy IChatClient példány esetén meghívhatja a IChatClient.GetResponseAsync metódust, hogy küldjön egy kérést, és kapjon egy választ. 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;
using OllamaSharp;

IChatClient client = new OllamaApiClient(
    new Uri("http://localhost:11434/"), "phi3:mini");

Console.WriteLine(await client.GetResponseAsync("What is AI?"));

Az alapvető IChatClient.GetResponseAsync 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.

Console.WriteLine(await client.GetResponseAsync(
[
    new(ChatRole.System, "You are a helpful AI assistant"),
    new(ChatRole.User, "What is AI?"),
]));

A ChatResponse visszaadott GetResponseAsync példányok listája ChatMessage a művelet részeként létrehozott egy vagy több üzenetet jeleníti meg. Gyakori esetekben csak egy válaszüzenet létezik, de bizonyos helyzetekben több üzenet is lehet. Az üzenetlista úgy van rendezve, hogy a lista utolsó üzenete a kérésnek küldött utolsó üzenetet adja meg. Ha az összes válaszüzenetet vissza szeretné adni a szolgáltatásnak egy későbbi kérésben, felveheti a válaszból származó üzeneteket vissza az üzenetek listájába.

List<ChatMessage> history = [];
while (true)
{
    Console.Write("Q: ");
    history.Add(new(ChatRole.User, Console.ReadLine()));

    ChatResponse response = await client.GetResponseAsync(history);
    Console.WriteLine(response);

    history.AddMessages(response);
}

Streamelési csevegési válasz kérése

A IChatClient.GetStreamingResponseAsync bemenetei megegyeznek a GetResponseAsyncbemenetével. Ahelyett azonban, hogy a teljes választ egy ChatResponse objektum részeként adja vissza, a metódus egy olyan IAsyncEnumerable<T> ad vissza, amelyben TChatResponseUpdate, és egy olyan frissítési adatfolyamot biztosít, amely együttesen alkotja az egyetlen választ.

await foreach (ChatResponseUpdate update in client.GetStreamingResponseAsync("What is AI?"))
{
    Console.Write(update);
}

Jótanács

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.

Ahogy az is GetResponseAsync, a frissítéseket visszaról IChatClient.GetStreamingResponseAsync is felveheti az üzenetek listájába. Mivel a frissítések egy adott válasz egyes részei, olyan segédeszközökkel, mint a ToChatResponse(IEnumerable<ChatResponseUpdate>), egy vagy több frissítést állíthat össze egyetlen ChatResponse példányba.

A segítők például AddMessages megírnak egy ChatResponse üzenetet, majd kinyerik a válaszból a megkomponált üzeneteket, és hozzáadják őket egy listához.

List<ChatMessage> chatHistory = [];
while (true)
{
    Console.Write("Q: ");
    chatHistory.Add(new(ChatRole.User, Console.ReadLine()));

    List<ChatResponseUpdate> updates = [];
    await foreach (ChatResponseUpdate update in
        client.GetStreamingResponseAsync(chatHistory))
    {
        Console.Write(update);
        updates.Add(update);
    }
    Console.WriteLine();

    chatHistory.AddMessages(updates);
}

Eszközhívási funkció

Egyes modellek és szolgáltatások támogatják az eszközhívást. További információk gyűjtéséhez konfigurálhatja azokat az ChatOptions eszközöket (általában .NET-metódusokat), amelyeket a modell meghívhat az ügyfél számára. 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. A Microsoft.Extensions.AI.Abstractions 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 IChatClient a felhasználók közvetlenül kezelhetik ezt a tartalmat, olyan segítőket biztosít, Microsoft.Extensions.AI amelyek lehetővé teszik az eszközök automatikus meghívását a megfelelő kérésekre válaszul. A Microsoft.Extensions.AI.Abstractions és Microsoft.Extensions.AI könyvtárak a következő típusokat biztosítják:

  • AIFunction: Egy AI-modellnek leírható és meghívható függvényt jelöl.
  • AIFunctionFactory: Gyári metódusokat biztosít a .NET-metódusokat képviselő példányok létrehozásához AIFunction .
  • FunctionInvokingChatClient: Egy másik IChatClient formájában burkolja be IChatClient-t, amely automatikus függvényhívási képességeket ad hozzá.

Az alábbi példa egy véletlenszerű függvényhívást mutat be (ez a példa az 📦 OllamaSharp NuGet-csomagtól függ):

using Microsoft.Extensions.AI;
using OllamaSharp;

string GetCurrentWeather() => Random.Shared.NextDouble() > 0.5 ? "It's sunny" : "It's raining";

IChatClient client = new OllamaApiClient(new Uri("http://localhost:11434"), "llama3.1");

client = ChatClientBuilderChatClientExtensions
    .AsBuilder(client)
    .UseFunctionInvocation()
    .Build();

ChatOptions options = new() { Tools = [AIFunctionFactory.Create(GetCurrentWeather)] };

var response = client.GetStreamingResponseAsync("Should I wear a rain coat?", options);
await foreach (var update in response)
{
    Console.Write(update);
}

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.
  • Létrehoz egy ChatClientBuilder-t egy OllamaSharp.OllamaApiClient-gyel, és konfigurálja a függvényhívás használatára.
  • Meghívja GetStreamingResponseAsync 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.

További információ az AI-függvények létrehozásáról: Access-adatok az AI-függvényekben.

A Model Context Protocol (MCP) eszközeit is használhatja a IChatClient. További információ: Minimális MCP-ügyfél létrehozása.

Gyorsítótár-válaszok

Ha ismeri a .NET-gyorsítótárazást, jó tudni, hogy Microsoft.Extensions.AI delegálási IChatClient implementációkat biztosít a gyorsítótárazáshoz. A DistributedCachingChatClient egy IChatClient, amely egy másik IChatClient tetszőleges példánya köré rétegezi a gyorsítótárazást. Amikor egy új csevegési előzményt küldenek be a DistributedCachingChatClient-nek, az továbbítja azt a mögöttes kliensnek, 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, és így a gyorsítótárban található gyorsítótárazott válasz, a DistributedCachingChatClient ahelyett, hogy a kérést továbbítaná a feldolgozási folyamat mentén, a gyorsítótárazott választ adja vissza.

using Microsoft.Extensions.AI;
using Microsoft.Extensions.Caching.Distributed;
using Microsoft.Extensions.Caching.Memory;
using Microsoft.Extensions.Options;
using OllamaSharp;

var sampleChatClient = new OllamaApiClient(new Uri("http://localhost:11434"), "llama3.1");

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.GetStreamingResponseAsync(prompt))
    {
        Console.Write(update);
    }
    Console.WriteLine();
}

Ez a példa a 📦 Microsoft.Extensions.Caching.Memory NuGet csomagtól függ. További információért lásd: Gyorsítótárazás a .NET-ben.

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. Más IChatClient delegátorokhoz hasonlóan a metrikákat rétegezi, és más tetszőleges IChatClient implementációkra terjed ki.

using Microsoft.Extensions.AI;
using OllamaSharp;
using OpenTelemetry.Trace;

// Configure OpenTelemetry exporter.
string sourceName = Guid.NewGuid().ToString();
TracerProvider tracerProvider = OpenTelemetry.Sdk.CreateTracerProviderBuilder()
    .AddSource(sourceName)
    .AddConsoleExporter()
    .Build();

IChatClient ollamaClient = new OllamaApiClient(
    new Uri("http://localhost:11434/"), "phi3:mini");

IChatClient client = new ChatClientBuilder(ollamaClient)
    .UseOpenTelemetry(
        sourceName: sourceName,
        configure: c => c.EnableSensitiveData = true)
    .Build();

Console.WriteLine((await client.GetResponseAsync("What is AI?")).Text);

(Az előző példa az 📦 OpenTelemetry.Exporter.Console NuGet csomagtól függ.)

Alternatív megoldásként a LoggingChatClient megfelelő UseLogging(ChatClientBuilder, ILoggerFactory, Action<LoggingChatClient>) metódussal egyszerűen írhat naplóbejegyzéseket minden ILogger kéréshez és válaszhoz.

Beállítások megadása

A GetResponseAsync vagy GetStreamingResponseAsync 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 névvel, gyengén begépelt módon, a ChatOptions.AdditionalProperties szótáron vagy a mögöttes szolgáltató által megértett beállításpéldányon keresztül lehet megadni a ChatOptions.RawRepresentationFactory tulajdonság használatával.

A fluent IChatClient API-val való létrehozásakor ChatClientBuilder is megadhatja a beállításokat a bővítménymetódushoz ConfigureOptions(ChatClientBuilder, Action<ChatOptions>) való hívás láncolásával. Ez a delegáló ügyfél egy másik ügyfelet burkol, és meghívja a megadott delegátot arra, 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;
using OllamaSharp;

IChatClient client = new OllamaApiClient(new Uri("http://localhost:11434"));

client = ChatClientBuilderChatClientExtensions.AsBuilder(client)
    .ConfigureOptions(options => options.ModelId ??= "phi3")
    .Build();

// Will request "phi3".
Console.WriteLine(await client.GetResponseAsync("What is AI?"));
// Will request "llama3.1".
Console.WriteLine(await client.GetResponseAsync("What is AI?", new() { ModelId = "llama3.1" }));

Funkcionalitási csővezetékek

IChatClient a példányok rétegzhetők, így olyan összetevőkből álló folyamatot hozhatnak létre, amelyek mindegyike további 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. Fontolja meg az alábbi kódrészletet, amely egy elosztott gyorsítótárat, függvényhívást és OpenTelemetria-nyomkövetést rétegez egy minta csevegőügyfél köré:

// Explore changing the order of the intermediate "Use" calls.
IChatClient client = new ChatClientBuilder(new OllamaApiClient(new Uri("http://localhost:11434"), "llama3.1"))
    .UseDistributedCache(new MemoryDistributedCache(Options.Create(new MemoryDistributedCacheOptions())))
    .UseFunctionInvocation()
    .UseOpenTelemetry(sourceName: sourceName, configure: c => c.EnableSensitiveData = true)
    .Build();

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íthatóak egy mögöttes ügyfélnek.

A DelegatingChatClient osztály alapértelmezett implementációkat biztosít olyan metódusokhoz, mint a GetResponseAsync, a GetStreamingResponseAsyncés a Dispose, amelyek a belső ügyfélnek továbbítják a hívásokat. A származtatott osztály ezután csak azokat a metódusokat bírálhatja felül, amelyekre a viselkedés növeléséhez szüksége van, miközben más hívásokat delegál az alap implementációba. Ez a megközelítés olyan rugalmas és moduláris csevegési ügyfelek létrehozásához hasznos, amelyek könnyen bővíthetőek és összeállíthatóak.

Az alábbiakban egy példaosztályt DelegatingChatClient mutatunk be, amely a System.Threading.RateLimiting kódtárat használja a sebességkorlátozó funkciók biztosításához.

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<ChatResponse> GetResponseAsync(
        IEnumerable<ChatMessage> messages,
        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.GetResponseAsync(messages, options, cancellationToken)
            .ConfigureAwait(false);
    }

    public override async IAsyncEnumerable<ChatResponseUpdate> GetStreamingResponseAsync(
        IEnumerable<ChatMessage> messages,
        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.GetStreamingResponseAsync(messages, options, cancellationToken)
            .ConfigureAwait(false))
        {
            yield return update;
        }
    }

    protected override void Dispose(bool disposing)
    {
        if (disposing)
            rateLimiter.Dispose();

        base.Dispose(disposing);
    }
}

Más implementációkhoz IChatClient hasonlóan a RateLimitingChatClient összetevői összeállíthatók.

using Microsoft.Extensions.AI;
using OllamaSharp;
using System.Threading.RateLimiting;

var client = new RateLimitingChatClient(
    new OllamaApiClient(new Uri("http://localhost:11434"), "llama3.1"),
    new ConcurrencyLimiter(new() { PermitLimit = 1, QueueLimit = int.MaxValue }));

Console.WriteLine(await client.GetResponseAsync("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ő UseRateLimiting bővítménymetódust:

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)
        );
}

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.

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,
                services.GetRequiredService<RateLimiter>())
        );
}

Most már a fogyasztó könnyedén használhatja ezt a feldolgozási folyamatot például:

HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);

IChatClient client = new OllamaApiClient(
    new Uri("http://localhost:11434/"),
    "phi3:mini");

builder.Services.AddChatClient(services =>
        client
        .AsBuilder()
        .UseDistributedCache()
        .UseRateLimiting()
        .UseOpenTelemetry()
        .Build(services));

Az előző bővítési metódusok bemutatják, hogyan használható egy metódus Use-n ChatClientBuilder. A ChatClientBuilder túlterhelési funkciókat is biztosít Use , amelyek megkönnyítik az ilyen delegáló kezelők írását. A korábbi RateLimitingChatClient példában például a GetResponseAsync és GetStreamingResponseAsync 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 GetResponseAsync, mind a GetStreamingResponseAsyncszámára használatos, a szükséges sablonkódot csökkentve.

using Microsoft.Extensions.AI;
using OllamaSharp;
using System.Threading.RateLimiting;

RateLimiter rateLimiter = new ConcurrencyLimiter(new()
{
    PermitLimit = 1,
    QueueLimit = int.MaxValue
});

IChatClient client = new OllamaApiClient(new Uri("http://localhost:11434"), "llama3.1");

client = ChatClientBuilderChatClientExtensions
    .AsBuilder(client)
    .UseDistributedCache()
    .Use(async (messages, 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(messages, options, cancellationToken);
    })
    .UseOpenTelemetry()
    .Build();

Az olyan helyzetekben, amikor az egyedi visszatérési típusok kezeléséhez különböző implementációkra van szükség GetResponseAsync és GetStreamingResponseAsync esetében, használhatja azt a Use(Func<IEnumerable<ChatMessage>,ChatOptions,IChatClient,CancellationToken, Task<ChatResponse>>, Func<IEnumerable<ChatMessage>,ChatOptions, IChatClient,CancellationToken,IAsyncEnumerable<ChatResponseUpdate>>) túlterhelést, amely mindegyikhez egy-egy delegáltat fogad el.

Függőséginjektálás

IChatClient implementációkat gyakran függőséginjektáláson (DI) keresztül biztosítják az alkalmazásoknak. Az alábbi példában a DI-tárolóhoz hozzáadunk egy IDistributedCache elemet, ahogy egy IChatClient. A regisztráció egy IChatClient olyan szerkesztőt használ, amely létrehoz egy gyorsítótárazási ügyfelet tartalmazó folyamatot (amely ezt követően lekéri a IDistributedCache DI-ből) és a mintaügyfélt. 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;
using OllamaSharp;

// App setup.
var builder = Host.CreateApplicationBuilder();
builder.Services.AddDistributedMemoryCache();
builder.Services.AddChatClient(new OllamaApiClient(new Uri("http://localhost:11434"), "llama3.1"))
    .UseDistributedCache();
var host = builder.Build();

// Elsewhere in the app.
var chatClient = host.Services.GetRequiredService<IChatClient>();
Console.WriteLine(await chatClient.GetResponseAsync("What is AI?"));

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.

Állapot nélküli és állapotmegőrző kliensek

Az állapot nélküli szolgáltatásokhoz minden kéréshez vissza kell küldeni az összes releváns beszélgetési előzményt. Ezzel szemben az állapotalapú szolgáltatások nyomon követik az előzményeket, és csak további üzeneteket igényelnek egy kéréssel. Az IChatClient interfész állapot nélküli és állapotalapú AI-szolgáltatások kezelésére is alkalmas.

Állapot nélküli szolgáltatás használatakor a hívók az összes üzenet listáját megőrzik. Az összes kapott válaszüzenetet hozzáadják, és a további interakciók során visszaadják a listát.

List<ChatMessage> history = [];
while (true)
{
    Console.Write("Q: ");
    history.Add(new(ChatRole.User, Console.ReadLine()));

    var response = await client.GetResponseAsync(history);
    Console.WriteLine(response);

    history.AddMessages(response);
}

Az állapotalapú szolgáltatások esetében előfordulhat, hogy már ismeri az adott beszélgetéshez használt azonosítót. Ezt az azonosítót beírhatja a fájlba ChatOptions.ConversationId. A használat ezután ugyanazt a mintát követi, kivéve, hogy nincs szükség az előzmények manuális karbantartására.

ChatOptions statefulOptions = new() { ConversationId = "my-conversation-id" };
while (true)
{
    Console.Write("Q: ");
    ChatMessage message = new(ChatRole.User, Console.ReadLine());

    Console.WriteLine(await client.GetResponseAsync(message, statefulOptions));
}

Egyes szolgáltatások támogathatják a beszélgetés azonosítójának automatikus létrehozását egy olyan kéréshez, amely nem rendelkezik ilyen azonosítóval, vagy létrehozhat egy új beszélgetési azonosítót, amely az utolsó üzenetkör beépítése után a beszélgetés aktuális állapotát jelöli. Ilyen esetekben átviheti a ChatResponse.ConversationId elemet a ChatOptions.ConversationId-re a későbbi kérésekhez. Például:

ChatOptions options = new();
while (true)
{
    Console.Write("Q: ");
    ChatMessage message = new(ChatRole.User, Console.ReadLine());

    ChatResponse response = await client.GetResponseAsync(message, options);
    Console.WriteLine(response);

    options.ConversationId = response.ConversationId;
}

Ha nem tudja előre, hogy a szolgáltatás állapot nélküli vagy állapotalapú-e, ellenőrizheti a választ ConversationId , és annak értéke alapján cselekedhet. Ha be van állítva, akkor a rendszer propagálja az értéket a beállításokra, és az előzmények törlődnek, hogy ne jelenjen meg újra ugyanaz az előzmény. Ha a válasz ConversationId nincs beállítva, akkor a rendszer hozzáadja a válaszüzenetet az előzményekhez, hogy a következő fordulóban visszaküldje azt a szolgáltatásnak.

List<ChatMessage> chatHistory = [];
ChatOptions chatOptions = new();
while (true)
{
    Console.Write("Q: ");
    chatHistory.Add(new(ChatRole.User, Console.ReadLine()));

    ChatResponse response = await client.GetResponseAsync(chatHistory);
    Console.WriteLine(response);

    chatOptions.ConversationId = response.ConversationId;
    if (response.ConversationId is not null)
    {
        chatHistory.Clear();
    }
    else
    {
        chatHistory.AddMessages(response);
    }
}

Megvalósítási példák

Az alábbi minta implementálja IChatClient az általános struktúra bemutatására.

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<ChatResponse> GetResponseAsync(
        IEnumerable<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(
            ChatRole.Assistant,
            responses[Random.Shared.Next(responses.Length)]
            ));
    }

    public async IAsyncEnumerable<ChatResponseUpdate> GetStreamingResponseAsync(
        IEnumerable<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 ChatResponseUpdate(ChatRole.Assistant, 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 valósághűbb, konkrétabb implementációkért IChatClientlásd:

Csevegés minimalizálása (próba)

Fontos

Ez a funkció kísérleti jellegű, és változhat.

A csevegés csökkentése segít kezelni a beszélgetések előzményeit az üzenetek számának korlátozásával vagy a régebbi üzenetek összegzésével, ha a beszélgetés túllépi a megadott időtartamot. A Microsoft.Extensions.AI kódtár olyan redukálókat biztosít, amelyek MessageCountingChatReducer korlátozzák a nem rendszerszintű üzenetek számát, és SummarizingChatReducer automatikusan összegzi a régebbi üzeneteket a környezet megőrzése mellett.