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
, IVectorStoreRecordCollection
VectorStoreRecordDataAttribute
, , , VectorStoreRecordKeyProperty
e 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.
Eseguire una ricerca vettoriale
// 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.