Partager via


Qu’est-ce que les connecteurs de magasin de vecteurs du noyau sémantique ? (Préversion)

Avertissement

La fonctionnalité de magasin de vecteurs du noyau sémantique est en préversion et des améliorations nécessitant des modifications cassants peuvent toujours se produire dans des circonstances limitées avant la mise en production.

Conseil

Si vous recherchez des informations sur les connecteurs de magasin de mémoire hérités, reportez-vous à la page Magasins de mémoire.

Les bases de données vectorielles ont de nombreux cas d’usage dans différents domaines et applications qui impliquent le traitement du langage naturel (NLP), la vision par ordinateur (CV), les systèmes de recommandation (RS) et d’autres domaines qui nécessitent une compréhension sémantique et une correspondance des données.

Un cas d’usage pour stocker des informations dans une base de données vectorielle consiste à permettre aux modèles de langage volumineux (LLMs) de générer des réponses plus pertinentes et cohérentes. Les grands modèles linguistiques sont souvent confrontés à des défis tels que la génération d’informations inexactes ou non pertinentes ; absence de cohérence factuelle ou de bon sens ; répéter ou contredire eux-mêmes ; être biaisé ou offensif. Pour vous aider à surmonter ces défis, vous pouvez utiliser une base de données vectorielle pour stocker des informations sur différentes rubriques, mots clés, faits, opinions et/ou sources liées à votre domaine ou genre souhaité. La base de données vectorielle vous permet de trouver efficacement le sous-ensemble d’informations relatives à une question ou une rubrique spécifique. Vous pouvez ensuite transmettre des informations de la base de données vectorielle avec votre invite à votre modèle de langage volumineux pour générer du contenu plus précis et pertinent.

Par exemple, si vous souhaitez écrire un billet de blog sur les dernières tendances de l’IA, vous pouvez utiliser une base de données vectorielle pour stocker les dernières informations sur cette rubrique et transmettre les informations avec la demande à un LLM afin de générer un billet de blog qui tire parti des dernières informations.

Le noyau sémantique et .net fournissent une abstraction permettant d’interagir avec les magasins de vecteurs et une liste de connecteurs prêtes à l’emploi qui implémentent ces abstractions. Les fonctionnalités incluent la création, la liste et la suppression de collections d’enregistrements et le chargement, la récupération et la suppression d’enregistrements. L’abstraction facilite l’expérimentation d’un magasin vectoriel gratuit ou hébergé localement, puis de basculer vers un service lorsque vous avez besoin d’effectuer un scale-up.

Abstraction du magasin de vecteurs

Les principales interfaces de l’abstraction Vector Store sont les suivantes.

Microsoft.Extensions.VectorData.IVectorStore

IVectorStore contient des opérations qui s’étendent sur toutes les collections du magasin vectoriel, par exemple ListCollectionNames. Il offre également la possibilité d’obtenir IVectorStoreRecordCollection<TKey, TRecord> des instances.

Microsoft.Extensions.VectorData.IVectorStoreRecordCollection<TKey, TRecord>

IVectorStoreRecordCollection<TKey, TRecord> représente une collection. Cette collection peut ou non exister et l’interface fournit des méthodes pour vérifier si la collection existe, la créer ou la supprimer. L’interface fournit également des méthodes pour upsert, obtenir et supprimer des enregistrements. Enfin, l’interface hérite de la fourniture de fonctionnalités de IVectorizedSearch<TRecord> recherche vectorielle.

Microsoft.Extensions.VectorData.IVectorizedSearch<TRecord>

IVectorizedSearch<TRecord> contient une méthode pour effectuer des recherches vectorielles. IVectorStoreRecordCollection<TKey, TRecord> hérite de la possibilité d’utiliser IVectorizedSearch<TRecord> IVectorizedSearch<TRecord> elle-même dans les cas où seule la recherche est nécessaire et qu’aucune gestion des enregistrements ou des collections n’est nécessaire.

IVectorizableTextSearch<TRecord>

IVectorizableTextSearch<TRecord> contient une méthode pour effectuer des recherches vectorielles où la base de données vectorielle a la possibilité de générer automatiquement des incorporations. Par exemple, vous pouvez appeler cette méthode avec une chaîne de texte et la base de données génère l’incorporation pour vous et effectue une recherche sur un champ vectoriel. Cela n’est pas pris en charge par toutes les bases de données vectorielles et est donc implémenté uniquement par les connecteurs sélectionnés.

Abstraction du magasin de vecteurs

Les principales interfaces de l’abstraction Vector Store sont les suivantes.

com.microsoft.semantickernel.data.vectorstorage.VectorStore

VectorStore contient des opérations qui s’étendent sur toutes les collections du magasin vectoriel, par exemple listCollectionNames. Il offre également la possibilité d’obtenir VectorStoreRecordCollection<Key, Record> des instances.

com.microsoft.semantickernel.data.vectorstorage.VectorStoreRecordCollection<Key, Record>

VectorStoreRecordCollection<Key, Record> représente une collection. Cette collection peut ou non exister et l’interface fournit des méthodes pour vérifier si la collection existe, la créer ou la supprimer. L’interface fournit également des méthodes pour upsert, obtenir et supprimer des enregistrements. Enfin, l’interface hérite de la fourniture de fonctionnalités de VectorizedSearch<Record> recherche vectorielle.

com.microsoft.semantickernel.data.vectorsearch.VectorizedSearch<Record>

VectorizedSearch<Record> contient une méthode pour effectuer des recherches vectorielles. VectorStoreRecordCollection<Key, Record> hérite de la possibilité d’utiliser VectorizedSearch<Record> VectorizedSearch<Record> elle-même dans les cas où seule la recherche est nécessaire et qu’aucune gestion des enregistrements ou des collections n’est nécessaire.

com.microsoft.semantickernel.data.vectorsearch.VectorizableTextSearch<Record>

VectorizableTextSearch<Record> contient une méthode pour effectuer des recherches vectorielles où la base de données vectorielle a la possibilité de générer automatiquement des incorporations. Par exemple, vous pouvez appeler cette méthode avec une chaîne de texte et la base de données génère l’incorporation pour vous et effectue une recherche sur un champ vectoriel. Cela n’est pas pris en charge par toutes les bases de données vectorielles et est donc implémenté uniquement par les connecteurs sélectionnés.

Prise en main des connecteurs Vector Store

Importer les packages nuget nécessaires

Toutes les interfaces de magasin de vecteurs et toutes les classes associées à l’abstraction sont disponibles dans le Microsoft.Extensions.VectorData.Abstractions package nuget. Chaque implémentation de magasin de vecteurs est disponible dans son propre package nuget. Pour obtenir la liste des implémentations connues, consultez la page connecteurs out-of-the-box.

Le package d’abstractions peut être ajouté comme suit.

dotnet add package Microsoft.Extensions.VectorData.Abstractions --prerelease

Avertissement

À partir de la version 1.23.0 du noyau sémantique, les abstractions du magasin de vecteurs ont été supprimées Microsoft.SemanticKernel.Abstractions et sont disponibles dans le nouveau package dédié Microsoft.Extensions.VectorData.Abstractions .

Notez que, à partir de la version 1.23.0, Microsoft.SemanticKernel.Abstractions il Microsoft.Extensions.VectorData.Abstractionsn’est donc pas nécessaire de référencer des packages supplémentaires. Toutefois, les abstractions se trouveront dans le nouvel Microsoft.Extensions.VectorData espace de noms.

Lors de la mise à niveau de la version 1.22.0 ou antérieure vers la version 1.23.0 ou ultérieure, vous devez ajouter une clause supplémentaire using Microsoft.Extensions.VectorData; dans les fichiers où l’un des types d’abstraction vector Store est utilisé, par exemple IVectorStore, , IVectorStoreRecordCollection, VectorStoreRecordDataAttribute, VectorStoreRecordKeyPropertyetc.

Cette modification a été apportée pour prendre en charge les fournisseurs de magasin de vecteurs lors de la création de leurs propres implémentations. Un fournisseur doit uniquement référencer le Microsoft.Extensions.VectorData.Abstractions package. Cela réduit les conflits de version potentiels et permet au noyau sémantique de continuer à évoluer rapidement sans affecter les fournisseurs de magasin de vecteurs.

Définir votre modèle de données

Les connecteurs de magasin de vecteurs de noyau sémantique utilisent une première approche de modèle pour interagir avec les bases de données. Cela signifie que la première étape consiste à définir un modèle de données mappé au schéma de stockage. Pour aider les connecteurs à créer des collections d’enregistrements et à mapper au schéma de stockage, le modèle peut être annoté pour indiquer la fonction de chaque propriété.

using Microsoft.Extensions.VectorData;

public class Hotel
{
    [VectorStoreRecordKey]
    public ulong HotelId { get; set; }

    [VectorStoreRecordData(IsFilterable = true)]
    public string HotelName { get; set; }

    [VectorStoreRecordData(IsFullTextSearchable = true)]
    public string Description { get; set; }

    [VectorStoreRecordVector(Dimensions: 4, DistanceFunction.CosineDistance, IndexKind.Hnsw)]
    public ReadOnlyMemory<float>? DescriptionEmbedding { get; set; }

    [VectorStoreRecordData(IsFilterable = true)]
    public string[] Tags { get; set; }
}
from dataclasses import dataclass, field
from typing import Annotated
from semantic_kernel.data import (
    DistanceFunction,
    IndexKind,
    VectorStoreRecordDataField,
    VectorStoreRecordDefinition,
    VectorStoreRecordKeyField,
    VectorStoreRecordVectorField,
    vectorstoremodel,
)

@vectorstoremodel
@dataclass
class Hotel:
    hotel_id: Annotated[str, VectorStoreRecordKeyField()] = field(default_factory=lambda: str(uuid4()))
    hotel_name: Annotated[str, VectorStoreRecordDataField(is_filterable=True)]
    description: Annotated[str, VectorStoreRecordDataField(is_full_text_searchable=True)]
    description_embedding: Annotated[list[float], VectorStoreRecordVectorField(dimensions=4, distance_function=DistanceFunction.COSINE, index_kind=IndexKind.HNSW)]
    tags: Annotated[list[str], VectorStoreRecordDataField(is_filterable=True)]
import com.microsoft.semantickernel.data.vectorstorage.annotations.VectorStoreRecordData;
import com.microsoft.semantickernel.data.vectorstorage.annotations.VectorStoreRecordKey;
import com.microsoft.semantickernel.data.vectorstorage.annotations.VectorStoreRecordVector;
import com.microsoft.semantickernel.data.vectorstorage.definition.DistanceFunction;
import com.microsoft.semantickernel.data.vectorstorage.definition.IndexKind;

import java.util.Collections;
import java.util.List;

public class Hotel {
    @VectorStoreRecordKey
    private String hotelId;

    @VectorStoreRecordData(isFilterable = true)
    private String name;

    @VectorStoreRecordData(isFullTextSearchable = true)
    private String description;

    @VectorStoreRecordVector(dimensions = 4, indexKind = IndexKind.HNSW, distanceFunction = DistanceFunction.COSINE_DISTANCE)
    private List<Float> descriptionEmbedding;

    @VectorStoreRecordData(isFilterable = true)
    private List<String> tags;

    public Hotel() { }

    public Hotel(String hotelId, String name, String description, List<Float> descriptionEmbedding, List<String> tags) {
        this.hotelId = hotelId;
        this.name = name;
        this.description = description;
        this.descriptionEmbedding = Collections.unmodifiableList(descriptionEmbedding);
        this.tags = Collections.unmodifiableList(tags);
    }

    public String getHotelId() { return hotelId; }
    public String getName() { return name; }
    public String getDescription() { return description; }
    public List<Float> getDescriptionEmbedding() { return descriptionEmbedding; }
    public List<String> getTags() { return tags; }
}

Conseil

Pour plus d’informations sur la façon d’annoter votre modèle de données, reportez-vous à la définition de votre modèle de données.

Conseil

Pour une alternative à l’annotation de votre modèle de données, reportez-vous à la définition de votre schéma avec une définition d’enregistrement.

Se connecter à votre base de données et sélectionner une collection

Une fois que vous avez défini votre modèle de données, l’étape suivante consiste à créer une instance VectorStore pour la base de données de votre choix et à sélectionner une collection d’enregistrements.

Dans cet exemple, nous allons utiliser Qdrant. Vous devez donc importer le package nuget Qdrant.

dotnet add package Microsoft.SemanticKernel.Connectors.Qdrant --prerelease

Étant donné que les bases de données prennent en charge de nombreux types de clés et d’enregistrements différents, nous vous permettent de spécifier le type de la clé et de l’enregistrement pour votre collection à l’aide de génériques. Dans notre cas, le type d’enregistrement sera la Hotel classe que nous avons déjà définie, et le type de clé sera ulong, car la HotelId propriété est un ulong et Qdrant prend uniquement en charge Guid ou ulong clés.

using Microsoft.SemanticKernel.Connectors.Qdrant;
using Qdrant.Client;

// Create a Qdrant VectorStore object
var vectorStore = new QdrantVectorStore(new QdrantClient("localhost"));

// Choose a collection from the database and specify the type of key and record stored in it via Generic parameters.
var collection = vectorStore.GetCollection<ulong, Hotel>("skhotels");

Étant donné que les bases de données prennent en charge de nombreux types de clés et d’enregistrements différents, nous vous permettent de spécifier le type de la clé et de l’enregistrement pour votre collection à l’aide de génériques. Dans notre cas, le type d’enregistrement sera la Hotel classe que nous avons déjà définie, et le type de clé sera str, car la HotelId propriété est un str et Qdrant prend uniquement en charge str ou int clés.

from semantic_kernel.connectors.memory.qdrant import QdrantStore

# Create a Qdrant VectorStore object, this will look in the environment for Qdrant related settings, and will fall back to the default, which is to run in-memory.
vector_store = QdrantStore()

# Choose a collection from the database and specify the type of key and record stored in it via Generic parameters.
collection = vector_store.get_collection(
    collection_name="skhotels", 
    data_model_type=Hotel
)

Étant donné que les bases de données prennent en charge de nombreux types de clés et d’enregistrements différents, nous vous permettent de spécifier le type de la clé et de l’enregistrement pour votre collection à l’aide de génériques. Dans notre cas, le type d’enregistrement sera la Hotel classe que nous avons déjà définie, et le type de clé sera String, car la hotelId propriété est un String magasin JDBC ne prend en charge String que les clés.

import com.microsoft.semantickernel.data.jdbc.JDBCVectorStore;
import com.microsoft.semantickernel.data.jdbc.JDBCVectorStoreOptions;
import com.microsoft.semantickernel.data.jdbc.JDBCVectorStoreRecordCollectionOptions;
import com.microsoft.semantickernel.data.jdbc.mysql.MySQLVectorStoreQueryProvider;
import com.mysql.cj.jdbc.MysqlDataSource;

import java.util.List;

public class Main {
    public static void main(String[] args) {
        // Create a MySQL data source
        var dataSource = new MysqlDataSource();
        dataSource.setUrl("jdbc:mysql://localhost:3306/sk");
        dataSource.setPassword("root");
        dataSource.setUser("root");

        // Create a JDBC vector store
        var vectorStore = JDBCVectorStore.builder()
            .withDataSource(dataSource)
            .withOptions(
                JDBCVectorStoreOptions.builder()
                    .withQueryProvider(MySQLVectorStoreQueryProvider.builder()
                        .withDataSource(dataSource)
                        .build())
                    .build()
            )
            .build();

        // Get a collection from the vector store
        var collection = vectorStore.getCollection("skhotels",
            JDBCVectorStoreRecordCollectionOptions.<Hotel>builder()
                .withRecordClass(Hotel.class)
                .build()
        );
    }
}

Conseil

Pour plus d’informations sur les types de clés et de champs pris en charge par chaque connecteur Vector Store, reportez-vous à la documentation de chaque connecteur.

Créer la collection et ajouter des enregistrements

// Create the collection if it doesn't exist yet.
await collection.CreateCollectionIfNotExistsAsync();

// Upsert a record.
string descriptionText = "A place where everyone can be happy.";
ulong hotelId = 1;

// Create a record and generate a vector for the description using your chosen embedding generation implementation.
// Just showing a placeholder embedding generation method here for brevity.
await collection.UpsertAsync(new Hotel
{
    HotelId = hotelId,
    HotelName = "Hotel Happy",
    Description = descriptionText,
    DescriptionEmbedding = await GenerateEmbeddingAsync(descriptionText),
    Tags = new[] { "luxury", "pool" }
});

// Retrieve the upserted record.
Hotel? retrievedHotel = await collection.GetAsync(hotelId);

Créer la collection et ajouter des enregistrements

# Create the collection if it doesn't exist yet.
await collection.create_collection_if_not_exists()

# Upsert a record.
description = "A place where everyone can be happy."
hotel_id = "1"

await collection.upsert(Hotel(
    hotel_id = hotel_id,
    hotel_name = "Hotel Happy",
    description = description,
    description_embedding = await GenerateEmbeddingAsync(description),
    tags = ["luxury", "pool"]
))

# Retrieve the upserted record.
retrieved_hotel = await collection.get(hotel_id)
// Create the collection if it doesn't exist yet.
collection.createCollectionAsync().block();

// Upsert a record.
var description = "A place where everyone can be happy";
var hotelId = "1";
var hotel = new Hotel(
    hotelId, 
    "Hotel Happy", 
    description, 
    generateEmbeddingsAsync(description).block(), 
    List.of("luxury", "pool")
);

collection.upsertAsync(hotel, null).block();

// Retrieve the upserted record.
var retrievedHotel = collection.getAsync(hotelId, null).block();

Conseil

Pour plus d’informations sur la génération d’incorporations, consultez la génération d’incorporation.

// Generate a vector for your search text, using your chosen embedding generation implementation.
// Just showing a placeholder method here for brevity.
var searchVector = await GenerateEmbeddingAsync("I'm looking for a hotel where customer happiness is the priority.");
// Do the search.
var searchResult = await collection.VectorizedSearchAsync(searchVector, new() { Top = 1 }).Results.ToListAsync()

// Inspect the returned hotels.
Hotel hotel = searchResult.First().Record;
Console.WriteLine("Found hotel description: " + hotel.Description);
// Generate a vector for your search text, using your chosen embedding generation implementation.
// Just showing a placeholder method here for brevity.
var searchVector = generateEmbeddingsAsync("I'm looking for a hotel where customer happiness is the priority.").block();

// Do the search.
var searchResult = collection.searchAsync(searchVector, VectorSearchOptions.builder()
    .withTop(1).build()
).block();

Hotel record = searchResult.getResults().get(0).getRecord();
System.out.printf("Found hotel description: %s\n", record.getDescription());

Conseil

Pour plus d’informations sur la génération d’incorporations, consultez la génération d’incorporation.

Étapes suivantes