Поделиться через


Что такое соединители хранилища векторов семантического ядра? (Предварительная версия)

Предупреждение

Функции хранилища векторов семантического ядра доступны в предварительной версии и улучшения, требующие критических изменений, могут по-прежнему возникать в ограниченных обстоятельствах перед выпуском.

Совет

Если вы ищете сведения о устаревших соединителях хранилища памяти, перейдите на страницу хранилища памяти.

Векторные базы данных имеют множество вариантов использования в разных доменах и приложениях, которые включают обработку естественного языка (NLP), компьютерное зрение (CV), системы рекомендаций (RS) и другие области, требующие семантического понимания и сопоставления данных.

Одним из вариантов использования для хранения информации в векторной базе данных является включение больших языковых моделей (LLM) для создания более релевантных и согласованных ответов. Крупные языковые модели часто сталкиваются с проблемами, такими как создание неточных или неуместных сведений; отсутствие фактической согласованности или здравого смысла; повторение или противоречие себе; быть предвзятым или оскорбительным. Чтобы устранить эти проблемы, можно использовать векторную базу данных для хранения информации о различных темах, ключевых словах, фактах, мнениях и/или источниках, связанных с нужным доменом или жанром. База данных векторов позволяет эффективно находить подмножество информации, связанной с определенным вопросом или разделом. Затем вы можете передать информацию из векторной базы данных с запросом на большую языковую модель, чтобы создать более точное и соответствующее содержимое.

Например, если вы хотите написать запись блога о последних тенденциях ВИ, можно использовать векторную базу данных для хранения последних сведений об этом разделе и передачи информации вместе с запросом на LLM, чтобы создать запись блога, которая использует последнюю информацию.

Семантический ядро и .net предоставляют абстракцию для взаимодействия с векторными хранилищами и список встроенных соединителей, реализующих эти абстракции. Функции включают создание, перечисление и удаление коллекций записей, а также отправку, извлечение и удаление записей. Абстракции позволяет легко экспериментировать с бесплатным или локально размещенным векторным хранилищем, а затем переключиться на службу при необходимости увеличения масштаба.

Извлечение дополненной генерации (RAG) с векторными хранилищами

Абстракции хранилища векторов — это api низкого уровня для добавления и получения данных из векторных хранилищ. Семантическое ядро имеет встроенную поддержку использования любой из реализаций векторного хранилища для RAG. Это достигается путем упаковки IVectorizedSearch<TRecord> и представления его в качестве реализации текстового поиска.

Совет

Дополнительные сведения об использовании векторных хранилищ для RAG см. в Использование векторных хранилищ с семантическим поиском текста ядра.

Совет

Дополнительные сведения о поиске текста см. в статье Что такое поиск текста семантического ядра?

Абстракция хранилища векторов

Ниже приведены основные интерфейсы абстракции векторного хранилища.

Microsoft.Extensions.VectorData.IVectorStore

IVectorStore содержит операции, охватывающие все коллекции в хранилище векторов, например ListCollectionNames. Он также предоставляет возможность получения IVectorStoreRecordCollection<TKey, TRecord> экземпляров.

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

IVectorStoreRecordCollection<TKey, TRecord> представляет коллекцию. Эта коллекция может существовать или не существовать, и интерфейс предоставляет методы для проверки наличия коллекции, создания или удаления. Интерфейс также предоставляет методы для upsert, получения и удаления записей. Наконец, интерфейс наследует от IVectorizedSearch<TRecord> предоставления возможностей поиска векторов.

Microsoft.Extensions.VectorData.IVectorizedSearch<TRecord>

IVectorizedSearch<TRecord> содержит метод для выполнения векторного поиска. IVectorStoreRecordCollection<TKey, TRecord> наследует от IVectorizedSearch<TRecord> того, чтобы можно было использовать IVectorizedSearch<TRecord> самостоятельно в тех случаях, когда требуется только поиск, а управление записями или коллекциями не требуется.

IVectorizableTextSearch<TRecord>

IVectorizableTextSearch<TRecord> содержит метод для выполнения векторного поиска, в котором база данных векторов имеет возможность автоматически создавать внедрения. Например, можно вызвать этот метод с текстовой строкой, и база данных создаст внедрение для вас и выполните поиск в поле вектора. Это не поддерживается всеми базами данных векторов и поэтому реализуется только с помощью соединителей выбора.

Получение дополненного поколения (RAG) с векторными хранилищами

Абстракции хранилища векторов — это api низкого уровня для добавления и получения данных из векторных хранилищ. Semantic Kernel имеет встроенную поддержку использования любой из реализаций векторных хранилищ для RAG. Это достигается, обернув VectorSearchBase[TKey, TModel] с помощью VectorizedSearchMixin[Tmodel], VectorizableTextSearchMixin[TModel] или VectorTextSearch[TModel] и представляя его в виде реализации поиска текста.

Совет

Дополнительные сведения об использовании векторных хранилищ для RAG см. в статье Использование векторных хранилищ с семантического ядра текстового поиска.

Совет

Дополнительные сведения о поиске текста см. в статье Что такое поиск текста семантического ядра?

Абстракция хранилища векторов

Ниже приведены основные интерфейсы абстракции векторного хранилища.

com.microsoft.semantickernel.data.vectorstorage.VectorStore

VectorStore содержит операции, охватывающие все коллекции в векторном хранилище, например listCollectionNames. Он также предоставляет возможность получения VectorStoreRecordCollection<Key, Record> экземпляров.

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

VectorStoreRecordCollection<Key, Record> представляет коллекцию. Эта коллекция может существовать или не существовать, и интерфейс предоставляет методы для проверки наличия коллекции, создания или удаления. Интерфейс также предоставляет методы для upsert, получения и удаления записей. Наконец, интерфейс наследует от VectorizedSearch<Record> предоставления возможностей поиска векторов.

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

VectorizedSearch<Record> содержит метод для выполнения векторного поиска. VectorStoreRecordCollection<Key, Record> наследует от VectorizedSearch<Record> того, чтобы можно было использовать VectorizedSearch<Record> самостоятельно в тех случаях, когда требуется только поиск, а управление записями или коллекциями не требуется.

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

VectorizableTextSearch<Record> содержит метод для выполнения векторного поиска, в котором база данных векторов имеет возможность автоматически создавать внедрения. Например, можно вызвать этот метод с текстовой строкой, и база данных создаст внедрение для вас и выполните поиск в поле вектора. Это не поддерживается всеми базами данных векторов и поэтому реализуется только с помощью соединителей выбора.

Начало работы с соединителями Vector Store

Импорт необходимых пакетов nuget

Все интерфейсы хранилища векторов и все связанные с абстракцией классы доступны в пакете Microsoft.Extensions.VectorData.Abstractions nuget. Каждая реализация хранилища векторов доступна в собственном пакете nuget. Список известных реализаций см. на странице соединителей вне поля.

Пакет абстракций можно добавить следующим образом.

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

Предупреждение

Из версии 1.23.0 семантического ядра абстракции векторного хранилища были удалены Microsoft.SemanticKernel.Abstractions и доступны в новом выделенном Microsoft.Extensions.VectorData.Abstractions пакете.

Обратите внимание, что от версии 1.23.0 зависитMicrosoft.SemanticKernel.Abstractions, Microsoft.Extensions.VectorData.Abstractions поэтому нет необходимости ссылаться на дополнительные пакеты. Абстракции, однако, теперь будут находиться в новом Microsoft.Extensions.VectorData пространстве имен.

При обновлении с версии 1.22.0 или более поздней версии до версии 1.23.0 или более поздней версии необходимо добавить дополнительное using Microsoft.Extensions.VectorData; предложение в файлы, в которых используются любые типы абстракции векторного хранилища, например IVectorStore, IVectorStoreRecordCollection, VectorStoreRecordDataAttributeи VectorStoreRecordKeyPropertyт. д.

Это изменение было внесено для поддержки поставщиков хранилища векторов при создании собственных реализаций. Поставщик должен ссылаться только на Microsoft.Extensions.VectorData.Abstractions пакет. Это снижает потенциальные конфликты версий и позволяет семантике ядра продолжать развиваться быстро, не влияя на поставщиков хранилища векторов.

Определение модели данных

Соединители хранилища векторов семантического ядра используют модель первого подхода к взаимодействию с базами данных. Это означает, что первым шагом является определение модели данных, которая сопоставляется со схемой хранения. Чтобы помочь соединителям создавать коллекции записей и сопоставляться со схемой хранилища, модель может быть аннотирована, чтобы указать функцию каждого свойства.

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

Совет

Дополнительные сведения о том, как означать модель данных, см. в определении модели данных.

Совет

Для альтернативы аннотации модели данных см . определение схемы с определением записи.

Подключение к базе данных и выбор коллекции

После определения модели данных необходимо создать экземпляр VectorStore для выбранной базы данных и выбрать коллекцию записей.

В этом примере мы будем использовать Qdrant. Поэтому необходимо импортировать пакет nuget Qdrant.

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

Если вы хотите запустить Qdrant локально с помощью Docker, используйте следующую команду, чтобы запустить контейнер Qdrant с параметрами, используемыми в этом примере.

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

Чтобы убедиться, что экземпляр Qdrant работает правильно, посетите панель мониторинга Qdrant, встроенную в контейнер Docker: http://localhost:6333/dashboard

Так как базы данных поддерживают множество различных типов ключей и записей, мы можем указать тип ключа и записи для коллекции с помощью универсальных шаблонов. В нашем случае тип записи будет классом Hotel , который мы уже определили, и тип ключа будет ulong, так как HotelId свойство является ulong и Qdrant поддерживает Guid только ключ или 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");

Так как базы данных поддерживают множество различных типов ключей и записей, мы можем указать тип ключа и записи для коллекции с помощью универсальных шаблонов. В нашем случае тип записи будет классом Hotel , который мы уже определили, и тип ключа будет str, так как HotelId свойство является str и Qdrant поддерживает str только ключ или 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
)

Так как базы данных поддерживают множество различных типов ключей и записей, мы можем указать тип ключа и записи для коллекции с помощью универсальных шаблонов. В нашем случае тип записи будет классом Hotel , который мы уже определили, и тип ключа будет String, так как hotelId свойство является хранилищем String JDBC только поддерживает String ключи.

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

Совет

Дополнительные сведения о том, какие ключи и типы полей поддерживает каждый соединитель Vector Store, см . в документации по каждому соединителю.

Создание коллекции и добавление записей

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

Создание коллекции и добавление записей

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

Совет

Дополнительные сведения о создании внедрения см . в разделе "Создание внедрения".

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

Выполнить векторный поиск

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

Совет

Дополнительные сведения о создании внедрения см . в разделе "Создание внедрения".

Следующие шаги