¡Bienvenidos de nuevo a la serie «Building Blocks for AI in .NET»! En la primera parte, exploramos las Extensiones de Microsoft para IA (MEAI) y cómo proporcionan una interfaz unificada para trabajar con modelos de lenguaje grandes (LLM). Hoy, nos sumergimos en el segundo componente fundamental: Microsoft.Extensions.VectorData.
En el post anterior, aprendimos a hacer preguntas y proporcionar contexto a un LLM. Sin embargo, la mayoría de las aplicaciones requieren más que una simple pregunta o un pequeño archivo Markdown como contexto. Es posible que quieras que el LLM tenga acceso a todos tus manuales de producto para ayudar a solucionar problemas de clientes, o que acceda al manual del empleado para un chatbot de RRHH. Aquí es donde entra en juego la búsqueda semántica.
La Búsqueda Semántica y los Embeddings
Una característica común en las aplicaciones inteligentes es la búsqueda semántica. A diferencia de la búsqueda tradicional que se basa en palabras clave, la búsqueda semántica utiliza el significado de una consulta. Esto se logra convirtiendo el texto en embeddings, que son representaciones numéricas del significado semántico del texto, y vectores que proporcionan información sobre cómo se relacionan entre sí.
Imaginemos una base de datos simple con tres entradas:
- Pase de sala
- Paso de montaña
- Pasar (verbo)
Un enfoque tradicional para buscar «Cómo cruzo el paso?» o «¿Dónde recojo mi pase?» desglosaría la consulta en palabras, y la palabra «pass» (paso/pase) aparecería en las tres entradas, devolviendo resultados irrelevantes. Sin embargo, con los embeddings, el sistema entiende el contexto. Si preguntamos «Cómo cruzo el paso?», el embedding de la consulta podría coincidir semánticamente con «Paso de montaña». Si preguntamos «¿Dónde recojo mi pase?», podría coincidir con «Pase de sala». Este enfoque semántico ofrece resultados mucho más precisos y relevantes.
Un modelo de embeddings especializado se encarga de crear estas representaciones numéricas, entrenado para comprender el significado semántico a través del contexto. Almacenar estos embeddings en una base de datos en lugar de generarlos en cada ejecución es crucial para la eficiencia, permitiendo aprovechar las capacidades de consulta de la base de datos.
Las bases de datos vectoriales están diseñadas específicamente para almacenar vectores y embeddings. Ejemplos incluyen Qdrant, Redis, SQL Server y Cosmos DB. Al igual que MEAI unifica el acceso a los LLM, las extensiones de datos vectoriales de .NET proporcionan una abstracción común para trabajar con estos almacenes de vectores.
¿Por Qué los Vectores Son Cruciales para las Aplicaciones de IA?
Cuando preguntas a un LLM sobre la documentación de tu empresa, el modelo no conoce mágicamente tu contenido. En cambio, una aplicación típicamente sigue estos pasos:
- Convierte tus documentos en embeddings – representaciones numéricas que capturan el significado semántico.
- Almacena esos embeddings en una base de datos vectorial junto con el contenido original.
- Convierte la consulta del usuario en un embedding utilizando el mismo modelo.
- Realiza una búsqueda de similitud para encontrar los documentos más relevantes.
- Pasa el contexto relevante al LLM junto con la consulta del usuario.

Este patrón, conocido como RAG (Retrieval-Augmented Generation – Generación Aumentada por Recuperación), permite a los modelos proporcionar respuestas precisas y fundamentadas basadas en tus datos específicos. El desafío radica en que cada base de datos vectorial tiene su propio SDK, estructuras de datos y patrones de consulta. Ahí es donde Microsoft.Extensions.VectorData ofrece una solución elegante.
Una Interfaz, Múltiples Almacenes de Vectores
La librería Microsoft Extensions for Vector Data ofrece abstracciones que funcionan con diversos proveedores de bases de datos vectoriales. Esto simplifica enormemente el desarrollo. Por ejemplo, mientras que una interacción directa con Qdrant requeriría código específico de Qdrant, utilizando las abstracciones universales, tu lógica de negocio permanece intacta, independientemente del almacén de vectores subyacente. Simplemente cambias la implementación de VectorStore, y tu aplicación sigue funcionando sin necesidad de reescribir la lógica.
Configuración de un almacén vectorial con abstracciones:
// Se configura una vez el generador de embeddings para el almacén de vectores
var embeddingGenerator = new OpenAIClient(apiKey)
.GetEmbeddingClient("text-embedding-3-small")
.AsIEmbeddingGenerator();
// Se instancia el almacén vectorial, por ejemplo Qdrant, usando la abstracción
var vectorStore = new QdrantVectorStore(
new QdrantClient("localhost"),
ownsClient: true,
new QdrantVectorStoreOptions { EmbeddingGenerator = embeddingGenerator });
var collection = vectorStore.GetCollection<string, DocumentRecord>("my_collection");
await collection.EnsureCollectionExistsAsync();
var record = new DocumentRecord
{
Key = Guid.NewGuid().ToString(),
Text = "Texto de documento de ejemplo",
Category = "documentación"
};
await collection.UpsertAsync(record);
var searchResults = collection.SearchAsync("buscar documentos sobre temas de ejemplo", top: 5);
Este código ilustra cómo la abstracción permite interactuar con un almacén vectorial (en este caso, Qdrant) de manera estandarizada, haciendo que tu aplicación sea portátil a otros proveedores compatibles.
Definiendo tu Modelo de Datos
Las abstracciones de datos vectoriales utilizan atributos para mapear tus clases C# a esquemas de bases de datos vectoriales. Esto permite definir de forma clara cómo se organizan y persisten tus datos:
public class DocumentRecord
{
[VectorStoreKey] // Identificador único del registro
public string Key { get; set; }
[VectorStoreData] // Campo de metadatos (el contenido principal)
public string Text { get; set; }
[VectorStoreData(IsIndexed = true)] // Campo de metadatos indexado
public string Category { get; set; }
[VectorStoreData(IsIndexed = true)] // Campo de metadatos indexado
public DateTimeOffset Timestamp { get; set; }
// El vector se genera automáticamente a partir de 'Text'
[VectorStoreVector(1536, DistanceFunction.CosineSimilarity)]
public string Embedding => this.Text;
}
Los atributos VectorStoreKey, VectorStoreData y VectorStoreVector guían a la librería sobre cómo manejar cada propiedad: como clave única, como campo de metadatos (potencialmente indexado) o como el vector de embedding con sus dimensiones y función de distancia.
Trabajando con Colecciones
Una vez definido el modelo de datos, operar con colecciones es directo y consistente, sin importar el almacén de vectores subyacente:
- Obtener o crear una colección:
vectorStore.GetCollection<string, DocumentRecord>("documents"); - Verificar si existe y asegurar su creación:
await collection.CollectionExistsAsync();yawait collection.EnsureCollectionExistsAsync(); - Insertar o actualizar registros:
await collection.UpsertAsync(documentRecord);(también para operaciones por lotes conUpsertBatchAsync). - Recuperar por clave:
var record = await collection.GetAsync("some-key"); - Eliminar registros:
await collection.DeleteAsync("some-key");(también por lotes conDeleteBatchAsync).
Búsqueda Semántica Eficaz
El verdadero potencial reside en el método SearchAsync. Cuando un IEmbeddingGenerator está configurado, solo necesitas pasar el texto de tu consulta, y los embeddings se generarán automáticamente para realizar la búsqueda de similitud:
// Los embeddings se generan automáticamente
await foreach (var result in collection.SearchAsync("¿Qué es la búsqueda semántica?", top: 5))
{
Console.WriteLine($"Puntuación: {result.Score}, Texto: {result.Record.Text}");
}
También puedes pasar un vector de embedding precalculado directamente, si ya lo tienes disponible.
Filtrado de Resultados Avanzado
La combinación de la similitud vectorial con el filtrado de metadatos permite afinar los resultados. Puedes usar expresiones LINQ estándar para filtrar por campos como categoría o fecha:
var searchOptions = new VectorSearchOptions<DocumentRecord>
{
Filter = r => r.Category == "documentación" &&
r.Timestamp > DateTimeOffset.UtcNow.AddDays(-30)
};
var results = collection.SearchAsync("buscar documentación relevante", top: 10, searchOptions);
Las operaciones de filtro soportadas incluyen comparaciones de igualdad (==, !=), consultas de rango (>, <, >=, <=), operadores lógicos (&&, ||) y pertenencia a colecciones (.Contains()).
Integración Transparente con Embeddings
La configuración de un IEmbeddingGenerator en el almacén de vectores o la colección es la forma recomendada. Esto asegura que los embeddings se generen automáticamente tanto al insertar/actualizar registros como al realizar búsquedas, eliminando la necesidad de preprocesamiento manual.
Implementación de Patrones RAG
Uniendo Microsoft.Extensions.AI y Microsoft.Extensions.VectorData, se puede implementar un patrón RAG simplificado para construir chatbots que proporcionen respuestas basadas en tu propia información:
public async Task<string> AskQuestionAsync(string question)
{
// 1. Encontrar documentos relevantes (embeddings generados automáticamente)
var contextParts = new List<string>();
await foreach (var result in collection.SearchAsync(question, top: 3))
{
contextParts.Add(result.Record.Text);
}
// 2. Construir el contexto a partir de los resultados
var context = string.Join("\n\n", contextParts);
// 3. Crear el prompt con el contexto
var messages = new List<ChatMessage>
{
new(ChatRole.System,
"Responde preguntas basándote en el contexto proporcionado. Si el contexto no contiene información relevante, indícalo."),
new(ChatRole.User,
$"Contexto:\n{context}\n\nPregunta: {question}")
};
// 4. Obtener respuesta del LLM
var response = await chatClient.GetResponseAsync(messages);
return response.Message.Text;
}
Este ejemplo demuestra la sinergia entre ambas extensiones para crear aplicaciones de IA robustas.
Almacenes de Vectores Soportados
Microsoft.Extensions.VectorData es compatible con una amplia gama de bases de datos vectoriales a través de conectores oficiales:
- Azure AI Search –
Microsoft.Extensions.VectorData.AzureAISearch - Qdrant –
Microsoft.SemanticKernel.Connectors.Qdrant - Redis –
Microsoft.SemanticKernel.Connectors.Redis - PostgreSQL –
Microsoft.SemanticKernel.Connectors.Postgres - Azure Cosmos DB (NoSQL) –
Microsoft.SemanticKernel.Connectors.AzureCosmosDBNoSQL - SQL Server –
Microsoft.SemanticKernel.Connectors.SqlServer - SQLite –
Microsoft.SemanticKernel.Connectors.Sqlite - In-Memory –
Microsoft.SemanticKernel.Connectors.InMemory(ideal para pruebas y desarrollo)
Para una lista completa de conectores (incluyendo Elasticsearch, MongoDB, Weaviate, Pinecone y más), consulta la documentación de conectores listos para usar.
¿Por qué una Librería Separada de las Extensiones Centrales de IA?
La decisión de mantener Microsoft.Extensions.VectorData como una librería separada de Microsoft.Extensions.AI se debe a que no todas las aplicaciones inteligentes requieren almacenamiento vectorial. Muchos escenarios, como chatbots básicos, generación de contenido o tareas de clasificación, funcionan perfectamente con solo las abstracciones de LLM. Al mantener los datos vectoriales separados, la librería principal sigue siendo ligera y enfocada.
Cuando necesites vectores para búsqueda semántica, RAG o memoria a largo plazo, puedes añadir fácilmente el paquete de datos vectoriales y beneficiarte de los mismos patrones consistentes que ya utilizas con MEAI.
Resumen
Microsoft.Extensions.VectorData aporta a las bases de datos vectoriales los mismos beneficios que Microsoft.Extensions.AI proporciona a los LLM: una interfaz unificada y agnóstica del proveedor que hace que tu código sea portátil y tu arquitectura flexible. Ya sea que estés implementando patrones RAG, construyendo una búsqueda semántica o creando memoria a largo plazo para agentes de IA, estas abstracciones te permiten centrarte en la lógica de tu aplicación en lugar de en los SDK específicos de cada base de datos.
En el próximo post, exploraremos el Microsoft Agent Framework y cómo estos componentes se unen para crear flujos de trabajo de agentes sofisticados. Hasta entonces, aquí tienes algunos recursos para empezar con los datos vectoriales en .NET:
- Aprende con código: Repositorio de ejemplos de IA
- Aprende con tutoriales: Documentación de .NET AI
- Aprende con videos: Bloques de construcción de IA, Construyendo aplicaciones inteligentes con .NET
¡Feliz codificación!