Por que recuperação vence fine-tuning
Um engenheiro de suporte pergunta para o seu app: "o plano Pro inclui logs de auditoria?" O modelo responde, com confiança, que sim. Não inclui. Ninguém escreveu essa frase em lugar nenhum. O modelo produziu uma continuação plausível da pergunta, e plausível é tudo que ele foi treinado para otimizar.
O modelo não está quebrado. Ele nunca viu a sua página de preços. Tudo que ele sabe congelou quando o treinamento terminou, e o seu preço mudou na terça passada.
Existem dois jeitos de fechar essa lacuna. Você pode gravar o seu conhecimento nos pesos do modelo (fine-tuning), ou pode buscar a resposta na hora da pergunta e entregá-la ao modelo como parte do prompt. A segunda abordagem é Retrieval-Augmented Generation, e para a esmagadora maioria dos sistemas em produção ela é a escolha certa.
Os dois jeitos de dar o seu conhecimento a um modelo
Fine-tuning muda o modelo. Você junta milhares de exemplos, roda um treino e recebe de volta pesos novos que absorveram o seu domínio. Recuperação muda o prompt. Você mantém o modelo como está, encontra os três parágrafos mais relevantes do seu próprio material e cola tudo acima da pergunta do usuário.
Para trabalho que depende de conhecimento, a comparação não é equilibrada:
| Fine-tuning | Recuperação | |
|---|---|---|
| Atualizar um fato | Retreinar | Atualizar uma linha |
| Custo de uma mudança | Horas e uma conta de treino | Milissegundos |
| Consegue citar a fonte | Não | Sim |
| Lida com dados privados por tenant | Um modelo por tenant | Um filtro na query |
| Ensina um novo formato ou estilo | Excelente | Desajeitado |
| Ensina um novo fato | Caro e furado | Natural |
As duas últimas linhas são a divisória real. Fine-tuning ensina comportamento; recuperação fornece fatos. Um modelo ajustado para responder sempre na voz seca do changelog da sua empresa é um bom uso de fine-tuning. Um modelo ajustado para memorizar o seu changelog é um uso ruim: amanhã você publica outra entrada.
Existe também um argumento de responsabilidade que importa mais que os dois. Uma resposta recuperada carrega as fontes junto. Quando o modelo diz que o plano Pro tem logs de auditoria, ele consegue apontar a linha de onde leu isso, e uma pessoa consegue conferir. Um modelo com fine-tuning que diz a mesma coisa não oferece nada além da própria confiança.
O que é RAG
Tirando o acrônimo, RAG é um mecanismo de busca ligado na frente de um prompt:
flowchart LR
Q["Pergunta do usuário"] --> R["Retriever"]
R --> D[("Seu corpus")]
D --> C["Top-k trechos"]
C --> P["Prompt: trechos + pergunta"]
P --> M["Claude"]
M --> A["Resposta com citações"]
Nada nesse diagrama é inédito. O retriever é busca. O prompt é concatenação de string. A chamada do modelo é uma requisição HTTP. RAG é uma arquitetura, e não uma tecnologia, e é por isso que vale estudar como arquitetura. O difícil fica nas decisões que ligam uma caixa à outra, mais do que nas caixas.
Dois pipelines, não um
A coisa mais útil para internalizar cedo: um sistema RAG são dois pipelines que rodam em momentos diferentes e falham de jeitos diferentes.
flowchart TB
subgraph Index["Tempo de indexação: lento, em lote, offline"]
S["Documentos de origem"] --> CH["Fatiar"]
CH --> EM["Gerar embeddings"]
EM --> ST[("Vector store")]
end
subgraph Query["Tempo de consulta: rápido, por requisição, online"]
U["Pergunta do usuário"] --> QE["Embedding da pergunta"]
QE --> SE["Buscar"]
ST -.-> SE
SE --> RR["Reordenar"]
RR --> GEN["Gerar"]
end
Tempo de indexação roda quando documentos mudam. Ele pode ser lento: é um job em background. É medido por throughput e custo, e as falhas dele são silenciosas: um documento que falha ao indexar nunca mais é encontrado, e nenhum usuário vê erro.
Tempo de consulta roda em toda pergunta. Tem um orçamento de latência medido em centenas de milissegundos, e as falhas dele são barulhentas: um retriever lento é um produto lento.
Misturar os dois é o erro de arquitetura mais comum numa primeira construção de RAG. Gerar o embedding de um documento dentro da requisição que o criou deixa o upload lento e acopla o seu caminho de escrita ao uptime de uma API de terceiro. Embedding é job.
Onde isso encaixa em Rails
Cada caixa acima mapeia em algo que você já conhece:
- Fatiar e gerar embeddings: um ActiveJob, disparado quando o registro de origem muda.
- O vector store: uma tabela Postgres com uma coluna de vetor, mesmo banco, mesmas transações, mesmo backup.
- Recuperação: um query object, do mesmo jeito que
Enrollment::UserGamificationQueryé um query object neste app. - Geração: um service object que recebe o contexto recuperado e a pergunta e devolve um resultado.
Não existe camada nova de infraestrutura aqui, a menos que você escolha adicionar uma. Esse é o argumento inteiro para começar com Postgres, e é o argumento que este curso vai repetir.
O que este curso cobre
- Por que recuperação vence fine-tuning: você está aqui.
- Indexação: como fatiar, e o que cada trecho precisa carregar.
- Embeddings como decisão de arquitetura: dimensões, custo e lock-in.
- Armazenamento e recuperação: vetores no banco que você já tem.
- Recuperação híbrida e reordenação: por que busca vetorial pura não basta.
- Geração: montar um prompt que possa ser cobrado.
- Juntando tudo: o pipeline como objetos Rails.
No fim você não vai ter decorado um SDK. Vai conseguir olhar para um sistema RAG e dizer quais das sete decisões foram tomadas mal, começando pela que quase todo mundo erra, que é o fatiamento, e que é para onde vamos agora.
Continue com a aula 2
Fatiamento: o que um trecho precisa carregar
Trata do tamanho dos trechos, do corte pela estrutura, dos prefixos contextuais e dos metadados de origem e tenant.
Com uma conta grátis você também tem os quizzes, seu progresso e suas anotações, e a discussão.