Editare

Vector databases for .NET AI apps

Vector databases store and manage vector embeddings. Embeddings are numeric representations of data that preserve semantic meaning. Words, documents, images, audio, and other types of data can all be vectorized. You can use embeddings to help an AI model understand the meaning of inputs so that it can perform comparisons and transformations, such as summarizing text, finding contextually related data, or creating images from text descriptions.

For example, you can use a vector database to:

  • Identify similar images, documents, and songs based on their contents, themes, sentiments, and styles.
  • Identify similar products based on their characteristics, features, and user groups.
  • Recommend content, products, or services based on user preferences.
  • Identify the best potential options from a large pool of choices to meet complex requirements.
  • Identify data anomalies or fraudulent activities that are dissimilar from predominant or normal patterns.

Vector databases provide vector search capabilities to find similar items based on their data characteristics rather than by exact matches on a property field. Vector search works by analyzing the vector representations of your data that you created using an AI embedding model such as the Azure OpenAI embedding models. The search process measures the distance between the data vectors and your query vector. The data vectors that are closest to your query vector are the ones that are most similar semantically.

Most modern database products support vector search alongside traditional querying; this is the case with Azure SQL/SQL Server, Azure Cosmos DB, PostgreSQL, and many other major products. As an alternative, a wide range of dedicated, specialized vector database products exist. These products are highly optimized to perform vector search, and are typically installed alongside a traditional database exclusively to handle vector search workloads.

Vector search workflows with .NET and OpenAI

Vector databases and their search features are especially useful in RAG pattern workflows with Azure OpenAI. This pattern lets you augment your AI model with additional semantically rich knowledge of your data. A common AI workflow using vector databases includes these steps:

  1. Create embeddings for your data using an OpenAI embedding model.
  2. Store and index the embeddings in a vector database or search service.
  3. Convert user prompts from your application to embeddings.
  4. Run a vector search across your data, comparing the user prompt embedding to the embeddings in your database.
  5. Use a language model such as gpt-4o to assemble a user-friendly completion from the vector search results.

For a hands-on example of this flow, see the Implement Azure OpenAI with RAG using vector search in a .NET app tutorial.

Other benefits of the RAG pattern include:

  • Generate contextually relevant and accurate responses to user prompts from AI models.
  • Overcome LLM token limits—the heavy lifting is done through the database vector search.
  • Reduce the costs from frequent fine-tuning on updated data.

Microsoft.Extensions.VectorData library

To use vector search from .NET, you can use your regular database driver or SDK without requiring any additional library or API. For example, on SQL Server, vector search can be performed in T-SQL when using the standard .NET driver, SqlClient. However, accessing vector search in this way is often quite low-level, requires considerable ceremony to handle serialization/deserialization, and the resulting code isn't portable across databases.

As an alternative, the Microsoft.Extensions.VectorData library provides a unified layer of abstractions for interacting with vector stores in .NET.

Key abstractions

Here's a minimal end-to-end example that creates a collection, upserts records, and performs a vector search:

using Microsoft.Extensions.AI;
using Microsoft.Extensions.VectorData;
using Microsoft.SemanticKernel.Connectors.InMemory;

// Configure an embedding generator to transform text to embeddings
IEmbeddingGenerator<string, Embedding<float>> embeddingGenerator = ...;

// Create a vector store and get a collection with the embedding generator
var vectorStore = new InMemoryVectorStore(new() { EmbeddingGenerator = embeddingGenerator });
var collection = vectorStore.GetCollection<int, Movie>("movies");
await collection.EnsureCollectionExistsAsync();

// Upsert some records
await collection.UpsertAsync(new Movie { Key = 1, Title = "The Lion King", Description = "An animated film about a young lion prince" });
await collection.UpsertAsync(new Movie { Key = 2, Title = "Inception", Description = "A thief who steals corporate secrets through dream-sharing technology" });
await collection.UpsertAsync(new Movie { Key = 3, Title = "Finding Nemo", Description = "A fish searches the ocean for his lost son" });

// Search for movies similar to the query text
await foreach (var result in collection.SearchAsync("animals in the wild", top: 2))
{
    Console.WriteLine($"{result.Record.Title} (score: {result.Score})");
}

// Define the data model
class Movie
{
    [VectorStoreKey]
    public int Key { get; set; }

    [VectorStoreData]
    public string Title { get; set; }

    [VectorStoreVector(Dimensions: 1536)]
    public string Description { get; set; }
}

Vector store providers

The Microsoft.Extensions.VectorData.Abstractions package defines the abstractions, and separate provider packages provide implementations for specific vector databases. Choose the provider that matches your vector database, for example, Microsoft.SemanticKernel.Connectors.AzureAISearch.

Note

Despite the inclusion of "SemanticKernel" in the package names, these providers have nothing to do with Semantic Kernel and are usable anywhere in .NET, including Agent Framework.

All providers implement the same VectorStore and VectorStoreCollection<TKey,TRecord> abstract classes, so you can switch between them without changing your application logic.

Tip

Use the in-memory provider (Microsoft.SemanticKernel.Connectors.InMemory) during initial development/prototyping - it doesn't require any external service or configuration, and you can swap it out for a production provider later. Avoid using the InMemory provider for testing, as there can be important differences between this provider and your production database. Consider using testcontainers to run tests against your production database system.