Catatan
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba masuk atau mengubah direktori.
Akses ke halaman ini memerlukan otorisasi. Anda dapat mencoba mengubah direktori.
Antarmuka IChatClient mendefinisikan abstraksi klien yang bertanggung jawab untuk berinteraksi dengan layanan AI yang menyediakan kemampuan obrolan. Ini termasuk metode untuk mengirim dan menerima pesan dengan konten multi-modal (seperti teks, gambar, dan audio), baik sebagai set lengkap atau di-streaming secara bertahap. Selain itu, ini memungkinkan pengambilan layanan bertipe kuat yang disediakan oleh klien atau layanan dasarnya.
Pustaka .NET yang menyediakan klien untuk model dan layanan bahasa dapat menyediakan implementasi IChatClient antarmuka. Setiap konsumen antarmuka kemudian dapat beroperasi dengan mulus dengan model dan layanan ini melalui abstraksi. Anda dapat menemukan contoh di bagian Contoh implementasi .
Meminta tanggapan obrolan
Dengan instans IChatClient, Anda dapat memanggil IChatClient.GetResponseAsync metode untuk mengirim permintaan dan mendapatkan respons. Permintaan terdiri dari satu atau beberapa pesan, yang masing-masing terdiri dari satu atau beberapa bagian konten. Metode akselerator ada untuk menyederhanakan kasus umum, seperti membuat permintaan untuk satu konten teks.
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?"));
Metode IChatClient.GetResponseAsync inti menerima daftar pesan. Daftar ini mewakili riwayat semua pesan yang merupakan bagian dari percakapan.
Console.WriteLine(await client.GetResponseAsync(
[
new(ChatRole.System, "You are a helpful AI assistant"),
new(ChatRole.User, "What is AI?"),
]));
ChatResponse yang dikembalikan dari GetResponseAsync mengekspos daftar ChatMessage instans yang mewakili satu atau beberapa pesan yang dihasilkan sebagai bagian dari operasi. Dalam kasus umum, hanya ada satu pesan respons, tetapi dalam beberapa situasi, mungkin ada beberapa pesan. Daftar pesan diurutkan, sehingga pesan terakhir dalam daftar mewakili pesan akhir untuk permintaan. Untuk memberikan semua pesan respons tersebut kembali ke layanan dalam permintaan berikutnya, Anda dapat menambahkan pesan dari respons kembali ke daftar pesan.
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);
}
Permintaan tanggapan obrolan langsung
Input ke IChatClient.GetStreamingResponseAsync identik dengan GetResponseAsync. Namun, daripada mengembalikan respons lengkap sebagai bagian dari objek ChatResponse, metode mengembalikan IAsyncEnumerable<T> di mana TChatResponseUpdate, menyediakan aliran pembaruan yang secara kolektif membentuk respons tunggal.
await foreach (ChatResponseUpdate update in client.GetStreamingResponseAsync("What is AI?"))
{
Console.Write(update);
}
Petunjuk / Saran
API Streaming hampir identik dengan pengalaman pengguna AI. C# memungkinkan skenario yang menarik dengan dukungan IAsyncEnumerable<T>, memungkinkan cara alami dan efisien untuk mengalirkan data.
Seperti halnya GetResponseAsync, Anda dapat menambahkan pembaruan dari IChatClient.GetStreamingResponseAsync kembali ke daftar pesan. Karena pembaruan adalah bagian individual dari respons, Anda dapat menggunakan pembantu seperti ToChatResponse(IEnumerable<ChatResponseUpdate>) untuk menyusun satu atau beberapa pembaruan kembali ke dalam satu ChatResponse instans.
Pembantu seperti AddMessages membuat ChatResponse lalu mengekstrak pesan yang disusun dari respons dan menambahkannya ke daftar.
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);
}
Panggilan alat
Beberapa model dan layanan mendukung panggilan alat. Untuk mengumpulkan informasi tambahan, Anda dapat mengonfigurasi ChatOptions dengan informasi tentang alat (biasanya metode .NET) yang dapat diminta untuk diaktifkan oleh klien. Alih-alih mengirim respons akhir, model meminta pemanggilan fungsi dengan argumen tertentu. Klien kemudian memanggil fungsi dan mengirim hasilnya kembali ke model dengan riwayat percakapan. Pustaka Microsoft.Extensions.AI.Abstractions mencakup abstraksi untuk berbagai jenis konten pesan, termasuk permintaan dan hasil panggilan fungsi. Meskipun IChatClient konsumen dapat berinteraksi dengan konten ini secara langsung, Microsoft.Extensions.AI menyediakan pembantu yang dapat memungkinkan pemanggilan alat secara otomatis sebagai respons terhadap permintaan yang sesuai. Pustaka Microsoft.Extensions.AI.Abstractions dan Microsoft.Extensions.AI menyediakan jenis berikut:
- AIFunction: Mewakili fungsi yang dapat dijelaskan ke model AI dan dipanggil.
-
AIFunctionFactory: Menyediakan metode pabrik untuk membuat
AIFunctioninstans yang mewakili metode .NET. -
FunctionInvokingChatClient: Membungkus
IChatClientmenjadiIChatClientlain yang memberikan kemampuan pemanggilan fungsi otomatis.
Contoh berikut menunjukkan pemanggilan fungsi acak (contoh ini tergantung pada 📦 paket OllamaSharp NuGet):
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);
}
Kode sebelumnya:
- Menentukan fungsi bernama
GetCurrentWeatheryang mengembalikan prakiraan cuaca acak. - Membuat instans ChatClientBuilder dengan
OllamaSharp.OllamaApiClientdan mengonfigurasinya untuk melakukan pemanggilan fungsi. - Memanggil
GetStreamingResponseAsyncpada klien, mengirimkan prompt dan daftar alat yang menyertakan fungsi yang dibuat dengan Create. - Melakukan iterasi atas respons, mencetak setiap pembaruan ke konsol.
Untuk informasi selengkapnya tentang membuat fungsi AI, lihat Mengakses data dalam fungsi AI.
Anda juga dapat menggunakan alat Model Context Protocol (MCP) dengan IChatClient. Untuk informasi selengkapnya, lihat Membangun klien MCP minimal.
Pengurangan alat (eksperimental)
Penting
Fitur ini bersifat eksperimental dan dapat berubah.
Pengurangan alat membantu mengelola katalog alat besar dengan memangkasnya berdasarkan relevansi dengan konteks percakapan saat ini. Antarmuka IToolReductionStrategy menentukan strategi untuk mengurangi jumlah alat yang dikirim ke model. Pustaka menyediakan implementasi seperti EmbeddingToolReductionStrategy itu memberi peringkat alat dengan menyematkan kesamaan dengan percakapan. Gunakan metode ekstensi UseToolReduction untuk menambahkan fungsi pengurangan alat ke dalam pipeline klien obrolan Anda.
Respons dari cache
Jika Anda terbiasa dengan cache di .NET, penting untuk mengetahui bahwa Microsoft.Extensions.AI menyediakan implementasi pendelegasian IChatClient untuk cache.
DistributedCachingChatClient adalah IChatClient yang menambahkan penyimpanan sementara pada instans IChatClient lain yang sewenang-wenang. Ketika riwayat obrolan baru dikirimkan ke DistributedCachingChatClient, ia mengirimkannya ke klien utama dan kemudian menyimpan respons sebelum mengirimkannya kembali ke konsumen. Lain kali riwayat yang sama dikirimkan, sehingga respons yang di-cache dapat ditemukan di cache, DistributedCachingChatClient mengembalikan respons yang di-cache daripada meneruskan permintaan di sepanjang alur.
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();
}
Contoh ini tergantung pada 📦 paket NuGet Microsoft.Extensions.Caching.Memory . Untuk informasi selengkapnya, lihat Caching di .NET.
Menggunakan telemetri
Contoh lain dari klien obrolan yang mendelegasikan adalah OpenTelemetryChatClient. Implementasi ini mematuhi Konvensi Semantik OpenTelemetry untuk sistem Kecerdasan Buatan (AI) Generatif. Mirip dengan delegator IChatClient lainnya, ia melapisi metrik dan menghubungkan berbagai implementasi IChatClient lain yang arbitrer.
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);
(Contoh sebelumnya tergantung pada 📦 paket OpenTelemetry.Exporter.Console NuGet.)
Atau, LoggingChatClient dan metode UseLogging(ChatClientBuilder, ILoggerFactory, Action<LoggingChatClient>) yang sesuai menyediakan cara sederhana untuk menulis entri log ke ILogger untuk setiap permintaan dan respons.
Sediakan opsi
Setiap panggilan ke GetResponseAsync atau GetStreamingResponseAsync dapat secara opsional menyediakan instans ChatOptions yang berisi parameter tambahan untuk operasi. Parameter yang paling umum di antara model dan layanan AI muncul sebagai properti yang bertiped kuat pada tipenya, seperti ChatOptions.Temperature. Parameter lain dapat disediakan berdasarkan nama dengan cara yang bertiped lemah, menggunakan kamus ChatOptions.AdditionalProperties, atau melalui instans opsi yang dipahami oleh penyedia dasar menggunakan properti ChatOptions.RawRepresentationFactory.
Anda juga dapat menentukan opsi saat membangun IChatClient dengan API ChatClientBuilder secara bersambung dengan menyambungkan panggilan ke metode ekstensi ConfigureOptions(ChatClientBuilder, Action<ChatOptions>). Klien yang mendelegasikan ini membungkus klien lain dan menggunakan delegasi yang disediakan untuk mengisi instans ChatOptions setiap kali ada panggilan. Misalnya, untuk memastikan bahwa properti ChatOptions.ModelId default ke nama model tertentu, Anda dapat menggunakan kode seperti berikut:
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" }));
Rangkaian fungsionalitas
IChatClient instans dapat dilapisi untuk membuat alur komponen yang masing-masing menambahkan fungsionalitas tambahan. Komponen-komponen ini dapat berasal dari Microsoft.Extensions.AI, paket NuGet lainnya, atau implementasi kustom. Pendekatan ini memungkinkan Anda untuk menambah perilaku IChatClient dengan berbagai cara untuk memenuhi kebutuhan spesifik Anda. Pertimbangkan cuplikan kode berikut yang melapisi cache terdistribusi, pemanggilan fungsi, dan pelacakan OpenTelemetry di sekitar klien obrolan sampel:
// 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();
Middleware IChatClient kustomisasi
Untuk menambahkan fungsionalitas tambahan, Anda dapat menerapkan IChatClient secara langsung atau menggunakan kelas DelegatingChatClient. Kelas ini berfungsi sebagai dasar untuk membuat klien obrolan yang mendelegasikan operasi ke instans IChatClient lain. Ini menyederhanakan penautan beberapa klien, yang memungkinkan panggilan untuk diteruskan ke klien yang mendasar.
Kelas DelegatingChatClient menyediakan implementasi default untuk metode seperti GetResponseAsync, GetStreamingResponseAsync, dan Dispose, yang meneruskan panggilan ke klien dalam. Kelas turunan kemudian hanya dapat mengambil alih metode yang diperlukan untuk menambah perilaku, sambil mendelegasikan panggilan lain ke implementasi dasar. Pendekatan ini berguna untuk membuat klien obrolan fleksibel dan modular yang mudah diperluas dan dibuat.
Berikut ini adalah contoh kelas yang berasal dari DelegatingChatClient yang menggunakan pustaka System.Threading.RateLimiting untuk menyediakan fungsionalitas pembatasan laju.
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);
}
}
Seperti halnya implementasi IChatClient lainnya, RateLimitingChatClient dapat disusun:
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?"));
Untuk menyederhanakan komposisi komponen tersebut dengan yang lain, penulis komponen harus membuat metode ekstensi Use* untuk mendaftarkan komponen ke dalam alur. Misalnya, pertimbangkan metode ekstensi berikut UseRateLimiting :
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)
);
}
Ekstensi tersebut juga dapat meminta layanan yang relevan dari kontainer DI; IServiceProvider yang digunakan oleh pipeline diteruskan sebagai parameter opsional:
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>())
);
}
Sekarang mudah bagi konsumen untuk mengintegrasikan ini ke dalam proses mereka, misalnya:
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));
Metode ekstensi sebelumnya menunjukkan menggunakan metode Use pada ChatClientBuilder.
ChatClientBuilder juga menyediakan Use kelebihan beban yang memudahkan penulisan pendelegasian handler tersebut. Misalnya, dalam contoh RateLimitingChatClient sebelumnya, penggantian GetResponseAsync dan GetStreamingResponseAsync hanya perlu melakukan pekerjaan sebelum dan sesudah mendelegasikan ke klien berikutnya dalam pipeline. Untuk mencapai hal yang sama tanpa menulis kelas kustom, Anda dapat menggunakan overload dari Use yang menerima delegate, yang digunakan untuk GetResponseAsync dan GetStreamingResponseAsync, sehingga mengurangi kode boilerplate yang diperlukan.
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();
Untuk skenario di mana Anda memerlukan implementasi yang berbeda untuk GetResponseAsync dan GetStreamingResponseAsync untuk menangani jenis pengembalian uniknya, Anda dapat menggunakan Use(Func<IEnumerable<ChatMessage>,ChatOptions,IChatClient,CancellationToken,
Task<ChatResponse>>, Func<IEnumerable<ChatMessage>,ChatOptions,
IChatClient,CancellationToken,IAsyncEnumerable<ChatResponseUpdate>>) overload yang menerima sebuah delegate untuk masing-masing.
Injeksi Ketergantungan
IChatClient implementasi sering diberikan kepada aplikasi melalui injeksi dependensi (DI). Dalam contoh berikut, ditambahkan IDistributedCache ke dalam kontainer DI, seperti halnya IChatClient. Pendaftaran untuk IChatClient menggunakan builder yang membuat pipeline yang berisi klien caching (yang kemudian menggunakan IDistributedCache yang diambil dari DI) dan klien sampel.
IChatClient yang disuntikkan dapat diambil dan digunakan di bagian lain dari aplikasi.
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?"));
Instans dan konfigurasi apa yang disuntikkan dapat berbeda berdasarkan kebutuhan aplikasi saat ini, dan beberapa alur dapat disuntikkan dengan kunci yang berbeda.
Pengguna stateless vs. stateful
Layanan stateless mengharuskan semua riwayat percakapan yang relevan dikirim kembali pada setiap permintaan. Sebaliknya, layanan stateful melacak riwayat dan hanya memerlukan pesan tambahan untuk dikirim dengan permintaan. Antarmuka IChatClient dirancang untuk menangani layanan AI "stateless" dan "stateful".
Saat bekerja dengan layanan stateless, pengguna menyimpan daftar semua pesan. Mereka menambahkan semua pesan respons yang diterima dan memberikan daftar kembali pada interaksi berikutnya.
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);
}
Untuk layanan stateful, Anda mungkin sudah mengetahui identitas yang digunakan untuk percakapan yang relevan. Anda dapat memasukkan pengidentifikasi itu ke dalam ChatOptions.ConversationId. Penggunaan kemudian mengikuti pola yang sama, kecuali tidak perlu mempertahankan riwayat secara manual.
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));
}
Beberapa layanan mungkin mendukung pembuatan ID percakapan secara otomatis untuk permintaan yang tidak memilikinya, atau membuat ID percakapan baru yang mewakili status percakapan saat ini setelah menggabungkan putaran terakhir pesan. Dalam kasus seperti itu, Anda dapat mentransfer ChatResponse.ConversationId ke ChatOptions.ConversationId untuk permintaan berikutnya. Contohnya:
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;
}
Jika Anda belum mengetahui sebelumnya apakah layanan tersebut tanpa status atau berstatus, Anda dapat memeriksa respons ConversationId dan mengambil tindakan berdasarkan nilai tersebut. Jika diatur, maka nilai tersebut disebarkan ke opsi dan riwayat dibersihkan agar tidak mengirim ulang riwayat yang sama lagi. Jika respons ConversationId tidak diatur, maka pesan respons ditambahkan ke riwayat sehingga dikirim kembali ke layanan pada giliran berikutnya.
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);
}
}
Contoh implementasi
Sampel berikut mengimplementasikan IChatClient untuk menunjukkan struktur umum.
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() { }
}
Untuk implementasi yang lebih realistis dan konkret dari IChatClient, lihat:
Pengurangan obrolan (eksperimental)
Penting
Fitur ini bersifat eksperimental dan dapat berubah.
Pengurangan obrolan membantu mengelola riwayat percakapan dengan membatasi jumlah pesan atau meringkas pesan yang lebih lama saat percakapan melebihi panjang yang ditentukan.
Microsoft.Extensions.AI Pustaka menyediakan pengurang seperti MessageCountingChatReducer yang membatasi jumlah pesan non-sistem, dan SummarizingChatReducer yang secara otomatis merangkum pesan lama sambil mempertahankan konteks.