IChatClient 和 IEmbeddingGenerator 的示例实现

提供用于语言模型和服务的客户端的 .NET 库可以提供IChatClientIEmbeddingGenerator<TInput,TEmbedding>接口的实现。 然后,接口的任何使用者都可以通过抽象与这些模型和服务无缝互作。

IChatClient 接口

IChatClient 接口定义一个客户端抽象,负责与提供聊天功能的 AI 服务交互。 它包括发送和接收具有多模式内容(如文本、图像和音频)的消息的方法,无论是作为一个完整的集合还是增量流式传输。 此外,它还允许检索由客户端或其基础服务提供的强类型服务。

以下示例实现 IChatClient 以显示一般结构。

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

有关 IChatClient 的更实际的具体实现,请参阅:

IEmbeddingGenerator<TInput,TEmbedding> 接口

IEmbeddingGenerator<TInput,TEmbedding> 接口表示嵌入的泛型生成器。 此处,TInput 是嵌入的输入值的类型,TEmbedding 是生成的嵌入的类型,它继承自 Embedding 类。

Embedding 类充当由 IEmbeddingGenerator<TInput,TEmbedding> 生成的嵌入的基类。 它旨在存储和管理与嵌入相关的元数据和数据。 派生类型(例如 Embedding<T>)提供具体的嵌入向量数据。 例如,Embedding<float> 公开一个 ReadOnlyMemory<float> Vector { get; } 属性以便访问其嵌入的数据。

IEmbeddingGenerator<TInput,TEmbedding> 接口定义一种方法,以异步方式为输入值的集合生成嵌入,并提供可选配置和取消支持。 它还提供描述生成器的元数据,并允许检索可由生成器或其基础服务提供的强类型服务。

以下代码演示如何类 SampleEmbeddingGenerator 实现 IEmbeddingGenerator<TInput,TEmbedding> 接口。 它有一个接受终结点和模型 ID 的主构造函数,用于标识生成器。 它还实现 GenerateAsync(IEnumerable<TInput>, EmbeddingGenerationOptions, CancellationToken) 为输入值集合生成嵌入的方法。

using Microsoft.Extensions.AI;

public sealed class SampleEmbeddingGenerator(
    Uri endpoint, string modelId)
        : IEmbeddingGenerator<string, Embedding<float>>
{
    private readonly EmbeddingGeneratorMetadata _metadata =
        new("SampleEmbeddingGenerator", endpoint, modelId);

    public async Task<GeneratedEmbeddings<Embedding<float>>> GenerateAsync(
        IEnumerable<string> values,
        EmbeddingGenerationOptions? options = null,
        CancellationToken cancellationToken = default)
    {
        // Simulate some async operation.
        await Task.Delay(100, cancellationToken);

        // Create random embeddings.
        return [.. from value in values
            select new Embedding<float>(
                Enumerable.Range(0, 384)
                .Select(_ => Random.Shared.NextSingle()).ToArray())];
    }

    public object? GetService(Type serviceType, object? serviceKey) =>
        serviceKey is not null
        ? null
        : serviceType == typeof(EmbeddingGeneratorMetadata)
            ? _metadata
            : serviceType?.IsInstanceOfType(this) is true
                ? this
                : null;

    void IDisposable.Dispose() { }
}

此示例实现只生成随机嵌入向量。 有关更现实的具体实现,请参阅 OpenTelemetryEmbeddingGenerator.cs