Bagikan melalui


Gunakan antarmuka IEmbeddingGenerator

Antarmuka IEmbeddingGenerator<TInput,TEmbedding> mewakili pembangkit generik untuk embedding. Untuk parameter jenis generik, TInput adalah jenis nilai input yang disematkan, dan TEmbedding merupakan jenis penyematan yang dihasilkan, yang mewarisi dari Embedding kelas .

Kelas Embedding berfungsi sebagai kelas dasar untuk penyematan yang dihasilkan oleh IEmbeddingGenerator. Ini dirancang untuk menyimpan dan mengelola metadata dan data yang terkait dengan penyematan. Jenis turunan, seperti Embedding<T>, menyediakan data vektor penyematan konkret. Misalnya, sebuah Embedding<float> mengekspos properti ReadOnlyMemory<float> Vector { get; } untuk akses ke data penyematannya.

Antarmuka IEmbeddingGenerator mendefinisikan metode untuk secara asinkron menghasilkan penyematan untuk kumpulan nilai input, dengan konfigurasi opsional dan dukungan pembatalan. Ini juga menyediakan metadata yang menjelaskan generator dan memungkinkan pengambilan layanan bertipe kuat yang dapat disediakan oleh generator atau layanan yang mendasari.

Buat embedding

Operasi utama yang dilakukan dengan IEmbeddingGenerator<TInput,TEmbedding> adalah membuat penyematan, yang dilakukan melalui metode GenerateAsync.

using Microsoft.Extensions.AI;
using OllamaSharp;

IEmbeddingGenerator<string, Embedding<float>> generator =
    new OllamaApiClient(new Uri("http://localhost:11434/"), "phi3:mini");

foreach (Embedding<float> embedding in
    await generator.GenerateAsync(["What is AI?", "What is .NET?"]))
{
    Console.WriteLine(string.Join(", ", embedding.Vector.ToArray()));
}

Metode ekstensi akselerator juga ada untuk menyederhanakan kasus-kasus umum, seperti menghasilkan vektor pengaksesan dari sebuah masukan tunggal.

ReadOnlyMemory<float> vector = await generator.GenerateVectorAsync("What is AI?");

Alur fungsionalitas

Seperti halnya implementasi IChatClient, IEmbeddingGenerator dapat dilapisi. Microsoft.Extensions.AI menyediakan implementasi delegasi untuk IEmbeddingGenerator, yang digunakan untuk tujuan penembolokan dan telemetri.

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

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

// Explore changing the order of the intermediate "Use" calls to see
// what impact that has on what gets cached and traced.
IEmbeddingGenerator<string, Embedding<float>> generator = new EmbeddingGeneratorBuilder<string, Embedding<float>>(
        new OllamaApiClient(new Uri("http://localhost:11434/"), "phi3:mini"))
    .UseDistributedCache(
        new MemoryDistributedCache(
            Options.Create(new MemoryDistributedCacheOptions())))
    .UseOpenTelemetry(sourceName: sourceName)
    .Build();

GeneratedEmbeddings<Embedding<float>> embeddings = await generator.GenerateAsync(
[
    "What is AI?",
    "What is .NET?",
    "What is AI?"
]);

foreach (Embedding<float> embedding in embeddings)
{
    Console.WriteLine(string.Join(", ", embedding.Vector.ToArray()));
}

IEmbeddingGenerator memungkinkan pembuatan middleware kustom yang memperluas fungsionalitas IEmbeddingGenerator. Kelas DelegatingEmbeddingGenerator<TInput,TEmbedding> adalah implementasi antarmuka IEmbeddingGenerator<TInput, TEmbedding> yang berfungsi sebagai kelas dasar untuk membuat generator penyematan yang mendelegasikan operasi mereka ke instans IEmbeddingGenerator<TInput, TEmbedding> lain. Ini memungkinkan untuk menautkan beberapa generator dalam urutan apa pun, dengan meneruskan panggilan ke generator yang mendasarinya. Kelas ini menyediakan implementasi default untuk metode seperti GenerateAsync dan Dispose, yang meneruskan panggilan ke instans generator dalam, memungkinkan pembuatan penyematan yang fleksibel dan modular.

Berikut ini adalah contoh implementasi dari generator penyematan yang mendelegasikan yang membatasi laju permintaan pembuatan penyematan:

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

public class RateLimitingEmbeddingGenerator(
    IEmbeddingGenerator<string, Embedding<float>> innerGenerator, RateLimiter rateLimiter)
        : DelegatingEmbeddingGenerator<string, Embedding<float>>(innerGenerator)
{
    public override async Task<GeneratedEmbeddings<Embedding<float>>> GenerateAsync(
        IEnumerable<string> values,
        EmbeddingGenerationOptions? 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.GenerateAsync(values, options, cancellationToken);
    }

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

        base.Dispose(disposing);
    }
}

Ini kemudian dapat dilapiskan di sekitar elemen arbitrer IEmbeddingGenerator<string, Embedding<float>> untuk membatasi laju semua operasi pembuatan embedding.

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

IEmbeddingGenerator<string, Embedding<float>> generator =
    new RateLimitingEmbeddingGenerator(
        new OllamaApiClient(new Uri("http://localhost:11434/"), "phi3:mini"),
        new ConcurrencyLimiter(new()
        {
            PermitLimit = 1,
            QueueLimit = int.MaxValue
        }));

foreach (Embedding<float> embedding in
    await generator.GenerateAsync(["What is AI?", "What is .NET?"]))
{
    Console.WriteLine(string.Join(", ", embedding.Vector.ToArray()));
}

Dengan cara ini, RateLimitingEmbeddingGenerator dapat dikombinasikan dengan instans IEmbeddingGenerator<string, Embedding<float>> lain untuk menyediakan fungsionalitas pembatasan laju.

Contoh implementasi

Sebagian besar pengguna tidak perlu mengimplementasikan IEmbeddingGenerator antarmuka. Namun, jika Anda adalah penulis pustaka, mungkin berguna untuk melihat contoh implementasi ini.

Kode berikut menunjukkan bagaimana SampleEmbeddingGenerator kelas mengimplementasikan IEmbeddingGenerator<TInput,TEmbedding> antarmuka. Ini memiliki konstruktor utama yang menerima titik akhir dan ID model, yang digunakan untuk mengidentifikasi generator. Ini mengimplementasikan juga metode GenerateAsync(IEnumerable<TInput>, EmbeddingGenerationOptions, CancellationToken) untuk menghasilkan embedding untuk kumpulan nilai input.

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

Implementasi sampel ini hanya menghasilkan vektor penyematan acak. Untuk implementasi yang lebih realistis dan konkret, lihat OpenTelemetryEmbeddingGenerator.cs.