зеркало из https://github.com/dotnet/extensions.git
EmbeddingGeneratorBuilder API updates (#5647)
This commit is contained in:
Родитель
aa6e8f0bbe
Коммит
09094aebc2
|
@ -432,10 +432,11 @@ var tracerProvider = OpenTelemetry.Sdk.CreateTracerProviderBuilder()
|
|||
|
||||
// Explore changing the order of the intermediate "Use" calls to see that impact
|
||||
// that has on what gets cached, traced, etc.
|
||||
IEmbeddingGenerator<string, Embedding<float>> generator = new EmbeddingGeneratorBuilder<string, Embedding<float>>()
|
||||
var generator = new EmbeddingGeneratorBuilder<string, Embedding<float>>(
|
||||
new SampleEmbeddingGenerator(new Uri("http://coolsite.ai"), "my-custom-model"))
|
||||
.UseDistributedCache(new MemoryDistributedCache(Options.Create(new MemoryDistributedCacheOptions())))
|
||||
.UseOpenTelemetry(sourceName)
|
||||
.Use(new SampleEmbeddingGenerator(new Uri("http://coolsite.ai"), "my-custom-model"));
|
||||
.Build();
|
||||
|
||||
var embeddings = await generator.GenerateAsync(
|
||||
[
|
||||
|
|
|
@ -210,9 +210,9 @@ IDistributedCache cache = new MemoryDistributedCache(Options.Create(new MemoryDi
|
|||
IEmbeddingGenerator<string, Embedding<float>> ollamaGenerator =
|
||||
new OllamaEmbeddingGenerator(new Uri("http://localhost:11434/"), "all-minilm");
|
||||
|
||||
IEmbeddingGenerator<string, Embedding<float>> generator = new EmbeddingGeneratorBuilder<string, Embedding<float>>()
|
||||
IEmbeddingGenerator<string, Embedding<float>> generator = new EmbeddingGeneratorBuilder<string, Embedding<float>>(ollamaGenerator)
|
||||
.UseDistributedCache(cache)
|
||||
.Use(ollamaGenerator);
|
||||
.Build();
|
||||
|
||||
foreach (var prompt in new[] { "What is AI?", "What is .NET?", "What is AI?" })
|
||||
{
|
||||
|
@ -256,8 +256,7 @@ var builder = WebApplication.CreateBuilder(args);
|
|||
builder.Services.AddChatClient(
|
||||
new OllamaChatClient(new Uri("http://localhost:11434/"), "llama3.1"));
|
||||
|
||||
builder.Services.AddEmbeddingGenerator<string,Embedding<float>>(g =>
|
||||
g.Use(new OllamaEmbeddingGenerator(endpoint, "all-minilm")));
|
||||
builder.Services.AddEmbeddingGenerator(new OllamaEmbeddingGenerator(endpoint, "all-minilm"));
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
|
|
|
@ -233,9 +233,9 @@ IEmbeddingGenerator<string, Embedding<float>> openAIGenerator =
|
|||
new OpenAIClient(Environment.GetEnvironmentVariable("OPENAI_API_KEY"))
|
||||
.AsEmbeddingGenerator("text-embedding-3-small");
|
||||
|
||||
IEmbeddingGenerator<string, Embedding<float>> generator = new EmbeddingGeneratorBuilder<string, Embedding<float>>()
|
||||
IEmbeddingGenerator<string, Embedding<float>> generator = new EmbeddingGeneratorBuilder<string, Embedding<float>>(openAIGenerator)
|
||||
.UseDistributedCache(cache)
|
||||
.Use(openAIGenerator);
|
||||
.Build();
|
||||
|
||||
foreach (var prompt in new[] { "What is AI?", "What is .NET?", "What is AI?" })
|
||||
{
|
||||
|
@ -284,8 +284,8 @@ builder.Services.AddSingleton(new OpenAIClient(builder.Configuration["OPENAI_API
|
|||
builder.Services.AddChatClient(services =>
|
||||
services.GetRequiredService<OpenAIClient>().AsChatClient("gpt-4o-mini"));
|
||||
|
||||
builder.Services.AddEmbeddingGenerator<string, Embedding<float>>(g =>
|
||||
g.Use(g.Services.GetRequiredService<OpenAIClient>().AsEmbeddingGenerator("text-embedding-3-small")));
|
||||
builder.Services.AddEmbeddingGenerator(services =>
|
||||
services.GetRequiredService<OpenAIClient>().AsEmbeddingGenerator("text-embedding-3-small"));
|
||||
|
||||
var app = builder.Build();
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ namespace Microsoft.Extensions.AI;
|
|||
/// <summary>A builder for creating pipelines of <see cref="IChatClient"/>.</summary>
|
||||
public sealed class ChatClientBuilder
|
||||
{
|
||||
private Func<IServiceProvider, IChatClient> _innerClientFactory;
|
||||
private readonly Func<IServiceProvider, IChatClient> _innerClientFactory;
|
||||
|
||||
/// <summary>The registered client factory instances.</summary>
|
||||
private List<Func<IServiceProvider, IChatClient, IChatClient>>? _clientFactories;
|
||||
|
@ -30,7 +30,7 @@ public sealed class ChatClientBuilder
|
|||
_innerClientFactory = Throw.IfNull(innerClientFactory);
|
||||
}
|
||||
|
||||
/// <summary>Returns an <see cref="IChatClient"/> that represents the entire pipeline. Calls to this instance will pass through each of the pipeline stages in turn.</summary>
|
||||
/// <summary>Builds an <see cref="IChatClient"/> that represents the entire pipeline. Calls to this instance will pass through each of the pipeline stages in turn.</summary>
|
||||
/// <param name="services">
|
||||
/// The <see cref="IServiceProvider"/> that should provide services to the <see cref="IChatClient"/> instances.
|
||||
/// If null, an empty <see cref="IServiceProvider"/> will be used.
|
||||
|
|
|
@ -37,7 +37,7 @@ public static class ChatClientBuilderServiceCollectionExtensions
|
|||
return builder;
|
||||
}
|
||||
|
||||
/// <summary>Registers a singleton <see cref="IChatClient"/> in the <see cref="IServiceCollection"/>.</summary>
|
||||
/// <summary>Registers a keyed singleton <see cref="IChatClient"/> in the <see cref="IServiceCollection"/>.</summary>
|
||||
/// <param name="serviceCollection">The <see cref="IServiceCollection"/> to which the client should be added.</param>
|
||||
/// <param name="serviceKey">The key with which to associate the client.</param>
|
||||
/// <param name="innerClient">The inner <see cref="IChatClient"/> that represents the underlying backend.</param>
|
||||
|
@ -49,7 +49,7 @@ public static class ChatClientBuilderServiceCollectionExtensions
|
|||
IChatClient innerClient)
|
||||
=> AddKeyedChatClient(serviceCollection, serviceKey, _ => innerClient);
|
||||
|
||||
/// <summary>Registers a singleton <see cref="IChatClient"/> in the <see cref="IServiceCollection"/>.</summary>
|
||||
/// <summary>Registers a keyed singleton <see cref="IChatClient"/> in the <see cref="IServiceCollection"/>.</summary>
|
||||
/// <param name="serviceCollection">The <see cref="IServiceCollection"/> to which the client should be added.</param>
|
||||
/// <param name="serviceKey">The key with which to associate the client.</param>
|
||||
/// <param name="innerClientFactory">A callback that produces the inner <see cref="IChatClient"/> that represents the underlying backend.</param>
|
||||
|
|
|
@ -13,39 +13,45 @@ namespace Microsoft.Extensions.AI;
|
|||
public sealed class EmbeddingGeneratorBuilder<TInput, TEmbedding>
|
||||
where TEmbedding : Embedding
|
||||
{
|
||||
private readonly Func<IServiceProvider, IEmbeddingGenerator<TInput, TEmbedding>> _innerGeneratorFactory;
|
||||
|
||||
/// <summary>The registered client factory instances.</summary>
|
||||
private List<Func<IServiceProvider, IEmbeddingGenerator<TInput, TEmbedding>, IEmbeddingGenerator<TInput, TEmbedding>>>? _generatorFactories;
|
||||
|
||||
/// <summary>Initializes a new instance of the <see cref="EmbeddingGeneratorBuilder{TInput, TEmbedding}"/> class.</summary>
|
||||
/// <param name="services">The service provider to use for dependency injection.</param>
|
||||
public EmbeddingGeneratorBuilder(IServiceProvider? services = null)
|
||||
/// <param name="innerGenerator">The inner <see cref="EmbeddingGeneratorBuilder{TInput, TEmbedding}"/> that represents the underlying backend.</param>
|
||||
public EmbeddingGeneratorBuilder(IEmbeddingGenerator<TInput, TEmbedding> innerGenerator)
|
||||
{
|
||||
Services = services ?? EmptyServiceProvider.Instance;
|
||||
_ = Throw.IfNull(innerGenerator);
|
||||
_innerGeneratorFactory = _ => innerGenerator;
|
||||
}
|
||||
|
||||
/// <summary>Gets the <see cref="IServiceProvider"/> associated with the builder instance.</summary>
|
||||
public IServiceProvider Services { get; }
|
||||
/// <summary>Initializes a new instance of the <see cref="EmbeddingGeneratorBuilder{TInput, TEmbedding}"/> class.</summary>
|
||||
/// <param name="innerGeneratorFactory">A callback that produces the inner <see cref="EmbeddingGeneratorBuilder{TInput, TEmbedding}"/> that represents the underlying backend.</param>
|
||||
public EmbeddingGeneratorBuilder(Func<IServiceProvider, IEmbeddingGenerator<TInput, TEmbedding>> innerGeneratorFactory)
|
||||
{
|
||||
_innerGeneratorFactory = Throw.IfNull(innerGeneratorFactory);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Builds an instance of <see cref="IEmbeddingGenerator{TInput, TEmbedding}"/> using the specified inner generator.
|
||||
/// Builds an <see cref="IEmbeddingGenerator{TInput, TEmbedding}"/> that represents the entire pipeline. Calls to this instance will pass through each of the pipeline stages in turn.
|
||||
/// </summary>
|
||||
/// <param name="innerGenerator">The inner generator to use.</param>
|
||||
/// <returns>An instance of <see cref="IEmbeddingGenerator{TInput, TEmbedding}"/>.</returns>
|
||||
/// <remarks>
|
||||
/// If there are any factories registered with this builder, <paramref name="innerGenerator"/> is used as a seed to
|
||||
/// the last factory, and the result of each factory delegate is passed to the previously registered factory.
|
||||
/// The final result is then returned from this call.
|
||||
/// </remarks>
|
||||
public IEmbeddingGenerator<TInput, TEmbedding> Use(IEmbeddingGenerator<TInput, TEmbedding> innerGenerator)
|
||||
/// <param name="services">
|
||||
/// The <see cref="IServiceProvider"/> that should provide services to the <see cref="IEmbeddingGenerator{TInput, TEmbedding}"/> instances.
|
||||
/// If null, an empty <see cref="IServiceProvider"/> will be used.
|
||||
/// </param>
|
||||
/// <returns>An instance of <see cref="IEmbeddingGenerator{TInput, TEmbedding}"/> that represents the entire pipeline.</returns>
|
||||
public IEmbeddingGenerator<TInput, TEmbedding> Build(IServiceProvider? services = null)
|
||||
{
|
||||
var embeddingGenerator = Throw.IfNull(innerGenerator);
|
||||
services ??= EmptyServiceProvider.Instance;
|
||||
var embeddingGenerator = _innerGeneratorFactory(services);
|
||||
|
||||
// To match intuitive expectations, apply the factories in reverse order, so that the first factory added is the outermost.
|
||||
if (_generatorFactories is not null)
|
||||
{
|
||||
for (var i = _generatorFactories.Count - 1; i >= 0; i--)
|
||||
{
|
||||
embeddingGenerator = _generatorFactories[i](Services, embeddingGenerator) ??
|
||||
embeddingGenerator = _generatorFactories[i](services, embeddingGenerator) ??
|
||||
throw new InvalidOperationException(
|
||||
$"The {nameof(IEmbeddingGenerator<TInput, TEmbedding>)} entry at index {i} returned null. " +
|
||||
$"Ensure that the callbacks passed to {nameof(Use)} return non-null {nameof(IEmbeddingGenerator<TInput, TEmbedding>)} instances.");
|
||||
|
|
|
@ -10,44 +10,74 @@ namespace Microsoft.Extensions.DependencyInjection;
|
|||
/// <summary>Provides extension methods for registering <see cref="IEmbeddingGenerator{TInput, TEmbedding}"/> with a <see cref="IServiceCollection"/>.</summary>
|
||||
public static class EmbeddingGeneratorBuilderServiceCollectionExtensions
|
||||
{
|
||||
/// <summary>Adds a embedding generator to the <see cref="IServiceCollection"/>.</summary>
|
||||
/// <summary>Registers a singleton embedding generator in the <see cref="IServiceCollection"/>.</summary>
|
||||
/// <typeparam name="TInput">The type from which embeddings will be generated.</typeparam>
|
||||
/// <typeparam name="TEmbedding">The type of embeddings to generate.</typeparam>
|
||||
/// <param name="services">The <see cref="IServiceCollection"/> to which the generator should be added.</param>
|
||||
/// <param name="generatorFactory">The factory to use to construct the <see cref="IEmbeddingGenerator{TInput, TEmbedding}"/> instance.</param>
|
||||
/// <returns>The <paramref name="services"/> collection.</returns>
|
||||
/// <remarks>The generator is registered as a scoped service.</remarks>
|
||||
public static IServiceCollection AddEmbeddingGenerator<TInput, TEmbedding>(
|
||||
this IServiceCollection services,
|
||||
Func<EmbeddingGeneratorBuilder<TInput, TEmbedding>, IEmbeddingGenerator<TInput, TEmbedding>> generatorFactory)
|
||||
/// <param name="serviceCollection">The <see cref="IServiceCollection"/> to which the generator should be added.</param>
|
||||
/// <param name="innerGenerator">The inner <see cref="IEmbeddingGenerator{TInput, TEmbedding}"/> that represents the underlying backend.</param>
|
||||
/// <returns>An <see cref="EmbeddingGeneratorBuilder{TInput, TEmbedding}"/> that can be used to build a pipeline around the inner generator.</returns>
|
||||
/// <remarks>The generator is registered as a singleton service.</remarks>
|
||||
public static EmbeddingGeneratorBuilder<TInput, TEmbedding> AddEmbeddingGenerator<TInput, TEmbedding>(
|
||||
this IServiceCollection serviceCollection,
|
||||
IEmbeddingGenerator<TInput, TEmbedding> innerGenerator)
|
||||
where TEmbedding : Embedding
|
||||
=> AddEmbeddingGenerator(serviceCollection, _ => innerGenerator);
|
||||
|
||||
/// <summary>Registers a singleton embedding generator in the <see cref="IServiceCollection"/>.</summary>
|
||||
/// <typeparam name="TInput">The type from which embeddings will be generated.</typeparam>
|
||||
/// <typeparam name="TEmbedding">The type of embeddings to generate.</typeparam>
|
||||
/// <param name="serviceCollection">The <see cref="IServiceCollection"/> to which the generator should be added.</param>
|
||||
/// <param name="innerGeneratorFactory">A callback that produces the inner <see cref="IEmbeddingGenerator{TInput, TEmbedding}"/> that represents the underlying backend.</param>
|
||||
/// <returns>An <see cref="EmbeddingGeneratorBuilder{TInput, TEmbedding}"/> that can be used to build a pipeline around the inner generator.</returns>
|
||||
/// <remarks>The generator is registered as a singleton service.</remarks>
|
||||
public static EmbeddingGeneratorBuilder<TInput, TEmbedding> AddEmbeddingGenerator<TInput, TEmbedding>(
|
||||
this IServiceCollection serviceCollection,
|
||||
Func<IServiceProvider, IEmbeddingGenerator<TInput, TEmbedding>> innerGeneratorFactory)
|
||||
where TEmbedding : Embedding
|
||||
{
|
||||
_ = Throw.IfNull(services);
|
||||
_ = Throw.IfNull(generatorFactory);
|
||||
_ = Throw.IfNull(serviceCollection);
|
||||
_ = Throw.IfNull(innerGeneratorFactory);
|
||||
|
||||
return services.AddScoped(services =>
|
||||
generatorFactory(new EmbeddingGeneratorBuilder<TInput, TEmbedding>(services)));
|
||||
var builder = new EmbeddingGeneratorBuilder<TInput, TEmbedding>(innerGeneratorFactory);
|
||||
_ = serviceCollection.AddSingleton(builder.Build);
|
||||
return builder;
|
||||
}
|
||||
|
||||
/// <summary>Adds an embedding generator to the <see cref="IServiceCollection"/>.</summary>
|
||||
/// <summary>Registers a keyed singleton embedding generator in the <see cref="IServiceCollection"/>.</summary>
|
||||
/// <typeparam name="TInput">The type from which embeddings will be generated.</typeparam>
|
||||
/// <typeparam name="TEmbedding">The type of embeddings to generate.</typeparam>
|
||||
/// <param name="services">The <see cref="IServiceCollection"/> to which the service should be added.</param>
|
||||
/// <param name="serviceCollection">The <see cref="IServiceCollection"/> to which the generator should be added.</param>
|
||||
/// <param name="serviceKey">The key with which to associated the generator.</param>
|
||||
/// <param name="generatorFactory">The factory to use to construct the <see cref="IEmbeddingGenerator{TInput, TEmbedding}"/> instance.</param>
|
||||
/// <returns>The <paramref name="services"/> collection.</returns>
|
||||
/// <remarks>The generator is registered as a scoped service.</remarks>
|
||||
public static IServiceCollection AddKeyedEmbeddingGenerator<TInput, TEmbedding>(
|
||||
this IServiceCollection services,
|
||||
/// <param name="innerGenerator">The inner <see cref="IEmbeddingGenerator{TInput, TEmbedding}"/> that represents the underlying backend.</param>
|
||||
/// <returns>An <see cref="EmbeddingGeneratorBuilder{TInput, TEmbedding}"/> that can be used to build a pipeline around the inner generator.</returns>
|
||||
/// <remarks>The generator is registered as a singleton service.</remarks>
|
||||
public static EmbeddingGeneratorBuilder<TInput, TEmbedding> AddKeyedEmbeddingGenerator<TInput, TEmbedding>(
|
||||
this IServiceCollection serviceCollection,
|
||||
object serviceKey,
|
||||
Func<EmbeddingGeneratorBuilder<TInput, TEmbedding>, IEmbeddingGenerator<TInput, TEmbedding>> generatorFactory)
|
||||
IEmbeddingGenerator<TInput, TEmbedding> innerGenerator)
|
||||
where TEmbedding : Embedding
|
||||
=> AddKeyedEmbeddingGenerator(serviceCollection, serviceKey, _ => innerGenerator);
|
||||
|
||||
/// <summary>Registers a keyed singleton embedding generator in the <see cref="IServiceCollection"/>.</summary>
|
||||
/// <typeparam name="TInput">The type from which embeddings will be generated.</typeparam>
|
||||
/// <typeparam name="TEmbedding">The type of embeddings to generate.</typeparam>
|
||||
/// <param name="serviceCollection">The <see cref="IServiceCollection"/> to which the generator should be added.</param>
|
||||
/// <param name="serviceKey">The key with which to associated the generator.</param>
|
||||
/// <param name="innerGeneratorFactory">A callback that produces the inner <see cref="IEmbeddingGenerator{TInput, TEmbedding}"/> that represents the underlying backend.</param>
|
||||
/// <returns>An <see cref="EmbeddingGeneratorBuilder{TInput, TEmbedding}"/> that can be used to build a pipeline around the inner generator.</returns>
|
||||
/// <remarks>The generator is registered as a singleton service.</remarks>
|
||||
public static EmbeddingGeneratorBuilder<TInput, TEmbedding> AddKeyedEmbeddingGenerator<TInput, TEmbedding>(
|
||||
this IServiceCollection serviceCollection,
|
||||
object serviceKey,
|
||||
Func<IServiceProvider, IEmbeddingGenerator<TInput, TEmbedding>> innerGeneratorFactory)
|
||||
where TEmbedding : Embedding
|
||||
{
|
||||
_ = Throw.IfNull(services);
|
||||
_ = Throw.IfNull(serviceCollection);
|
||||
_ = Throw.IfNull(serviceKey);
|
||||
_ = Throw.IfNull(generatorFactory);
|
||||
_ = Throw.IfNull(innerGeneratorFactory);
|
||||
|
||||
return services.AddKeyedScoped(serviceKey, (services, _) =>
|
||||
generatorFactory(new EmbeddingGeneratorBuilder<TInput, TEmbedding>(services)));
|
||||
var builder = new EmbeddingGeneratorBuilder<TInput, TEmbedding>(innerGeneratorFactory);
|
||||
_ = serviceCollection.AddKeyedSingleton(serviceKey, (services, _) => builder.Build(services));
|
||||
return builder;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -63,10 +63,10 @@ public class AzureAIInferenceEmbeddingGeneratorTests
|
|||
Assert.Same(embeddingGenerator, embeddingGenerator.GetService<IEmbeddingGenerator<string, Embedding<float>>>());
|
||||
Assert.Same(client, embeddingGenerator.GetService<EmbeddingsClient>());
|
||||
|
||||
using IEmbeddingGenerator<string, Embedding<float>> pipeline = new EmbeddingGeneratorBuilder<string, Embedding<float>>()
|
||||
using IEmbeddingGenerator<string, Embedding<float>> pipeline = new EmbeddingGeneratorBuilder<string, Embedding<float>>(embeddingGenerator)
|
||||
.UseOpenTelemetry()
|
||||
.UseDistributedCache(new MemoryDistributedCache(Options.Options.Create(new MemoryDistributedCacheOptions())))
|
||||
.Use(embeddingGenerator);
|
||||
.Build();
|
||||
|
||||
Assert.NotNull(pipeline.GetService<DistributedCachingEmbeddingGenerator<string, Embedding<float>>>());
|
||||
Assert.NotNull(pipeline.GetService<CachingEmbeddingGenerator<string, Embedding<float>>>());
|
||||
|
|
|
@ -81,10 +81,10 @@ public abstract class EmbeddingGeneratorIntegrationTests : IDisposable
|
|||
{
|
||||
SkipIfNotEnabled();
|
||||
|
||||
using var generator = new EmbeddingGeneratorBuilder<string, Embedding<float>>()
|
||||
using var generator = new EmbeddingGeneratorBuilder<string, Embedding<float>>(CreateEmbeddingGenerator()!)
|
||||
.UseDistributedCache(new MemoryDistributedCache(Options.Options.Create(new MemoryDistributedCacheOptions())))
|
||||
.UseCallCounting()
|
||||
.Use(CreateEmbeddingGenerator()!);
|
||||
.Build();
|
||||
|
||||
string input = "Red, White, and Blue";
|
||||
var embedding1 = await generator.GenerateEmbeddingAsync(input);
|
||||
|
@ -110,9 +110,9 @@ public abstract class EmbeddingGeneratorIntegrationTests : IDisposable
|
|||
.AddInMemoryExporter(activities)
|
||||
.Build();
|
||||
|
||||
var embeddingGenerator = new EmbeddingGeneratorBuilder<string, Embedding<float>>()
|
||||
var embeddingGenerator = new EmbeddingGeneratorBuilder<string, Embedding<float>>(CreateEmbeddingGenerator()!)
|
||||
.UseOpenTelemetry(sourceName: sourceName)
|
||||
.Use(CreateEmbeddingGenerator()!);
|
||||
.Build();
|
||||
|
||||
_ = await embeddingGenerator.GenerateEmbeddingAsync("Hello, world!");
|
||||
|
||||
|
|
|
@ -29,10 +29,10 @@ public class OllamaEmbeddingGeneratorTests
|
|||
Assert.Same(generator, generator.GetService<OllamaEmbeddingGenerator>());
|
||||
Assert.Same(generator, generator.GetService<IEmbeddingGenerator<string, Embedding<float>>>());
|
||||
|
||||
using IEmbeddingGenerator<string, Embedding<float>> pipeline = new EmbeddingGeneratorBuilder<string, Embedding<float>>()
|
||||
using IEmbeddingGenerator<string, Embedding<float>> pipeline = new EmbeddingGeneratorBuilder<string, Embedding<float>>(generator)
|
||||
.UseOpenTelemetry()
|
||||
.UseDistributedCache(new MemoryDistributedCache(Options.Options.Create(new MemoryDistributedCacheOptions())))
|
||||
.Use(generator);
|
||||
.Build();
|
||||
|
||||
Assert.NotNull(pipeline.GetService<DistributedCachingEmbeddingGenerator<string, Embedding<float>>>());
|
||||
Assert.NotNull(pipeline.GetService<CachingEmbeddingGenerator<string, Embedding<float>>>());
|
||||
|
|
|
@ -78,10 +78,10 @@ public class OpenAIEmbeddingGeneratorTests
|
|||
|
||||
Assert.NotNull(embeddingGenerator.GetService<EmbeddingClient>());
|
||||
|
||||
using IEmbeddingGenerator<string, Embedding<float>> pipeline = new EmbeddingGeneratorBuilder<string, Embedding<float>>()
|
||||
using IEmbeddingGenerator<string, Embedding<float>> pipeline = new EmbeddingGeneratorBuilder<string, Embedding<float>>(embeddingGenerator)
|
||||
.UseOpenTelemetry()
|
||||
.UseDistributedCache(new MemoryDistributedCache(Options.Options.Create(new MemoryDistributedCacheOptions())))
|
||||
.Use(embeddingGenerator);
|
||||
.Build();
|
||||
|
||||
Assert.NotNull(pipeline.GetService<DistributedCachingEmbeddingGenerator<string, Embedding<float>>>());
|
||||
Assert.NotNull(pipeline.GetService<CachingEmbeddingGenerator<string, Embedding<float>>>());
|
||||
|
@ -100,10 +100,10 @@ public class OpenAIEmbeddingGeneratorTests
|
|||
Assert.Same(embeddingGenerator, embeddingGenerator.GetService<IEmbeddingGenerator<string, Embedding<float>>>());
|
||||
Assert.Same(openAIClient, embeddingGenerator.GetService<EmbeddingClient>());
|
||||
|
||||
using IEmbeddingGenerator<string, Embedding<float>> pipeline = new EmbeddingGeneratorBuilder<string, Embedding<float>>()
|
||||
using IEmbeddingGenerator<string, Embedding<float>> pipeline = new EmbeddingGeneratorBuilder<string, Embedding<float>>(embeddingGenerator)
|
||||
.UseOpenTelemetry()
|
||||
.UseDistributedCache(new MemoryDistributedCache(Options.Options.Create(new MemoryDistributedCacheOptions())))
|
||||
.Use(embeddingGenerator);
|
||||
.Build();
|
||||
|
||||
Assert.NotNull(pipeline.GetService<DistributedCachingEmbeddingGenerator<string, Embedding<float>>>());
|
||||
Assert.NotNull(pipeline.GetService<CachingEmbeddingGenerator<string, Embedding<float>>>());
|
||||
|
|
|
@ -20,7 +20,8 @@ public class ConfigureOptionsEmbeddingGeneratorTests
|
|||
[Fact]
|
||||
public void ConfigureOptions_InvalidArgs_Throws()
|
||||
{
|
||||
var builder = new EmbeddingGeneratorBuilder<string, Embedding<float>>();
|
||||
using var innerGenerator = new TestEmbeddingGenerator();
|
||||
var builder = new EmbeddingGeneratorBuilder<string, Embedding<float>>(innerGenerator);
|
||||
Assert.Throws<ArgumentNullException>("configure", () => builder.ConfigureOptions(null!));
|
||||
}
|
||||
|
||||
|
@ -44,7 +45,7 @@ public class ConfigureOptionsEmbeddingGeneratorTests
|
|||
}
|
||||
};
|
||||
|
||||
using var generator = new EmbeddingGeneratorBuilder<string, Embedding<float>>()
|
||||
using var generator = new EmbeddingGeneratorBuilder<string, Embedding<float>>(innerGenerator)
|
||||
.ConfigureOptions(options =>
|
||||
{
|
||||
Assert.NotSame(providedOptions, options);
|
||||
|
@ -59,7 +60,7 @@ public class ConfigureOptionsEmbeddingGeneratorTests
|
|||
|
||||
returnedOptions = options;
|
||||
})
|
||||
.Use(innerGenerator);
|
||||
.Build();
|
||||
|
||||
var embeddings = await generator.GenerateAsync([], providedOptions, cts.Token);
|
||||
Assert.Same(expectedEmbeddings, embeddings);
|
||||
|
|
|
@ -321,12 +321,12 @@ public class DistributedCachingEmbeddingGeneratorTest
|
|||
return Task.FromResult<GeneratedEmbeddings<Embedding<float>>>([_expectedEmbedding]);
|
||||
},
|
||||
};
|
||||
using var outer = new EmbeddingGeneratorBuilder<string, Embedding<float>>(services)
|
||||
using var outer = new EmbeddingGeneratorBuilder<string, Embedding<float>>(testGenerator)
|
||||
.UseDistributedCache(configure: instance =>
|
||||
{
|
||||
instance.JsonSerializerOptions = TestJsonSerializerContext.Default.Options;
|
||||
})
|
||||
.Use(testGenerator);
|
||||
.Build(services);
|
||||
|
||||
// Act: Make a request that should populate the cache
|
||||
Assert.Empty(_storage.Keys);
|
||||
|
|
|
@ -13,32 +13,37 @@ public class EmbeddingGeneratorBuilderTests
|
|||
public void PassesServiceProviderToFactories()
|
||||
{
|
||||
var expectedServiceProvider = new ServiceCollection().BuildServiceProvider();
|
||||
using var expectedResult = new TestEmbeddingGenerator();
|
||||
var builder = new EmbeddingGeneratorBuilder<string, Embedding<float>>(expectedServiceProvider);
|
||||
using var expectedOuterGenerator = new TestEmbeddingGenerator();
|
||||
using var expectedInnerGenerator = new TestEmbeddingGenerator();
|
||||
|
||||
builder.Use((serviceProvider, innerClient) =>
|
||||
var builder = new EmbeddingGeneratorBuilder<string, Embedding<float>>(services =>
|
||||
{
|
||||
Assert.Same(expectedServiceProvider, serviceProvider);
|
||||
return expectedResult;
|
||||
Assert.Same(expectedServiceProvider, services);
|
||||
return expectedInnerGenerator;
|
||||
});
|
||||
|
||||
using var innerGenerator = new TestEmbeddingGenerator();
|
||||
Assert.Equal(expectedResult, builder.Use(innerGenerator));
|
||||
builder.Use((services, innerClient) =>
|
||||
{
|
||||
Assert.Same(expectedServiceProvider, services);
|
||||
return expectedOuterGenerator;
|
||||
});
|
||||
|
||||
Assert.Equal(expectedOuterGenerator, builder.Build(expectedServiceProvider));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void BuildsPipelineInOrderAdded()
|
||||
{
|
||||
// Arrange
|
||||
using var expectedInnerService = new TestEmbeddingGenerator();
|
||||
var builder = new EmbeddingGeneratorBuilder<string, Embedding<float>>();
|
||||
using var expectedInnerGenerator = new TestEmbeddingGenerator();
|
||||
var builder = new EmbeddingGeneratorBuilder<string, Embedding<float>>(expectedInnerGenerator);
|
||||
|
||||
builder.Use(next => new InnerServiceCapturingEmbeddingGenerator("First", next));
|
||||
builder.Use(next => new InnerServiceCapturingEmbeddingGenerator("Second", next));
|
||||
builder.Use(next => new InnerServiceCapturingEmbeddingGenerator("Third", next));
|
||||
|
||||
// Act
|
||||
var first = (InnerServiceCapturingEmbeddingGenerator)builder.Use(expectedInnerService);
|
||||
var first = (InnerServiceCapturingEmbeddingGenerator)builder.Build();
|
||||
|
||||
// Assert
|
||||
Assert.Equal("First", first.Name);
|
||||
|
@ -46,29 +51,28 @@ public class EmbeddingGeneratorBuilderTests
|
|||
Assert.Equal("Second", second.Name);
|
||||
var third = (InnerServiceCapturingEmbeddingGenerator)second.InnerGenerator;
|
||||
Assert.Equal("Third", third.Name);
|
||||
Assert.Same(expectedInnerService, third.InnerGenerator);
|
||||
Assert.Same(expectedInnerGenerator, third.InnerGenerator);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DoesNotAcceptNullInnerService()
|
||||
{
|
||||
Assert.Throws<ArgumentNullException>(() => new EmbeddingGeneratorBuilder<string, Embedding<float>>().Use((IEmbeddingGenerator<string, Embedding<float>>)null!));
|
||||
Assert.Throws<ArgumentNullException>(() => new EmbeddingGeneratorBuilder<string, Embedding<float>>((IEmbeddingGenerator<string, Embedding<float>>)null!));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DoesNotAcceptNullFactories()
|
||||
{
|
||||
var builder = new EmbeddingGeneratorBuilder<string, Embedding<float>>();
|
||||
Assert.Throws<ArgumentNullException>(() => builder.Use((Func<IEmbeddingGenerator<string, Embedding<float>>, IEmbeddingGenerator<string, Embedding<float>>>)null!));
|
||||
Assert.Throws<ArgumentNullException>(() => builder.Use((Func<IServiceProvider, IEmbeddingGenerator<string, Embedding<float>>, IEmbeddingGenerator<string, Embedding<float>>>)null!));
|
||||
Assert.Throws<ArgumentNullException>(() => new EmbeddingGeneratorBuilder<string, Embedding<float>>((Func<IServiceProvider, IEmbeddingGenerator<string, Embedding<float>>>)null!));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DoesNotAllowFactoriesToReturnNull()
|
||||
{
|
||||
var builder = new EmbeddingGeneratorBuilder<string, Embedding<float>>();
|
||||
using var innerGenerator = new TestEmbeddingGenerator();
|
||||
var builder = new EmbeddingGeneratorBuilder<string, Embedding<float>>(innerGenerator);
|
||||
builder.Use(_ => null!);
|
||||
var ex = Assert.Throws<InvalidOperationException>(() => builder.Use(new TestEmbeddingGenerator()));
|
||||
var ex = Assert.Throws<InvalidOperationException>(() => builder.Build());
|
||||
Assert.Contains("entry at index 0", ex.Message);
|
||||
}
|
||||
|
||||
|
|
|
@ -39,9 +39,9 @@ public class LoggingEmbeddingGeneratorTests
|
|||
},
|
||||
};
|
||||
|
||||
using IEmbeddingGenerator<string, Embedding<float>> generator = new EmbeddingGeneratorBuilder<string, Embedding<float>>(services)
|
||||
using IEmbeddingGenerator<string, Embedding<float>> generator = new EmbeddingGeneratorBuilder<string, Embedding<float>>(innerGenerator)
|
||||
.UseLogging()
|
||||
.Use(innerGenerator);
|
||||
.Build(services);
|
||||
|
||||
await generator.GenerateEmbeddingAsync("Blue whale");
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче