RAG com controle de qualidade e os recursos mais recentes de pesquisa vetorial do AlloyDB.

1. Visão geral

Em diferentes setores, a pesquisa contextual é uma funcionalidade essencial que forma o centro dos aplicativos. A Geração Aumentada de Recuperação tem sido um fator-chave para essa evolução tecnológica crucial há algum tempo, com mecanismos de recuperação com tecnologia de IA generativa. Os modelos generativos, com janelas de contexto grandes e qualidade de saída impressionante, estão transformando a IA. A RAG oferece uma maneira sistemática de injetar contexto em aplicativos e agentes de IA, fundamentando-os em bancos de dados estruturados ou informações de várias mídias. Esses dados contextuais são essenciais para a clareza da verdade e a precisão da saída, mas quão precisos são esses resultados? Sua empresa depende principalmente da precisão dessas correspondências contextuais e da relevância? Então este projeto vai te agradar!

O segredo da pesquisa vetorial não é apenas criá-la, mas saber se as correspondências de vetores são realmente boas. Todos nós já estivemos lá, olhando para uma lista de resultados e nos perguntando: "Será que isso está funcionando?" Vamos analisar como avaliar a qualidade das correspondências de vetor. "O que mudou na RAG?", você pergunta. Tudo! Por anos, a geração aumentada de recuperação (RAG) parecia uma meta promissora, mas difícil de alcançar. Agora, finalmente, temos as ferramentas para criar aplicativos RAG com a performance e a confiabilidade necessárias para tarefas essenciais.

Agora já temos o entendimento básico de três coisas:

  1. O que a pesquisa contextual significa para seu agente e como fazer isso usando a Pesquisa Vetorial.
  2. Também abordamos a Pesquisa vetorial no escopo dos seus dados, ou seja, no seu banco de dados. Todos os bancos de dados do Google Cloud oferecem suporte a isso.
  3. Fomos além do resto do mundo ao explicar como alcançar um recurso de RAG de pesquisa vetorial leve com alto desempenho e qualidade com o recurso de pesquisa vetorial do AlloyDB, que usa o índice ScaNN.

Se você não fez esses experimentos básicos, intermediários e um pouco avançados de RAG, recomendamos que leia os três aqui, aqui e aqui na ordem indicada.

A Pesquisa de patentes ajuda o usuário a encontrar patentes relevantes para o texto de pesquisa. Já criamos uma versão dela no passado. Agora vamos criar o app com recursos novos e avançados de RAG que permitem uma pesquisa contextual controlada de qualidade para esse aplicativo. Vamos lá.

A imagem abaixo mostra o fluxo geral do que está acontecendo neste aplicativo.~ 1c871099f1fde825.png

Objetivo

Permitir que um usuário pesquise patentes com base em uma descrição textual com melhor desempenho e qualidade, além de avaliar a qualidade das correspondências geradas usando os recursos mais recentes do RAG do AlloyDB.

O que você vai criar

Como parte deste laboratório, você vai:

  1. Criar uma instância do AlloyDB e carregar o conjunto de dados público de patentes
  2. Criar índice de metadados e índice ScaNN
  3. Implementar a pesquisa vetorial avançada no AlloyDB usando o método de filtragem inline do ScaNN
  4. Implementar o recurso de avaliação de recordação
  5. Avaliar a resposta da consulta

Requisitos

  • Use um navegador, como o Chrome ou o Firefox.
  • Ter um projeto do Google Cloud com o faturamento ativado.

2. Antes de começar

Criar um projeto

  1. No console do Google Cloud, na página de seletor de projetos, selecione ou crie um projeto do Google Cloud.
  2. Verifique se o faturamento está ativado para seu projeto do Cloud. Saiba como verificar se o faturamento está ativado em um projeto .
  3. Você vai usar o Cloud Shell, um ambiente de linha de comando executado no Google Cloud. Clique em "Ativar o Cloud Shell" na parte de cima do console do Google Cloud.

Imagem do botão "Ativar o Cloud Shell"

  1. Depois de se conectar ao Cloud Shell, verifique se você já está autenticado e se o projeto está definido como seu ID usando o seguinte comando:
gcloud auth list
  1. Execute o comando a seguir no Cloud Shell para confirmar se o comando gcloud sabe sobre seu projeto.
gcloud config list project
  1. Se o projeto não estiver definido, use este comando:
gcloud config set project <YOUR_PROJECT_ID>
  1. Ative as APIs necessárias. Você pode usar um comando gcloud no terminal do Cloud Shell:
gcloud services enable alloydb.googleapis.com compute.googleapis.com cloudresourcemanager.googleapis.com servicenetworking.googleapis.com run.googleapis.com cloudbuild.googleapis.com cloudfunctions.googleapis.com aiplatform.googleapis.com

A alternativa ao comando gcloud é pelo console, pesquisando cada produto ou usando este link.

Consulte a documentação para ver o uso e os comandos gcloud.

3. Configuração do banco de dados

Neste laboratório, vamos usar o AlloyDB como o banco de dados dos dados de patente. Ele usa clusters para armazenar todos os recursos, como bancos de dados e registros. Cada cluster tem uma instância principal que fornece um ponto de acesso aos dados. As tabelas vão conter os dados reais.

Vamos criar um cluster, uma instância e uma tabela do AlloyDB em que o conjunto de dados de patentes será carregado.

Criar um cluster e uma instância

  1. Navegue pela página do AlloyDB no Console do Cloud. Uma maneira fácil de encontrar a maioria das páginas no console do Cloud é pesquisar usando a barra de pesquisa do console.
  2. Selecione CREATE CLUSTER nessa página:

f76ff480c8c889aa.png

  1. Uma tela como esta vai aparecer. Crie um cluster e uma instância com os seguintes valores. Confira se os valores correspondem ao clonar o código do aplicativo do repositório:
  • ID do cluster: "vector-cluster"
  • senha: "alloydb"
  • PostgreSQL 15 / a versão mais recente recomendada
  • Região: "us-central1"
  • Redes: "default"

538dba58908162fb.png

  1. Ao selecionar a rede padrão, uma tela como a mostrada abaixo será exibida.

Selecione CONFIGURAR CONEXÃO.

7939bbb6802a91bf.png

  1. Em seguida, selecione Usar um intervalo de IP alocado automaticamente e clique em "Continuar". Depois de analisar as informações, selecione "CRIAR CONEXÃO". 768ff5210e79676f.png
  2. Depois que a rede estiver configurada, você poderá continuar a criar o cluster. Clique em CRIAR CLUSTER para concluir a configuração do cluster, conforme mostrado abaixo:

e06623e55195e16e.png

Altere o ID da instância (que pode ser encontrado no momento da configuração do cluster / instância) para

vector-instance. Se não for possível fazer isso, lembre-se de usar o ID da instância em todas as próximas referências.

A criação do cluster leva cerca de 10 minutos. Depois que a criação for concluída, uma tela vai mostrar uma visão geral do cluster que você acabou de criar.

4. Ingestão de dados

Agora é hora de adicionar uma tabela com os dados da loja. Acesse o AlloyDB, selecione o cluster principal e o AlloyDB Studio:

847e35f1bf8a8bd8.png

Talvez seja necessário aguardar a conclusão da criação da instância. Depois disso, faça login no AlloyDB usando as credenciais que você criou ao criar o cluster. Use os seguintes dados para autenticação no PostgreSQL:

  • Nome de usuário : "postgres"
  • Banco de dados : "postgres"
  • Senha : "alloydb"

Depois que você fizer a autenticação no AlloyDB Studio, os comandos SQL serão inseridos no editor. É possível adicionar várias janelas do Editor usando o sinal de adição à direita da última janela.

91a86d9469d499c4.png

Você vai inserir comandos do AlloyDB nas janelas do editor usando as opções Executar, Formatar e Limpar conforme necessário.

Ativar extensões

Para criar este app, vamos usar as extensões pgvector e google_ml_integration. A extensão pgvector permite armazenar e pesquisar embeddings de vetor. A extensão google_ml_integration fornece funções que você usa para acessar os endpoints de previsão da Vertex AI e receber previsões no SQL. Ative essas extensões executando os seguintes DDLs:

CREATE EXTENSION IF NOT EXISTS google_ml_integration CASCADE;
CREATE EXTENSION IF NOT EXISTS vector;

Se você quiser verificar as extensões que foram ativadas no seu banco de dados, execute este comando SQL:

select extname, extversion from pg_extension;

Criar uma tabela

É possível criar uma tabela usando a instrução DDL abaixo no AlloyDB Studio:

CREATE TABLE patents_data ( id VARCHAR(25), type VARCHAR(25), number VARCHAR(20), country VARCHAR(2), date VARCHAR(20), abstract VARCHAR(300000), title VARCHAR(100000), kind VARCHAR(5), num_claims BIGINT, filename VARCHAR(100), withdrawn BIGINT, abstract_embeddings vector(768)) ;

A coluna abstract_embeddings permite o armazenamento dos valores do vetor do texto.

Conceder permissão

Execute a declaração abaixo para conceder execução na função "embedding":

GRANT EXECUTE ON FUNCTION embedding TO postgres;

Conceder o papel de usuário da Vertex AI à conta de serviço do AlloyDB

No console do IAM do Google Cloud, conceda à conta de serviço do AlloyDB (que tem este formato: service-<<PROJECT_NUMBER>>@gcp-sa-alloydb.iam.gserviceaccount.com) acesso à função "Usuário do Vertex AI". PROJECT_NUMBER terá o número do seu projeto.

Como alternativa, execute o comando abaixo no terminal do Cloud Shell:

PROJECT_ID=$(gcloud config get-value project)


gcloud projects add-iam-policy-binding $PROJECT_ID \
  --member="serviceAccount:service-$(gcloud projects describe $PROJECT_ID --format="value(projectNumber)")@gcp-sa-alloydb.iam.gserviceaccount.com" \
--role="roles/aiplatform.user"

Carregar dados de patentes no banco de dados

Os conjuntos de dados públicos das patentes do Google no BigQuery serão usados como nosso conjunto de dados. Vamos usar o AlloyDB Studio para executar nossas consultas. Os dados são fornecidos neste arquivo insert_scripts.sql e serão executados para carregar os dados da patente.

  1. No console do Google Cloud, abra a página AlloyDB.
  2. Selecione o cluster recém-criado e clique na instância.
  3. No menu de navegação do AlloyDB, clique em AlloyDB Studio. Faça login com suas credenciais.
  4. Abra uma nova guia clicando no ícone Nova guia à direita.
  5. Copie a instrução de consulta insert do script insert_scripts.sql mencionado acima para o editor. Você pode copiar de 10 a 50 instruções de inserção para uma demonstração rápida desse caso de uso.
  6. Clique em Executar. Os resultados da consulta aparecem na tabela Resultados.

Observação:o script de inserção tem muitos dados. Isso acontece porque incluímos incorporações nos scripts de inserção. Clique em "Ver registros brutos" caso tenha problemas para carregar o arquivo no GitHub. Isso é feito para evitar que você tenha problemas (nas próximas etapas) ao gerar mais de algumas incorporações (por exemplo, 20 a 25 no máximo) caso esteja usando uma conta de faturamento de crédito de teste para o Google Cloud.

5. Criar embeddings para dados de patentes

Primeiro, vamos testar a função de incorporação executando o seguinte exemplo de consulta:

SELECT embedding('text-embedding-005', 'AlloyDB is a managed, cloud-hosted SQL database service.');

Isso deve retornar o vetor de embeddings, que se parece com uma matriz de números flutuantes, para o texto de exemplo na consulta. Fica assim:

25a1d7ef0e49e91e.png

Atualizar o campo de vetor abstract_embeddings

Execute a DML abaixo para atualizar os resumos de patentes na tabela com as embeddings correspondentes somente se você não inseriu os dados de abstract_embeddings como parte do script de inserção:

UPDATE patents_data set abstract_embeddings = embedding( 'text-embedding-005', abstract);

Você pode ter problemas ao gerar mais de algumas incorporações (por exemplo, 20 a 25 no máximo) se estiver usando uma conta de faturamento de crédito de teste para o Google Cloud. Por isso, já incluí as incorporações nos scripts de inserção. Você vai ter isso na tabela carregada se tiver concluído a etapa "carregar dados de patentes no banco de dados".

6. Realizar RAG avançado com os novos recursos do AlloyDB

Agora que a tabela, os dados e as embeddings estão prontos, vamos realizar a pesquisa de vetor em tempo real para o texto de pesquisa do usuário. Para testar isso, execute a consulta abaixo:

SELECT id || ' - ' || title as title FROM patents_data ORDER BY abstract_embeddings <=> embedding('text-embedding-005', 'Sentiment Analysis')::vector LIMIT 10;

Nesta consulta,

  1. O texto pesquisado pelo usuário é "Análise de sentimento".
  2. Estamos convertendo o texto em embeddings no método embedding() usando o modelo: text-embedding-005.
  3. "<=>" representa o uso do método de distância de SIMILARIDADE COSINE.
  4. Estamos convertendo o resultado do método de embedding em um tipo de vetor para que ele seja compatível com os vetores armazenados no banco de dados.
  5. LIMIT 10 representa que estamos selecionando as 10 correspondências mais próximas do texto de pesquisa.

O AlloyDB leva a RAG de pesquisa vetorial a outro patamar:

Há um bom número de coisas introduzidas. Duas delas são:

  1. Filtragem inline
  2. Avaliador de recall

Filtragem inline

Anteriormente, como desenvolvedor, você precisava realizar a consulta de pesquisa de vetor e lidar com a filtragem e a recuperação. O otimizador de consulta do AlloyDB faz escolhas sobre como executar uma consulta com filtros. A filtragem inline é uma nova técnica de otimização de consulta que permite que o otimizador de consulta do AlloyDB avalie as condições de filtragem de metadados e a pesquisa de vetores ao mesmo tempo, aproveitando os índices de vetores e os índices nas colunas de metadados. Isso aumentou a performance de recuperação, permitindo que os desenvolvedores aproveitassem o que o AlloyDB tem a oferecer.

A filtragem inline é a melhor opção para casos com seletividade média. À medida que o AlloyDB pesquisa no índice vetorial, ele só calcula distâncias para vetores que correspondem às condições de filtragem de metadados (seus filtros funcionais em uma consulta geralmente são processados na cláusula WHERE). Isso melhora muito a performance dessas consultas, complementando as vantagens do filtro pós-filtro ou pré-filtro.

  1. Instalar ou atualizar a extensão pgvector
CREATE EXTENSION IF NOT EXISTS vector WITH VERSION '0.8.0.google-3';

Se a extensão pgvector já estiver instalada, atualize-a para a versão 0.8.0.google-3 ou mais recente para ter os recursos do avaliador de recuperação.

ALTER EXTENSION vector UPDATE TO '0.8.0.google-3';

Esta etapa só precisa ser executada se a extensão de vetor for <0.8.0.google-3>.

Observação importante:se a contagem de linhas for inferior a 100, não será necessário criar o índice ScaNN, já que ele não se aplica a menos linhas. Nesse caso, pule as etapas a seguir.

  1. Para criar índices ScaNN, instale a extensão alloydb_scann.
CREATE EXTENSION IF NOT EXISTS alloydb_scann;
  1. Primeiro, execute a consulta de pesquisa vetorial sem o índice e sem o filtro inline ativado:
SELECT id || ' - ' || title as title FROM patents_data 
WHERE num_claims >= 15 
ORDER BY abstract_embeddings <=> embedding('text-embedding-005', 'Sentiment Analysis')::vector LIMIT 10;

O resultado será semelhante a este:

6989de0fc3f0f753.png

  1. Execute a análise detalhada: (sem índice nem filtragem inline)

908dcf87c7f00ed4.png

O tempo de execução é de 2,4 ms

  1. Vamos criar um índice regular no campo num_claims para podermos filtrar por ele:
CREATE INDEX idx_patents_data_num_claims ON patents_data (num_claims);
  1. Vamos criar o índice ScaNN para nosso aplicativo de pesquisa de patentes. Execute o seguinte no AlloyDB Studio:
CREATE INDEX patent_index ON patents_data 
USING scann (abstract_embeddings cosine)
WITH (num_leaves=32);

Observação importante : (num_leaves=32) se aplica ao conjunto de dados total com mais de 1.000 linhas. Se a contagem de linhas for menor que 100, não será necessário criar um índice, já que ele não se aplica a menos linhas.

  1. Ative a filtragem inline no índice ScaNN:
SET scann.enable_inline_filtering = on
  1. Agora, vamos executar a mesma consulta com filtro e pesquisa vetorial:
SELECT id || ' - ' || title as title FROM patents_data 
WHERE num_claims >= 15 
ORDER BY abstract_embeddings <=> embedding('text-embedding-005', 'Sentiment Analysis')::vector LIMIT 10;

aa54cba2b2ada2cb.png

Como você pode ver, o tempo de execução é reduzido significativamente para a mesma pesquisa de vetor. A filtragem inline infundida no índice ScaNN na pesquisa vetorial tornou isso possível!!!

Em seguida, vamos avaliar o recall dessa pesquisa vetorial ativada pelo ScaNN.

Avaliador de recall

A recuperação na pesquisa de similaridade é a porcentagem de instâncias relevantes que foram recuperadas de uma pesquisa, ou seja, o número de verdadeiros positivos. Essa é a métrica mais comum usada para medir a qualidade da pesquisa. Uma fonte de perda de recall vem da diferença entre a pesquisa de vizinho mais próximo aproximado, ou aNN, e a pesquisa de vizinho mais próximo exato, ou kNN. Índices vetoriais, como o ScaNN do AlloyDB, implementam algoritmos de ANN, permitindo acelerar a pesquisa vetorial em grandes conjuntos de dados em troca de uma pequena compensação na recuperação. Agora, o AlloyDB permite medir essa troca diretamente no banco de dados para consultas individuais e garantir que ela seja estável ao longo do tempo. Você pode atualizar os parâmetros de consulta e índice em resposta a essas informações para conseguir resultados e desempenho melhores.

Qual é a lógica por trás da recuperação de resultados de pesquisa?

No contexto da pesquisa vetorial, o recall se refere à porcentagem de vetores que o índice retorna e que são vizinhos mais próximos reais. Por exemplo, se uma consulta de vizinho mais próximo de 20 vizinhos mais próximos retornar 19 dos vizinhos mais próximos, o recall será de 19/20x100 = 95%. O recall é a métrica usada para a qualidade da pesquisa e é definido como a porcentagem dos resultados retornados que são objetivamente mais próximos dos vetores de consulta.

É possível encontrar o recall de uma consulta de vetor em um índice de vetor para uma determinada configuração usando a função evaluate_query_recall. Essa função permite ajustar os parâmetros para conseguir os resultados de recuperação de consulta de vetor que você quer.

Observação importante:

Se você encontrar um erro de permissão negada no índice HNSW nas etapas a seguir, pule esta seção de avaliação de recuperação por enquanto. Talvez isso tenha a ver com restrições de acesso, já que o codelab foi documentado recentemente.

  1. Defina a flag "Enable Index Scan" no índice ScaNN e HNSW:
SET scann.enable_indexscan = on
SET hnsw.enable_index_scan = on
  1. Execute a seguinte consulta no AlloyDB Studio:
SELECT
  *
FROM
  evaluate_query_recall($$
  SELECT
    id || ' - ' || title AS title,
    abstract
  FROM
    patents_data
    where num_claims >= 15
  ORDER BY
    abstract_embeddings <=> embedding('text-embedding-005',
      'sentiment analysis')::vector
  LIMIT 25 $$,
    '{"scann.num_leaves_to_search":1, "scann.pre_reordering_num_neighbors":10}',
    ARRAY['scann']);

A função evaluate_query_recall recebe a consulta como parâmetro e retorna a recuperação. Estou usando a mesma consulta que usei para verificar a performance como a consulta de entrada da função. Adicionei o SCaNN como o método de índice. Para mais opções de parâmetro, consulte a documentação.

O recall para esta consulta de pesquisa vetorial que usamos:

c98f38fbe6a0b6c5.png

Vejo que a RECALL é de 70%. Agora posso usar essas informações para mudar os parâmetros de índice, métodos e consultas e melhorar minha recuperação para essa pesquisa vetorial.

7. Testar com parâmetros de consulta e índice modificados

Agora vamos testar a consulta modificando os parâmetros com base na recuperação recebida.

  1. Mudei o número de linhas no conjunto de resultados para 7 (antes eram 25) e notei uma melhora na RECALL, ou seja, 86%.

c12f7b92b8481ceb.png

Isso significa que, em tempo real, posso variar o número de correspondências que meus usuários veem para melhorar a relevância delas de acordo com o contexto de pesquisa dos usuários.

  1. Vamos tentar de novo modificando os parâmetros de índice:

Para este teste, vou usar a "Distância L2" em vez da função de distância de similaridade "Cosseno". Também vou mudar o limite da consulta para 10 para mostrar se há melhoria na qualidade dos resultados da pesquisa, mesmo com um aumento na contagem de conjuntos de resultados da pesquisa.

[ANTES] Consulta que usa a função de distância de similaridade de cosseno:

SELECT
  *
FROM
  evaluate_query_recall($$
  SELECT
    id || ' - ' || title AS title,
    abstract
  FROM
    patents_data
    where num_claims >= 15
  ORDER BY
    abstract_embeddings <=> embedding('text-embedding-005',
      'sentiment analysis')::vector
  LIMIT 10 $$,
    '{"scann.num_leaves_to_search":1, "scann.pre_reordering_num_neighbors":10}',
    ARRAY['scann']);

Observação muito importante: "Como sabemos que essa consulta usa a similaridade COSINE?", você pergunta. É possível identificar a função de distância usando "<=>" para representar a distância do cosseno.

Link para a documentação sobre as funções de distância da Pesquisa de vetores.

O resultado da consulta acima é:

c62ef8922d6bf0b2.png

Como você pode ver, a RECALL é de 70% sem nenhuma mudança na lógica do índice. Lembra do índice ScaNN que criamos na etapa 6 da seção "Filtragem inline", "patent_index"? O mesmo índice ainda é eficaz enquanto executamos a consulta acima.

Agora vamos criar um índice com uma consulta de função de distância diferente: Distância L2: <->

drop index patent_index;

CREATE INDEX patent_index_L2 ON patents_data 
USING scann (abstract_embeddings L2)
WITH (num_leaves=32);

A instrução de exclusão de índice serve apenas para garantir que não haja índices desnecessários na tabela.

Agora, posso executar a consulta a seguir para avaliar a RECALL depois de mudar a função de distância da minha funcionalidade de pesquisa de vetor.

[DEPOIS] Consulta que usa a função de distância de similaridade de cosseno:

SELECT
  *
FROM
  evaluate_query_recall($$
  SELECT
    id || ' - ' || title AS title,
    abstract
  FROM
    patents_data
    where num_claims >= 15
  ORDER BY
    abstract_embeddings <-> embedding('text-embedding-005',
      'sentiment analysis')::vector
  LIMIT 10 $$,
    '{"scann.num_leaves_to_search":1, "scann.pre_reordering_num_neighbors":10}',
    ARRAY['scann']);

O resultado da consulta acima é:

6c163dd08cf4d693.png

Que transformação no valor de recordação, 90%!!!

Há outros parâmetros que podem ser alterados no índice, como num_leaves etc. com base no valor de recuperação desejado e no conjunto de dados usado pelo aplicativo.

8. Limpar

Para evitar cobranças na sua conta do Google Cloud pelos recursos usados nesta postagem, siga estas etapas:

  1. No console do Google Cloud, acesse a página Resource Manager.
  2. Na lista de projetos, selecione o projeto que você quer excluir e clique em Excluir.
  3. Na caixa de diálogo, digite o ID do projeto e clique em Encerrar para excluí-lo.
  4. Como alternativa, você pode excluir o cluster do AlloyDB (mude o local neste hiperlink se você não tiver escolhido us-central1 para o cluster no momento da configuração) que acabamos de criar para este projeto clicando no botão EXCLUIR CLUSTER.

9. Parabéns

Parabéns! Você criou sua consulta de pesquisa de patentes contextual com a pesquisa vetorial avançada do AlloyDB para alto desempenho e para que ela seja realmente orientada pelo significado. Eu montei um aplicativo de agente multiferramenta com controle de qualidade que usa o ADK e todas as coisas do AlloyDB que discutimos aqui para criar um agente de pesquisa e análise vetorial de patentes de alto desempenho e qualidade que você pode conferir aqui: https://youtu.be/Y9fvVY0yZTY

Se você quiser aprender a criar esse agente, consulte este codelab.

Comece hoje mesmo.