Condividi tramite


Che cosa sono i connettori dell'archivio vettoriale del kernel semantico? (anteprima)

Avviso

La funzionalità di archiviazione vettoriale del kernel semantico è in anteprima e i miglioramenti che richiedono modifiche di rilievo possono ancora verificarsi in circostanze limitate prima del rilascio.

Suggerimento

Per informazioni sui connettori dell'archivio memoria legacy, vedere la pagina Archivi memoria.

I database vettoriali hanno molti casi d'uso in domini e applicazioni diversi che coinvolgono l'elaborazione del linguaggio naturale (NLP), visione artificiale (CV), sistemi di raccomandazione (RS) e altre aree che richiedono la comprensione semantica e la corrispondenza dei dati.

Un caso d'uso per l'archiviazione di informazioni in un database vettoriale consiste nell'abilitare modelli di linguaggio di grandi dimensioni per generare risposte più pertinenti e coerenti. I modelli linguistici di grandi dimensioni spesso affrontano sfide come la generazione di informazioni imprecise o irrilevanti; mancanza di coerenza effettiva o di buon senso; ripetendo o contraddicendo se stessi; essere biasimo o offensivo. Per superare queste sfide, è possibile usare un database vettoriale per archiviare informazioni su argomenti, parole chiave, fatti, opinioni e/o origini correlate al dominio o al genere desiderato. Il database vettoriale consente di trovare in modo efficiente il subset di informazioni correlate a una domanda o a un argomento specifico. È quindi possibile passare informazioni dal database vettoriale con la richiesta al modello linguistico di grandi dimensioni per generare contenuto più accurato e pertinente.

Ad esempio, se si vuole scrivere un post di blog sulle tendenze più recenti dell'IA, è possibile usare un database vettoriale per archiviare le informazioni più recenti su tale argomento e passare le informazioni insieme alla richiesta a un LLM per generare un post di blog che sfrutta le informazioni più recenti.

Il kernel semantico e .net forniscono un'astrazione per interagire con gli archivi vettoriali e un elenco di connettori predefiniti che implementano queste astrazioni. Le funzionalità includono la creazione, l'elenco e l'eliminazione di raccolte di record e il caricamento, il recupero e l'eliminazione di record. L'astrazione semplifica l'esperimento con un archivio vettoriale gratuito o ospitato in locale e quindi passa a un servizio quando è necessario aumentare le prestazioni.

Astrazione dell'archivio vettoriale

Le interfacce principali nell'astrazione dell'archivio vettoriale sono le seguenti.

Microsoft.Extensions.VectorData.IVectorStore

IVectorStore contiene operazioni che si estendono su tutte le raccolte nell'archivio vettoriale, ad esempio ListCollectionNames. Offre anche la possibilità di ottenere IVectorStoreRecordCollection<TKey, TRecord> istanze.

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

IVectorStoreRecordCollection<TKey, TRecord> rappresenta una raccolta. Questa raccolta può essere o meno esistente e l'interfaccia fornisce metodi per verificare se la raccolta esiste, crearla o eliminarla. L'interfaccia fornisce anche metodi per l'upsert, il recupero e l'eliminazione di record. Infine, l'interfaccia eredita dalla IVectorizedSearch<TRecord> fornitura di funzionalità di ricerca vettoriale.

Microsoft.Extensions.VectorData.IVectorizedSearch<TRecord>

IVectorizedSearch<TRecord> contiene un metodo per eseguire ricerche vettoriali. IVectorStoreRecordCollection<TKey, TRecord> eredita dal IVectorizedSearch<TRecord> rendere possibile l'uso IVectorizedSearch<TRecord> autonomamente nei casi in cui è necessaria solo la ricerca e non è necessaria alcuna gestione di record o raccolta.

IVectorizableTextSearch<TRecord>

IVectorizableTextSearch<TRecord> contiene un metodo per eseguire ricerche vettoriali in cui il database vettoriale ha la possibilità di generare automaticamente incorporamenti. Ad esempio, è possibile chiamare questo metodo con una stringa di testo e il database genererà automaticamente l'incorporamento e la ricerca in un campo vettoriale. Questo non è supportato da tutti i database vettoriali ed è quindi implementato solo dai connettori selezionati.

Astrazione dell'archivio vettoriale

Le interfacce principali nell'astrazione dell'archivio vettoriale sono le seguenti.

com.microsoft.semantickernel.data.vectorstorage.VectorStore

VectorStore contiene operazioni che si estendono su tutte le raccolte nell'archivio vettoriale, ad esempio listCollectionNames. Offre anche la possibilità di ottenere VectorStoreRecordCollection<Key, Record> istanze.

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

VectorStoreRecordCollection<Key, Record> rappresenta una raccolta. Questa raccolta può essere o meno esistente e l'interfaccia fornisce metodi per verificare se la raccolta esiste, crearla o eliminarla. L'interfaccia fornisce anche metodi per l'upsert, il recupero e l'eliminazione di record. Infine, l'interfaccia eredita dalla VectorizedSearch<Record> fornitura di funzionalità di ricerca vettoriale.

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

VectorizedSearch<Record> contiene un metodo per eseguire ricerche vettoriali. VectorStoreRecordCollection<Key, Record> eredita dal VectorizedSearch<Record> rendere possibile l'uso VectorizedSearch<Record> autonomamente nei casi in cui è necessaria solo la ricerca e non è necessaria alcuna gestione di record o raccolta.

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

VectorizableTextSearch<Record> contiene un metodo per eseguire ricerche vettoriali in cui il database vettoriale ha la possibilità di generare automaticamente incorporamenti. Ad esempio, è possibile chiamare questo metodo con una stringa di testo e il database genererà automaticamente l'incorporamento e la ricerca in un campo vettoriale. Questo non è supportato da tutti i database vettoriali ed è quindi implementato solo dai connettori selezionati.

Introduzione ai connettori di Vector Store

Importare i pacchetti NuGet necessari

Tutte le interfacce dell'archivio vettoriale e tutte le classi correlate all'astrazione Microsoft.Extensions.VectorData.Abstractions sono disponibili nel pacchetto nuget. Ogni implementazione dell'archivio vettoriale è disponibile nel proprio pacchetto NuGet. Per un elenco delle implementazioni note, vedere la pagina Connettori predefiniti.

Il pacchetto di astrazioni può essere aggiunto in questo modo.

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

Avviso

Dalla versione 1.23.0 del kernel semantico, le astrazioni dell'archivio vettoriale sono state rimosse da Microsoft.SemanticKernel.Abstractions e sono disponibili nel nuovo pacchetto dedicato Microsoft.Extensions.VectorData.Abstractions .

Si noti che dalla versione 1.23.0, Microsoft.SemanticKernel.Abstractions ha una dipendenza da Microsoft.Extensions.VectorData.Abstractions, pertanto non è necessario fare riferimento a pacchetti aggiuntivi. Le astrazioni saranno tuttavia ora presenti nel nuovo Microsoft.Extensions.VectorData spazio dei nomi.

Quando si esegue l'aggiornamento dalla versione 1.22.0 o precedente alla versione 1.23.0 o successiva, sarà necessario aggiungere una clausola aggiuntiva using Microsoft.Extensions.VectorData; nei file in cui vengono usati uno dei tipi di astrazione di Vector Store, ad esempio IVectorStore, IVectorStoreRecordCollectionVectorStoreRecordDataAttribute, , , VectorStoreRecordKeyPropertye così via.

Questa modifica è stata apportata per supportare i provider di archivi vettoriali durante la creazione di implementazioni personalizzate. Un provider deve fare riferimento solo al Microsoft.Extensions.VectorData.Abstractions pacchetto. In questo modo si riducono i potenziali conflitti di versione e si consente al kernel semantico di continuare a evolversi rapidamente senza alcun impatto sul provider di archivi vettoriali.

Definire il modello di dati

I connettori dell'archivio vettoriale del kernel semantico usano un approccio basato sul modello per interagire con i database. Questo significa che il primo passaggio consiste nel definire un modello di dati mappato allo schema di archiviazione. Per consentire ai connettori di creare raccolte di record ed eseguire il mapping allo schema di archiviazione, il modello può essere annotato per indicare la funzione di ogni proprietà.

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; }
}

Suggerimento

Per altre informazioni su come annotare il modello di dati, vedere Definizione del modello di dati.

Suggerimento

Per un'alternativa all'annotazione del modello di dati, fare riferimento alla definizione dello schema con una definizione di record.

Connettersi al database e selezionare una raccolta

Dopo aver definito il modello di dati, il passaggio successivo consiste nel creare un'istanza vectorstore per il database preferito e selezionare una raccolta di record.

In questo esempio si userà Qdrant. Sarà quindi necessario importare il pacchetto NuGet Qdrant.

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

Poiché i database supportano molti tipi diversi di chiavi e record, è possibile specificare il tipo di chiave e di record per la raccolta usando i generics. In questo caso, il tipo di record sarà la Hotel classe già definita e il tipo di chiave sarà ulong, poiché la HotelId proprietà è un ulong e Qdrant supporta Guid solo o ulong chiavi.

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");

Poiché i database supportano molti tipi diversi di chiavi e record, è possibile specificare il tipo di chiave e di record per la raccolta usando i generics. In questo caso, il tipo di record sarà la Hotel classe già definita e il tipo di chiave sarà str, poiché la HotelId proprietà è un str e Qdrant supporta str solo o int chiavi.

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
)

Poiché i database supportano molti tipi diversi di chiavi e record, è possibile specificare il tipo di chiave e di record per la raccolta usando i generics. In questo caso, il tipo di record sarà la Hotel classe già definita e il tipo di chiave sarà String, poiché la hotelId proprietà è un String e l'archivio JDBC supporta String solo le chiavi.

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()
        );
    }
}

Suggerimento

Per altre informazioni sui tipi di chiave e di campo supportati da ogni connettore vector store, vedere la documentazione per ogni connettore.

Creare la raccolta e aggiungere record

// 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);

Creare la raccolta e aggiungere record

# 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();

Suggerimento

Per altre informazioni su come generare incorporamenti, vedere Generazione di incorporamenti.

// 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());

Suggerimento

Per altre informazioni su come generare incorporamenti, vedere Generazione di incorporamenti.

Passaggi successivi