O que mudou em 2026: dados de raciocínio agora são acessíveis a qualquer um
Até pouco tempo, treinar um modelo com capacidade de raciocínio explícito — aquele que “pensa” passo a passo antes de responder — era território exclusivo de grandes laboratórios com clusters caros e datasets proprietários. O cenário mudou: hoje existem corpora públicos massivos de raciocínio, como o SupraLabs Reasoning Corpus, e técnicas de ajuste eficiente como LoRA que cabem em uma GPU gratuita do Google Colab.
Neste tutorial, você vai acompanhar um pipeline completo e reproduzível: transmitir (streaming) um subconjunto do corpus direto do Hugging Face Hub, analisar sua composição, aplicar filtros de qualidade, converter os dados para o formato de chat com tags <think> e ajustar o modelo SmolLM2-135M-Instruct usando o SFTTrainer da biblioteca TRL. Ao final, você terá um modelo compacto focado em raciocínio — e um conjunto de dados curado exportado em Parquet para reutilização.
✅ O que você ganha
- Acesso escalável a dados: o streaming do Hugging Face evita baixar o corpus inteiro para a memória do Colab — você materializa apenas 8.000 exemplos representativos.
- Curadoria orientada por dados: você aprende a medir razão de raciocínio, repetição e completude antes de treinar, em vez de aceitar qualquer exemplo.
- Fine-tuning barato: LoRA com
r=16ajusta poucos milhões de parâmetros, viabilizando o treino em uma GPU T4 gratuita em ~10–20 minutos. - Pipeline reutilizável: o código serve de base para mistura de fontes, curriculum learning e modelos maiores.
- Dataset exportável: ao final, você tem os subconjuntos de treino e avaliação em Parquet, prontos para experimentos futuros.
⚠️ O que você NÃO ganha
- Um modelo no nível dos grandes laboratórios: o SmolLM2-135M é um modelo pequeno, para aprendizado e prototipagem — não compete com modelos de fronteira.
- Raciocínio “puro” garantido: o filtro de razão de raciocínio (0,15–0,97) é heurístico; exemplos passam sem verificação humana.
- Escala de produção: 1.500 exemplos de treino e 1 época são suficientes para demonstrar a técnica, não para um produto final.
| Componente | Mínimo | Recomendado | Ideal |
|---|---|---|---|
| GPU | CPU (lento) | NVIDIA T4 (Colab free) | GPU com 16 GB+ VRAM |
| Memória RAM | 8 GB | 12 GB | 16 GB+ |
| Armazenamento | 5 GB livres | 10 GB | 20 GB (datasets maiores) |
| Python | 3.9+ | 3.10 | 3.11 |
| Conhecimento prévio | Python básico | Noções de PyTorch | Experiência com Hugging Face/TRL |
| Tempo estimado | ~30 min | ~45 min | ~1h (com análise) |
Passo 1 — Preparar o ambiente no Google Colab
O primeiro bloco instala as bibliotecas de machine learning e remove o pacote torchao, que é incompatível com a versão atual do PEFT. Em seguida, detecta o dispositivo de computação disponível e conecta-se ao corpus via streaming do Hugging Face.
import subprocess, sys
def pip_install(pkgs):
subprocess.check_call([sys.executable, "-m", "pip", "install", "-q", *pkgs])
subprocess.call([sys.executable, "-m", "pip", "uninstall", "-y", "-q", "torchao"])
pip_install(["datasets>=3.0.0", "transformers>=4.46.0", "trl>=0.12.0",
"peft>=0.13.0", "accelerate>=1.0.0", "bitsandbytes",
"matplotlib", "pandas"])
DATASET_ID = "SupraLabs/reasoning-corpus-4K-5M-v1"
SAMPLE_SIZE = 8_000
stream = load_dataset(DATASET_ID, split="train", streaming=True)
stream = stream.shuffle(seed=42, buffer_size=30_000)
rows = list(itertools.islice(stream, SAMPLE_SIZE))
ds = Dataset.from_list(rows)O ponto-chave aqui é o streaming: em vez de baixar o corpus inteiro (que é grande), você embaralha um buffer e “fatia” os 8.000 primeiros registros. Cada exemplo tem os campos repo_id (repositório de origem), tok_len (comprimento em tokens), user (a pergunta), thought_trace (a cadeia de raciocínio) e assistant (a resposta final).
Passo 2 — Análise exploratória dos dados
Antes de treinar, vale entender o que há dentro do corpus. O segundo bloco converte a amostra em DataFrame do pandas e calcula distribuições de repositórios de origem, comprimento de tokens e a razão de raciocínio — a proporção entre o “pensamento” e a resposta final.
df = ds.to_pandas()
df["think_chars"] = df["thought_trace"].str.len()
df["answer_chars"] = df["assistant"].str.len()
df["reason_ratio"] = df["think_chars"] / (df["think_chars"] + df["answer_chars"] + 1)
df["reason_ratio"].hist(bins=50) # visualiza a distribuiçãoO código também classifica cada exemplo por tarefa usando heurísticas de texto: se a resposta contém def, class ou import, é código; se a pergunta traz termos como prove, integral ou theorem, é matemática; se fala de diagnosis ou treatment, é médica; e assim por diante. Essa visão por tarefa ajuda a decidir se o seu subconjunto está balanceado.
Passo 3 — Filtros de qualidade
Nem todo exemplo do corpus é bom para treino. O pipeline aplica quatro filtros em sequência:
def filter_length(row, min_tok=200, max_tok=3000):
return min_tok <= row["tok_len"] <= max_tok
def filter_degenerate(row):
return len(row["thought_trace"]) > 100 and len(row["assistant"]) > 20
def filter_repetition(row, max_line_repeat=0.30):
lines = [l.strip() for l in row["thought_trace"].split("\n") if l.strip()]
if len(lines) < 5:
return True
most_common = Counter(lines).most_common(1)[0][1]
return (most_common / len(lines)) <= max_line_repeat
def filter_reason_ratio(row, lo=0.15, hi=0.97):
t, a = len(row["thought_trace"]), len(row["assistant"])
r = t / (t + a + 1)
return lo <= r <= hi
ds_f = ds.filter(filter_length).filter(filter_degenerate)
ds_f = ds_f.filter(filter_repetition).filter(filter_reason_ratio)Cada filtro tem um propósito claro: comprimento mantém exemplos dentro de um orçamento de tokens amigável ao treino; degeneração descarta pensamentos ou respostas vazios; repetição elimina rastros de modelos “em loop” que repetem a mesma linha; e razão de raciocínio garante que o exemplo realmente raciocina — sem ser só raciocínio, sem resposta.
Passo 4 — Converter para formato de chat com tags <think>
O próximo passo transforma cada exemplo em uma conversa estruturada: uma instrução de sistema, a pergunta do usuário e a resposta do assistente com o raciocínio entre tags <think>.
SYSTEM_PROMPT = ("You are a careful reasoning assistant. Think step by step "
"inside <think>...</think> tags, then give your final answer.")
def to_chat(row):
return {"messages": [
{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": row["user"]},
{"role": "assistant", "content": f"<think>\n{row['thought_trace']}\n</think>\n\n{row['assistant']}"},
]}
train_ds = ds_f.map(to_chat, remove_columns=ds_f.column_names)
train_ds = train_ds.shuffle(seed=42)
N_TRAIN, N_EVAL = 1_500, 100
eval_ds = train_ds.select(range(N_TRAIN, min(N_TRAIN + N_EVAL, len(train_ds))))
train_ds = train_ds.select(range(min(N_TRAIN, len(train_ds))))As tags <think> são a convenção que ensina o modelo a separar o raciocínio interno da resposta final — o mesmo padrão usado por modelos como DeepSeek-R1. Ao dividir 1.500 exemplos para treino e 100 para avaliação, você consegue medir a perda de validação durante o ajuste.
Passo 5 — Fine-tuning com LoRA via SFTTrainer
Agora vem o treino. O modelo base é o SmolLM2-135M-Instruct, carregado em bfloat16 quando há GPU. A configuração LoRA com r=16 e alpha=32 adiciona apenas um pequeno conjunto de parâmetros treináveis.
from trl import SFTTrainer, SFTConfig
from peft import LoraConfig
model = AutoModelForCausalLM.from_pretrained(
MODEL_ID, dtype=torch.bfloat16 if DEVICE == "cuda" else torch.float32).to(DEVICE)
peft_config = LoraConfig(r=16, lora_alpha=32, lora_dropout=0.05,
bias="none", task_type="CAUSAL_LM")
sft_config = SFTConfig(
output_dir="smollm2-reasoning-demo", max_length=2048,
per_device_train_batch_size=2, gradient_accumulation_steps=8,
num_train_epochs=1, learning_rate=2e-4, lr_scheduler_type="cosine",
warmup_steps=10, eval_strategy="steps", eval_steps=50,
save_strategy="no", bf16=(DEVICE == "cuda"), gradient_checkpointing=True,
report_to="none")
trainer = SFTTrainer(model=model, args=sft_config, train_dataset=train_ds,
eval_dataset=eval_ds, peft_config=peft_config,
processing_class=tokenizer)
trainer.train() # ≈10–20 min em uma T4O artigo usa 1 época com learning rate de 2e-4 e gradient checkpointing para economizar VRAM. O detalhe do torchao é importante: há um workaround que desativa a detecção automática do torchao no PEFT para evitar conflito de dependências — por isso o pacote foi removido no Passo 1.
Passo 6 — Inferência estruturada e exportação
O bloco final define a função de geração, testa o modelo com um problema de lógica e exporta os datasets curados.
def generate(question, max_new_tokens=512, temperature=0.7):
msgs = [{"role": "system", "content": SYSTEM_PROMPT},
{"role": "user", "content": question}]
prompt = tokenizer.apply_chat_template(msgs, tokenize=False, add_generation_prompt=True)
inputs = tokenizer(prompt, return_tensors="pt").to(DEVICE)
with torch.no_grad():
out = trainer.model.generate(**inputs, max_new_tokens=max_new_tokens,
temperature=temperature, top_p=0.9, do_sample=True,
pad_token_id=tokenizer.pad_token_id)
# separa da resposta final via regex
...
generate("If all bloops are razzies and all razzies are lazzies, "
"are all bloops definitely lazzies? Explain briefly.")
train_ds.to_parquet("reasoning_subset_train.parquet")
eval_ds.to_parquet("reasoning_subset_eval.parquet") A função de geração usa o mesmo system prompt do treino para manter consistência, e depois separa o bloco <think> da resposta final com uma expressão regular — permitindo inspecionar o raciocínio do modelo. A exportação em Parquet fecha o ciclo: os dados curados ficam prontos para experimentos maiores.
Casos de uso reais
- Assistente de matemática local: rode o modelo ajustado em um notebook para resolver problemas passo a passo sem chamar APIs cloud.
- Prototipagem de agentes: use o padrão
<think>para que um agente explique o raciocínio antes de executar uma ação. - Ensino de NLP: o pipeline é um material didático completo sobre curadoria de dados e PEFT.
- Base para modelos maiores: reutilize os filtros e o formato de chat para ajustar um modelo de 1B ou 3B com o mesmo corpus.
- Benchmark interno: compare a razão de raciocínio antes e depois do fine-tuning para medir ganho real.
Troubleshooting — erros comuns e soluções
- ❌ Erro de dependência com
torchaoao importar PEFT. Causa: versões conflitantes. Solução: desinstaletorchaoantes de instalar as demais e aplique o workaround deis_torchao_available. - ❌ Memória insuficiente (CUDA OOM) no treino. Causa:
batch_sizealto oumax_lengthgrande demais. Solução: reduza paraper_device_train_batch_size=1e ativegradient_checkpointing. - ❌ Dataset parece vazio após os filtros. Causa: limites muito restritivos. Solução: cheque a taxa de retenção impressa e afrouxe
filter_reason_ratiooufilter_length. - ❌ Treino lento demais na CPU. Causa: dispositivo
cpudetectado. Solução: ative a GPU no Colab (Runtime → Change runtime type) e confiraDEVICE == "cuda". - ❌ A resposta gerada não mostra
<think>. Causa: o modelo não aprendeu a convenção ou o system prompt da inferência difere do treino. Solução: mantenha o mesmoSYSTEM_PROMPTnos dois momentos e aumentemax_new_tokens.
FAQ
- Preciso pagar por GPU? Não. O Google Colab oferece GPU T4 gratuita, suficiente para o treino descrito (~10–20 min).
- O que significa “4K-5M” no nome do dataset? Refere-se à escala do corpus: cerca de 4 mil repositórios de origem e 5 milhões de exemplos, dos quais você usa apenas 8.000.
- Posso trocar o SmolLM2 por outro modelo? Sim. Basta mudar
MODEL_IDpara qualquer modelo causal compatível com Hugging Face, como Qwen ou Llama pequenos. - Por que usar LoRA em vez de treinar tudo? LoRA ajusta poucos parâmetros, reduzindo custo de memória e tempo — ideal para demonstrações e protótipos.
- O modelo resultante serve para produção? Para produção, você precisaria de mais dados, mais épocas e um modelo base maior. Este tutorial é o ponto de partida.
Para onde isso vai
A tendência é clara: dados de raciocínio abertos e técnicas de ajuste eficiente estão democratizando o acesso a modelos que “pensam”. O pipeline descrito aqui é uma fundação reutilizável — a partir dele, dá para evoluir para mistura de fontes ponderada, curriculum learning (treinar primeiro em exemplos fáceis) e contextos mais longos. Se hoje um modelo de 135M aprende a raciocinar em uma GPU gratuita, em pouco tempo veremos fluxos equivalentes rodando em escala, com modelos de bilhões de parâmetros ajustados em ambientes acessíveis.
Descubra mais sobre noticiAI
Assine para receber nossas notícias mais recentes por e-mail.



