Partilhar via


O que são conectores do Semantic Kernel Vetor Store? (Pré-visualização)

Aviso

A funcionalidade Semantic Kernel Vetor Store está em pré-visualização, e melhorias que exigem alterações de quebra ainda podem ocorrer em circunstâncias limitadas antes do lançamento.

Gorjeta

Se você estiver procurando informações sobre os conectores de armazenamento de memória herdados, consulte a página Armazenamentos de memória.

Os bancos de dados vetoriais têm muitos casos de uso em diferentes domínios e aplicativos que envolvem processamento de linguagem natural (NLP), visão computacional (CV), sistemas de recomendação (RS) e outras áreas que exigem compreensão semântica e correspondência de dados.

Um caso de uso para armazenar informações em um banco de dados vetorial é permitir que grandes modelos de linguagem (LLMs) gerem respostas mais relevantes e coerentes. Os modelos linguísticos de grande dimensão enfrentam frequentemente desafios como a geração de informações imprecisas ou irrelevantes; falta de coerência factual ou de bom senso; repetir-se ou contradizer-se; ser tendencioso ou ofensivo. Para ajudar a superar esses desafios, você pode usar um banco de dados vetorial para armazenar informações sobre diferentes tópicos, palavras-chave, fatos, opiniões e/ou fontes relacionadas ao domínio ou gênero desejado. O banco de dados vetorial permite que você encontre eficientemente o subconjunto de informações relacionadas a uma pergunta ou tópico específico. Em seguida, você pode passar informações do banco de dados vetorial com seu prompt para seu modelo de linguagem grande para gerar conteúdo mais preciso e relevante.

Por exemplo, se você quiser escrever uma postagem de blog sobre as últimas tendências em IA, você pode usar um banco de dados vetorial para armazenar as informações mais recentes sobre esse tópico e passar as informações junto com a solicitação para um LLM, a fim de gerar uma postagem de blog que aproveite as informações mais recentes.

O Semantic Kernel e o .net fornecem uma abstração para interagir com Vetor Stores e uma lista de conectores prontos para uso que implementam essas abstrações. Os recursos incluem criar, listar e excluir coleções de registros e carregar, recuperar e excluir registros. A abstração facilita a experimentação com um Vetor Store gratuito ou hospedado localmente e, em seguida, alterna para um serviço quando precisar aumentar a escala.

A abstração do repositório vetorial

As principais interfaces na abstração do Vetor Store são as seguintes.

Microsoft.Extensions.VectorData.IVectorStore

IVectorStore contém operações que abrangem todas as coleções no repositório de vetores, por exemplo, ListCollectionNames. Ele também fornece a capacidade de obter IVectorStoreRecordCollection<TKey, TRecord> instâncias.

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

IVectorStoreRecordCollection<TKey, TRecord> representa uma coleção. Essa coleção pode ou não existir, e a interface fornece métodos para verificar se a coleção existe, criá-la ou excluí-la. A interface também fornece métodos para upsert, obter e excluir registros. Finalmente, a interface herda do fornecimento de recursos de IVectorizedSearch<TRecord> pesquisa vetorial.

Microsoft.Extensions.VectorData.IVectorizedSearch<TRecord>

IVectorizedSearch<TRecord> Contém um método para fazer pesquisas vetoriais. IVectorStoreRecordCollection<TKey, TRecord> herda de IVectorizedSearch<TRecord> tornar possível a utilização IVectorizedSearch<TRecord> por conta própria nos casos em que apenas a pesquisa é necessária e nenhum registro ou gerenciamento de coleta é necessário.

IVectorizableTextSearch<TRecord>

IVectorizableTextSearch<TRecord> Contém um método para fazer pesquisas vetoriais onde o banco de dados vetorial tem a capacidade de gerar incorporações automaticamente. Por exemplo, você pode chamar esse método com uma cadeia de texto e o banco de dados gerará a incorporação para você e pesquisará em um campo vetorial. Isso não é suportado por todos os bancos de dados vetoriais e, portanto, só é implementado por conectores selecionados.

A abstração do repositório vetorial

As principais interfaces na abstração do Vetor Store são as seguintes.

com.microsoft.semantickernel.data.vectorstorage.VectorStore

VectorStore contém operações que abrangem todas as coleções no repositório de vetores, por exemplo, listCollectionNames. Ele também fornece a capacidade de obter VectorStoreRecordCollection<Key, Record> instâncias.

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

VectorStoreRecordCollection<Key, Record> representa uma coleção. Essa coleção pode ou não existir, e a interface fornece métodos para verificar se a coleção existe, criá-la ou excluí-la. A interface também fornece métodos para upsert, obter e excluir registros. Finalmente, a interface herda do fornecimento de recursos de VectorizedSearch<Record> pesquisa vetorial.

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

VectorizedSearch<Record> Contém um método para fazer pesquisas vetoriais. VectorStoreRecordCollection<Key, Record> herda de VectorizedSearch<Record> tornar possível a utilização VectorizedSearch<Record> por conta própria nos casos em que apenas a pesquisa é necessária e nenhum registro ou gerenciamento de coleta é necessário.

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

VectorizableTextSearch<Record> Contém um método para fazer pesquisas vetoriais onde o banco de dados vetorial tem a capacidade de gerar incorporações automaticamente. Por exemplo, você pode chamar esse método com uma cadeia de texto e o banco de dados gerará a incorporação para você e pesquisará em um campo vetorial. Isso não é suportado por todos os bancos de dados vetoriais e, portanto, só é implementado por conectores selecionados.

Introdução aos conectores do Vetor Store

Importe os pacotes nuget necessários

Todas as interfaces de armazenamento vetorial e quaisquer classes relacionadas à Microsoft.Extensions.VectorData.Abstractions abstração estão disponíveis no pacote nuget. Cada implementação de armazenamento vetorial está disponível em seu próprio pacote nuget. Para obter uma lista de implementações conhecidas, consulte a página Conectores prontos para uso.

O pacote de abstrações pode ser adicionado assim.

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

Aviso

A partir da versão 1.23.0 do Semantic Kernel, as abstrações do Microsoft.SemanticKernel.Abstractions Vetor Store foram removidas e estão disponíveis no novo pacote dedicado Microsoft.Extensions.VectorData.Abstractions .

Note que a partir da versão 1.23.0, tem uma dependência de Microsoft.Extensions.VectorData.Abstractions, portanto, Microsoft.SemanticKernel.Abstractions não há necessidade de fazer referência a pacotes adicionais. As abstrações, no entanto, agora estarão no novo Microsoft.Extensions.VectorData namespace.

Ao atualizar de 1.22.0 ou anterior para 1.23.0 ou posterior, você precisará adicionar uma cláusula adicional using Microsoft.Extensions.VectorData; em arquivos onde qualquer um dos tipos de abstração do Vetor Store são usados, por exemplo, , IVectorStoreRecordCollection, VectorStoreRecordDataAttribute, VectorStoreRecordKeyProperty, etc. IVectorStore

Essa alteração foi feita para dar suporte a provedores de armazenamento de vetores ao criar suas próprias implementações. Um provedor só precisa fazer referência ao Microsoft.Extensions.VectorData.Abstractions pacote. Isso reduz possíveis conflitos de versão e permite que o Semantic Kernel continue a evoluir rapidamente sem afetar os provedores de armazenamento vetorial.

Defina seu modelo de dados

Os conectores do Semantic Kernel Vetor Store usam uma abordagem de modelo inicial para interagir com bancos de dados. Isso significa que a primeira etapa é definir um modelo de dados que mapeie para o esquema de armazenamento. Para ajudar os conectores a criar coleções de registros e mapear para o esquema de armazenamento, o modelo pode ser anotado para indicar a função de cada propriedade.

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

Gorjeta

Para obter mais informações sobre como anotar seu modelo de dados, consulte Definindo seu modelo de dados.

Gorjeta

Para obter uma alternativa à anotação do modelo de dados, consulte a definição do esquema com uma definição de registro.

Conecte-se ao seu banco de dados e selecione uma coleção

Depois de definir seu modelo de dados, a próxima etapa é criar uma instância VectorStore para o banco de dados de sua escolha e selecionar uma coleção de registros.

Neste exemplo, usaremos o Qdrant. Portanto, você precisará importar o pacote nuget Qdrant.

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

Como os bancos de dados suportam muitos tipos diferentes de chaves e registros, permitimos que você especifique o tipo de chave e registro para sua coleção usando genéricos. No nosso caso, o tipo de registo será a Hotel classe que já definimos, e o tipo de chave será ulong, uma vez que a HotelId propriedade é a ulong e Qdrant apenas suporta Guid ou ulong chaves.

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

Como os bancos de dados suportam muitos tipos diferentes de chaves e registros, permitimos que você especifique o tipo de chave e registro para sua coleção usando genéricos. No nosso caso, o tipo de registo será a Hotel classe que já definimos, e o tipo de chave será str, uma vez que a HotelId propriedade é a str e Qdrant apenas suporta str ou int chaves.

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
)

Como os bancos de dados suportam muitos tipos diferentes de chaves e registros, permitimos que você especifique o tipo de chave e registro para sua coleção usando genéricos. No nosso caso, o tipo de registro será a Hotel classe que já definimos, e o tipo de chave será String, já que a hotelId propriedade é uma String e o armazenamento JDBC só suporta String chaves.

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

Gorjeta

Para obter mais informações sobre quais tipos de chave e campo cada conector do Vetor Store suporta, consulte a documentação de cada conector.

Criar a coleção e adicionar registros

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

Criar a coleção e adicionar registros

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

Gorjeta

Para obter mais informações sobre como gerar incorporações, consulte Geração de incorporação.

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

Gorjeta

Para obter mais informações sobre como gerar incorporações, consulte Geração de incorporação.

Próximos passos