Saltar para o conteúdo
Fine-tuning de LLMs: Quando Vale a Pena (e Quando Não Vale)
IA

Fine-tuning de LLMs: Quando Vale a Pena (e Quando Não Vale)

30 de outubro de 2024·Paulo de Paula

Fine-tuning virou a resposta padrão para “o modelo não está fazendo o que quero”. Problema: na maioria dos casos, não é a solução certa, e o custo (tempo, dados, dinheiro) não se justifica.

O fluxo de decisão correto

Problema com o modelo
        ↓
Melhorei o prompt? ────── Não → Melhore o prompt primeiro
        ↓ Sim
RAG resolve? ──────────── Sim → Use RAG (muito mais simples)
        ↓ Não
O problema é de FORMATO  ─ Sim → Fine-tuning pode ajudar
ou ESTILO de resposta?
        ↓ Não
O problema é de          ─ Sim → Fine-tuning provavelmente não
CONHECIMENTO?                    resolve — use RAG ou modelo maior

Quando fine-tuning resolve

1. Formato de saída consistente

# Você quer SEMPRE isso:
# {
#   "action": "...",
#   "confidence": 0.95,
#   "reasoning": "..."
# }
#
# Mas o modelo às vezes retorna JSON com campos extras,
# às vezes markdown, às vezes texto livre.
# Fine-tuning treina o modelo a seguir o formato
# de forma mais confiável que instruções no prompt.

2. Tom e estilo de marca

Se você precisa que o modelo responda sempre com a voz da sua empresa — tom específico, vocabulário proprietário, sem desvios — fine-tuning é mais eficiente que prompt gigante.

3. Redução de custo com modelos menores

# Cenário: você usa GPT-4 com um prompt de 2000 tokens
# para classificar emails em 5 categorias.
#
# Com fine-tuning em GPT-3.5-turbo (ou Llama 3.1 8B):
# - Modelo menor = custo ~10x menor
# - Prompt menor = sem instrução detalhada de classificação
# - Latência menor
#
# Esse é o caso de uso mais forte para fine-tuning.

Quando fine-tuning NÃO resolve

Injetar conhecimento novo

# ❌ Expectativa comum:
# "Vou fazer fine-tuning com minha documentação interna
#  para o modelo 'saber' sobre o meu produto."
#
# ❌ O que realmente acontece:
# - O modelo pode memorizar alguns fatos
# - Mas hallucina com confiança em perguntas não vistas no treino
# - RAG é muito mais confiável para esse caso

Por que RAG é melhor para conhecimento:

from langchain.vectorstores import Chroma
from langchain.embeddings import OpenAIEmbeddings

# Indexa sua documentação
vectorstore = Chroma.from_documents(
    documents=docs,
    embedding=OpenAIEmbeddings()
)

# Na query: busca os trechos relevantes e inclui no contexto
def answer_question(question: str) -> str:
    relevant_docs = vectorstore.similarity_search(question, k=4)
    context = "\n\n".join([d.page_content for d in relevant_docs])
    
    # O modelo tem o CONTEXTO EXATO — não precisa "memorizar"
    return llm.invoke(f"Contexto:\n{context}\n\nPergunta: {question}")

Comportamento errado com pouco dado

# Fine-tuning com < 100 exemplos raramente funciona bem.
# O modelo "decora" os exemplos ao invés de generalizar.
# Recomendado: 500-1000+ exemplos para casos simples,
# mais para tarefas complexas.

Preparando dados de fine-tuning (OpenAI)

# Formato JSONL para GPT-3.5-turbo / GPT-4o-mini
import json

training_data = [
    {
        "messages": [
            {
                "role": "system",
                "content": "Você classifica emails de suporte em: billing, technical, general, urgent."
            },
            {
                "role": "user",
                "content": "Meu cartão foi cobrado duas vezes esse mês."
            },
            {
                "role": "assistant",
                "content": '{"category": "billing", "priority": "high"}'
            }
        ]
    },
    # ... mais exemplos
]

# Salva como JSONL
with open('training.jsonl', 'w') as f:
    for example in training_data:
        f.write(json.dumps(example) + '\n')

# Valida o arquivo
# openai tools fine_tunes.prepare_data -f training.jsonl

Iniciando o fine-tuning

from openai import OpenAI

client = OpenAI()

# Upload do dataset
file = client.files.create(
    file=open("training.jsonl", "rb"),
    purpose="fine-tune"
)

# Cria o job
job = client.fine_tuning.jobs.create(
    training_file=file.id,
    model="gpt-4o-mini-2024-07-18",  # mais barato para fine-tuning
    hyperparameters={
        "n_epochs": 3,                # padrão; aumente se underfitting
    }
)

print(f"Job criado: {job.id}")

# Monitora
events = client.fine_tuning.jobs.list_events(fine_tuning_job_id=job.id)
for event in events:
    print(event.message)

Avaliando o resultado

# Sempre compare com o modelo base no seu conjunto de teste
import json

test_cases = [...]  # dados que o modelo NÃO viu no treino

def evaluate(model_id: str, test_cases: list) -> float:
    correct = 0
    for case in test_cases:
        response = client.chat.completions.create(
            model=model_id,
            messages=case['messages'][:-1]  # sem a resposta esperada
        )
        predicted = json.loads(response.choices[0].message.content)
        expected = json.loads(case['messages'][-1]['content'])
        
        if predicted['category'] == expected['category']:
            correct += 1
    
    return correct / len(test_cases)

base_accuracy = evaluate("gpt-4o-mini", test_cases)
finetuned_accuracy = evaluate(job.fine_tuned_model, test_cases)

print(f"Base: {base_accuracy:.1%} → Fine-tuned: {finetuned_accuracy:.1%}")

A regra prática

Tente na ordem:

  1. Melhor prompt (zero custo)
  2. Few-shot no prompt (adicionar exemplos)
  3. RAG (para conhecimento específico)
  4. Fine-tuning (para formato/estilo consistente ou custo/latência)
  5. Modelo maior (se nada mais funcionar)

Fine-tuning é caro para criar, caro para manter e frágil com atualizações de modelo. Use quando os benefícios concretos — latência, custo, consistência — justificam o investimento.