Embeddings e Vector Search
Como embeddings funcionam, distâncias vetoriais, escolha de modelo e bancos vetoriais.
Definição
Embeddings transformam texto em vetores de alta dimensão onde similaridade semântica = proximidade geométrica. Texto sobre React e texto sobre "componentes de interface" ficam próximos no espaço vetorial. Distâncias: cosine similarity (ângulo entre vetores, padrão para NLP), dot product (mais rápido, requer vetores normalizados), euclidiana (menos usada para texto). Vector DBs: Pinecone, Weaviate, Qdrant, pgvector (Postgres), Chroma (local).
Problema → Solução
Problema
Busca por palavras-chave (BM25, LIKE) não encontra documentos semanticamente relevantes se as palavras exatas não coincidem. "Como fazer autenticação" não acha "implementar login".Solução
Embeddings + vector search para busca semântica. Hybrid search (vetorial + keyword) para melhor cobertura. Re-ranking com cross-encoder para refinar os top-K resultados. Chunking adequado do documento antes de gerar embeddings.Dica de entrevista
Tip
Escolha do modelo de embedding importa: text-embedding-3-small (OpenAI) para produção custo-eficiente. all-MiniLM-L6-v2 (sentence-transformers) para rodar local sem custo. Para português, modelos multilinguais como multilingual-e5-large têm qualidade muito melhor que modelos English-only.Código
// Comparar similaridade entre textos
import { OpenAIEmbeddings } from '@langchain/openai'
const embeddings = new OpenAIEmbeddings({ model: 'text-embedding-3-small' })
const [vecA, vecB] = await embeddings.embedDocuments([
'Como implementar autenticação JWT',
'Tutorial de login com tokens no Node.js'
])
function cosineSimilarity(a: number[], b: number[]): number {
const dot = a.reduce((sum, val, i) => sum + val * b[i], 0)
const magA = Math.sqrt(a.reduce((sum, val) => sum + val * val, 0))
const magB = Math.sqrt(b.reduce((sum, val) => sum + val * val, 0))
return dot / (magA * magB)
}
const similarity = cosineSimilarity(vecA, vecB)
console.log(`Similaridade: ${(similarity * 100).toFixed(1)}%`)
// → ~85% — semanticamente similares
// Hybrid search com pgvector + full-text
const results = await db.query(`
SELECT id, content,
-- Combina score vetorial e keyword com RRF
(1.0 / (60 + rank_vector)) + (1.0 / (60 + rank_text)) as rrf_score
FROM (
SELECT id, content,
ROW_NUMBER() OVER (ORDER BY embedding <=> $1) as rank_vector,
ROW_NUMBER() OVER (ORDER BY ts_rank(tsv, plainto_tsquery($2)) DESC) as rank_text
FROM documents
) ranked
ORDER BY rrf_score DESC LIMIT 10
`, [queryEmbedding, queryText])Perguntas de entrevista
Q.Cosine similarity vs dot product para busca vetorial?▾
A.Cosine similarity mede o ângulo entre vetores — independe da magnitude. Melhor para comparar embeddings de textos de comprimentos diferentes. Dot product é computacionalmente mais barato e equivalente ao cosine se os vetores forem normalizados (magnitude 1). Pinecone e a maioria dos vector DBs oferecem ambos — use cosine para text embeddings.
Q.O que é hybrid search?▾
A.Combinar busca vetorial (semântica) com busca por palavras-chave (BM25/sparse). Cada método retorna uma lista de resultados com scores. Reciprocal Rank Fusion (RRF) ou scores ponderados combinam as listas. Hybrid search quase sempre supera só vetorial, especialmente para queries com termos técnicos exatos (nomes de função, erro específico).
Q.Como escolher o tamanho do chunk para RAG?▾
A.Depende do caso de uso: chunks pequenos (128-256 tokens) — maior precisão, menor contexto, bom para Q&A factual. Chunks grandes (512-1024 tokens) — mais contexto, possível ruído, bom para sumarização. Parent-child chunking: indexar chunks pequenos, retornar o chunk pai maior. Testar empiricamente com RAGAS é mais confiável que regra fixa.
89/122← →