Delen via


IEmbeddingGenerator De interface gebruiken

De IEmbeddingGenerator<TInput,TEmbedding>-interface vertegenwoordigt een algemene generator van insluitingen. Voor de algemene typeparameters TInput is het type invoerwaarden dat wordt ingesloten en TEmbedding het type gegenereerde insluiting, dat wordt overgenomen van de Embedding klasse.

De Embedding-klasse fungeert als basisklasse voor insluitingen die worden gegenereerd door een IEmbeddingGenerator. Het is ontworpen voor het opslaan en beheren van de metagegevens en gegevens die zijn gekoppeld aan insluitingen. Afgeleide typen, zoals Embedding<T>, bieden de concrete insluitingsvectorgegevens. Een Embedding<float> eigenschap biedt een ReadOnlyMemory<float> Vector { get; } eigenschap voor toegang tot de ingesloten gegevens.

De IEmbeddingGenerator-interface definieert een methode voor het asynchroon genereren van insluitingen voor een verzameling invoerwaarden, met optionele configuratie- en annuleringsondersteuning. Het biedt ook metagegevens die de generator beschrijven en het ophalen van sterk getypte services die door de generator of de onderliggende services kunnen worden geleverd.

Insluitingen maken

De primaire bewerking die wordt uitgevoerd met een IEmbeddingGenerator<TInput,TEmbedding> is het genereren van embeddings, wat wordt bereikt met de methode 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()));
}

Uitbreidingsmethoden voor accelerators bestaan ook om veelvoorkomende gevallen te vereenvoudigen, zoals het genereren van een insluitvector van één invoer.

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

Pijplijnen van functionaliteit

Net als bij IChatClientkunnen IEmbeddingGenerator implementaties gelaagd worden. Microsoft.Extensions.AI biedt een delegerings-implementatie voor IEmbeddingGenerator caching en telemetrie.

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

De IEmbeddingGenerator maakt het mogelijk om aangepaste middleware te bouwen die de functionaliteit van een IEmbeddingGeneratoruitbreidt. De DelegatingEmbeddingGenerator<TInput,TEmbedding>-klasse is een implementatie van de IEmbeddingGenerator<TInput, TEmbedding>-interface die fungeert als basisklasse voor het maken van insluitgeneratoren die hun bewerkingen delegeren aan een ander IEmbeddingGenerator<TInput, TEmbedding> exemplaar. Het maakt het mogelijk om meerdere generatoren in elke volgorde te koppelen, waarbij aanroepen worden doorgegeven aan een onderliggende generator. De klasse biedt standaard implementaties voor methoden zoals GenerateAsync en Dispose, waarmee de aanroepen naar het binnenste generatorexemplaren worden doorgestuurd, waardoor flexibele en modulaire insluitingsgeneratie mogelijk is.

Hier volgt een voorbeeldimplementatie van een dergelijke delegerende embedding generator die het aantal embedding generatieverzoeken beperkt.

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

Dit kan vervolgens worden gelaagd rond een willekeurig element IEmbeddingGenerator<string, Embedding<float>> om alle bewerkingen voor het genereren van insluitingen te beperken.

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

Op deze manier kan de RateLimitingEmbeddingGenerator functie worden samengesteld met andere IEmbeddingGenerator<string, Embedding<float>> exemplaren om functionaliteit voor snelheidsbeperking te bieden.

Implementatievoorbeelden

De meeste gebruikers hoeven de IEmbeddingGenerator interface niet te implementeren. Als u echter een auteur van een bibliotheek bent, kan het handig zijn om deze implementatievoorbeelden te bekijken.

De volgende code laat zien hoe de SampleEmbeddingGenerator klasse de IEmbeddingGenerator<TInput,TEmbedding> interface implementeert. Het heeft een primaire constructor die een eindpunt en model-id accepteert, die worden gebruikt om de generator te identificeren. Ook wordt de methode geïmplementeerd voor het GenerateAsync(IEnumerable<TInput>, EmbeddingGenerationOptions, CancellationToken) genereren van insluitingen voor een verzameling invoerwaarden.

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

Met deze voorbeeld-implementatie worden alleen willekeurige insluitingsvectoren gegenereerd. Zie OpenTelemetryEmbeddingGenerator.cs voor een realistischere, concrete implementatie.