LLM (Large Language Models)¶
O que é um modelo de linguagem¶
Definição: Modelo de linguagem
Ferramenta probabilística que analisa e gera sequências de palavras com base em dados textuais — dado um texto de entrada, prevê repetidamente qual é o próximo token (unidade mínima de informação textual: pode ser uma palavra, subpalavra ou até um único caractere, dependendo de como o modelo foi treinado).
flowchart LR
A["N-gramas<br/>(estatística pura:<br/>probabilidade de cada<br/>palavra dada uma<br/>janela anterior)"] --> B["Redes Neurais<br/>Recorrentes (RNN)<br/>(capturam relações<br/>temporais no texto)"]
B --> C["Transformers<br/>(estado da arte:<br/>desempenho excepcional<br/>em tarefas diversas)"]
Modelos de linguagem são úteis numa série de aplicações: reconhecimento de fala (prevendo a sequência de palavras mais provável, minimizando erros), tradução automática (aumentando a precisão e naturalidade do texto traduzido), geração de texto natural (criando textos que se assemelham à escrita humana, como em chatbots) e reconhecimento óptico de caracteres e de escrita à mão (melhorando a conversão de texto escaneado ou manuscrito para texto digital).
Modelos de linguagem de grande porte (LLMs)¶
Definição: LLM (Large Language Model)
Modelo de linguagem que se caracteriza pelo tamanho — possibilitado por aceleradores de IA capazes de processar grandes quantidades de dados textuais (em geral, raspados da internet). São redes neurais artificiais que podem conter dezenas de milhões a bilhões de pesos, (pré-)treinadas usando aprendizagem autossupervisionada e semissupervisionada, sobre a arquitetura do transformador — que ajuda o modelo a entender as conexões entre palavras ou símbolos num texto de forma mais eficaz que arquiteturas anteriores.
Definição: Pré-processamento de dados para treinar um LLM
Antes do treino, os dados coletados (livros, artigos, páginas web, redes sociais, fóruns) passam por quatro etapas:
- Tokenização — os dados são divididos em tokens (palavras, números, símbolos ou outras sequências de caracteres).
- Limpeza — remoção de conteúdo indesejado (erros de digitação, conteúdo ofensivo, spam).
- Normalização — padronização do formato dos tokens (ex.: converter tudo para minúsculas).
- Codificação — conversão dos tokens em números (ou outros valores) que os modelos conseguem processar.
O treino em si usa aprendizado supervisionado: cada exemplo tem uma "entrada" e uma "saída" certa (ex.: uma frase em português e sua tradução em inglês) — o modelo ajusta suas configurações repetidamente para que suas respostas fiquem o mais próximas possível das respostas corretas.
Anatomia de um LLM: do texto à resposta¶
Para um computador, a palavra "gato" não é um animal — é uma sequência de bytes. O que permite a um LLM responder de forma coerente é um processo de tradução e contextualização que transforma texto em matemática, em três passos: tokenização, embeddings e a arquitetura Transformer (com seu mecanismo de self-attention).
flowchart TD
A["Texto de entrada:<br/>'O gato subiu no telhado'"] --> B["Tokenização"]
B --> C["Tokens:<br/>'O', 'gato', 'subiu', 'no', 'telhado'"]
C --> D["Embeddings"]
D --> E["Vetores numéricos"]
E --> F["Blocos Transformer<br/>(self-attention + feed forward)"]
F --> G["Saída: próximo token<br/>ou representação"]
Passo 1 — Tokenização¶
Definição: Tokenização
Processo de quebrar o texto em pedaços (tokens) que o modelo consegue
processar. Um token não é necessariamente uma palavra: pode ser um pedaço de
palavra, um caractere ou um sinal de pontuação (ex.: "Engenharia de IA" →
Eng · enharia · de · IA). Importa porque o número de tokens afeta
diretamente o custo e a velocidade do sistema: mais tokens significam mais
processamento — um prompt conciso é sempre mais eficiente que um prolixo que
diz a mesma coisa.
Na prática, a biblioteca tiktoken mostra exatamente como um modelo tokeniza um texto:
import tiktoken
codificador = tiktoken.encoding_for_model("gpt-4")
tokens_pt = codificador.encode("A Engenharia de Inteligência Artificial é fascinante.")
tokens_en = codificador.encode("Artificial Intelligence Engineering is fascinating.")
print(len(tokens_pt), len(tokens_en))
# Texto em português costuma consumir ~30% mais tokens que o equivalente em inglês
Isso tem impacto direto no custo de uma aplicação: o mesmo conteúdo em português tende a custar mais que em inglês.
Passo 2 — Embeddings¶
Definição: Embedding
Representação vetorial (uma lista de números) que captura o significado semântico de um token ou texto. Em um bom modelo de embedding, palavras ou frases com significados parecidos têm vetores próximos no espaço vetorial — "gato" e "cachorro" ficam perto um do outro, e "carro" fica distante. É a base da busca semântica usada em RAG.
from sentence_transformers import SentenceTransformer
from sklearn.metrics.pairwise import cosine_similarity
modelo = SentenceTransformer('all-MiniLM-L6-v2')
frases = [
"Carros velozes são emocionantes",
"Automóveis rápidos são empolgantes",
"Receita de bolo de chocolate",
]
embeddings = modelo.encode(frases)
similaridades = cosine_similarity(embeddings)
# frase 0 x frase 1 ≈ 0.85 (mesmo significado, palavras diferentes)
# frase 0 x frase 2 ≈ 0.15 (temas distintos)
Passo 3 — A arquitetura Transformer¶
Definição: Transformer
Arquitetura de rede neural (proposta em 2017) que resolveu dois problemas das arquiteturas anteriores (como as RNNs): o processamento lento (RNNs liam palavra por palavra, em sequência, sem aproveitar o paralelismo das GPUs) e a memória curta (em textos longos, "esqueciam" o início ao chegar ao fim). O Transformer processa todos os tokens em paralelo, e consegue relacionar palavras muito distantes na mesma frase.
Definição: Self-attention (autoatenção)
Mecanismo central do Transformer: para cada palavra, avalia todas as outras palavras da frase e decide quais são mais importantes para definir seu contexto. Na frase "O gato subiu no telhado porque estava assustado", a atenção de "gato" dá peso maior a "subiu" e "telhado", e menor a "porque". Para isso, cada palavra é transformada em três vetores:
- Query (Q) — a pergunta: "quem pode me ajudar a entender o contexto?"
- Key (K) — a etiqueta: "eu sou este tipo de palavra, com estas características"
- Value (V) — o conteúdo: "se você me escolher, esta é a informação que contribuo"
O funcionamento tem três etapas: comparação (o vetor Query da palavra é comparado com o Key de todas as outras — um produto escalar), pontuação (cada comparação gera um score) e ponderação (os scores são normalizados com softmax e usados como pesos para somar os vetores Value). O resultado é uma representação de "gato" que já carrega contexto: não é mais só "um animal felino", mas "um animal felino que subiu em algum lugar elevado".
Em fórmula (com \(d_k\) a dimensão dos vetores Key):
Definição: Por que o tamanho do contexto custa caro — O(n²)
O número de cálculos da self-attention cresce quadraticamente com o número de tokens — O(n²): dobrar o tamanho da entrada multiplica por ~4 o volume de cálculos dessa etapa. Por isso o tamanho do contexto (limite máximo de tokens que o modelo processa de uma vez, a context window) é um fator central de custo e latência. Ordens de grandeza ilustrativas:
| Contexto | Tokens | Custo relativo | Latência típica |
|---|---|---|---|
| Pergunta simples | 500 | 1x | ~200 ms |
| Documento curto | 4.000 | ~8x | ~800 ms |
| Documento longo | 32.000 | ~64x | ~3 s |
| Contexto máximo | 128.000 | ~256x | ~10 s+ |
Além disso, a saída (output) costuma custar de 3x a 5x mais que a entrada (input) por token — numa aplicação com alto volume de mensagens, a escolha do modelo e o enxugamento do system prompt podem significar milhares de dólares de diferença por mês (reduzir um system prompt de 8.000 para 2.000 tokens pode derrubar a latência de ~1,2 s para ~400 ms).
Os três sabores de Transformers¶
O Transformer original tinha duas partes: um encoder que lia a entrada e um decoder que gerava a saída. Como nem toda tarefa precisa das duas, surgiram três variações:
flowchart LR
E["Encoder-only<br/>(ex.: BERT)<br/>Entender texto"] --> E1["Uso: busca,<br/>classificação,<br/>embeddings"]
D["Decoder-only<br/>(ex.: GPT, Claude, Llama)<br/>Gerar texto"] --> D1["Uso: chatbots,<br/>geração de texto"]
ED["Encoder-Decoder<br/>(ex.: T5, BART)<br/>Transformar texto"] --> ED1["Uso: tradução,<br/>sumarização"]
| Sabor | Como funciona | Exemplos |
|---|---|---|
| Encoder-only | Só a parte que "lê": processa o texto inteiro de uma vez, olhando para todas as palavras ao mesmo tempo, e produz representações ricas de significado — não gera texto novo. | BERT, all-MiniLM-L6-v2 |
| Decoder-only | Só a parte que "escreve": gera uma palavra de cada vez, sempre olhando para o que já foi escrito, nunca "espiando" o futuro (masked attention) — como escrever uma redação da esquerda para a direita, sem poder voltar. É o que acontece quando você conversa com um chatbot. | GPT, Claude, Llama |
| Encoder-Decoder | Primeiro lê toda a entrada (encoder), depois gera a saída (decoder) — útil quando é preciso entender completamente algo antes de produzir outra coisa. | T5, BART |
Num sistema RAG típico (busca de documentos relevantes para enriquecer o contexto do modelo, detalhada mais adiante), os dois sabores trabalham juntos: um modelo Encoder-Only transforma documentos e perguntas em vetores para encontrar os mais similares, e um modelo Decoder-Only recebe esses documentos como contexto e gera a resposta final.
RAG — dando memória externa aos LLMs¶
O conhecimento de um LLM é estático (congelado no momento do treinamento) e genérico (ele não conhece os documentos internos, clientes ou processos de uma empresa). A solução mais elegante tem nome: RAG (Retrieval-Augmented Generation — geração aumentada por recuperação). A ideia: em vez de esperar que o modelo "saiba" a resposta, buscamos a informação relevante na nossa própria base de documentos e a entregamos ao modelo junto com a pergunta — como dar a um consultor um livro de consulta aberto na página certa antes de ele responder.
RAG ou fine-tuning?¶
Treinar o modelo com os documentos (fine-tuning, ver Fine-tuning em detalhe) é caro, lento, e o conhecimento fica "congelado" — um modelo treinado com os relatórios de janeiro não sabe nada sobre os de fevereiro. Com RAG, basta adicionar os novos documentos à base e o sistema os usa imediatamente.
Definição: As três vantagens do RAG
- Conhecimento sempre atualizado — atualizar uma base de documentos é infinitamente mais simples e barato que retreinar um modelo de bilhões de parâmetros; adicionar, remover ou modificar documentos reflete instantaneamente.
- Redução de alucinações — forçado a basear as respostas em trechos concretos de documentos, o modelo "inventa" muito menos: responde com base em evidências, não em suposições.
- Auditabilidade e citação de fontes — sabe-se exatamente qual documento foi usado para gerar cada resposta, o que permite verificar fatos, citar fontes e construir confiança.
RAG e fine-tuning resolvem problemas complementares: o fine-tuning ensina um novo comportamento (estilo de escrita, formato de resposta, persona); o RAG fornece novo conhecimento (dados recentes, documentos internos, informações que mudam com frequência). A maioria dos sistemas de produção usa ambos: RAG para conhecimento atualizado, fine-tuning para comportamento consistente.
A arquitetura clássica (RAG 1.0)¶
Formalizada em 2020 por pesquisadores do Facebook AI Research (Lewis et al.), a técnica funciona em duas fases: a indexação (offline, feita antes de o sistema entrar em operação) e a geração (online, executada em tempo real a cada pergunta).
flowchart LR
subgraph Offline["Offline: indexação"]
D["Documentos"] --> C["Chunking"] --> E1["Embedding"] --> VS[("Vector store")]
end
subgraph Online["Online: geração"]
P["Pergunta do usuário"] --> E2["Embedding"] --> B{"Busca de<br/>similaridade"}
B --> CR["Chunks relevantes"] --> PA["Prompt aumentado"] --> L["LLM"] --> R["Resposta final"]
P --> PA
end
VS --> B
Fase 1 — indexação (offline). Transforma documentos brutos num formato otimizado para busca semântica, em quatro etapas:
- Carregar os documentos — de fontes variadas (PDFs, páginas HTML, planilhas, transcrições); cada formato exige um tratamento específico para extrair o texto.
- Fatiar em pedaços (chunks) — um documento de 50 páginas é grande demais para ser processado de uma vez; dividi-lo em trechos autocontidos é como transformar um livro em fichas de resumo. Se os pedaços forem muito pequenos, perdem contexto; se forem muito grandes, ficam genéricos demais.
- Transformar em vetores (embeddings) — cada chunk vira uma lista de números que representa seu significado semântico (ver Anatomia de um LLM).
- Armazenar no vector store — banco de dados especializado (otimizado para encontrar rapidamente os vetores mais próximos de um vetor de consulta) que guarda os vetores e o texto original dos chunks.
Definição: Vector store (banco vetorial)
Banco de dados especializado em armazenar embeddings e encontrar rapidamente os mais próximos de um vetor de consulta. Opções: Pinecone e Weaviate (serviços em nuvem), FAISS (biblioteca do Facebook para uso local) e Chroma (leve e simples, roda localmente sem configuração e já gera os embeddings automaticamente — ideal para prototipagem).
A qualidade da indexação determina o teto do sistema: se os chunks forem mal cortados ou os embeddings forem de baixa qualidade, nenhuma técnica sofisticada de geração compensa — é o princípio do "lixo para dentro, lixo para fora".
Fase 2 — geração (online). A cada pergunta: (1) recebe a pergunta; (2) a transforma em vetor com o mesmo modelo de embedding da indexação; (3) busca no vector store os chunks cujos vetores estão mais próximos — uma busca por similaridade semântica, não por palavras-chave, então documentos que falam de "resultados do terceiro trimestre do projeto Phoenix" são encontrados mesmo sem palavras exatamente iguais; (4) monta o prompt aumentado inserindo os chunks no contexto; (5) o LLM gera a resposta baseada nas evidências fornecidas — ele não precisa "saber" a resposta de antemão.
import chromadb
from openai import OpenAI
cliente_chroma = chromadb.Client()
colecao = cliente_chroma.create_collection("documentos")
colecao.add(
documents=[
"O Projeto Phoenix teve faturamento de R$ 2M no Q3.",
"A equipe do Phoenix é composta por 12 pessoas.",
"O prazo de entrega do Phoenix é dezembro de 2024.",
],
ids=["doc1", "doc2", "doc3"],
)
pergunta = "Qual foi o faturamento do Projeto Phoenix?"
resultados = colecao.query(query_texts=[pergunta], n_results=2)
contexto = "\n".join(resultados["documents"][0])
resposta = OpenAI().chat.completions.create(
model="gpt-4o-mini",
messages=[
{"role": "system", "content": f"Responda com base no contexto:\n{contexto}"},
{"role": "user", "content": pergunta},
],
)
print(resposta.choices[0].message.content)
Chunking e re-ranking — melhorando a qualidade da busca¶
A qualidade do RAG é proporcional à qualidade dos chunks recuperados: se a busca trouxer os trechos errados, o LLM responderá com base em informação irrelevante ou incompleta. Três estratégias de chunking, em progressão de complexidade:
| Estratégia | Como funciona | Use quando | Não use quando |
|---|---|---|---|
| Tamanho fixo (fixed-size) | Corta o texto a cada N caracteres ou tokens. Rápida de implementar, mas pode cortar no meio de uma frase ou ideia. | Prototipagem rápida; documentos com estrutura repetitiva e uniforme (relatórios padronizados, logs, dados tabulares). | O texto é narrativo ou técnico, com parágrafos longos — cortes arbitrários geram chunks incoerentes. |
| Semântico (semantic chunking) | Usa modelos de linguagem para identificar onde uma ideia termina e outra começa: calcula a similaridade entre frases consecutivas e insere um corte quando ela cai abruptamente (mudança de assunto). | Documentos narrativos, técnicos ou acadêmicos, onde as ideias se desenvolvem ao longo de vários parágrafos. | A velocidade de indexação é crítica (processamento mais lento) ou o texto já tem estrutura clara (como cabeçalhos de seção). |
| Janela deslizante (sliding window) | Cria chunks com sobreposição (ex.: o 1º cobre as linhas 1-50, o 2º as linhas 40-90), de modo que nenhuma informação se perde nas "bordas" dos cortes. Custo: com 20% de sobreposição, armazena-se 20% mais chunks. | Conteúdo denso, cujas informações frequentemente cruzam fronteiras de parágrafos (contratos legais, manuais técnicos, transcrições de reuniões). | Os documentos são curtos ou claramente independentes — a sobreposição geraria redundância sem benefício. |
Um chunk bem cortado é autocontido: faz sentido sozinho, sem depender do que veio antes ou depois. Um chunk mal cortado começa com "Portanto, ele decidiu..." — quem é "ele"? Que decisão? O contexto foi perdido no corte.
Definição: Re-ranking (reordenação) — Bi-Encoder x Cross-Encoder
A busca por similaridade de vetores é rápida, mas não perfeita: às vezes os chunks retornados são apenas "parecidos" com a pergunta, mas não realmente relevantes. Isso acontece por causa de como a busca vetorial funciona — um Bi-Encoder: a pergunta vira um vetor, cada chunk vira um vetor, e os vetores são comparados. É rápido, mas o modelo nunca "vê" a pergunta e o chunk juntos. O Cross-Encoder (Reimers e Gurevych, 2019) analisa a pergunta e o chunk lado a lado, como um texto só — captura nuances que a comparação de vetores perde, mas é muito mais lento, pois precisa processar cada par individualmente. A solução prática combina os dois em dois estágios: (1) o Retriever (rápido) recupera um número maior de candidatos (ex.: os 20 mais similares) por comparação de vetores; (2) o Re-ranker (preciso, um Cross-Encoder) avalia cada candidato junto com a pergunta e atribui uma pontuação de relevância mais precisa; os top 3 ou 5 compõem o contexto final. Adiciona latência, mas o ganho de qualidade costuma compensar — a diferença entre "bom o suficiente" e "excelente".
Definição: Hybrid Search (busca híbrida)
A busca semântica é poderosa, mas tem um ponto fraco: termos técnicos e siglas. Se o usuário busca "relatório NPS Q3", a busca vetorial pode trazer documentos sobre "satisfação do cliente no terceiro trimestre" — semanticamente relacionados, mas que não mencionam "NPS" explicitamente. A busca híbrida combina busca semântica (vetores) com busca por palavras-chave usando BM25 (algoritmo clássico que pontua documentos pela frequência dos termos buscados): executa as duas buscas (top 20 de cada), combina os rankings com Reciprocal Rank Fusion (RRF) e retorna o top K combinado. Documentos que contêm "NPS" literalmente sobem no ranking, mesmo que semanticamente estivessem distantes. Pinecone, Weaviate e Qdrant oferecem hybrid search nativamente.
Agentic RAG — tornando o RAG mais inteligente¶
O RAG clássico é passivo: recebe uma pergunta, busca e responde — e se a pergunta for ambígua, ou a resposta estiver espalhada em vários documentos, ele não percebe. A partir de 2023-2024, com a popularização de frameworks como LangChain e LlamaIndex, surgiu uma evolução natural: combinar RAG com o padrão ReAct (ver Engenharia de Prompt). Em vez de um pipeline fixo, o próprio LLM decide quando buscar, o que buscar e se os resultados são suficientes — o sistema ganha um laço de raciocínio. Três capacidades distinguem o Agentic RAG (ou RAG 2.0) do clássico:
- Detecção de ambiguidade e clarificação — se o usuário pergunta "Fale sobre o projeto X", o agente percebe que a pergunta é vaga e pergunta de volta ("Você gostaria de saber sobre o cronograma, o orçamento ou a equipe?") antes de buscar, em vez de adivinhar. Troca consciente: adiciona uma interação a mais, mas a qualidade da resposta final melhora significativamente (num caso ilustrativo, a taxa de respostas úteis na primeira tentativa subiu de 65% para 89%).
- Refino iterativo — em vez de uma única busca, executa várias em sequência, usando os resultados de uma para refinar a próxima, e avalia se tem informação suficiente para responder com confiança; se não, reformula a busca e tenta novamente — respeitando um limite de iterações para evitar loops infinitos.
- Escolha inteligente de fontes — decide se a resposta está em documentos não estruturados (usa o vector store) ou em um banco de dados estruturado (gera uma query SQL), em vez de forçar tudo pelo mesmo caminho.
flowchart TD
U["Pergunta do usuário"] --> A{"Pergunta é<br/>ambígua?"}
A -->|Sim| Q["Fazer pergunta<br/>de clarificação"]
Q --> U
A -->|Não| R["Executar RAG"] --> RESP["Resposta"]
Avaliação de sistemas RAG¶
Não basta "parecer" que as respostas estão corretas: são necessárias métricas objetivas que avaliem tanto a qualidade da busca quanto a da geração. Quatro métricas, em duas dimensões:
| Dimensão | Métrica | O que mede | Como melhorar quando baixa |
|---|---|---|---|
| Busca | Precisão do contexto (context precision) | Dos chunks recuperados, quantos são realmente relevantes? (5 recuperados, 2 úteis = baixa precisão — polui o contexto, desperdiça tokens e pode confundir o LLM.) | Ajustar o número de chunks retornados (k); usar re-ranking. |
| Busca | Cobertura do contexto (context recall) | Dos chunks relevantes que existem na base, quantos foram recuperados? (havia 4 importantes, recuperou 1 = resposta incompleta.) | Estratégias de chunking diferentes; aumentar o número de candidatos; hybrid search. |
| Geração | Fidelidade (faithfulness) | A resposta está estritamente baseada no contexto fornecido, ou o modelo "inventou" informação? Mede diretamente a alucinação — o problema mais perigoso em RAG de produção. | Instruir claramente no prompt a responder apenas com base no contexto ("se a informação não estiver no contexto, diga que não sabe"). |
| Geração | Relevância da resposta (answer relevance) | A resposta final é útil e responde de fato à pergunta do usuário? (Pode ser fiel ao contexto e ainda assim responder sobre o projeto errado.) | Verificar se os chunks são sobre o assunto da pergunta; orientar o prompt a focar na pergunta original. |
Exemplo de diagnóstico: o usuário pergunta "Qual foi o faturamento do Projeto Phoenix no Q3?" e o sistema responde "R$ 2M no Q3, superando a meta de R$ 1,5M". Foram recuperados 5 chunks (2 sobre Phoenix/Q3, 2 sobre Phoenix/Q2, 1 de outro projeto) — precisão = 2/5 = 40% (baixa); existem 3 relevantes na base e 2 foram recuperados — cobertura = 2/3 = 67%; o faturamento (R$ 2M) está nos chunks, mas a meta de R$ 1,5M não — o modelo inventou: fidelidade = 50% (crítica, há alucinação); a resposta fala de faturamento do Phoenix no Q3, exatamente o perguntado — relevância = 100%. A ação imediata: ajustar o prompt para proibir a invenção de dados e reduzir o número de chunks ou aplicar re-ranking mais agressivo.
Essas métricas são frequentemente calculadas usando outro LLM como "juiz" (LLM-as-a-Judge, ver Engenharia de Prompt), o que permite avaliar centenas ou milhares de casos automaticamente e identificar padrões de falha. Dominar chunking, re-ranking e avaliação é o que separa um protótipo frágil de um sistema confiável e bem testado.
Modelos de linguagem populares¶
| Modelo | Criador | Característica principal |
|---|---|---|
| BERT (Bidirectional Encoder Representations from Transformers) | Google AI, 2018 | Treinamento bidirecional — entende o contexto de uma palavra a partir das palavras antes e depois dela na frase. Bom para análise de sentimento, tradução e preenchimento de lacunas. |
| GPT (Generative Pre-trained Transformer) | OpenAI, 2020+ | Prevê o próximo token com base só nos tokens anteriores. Conhecido pela capacidade de gerar texto coerente e relevante. |
| RoBERTa (Robustly Optimized BERT Pretraining Approach) | Meta | Variante do BERT com processo de treinamento otimizado e mais dados — melhor desempenho em tarefas de PLN. |
| T5 (Text-to-Text Transfer Transformer) | Google AI | Aborda toda tarefa de PLN como um problema de "texto para texto", numa abordagem unificada. |
| XLNet (Generalized Autoregressive Pretraining) | — | Combina treinamento autorregressivo e bidirecional, capturando contexto de forma mais eficiente que o BERT original. |
Adaptação e personalização de modelos de linguagem¶
Definição: Estratégias para adaptar um modelo de linguagem
- Fine-tuning (ajuste fino) — método mais comum: treina um modelo pré-treinado com um conjunto de dados relacionado a uma tarefa/domínio específico, permitindo que ele aprenda as nuances daquele contexto.
- Transferência de aprendizado — adapta um modelo treinado numa tarefa para outra relacionada, compartilhando conhecimento entre as duas — útil quando há poucos dados rotulados para a tarefa-alvo.
- Modelos específicos de domínio — treinados do zero quando a aplicação exige um vocabulário ou estrutura de conhecimento muito específicos, que modelos genéricos não conseguem incorporar facilmente. Mais precisos e eficientes, mas exigem mais recursos e tempo de treinamento.
- Ajuste de hiperparâmetros — parâmetros como taxa de aprendizado, tamanho do lote e número de camadas podem ser ajustados para melhorar o desempenho numa aplicação específica.
- Incorporação de conhecimento externo — integrar ontologias, bases de conhecimento ou recursos lexicais ao modelo, melhorando a precisão e a capacidade de lidar com informações específicas de domínio.
Definição: Personalizar um modelo é um empreendimento caro
Adaptar ou personalizar um modelo de linguagem para necessidades específicas exige alto investimento de tempo e dinheiro — por isso, a maioria das aplicações de IA para desenvolvedores prefere usar um modelo já pronto (via API ou ferramenta) combinado com boas técnicas de engenharia de prompt (ver Engenharia de Prompt), em vez de treinar ou ajustar seu próprio modelo do zero.
Fine-tuning em detalhe: quando fazer, tipos, LoRA, dados e riscos¶
Pense num médico generalista brilhante: sabe um pouco de tudo. Para a clínica de atletas, há duas opções — dar a ele livros e manuais sobre medicina esportiva (isso é RAG) ou mandá-lo fazer uma residência de dois anos na área (isso é fine-tuning). O RAG dá conhecimento (a informação que o modelo consulta quando precisa); o fine-tuning ensina comportamentos e habilidades e muda a forma como o modelo pensa e responde — depois da residência, o médico não apenas sabe mais, ele pensa como um especialista.
Quando fazer fine-tuning? A decisão mais importante¶
O fine-tuning é poderoso, mas caro, demorado e introduz riscos: não deve ser a primeira opção — deve ser a última, quando tudo mais falhou. A decisão segue uma árvore simples:
flowchart TD
P["Problema de IA"] --> Q1{"Precisa de conhecimento<br/>específico/recente?"}
Q1 -->|Sim| RAG["Use RAG"]
Q1 -->|Não| Q2{"Precisa de um comportamento/<br/>estilo muito específico?"}
Q2 -->|Não| PE["Use Prompt Engineering"]
Q2 -->|Sim| FT["Use Fine-Tuning"]
- Comece sempre com Engenharia de Prompt — é a forma mais rápida e barata de melhorar resultados; se ainda não tentou few-shot ou chain-of-thought (ver Engenharia de Prompt), volte a eles antes.
- Se o problema é que o modelo não tem conhecimento específico (dados recentes, documentos internos, informações proprietárias), a solução é RAG — fine-tuning não serve para ensinar fatos, e sim comportamentos.
- Se, mesmo com prompts excelentes e RAG, o modelo não se comporta como você precisa (não segue um formato complexo, não usa o jargão correto, não adota o tom adequado), aí é hora de considerar fine-tuning.
Na prática: RAG dá conhecimento, agentes dão ferramentas, e fine-tuning dá comportamento — os três se complementam. Muitas equipes pulam direto para o fine-tuning quando a Engenharia de Prompt resolveria: o resultado são semanas coletando dados e treinando modelos para algo que um prompt de 10 linhas poderia ter feito.
Tipos de fine-tuning¶
Duas grandes categorias, conforme como se define a "resposta correta": se há uma resposta ideal clara para cada pergunta, o caminho é o treinamento supervisionado; se a qualidade é mais subjetiva (uma resposta é "melhor" que outra, mas nenhuma é perfeita), o caminho é o treinamento por preferência.
Definição: SFT (Supervised Fine-Tuning) — \"faça assim\"
Mostra-se ao modelo exatamente o que ele deve fazer: cria-se um dataset com centenas ou milhares de pares de prompt e resposta ideal, e treina-se o modelo para imitá-las — como um professor que corrige provas: com muitas repetições, o aluno aprende o padrão. Ganhou protagonismo em 2022, com o artigo do InstructGPT (OpenAI): modelos treinados só para "prever a próxima palavra" eram bons em completar texto, mas péssimos em seguir instruções — a solução foi coletar milhares de exemplos de humanos respondendo a prompts da forma desejada. É o tipo mais intuitivo; use quando o modelo precisa sempre responder num formato específico (ex.: JSON com campos fixos), com um tom consistente, ou gerar código numa linguagem proprietária. O dataset costuma ser um arquivo JSONL (JSON Lines — cada linha é um JSON independente) com a conversa completa do comportamento desejado.
{"messages": [
{"role": "system", "content": "Você é um atendente formal de banco."},
{"role": "user", "content": "Quero saber meu saldo"},
{"role": "assistant", "content": "Prezado cliente, seu saldo atual é de R$ 1.234,56. Posso ajudá-lo com mais alguma informação?"}
]}
Definição: Preference Tuning — RLHF e DPO (\"qual você prefere?\")
Em vez de mostrar a resposta correta, mostram-se duas respostas e diz-se qual é
a preferível ("dada essa pergunta, a resposta A é melhor que a B"). Com milhares
desses pares, o modelo aprende a gerar respostas alinhadas ao que se considera
"bom" (mais seguras, mais úteis, de melhor tom). A abordagem clássica é o RLHF
(Reinforcement Learning from Human Feedback — aprendizado por reforço com
feedback humano): humanos avaliam respostas, um modelo de reward (recompensa)
aprende essas preferências e o LLM é otimizado para maximizar essa recompensa —
funciona, mas é complexo e caro. Uma alternativa mais moderna e simples é o DPO
(Direct Preference Optimization): otimiza o LLM diretamente usando os pares de
preferência, sem treinar um modelo de reward separado — menos peças móveis, mais
estabilidade e, frequentemente, melhores resultados. O dataset do DPO traz, em vez
de uma resposta ideal, uma resposta escolhida (chosen) e uma rejeitada
(rejected) — a escolhida não precisa ser perfeita, só melhor que a rejeitada,
segundo os critérios definidos.
| Técnica | O que ensina | Dados necessários | Complexidade | Quando usar |
|---|---|---|---|---|
| SFT | Formato, estilo, tarefas específicas | Pares prompt → resposta ideal | Baixa | Formato JSON, tom específico, jargão |
| RLHF | Alinhamento com preferências humanas | Comparações + modelo de reward | Alta | Segurança, helpfulness (utilidade) geral |
| DPO | Mesmo objetivo do RLHF, mais simples | Pares escolhido/rejeitado | Média | Alternativa moderna ao RLHF |
Na prática, comece com SFT se precisa de formato ou estilo específico; use DPO se quer refinar qualidade subjetiva (tom, segurança) sem a complexidade do RLHF.
LoRA e QLoRA — fine-tuning acessível¶
Fine-tuning de um modelo com bilhões de parâmetros é computacionalmente brutal: atualizar todos os pesos exige múltiplas GPUs caras e dias de treinamento.
Definição: LoRA (Low-Rank Adaptation) e PEFT
Técnica (Hu et al., Microsoft, 2021) baseada na intuição de que as mudanças necessárias para adaptar um modelo a uma nova tarefa ocupam um "espaço" muito menor que o modelo inteiro — e podem ser representadas de forma compacta, via decomposição de baixo rank (álgebra linear: matrizes grandes aproximadas pelo produto de duas matrizes menores). Em vez de mudar os bilhões de pesos originais, congelam-se esses pesos e adicionam-se "extensões" — pequenas matrizes adaptadoras — treinando apenas essas. É parte de uma família de técnicas chamada PEFT (Parameter-Efficient Fine-Tuning). O resultado: em vez de treinar bilhões de parâmetros, treinam-se apenas milhões; o consumo de memória despenca, o tempo cai de dias para horas, e dá para fazer fine-tuning numa única GPU.
Definição: QLoRA (Quantized LoRA)
Combina o LoRA com a quantização (redução da precisão numérica do modelo base — ex.: 4 bits em vez de 16), liberando ainda mais memória para as matrizes adaptadoras, com perda de qualidade pequena (Dettmers et al., Univ. de Washington, 2023). Na prática: um modelo de 7 bilhões de parâmetros exige, com LoRA padrão, uma GPU com pelo menos 16 GB; com QLoRA, cabe numa GPU de 6 GB (tipo laptop gamer); e um modelo de 70 bilhões, que exigiria várias GPUs profissionais com LoRA, passa a caber numa única GPU de consumo. Use QLoRA quando o orçamento de hardware é limitado ou o modelo é grande demais para caber na memória; a qualidade é ligeiramente inferior ao LoRA padrão em alguns casos, mas a diferença raramente justifica o custo adicional.
Configurar LoRA com a biblioteca peft envolve três parâmetros: o rank r
(tamanho das matrizes adaptadoras — valores maiores capturam mais informação, mas usam
mais memória), o lora_alpha (escala da intensidade da adaptação) e os
target_modules (quais camadas do modelo recebem as matrizes adaptadoras):
from peft import LoraConfig, get_peft_model
from transformers import AutoModelForCausalLM
modelo = AutoModelForCausalLM.from_pretrained("meta-llama/Llama-2-7b-hf")
config_lora = LoraConfig(
r=16, lora_alpha=32,
target_modules=["q_proj", "v_proj"],
lora_dropout=0.05, task_type="CAUSAL_LM",
)
modelo_lora = get_peft_model(modelo, config_lora)
modelo_lora.print_trainable_parameters()
# trainable params: ~4M || all params: ~7B || trainable%: ~0.05%
Com apenas ~0,05% dos parâmetros treináveis, obtêm-se resultados comparáveis ao fine-tuning completo, com uma fração do custo. Um adaptador LoRA ocupa poucos megabytes e pode ser carregado e trocado dinamicamente em servidores de inferência (como o vLLM), permitindo servir múltiplas especializações do mesmo modelo base multiplicando o consumo de memória. Antes do LoRA, fine-tuning era privilégio de empresas com orçamentos milionários; hoje, um desenvolvedor com um laptop gamer pode especializar um modelo de linguagem.
Dados para fine-tuning¶
Mesmo com a melhor técnica, se os dados forem inadequados, o modelo treinado será ruim. A qualidade do dataset é o fator mais crítico, e três princípios guiam a curadoria:
- Qualidade sobre quantidade — para SFT, cada resposta deve ser impecável, sem erros de gramática, sem inconsistências, no formato exato desejado (se metade das respostas usa markdown e metade não, o modelo vai reproduzir a inconsistência). Para DPO, a resposta "escolhida" deve ser genuinamente melhor que a "rejeitada", com critérios iguais em todo o dataset. Mil exemplos perfeitos são melhores que dez mil mediocres.
- Diversidade — o dataset deve cobrir todos os cenários e casos de borda que o modelo vai encontrar em produção. Uma armadilha: se 80% dos exemplos seguem o mesmo padrão, o modelo aprende esse padrão e ignora os outros 20% (ex.: treinar com quase só consultas de saldo faz o modelo não saber responder sobre empréstimos).
- Consistência — os mesmos padrões e formatos em todo o dataset: um guia de estilo
para os dados (ex.: sempre "Prezado cliente", nunca alternar com "Olá") e a mesma
estrutura (se um campo JSON se chama
data_nascimentonum exemplo edataNascimentoem outro, o modelo reproduz a inconsistência). Valide os dados programaticamente antes de treinar.
Riscos do fine-tuning¶
Definição: Overfitting (sobreajuste) — especialização excessiva
Ocorre quando o modelo se especializa demais no dataset de treino e perde a capacidade de generalizar (ex.: treinar só com exemplos de um único domínio pode torná-lo inútil para qualquer outra coisa). Detecção: comparar o desempenho nos dados de treino com o desempenho em dados novos (dados de validação) — se o modelo acerta quase tudo no treino mas erra muito nos dados novos, está sobreajustado. Mitigação: aumentar a diversidade do dataset, usar dropout (desativação aleatória de neurônios durante o treino) e parar o treinamento mais cedo.
Definição: Catastrophic forgetting (esquecimento catastrófico)
Ao otimizar para uma tarefa específica, o modelo pode "esquecer" habilidades que tinha antes — um modelo excelente em raciocínio matemático pode perder essa habilidade após um fine-tuning focado em outro domínio. Mitigação: incluir de 10% a 20% de exemplos de tarefas gerais no dataset de fine-tuning, o que lembra o modelo de que precisa manter suas habilidades anteriores; e monitorar benchmarks amplos (conjuntos de testes padronizados) durante o treinamento — se o desempenho em raciocínio geral cai, parar e ajustar o dataset.
Definição: Alignment tax (custo do alinhamento)
O risco de piorar características importantes, como segurança ou honestidade, ao otimizar para outra métrica. Um modelo pode se tornar mais persuasivo, mas também mais disposto a gerar conteúdo problemático, porque o treinamento recompensou "respostas convincentes" sem penalizar respostas inseguras. Mitigação: avaliar o modelo não apenas na tarefa-alvo, mas também em critérios de segurança e alinhamento — se o modelo ficou melhor em gerar relatórios mas pior em recusar pedidos perigosos, o fine-tuning criou um problema maior do que resolveu.
O fine-tuning é uma ferramenta poderosa para moldar o comportamento de LLMs, mas deve ser tratado como recurso de último caso, quando Engenharia de Prompt e RAG não são suficientes. Com dados de alta qualidade e avaliação rigorosa, gera modelos altamente especializados; combinado com agentes (ver Agentes e Agentic AI), o resultado é ainda mais poderoso — um agente cujo "cérebro" foi treinado para pensar como um especialista do domínio.
Modelos de Linguagem de Código (Code Language Models)¶
Definição: Modelo de Linguagem de Código
Especialização dos LLMs, treinada com concentração em datasets de código-fonte (em vez de texto genérico) — o que permite uma abordagem mais focada e eficaz no trato com linguagens de programação, padrões de codificação e estruturas de dados. Embora baseados na mesma arquitetura Transformer dos LLMs gerais, são afinados especificamente para captar as nuances e a complexidade das linguagens de programação, operando em conjunto com IDEs e outras ferramentas de desenvolvimento.
| Ferramenta | Característica |
|---|---|
| GitHub Copilot | Desenvolvido em colaboração entre GitHub e OpenAI; sugestões de código em tempo real, compatível com diversas IDEs. |
| OpenAI Codex | Também da OpenAI; eficaz em Python, mas suporta múltiplas linguagens; treinado em bilhões de linhas de código. |
| Code Intelligence | Une testes dinâmicos com autoaprendizagem para encontrar bugs e vulnerabilidades (Java, C/C++, Golang, JavaScript). |
| ChatGPT | Primariamente um chatbot, mas também oferece funcionalidades de geração de código. |
| Visual Studio IntelliCode | Plugin da Microsoft para o Visual Studio Code, com sugestões de código baseadas em contexto. |
| Tabnine | Lançado em 2013, usa aprendizado profundo para prever a intenção de codificação. |
| CodeT5 | Solução de código aberto para geração rápida de código em várias linguagens. |
| DeepCode (Snyk) | Foco em análise de segurança de código. |
GitHub Copilot na prática¶
Definição: Modos de uso do GitHub Copilot
Integrado a IDEs (como o Visual Studio Code) via extensão, oferece sugestões
baseadas no modelo GPT-4 de duas formas: autocomplete inline — ao digitar o
início de uma função (ex.: function removeTodo), sugere o corpo completo com
base no nome e no contexto do arquivo — e chat integrado — permite pedir
mudanças diretamente em linguagem natural (ex.: "estilize o HTML com
Bootstrap"), usando toda a pasta do projeto aberta no editor como contexto
implícito, o que permite alterações que afetam o projeto inteiro numa única
instrução.
Definição: Sugestões do Copilot exigem revisão — não são infalíveis
O código gerado nunca é idêntico entre duas execuções (não é determinístico), o Copilot não referencia sozinho arquivos além do que já está aberto no editor (quem programa precisa nomear/criar os arquivos), e as sugestões podem conter erros — inclusive erros de lógica que passam despercebidos até serem testados. Cabe a quem desenvolve revisar e corrigir manualmente antes de aceitar uma sugestão, do mesmo jeito que revisaria o código de qualquer colega.
Definição: GitHub Copilot X (evolução do produto)
Amplia o Copilot para todas as etapas do desenvolvimento de software, não só a geração de código: oferece explicações de código, ajuda na detecção e correção de vulnerabilidades de segurança, e permite interação direta com o código via comandos em chat. A versão Enterprise (lançada em 2024) personaliza sugestões com base em código interno da organização. O Copilot também atua na prevenção de vulnerabilidades, bloqueando padrões de codificação inseguros em tempo real, e um Partner Program expande seu ecossistema integrando ferramentas e serviços de terceiros.