Partilhar via


Serialização do modelo de dados de e para diferentes armazenamentos (Visualização)

Para que seu modelo de dados seja armazenado em um banco de dados, ele precisa ser convertido em um formato que o banco de dados possa entender. Bancos de dados diferentes exigem esquemas e formatos de armazenamento diferentes. Alguns têm um esquema rigoroso que precisa ser respeitado, enquanto outros permitem que o esquema seja definido pelo usuário.

Opções de mapeamento

Os conectores de armazenamento vetorial fornecidos pelo Semantic Kernel fornecem várias maneiras de alcançar esse mapeamento.

Mapeadores integrados

Os conectores de armazenamento vetorial fornecidos pelo Semantic Kernel têm mapeadores internos que mapearão seu modelo de dados de e para os esquemas de banco de dados. Consulte a página para cada conector para obter mais informações sobre como os mapeadores internos mapeiam dados para cada banco de dados.

Mapeadores personalizados

Os conectores de armazenamento vetorial fornecidos pelo Semantic Kernel permitem fornecer mapeadores personalizados em combinação com um VectorStoreRecordDefinition. Nesse caso, o VectorStoreRecordDefinition pode diferir do modelo de dados fornecido. O VectorStoreRecordDefinition é usado para definir o esquema de banco de dados, enquanto o modelo de dados é usado pelo desenvolvedor para interagir com o repositório vetorial. Neste caso, é necessário um mapeador personalizado para mapear do modelo de dados para o esquema de banco de dados personalizado definido pelo VectorStoreRecordDefinition.

Dica

Consulte Como criar um mapeador personalizado para um conector do Vetor Store para obter um exemplo sobre como criar seu próprio mapeador personalizado.

Para que seu modelo de dados definido como uma classe ou uma definição seja armazenado em um banco de dados, ele precisa ser serializado para um formato que o banco de dados possa entender.

Há duas maneiras que podem ser feitas, usando a serialização interna fornecida pelo Kernel Semântico ou fornecendo sua própria lógica de serialização.

Os dois diagramas a seguir mostram que os fluxos são mostrados para serialização e desserialização de modelos de dados de e para um modelo de armazenamento.

Fluxo de serialização (usado no Upsert)

Fluxo de Serialização

Fluxo de desserialização

As etapas marcadas com * (em ambos os diagramas) são implementadas pelo desenvolvedor de um conector específico e são diferentes para cada loja. As etapas marcadas com ** (em ambos os diagramas) são fornecidas como um método em um registro ou como parte da definição de registro, isso é sempre fornecido pelo usuário, consulte de serialização direta para obter mais informações.

(De)Serialização: Abordagens

Serialização direta (Modelo de Dados para Modelo de Armazenamento)

A serialização direta é a melhor maneira de garantir o controle total sobre como seus modelos são serializados e otimizar o desempenho. A desvantagem é que ele é específico para um armazenamento de dados e, portanto, ao usá-lo, não é tão fácil alternar entre diferentes armazenamentos com o mesmo modelo de dados.

Você pode usar isso implementando um método que segue o protocolo SerializeMethodProtocol em seu modelo de dados ou adicionando funções que seguem o SerializeFunctionProtocol à sua definição de registro, ambas podem ser encontradas em semantic_kernel/data/vector_store_model_protocols.py.

Quando uma dessas funções estiver presente, ela será usada para serializar diretamente o modelo de dados para o modelo de armazenamento.

Você pode até implementar apenas uma das duas e usar a (des)serialização interna para a outra direção; tal abordagem pode ser útil, por exemplo, quando está a lidar com uma coleção criada fora do seu domínio e precisa personalizar a forma como é desserializada (e não é possível fazer um "upsert" de qualquer maneira).

(des)serialização integrada (Data Model to Dict e Dict to Store Model e vice-versa)

A serialização interna é feita primeiro convertendo o modelo de dados em um dicionário e, em seguida, serializando-o para o modelo que o repositório entende, para cada armazenamento que é diferente e definido como parte do conector interno. A desserialização é feita na ordem inversa.

Etapa de serialização 1: Modelo de dados a ser ditado

Dependendo do tipo de modelo de dados que você tem, as etapas são feitas de maneiras diferentes. Há quatro maneiras de serializar o modelo de dados para um dicionário:

  1. to_dict método na definição (alinha-se com o atributo to_dict do modelo de dados, seguindo o ToDictFunctionProtocol)
  2. Verifique se o registro é um ToDictMethodProtocol e use o método to_dict
  3. verifique se o registro é um modelo Pydantic e use o model_dump do modelo, veja a nota abaixo para mais informações.
  4. percorrer os campos na definição e criar o dicionário

Etapa de Serialização 2: Dic para Guardar o Modelo

Um método deve ser fornecido pelo conector para converter o dicionário no modelo de armazenamento. Isto é realizado pelo desenvolvedor do conector e é diferente para cada loja.

Desserialização Etapa 1: Armazenar modelo para ditar

Um método deve ser fornecido pelo conector para converter o modelo de armazenamento em um dicionário. Isso é feito pelo desenvolvedor do conector e é diferente para cada loja.

Desserialização Etapa 2: Ditar para o modelo de dados

A desserialização é feita na ordem inversa, ele tenta estas opções:

  1. from_dict método na definição (alinha-se ao atributo from_dict do modelo de dados, seguindo o FromDictFunctionProtocol)
  2. Verifique se o registro é um FromDictMethodProtocol e use o método from_dict
  3. verifique se o registro é um modelo Pydantic e use o model_validate do modelo, veja a nota abaixo para mais informações.
  4. faça um loop pelos campos na definição e defina os valores, então esse ditado é passado para o construtor do modelo de dados como argumentos nomeados (a menos que o modelo de dados seja um ditado em si, nesse caso ele é retornado como está)

Observação

Usando o Pydantic com serialização integrada

Quando você define seu modelo usando um Pydantic BaseModel, ele usará os model_dump métodos e model_validate para serializar e desserializar o modelo de dados de e para um dict. Isso é feito usando o método model_dump sem parâmetros, se você quiser controlar isso, considere implementar o ToDictMethodProtocol em seu modelo de dados, pois isso é tentado primeiro.

Serialização de vetores

Quando você tem um vetor em seu modelo de dados, ele precisa ser uma lista de floats ou uma lista de ints, já que é isso que a maioria das lojas precisa, se você quiser que sua classe armazene o vetor em um formato diferente, você pode usar o serialize_function e deserialize_function definido na VectorStoreRecordVectorField anotação. Por exemplo, para uma matriz numpy, você pode usar a seguinte anotação:

import numpy as np

vector: Annotated[
    np.ndarray | None,
    VectorStoreRecordVectorField(
        dimensions=1536,
        serialize_function=np.ndarray.tolist,
        deserialize_function=np.array,
    ),
] = None

Se você usar um repositório de vetores que possa lidar com matrizes numpy nativas e não quiser convertê-las de um lado para o outro, deverá configurar os métodos de serialização e desserialização diretas para o modelo e esse armazenamento.

Observação

Isso só é usado ao usar a serialização interna, ao usar a serialização direta, você pode manipular o vetor da maneira que desejar.

Brevemente

Mais informações em breve.