Recuperação híbrida e permissões por usuário no índice: como não vazar dados no RAG
Busca léxica mais vetorial, fusão de resultados, ACL herdada da origem aplicada em tempo de consulta, revogação, multi-tenancy e testes automatizados de vazamento.
A maior parte dos incidentes de segurança em sistemas de RAG não vem de prompt injection sofisticada. Vem de algo mais banal: o índice de busca devolve um documento que o usuário não tinha permissão de ver na origem. A causa raiz quase sempre é a mesma — permissões foram tratadas como detalhe de implementação, não como parte do desenho da recuperação.
Este artigo cobre como montar recuperação híbrida (léxica + vetorial) com controle de acesso correto: onde aplicar o filtro, como sincronizar revogações, como isolar tenants e como testar que nada disso está furado.
Por que híbrida, não só vetorial
Busca puramente vetorial erra em dois cenários comuns: termos exatos (códigos de produto, IDs, siglas) e negações ou filtros estruturados. Busca léxica (BM25 ou equivalente) cobre exatamente esses casos.
A arquitetura híbrida roda as duas em paralelo e funde os resultados:
Consulta do usuário
│
├─→ Busca léxica (BM25) ──┐
│ ├─→ Fusão (RRF ou score ponderado) → Top-K final
└─→ Busca vetorial (embeddings) ──┘Reciprocal Rank Fusion (RRF) é a escolha mais robusta quando as duas listas têm escalas de score incomparáveis: em vez de normalizar scores, soma-se 1 / (k + rank) para cada documento nas duas listas e reordena pelo total. Isso evita ter que calibrar pesos toda vez que um dos motores muda de versão.
Alternativa mais simples — e mais frágil — é normalizar os scores (min-max) e combinar com peso fixo (ex.: 0.6 vetorial + 0.4 léxico). Funciona, mas exige recalibração cada vez que a distribuição de scores muda.
Onde aplicar a ACL: pré-filtro vs. pós-filtro
Este é o ponto onde a maioria dos sistemas de RAG erra.
Pós-filtro — buscar primeiro, filtrar depois por permissão — é a abordagem mais comum porque é mais simples de implementar. O problema: se o usuário não tem acesso a nenhum dos top-K documentos retornados, a resposta final fica vazia ou pobre, mesmo havendo documentos permitidos mais abaixo no ranking. Pior, dependendo da implementação, contagens e agregações podem vazar a existência de documentos (a IA menciona "há 3 documentos sobre X" mesmo que o usuário não possa ver nenhum).
Pré-filtro — restringir o espaço de busca à permissão do usuário antes de rankear — é a abordagem correta para dados sensíveis. O filtro de ACL entra como parte da query ao motor de busca (filtro de metadado), não como etapa posterior em memória:
Consulta + ACL do usuário (grupos, tenant, papéis)
│
▼
Motor de busca filtra por ACL ANTES de rankear
│
▼
Top-K já é 100% dentro do que o usuário pode verA maioria dos bancos vetoriais modernos (Pinecone, Weaviate, Qdrant, pgvector com RLS) suporta filtro de metadado nativo o suficiente rápido para isso não virar gargalo, desde que o campo de ACL seja indexado.
Modelando a ACL herdada da origem
O índice não deve reinventar permissões — ele deve espelhar as da fonte (SharePoint, Google Drive, Confluence, banco de dados). Cada chunk indexado carrega metadados de controle de acesso:
| Campo | Exemplo | ||
|---|---|---|---|
tenant_id | empresa-123 | ||
acl_groups | [grupo-financeiro, grupo-diretoria] | ||
acl_users | [user-456] (para overrides pontuais) | ||
visibility | restricted \ | internal \ | public |
source_updated_at | timestamp da última sincronização de ACL |
Na hora da consulta, resolve-se a identidade do usuário (grupos, papéis, tenant) e compõe-se o filtro: tenant_id = X AND (acl_groups INTERSECTS user_groups OR acl_users CONTAINS user_id).
Revogação e sincronização de permissões
Permissão herdada da origem só é confiável se o índice for atualizado quando a origem muda. Duas estratégias, combináveis:
- 1.Sincronização por eventos: a origem emite webhook ou evento (ex.: usuário removido de um grupo no SharePoint) e o índice reprocessa os documentos afetados quase em tempo real.
- 2.Reconciliação periódica: um job roda em cadência fixa (ex.: a cada 15–30 minutos para dados sensíveis, horária para o resto) e recomputa ACLs a partir da origem, corrigindo drift que os eventos não capturaram.
Trate a reconciliação periódica como rede de segurança obrigatória, não como opcional — sistemas de eventos falham silenciosamente, e é nela que revogações perdidas são pegas antes de virar incidente.
Multi-tenancy
Multi-tenancy é permissão em escala máxima: um bug de isolamento entre tenants é o pior tipo de vazamento, porque cruza fronteiras organizacionais.
- Prefira isolamento físico ou de namespace (índice ou coleção por tenant) quando o volume permitir — elimina uma classe inteira de bugs de filtro.
- Quando o índice é compartilhado, o
tenant_iddeve ser um filtro obrigatório, aplicado no nível de infraestrutura (política de banco, não só em código de aplicação) — para que um bug de aplicação não vire vazamento entre clientes. - Nunca confie em um filtro de tenant que pode ser omitido por engano em uma query específica; use row-level security ou equivalente que rejeite consultas sem o filtro.
Testes automatizados de vazamento
ACL sem teste automatizado é ACL que vai vazar, é questão de tempo. O conjunto mínimo de testes:
- Teste de isolamento de tenant: usuário do tenant A nunca deve ver, em nenhuma consulta, documento do tenant B — rodar com um dataset de fixtures cobrindo múltiplos tenants.
- Teste de revogação: remover permissão de um usuário e verificar que uma consulta imediatamente após deixa de retornar o documento (dentro da janela de sincronização aceita).
- Teste de vazamento por agregação: verificar que contagens, resumos e sugestões da IA não revelam a existência de documentos fora do escopo do usuário.
- Teste de escalonamento de privilégio: simular usuário sem grupo nenhum e confirmar que zero documentos restritos retornam.
Rode esse conjunto no CI, contra um índice de teste com dados sintéticos representando múltiplos tenants e níveis de permissão — não apenas manualmente antes de um release grande.
O que fazer na segunda-feira
- Audite se seu pipeline de RAG aplica ACL como pré-filtro ou pós-filtro na busca, e migre para pré-filtro se ainda não for o caso.
- Verifique se existe reconciliação periódica de permissões, não só sincronização por eventos, e defina a cadência para dados sensíveis.
- Escreva o primeiro teste automatizado de isolamento entre tenants e rode-o no CI antes do próximo deploy.
- Se o índice for compartilhado entre tenants, confirme que o filtro de
tenant_idestá no nível de infraestrutura, não apenas no código da aplicação.
Leitura complementar
Trilha executiva:
- RAG não é mágica: o custo real de dar contexto corporativo à IA — a leitura de negócio deste mesmo tema.
