O que são conectores do Repositório de Vetores do Kernel Semântico? (versão prévia)
Aviso
A funcionalidade do Repositório de Vetores do Kernel Semântico está em versão prévia e as melhorias que exigem alterações significativas ainda podem ocorrer em circunstâncias limitadas antes do lançamento.
Dica
Se você estiver procurando informações sobre os conectores herdados do Armazenamento de Memória, 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. Grandes modelos de linguagem geralmente enfrentam desafios como gerar informações imprecisas ou irrelevantes; falta de consistência factual ou bom senso; repetindo ou contradizendo-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 com eficiência 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ê deseja escrever uma postagem de blog sobre as últimas tendências em IA, 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 para gerar uma postagem de blog que aproveite as informações mais recentes.
O Kernel Semântico e o .net fornecem uma abstração para interagir com Repositórios de Vetores 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 Vector Store gratuito ou hospedado localmente e, em seguida, a alternância para um serviço quando for necessário escalar verticalmente.
A abstração do repositório de vetores
As principais interfaces na abstração do Vector Store são as seguintes.
Microsoft.Extensions.VectorData.IVectorStore
IVectorStore
contém operações que se estendem por 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, get e delete registros.
Por fim, a interface herda o 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 o uso IVectorizedSearch<TRecord>
por conta própria nos casos em que apenas a pesquisa é necessária e nenhum gerenciamento de registro ou coleção é necessário.
IVectorizableTextSearch<TRecord>
IVectorizableTextSearch<TRecord>
contém um método para fazer pesquisas vetoriais em que o banco de dados vetorial tem a capacidade de gerar incorporações automaticamente. Por exemplo, você pode chamar esse método com uma string 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, é implementado apenas por conectores selecionados.
A abstração do repositório de vetores
As principais interfaces na abstração do Vector Store são as seguintes.
com.microsoft.semantickernel.data.vectorstorage.VectorStore
VectorStore
contém operações que se estendem por 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<chave, 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, get e delete registros.
Por fim, a interface herda o fornecimento de recursos de VectorizedSearch<Record>
pesquisa vetorial.
com.microsoft.semantickernel.data.vectorsearch.VectorizedSearch<Registro>
VectorizedSearch<Record>
contém um método para fazer pesquisas vetoriais.
VectorStoreRecordCollection<Key, Record>
herda de VectorizedSearch<Record>
tornar possível o uso VectorizedSearch<Record>
por conta própria nos casos em que apenas a pesquisa é necessária e nenhum gerenciamento de registro ou coleção é necessário.
com.microsoft.semantickernel.data.vectorsearch.VectorizableTextSearch<Registro>
VectorizableTextSearch<Record>
contém um método para fazer pesquisas vetoriais em que o banco de dados vetorial tem a capacidade de gerar incorporações automaticamente. Por exemplo, você pode chamar esse método com uma string 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, é implementado apenas por conectores selecionados.
Introdução aos conectores do Vector Store
Importar os pacotes nuget necessários
Todas as interfaces de repositório de vetores e todas as classes relacionadas à abstração estão disponíveis no Microsoft.Extensions.VectorData.Abstractions
pacote nuget.
Cada implementação de repositório de vetores 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 Kernel Semântico, as abstrações do Microsoft.SemanticKernel.Abstractions
Vector Store foram removidas e estão disponíveis no novo pacote dedicado Microsoft.Extensions.VectorData.Abstractions
.
Observe que, a partir da versão 1.23.0, tem uma dependência do Microsoft.Extensions.VectorData.Abstractions
, portanto, Microsoft.SemanticKernel.Abstractions
não há necessidade de fazer referência a pacotes adicionais.
No entanto, as abstrações 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 em que qualquer um dos tipos de abstração do Vector Store é usado, por exemplo IVectorStore
, , IVectorStoreRecordCollection
, VectorStoreRecordDataAttribute
, VectorStoreRecordKeyProperty
, etc.
Essa alteração foi feita para oferecer suporte a provedores de repositório 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 de vetores.
Definir seu modelo de dados
Os conectores do Repositório de Vetores do Kernel Semântico usam uma abordagem de primeiro modelo 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; }
}
Dica
Para obter mais informações sobre como anotar seu modelo de dados, consulte definindo seu modelo de dados.
Dica
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 do VectorStore para o banco de dados de sua escolha e selecionar uma coleção de registros.
Neste exemplo, usaremos Qdrant. Portanto, você precisará importar o pacote nuget Qdrant.
dotnet add package Microsoft.SemanticKernel.Connectors.Qdrant --prerelease
Como os bancos de dados oferecem suporte a 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á ulong
, já que a HotelId
propriedade é a ulong
e Qdrant suporta apenas 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 oferecem suporte a 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á str
, já que a HotelId
propriedade é a str
e Qdrant suporta apenas 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 oferecem suporte a 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 propriedade é a String
e o hotelId
armazenamento JDBC suporta String
apenas 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()
);
}
}
Dica
Para obter mais informações sobre quais tipos de chave e campo cada conector do Repositório de Vetores dá suporte, 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();
Dica
Para obter mais informações sobre como gerar inserções, consulte geração de inserção.
Faça uma pesquisa vetorial
// 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());
Dica
Para obter mais informações sobre como gerar inserções, consulte geração de inserção.