From e95f93c5923e3226ec8448db561213c28845ecd6 Mon Sep 17 00:00:00 2001 From: Laurianti Date: Wed, 14 Oct 2026 11:57:29 +0200 Subject: [PATCH 1/2] .Net: Add Chroma to the vector store samples --- dotnet/Directory.Packages.props | 1 + dotnet/samples/Concepts/Concepts.csproj | 1 + .../VectorStoreChromaContainerFixture.cs | 56 ++++++++++++ .../VectorStoreFixtures/VectorStoreInfra.cs | 40 +++++++++ ...e_VectorSearch_MultiStore_AzureAISearch.cs | 1 + ...torStore_VectorSearch_MultiStore_Chroma.cs | 86 +++++++++++++++++++ ...torStore_VectorSearch_MultiStore_Common.cs | 1 + ...rStore_VectorSearch_MultiStore_InMemory.cs | 1 + ...rStore_VectorSearch_MultiStore_Postgres.cs | 1 + ...torStore_VectorSearch_MultiStore_Qdrant.cs | 1 + ...ctorStore_VectorSearch_MultiStore_Redis.cs | 1 + .../Options/ApplicationConfig.cs | 6 ++ .../VectorStoreRAG/Options/ChromaConfig.cs | 16 ++++ .../samples/Demos/VectorStoreRAG/Program.cs | 6 ++ dotnet/samples/Demos/VectorStoreRAG/README.md | 17 ++++ .../VectorStoreRAG/VectorStoreRAG.csproj | 1 + .../Demos/VectorStoreRAG/appsettings.json | 3 + 17 files changed, 239 insertions(+) create mode 100644 dotnet/samples/Concepts/Memory/VectorStoreFixtures/VectorStoreChromaContainerFixture.cs create mode 100644 dotnet/samples/Concepts/Memory/VectorStore_VectorSearch_MultiStore_Chroma.cs create mode 100644 dotnet/samples/Demos/VectorStoreRAG/Options/ChromaConfig.cs diff --git a/dotnet/Directory.Packages.props b/dotnet/Directory.Packages.props index f4a51a045a48..82fe6178c515 100644 --- a/dotnet/Directory.Packages.props +++ b/dotnet/Directory.Packages.props @@ -189,6 +189,7 @@ + diff --git a/dotnet/samples/Concepts/Concepts.csproj b/dotnet/samples/Concepts/Concepts.csproj index 9633d7893ff9..c9535ba8898d 100644 --- a/dotnet/samples/Concepts/Concepts.csproj +++ b/dotnet/samples/Concepts/Concepts.csproj @@ -53,6 +53,7 @@ + diff --git a/dotnet/samples/Concepts/Memory/VectorStoreFixtures/VectorStoreChromaContainerFixture.cs b/dotnet/samples/Concepts/Memory/VectorStoreFixtures/VectorStoreChromaContainerFixture.cs new file mode 100644 index 000000000000..feb195663838 --- /dev/null +++ b/dotnet/samples/Concepts/Memory/VectorStoreFixtures/VectorStoreChromaContainerFixture.cs @@ -0,0 +1,56 @@ +// Copyright (c) Microsoft. All rights reserved. + +using ChromaDB.Client; +using Docker.DotNet; + +namespace Memory.VectorStoreFixtures; + +/// +/// Fixture to use for creating a Chroma container before tests and delete it after tests. +/// +public class VectorStoreChromaContainerFixture : IAsyncLifetime +{ + private DockerClient? _dockerClient; + private string? _chromaContainerId; + + public async Task InitializeAsync() + { + } + + public async Task ManualInitializeAsync() + { + if (this._chromaContainerId == null) + { + // Connect to docker and start the docker container. + using var dockerClientConfiguration = new DockerClientConfiguration(); + this._dockerClient = dockerClientConfiguration.CreateClient(); + this._chromaContainerId = await VectorStoreInfra.SetupChromaContainerAsync(this._dockerClient); + + // Delay until the Chroma server is ready. + var chromaClient = new ChromaClient("http://localhost:8000"); + var succeeded = false; + var attemptCount = 0; + while (!succeeded && attemptCount++ < 10) + { + try + { + await chromaClient.ListCollectionsAsync(); + succeeded = true; + } + catch (Exception) + { + await Task.Delay(1000); + } + } + } + } + + public async Task DisposeAsync() + { + if (this._dockerClient != null && this._chromaContainerId != null) + { + // Delete docker container. + await VectorStoreInfra.DeleteContainerAsync(this._dockerClient, this._chromaContainerId); + } + } +} diff --git a/dotnet/samples/Concepts/Memory/VectorStoreFixtures/VectorStoreInfra.cs b/dotnet/samples/Concepts/Memory/VectorStoreFixtures/VectorStoreInfra.cs index 77c5e8a55db9..767e7d2de956 100644 --- a/dotnet/samples/Concepts/Memory/VectorStoreFixtures/VectorStoreInfra.cs +++ b/dotnet/samples/Concepts/Memory/VectorStoreFixtures/VectorStoreInfra.cs @@ -10,6 +10,46 @@ namespace Memory.VectorStoreFixtures; /// internal static class VectorStoreInfra { + /// + /// Setup the chroma container by pulling the image and running it. + /// + /// The docker client to create the container with. + /// The id of the container. + public static async Task SetupChromaContainerAsync(DockerClient client) + { + await client.Images.CreateImageAsync( + new ImagesCreateParameters + { + FromImage = "chromadb/chroma", + Tag = "latest", + }, + null, + new Progress()); + + var container = await client.Containers.CreateContainerAsync(new CreateContainerParameters() + { + Image = "chromadb/chroma", + HostConfig = new HostConfig() + { + PortBindings = new Dictionary> + { + {"8000", new List {new() {HostPort = "8000" } }}, + }, + PublishAllPorts = true + }, + ExposedPorts = new Dictionary + { + { "8000", default }, + }, + }); + + await client.Containers.StartContainerAsync( + container.ID, + new ContainerStartParameters()); + + return container.ID; + } + /// /// Setup the postgres pgvector container by pulling the image and running it. /// diff --git a/dotnet/samples/Concepts/Memory/VectorStore_VectorSearch_MultiStore_AzureAISearch.cs b/dotnet/samples/Concepts/Memory/VectorStore_VectorSearch_MultiStore_AzureAISearch.cs index 81cd303017d6..fe565d333a5b 100644 --- a/dotnet/samples/Concepts/Memory/VectorStore_VectorSearch_MultiStore_AzureAISearch.cs +++ b/dotnet/samples/Concepts/Memory/VectorStore_VectorSearch_MultiStore_AzureAISearch.cs @@ -22,6 +22,7 @@ namespace Memory; /// /// /// +/// /// /// To run this sample, you need an already existing Azure AI Search instance. /// To set your secrets use: diff --git a/dotnet/samples/Concepts/Memory/VectorStore_VectorSearch_MultiStore_Chroma.cs b/dotnet/samples/Concepts/Memory/VectorStore_VectorSearch_MultiStore_Chroma.cs new file mode 100644 index 000000000000..826b63230d8b --- /dev/null +++ b/dotnet/samples/Concepts/Memory/VectorStore_VectorSearch_MultiStore_Chroma.cs @@ -0,0 +1,86 @@ +// Copyright (c) Microsoft. All rights reserved. + +using Azure.AI.OpenAI; +using Azure.Identity; +using ChromaDB.Client; +using CommunityToolkit.VectorData.Chroma; +using Memory.VectorStoreFixtures; +using Microsoft.Extensions.AI; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.SemanticKernel; + +namespace Memory; + +/// +/// An example showing how to use common code, that can work with any vector database, with a Chroma database. +/// The common code is in the class. +/// The common code ingests data into the vector store and then searches over that data. +/// This example is part of a set of examples each showing a different vector database. +/// +/// For other databases, see the following classes: +/// +/// +/// +/// +/// +/// +/// To run this sample, you need a local instance of Docker running, since the associated fixture will try and start a Chroma container in the local docker instance. +/// +public class VectorStore_VectorSearch_MultiStore_Chroma(ITestOutputHelper output, VectorStoreChromaContainerFixture chromaFixture) : BaseTest(output), IClassFixture +{ + [Fact] + public async Task ExampleWithDIAsync() + { + // Use the kernel for DI purposes. + var kernelBuilder = Kernel + .CreateBuilder(); + + // Register an embedding generation service with the DI container. + kernelBuilder.AddAzureOpenAIEmbeddingGenerator( + deploymentName: TestConfiguration.AzureOpenAIEmbeddings.DeploymentName, + endpoint: TestConfiguration.AzureOpenAIEmbeddings.Endpoint, + credential: new AzureCliCredential(), + dimensions: 1536); + + // Initialize the Chroma docker container via the fixtures and register the Chroma VectorStore. + await chromaFixture.ManualInitializeAsync(); + kernelBuilder.Services.AddChromaVectorStore("http://localhost:8000"); + + // Register the test output helper common processor with the DI container. + kernelBuilder.Services.AddSingleton(this.Output); + kernelBuilder.Services.AddTransient(); + + // Build the kernel. + var kernel = kernelBuilder.Build(); + + // Build a common processor object using the DI container. + var processor = kernel.GetRequiredService(); + + // Run the process and pass a key generator function to it, to generate unique record keys. + // The key generator function is required, since different vector stores may require different key types. + // E.g. Chroma supports Guid and string keys, but others may not support Guid. + await processor.IngestDataAndSearchAsync("skglossaryWithDI", () => Guid.NewGuid()); + } + + [Fact] + public async Task ExampleWithoutDIAsync() + { + // Create an embedding generation service. + var embeddingGenerator = new AzureOpenAIClient(new Uri(TestConfiguration.AzureOpenAIEmbeddings.Endpoint), new AzureCliCredential()) + .GetEmbeddingClient(TestConfiguration.AzureOpenAIEmbeddings.DeploymentName) + .AsIEmbeddingGenerator(1536); + + // Initialize the Chroma docker container via the fixtures and construct the Chroma VectorStore. + await chromaFixture.ManualInitializeAsync(); + var chromaClient = new ChromaClient("http://localhost:8000"); + var vectorStore = new ChromaVectorStore(chromaClient, ownsClient: true); + + // Create the common processor that works for any vector store. + var processor = new VectorStore_VectorSearch_MultiStore_Common(vectorStore, embeddingGenerator, this.Output); + + // Run the process and pass a key generator function to it, to generate unique record keys. + // The key generator function is required, since different vector stores may require different key types. + // E.g. Chroma supports Guid and string keys, but others may not support Guid. + await processor.IngestDataAndSearchAsync("skglossaryWithoutDI", () => Guid.NewGuid()); + } +} diff --git a/dotnet/samples/Concepts/Memory/VectorStore_VectorSearch_MultiStore_Common.cs b/dotnet/samples/Concepts/Memory/VectorStore_VectorSearch_MultiStore_Common.cs index cf92aa577e3d..54d9be374856 100644 --- a/dotnet/samples/Concepts/Memory/VectorStore_VectorSearch_MultiStore_Common.cs +++ b/dotnet/samples/Concepts/Memory/VectorStore_VectorSearch_MultiStore_Common.cs @@ -16,6 +16,7 @@ namespace Memory; /// /// /// +/// /// /// The vector store to ingest data into. /// The service to use for generating embeddings. diff --git a/dotnet/samples/Concepts/Memory/VectorStore_VectorSearch_MultiStore_InMemory.cs b/dotnet/samples/Concepts/Memory/VectorStore_VectorSearch_MultiStore_InMemory.cs index f88f893c489d..116dbb29c505 100644 --- a/dotnet/samples/Concepts/Memory/VectorStore_VectorSearch_MultiStore_InMemory.cs +++ b/dotnet/samples/Concepts/Memory/VectorStore_VectorSearch_MultiStore_InMemory.cs @@ -20,6 +20,7 @@ namespace Memory; /// /// /// +/// /// public class VectorStore_VectorSearch_MultiStore_InMemory(ITestOutputHelper output) : BaseTest(output) { diff --git a/dotnet/samples/Concepts/Memory/VectorStore_VectorSearch_MultiStore_Postgres.cs b/dotnet/samples/Concepts/Memory/VectorStore_VectorSearch_MultiStore_Postgres.cs index 3995ba486c87..0b6377fa6bde 100644 --- a/dotnet/samples/Concepts/Memory/VectorStore_VectorSearch_MultiStore_Postgres.cs +++ b/dotnet/samples/Concepts/Memory/VectorStore_VectorSearch_MultiStore_Postgres.cs @@ -21,6 +21,7 @@ namespace Memory; /// /// /// +/// /// /// To run this sample, you need a local instance of Docker running, since the associated fixture will try and start a Postgres container in the local docker instance. /// diff --git a/dotnet/samples/Concepts/Memory/VectorStore_VectorSearch_MultiStore_Qdrant.cs b/dotnet/samples/Concepts/Memory/VectorStore_VectorSearch_MultiStore_Qdrant.cs index 3640c4ba7330..e97fe9a11534 100644 --- a/dotnet/samples/Concepts/Memory/VectorStore_VectorSearch_MultiStore_Qdrant.cs +++ b/dotnet/samples/Concepts/Memory/VectorStore_VectorSearch_MultiStore_Qdrant.cs @@ -22,6 +22,7 @@ namespace Memory; /// /// /// +/// /// /// To run this sample, you need a local instance of Docker running, since the associated fixture will try and start a Qdrant container in the local docker instance. /// diff --git a/dotnet/samples/Concepts/Memory/VectorStore_VectorSearch_MultiStore_Redis.cs b/dotnet/samples/Concepts/Memory/VectorStore_VectorSearch_MultiStore_Redis.cs index ae8e2e1d2bab..ab2f42c12819 100644 --- a/dotnet/samples/Concepts/Memory/VectorStore_VectorSearch_MultiStore_Redis.cs +++ b/dotnet/samples/Concepts/Memory/VectorStore_VectorSearch_MultiStore_Redis.cs @@ -22,6 +22,7 @@ namespace Memory; /// /// /// +/// /// /// Redis supports two record storage types: Json and HashSet. /// Note the use of the enum to specify the preferred storage type. diff --git a/dotnet/samples/Demos/VectorStoreRAG/Options/ApplicationConfig.cs b/dotnet/samples/Demos/VectorStoreRAG/Options/ApplicationConfig.cs index 3b9658419ecd..f3ad10e9a7b1 100644 --- a/dotnet/samples/Demos/VectorStoreRAG/Options/ApplicationConfig.cs +++ b/dotnet/samples/Demos/VectorStoreRAG/Options/ApplicationConfig.cs @@ -16,6 +16,7 @@ internal sealed class ApplicationConfig private readonly RagConfig _ragConfig = new(); private readonly AzureAISearchConfig _azureAISearchConfig = new(); private readonly CosmosConfig _azureDocumentDBConfig = new(); + private readonly ChromaConfig _chromaConfig = new(); private readonly CosmosConfig _cosmosNoSqlConfig = new(); private readonly QdrantConfig _qdrantConfig = new(); private readonly RedisConfig _redisConfig = new(); @@ -45,6 +46,9 @@ public ApplicationConfig(ConfigurationManager configurationManager) configurationManager .GetRequiredSection($"VectorStores:{CosmosConfig.DocumentDBConfigSectionName}") .Bind(this._azureDocumentDBConfig); + configurationManager + .GetRequiredSection($"VectorStores:{ChromaConfig.ConfigSectionName}") + .Bind(this._chromaConfig); configurationManager .GetRequiredSection($"VectorStores:{CosmosConfig.NoSqlConfigSectionName}") .Bind(this._cosmosNoSqlConfig); @@ -73,6 +77,8 @@ public ApplicationConfig(ConfigurationManager configurationManager) public CosmosConfig AzureDocumentDBConfig => this._azureDocumentDBConfig; + public ChromaConfig ChromaConfig => this._chromaConfig; + public CosmosConfig CosmosNoSqlConfig => this._cosmosNoSqlConfig; public QdrantConfig QdrantConfig => this._qdrantConfig; diff --git a/dotnet/samples/Demos/VectorStoreRAG/Options/ChromaConfig.cs b/dotnet/samples/Demos/VectorStoreRAG/Options/ChromaConfig.cs new file mode 100644 index 000000000000..6e1f45cbe07e --- /dev/null +++ b/dotnet/samples/Demos/VectorStoreRAG/Options/ChromaConfig.cs @@ -0,0 +1,16 @@ +// Copyright (c) Microsoft. All rights reserved. + +using System.ComponentModel.DataAnnotations; + +namespace VectorStoreRAG.Options; + +/// +/// Chroma service settings. +/// +internal sealed class ChromaConfig +{ + public const string ConfigSectionName = "Chroma"; + + [Required] + public string ConnectionString { get; set; } = string.Empty; +} diff --git a/dotnet/samples/Demos/VectorStoreRAG/Program.cs b/dotnet/samples/Demos/VectorStoreRAG/Program.cs index e7382eb9e71e..2f092dd3f122 100644 --- a/dotnet/samples/Demos/VectorStoreRAG/Program.cs +++ b/dotnet/samples/Demos/VectorStoreRAG/Program.cs @@ -82,6 +82,11 @@ appConfig.AzureDocumentDBConfig.ConnectionString, appConfig.AzureDocumentDBConfig.DatabaseName); break; + case "Chroma": + kernelBuilder.Services.AddChromaCollection>( + appConfig.RagConfig.CollectionName, + appConfig.ChromaConfig.ConnectionString); + break; case "CosmosNoSql": kernelBuilder.Services.AddCosmosCollection>( appConfig.RagConfig.CollectionName, @@ -121,6 +126,7 @@ { case "AzureAISearch": case "AzureDocumentDB": + case "Chroma": case "CosmosNoSql": case "InMemory": case "Redis": diff --git a/dotnet/samples/Demos/VectorStoreRAG/README.md b/dotnet/samples/Demos/VectorStoreRAG/README.md index 95f4b1909318..57bee44dfd44 100644 --- a/dotnet/samples/Demos/VectorStoreRAG/README.md +++ b/dotnet/samples/Demos/VectorStoreRAG/README.md @@ -10,6 +10,7 @@ The sample can be configured in various ways: 1. You can choose your preferred vector store by setting the `Rag:VectorStoreType` configuration setting in the `appsettings.json` file to one of the following values: 1. AzureAISearch 1. AzureDocumentDB + 1. Chroma 1. CosmosNoSql 1. InMemory 1. Qdrant @@ -130,6 +131,22 @@ dotnet user-secrets set "VectorStores:CosmosNoSql:ConnectionString" "" ``` +### Chroma + +If you want to use Chroma as your vector store, you will need to have an instance of Chroma available. + +You can use the following command to start a Chroma instance in docker, and this will work with the default configured settings: + +```cli +docker run -d --name chroma -p 8000:8000 chromadb/chroma:latest +``` + +If you want to use a different instance of Chroma, you can update the appsettings.json file or add the following secret to reconfigure: + +```cli +dotnet user-secrets set "VectorStores:Chroma:ConnectionString" "" +``` + ### Qdrant If you want to use Qdrant as your vector store, you will need to have an instance of Qdrant available. diff --git a/dotnet/samples/Demos/VectorStoreRAG/VectorStoreRAG.csproj b/dotnet/samples/Demos/VectorStoreRAG/VectorStoreRAG.csproj index 6e9d9f62fc7b..099e745caac9 100644 --- a/dotnet/samples/Demos/VectorStoreRAG/VectorStoreRAG.csproj +++ b/dotnet/samples/Demos/VectorStoreRAG/VectorStoreRAG.csproj @@ -20,6 +20,7 @@ + diff --git a/dotnet/samples/Demos/VectorStoreRAG/appsettings.json b/dotnet/samples/Demos/VectorStoreRAG/appsettings.json index 8ba1a6952153..981bfb86c31a 100644 --- a/dotnet/samples/Demos/VectorStoreRAG/appsettings.json +++ b/dotnet/samples/Demos/VectorStoreRAG/appsettings.json @@ -33,6 +33,9 @@ "ConnectionString": "", "DatabaseName": "" }, + "Chroma": { + "ConnectionString": "http://localhost:8000" + }, "CosmosNoSql": { "ConnectionString": "", "DatabaseName": "" From ef53096d74befae24534ab98a177ab27830c6197 Mon Sep 17 00:00:00 2001 From: Laurianti Date: Wed, 14 Oct 2026 16:46:11 +0200 Subject: [PATCH 2/2] .Net: Remove the leftovers of the Chroma connector --- .../samples/InternalUtilities/TestConfiguration.cs | 6 ------ dotnet/src/VectorData/Chroma/README.md | 2 +- dotnet/test/VectorData/Chroma.UnitTests/.editorconfig | 6 ------ 3 files changed, 1 insertion(+), 13 deletions(-) delete mode 100644 dotnet/test/VectorData/Chroma.UnitTests/.editorconfig diff --git a/dotnet/src/InternalUtilities/samples/InternalUtilities/TestConfiguration.cs b/dotnet/src/InternalUtilities/samples/InternalUtilities/TestConfiguration.cs index e64e97904a35..6d908cafa445 100644 --- a/dotnet/src/InternalUtilities/samples/InternalUtilities/TestConfiguration.cs +++ b/dotnet/src/InternalUtilities/samples/InternalUtilities/TestConfiguration.cs @@ -41,7 +41,6 @@ public static void Initialize(IConfigurationRoot configRoot) public static PostgresConfig Postgres => LoadSection(); public static RedisConfig Redis => LoadSection(); public static JiraConfig Jira => LoadSection(); - public static ChromaConfig Chroma => LoadSection(); public static MongoDBConfig MongoDB => LoadSection(); public static ChatGPTRetrievalPluginConfig ChatGPTRetrievalPlugin => LoadSection(); public static MsGraphConfiguration MSGraph => LoadSection(); @@ -219,11 +218,6 @@ public class JiraConfig public string Domain { get; set; } } - public class ChromaConfig - { - public string Endpoint { get; set; } - } - public class MongoDBConfig { public string ConnectionString { get; set; } diff --git a/dotnet/src/VectorData/Chroma/README.md b/dotnet/src/VectorData/Chroma/README.md index 2e862fa4adff..62029d71137e 100644 --- a/dotnet/src/VectorData/Chroma/README.md +++ b/dotnet/src/VectorData/Chroma/README.md @@ -1 +1 @@ -Microsoft.SemanticKernel.Connectors.Chroma and the MemoryStore abstraction has been deprecated. Please use the new Microsoft.Extensions.VectorData abstractions with the Chroma implementation that can be found in the [CommunityToolkit/AI repository](https://github.com/CommunityToolkit/AI/tree/main/MEVD/src/Chroma) +Microsoft.SemanticKernel.Connectors.Chroma and the MemoryStore abstraction have been deprecated. Please use the new Microsoft.Extensions.VectorData abstractions with the Chroma implementation that can be found in the [CommunityToolkit/AI repository](https://github.com/CommunityToolkit/AI/tree/main/MEVD/src/Chroma), published as [CommunityToolkit.VectorData.Chroma](https://www.nuget.org/packages/CommunityToolkit.VectorData.Chroma). diff --git a/dotnet/test/VectorData/Chroma.UnitTests/.editorconfig b/dotnet/test/VectorData/Chroma.UnitTests/.editorconfig deleted file mode 100644 index 394eef685f21..000000000000 --- a/dotnet/test/VectorData/Chroma.UnitTests/.editorconfig +++ /dev/null @@ -1,6 +0,0 @@ -# Suppressing errors for Test projects under dotnet folder -[*.cs] -dotnet_diagnostic.CA2007.severity = none # Do not directly await a Task -dotnet_diagnostic.VSTHRD111.severity = none # Use .ConfigureAwait(bool) is hidden by default, set to none to prevent IDE from changing on autosave -dotnet_diagnostic.CS1591.severity = none # Missing XML comment for publicly visible type or member -dotnet_diagnostic.IDE1006.severity = warning # Naming rule violations