PRODPlataforma BaaS europeia soberanaAbra o painel →

IA nativa · 10 minutos de leitura

Tutorial: pipeline RAG com Postgres e pgvector

Affane Daylami · Fondateur · 13 de abril de 2026

Voltar ao blog

Construir um pipeline RAG no Postgres geralmente requer a montagem de várias peças: um fatiador de texto, uma chamada de incorporação, uma tabela pgvector, uma consulta de similaridade. Este é o clássico LangChain + PGVectorchain. No Aurabase, esse pipeline já existe no lado do servidor: duas chamadas, ragIngest() e rag(), o substituem, enquanto conta com PostgreSQL e pgvector padrão, sem uma base de vetor proprietária para adicionar.

Este texto em inglês foi gerado automaticamente a partir do original em francês e ainda não foi revisado.
Esta página foi traduzida automaticamente. A versão em inglês é oficial.

O RAG nativo faz parte da IA nativaintegrada ao backend Aurabase, junto com NL2SQL: não é um serviço de terceiros a ser montado em cima de uma base geral. Pré-requisitos para seguir este tutorial: um projeto Aurabase existente, um provedor LLM configurado (OpenAI ou Google Gemini para embeddings, um dos três provedores nativos para geração) e uma chave de API do projeto.

O essencial
  • Um pipeline Aurabase RAG consiste em duas chamadas: ragIngest() para indexar um documento, rag() para consultar e gerar uma resposta. Chunking, embeddings e pesquisa vetorial são gerenciados no lado do servidor.
  • Nos bastidores, está o PostgreSQL e o pgvector padrão: uma tabela embeddings com uma coluna de vetor por classe de dimensão (768, 1536, 3072) e um índice HNSW parcial por classe.
  • Chunking usa um tokenizer real (tiktoken o200k), com sobreposição configurável e proteção anti-explosão em documentos grandes.
  • O conteúdo recuperado é neutralizado antes de ser injetado no prompt: um documento que tenta escapar de sua tag para falsificar instruções do sistema é explicitamente desativado.
  • Apenas OpenAI e Gemini geram embeddings no lado Aurabase. Anthropic/Claude não possui API de embeddings públicos, ela permanece reservada para gerar a resposta final.
#
Conceito

Como funciona esse pipeline RAG

O pipeline ocorre em cinco etapas. Após a ingestão, o texto é cortado, cada pedaço é vetorizado em lote e depois armazenado. Na consulta, a questão é vetorizada por sua vez, comparada aos pedaços armazenados por similaridade de cosseno, e os trechos mais próximos são injetados no prompt enviado ao modelo de geração.

Chunking (tiktoken)→Embeddings (lote)→armazenamento pgvector (HNSW)→Pesquisa de similaridade→Geração aumentada

Um detalhe arquitetônico que importa na produção: nenhuma conexão Postgres é mantida durante chamadas de rede para o provedor de incorporação ou geração. A transação do banco de dados fecha antes da chamada externa e reabre depois, para nunca bloquear um backend PgBouncer compartilhado para latência de rede de terceiros.

#
Passo 1

Crie o projeto

Ao contrário de um pgvector auto-hospedado típico, você não precisa executar CREATE EXTENSION vector ou criar uma tabela para esse pipeline. O esquema embeddings do projeto, com suas colunas vetoriais e índices HNSW, é provisionado automaticamente quando o projeto é criado.

terminalbash
# Conta Aurabase + CLI
npm i -g @aurabase/cli
aura login

# Crie o projeto e vincule-o a esta pasta
aura projects create mon-assistant --engine postgres
aura link --project-id <uuid-du-projet>

# Recuperar as chaves de API do projeto vinculado
aura projects api-keys

O provedor de incorporação é configurado uma vez, no lado do projeto (Studio → IA → Fornecedores). É este provedor que determina a dimensão efetiva de seus vetores, portanto a coluna utilizada na tabela embeddings.

#
Etapa 2

Indexe seus documentos com ragIngest()

Uma chamada é suficiente para indexar um documento: o texto é dividido em pedaços, cada pedaço é vetorizado e depois armazenado no namespace solicitado. A divisão usa um tokenizer real (tiktoken, codificação o200k_base), não uma simples divisão por espaços, que permanece correta em texto sem espaços como alguns idiomas asiáticos.

app/api/ingest/route.tstypescript
import { aura } from '@/lib/aurabase'

export async function POST(req: Request) {
  const { content, metadata } = await req.json()

  const { data, error } = await aura.ai.ragIngest({
    namespace: 'docs-produit',
    content,
    metadata,
  })

  if (error) return Response.json({ error }, { status: 400 })
  return Response.json(data) // {id, pedaços}
}

No HTTP bruto, a rota equivalente é POST /v1/ai/{project_id}/rag/ingest, autenticada pela chave API do projeto.

terminalbash
curl -X POST https://<votre-gateway>/v1/ai/<project_id>/rag/ingest \
  -H "apikey: <votre-cle-api>" \
  -H "Content-Type: application/json" \
  -d '{
    "namespace": "docs-produit",
    "content": "Le texte complet de votre document ici...",
    "metadata": { "source": "guide-utilisateur.pdf" }
  }'

A ingestão é idempotente por padrão: um identificador de documento é derivado automaticamente (hash SHA-256 do conteúdo ou metadata.document_id se você o fornecer). A reingestão do mesmo conteúdo substitui seus blocos existentes em vez de duplicá-los, tornando seguro a reprodução de um trabalho de sincronização periódico.

#
Etapa 3

O que realmente chega ao Postgres

Nenhuma mágica proprietária aqui: a tabela que recebe seus vetores é uma tabela Postgres comum, com uma coluna vector por classe de dimensão e um índice HNSW parcial por coluna (ativo apenas nas linhas que a preenchem). Aqui está sua definição real, simplificada:

diagrama da plataforma do projeto (simplificado)sql
create table embeddings (
  id               uuid primary key default gen_random_uuid(),
  project_id       text not null,
  namespace        text not null,
  content          text not null,
  embedding_768    vector(768),
  embedding_1536   vector(1536),
  embedding_3072   vector(3072),
  embedding_model  text,
  dims             int,
  metadata         jsonb default '{}'::jsonb,
  created_at       timestamptz not null default now()
);

-- Um índice HNSW parcial por classe de dimensão
create index idx_embeddings_vec_1536 on embeddings
  using hnsw (embedding_1536 vector_cosine_ops)
  where embedding_1536 is not null;

-- Além de 2.000 dimensões, o HNSW não oferece suporte ao tipo de vetor:
-- lançado em halfvec para a classe 3072
create index idx_embeddings_vec_3072 on embeddings
  using hnsw ((embedding_3072::halfvec(3072)) halfvec_cosine_ops)
  where embedding_3072 is not null;

Cada pesquisa compara os vetores com o operador de distância cosseno (<=>), aquele alvo das classes de operadores vector_cosine_ops e halfvec_cosine_ops do índice. Para obter detalhes sobre as compensações de recall/latência de HNSW versus IVFFlat, consulte o artigo dedicado à indexação de HNSW. Para a escolha da dimensão de incorporação em si, consulte a comparação 768 vs 1536 vs 3072.

#
Etapa 4

Consultar e gerar resposta com rag()

Do lado da consulta, rag() encadeia a vetorização da questão, a busca por similaridade no namespace, a construção do prompt aumentado e a chamada ao modelo de geração, em uma única rede de ida e volta no lado do cliente.

app/api/ask/route.tstypescript
import { aura } from '@/lib/aurabase'

export async function POST(req: Request) {
  const { question } = await req.json()

  const { data, error } = await aura.ai.rag({
    question,
    namespace: 'docs-produit',
  })

  if (error) return Response.json({ error }, { status: 400 })
  return Response.json(data)
}

A resposta carrega a resposta gerada e suas fontes, com o provedor realmente utilizado:

resposta (trecho)json
{
  "data": {
    "answer": "D'après la documentation, ...",
    "sources": [
      { "id": "...", "content": "...", "similarity": 0.87 }
    ],
    "model": "claude-3-5-sonnet",
    "tokens": 412,
    "provider": "anthropic",
    "fallback_used": false
  }
}

O conteúdo recuperado nunca é injetado bruto no prompt do sistema. Estes são dados não confiáveis ​​(upload do usuário, página indexada): um documento que contém, por exemplo, uma tag de seção de fechamento seguida de instruções falsas é neutralizado antes da montagem, seus colchetes angulares são substituídos por colchetes, o texto é preservado, mas a estrutura é desativada.

Corpus indexado sob outro modelo

Se rag() não encontrar nada, mesmo que seu namespace não esteja vazio, a resposta carrega um aviso explícito em vez de um silêncio enganoso: seu corpus provavelmente está indexado em outro modelo ou outra dimensão de incorporação. Reindexe-o via POST /v1/ai/{project_id}/rag/{namespace}/reindex.

#
Comparação

Do LangChain e um pgvector feito à mão: o que muda

Se você já construiu um chatbot RAG no PostgreSQL com LangChain, cada bloco manual tem um equivalente gerenciado no lado do servidor aqui, sem alterar o banco de dados subjacente.

Separando o textoRecursiveCharacterTextSplitter para definir você mesmoragIngest(): chunking tiktoken integrado, 512 tokens/64 sobreposição por padrão
IncorporaçõesChamada manual para OpenAIEmbeddings, gerenciamento de limites de loteNova tentativa transitória integrada e em lote automático
Armazenamento de vetorestabela pgvector + índice HNSW para criar e migrar você mesmoEsquema e índices provisionados por projeto
Pesquisa + promptPGVector.similarity_search() e então montando manualmente o promptrag(): pesquisa e geração aumentada em uma chamada
Conteúdo recuperadoInjetado como está no promptNeutralização automática de tags de estrutura antes da montagem

Você está migrando um projeto existente construído em Supabase com este tipo de montagem manual? A lógica de migração para o restante do back-end (esquema, políticas RLS, SDK) é abordada em nosso Guia de migração de Supabase para Aurabase.

#
Produção

Configurações e limites que você deve conhecer antes de entrar em produção

Três configurações afetam diretamente o custo e a latência, todas verificadas no código de serviço aura-ai. O número de tentativas em uma chamada de incorporação transitória (falha de rede, erro de provedor 429) é 3 por padrão, com uma espera básica de 100 ms. Documentos grandes são incorporados em sublotes limitados a 2.048 blocos por padrão, para respeitar os limites da API dos fornecedores sem falhar em um único documento enorme. Um guardrail (10.000 pedaços por padrão, configurável) rejeita explicitamente a ingestão de um documento que produziria um número aberrante de pedaços.

No lado da pesquisa, o tamanho da lista de candidatos HNSW se ajusta automaticamente para max(64, top_k × 4): quanto mais resultados você solicitar, mais candidatos o índice explorará para preservar a recuperação. Um valor fixo permanece possível através de uma variável de ambiente se o seu corpus tiver um perfil específico.

Os espaços vetoriais de diferentes modelos nunca são comparados entre si: cada pesquisa permanece limitada ao modelo de incorporação atual, e a mudança de modelos requer uma reindexação explícita em vez de uma mudança silenciosa que quebraria a consistência dos resultados.

#
Honestidade

Limites atuais a serem observados

A dimensão de incorporação deve estar em uma das três classes suportadas: 768, 1536 ou 3072. Um provedor que retorna outra dimensão é rejeitado com um erro explícito, nunca truncado ou convertido silenciosamente.

A geração de incorporação só está disponível via OpenAI ou Google Gemini entre os três provedores nativos: Anthropic/Claude não expõe uma API de incorporação pública, portanto é usada apenas para gerar a resposta final neste pipeline, nunca para vetorização.

O JavaScript SDK ainda não expõe as substituições top_k e threshold na chamada rag(): elas permanecem acessíveis em HTTP direto, limitadas respectivamente a [1, 50] e [0, 1], mas não a partir de aura.ai.rag() como é hoje. O limite de similaridade padrão (0,3) é deliberadamente permissivo; reduza-o a um corpus denso para evitar fontes irrelevantes no prompt.

#
Vá mais longe

Para ir mais longe

O RAG abrange questões sobre conteúdos não estruturados (documentos, notas, tickets). Para perguntas sobre seus dados relacionais, o NL2SQL nativo do Aurabase traduz diretamente uma pergunta em SQL validado. Para obter detalhes sobre os parâmetros HNSW e classes de dimensão mencionados acima, consulte o artigo sobre indexação HNSW e a comparação de dimensões incorporadas. A referência completa da API continua sendo a documentação do RAG & pgvector e a documentação do AI Gateway.

#
Perguntas frequentes

Perguntas frequentes

Você mesmo precisa gerenciar a extensão pgvector e o índice HNSW?+
Não. O esquema de embeddings, a extensão pgvector e os índices HNSW parciais (um por classe de dimensão: 768, 1536, 3072) são provisionados automaticamente quando o projeto é criado. Você chama diretamente ragIngest() e depois rag(); o ajuste fino do índice (ef_search, modo iterative_scan) permanece acessível no lado do servidor se o seu corpus tiver um perfil específico.
Qual dimensão de incorporação devo escolher para meu caso de uso?+
Aurabase valida a dimensão retornada pelo seu fornecedor em relação a três classes suportadas: 768, 1536 e 3072. A escolha depende do modelo de incorporação configurado (por exemplo, text-embedding-3-small no OpenAI produz 1536 dimensões) e envolve um compromisso entre recall, custo e tamanho de armazenamento detalhado em nossa comparação dedicada às dimensões de incorporação.

PRONTO PARA IMPLEMENTAR?

Seu back-end em cinco minutos.

Não é necessário cartão de crédito · 500 MB grátis · 50.000 MAU