O problema: ensinar o que você ainda não ensinou
Tenho um curso de programação com 47 aulas. Cada aula tem notes (onde explico as coisas) e labs (onde o aluno pratica). E tenho um problema: às vezes uso conceitos nos labs que ainda não expliquei nas notes.
“Beleza, neste exercício usa map para transformar a lista.”
O problema? Não expliquei o que diabos é map até três aulas depois.
Isso acontece mais do que você pensa. Você tem o material na cabeça, pula de um lugar para outro, e sem perceber assume que o aluno sabe coisas que você ainda não contou para ele. O resultado: frustração, confusão, e alunos que pensam que são burros quando o burro é você.
A solução manual seria revisar cada lab, anotar que conceitos usa, e verificar se foram explicados antes. Mas tenho 47 aulas com vários notebooks cada uma. Nem pensar.
A solução: busca semântica com ChromaDB
A ideia é simples:
- Extrair os conceitos de cada notebook (o que se ensina, o que se usa)
- Guardá-los em um banco de dados que entenda significado, não só texto
- Para cada conceito usado em um lab, verificar se existe em notes anteriores
Isso de “entender significado” é crucial. Se nas notes digo “função de ordem superior” e no lab uso “higher-order function”, um grep não vai encontrar nada. Mas semanticamente são a mesma coisa.
Aqui que entra o ChromaDB: um banco de dados de vetores que converte texto em embeddings e permite buscar por similaridade. Dito em português: você guarda texto, e depois pode perguntar “tem algo parecido com isso?” e ele te devolve os mais similares.
ChromaDB em 5 minutos
ChromaDB é como SQLite mas para embeddings. Um único arquivo (ou pasta), sem servidor, sem configuração. Instala, usa e vai embora.
| |
O conceito básico
Num banco normal você guarda linhas com colunas. No ChromaDB você guarda documentos com embeddings:
| |
É isso. ChromaDB automaticamente:
- Gera embeddings dos documentos (por padrão usa
all-MiniLM-L6-v2) - Indexa para busca rápida
- Persiste no disco
Buscar por similaridade
| |
Viu? Busquei “higher-order function” e encontrou “função de ordem superior” mesmo que o texto seja completamente diferente. Essa é a mágica dos embeddings.
O sistema completo: validação curricular
Agora vamos construir o sistema que valida pra não fazer besteira. O código real está no meu projeto, mas aqui te dou a versão simplificada pra você entender o conceito.
Passo 1: Extrair conceitos de notebooks
Primeiro precisamos tirar os conceitos de cada notebook. Isso faço com um LLM (Gemini Flash via OpenRouter), mas você poderia fazer com regexes se for corajoso:
| |
O LLM classifica cada conceito como:
- introduces: Se ensina com explicação
- uses: Se usa assumindo conhecimento prévio
Passo 2: Guardar no ChromaDB
Agora guardamos os conceitos com seus metadados:
| |
Passo 3: Validar a progressão
Aqui vem o interessante. Para cada conceito “usado” num lab, verificamos se existe algo similar em notes anteriores:
| |
A função is_concept_known é onde entra o ChromaDB. Não fazemos match exato, fazemos busca semântica:
| |
Passo 4: O relatório
Executando a validação sobre meu curso, obtenho um belo relatório:
| |
Agora sei exatamente o que tenho que arrumar.
Detalhes que importam
Modelo de embeddings multilíngue
Se seu conteúdo está em português, use um modelo multilíngue:
| |
O modelo padrão (all-MiniLM-L6-v2) está treinado principalmente em inglês e pode dar resultados estranhos com português.
Distância cosseno vs euclidiana
Para texto, use distância cosseno:
| |
A distância cosseno mede o ângulo entre vetores, ignorando a magnitude. Isso é o que você quer para similaridade semântica.
Converter distância em similaridade
ChromaDB retorna distância (menor = mais similar). Se quiser similaridade (maior = mais similar):
| |
Com distância cosseno, o range é [0, 2], então a similaridade fica em [-1, 1]. Na prática, para textos similares costuma estar em [0.5, 1].
Persistência
ChromaDB tem dois modos:
| |
Para um sistema de validação que você vai executar repetidamente, use persistente. Assim não recalcula embeddings toda vez.
Filtros com where
Pode filtrar resultados por metadados:
| |
Isso é crucial para a validação: só queremos buscar em conceitos que já foram ensinados.
Alternativas ao ChromaDB
ChromaDB não é a única opção. Aqui tem outras:
| Ferramenta | Prós | Contras |
|---|---|---|
| ChromaDB | Simples, sem servidor, boa documentação | Limitado a milhões de vetores |
| Pinecone | Escalável, managed | Pago, vendor lock-in |
| Weaviate | Poderoso, GraphQL API | Mais complexo de configurar |
| Qdrant | Rápido, Rust | Menos conhecido |
| pgvector | Se já usa PostgreSQL | Requer PostgreSQL |
Para um projeto como este (milhares de conceitos, não milhões), ChromaDB é perfeito. Se precisar escalar para bilhões de vetores ou alta disponibilidade, veja as alternativas.
O hook de pre-commit
Para isso ser útil de verdade, integrei no workflow do git:
| |
Agora, toda vez que tento fazer commit, o sistema verifica se não estou fazendo besteira. Se há violações, o commit é bloqueado e me diz o que arrumar.
Conclusão
ChromaDB é uma dessas ferramentas que quando você descobre pensa “como vivi sem isso?”. É SQLite para embeddings: simples, local, e funciona.
O caso de uso que te mostrei (validação curricular) é só um exemplo. Bancos de dados vetoriais servem para:
- Busca semântica em documentos
- RAG (Retrieval-Augmented Generation) para LLMs
- Detecção de duplicados semânticos
- Recomendações baseadas em similaridade
- Clustering de conteúdo
E o melhor: a barreira de entrada é mínima. Instala, guarda documentos, busca. Nada de configurar servidores, schemas, ou índices complicados.
Se você tem um problema onde precisa encontrar “coisas parecidas com isso”, experimenta ChromaDB. O pior que pode acontecer é funcionar bem demais e você se perguntar por que não usou antes.
TL;DR: ChromaDB é um banco de dados vetorial local e simples. Usamos para verificar que um curso de programação não use conceitos antes de ensiná-los, usando busca semântica para detectar conceitos similares mesmo que o texto seja diferente.