Aula 5, Qdrant para produção
Esta aula fecha o módulo olhando para a produção. O ChromaDB é ótimo para aprender e para projetos locais, mas sistemas maiores pedem um banco vetorial mais robusto, como o Qdrant. Vamos comparar os dois e ver os recursos que importam quando o assistente sai do notebook.
Construímos um assistente de RAG que funciona, com banco vetorial, busca semântica e respostas fundamentadas. Para aprender e para projetos pessoais, o ChromaDB embutido dá conta com folga. Mas quando o assistente precisa servir muitos usuários, lidar com milhões de documentos, filtrar por metadados e rodar de forma confiável em um servidor, vale conhecer uma ferramenta pensada para produção.
O Qdrant é um banco vetorial robusto, que roda como serviço, em geral em um contêiner Docker, e oferece busca eficiente em larga escala, filtragem por metadados, persistência e uma API de rede. Nesta aula você vai entender quando migrar do ChromaDB para o Qdrant, conhecer os recursos que importam em produção, e ver como a mesma lógica de RAG se adapta a um banco vetorial servidor. Aqui também vive o projeto que fecha o módulo, o assistente educacional completo.
Objetivos
Ao final desta aula, você deve ser capaz de:
- Diferenciar um banco vetorial embutido de um servidor.
- Reconhecer os recursos de produção, como filtragem por metadados e persistência.
- Entender quando migrar do ChromaDB para o Qdrant.
- Integrar o assistente de RAG a um banco vetorial de produção.
Teoria
A diferença central entre ChromaDB e Qdrant, no uso típico, é o modelo de execução. O ChromaDB roda embutido no seu programa, o que é simples e ótimo para começar. O Qdrant roda como um serviço separado, que o seu programa acessa pela rede, em geral subido com Docker. Esse modelo de serviço é o que permite escalar, várias aplicações acessam o mesmo banco, e ele pode ser dimensionado de forma independente.
Em produção, alguns recursos passam a importar muito. A filtragem por metadados permite restringir a busca, por exemplo só nos documentos de uma disciplina ou de um período, combinando a busca semântica com filtros exatos. A persistência confiável garante que os dados sobrevivem a reinícios. E a busca aproximada eficiente, com índices como o HNSW, mantém a resposta rápida mesmo com milhões de vetores.
flowchart LR
A[Assistente] --> Q[(Qdrant, serviço via Docker)]
Q --> F[Filtra por metadados]
F --> S[Busca semântica eficiente]
S --> A
A boa notícia é que a lógica de RAG não muda. Continuamos indexando vetores, recuperando os top-k e montando o contexto. Só trocamos o componente de armazenamento e busca. Por isso vale a pena ter isolado o banco vetorial atrás de uma interface clara, como fizemos, trocar de ChromaDB para Qdrant vira uma questão de implementar a mesma interface com o novo backend.
Explicação Intuitiva
Pense na diferença entre uma estante na sua sala e uma biblioteca pública. A estante, que é o ChromaDB, é perfeita para a sua coleção pessoal, prática e sempre à mão. A biblioteca pública, que é o Qdrant, é uma instituição preparada para muitos usuários, com catálogo robusto, controle de acesso e capacidade de crescer. Você não monta uma biblioteca pública para guardar dez livros, e nem cabe a sua cidade inteira em uma estante de sala.
A filtragem por metadados é como poder dizer à biblioteca, quero livros sobre cálculo, mas só os publicados depois de tal ano. Você combina a busca por assunto com filtros precisos. Essa capacidade, que parece pequena, é decisiva em sistemas reais, onde quase sempre queremos buscar dentro de um recorte específico do acervo.
Explicação Matemática
A matemática da busca é a mesma das aulas anteriores, similaridade do cosseno e seleção dos top-k, com índices aproximados para escalar. O que o Qdrant acrescenta é a combinação com filtros. A busca passa a ser condicionada, primeiro restringimos o conjunto candidato aos vetores cujos metadados satisfazem o filtro, e então buscamos os mais similares dentro desse subconjunto.
Formalmente, em vez de buscar os top-k sobre todos os vetores, buscamos os top-k sobre o subconjunto ${\mathbf{d}_i : \text{metadados}(i) \text{ satisfazem o filtro}}$. Isso melhora tanto a precisão, ao excluir o que não interessa, quanto o desempenho, ao reduzir o espaço de busca. Implementar isso de forma eficiente, sem percorrer tudo, é parte do valor de um banco vetorial de produção.
Exemplo Prático
Vamos mostrar como a filtragem por metadados muda a busca, estendendo o nosso banco mínimo para guardar um metadado por documento, como a disciplina, e permitir consultar só dentro de uma disciplina. Isso ilustra, sem depender de servidor, o recurso mais característico da produção.
Em seguida, o notebook traz o caminho com o Qdrant de verdade, via Docker, como referência. O código está no notebook notebooks/modulo-09/05-qdrant-producao.ipynb, então abra-o ao lado para acompanhar.
Código Comentado
import re
import math
from collections import Counter
def tok(texto):
return re.findall(r"\w+", texto.lower())
# Documentos com metadados (a disciplina de cada um).
itens = [
{"texto": "A derivada mede a taxa de variação de uma função.", "disciplina": "calculo"},
{"texto": "A integral acumula valores ao longo de um intervalo.", "disciplina": "calculo"},
{"texto": "Uma matriz organiza números em linhas e colunas.", "disciplina": "algebra"},
{"texto": "O determinante indica se uma matriz é invertível.", "disciplina": "algebra"},
]
N = len(itens)
df = Counter()
for it in itens:
for w in set(tok(it["texto"])):
df[w] += 1
idf = {w: math.log(N / f) for w, f in df.items()}
def vetor(texto):
tf = Counter(tok(texto))
return {w: tf[w] * idf.get(w, 0.0) for w in tf}
def cos(a, b):
p = sum(a[w] * b.get(w, 0.0) for w in a)
na = math.sqrt(sum(v * v for v in a.values()))
nb = math.sqrt(sum(v * v for v in b.values()))
return p / (na * nb) if na and nb else 0.0
def buscar(pergunta, filtro_disciplina=None, k=2):
"""Busca semântica com filtro opcional por metadado."""
q = vetor(pergunta)
candidatos = [it for it in itens
if filtro_disciplina is None or it["disciplina"] == filtro_disciplina]
ranking = sorted(((cos(q, vetor(it["texto"])), it) for it in candidatos), reverse=True,
key=lambda par: par[0])
return [(round(s, 3), it["texto"]) for s, it in ranking[:k]]
print("Sem filtro:")
for s, t in buscar("o que é uma matriz?"):
print(" ", s, t)
print("\nFiltrando só álgebra:")
for s, t in buscar("o que é uma matriz?", filtro_disciplina="algebra"):
print(" ", s, t)
Ao rodar, a busca sem filtro percorre toda a base, enquanto a busca filtrada por álgebra ignora os documentos de cálculo, retornando apenas os relevantes daquela disciplina. Esse recurso, que aqui implementamos de forma simples, é nativo e eficiente no Qdrant, e é o que permite, em um sistema real, buscar exatamente no recorte certo do acervo. A lógica de RAG continua a mesma, só o componente de armazenamento ficou mais poderoso.
Exercícios
1) Conceitual: Qual a diferença principal entre um banco vetorial embutido e um servidor? 2) Conceitual: Por que a filtragem por metadados é tão importante em produção? 3) Prático: Acrescente um segundo metadado, como o nível de dificuldade, e filtre por ele. 4) Prático: Suba o Qdrant via Docker e reproduza a indexação e a busca filtrada. 5) Extensão: Pesquise como o Qdrant lida com persistência e atualização de coleções em produção.
Projeto da Aula e Projeto do Módulo
Este é o projeto que fecha o módulo, o assistente educacional de RAG completo, na pasta
projects/m09-rag-assistant/. A entrega reúne tudo, um indexador com chunking, um banco vetorial
com a opção de ChromaDB, a busca semântica com montagem de contexto e citação, o tratamento da
ausência, e a geração com o LLM, com filtragem por metadados como recurso adicional.
O roteiro sugerido é o seguinte. Monte uma base de notas de aula de pelo menos duas disciplinas, com metadados. Indexe tudo no banco vetorial. Implemente o fluxo de resposta com citação e tratamento da ausência. Permita filtrar a busca por disciplina. Teste com perguntas cobertas e não cobertas pela base.
Considere o projeto pronto quando o assistente responder perguntas citando as fontes corretas, recusar de forma honesta o que não está no material, e respeitar o filtro de disciplina. Com isso, você terá construído o seu primeiro assistente educacional de verdade, e estará pronto para o Módulo 10, em que o assistente ganha a capacidade de agir, virando um agente.
Leituras Recomendadas
- A documentação do Qdrant, com guias de instalação via Docker e de filtragem por metadados.
- Comparações entre ChromaDB, Qdrant e outros bancos vetoriais.
- O artigo do FAISS, de Johnson e colegas, sobre a busca eficiente que sustenta esses bancos.
Referências Científicas
As referências abaixo são reais e estão registradas em references/referencias.bib. As chaves entre parênteses são as do BibTeX.
- Johnson, J., Douze, M., e Jégou, H. (2021). Billion-Scale Similarity Search with GPUs. IEEE
Transactions on Big Data. (
johnson2019faiss) - Lewis, P., et al. (2020). Retrieval-Augmented Generation for Knowledge-Intensive NLP Tasks.
NeurIPS. (
lewis2020rag) - Karpukhin, V., et al. (2020). Dense Passage Retrieval for Open-Domain Question Answering.
EMNLP. (
karpukhin2020dpr)