Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of de directory te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen de mappen te wijzigen.
De IChatClient-interface definieert een clientabstractie die verantwoordelijk is voor interactie met AI-services die chatmogelijkheden bieden. Het bevat methoden voor het verzenden en ontvangen van berichten met multimodale inhoud (zoals tekst, afbeeldingen en audio), als een volledige set of incrementeel gestreamd. Daarnaast is het mogelijk om sterk getypte services op te halen die worden geleverd door de klant of de onderliggende services.
.NET-bibliotheken die clients bieden voor taalmodellen en -services, kunnen een implementatie van de IChatClient interface bieden. Alle consumenten van de interface kunnen vervolgens naadloos samenwerken met deze modellen en services via de abstracties. U vindt voorbeelden in de sectie Implementatievoorbeelden .
Een chatantwoord aanvragen
Met een exemplaar van IChatClientkunt u de IChatClient.GetResponseAsync methode aanroepen om een aanvraag te verzenden en een antwoord te krijgen. De aanvraag bestaat uit een of meer berichten, die elk bestaan uit een of meer inhoudsonderdelen. Er bestaan acceleratormethoden om veelvoorkomende gevallen te vereenvoudigen, zoals het samenstellen van een aanvraag voor één stuk tekstinhoud.
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?"));
De kernmethode IChatClient.GetResponseAsync accepteert een lijst met berichten. Deze lijst vertegenwoordigt de geschiedenis van alle berichten die deel uitmaken van het gesprek.
Console.WriteLine(await client.GetResponseAsync(
[
new(ChatRole.System, "You are a helpful AI assistant"),
new(ChatRole.User, "What is AI?"),
]));
ChatResponse dat geretourneerd wordt vanuit GetResponseAsync, geeft een lijst van ChatMessage exemplaren weer die een of meer berichten vertegenwoordigen die als onderdeel van de bewerking zijn gegenereerd. In veelvoorkomende gevallen is er slechts één antwoordbericht, maar in sommige gevallen kunnen er meerdere berichten zijn. De berichtenlijst is geordend, zodat het laatste bericht in de lijst het laatste bericht aan de aanvraag voorstelt. Als u al deze antwoordberichten wilt terugsturen naar de service in een volgende aanvraag, kunt u de berichten uit het antwoord weer toevoegen aan de berichtenlijst.
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);
}
Een streaming-chatantwoord aanvragen
De invoer voor IChatClient.GetStreamingResponseAsync is identiek aan die van GetResponseAsync. In plaats van het volledige antwoord als onderdeel van een ChatResponse-object te retourneren, retourneert de methode echter een IAsyncEnumerable<T> waarbij T is ChatResponseUpdate, waardoor een stroom updates wordt geboden die gezamenlijk het enige antwoord vormen.
await foreach (ChatResponseUpdate update in client.GetStreamingResponseAsync("What is AI?"))
{
Console.Write(update);
}
Aanbeveling
Streaming-API's zijn bijna synoniem voor AI-gebruikerservaringen. C# maakt aantrekkelijke scenario's mogelijk met de IAsyncEnumerable<T> ondersteuning, waardoor gegevens op een natuurlijke en efficiënte manier kunnen worden gestreamd.
Net als bij GetResponseAsync, kunt u de updates van IChatClient.GetStreamingResponseAsync terug naar de berichtenlijst toevoegen. Omdat de updates afzonderlijke onderdelen van een antwoord zijn, kunt u helpers ToChatResponse(IEnumerable<ChatResponseUpdate>) gebruiken om een of meer updates weer op te stellen in één ChatResponse exemplaar.
Helpers, zoals AddMessages, stellen een ChatResponse samen en halen vervolgens de samengestelde berichten uit de reactie om ze aan een lijst toe te voegen.
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);
}
Aanroepen van hulpprogramma's
Sommige modellen en services ondersteunen het aanroepen van hulpprogramma's. Als u aanvullende informatie wilt verzamelen, kunt u de ChatOptions configuratie uitvoeren met informatie over hulpprogramma's (meestal .NET-methoden) die het model kan aanvragen om de client aan te roepen. In plaats van een definitief antwoord te verzenden, vraagt het model een functie-aanroep aan met specifieke argumenten. De client roept vervolgens de functie aan en stuurt de resultaten terug naar het model met de gespreksgeschiedenis. De Microsoft.Extensions.AI.Abstractions-bibliotheek bevat abstracties voor verschillende berichtinhoudstypen, waaronder aanvragen voor functieoproepen en resultaten. Hoewel IChatClient consumenten rechtstreeks met deze inhoud kunnen werken, Microsoft.Extensions.AI biedt helpers die de hulpprogramma's automatisch kunnen inschakelen als reactie op de bijbehorende aanvragen. De Microsoft.Extensions.AI.Abstractions en Microsoft.Extensions.AI bibliotheken bieden de volgende typen:
- AIFunction: Vertegenwoordigt een functie die kan worden beschreven in een AI-model en wordt aangeroepen.
-
AIFunctionFactory: biedt factorymethoden voor het maken van instanties van
AIFunctiondie .NET-methoden vertegenwoordigen. -
FunctionInvokingChatClient: verpakt een
IChatClientals een andereIChatClientdie automatische functieaanroepmogelijkheden toevoegt.
In het volgende voorbeeld ziet u een willekeurige functieaanroep (dit voorbeeld is afhankelijk van het 📦 OllamaSharp NuGet-pakket):
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);
}
De voorgaande code:
- Definieert een functie met de naam
GetCurrentWeatherdie een willekeurige weersvoorspelling retourneert. - Instantieert een ChatClientBuilder met een
OllamaSharp.OllamaApiClienten configureert deze voor het gebruik van functieaanroepen. - Roept
GetStreamingResponseAsyncaan op de client, waarbij een prompt en een lijst met hulpprogramma's worden doorgegeven die een functie bevat die is gemaakt met Create. - Doorloopt het antwoord en drukt elke update af op de console.
Zie Access-gegevens in AI-functies voor meer informatie over het maken van AI-functies.
U kunt ook MCP-hulpprogramma's (Model Context Protocol) gebruiken met uw IChatClient. Zie Een minimale MCP-client bouwen voor meer informatie.
Hulpprogrammareductie (experimenteel)
Belangrijk
Deze functie is experimenteel en kan worden gewijzigd.
Met het verminderen van hulpprogramma's kunt u grote hulpprogrammacatalogussen beheren door ze te beperken op basis van relevantie voor de huidige gesprekscontext. De IToolReductionStrategy interface definieert strategieën voor het verminderen van het aantal hulpprogramma's dat naar het model wordt verzonden. De bibliotheek biedt implementaties zoals EmbeddingToolReductionStrategy die hulpprogramma's rangschikken door overeenkomsten met het gesprek in te sluiten. Gebruik de UseToolReduction extensiemethode om hulpprogrammareductie toe te voegen aan uw chatclientpijplijn.
Reacties in cache
Als u bekend bent met caching in .NET, is het handig om te weten dat Microsoft.Extensions.AI gedelegeerde IChatClient implementaties voor caching biedt. De DistributedCachingChatClient is een IChatClient dat caching lagen legt rondom een ander willekeurig IChatClient exemplaar. Wanneer een nieuwe chatgeschiedenis naar de DistributedCachingChatClientclient wordt verzonden, wordt deze doorgestuurd naar de onderliggende client en wordt het antwoord vervolgens in de cache opgeslagen voordat deze naar de consument wordt verzonden. De volgende keer dat dezelfde geschiedenis wordt verzonden, zodat een reactie in de cache kan worden gevonden, retourneert het DistributedCachingChatClient antwoord in de cache in plaats van de aanvraag door te sturen langs de pijplijn.
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();
}
Dit voorbeeld is afhankelijk van het 📦 NuGet-pakket Microsoft.Extensions.Caching.Memory . Zie Caching in .NETvoor meer informatie.
Telemetrie gebruiken
Een ander voorbeeld van een delegering van een chatclient is de OpenTelemetryChatClient. Deze implementatie voldoet aan de OpenTelemetry Semantic Conventions voor generatieve AI-systemen. Net zoals bij andere IChatClient afvaardigers, worden metrieken en spans om andere willekeurige IChatClient implementaties heen gelaagd.
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);
(Het voorgaande voorbeeld is afhankelijk van het 📦 NuGet-pakket OpenTelemetry.Exporter.Console .)
De en bijbehorende LoggingChatClient methode bieden ook UseLogging(ChatClientBuilder, ILoggerFactory, Action<LoggingChatClient>) een eenvoudige manier om logboekvermeldingen naar een ILogger voor elke aanvraag en elk antwoord te schrijven.
Opties opgeven
Elke aanroep naar GetResponseAsync of GetStreamingResponseAsync kan eventueel een ChatOptions exemplaar met extra parameters voor de bewerking opgeven. De meest voorkomende parameters onder AI-modellen en -services verschijnen als sterk getypte eigenschappen van het type, zoals ChatOptions.Temperature. Andere parameters kunnen op naam worden opgegeven op een zwak getypte manier, via de ChatOptions.AdditionalProperties woordenlijst of via een instantie van opties die de onderliggende provider begrijpt, met behulp van de ChatOptions.RawRepresentationFactory eigenschap.
U kunt ook opties opgeven bij het bouwen van een IChatClient met de fluent-API ChatClientBuilder door een aanroep naar de ConfigureOptions(ChatClientBuilder, Action<ChatOptions>) extensiemethode te koppelen. Deze delegatieclient verpakt een andere client en roept de opgegeven gedelegeerde aan om een ChatOptions instantie voor elke aanroep te vullen. Als u er bijvoorbeeld voor wilt zorgen dat de eigenschap ChatOptions.ModelId standaard wordt ingesteld op een bepaalde modelnaam, kunt u code als volgt gebruiken:
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" }));
Functionaliteitspijplijnen
IChatClient exemplaren kunnen gelaagd worden om een pijplijn met onderdelen te maken die elk extra functionaliteit toevoegen. Deze onderdelen kunnen afkomstig zijn van Microsoft.Extensions.AI, andere NuGet-pakketten of aangepaste implementaties. Met deze aanpak kunt u het gedrag van de IChatClient op verschillende manieren uitbreiden om te voldoen aan uw specifieke behoeften. Houd rekening met het volgende codefragment dat een gedistribueerde cache, functieaanroep en OpenTelemetry-tracering rond een voorbeeld-chatclient bevat:
// 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();
Aangepaste IChatClient middleware
Als u extra functionaliteit wilt toevoegen, kunt u IChatClient rechtstreeks implementeren of de DelegatingChatClient-klasse gebruiken. Deze klasse fungeert als basis voor het maken van chatclients die bewerkingen delegeren aan een ander IChatClient exemplaar. Het vereenvoudigt het koppelen van meerdere clients, waardoor aanroepen naar een onderliggende client kunnen worden doorgegeven.
De DelegatingChatClient-klasse biedt standaard implementaties voor methoden zoals GetResponseAsync, GetStreamingResponseAsyncen Dispose, waarmee aanroepen naar de interne client worden doorgestuurd. Een afgeleide klasse kan vervolgens alleen de methoden overschrijven die nodig zijn om het gedrag te verbeteren, terwijl andere aanroepen naar de basis-implementatie worden overgedragen. Deze aanpak is handig voor het maken van flexibele en modulaire chatclients die eenvoudig kunnen worden uitgebreid en samengesteld.
Hier volgt een voorbeeldklasse die is afgeleid van die gebruikmaakt van DelegatingChatClient de System.Threading.RateLimiting-bibliotheek om functionaliteit voor snelheidsbeperking te bieden.
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);
}
}
Net als bij andere IChatClient implementaties kan de RateLimitingChatClient worden samengesteld.
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?"));
Om de samenstelling van dergelijke onderdelen met anderen te vereenvoudigen, moeten auteurs van onderdelen een Use* uitbreidingsmethode maken voor het registreren van het onderdeel in een pijplijn. Denk bijvoorbeeld aan de volgende UseRateLimiting extensiemethode:
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)
);
}
Dergelijke extensies kunnen ook query's uitvoeren op relevante services uit de DI-container; de IServiceProvider die door de pijplijn worden gebruikt, worden doorgegeven als een optionele parameter:
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>())
);
}
Nu is het voor de consument eenvoudig om dit te gebruiken in hun pijplijn, bijvoorbeeld:
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));
De vorige uitbreidingsmethoden demonstreren het gebruik van een Use-methode op ChatClientBuilder.
ChatClientBuilder biedt Use ook overbelastingen die het gemakkelijker maken om dergelijke delegerende handlers te schrijven. In het vorige RateLimitingChatClient-voorbeeld hoeven de overschrijvingen van GetResponseAsync en GetStreamingResponseAsync slechts taken uit te voeren voordat en nadat ze aan de volgende cliënt in de pijplijn delegeren. Om hetzelfde te bereiken zonder een aangepaste klasse te schrijven, kunt u een overload van Use gebruiken die een gedelegeerde accepteert die wordt gebruikt voor zowel GetResponseAsync als GetStreamingResponseAsync, waardoor de overbodige opmaak vermindert die nodig is.
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();
Voor scenario's waarin u een andere implementatie voor GetResponseAsync en GetStreamingResponseAsync nodig hebt om hun unieke retourtypen af te handelen, kunt u de Use(Func<IEnumerable<ChatMessage>,ChatOptions,IChatClient,CancellationToken,
Task<ChatResponse>>, Func<IEnumerable<ChatMessage>,ChatOptions,
IChatClient,CancellationToken,IAsyncEnumerable<ChatResponseUpdate>>) overload gebruiken die voor elke een delegaat accepteert.
Afhankelijkheidsinjectie
IChatClient implementaties worden vaak via afhankelijkheidsinjectie (DI) aan een toepassing verstrekt. In het volgende voorbeeld wordt er een IDistributedCache toegevoegd aan de DI-container, net als een IChatClient. De registratie voor de IChatClient maakt gebruik van een builder die een pijplijn creëert met een cacheclient (die vervolgens een IDistributedCache uit DI ophaalt) en gebruikt de voorbeeldclient. De geïnjecteerde IChatClient kan elders in de app worden opgehaald en gebruikt.
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?"));
Welke instantie en configuratie wordt geïnjecteerd, kunnen verschillen op basis van de huidige behoeften van de toepassing en meerdere pijplijnen kunnen worden geïnjecteerd met verschillende sleutels.
Stateless versus stateful clients
Staatloze services vereisen dat bij elke aanvraag alle relevante gespreksgeschiedenis wordt teruggestuurd. Daarentegen houden stateful services de geschiedenis bij en vereisen ze alleen dat extra berichten met een aanvraag worden meegezonden. De IChatClient interface is ontworpen om zowel stateless- als stateful AI-services te ondersteunen.
Bij het werken met een staatloze service onderhouden bellers een lijst met alle berichten. Ze voegen alle ontvangen antwoordberichten toe en geven de lijst weer op volgende interacties.
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);
}
Voor stateful services weet u mogelijk al de id die wordt gebruikt voor het relevante gesprek. U kunt die identifier in ChatOptions.ConversationId plaatsen. Gebruik volgt vervolgens hetzelfde patroon, behalve dat er geen geschiedenis handmatig hoeft te worden onderhouden.
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));
}
Sommige services bieden mogelijk ondersteuning voor het automatisch maken van een gespreks-id voor een aanvraag die geen gespreks-id heeft of het maken van een nieuwe gespreks-id die de huidige status van het gesprek vertegenwoordigt nadat de laatste ronde berichten is opgenomen. In dergelijke gevallen kunt u de ChatResponse.ConversationId verplaatsen naar de ChatOptions.ConversationId voor volgende verzoeken. Voorbeeld:
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;
}
Als u van tevoren niet weet of de service staatloos of met toestand is, kunt u het antwoord ConversationId controleren en actie ondernemen op basis van de waarde ervan. Als deze is ingesteld, wordt die waarde doorgegeven aan de opties en wordt de geschiedenis gewist, zodat dezelfde geschiedenis niet opnieuw kan worden verzonden. Als het antwoord ConversationId niet is ingesteld, wordt het antwoordbericht toegevoegd aan de geschiedenis, zodat het opnieuw naar de service wordt verzonden bij de volgende keer.
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);
}
}
Implementatievoorbeelden
Het volgende voorbeeld implementeert IChatClient om de algemene structuur te tonen.
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() { }
}
Voor meer realistische, concrete implementaties van IChatClient, zie:
Chatreductie (experimenteel)
Belangrijk
Deze functie is experimenteel en kan worden gewijzigd.
Met chatreductie kunt u de gespreksgeschiedenis beheren door het aantal berichten te beperken of oudere berichten samen te vatten wanneer het gesprek een opgegeven lengte overschrijdt. De Microsoft.Extensions.AI bibliotheek biedt reductieprogramma's zoals MessageCountingChatReducer dat beperkt het aantal niet-systeemberichten en SummarizingChatReducer dat automatisch oudere berichten samenvat terwijl context behouden blijft.