Por que recuperação vence fine-tuning

Prévia grátis 5 min de leitura

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

  1. Por que recuperação vence fine-tuning: você está aqui.
  2. Indexação: como fatiar, e o que cada trecho precisa carregar.
  3. Embeddings como decisão de arquitetura: dimensões, custo e lock-in.
  4. Armazenamento e recuperação: vetores no banco que você já tem.
  5. Recuperação híbrida e reordenação: por que busca vetorial pura não basta.
  6. Geração: montar um prompt que possa ser cobrado.
  7. 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.

Aula 1 de 7 · grátis

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.

Digite para buscar...