Aracılığıyla paylaş


Arabirimi kullanın IChatClient

IChatClient arabirimi, sohbet özellikleri sağlayan yapay zeka hizmetleriyle etkileşimden sorumlu bir istemci soyutlaması tanımlar. Çok modlu içeriğe (metin, görüntü ve ses gibi) sahip iletileri tam bir küme olarak veya sürekli akışla artımlı gönderme ve alma yöntemlerini içerir. Buna ek olarak, istemci veya temel hizmetleri tarafından sağlanan kesin türde hizmetlere erişim sağlar.

Dil modelleri ve hizmetleri için istemciler sağlayan .NET kitaplıkları arabiriminin IChatClient bir uygulamasını sağlayabilir. Daha sonra arabirimin tüm tüketicileri soyutlamalar aracılığıyla bu model ve hizmetlerle sorunsuz bir şekilde birlikte çalışabilir. Örnekleri Uygulama örnekleri bölümünde bulabilirsiniz.

Sohbet yanıtı isteme

IChatClient örneğiyle, istek göndermek ve yanıt almak için IChatClient.GetResponseAsync yöntemini çağırabilirsiniz. İstek, her biri bir veya daha fazla içerik parçasından oluşan bir veya daha fazla iletiden oluşur. Tek bir metin içeriği için istek oluşturma gibi yaygın durumları basitleştirmek için hızlandırıcı yöntemleri vardır.

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?"));

Çekirdek IChatClient.GetResponseAsync yöntemi iletilerin listesini kabul eder. Bu liste, konuşmanın parçası olan tüm iletilerin geçmişini temsil eder.

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

ChatResponse 'dan döndürülen GetResponseAsync öğesi, işlemin bir parçası olarak oluşturulan bir veya daha fazla iletiyi temsil eden ChatMessage örneklerinin bir listesini sunar. Yaygın durumlarda yalnızca bir yanıt iletisi vardır, ancak bazı durumlarda birden çok ileti olabilir. İleti listesi, listedeki son iletinin isteğin son iletisini temsil ettiği şekilde sıralanır. Sonraki bir istekte bu yanıt iletilerinin tümünü hizmete geri sağlamak için, yanıttaki iletileri iletiler listesine geri ekleyebilirsiniz.

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

Canlı sohbet yanıtı talep et

IChatClient.GetStreamingResponseAsync girişleri, GetResponseAsyncile aynıdır. Ancak, tam yanıtı bir ChatResponse nesnesinin parçası olarak döndürmek yerine, IAsyncEnumerable<T>'nin Tolduğu bir ChatResponseUpdate döndüren yöntem, toplu olarak tek bir yanıtı oluşturan bir güncelleme akışı sağlar.

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

Tip

Akış API'leri, yapay zeka kullanıcı deneyimleri ile neredeyse eş anlamlıdır. C# IAsyncEnumerable<T> desteğiyle ilgi çekici senaryolara olanak tanıyarak veri akışının doğal ve verimli bir yolunu sunar.

GetResponseAsync olduğu gibi, IChatClient.GetStreamingResponseAsync içindeki güncellemeleri ileti listesine geri ekleyebilirsiniz. Güncelleştirmeler bir yanıtın bireysel parçaları olduğundan, bir veya daha fazla güncelleştirmeyi tek bir ToChatResponse(IEnumerable<ChatResponseUpdate>) örneğe komponlemek için ChatResponse gibi yardımcılar kullanabilirsiniz.

Yardımcılar, AddMessages bir ChatResponse oluşturur ve ardından yanıttan oluşturulan iletileri ayıklayarak bunları bir listeye ekler.

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

Araç çağırma

Bazı modeller ve hizmetler araç çağrılarını destekler. Ek bilgi toplamak için, modelin istemciden ChatOptions çağırmasını isteyebileceği araçlar (genellikle .NET yöntemleri) hakkındaki bilgilerle öğesini yapılandırabilirsiniz. Model, son yanıtı göndermek yerine belirli bağımsız değişkenlerle bir işlev çağrısı isteğinde bulunur. İstemci daha sonra işlevi çağırır ve sonuçları konuşma geçmişiyle birlikte modele geri gönderir. Microsoft.Extensions.AI.Abstractions kitaplığı, işlev çağrısı istekleri ve sonuçları dahil olmak üzere çeşitli ileti içerik türleri için soyutlamalar içerir. IChatClient Tüketiciler bu içerikle doğrudan etkileşime geçmekle birlikte, Microsoft.Extensions.AI ilgili isteklere yanıt olarak araçları otomatik olarak çağırmayı etkinleştirebilen yardımcılar sağlar. Microsoft.Extensions.AI.Abstractions ve Microsoft.Extensions.AI kitaplıkları aşağıdaki türleri sağlar:

  • AIFunction: Yapay zeka modeline açıklanabilen ve çağrılabilen bir işlevi temsil eder.
  • AIFunctionFactory: .NET yöntemlerini temsil eden AIFunction örnekler oluşturmak için fabrika metotları sağlar.
  • FunctionInvokingChatClient: Otomatik işlev çağırma özellikleri ekleyen bir IChatClient, başka bir IChatClient'yi sarar.

Aşağıdaki örnekte rastgele bir işlev çağrısı gösterilmektedir (bu örnek OllamaSharp NuGet paketine 📦 bağlıdır):

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

Önceki kod:

  • Rastgele hava durumu tahmini döndüren GetCurrentWeather adlı bir işlev tanımlar.
  • Bir ChatClientBuilder bir OllamaSharp.OllamaApiClient ile örneklenir ve fonksiyon çağrısını kullanacak şekilde yapılandırılır.
  • GetStreamingResponseAsyncile oluşturulan bir işlevi içeren bir istem metni ve araç listesini geçirerek istemcideki Create'ı çağırır.
  • Yanıt üzerinde tekrar tekrar döngü yapılarak her güncelleme konsola yazdırılır.

Yapay zeka işlevleri oluşturma hakkında daha fazla bilgi için bkz. Yapay zeka işlevlerindeki verilere erişme.

Model Bağlam Protokolü (MCP) araçlarını IChatClient ile de kullanabilirsiniz. Daha fazla bilgi için bkz. En az MCP istemcisi oluşturma.

Araç azaltma (deneysel)

Önemli

Bu özellik deneyseldir ve değiştirilebilir.

Araç azaltma, büyük araç kataloglarını geçerli konuşma bağlamı ile ilgisine göre kırparak yönetmenize yardımcı olur. Arabirim, IToolReductionStrategy modele gönderilen araç sayısını azaltmaya yönelik stratejileri tanımlar. Kitaplık, konuşmayla benzerlik ekleyerek araçları derecelendirmek gibi EmbeddingToolReductionStrategy uygulamalar sağlar. Sohbet istemci işlem hattınıza araç azaltma ekleyebilmek için UseToolReduction uzantı metodunu kullanın.

Yanıtları önbelleğe al

.NET'te önbelleğe alma hakkında bilginiz varsa, Microsoft.Extensions.AI önbelleğe alma için delegasyon IChatClient uygulamaları sağladığını bilmek iyi olur. Başka bir rastgele DistributedCachingChatClient örneğinin etrafına önbellekleme katmanları ekleyen bir IChatClient olan IChatClient. 'a DistributedCachingChatClientyeni bir sohbet geçmişi gönderildiğinde, bunu temel alınan istemciye iletir ve ardından yanıtı tüketiciye geri göndermeden önce önbelleğe alır. Aynı geçmiş, önbellekte önbelleğe alınmış bir yanıt bulunabileceği şekilde bir sonraki sefer gönderildiğinde, DistributedCachingChatClient, isteği işlem hattı boyunca iletmek yerine önbelleğe alınmış yanıtı döndürür.

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

Bu örnek, Microsoft.Extensions.Caching.Memory NuGet paketine bağlıdır📦. Daha fazla bilgi için Caching in .NET bölümüne bakın.

Telemetri kullanma

Başka bir vekil sohbet istemcisi örneği de OpenTelemetryChatClient. Bu uygulama, Üretici Yapay Zeka sistemleri için OpenTelemetry Anlamsal Kurallarına uygundur. Diğer IChatClient temsilcilere benzer şekilde, ölçümleri ve spesifikasyonları diğer keyfi IChatClient uygulamalar etrafında katmanlar oluşturur.

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

(Yukarıdaki örnek OpenTelemetry.Exporter.Console NuGet paketine bağlıdır📦.)

Alternatif olarak, LoggingChatClient ve ilgili UseLogging(ChatClientBuilder, ILoggerFactory, Action<LoggingChatClient>) yöntemi, her istek ve yanıt için ILogger'ye günlük girdileri yazmak için basit bir yol sağlar.

Seçenekleri belirtin

GetResponseAsync veya GetStreamingResponseAsync adlı her çağrı, isteğe bağlı olarak işlem için ek parametreler içeren bir ChatOptions örneği sağlayabilir. Yapay zeka modelleri ve hizmetleri arasındaki en yaygın parametreler, türü üzerinde ChatOptions.Temperaturegibi kesin olarak belirlenmiş özellikler olarak gösterilir. Diğer parametreler, zayıf tipli bir şekilde, ChatOptions.AdditionalProperties sözlüğü aracılığıyla veya temel sağlayıcının anladığı bir seçenek örneğini kullanarak ChatOptions.RawRepresentationFactory özelliği aracılığıyla sağlanabilir.

Akıcı IChatClient API'si ile ChatClientBuilder oluştururken, ConfigureOptions(ChatClientBuilder, Action<ChatOptions>) uzantı yöntemine yapılan bir çağrıyı zincirleyerek seçenekleri belirtebilirsiniz. Bu yetkilendirme istemcisi, başka bir istemciyi sarar ve her çağrıda bir ChatOptions örneğini doldurmak için sağlanan vekili çağırır. Örneğin, ChatOptions.ModelId özelliğinin varsayılan olarak belirli bir model adı olduğundan emin olmak için aşağıdaki gibi bir kod kullanabilirsiniz:

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

İşlevsellik işlem hatları

IChatClient örnekler, her biri ek işlevler ekleyen bir bileşen işlem hattı oluşturmak için katmanlanabilir. Bu bileşenler Microsoft.Extensions.AI, diğer NuGet paketlerinden veya özel uygulamalardan gelebilir. Bu yaklaşım, IChatClient davranışını belirli gereksinimlerinizi karşılamak için çeşitli şekillerde artırmanıza olanak tanır. Örnek bir sohbet istemcisi etrafında dağıtılmış bir önbelleği, işlev çağırmayı ve OpenTelemetry izlemeyi katmanlayan aşağıdaki kod parçacığını göz önünde bulundurun:

// 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();

Özel IChatClient ara yazılımı

Ek işlevler eklemek için doğrudan IChatClient uygulayabilir veya DelegatingChatClient sınıfını kullanabilirsiniz. Bu sınıf, işlemleri başka bir IChatClient örneğine devreden sohbet istemcileri oluşturmak için bir temel görevi görür. Birden çok istemcinin zincirlemesini basitleştirir ve bu da çağrıların temel alınan istemciye geçirilmesini sağlar.

DelegatingChatClient sınıfı, çağrıları iç istemciye iletan GetResponseAsync, GetStreamingResponseAsyncve Disposegibi yöntemler için varsayılan uygulamalar sağlar. Türetilmiş bir sınıf daha sonra yalnızca davranışı artırmak için ihtiyaç duyduğu yöntemleri geçersiz kılabilir ve diğer çağrıları temel uygulamaya atayabilir. Bu yaklaşım, genişletmesi ve oluşturması kolay esnek ve modüler sohbet istemcileri oluşturmak için kullanışlıdır.

Aşağıda, hız sınırlama işlevselliği sağlamak için DelegatingChatClient kitaplığını kullanan türetilmiş bir örnek sınıf verilmiştir.

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

Diğer IChatClient uygulamalarda olduğu gibi, RateLimitingChatClient oluşturulabilir:

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?"));

Bu tür bileşenlerin başkalarıyla bileşimini basitleştirmek için, bileşen yazarlarının bileşeni bir işlem hattına kaydetmek için Use* bir uzantı yöntemi oluşturması gerekir. Örneğin, aşağıdaki UseRateLimiting uzantı yöntemini göz önünde bulundurun:

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

Bu tür uzantılar DI kapsayıcısından ilgili hizmetleri de sorgulayabilir; işlem hattı tarafından kullanılan IServiceProvider isteğe bağlı bir parametre olarak geçirilir:

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

Artık tüketicinin işlem hattında bunu kullanması kolaydır, örneğin:

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

Önceki uzantı yöntemleri üzerinde Usebir ChatClientBuilder yöntem kullanmayı gösterir. ChatClientBuilder ayrıca, Use bu tür delegasyon işleyicilerini yazmayı kolaylaştıran overloadlar sağlar. Örneğin, önceki RateLimitingChatClient örneğinde, GetResponseAsync ve GetStreamingResponseAsync geçersiz kılmalarının yalnızca işlem hattındaki bir sonraki istemciye görevi devretmeden önce ve sonra çalışması gerekir. Özel bir sınıf yazmaya gerek kalmadan aynı şeyi elde etmek için, hem Use hem de GetResponseAsynciçin kullanılan bir temsilciyi kabul eden bir GetStreamingResponseAsync aşırı yükünü kullanarak gerekli kalıp kodunu azaltabilirsiniz.

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

Uygulama gereksinimlerini karşılamak için GetResponseAsync ve GetStreamingResponseAsync'in benzersiz dönüş türlerini işleme ihtiyacınız olan senaryolarda, her biri için bir temsilci kabul eden Use(Func<IEnumerable<ChatMessage>,ChatOptions,IChatClient,CancellationToken, Task<ChatResponse>>, Func<IEnumerable<ChatMessage>,ChatOptions, IChatClient,CancellationToken,IAsyncEnumerable<ChatResponseUpdate>>) aşırı yüklemesini kullanabilirsiniz.

Bağımlılık enjeksiyonu

IChatClient uygulamaları genellikle bir uygulamaya bağımlılık ekleme (DI) yoluyla sağlanır. Aşağıdaki örnekte, IDistributedCache ve IChatClient DI kapsayıcısına eklenir. IChatClient kaydı, DI'den alınan bir IDistributedCache kullanan bir önbelleğe alma istemcisi ve örnek istemciyi içeren bir işlem hattı oluşturan bir oluşturucu kullanır. Enjekte edilen IChatClient, uygulamanın başka bir yerinde erişilebilir ve kullanılabilir.

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?"));

Eklenen örnek ve yapılandırma, uygulamanın geçerli gereksinimlerine göre farklılık gösterebilir ve farklı anahtarlarla birden çok işlem hattı eklenebilir.

Durum bilgisi olmayan ve durum bilgisi olan istemciler karşılaştırması

Durum bilgisi olmayan hizmetler, tüm ilgili konuşma geçmişinin her istekte geri gönderilmesini gerektirir. Buna karşılık, durum bilgisi olan hizmetler geçmişin kaydını tutar ve istekle birlikte yalnızca ek mesajların gönderilmesini gerektirir. Arabirim IChatClient hem durum bilgisi olmayan hem de durum bilgisi olan yapay zeka hizmetlerini işleyecek şekilde tasarlanmıştır.

Durumsuz bir hizmetle çalışırken, arayanlar tüm iletilerin listesini tutar. Gelen tüm yanıt iletilerini ekler ve sonraki etkileşimlerde listeyi yeniden sunar.

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

Durum bilgisine sahip hizmetler için, ilgili konuşma için kullanılan tanımlayıcıyı zaten biliyor olabilirsiniz. Bu tanımlayıcıyı içine ChatOptions.ConversationIdkoyabilirsiniz. Daha sonra kullanım aynı deseni izler, ancak bir geçmişi el ile tutmanız gerekmez.

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

Bazı hizmetler, kimlik bilgisi olmayan bir istek için otomatik olarak bir konuşma kimliği oluşturmayı veya son ileti aşamasını birleştirdikten sonra konuşmanın geçerli durumunu temsil eden yeni bir konuşma kimliği oluşturmayı destekleyebilir. Bu gibi durumlarda, sonraki istekler için ChatResponse.ConversationId öğesini ChatOptions.ConversationId üzerine aktarabilirsiniz. Örneğin:

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

Hizmetin durumsuz veya durumlu olduğunu önceden bilmiyorsanız, yanıtı ConversationId kontrol edebilir ve değerine göre harekete geçebilirsiniz. Ayarlanırsa, bu değer seçeneklere yayılır ve aynı geçmişi yeniden göndermemek için geçmiş temizlenir. Yanıt ConversationId ayarlı değilse yanıt iletisi geçmişe eklenir ve bir sonraki dönüşte hizmete geri gönderilir.

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

Uygulama örneği

Aşağıdaki örnek, genel yapıyı göstermek için IChatClient kullanmaktadır.

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() { }
}

daha gerçekçi, somut uygulamaları için IChatClientbkz:

Sohbet azaltma (deneysel)

Önemli

Bu özellik deneyseldir ve değiştirilebilir.

Sohbet azaltma, ileti sayısını sınırlayarak veya konuşma belirtilen uzunluğu aştığında eski iletileri özetleyerek konuşma geçmişini yönetmeye yardımcı olur. Kitaplık, Microsoft.Extensions.AI ile sistem dışı iletilerin sayısını sınırlayan ve MessageCountingChatReducer ile bağlamı korurken eski iletileri otomatik olarak özetleyen azaltıcı fonksiyonlar sağlar.