Nota
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare ad accedere o modificare le directory.
L'accesso a questa pagina richiede l'autorizzazione. È possibile provare a modificare le directory.
Avviso
La funzionalità di archiviazione vettoriale del kernel semantico è in fase di release candidate (RC) e miglioramenti che richiedono modifiche significative potrebbero ancora verificarsi in circostanze limitate prima del rilascio.
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 obsoleti, 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 di vettori e un elenco di connettori già pronti 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 sperimentare con un archivio vettoriale gratuito o ospitato in locale e quindi passare a un servizio quando è necessario scalare.
Generazione aumentata di recupero (RAG) con archivi vettoriali
Le astrazioni dell'archivio vettoriale sono un'API di basso livello per l'aggiunta e il recupero di dati dagli archivi vettoriali.
Il Kernel Semantico ha il supporto integrato per l'uso di una delle implementazioni di Vector Store per RAG.
Questo risultato viene ottenuto incapsulando IVectorSearchable<TRecord>
e rendendolo disponibile come un'implementazione di ricerca di testo.
Suggerimento
Per altre informazioni su come usare gli archivi vettoriali per RAG, vedere Come usare gli archivi vettoriali con la ricerca di testo del kernel semantico.
Suggerimento
Per altre informazioni sulla ricerca di testo, vedere Che cos'è la ricerca di testo del kernel semantico?
Astrazione della memoria vettoriale
Di seguito sono riportate le classi e le interfacce di base astratte principali nell'astrazione Vector Store.
Microsoft.Extensions.VectorData.VectorStore
VectorStore
contiene operazioni che si estendono su tutte le raccolte nell'archivio vettoriale, ad esempio ListCollectionNames.
Offre anche la possibilità di ottenere istanze di VectorStoreCollection<TKey, TRecord>
.
Microsoft.Extensions.VectorData.VectorStoreCollection<TKey, TRecord>
VectorStoreCollection<TKey, TRecord>
rappresenta una raccolta.
Questa raccolta può essere o meno esistente e la classe base astratta fornisce metodi per verificare se la raccolta esiste, crearla o eliminarla.
La classe base astratta fornisce anche metodi per upsert, ottenere ed eliminare record.
Infine, la classe base astratta eredita dalla IVectorSearchable<TRecord>
fornitura di funzionalità di ricerca vettoriale.
Microsoft.Extensions.VectorData.IVectorSearchable<TRecord>
-
SearchAsync<TRecord>
può essere usato per eseguire una delle operazioni seguenti:- ricerche vettoriali che accettano alcuni input che possono essere vettorizzati da un generatore di incorporamento registrato o dal database vettoriale in cui il database supporta questo.
- ricerche vettoriali che accettano un vettore come input.
Generazione aumentata di recupero (RAG) con archivi vettoriali
Le astrazioni dell'archivio vettoriale sono un'API di basso livello per l'aggiunta e il recupero di dati dagli archivi vettoriali.
Il Kernel Semantico ha il supporto integrato per l'uso di una delle implementazioni di Vector Store per RAG.
Il risultato si ottiene incapsulando VectorSearchBase[TKey, TModel]
con VectorizedSearchMixin[Tmodel]
, VectorizableTextSearchMixin[TModel]
o VectorTextSearch[TModel]
ed esponendolo come implementazione di ricerca testuale.
Suggerimento
Per altre informazioni su come usare gli archivi vettoriali per RAG, vedere Come usare gli archivi vettoriali con la ricerca di testo del kernel semantico.
Suggerimento
Per altre informazioni sulla ricerca di testo, vedere Che cos'è la ricerca di testo del kernel semantico?
Astrazione della memoria vettoriale
Le interfacce principali nell'ambito dell'astrazione del Vector Store 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 istanze di VectorStoreRecordCollection<Key, Record>
.
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 aggiornare o inserire, recuperare e eliminare i dati.
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
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
{
[VectorStoreKey]
public ulong HotelId { get; set; }
[VectorStoreData(IsIndexed = true)]
public string HotelName { get; set; }
[VectorStoreData(IsFullTextIndexed = true)]
public string Description { get; set; }
[VectorStoreVector(Dimensions: 4, DistanceFunction = DistanceFunction.CosineSimilarity, IndexKind = IndexKind.Hnsw)]
public ReadOnlyMemory<float>? DescriptionEmbedding { get; set; }
[VectorStoreData(IsIndexed = true)]
public string[] Tags { get; set; }
}
from dataclasses import dataclass, field
from typing import Annotated
from semantic_kernel.data.vector import (
DistanceFunction,
IndexKind,
VectorStoreField,
vectorstoremodel,
)
@vectorstoremodel
@dataclass
class Hotel:
hotel_id: Annotated[str, VectorStoreField('key')] = field(default_factory=lambda: str(uuid4()))
hotel_name: Annotated[str, VectorStoreField('data', is_filterable=True)]
description: Annotated[str, VectorStoreField('data', is_full_text_searchable=True)]
description_embedding: Annotated[list[float], VectorStoreField('vector', dimensions=4, distance_function=DistanceFunction.COSINE, index_kind=IndexKind.HNSW)]
tags: Annotated[list[str], VectorStoreField('data', 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
Se si vuole eseguire Qdrant in locale usando Docker, usare il comando seguente per avviare il contenitore Qdrant con le impostazioni usate in questo esempio.
docker run -d --name qdrant -p 6333:6333 -p 6334:6334 qdrant/qdrant:latest
Per verificare che l'istanza di Qdrant sia operativa correttamente, visitare il dashboard Qdrant integrato nel Docker container: http://localhost:6333/dashboard
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 classe Hotel
che abbiamo già definito e il tipo di chiave sarà ulong
, poiché la proprietà HotelId
è un ulong
e Qdrant supporta solo chiavi Guid
o ulong
.
using Microsoft.SemanticKernel.Connectors.Qdrant;
using Qdrant.Client;
// Create a Qdrant VectorStore object
var vectorStore = new QdrantVectorStore(new QdrantClient("localhost"), ownsClient: true);
// 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 classe Hotel
che abbiamo già definito e il tipo di chiave sarà str
, poiché la proprietà HotelId
è un str
e Qdrant supporta solo chiavi str
o int
.
from semantic_kernel.connectors.qdrant import QdrantCollection
# Create a collection specify the type of key and record stored in it via Generic parameters.
collection: QdrantCollection[str, Hotel] = QdrantCollection(
record_type=Hotel,
collection_name="skhotels" # this is optional, you can also specify the collection_name in the vectorstoremodel decorator.
)
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
// Placeholder embedding generation method.
async Task<ReadOnlyMemory<float>> GenerateEmbeddingAsync(string textToVectorize)
{
// your logic here
}
// Create the collection if it doesn't exist yet.
await collection.EnsureCollectionExistsAsync();
// 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.
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.ensure_collection_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
// Placeholder embedding generation method.
async Task<ReadOnlyMemory<float>> GenerateEmbeddingAsync(string textToVectorize)
{
// your logic here
}
// Generate a vector for your search text, using your chosen embedding generation implementation.
ReadOnlyMemory<float> searchVector = await GenerateEmbeddingAsync("I'm looking for a hotel where customer happiness is the priority.");
// Do the search.
var searchResult = collection.SearchAsync(searchVector, top: 1);
// Inspect the returned hotel.
await foreach (var record in searchResult)
{
Console.WriteLine("Found hotel description: " + record.Record.Description);
Console.WriteLine("Found record score: " + record.Score);
}
Eseguire una ricerca vettoriale
Il metodo di ricerca può essere utilizzato per cercare i record nella raccolta. Accetta una stringa, che viene quindi vettorializzata utilizzando la configurazione per la generazione di incapsulamento nel modello o nella raccolta, oppure un vettore già generato.
# Do a search.
search_result = await collection.search("I'm looking for a hotel where customer happiness is the priority.", vector_property_name="description_embedding", top=3)
# Inspect the returned hotels.
async for result in search_result.results:
print(f"Found hotel description: {result.record.description}")
Creare una funzione di ricerca
Per creare una semplice funzione di ricerca che può essere usata per cercare gli hotel, è possibile usare il create_search_function
metodo nella raccolta.
Il nome e la descrizione, nonché i nomi e le descrizioni dei parametri, vengono usati per generare una firma di funzione inviata a LLM quando viene usata la chiamata di funzione. Ciò significa che modificare questo può essere utile per ottenere che l'LLM generi la chiamata di funzione corretta.
collection.create_search_function(
function_name="hotel_search",
description="A hotel search engine, allows searching for hotels in specific cities, "
"you do not have to specify that you are searching for hotels, for all, use `*`."
)
Esistono molti altri parametri, ad esempio questa è l'aspetto di una versione più complessa, si noti la personalizzazione dei parametri e la string_mapper
funzione usata per convertire il record in una stringa.
from semantic_kernel.function import KernelParameterMetadata
collection.create_search_function(
function_name="hotel_search",
description="A hotel search engine, allows searching for hotels in specific cities, "
"you do not have to specify that you are searching for hotels, for all, use `*`.",
search_type="keyword_hybrid", # default is "vector"
parameters=[
KernelParameterMetadata(
name="query",
description="The terms you want to search for in the hotel database.",
type="str",
is_required=True,
type_object=str,
),
KernelParameterMetadata(
name="tags",
description="The tags you want to search for in the hotel database, use `*` to match all.",
type="str",
type_object=str,
default_value="*",
),
KernelParameterMetadata(
name="top",
description="Number of results to return.",
type="int",
default_value=5,
type_object=int,
),
],
# finally, we specify the `string_mapper` function that is used to convert the record to a string.
# This is used to make sure the relevant information from the record is passed to the LLM.
string_mapper=lambda x: f"Hotel {x.record.hotel_name}: {x.record.description}. Tags: {x.record.tags} (hotel_id: {x.record.hotel_id}) ",
)
Suggerimento
Per altri esempi, inclusi esempi completi, vedere il repository di esempi di Semantic Kernel.
// 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.