Udostępnij za pośrednictwem


Co to są łączniki semantycznego magazynu wektorów jądra? (wersja zapoznawcza)

Ostrzeżenie

Funkcja semantycznego magazynu wektorów jądra jest dostępna w wersji zapoznawczej, a ulepszenia wymagające zmian powodujących niezgodność mogą nadal występować w ograniczonych okolicznościach przed wydaniem.

Napiwek

Jeśli szukasz informacji o starszych łącznikach magazynu pamięci, zapoznaj się ze stroną Magazyny pamięci.

Bazy danych wektorów mają wiele przypadków użycia w różnych domenach i aplikacjach, które obejmują przetwarzanie języka naturalnego (NLP), przetwarzanie obrazów (CV), systemy rekomendacji (RS) i inne obszary, które wymagają semantycznego zrozumienia i dopasowywania danych.

Jednym z przypadków użycia przechowywania informacji w bazie danych wektorów jest umożliwienie dużych modeli językowych (LLM) generowania bardziej odpowiednich i spójnych odpowiedzi. Duże modele językowe często napotykają wyzwania, takie jak generowanie niedokładnych lub nieistotnych informacji; brak spójności faktycznej lub zdrowego rozsądku; powtarzające się lub sprzeczne; jest stronniczy lub obraźliwy. Aby pomóc w pokonaniu tych wyzwań, możesz użyć wektorowej bazy danych do przechowywania informacji o różnych tematach, słowach kluczowych, faktach, opiniach i/lub źródłach związanych z żądaną domeną lub gatunkiem. Baza danych wektorów umożliwia efektywne znajdowanie podzestawu informacji związanych z konkretnym pytaniem lub tematem. Następnie możesz przekazać informacje z bazy danych wektorów z monitem do dużego modelu językowego, aby wygenerować dokładniejszą i odpowiednią zawartość.

Jeśli na przykład chcesz napisać wpis w blogu na temat najnowszych trendów w sztucznej inteligencji, możesz użyć bazy danych wektorów do przechowywania najnowszych informacji o tym temacie i przekazać informacje wraz z prośbą do llM w celu wygenerowania wpisu w blogu, który wykorzystuje najnowsze informacje.

Semantyczne jądro i platforma .net zapewniają abstrakcję interakcji z magazynami wektorów oraz listę wbudowanych łączników, które implementują te abstrakcji. Funkcje obejmują tworzenie, wyświetlanie i usuwanie kolekcji rekordów oraz przekazywanie, pobieranie i usuwanie rekordów. Abstrakcja ułatwia eksperymentowanie z bezpłatnym lub lokalnie hostowanym magazynem wektorów, a następnie przełączanie się do usługi w razie potrzeby skalowania w górę.

Generacja wspomagana wyszukiwaniem (RAG) z magazynami wektorów

Abstrakcje magazynów wektorów to interfejs API niskiego poziomu służący do dodawania i pobierania danych z magazynów wektorów. Kernel semantyczny ma wbudowaną obsługę korzystania z dowolnej implementacji magazynu wektorów dla RAG. Jest to osiągane przez zawijanie IVectorizedSearch<TRecord> i uwidacznianie go jako implementacji wyszukiwania tekstu.

Napiwek

Aby dowiedzieć się więcej na temat używania magazynów wektorów dla programu RAG, zobacz Jak używać magazynów wektorów z semantycznym wyszukiwaniem tekstu jądra.

Napiwek

Aby dowiedzieć się więcej na temat wyszukiwania tekstu, zobacz Co to jest wyszukiwanie tekstu jądra semantycznego?

Abstrakcję magazynu wektorów

Główne interfejsy w abstrakcji magazynu wektorów są następujące.

Microsoft.Extensions.VectorData.IVectorStore

IVectorStore zawiera operacje obejmujące wszystkie kolekcje w magazynie wektorów, np. ListCollectionNames. Zapewnia również możliwość pobierania IVectorStoreRecordCollection<TKey, TRecord> wystąpień.

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

IVectorStoreRecordCollection<TKey, TRecord> reprezentuje kolekcję. Ta kolekcja może lub nie istnieje, a interfejs udostępnia metody sprawdzania, czy kolekcja istnieje, utwórz ją lub usuń. Interfejs udostępnia również metody rozbudowy, pobierania i usuwania rekordów. Na koniec interfejs dziedziczy z IVectorizedSearch<TRecord> funkcji wyszukiwania wektorowego.

Microsoft.Extensions.VectorData.IVectorizedSearch<TRecord>

IVectorizedSearch<TRecord> zawiera metodę wykonywania wyszukiwań wektorowych. IVectorStoreRecordCollection<TKey, TRecord> dziedziczy z IVectorizedSearch<TRecord> możliwości używania IVectorizedSearch<TRecord> go samodzielnie w przypadkach, gdy jest potrzebne tylko wyszukiwanie i nie jest potrzebne żadne zarządzanie rekordami lub kolekcjami.

IVectorizableTextSearch<TRecord>

IVectorizableTextSearch<TRecord> Zawiera metodę wyszukiwania wektorowego, w której baza danych wektorów ma możliwość automatycznego generowania osadzonych. Na przykład można wywołać tę metodę za pomocą ciągu tekstowego, a baza danych wygeneruje osadzanie dla Ciebie i wyszuka pole wektora. Nie jest to obsługiwane przez wszystkie wektorowe bazy danych i dlatego jest implementowane tylko przez wybrane łączniki.

Generacja wspomagana wyszukiwaniem (RAG) z magazynami wektorów

Abstrakcje repozytoriów wektorów to niskopoziomowe API do dodawania i pobierania danych z tych repozytoriów. Semantyczne jądro ma wbudowaną obsługę korzystania z dowolnej implementacji magazynu wektorów dla programu RAG. Jest to osiągane przez zawijanie VectorSearchBase[TKey, TModel] za pomocą VectorizedSearchMixin[Tmodel], VectorizableTextSearchMixin[TModel] lub VectorTextSearch[TModel] i uwidacznianie go jako implementacji wyszukiwania tekstu.

Napiwek

Aby dowiedzieć się więcej na temat używania magazynów wektorów dla programu RAG, zobacz Jak używać magazynów wektorów z semantycznym wyszukiwaniem tekstu jądra.

Napiwek

Aby dowiedzieć się więcej na temat wyszukiwania tekstu, zobacz Co to jest wyszukiwanie tekstu jądra semantycznego?

Abstrakcję magazynu wektorów

Główne interfejsy w abstrakcji magazynu wektorów są następujące.

com.microsoft.semantickernel.data.vectorstorage.VectorStore

VectorStore zawiera operacje obejmujące wszystkie kolekcje w magazynie wektorów, np. listCollectionNames. Zapewnia również możliwość pobierania VectorStoreRecordCollection<Key, Record> wystąpień.

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

VectorStoreRecordCollection<Key, Record> reprezentuje kolekcję. Ta kolekcja może lub nie istnieje, a interfejs udostępnia metody sprawdzania, czy kolekcja istnieje, utwórz ją lub usuń. Interfejs udostępnia również metody rozbudowy, pobierania i usuwania rekordów. Na koniec interfejs dziedziczy z VectorizedSearch<Record> funkcji wyszukiwania wektorowego.

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

VectorizedSearch<Record> zawiera metodę wykonywania wyszukiwań wektorowych. VectorStoreRecordCollection<Key, Record> dziedziczy z VectorizedSearch<Record> możliwości używania VectorizedSearch<Record> go samodzielnie w przypadkach, gdy jest potrzebne tylko wyszukiwanie i nie jest potrzebne żadne zarządzanie rekordami lub kolekcjami.

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

VectorizableTextSearch<Record> Zawiera metodę wyszukiwania wektorowego, w której baza danych wektorów ma możliwość automatycznego generowania osadzonych. Na przykład można wywołać tę metodę za pomocą ciągu tekstowego, a baza danych wygeneruje osadzanie dla Ciebie i wyszuka pole wektora. Nie jest to obsługiwane przez wszystkie wektorowe bazy danych i dlatego jest implementowane tylko przez wybrane łączniki.

Wprowadzenie do łączników usługi Vector Store

Importowanie niezbędnych pakietów NuGet

Wszystkie interfejsy magazynu wektorów i wszystkie klasy powiązane z abstrakcją są dostępne w pakiecie Microsoft.Extensions.VectorData.Abstractions NuGet. Każda implementacja magazynu wektorów jest dostępna we własnym pakiecie NuGet. Aby uzyskać listę znanych implementacji, zobacz stronę Łączniki gotowe do użycia.

Pakiet abstrakcji można dodać w ten sposób.

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

Ostrzeżenie

Z wersji 1.23.0 jądra semantycznego abstrakcje magazynu wektorów zostały usunięte i Microsoft.SemanticKernel.Abstractions są dostępne w nowym dedykowanym Microsoft.Extensions.VectorData.Abstractions pakiecie.

Należy pamiętać, Microsoft.SemanticKernel.Abstractions że w wersji 1.23.0 istnieje zależność od Microsoft.Extensions.VectorData.Abstractionsprogramu , dlatego nie ma potrzeby odwołowania się do dodatkowych pakietów. Abstrakcje będą jednak teraz znajdować się w nowej Microsoft.Extensions.VectorData przestrzeni nazw.

Podczas uaktualniania z wersji 1.22.0 lub starszej do wersji 1.23.0 lub nowszej należy dodać dodatkową using Microsoft.Extensions.VectorData; klauzulę w plikach, w których są używane dowolne typy abstrakcji magazynu wektorów, np. IVectorStore, IVectorStoreRecordCollectionVectorStoreRecordDataAttribute, , VectorStoreRecordKeyPropertyitp.

Ta zmiana została wprowadzona w celu obsługi dostawców magazynu wektorów podczas tworzenia własnych implementacji. Dostawca musi odwoływać Microsoft.Extensions.VectorData.Abstractions się tylko do pakietu. Zmniejsza to potencjalne konflikty wersji i umożliwia kontynuowanie szybkiego rozwoju jądra semantycznego bez wpływu na dostawców magazynu wektorów.

Definiowanie modelu danych

Łączniki semantycznego magazynu wektorów jądra używają modelu pierwszego podejścia do interakcji z bazami danych. Oznacza to, że pierwszym krokiem jest zdefiniowanie modelu danych mapowania na schemat magazynu. Aby ułatwić łącznikom tworzenie kolekcji rekordów i mapowanie na schemat magazynu, można dodać adnotacje do modelu, aby wskazać funkcję każdej właściwości.

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

Napiwek

Aby uzyskać więcej informacji na temat dodawania adnotacji do modelu danych, zobacz Definiowanie modelu danych.

Napiwek

Alternatywą dla dodawania adnotacji do modelu danych jest definiowanie schematu przy użyciu definicji rekordu.

Nawiązywanie połączenia z bazą danych i wybieranie kolekcji

Po zdefiniowaniu modelu danych następnym krokiem jest utworzenie wybranej bazy danych wystąpienia VectorStore i wybranie kolekcji rekordów.

W tym przykładzie użyjemy funkcji Qdrant. W związku z tym należy zaimportować pakiet nuget Qdrant.

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

Jeśli chcesz uruchomić usługę Qdrant lokalnie przy użyciu platformy Docker, użyj następującego polecenia, aby uruchomić kontener Qdrant z ustawieniami używanymi w tym przykładzie.

docker run -d --name qdrant -p 6333:6333 -p 6334:6334 qdrant/qdrant:latest

Aby sprawdzić, czy wystąpienie usługi Qdrant działa prawidłowo, odwiedź pulpit nawigacyjny Qdrant wbudowany w kontener Docker Qdrant: http://localhost:6333/dashboard

Ponieważ bazy danych obsługują wiele różnych typów kluczy i rekordów, umożliwiamy określenie typu klucza i rekordu dla kolekcji przy użyciu typów ogólnych. W naszym przypadku typ rekordu będzie klasą Hotel , która została już zdefiniowana, a typem klucza będzie ulong, ponieważ HotelId właściwość to i ulong funkcja Qdrant obsługuje Guid tylko klucze lub ulong .

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

Ponieważ bazy danych obsługują wiele różnych typów kluczy i rekordów, umożliwiamy określenie typu klucza i rekordu dla kolekcji przy użyciu typów ogólnych. W naszym przypadku typ rekordu będzie klasą Hotel , która została już zdefiniowana, a typem klucza będzie str, ponieważ HotelId właściwość to i str funkcja Qdrant obsługuje str tylko klucze lub int .

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
)

Ponieważ bazy danych obsługują wiele różnych typów kluczy i rekordów, umożliwiamy określenie typu klucza i rekordu dla kolekcji przy użyciu typów ogólnych. W naszym przypadku typ rekordu będzie klasą Hotel , która została już zdefiniowana, a typem klucza będzie String, ponieważ hotelId właściwość jest magazynem String JDBC i obsługuje String tylko klucze.

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

Napiwek

Aby uzyskać więcej informacji na temat typów kluczy i pól, które obsługuje łącznik Vector Store, zapoznaj się z dokumentacją każdego łącznika.

Tworzenie kolekcji i dodawanie rekordów

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

Tworzenie kolekcji i dodawanie rekordów

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

Napiwek

Aby uzyskać więcej informacji na temat sposobu generowania osadzania, zobacz osadzanie generowania.

// 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 = await collection.VectorizedSearchAsync(searchVector, new() { Top = 1 });

// Inspect the returned hotel.
await foreach (var record in searchResult.Results)
{
    Console.WriteLine("Found hotel description: " + record.Record.Description);
    Console.WriteLine("Found record score: " + record.Score);
}

Wykonywanie wyszukiwania wektorowego

# Generate a vector for your search text, using your chosen embedding generation implementation.
# Just showing a placeholder method here for brevity.
search_vector = await GenerateEmbedding("I'm looking for a hotel where customer happiness is the priority.");
# Do the search.
search_result = await collection.vectorized_search(vector=searchVector, VectorSearchOptions(top = 1 ))

# Inspect the returned hotels.
async for result in search_result.results:
    print(f"Found hotel description: {result.record.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());

Napiwek

Aby uzyskać więcej informacji na temat sposobu generowania osadzania, zobacz osadzanie generowania.

Następne kroki