IEmbeddingGenerator<TInput,TEmbedding> インターフェイスは、埋め込みの汎用ジェネレーターを表します。 ジェネリック型パラメーターの場合、 TInput は埋め込まれる入力値の型であり、 TEmbedding は生成された埋め込みの型であり、 Embedding クラスから継承されます。
Embedding クラスは、 IEmbeddingGeneratorによって生成された埋め込みの基底クラスとして機能します。 埋め込みに関連付けられているメタデータとデータを格納および管理するように設計されています。
Embedding<T>などの派生型は、具象埋め込みベクター データを提供します。 たとえば、 Embedding<float> は埋め込みデータにアクセスするための ReadOnlyMemory<float> Vector { get; } プロパティを公開します。
IEmbeddingGenerator インターフェイスは、オプションの構成とキャンセルのサポートを使用して、入力値のコレクションの埋め込みを非同期的に生成するメソッドを定義します。 また、ジェネレーターを記述するメタデータも提供され、ジェネレーターまたはその基になるサービスによって提供できる厳密に型指定されたサービスを取得できます。
埋め込みを作成する
IEmbeddingGenerator<TInput,TEmbedding> で実行される主な操作は、 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()));
}
アクセラレータ拡張メソッドは、1 つの入力から埋め込みベクターを生成するなど、一般的なケースを簡略化するためにも存在します。
ReadOnlyMemory<float> vector = await generator.GenerateVectorAsync("What is AI?");
機能のパイプライン
IChatClient と同様に、 IEmbeddingGenerator 実装を階層化できます。
Microsoft.Extensions.AI には、キャッシュとテレメトリの 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 を使用すると、 IEmbeddingGeneratorの機能を拡張するカスタム ミドルウェアを構築できます。
DelegatingEmbeddingGenerator<TInput,TEmbedding> クラスは、操作を別の IEmbeddingGenerator<TInput, TEmbedding> インスタンスに委任する埋め込みジェネレーターを作成するための基底クラスとして機能する IEmbeddingGenerator<TInput, TEmbedding> インターフェイスの実装です。 これにより、複数のジェネレーターを任意の順序でチェーンし、基になるジェネレーターに呼び出しを渡すことができます。 このクラスは、内部ジェネレーター インスタンスに呼び出しを転送する GenerateAsync や Disposeなどのメソッドの既定の実装を提供し、柔軟でモジュール式の埋め込み生成を可能にします。
次に、埋め込み生成要求をレート制限する、このような委任埋め込みジェネレーターの実装例を示します。
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);
}
}
これを任意の IEmbeddingGenerator<string, Embedding<float>> に重ねて、すべての埋め込み生成操作をレート制限できます。
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()));
}
このようにして、レート制限機能を提供するために、 RateLimitingEmbeddingGenerator を他の IEmbeddingGenerator<string, Embedding<float>> インスタンスと共に構成できます。
実装の例
ほとんどのユーザーは、 IEmbeddingGenerator インターフェイスを実装する必要はありません。 ただし、ライブラリの作成者の場合は、これらの実装例を参照すると役に立つ場合があります。
次のコードは、 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を参照してください。
.NET