Použijte rozhraní IEmbeddingGenerator

Rozhraní IEmbeddingGenerator<TInput,TEmbedding> představuje obecný generátor vnoření. Pro generické typové parametry je TInput typ vstupních hodnot, který je vkládán, a TEmbedding je typem vygenerovaného vetknutí, který dědí z třídy Embedding.

Třída Embedding slouží jako základní třída pro vkládání vytvořená IEmbeddingGenerator. Je navržený tak, aby ukládal a spravoval metadata a data spojená s embedováním. Odvozené typy, jako Embedding<T>, poskytují konkrétní vložená vektorová data. Například Embedding<float> zpřístupňuje ReadOnlyMemory<float> Vector { get; } vlastnost pro přístup ke svým vloženým datům.

Rozhraní IEmbeddingGenerator definuje metodu pro asynchronní generování vkládání pro kolekci vstupních hodnot s volitelnou konfigurací a podporou zrušení. Poskytuje také metadata popisující generátor a umožňuje načtení pevně typovaných služeb, které může generátor nebo jeho základní služby poskytovat.

Vytváření vložených objektů

Primární operace prováděná s IEmbeddingGenerator<TInput,TEmbedding> je vytváření vnoření, které se provádí pomocí metody 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()));
}

Existují také metody rozšíření akcelerátoru, které zjednodušují běžné případy, jako je generování vloženého vektoru z jednoho vstupu.

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

Kanály funkcí

Stejně jako u IChatClientmohou být implementace IEmbeddingGenerator vrstvené. Microsoft.Extensions.AI poskytuje delegovanou implementaci pro ukládání do mezipaměti a telemetrii IEmbeddingGenerator.

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 umožňuje vytvářet vlastní middleware, který rozšiřuje funkce IEmbeddingGenerator. Třída DelegatingEmbeddingGenerator<TInput,TEmbedding> je implementace IEmbeddingGenerator<TInput, TEmbedding> rozhraní, které slouží jako základní třída pro vytváření generátorů pro vkládání, které delegují své operace na jinou instanci IEmbeddingGenerator<TInput, TEmbedding>. Umožňuje řetězit více generátorů v libovolném pořadí a předávat volání do podkladového generátoru. Třída poskytuje výchozí implementace pro metody, jako jsou GenerateAsync a Dispose, které přesměrují volání do instance vnitřního generátoru, což umožňuje flexibilní a modulární generování vkládání.

Následuje příklad implementace takového delegujícího generátoru vnoření, který omezuje rychlost žádostí o generování vnoření.

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

Tato možnost se pak dá vrstvit kolem libovolné IEmbeddingGenerator<string, Embedding<float>>, aby se omezila rychlost všech operací generování vložení.

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

Tímto způsobem lze RateLimitingEmbeddingGenerator komponovat s dalšími instancemi IEmbeddingGenerator<string, Embedding<float>>, což poskytuje funkce omezování rychlosti.

Příklad implementace

Většina uživatelů rozhraní nemusí implementovat IEmbeddingGenerator . Pokud jste ale autorem knihovny, může být užitečné se podívat na tyto příklady implementace.

Následující kód ukazuje, jak SampleEmbeddingGenerator třída implementuje IEmbeddingGenerator<TInput,TEmbedding> rozhraní. Má primární konstruktor, který přijímá ID koncového bodu a modelu, které slouží k identifikaci generátoru. Implementuje také metodu GenerateAsync(IEnumerable<TInput>, EmbeddingGenerationOptions, CancellationToken) pro generování vložených hodnot pro kolekci vstupních hodnot.

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

Tato ukázková implementace pouze generuje náhodné vložené vektory. Realističtější konkrétní implementaci najdete v tématu OpenTelemetryEmbeddingGenerator.cs.