Conteúdo detalhado
🔢 O que são embeddings
Computador não entende palavra — entende número. Embedding é o truque que vira texto em número de um jeito que preserva o significado: cada frase vira uma lista longa de números (um vetor), e textos com sentido parecido caem perto uns dos outros num espaço imaginário. "Gato" e "felino" ficam vizinhos; "gato" e "caminhão" ficam longe.
🆕 Novo aqui?
"Embedding" (ou "vetor") é uma lista de números — tipo [0.12, -0.03, 0.88, ...], geralmente com 384 a 1024 posições — que representa o significado de um texto. Um "modelo de embeddings" é uma IA pequena, treinada só pra produzir esses vetores (não gera texto, só "mede sentido"). "Similaridade" = quão perto dois vetores estão; perto = sentido parecido.
🔑 A ideia central
Embeddings transformam "buscar texto" num problema de geometria:
- •Cada pedaço de texto vira um ponto num espaço de muitas dimensões.
- •Significados parecidos ficam próximos; significados distantes ficam longe.
- •Buscar "o que combina com a pergunta" vira achar os pontos mais próximos — não importa se as palavras exatas batem.
Cada palavra vira um ponto. A pergunta (em ciano) cai perto do aglomerado de "animais" e longe de "transporte" e "comida" — então a busca devolve gato, felino, bichano, mesmo que a pergunta não use nenhuma dessas palavras. Isso é busca por significado, não por palavra exata.
📚 Por que RAG
O modelo local sabe muita coisa do mundo — mas não sabe nada do seu mundo: seus PDFs, suas notas, a documentação interna da empresa. Treinar o modelo de novo com isso é caro e lento. RAG resolve por fora: na hora da pergunta, ele busca os trechos certos dos seus documentos e cola no prompt, como contexto. O modelo responde lendo aquilo — sem retreinar nada.
🆕 Novo aqui?
RAG = Retrieval-Augmented Generation (geração aumentada por recuperação). Em português direto: "antes de responder, vá buscar os trechos relevantes e leia-os". O modelo continua o mesmo — você só enriquece o prompt com o material certo, na hora certa.
✗ Só o modelo (sem RAG)
- ✗Não conhece seus documentos privados
- ✗"Alucina" quando não sabe — inventa com confiança
- ✗Conhecimento congelado na data do treino
- ✗Não tem como citar a fonte
✓ Modelo + RAG
- ✓Responde sobre os SEUS arquivos
- ✓Menos alucinação — fala com base no trecho recuperado
- ✓Atualiza na hora: trocou o documento, mudou a resposta
- ✓Dá pra mostrar de onde veio a resposta
🆚 RAG não é fine-tuning
Fine-tuning muda os pesos do modelo (ensina um novo jeito de responder) — caro, demorado e difícil de atualizar. RAG não toca no modelo: ele só decide o que mostrar no prompt. Para "responder sobre os meus dados", RAG é quase sempre o caminho mais simples, barato e atualizável.
💡 Dica prática
RAG é o que dá memória de longo prazo a um agente local (Trilha 4): você guarda conversas, notas e fatos como vetores, e o agente "lembra" recuperando o que importa — em vez de tentar enfiar tudo na janela de contexto. Memória = RAG sobre o que já aconteceu.
🔧 Anatomia de um RAG
Todo RAG tem duas metades: a ingestão (feita uma vez, quando você adiciona documentos) e a consulta (feita a cada pergunta). Entenda o desenho e o resto vira detalhe de código.
🆕 Novo aqui?
"Chunk" (pedaço) é um trecho do documento — um parágrafo, uns 200–500 tokens. Você quebra o texto em chunks porque (1) o modelo de embeddings tem limite de tamanho e (2) você quer recuperar só o trecho relevante, não o arquivo inteiro. Chunk bom = autocontido (faz sentido sozinho) e nem grande nem minúsculo demais.
Leia em duas linhas: em cima (roxo), a ingestão — documento → pedaços → vetores → banco. Embaixo (ciano), a consulta — pergunta → vetor → busca os vizinhos no banco → o LLM local recebe os trechos e escreve a resposta. O mesmo modelo de embeddings é usado dos dois lados.
Os 6 passos, em ordem
Chunk — quebrar o documento
Divida o texto em pedaços autocontidos (ex.: 1 parágrafo). Só na ingestão.
Embed — virar vetor
Passe cada chunk pelo modelo de embeddings; cada um vira um vetor.
Store — guardar no banco vetorial
Salve vetor + texto original no vector store. Pronto: documento "indexado".
Query — embedar a pergunta
Na hora da pergunta, embede o texto dela com o mesmo modelo.
Retrieve — buscar os vizinhos
Peça ao banco os N chunks mais próximos do vetor da pergunta.
Generate — responder com contexto
Cole os trechos no prompt e peça ao LLM local responder só com base neles.
⚡ Rodando embeddings local
Modelos de embeddings são pequenos — alguns têm poucas centenas de MB e rodam liso até em hardware budget, sem GPU. O nomic-embed-text é um ótimo padrão para começar: leve, bom em português e já empacotado no Ollama. Vamos baixar e gerar o primeiro vetor.
⌨️ Exemplo prático: seu primeiro embedding
Objetivo: baixar um modelo de embeddings e transformar uma frase num vetor. Cole no terminal e depois no Python.
Como verificar: o curl devolve um JSON com uma lista grande de números — esse é o vetor. No Python, len(...) imprime a dimensão (ex.: 768). Se imprimiu um número, seus embeddings estão rodando 100% local. Guarde esse número: todos os vetores do mesmo modelo têm o mesmo tamanho.
💡 Dica prática
Use o mesmo modelo de embeddings para indexar os documentos e para embedar a pergunta. Misturar modelos (ou trocar de modelo no meio) quebra a busca, porque os vetores deixam de viver no mesmo espaço. Trocou de modelo de embeddings? Re-indexe tudo.
🗄️ Banco vetorial simples
Você poderia guardar os vetores numa lista e comparar um por um — funciona com 10 chunks, vira tartaruga com 100 mil. Um banco vetorial existe pra isso: armazena os vetores e responde rápido à pergunta "quais são os N mais parecidos com este aqui?".
🆕 Novo aqui?
"Vector store" / "banco vetorial" é um banco de dados especializado em busca por similaridade entre vetores. Opções locais comuns: Chroma (mais fácil pra começar, guarda em disco com 2 linhas), FAISS (biblioteca da Meta, rapidíssima, sem servidor) e sqlite-vec (uma extensão que dá busca vetorial ao SQLite que você já conhece). Todos rodam local, sem nuvem.
🟣 Chroma
Mais simples pra começar. Persiste em disco sozinho, API amigável.
Use quando: quer subir um RAG em minutos.
🟣 FAISS
Biblioteca de busca da Meta. Muito rápida, ótima em escala.
Use quando: são muitos vetores e velocidade importa.
🟣 sqlite-vec
Busca vetorial dentro de um arquivo SQLite. Zero servidor.
Use quando: já usa SQLite e quer um arquivo só.
⌨️ Montagem mínima com Chroma
Objetivo: guardar um vetor e buscar o mais parecido — o coração do RAG, isolado.
# pip install chromadb import chromadb db = chromadb.PersistentClient(path="./meu_rag") # guarda em disco col = db.get_or_create_collection("docs") # guardar: id + texto + o vetor que veio do nomic-embed-text col.add(ids=["1"], documents=["A senha do wifi do escritório é roxo-1234"], embeddings=[[0.12, -0.03, 0.88]]) # <vetor real do passo 4> # buscar: os 3 mais parecidos com o vetor da pergunta hits = col.query(query_embeddings=[[0.10, -0.01, 0.90]], n_results=3) print(hits["documents"]) # → o(s) trecho(s) recuperado(s)
Como verificar: rode duas vezes. O PersistentClient grava em ./meu_rag, então na segunda execução o documento já está lá sem precisar adicionar de novo. O query deve devolver o texto que você guardou.
💡 Dica prática
Guarde sempre o texto original junto do vetor (o campo documents). O vetor serve só para encontrar; o que você cola no prompt é o texto. Banco vetorial sem o texto guardado é uma busca que acha o ponto certo mas não sabe te mostrar o conteúdo.
🚀 Um RAG mínimo end-to-end
Hora de juntar tudo. Este script faz o RAG completo: lê um .txt, quebra em chunks, embeda, guarda, e aí responde uma pergunta usando só o que está no documento — tudo no seu Ollama. Os trechos marcados com <...> são o que você troca.
⌨️ Exemplo prático: RAG completo em ~25 linhas
Objetivo: responder uma pergunta cuja resposta só existe no seu arquivo. Salve como rag.py e rode.
# pip install chromadb openai (Ollama já rodando) from openai import OpenAI import chromadb client = OpenAI(base_url="http://localhost:11434/v1", api_key="ollama") EMB = "nomic-embed-text" LLM = "qwen2.5:7b" # <troque pelo seu modelo> def embed(txt): return client.embeddings.create(model=EMB, input=txt).data[0].embedding # 1) INGESTÃO: lê o .txt, quebra em chunks, embeda e guarda texto = open("notas.txt").read() # <seu arquivo .txt> chunks = [c for c in texto.split("\n\n") if c.strip()] # 1 parágrafo = 1 chunk col = chromadb.Client().create_collection("notas") col.add(ids=[str(i) for i in range(len(chunks))], documents=chunks, embeddings=[embed(c) for c in chunks]) # 2) CONSULTA: embeda a pergunta, busca os vizinhos, monta o prompt pergunta = "Qual a senha do wifi do escritorio?" # <sua pergunta> viz = col.query(query_embeddings=[embed(pergunta)], n_results=3)["documents"][0] contexto = "\n".join(viz) resp = client.chat.completions.create(model=LLM, messages=[ {"role": "system", "content": "Responda SO com base no contexto. Se nao houver, diga 'nao sei'."}, {"role": "user", "content": f"Contexto:\n{contexto}\n\nPergunta: {pergunta}"} ]) print(resp.choices[0].message.content)
Como verificar: crie um notas.txt com um fato que o modelo não teria como saber — ex.: a linha A senha do wifi do escritório é roxo-1234. Rode e faça a pergunta acima: se a resposta trouxer roxo-1234, o RAG funcionou — o modelo só acertou porque o trecho veio do seu documento. Agora pergunte algo que não está no arquivo: ele deve responder não sei em vez de inventar.
✓ RAG que funciona
- ✓Chunks autocontidos e do tamanho certo
- ✓Mesmo modelo de embeddings na ingestão e na consulta
- ✓System prompt manda usar SÓ o contexto
- ✓Mostra a fonte de cada resposta
✗ RAG que falha
- ✗Chunk gigante (documento inteiro) ou picado demais
- ✗Trocou o modelo de embeddings e não re-indexou
- ✗Sem regra de "não inventar" — o modelo alucina
- ✗Joga texto demais no prompt e estoura o contexto
Auto-checagem (opcional): o que o RAG faz, na prática?
📌 Resumo do módulo
Próximo:
Trilha 4 — Avançado & Agentes 24/7 · você sai de "rodar e servir modelos" para colocá-los a trabalhar sozinhos, o tempo todo.