Escalando treinamento de LLMs na Maritaca AI
Como construímos cada nova geração da família Sabiá: o ciclo de desenvolvimento centrado em benchmarks, a pirâmide de escala que parte de centenas de experimentos em modelos pequenos e termina no treinamento da versão final, e as escolhas de arquitetura, dados e infraestrutura que sustentam essa cadência.
por Rodrigo Nogueira
O vídeo acima é um resumo, em formato de palestra, do que está descrito neste post.
Treinar um modelo de linguagem não é uma fase com começo, meio e fim, mas um ciclo contínuo. Cada nova geração da família Sabiá nasce de um conjunto de decisões sobre o que o modelo precisa aprender a fazer melhor, decisões que vêm de três fontes:
- Feedback dos clientes: pontos a melhorar identificados a partir do uso real do modelo.
- Paridade com novos modelos do mercado: capacidades que aparecem em concorrentes e que ainda não cobrimos.
- Oportunidades de diferenciação: capacidades que ninguém ainda atende bem e que podem virar um diferencial nosso.
A partir disso, o ciclo se repete em três grandes etapas:
Figura 1: o ciclo de desenvolvimento dos nossos modelos. Cada volta refina o conjunto de capacidades que o modelo precisa entregar.
Nas próximas seções abrimos cada uma dessas caixas.
Passo 1: Seleção das capacidades
A primeira caixa do ciclo é decidir, para a próxima geração, quais capacidades vamos atacar. Aqui “capacidade” significa a habilidade do LLM de resolver uma classe de tarefas, como escrever uma peça jurídica, sintetizar um prontuário médico, executar um workflow de busca, fazer análise de documentos longos, e assim por diante.
As três fontes de pauta listadas acima nos dão uma lista inicial de candidatas. A partir daí, o trabalho é priorizar: cobertura de mercado brasileiro, retorno para a base de clientes atual, viabilidade técnica e diferenciação competitiva.
Passo 2: Criação e avaliação em benchmarks
Para cada capacidade que decidimos atacar, criamos um benchmark antes de qualquer mudança no treinamento. Na Maritaca, todo o desenvolvimento é centrado em benchmarks: não fazemos mudanças no modelo se não conseguimos medir a capacidade que estamos tentando implementar.
A razão é simples: ao contrário de software tradicional, em machine learning é difícil saber se uma mudança no modelo realmente melhorou seu comportamento como um todo. Uma melhora pontual depois de um ajuste de prompt, de uma tool nova ou de um fine-tuning em poucos dados pode ser genuína para os dois ou três exemplos em que você observou, mas isso, sozinho, não diz se a mudança quebrou outras capacidades que já estavam funcionando, nem se o ganho se sustenta em um conjunto maior de casos. Sem um benchmark amplo o suficiente para detectar regressões e medir robustez, é impossível separar uma melhoria real de uma flutuação local.
De onde vêm os benchmarks
Os benchmarks que usamos vêm de três fontes principais. Importamos benchmarks públicos para o nosso framework de avaliação interno, coletamos manualmente provas e exames de seleção (ENEM, OAB, Revalida, vestibulares, concursos públicos) e construímos benchmarks proprietários, frequentemente em parceria com profissionais da área (médicos, advogados, engenheiros).
Da múltipla escolha às rubricas
Por muito tempo o padrão foram benchmarks de múltipla escolha: dada uma pergunta e algumas alternativas, o modelo deve escolher a correta. A vantagem é poder medir o conhecimento do modelo sem depender de instruction tuning, o nome genérico para os estágios de treino que ensinam o modelo a seguir instruções e produzir respostas no formato esperado pelo usuário (no nosso pipeline, esses estágios são o SFT e o RL, descritos adiante). Em benchmarks de múltipla escolha bastam alguns few-shot examples no prompt para induzir o modelo a gerar a letra da alternativa correta, então é possível avaliar até modelos que passaram apenas pelo pré-treino.
O problema é que acertar a alternativa correta sobre, digamos, economia ou geografia do Brasil mostra que o modelo conhece o assunto, mas não garante que o modelo escreva uma boa redação sobre os temas que acertou, por exemplo.
Daí surge a segunda geração de benchmarks, que cada vez mais domina nosso pipeline: avaliações cuja saída esperada são textos longos, como redações, pareceres jurídicos, relatórios médicos, respostas com tabelas e gráficos. Para textos longos, comparações par-a-par via LLM-as-a-judge (“dada a resposta A e a resposta B, qual é melhor?”) esbarram em limitações sérias: respostas misturam pontos fortes e fracos em trechos diferentes, e mesmo um juiz com bastante conhecimento do assunto tem dificuldade de ponderar todos esses aspectos simultaneamente para escolher um vencedor absoluto.
Por isso adotamos rubricas. Em vez de comparar respostas inteiras, decompomos a avaliação em itens objetivos, cada um cobrando um aspecto específico da resposta. Por exemplo, para uma peça jurídica a rubrica pode ter itens como “citou corretamente o artigo X”, “respeitou a estrutura formal de uma petição inicial”, “fundamentou o pedido com jurisprudência aplicável”. A avaliação então funciona assim:
- O modelo gera a resposta para a entrada.
- Um LLM-as-a-judge recebe a resposta e a rubrica, com seus vários itens.
- Item a item, o juiz pontua se a resposta satisfaz aquele critério.
- A nota final é a soma (ou proporção) dos itens satisfeitos.
Figura 2: comparação entre as duas abordagens de avaliação para textos longos. À esquerda, a avaliação par-a-par força o juiz a escolher um vencedor absoluto entre duas respostas inteiras, mesmo quando elas têm pontos fortes e fracos misturados. À direita, a avaliação por rubrica decompõe o julgamento em itens objetivos: cada aspecto é pontuado separadamente, regressões podem ser localizadas, e a comparação entre treinos fica ancorada na mesma escala. O custo da rubrica também escala linearmente no número de respostas, enquanto o par-a-par exige N(N−1)/2 comparações.
Em comparação com a múltipla escolha, a abordagem por rubrica tem duas desvantagens: ela só funciona em modelos que já passaram por instruction tuning, e tende a custar caro, já que o juiz costuma ser um modelo forte, ou uma combinação de vários para reduzir variância.
Benchmarks com rubrica também podem ser expandidos com tools, tanto do lado do modelo gerador quanto do juiz. Por exemplo, se a tarefa é redigir um documento jurídico que cita um artigo de lei, o gerador pode usar uma busca de legislação para fundamentar o texto, e o juiz pode usar a mesma busca para verificar se as citações são reais.
Avaliando antes de treinar
Uma vez definido o benchmark, avaliamos a versão atual do nosso modelo e dos concorrentes de tamanho/preço comparáveis. Em geral, uma das duas coisas acontece:
- A suspeita anedotal vira problema sistemático: o modelo realmente falha naquela classe de tarefas, e a capacidade precisa ser inserida em um ou mais estágios de treinamento.
- O modelo já resolve a tarefa razoavelmente: nesse caso, investimos em mais dados e em variações do benchmark para subir o teto e abrir vantagem competitiva.
Benchmarks que publicamos
Parte dos nossos benchmarks fica restrita por razões de sigilo, licenças ou vantagem competitiva, mas sempre que é possível publicar abrimos para que a comunidade possa reproduzir e comparar resultados:
- HealthBench-BR e PDCT-QA, protocolos clínicos brasileiros: github.com/hugoabonizio/clinical-protocols-br
- OAB-Bench, questões da prova da OAB: dl.acm.org/doi/10.1145/3769126.3769227
- Magis-Bench, escrita de sentenças cíveis e criminais: github.com/maritaca-ai/magis-bench
- PROSA, avaliação por rubricas binárias com múltiplos juízes em chats reais em português: arxiv.org/pdf/2605.01630
- CAPITU, compreensão de literatura brasileira: arxiv.org/abs/2603.22576
- MARCA, busca na web multilíngue avaliada com checklists: arxiv.org/pdf/2604.14448
- Poeta v2, avaliação ampla em PT-BR: ieeexplore.ieee.org/abstract/document/11303664
- TIEBE, eventos brasileiros: arxiv.org/abs/2501.07482
- ENEM + visão, questões com imagens: arxiv.org/abs/2311.14169
- ENEM, questões textuais: arxiv.org/abs/2303.17003
- BLUEX, vestibulares: link.springer.com/chapter/10.1007/978-3-031-45368-7_22
Passo 3: Coleta de dados e treinamento
Definidas as capacidades faltantes e estabelecidos os benchmarks, partimos para o que mais consome tempo e recursos: produzir os dados e rodar o treinamento. Esse trabalho se divide em três estágios: pré-treino, SFT (supervised fine-tuning) e aprendizado por reforço. Cada um tem objetivos e características distintos.
Figura 3: os três estágios de treinamento, com seus objetivos e tipos de dado.
Pré-treino
Vale uma nota importante antes de seguir: o que chamamos de pré-treino no nosso pipeline é, na prática, pré-treino continuado. Em vez de começar de pesos aleatórios, partimos de um checkpoint open-weights (um modelo cujo pré-treino do zero já foi feito por outro grupo) e continuamos a treinar com nossos próprios dados. A razão não é apenas econômica. Treinar do zero na escala de fronteira custa dezenas a centenas de milhões de dólares e ocupa um cluster grande por meses, o que já é motivo suficiente para não fazer quando há checkpoints públicos sólidos para partir. Mas há também o lado técnico: é preciso conseguir um cluster com milhares de GPUs, curar um corpus com dezenas de trilhões de tokens e aprender a tunar os pesos partindo de estado aleatório, três coisas que poucos grupos no mundo dominam hoje.
Nesse pré-treino continuado, o modelo refina a estrutura da linguagem que já tem e amplia seu conhecimento de mundo nos domínios que mais interessam à geração que estamos construindo. A escala dos dados adicionais costuma ser de dezenas a centenas de bilhões de tokens, com diversidade alta de domínios e fontes.
Aqui a qualidade dos dados é heterogênea por design. Mantemos uma mistura de dados de alta, média e até baixa qualidade, já que mesmo um documento incompleto ou parcialmente incorreto pode conter informações que não aparecem em nenhum outro lugar do corpus. O que importa é que a mistura, no agregado, cubra bem cada capacidade que queremos induzir.
Para guiar essa mistura, usamos modelos classificadores que estimam, para cada documento, quanto ele tende a contribuir para uma capacidade específica. Esses classificadores ficam na ordem de algumas centenas de milhões de parâmetros quando fine-tunados, ou de poucos bilhões quando operados em modo few-shot. Eles são pequenos o bastante para rodar sobre o corpus inteiro de pré-treino em tempo razoável.
Para garantir cobertura ampla das capacidades que escolhemos atacar, o crawl da web não é genérico: usamos focused crawl, em que classificadores especializados, partindo de um conjunto de páginas-semente, decidem quais links seguir e quais ignorar com base na probabilidade de levarem a páginas relevantes para a capacidade que está sendo desenvolvida.
Figura 4: focused crawl. Um classificador SLM (BERT-like ou small LM, ~100M–1B parâmetros) seleciona, do pool de sementes, apenas as páginas relevantes à capacidade que está sendo desenvolvida. A partir das sementes selecionadas, expandimos os links e reaplicamos o mesmo classificador em cada novo conjunto de páginas: as relevantes (✓) seguem expandindo, as irrelevantes (✗) param ali.
Reescritas: organizar a informação para facilitar o aprendizado
Uma técnica que cada vez mais ganha espaço no nosso pré-treino é reescrever documentos antes de usá-los para treinar. A intuição é que a ordem em que a informação aparece no texto tem efeito direto no quanto o modelo consegue aprender daquele documento.
Modelos de linguagem são causais: preveem o próximo token da esquerda para a direita, sem poder voltar atrás para corrigir uma previsão. Quando um documento apresenta um resultado logo no começo (por exemplo, “a resposta é 40 metros”) e só depois explica a metodologia, o modelo, ao tentar prever os tokens do resultado, ainda não tem acesso ao raciocínio. O sinal de aprendizado nesse trecho é fraco: ele só pode aprender a “adivinhar” o resultado a partir da pergunta, sem o caminho que levou até ele. Já um documento que apresenta o problema, depois constrói o raciocínio em níveis crescentes de detalhe e termina no resultado dá ao modelo, em cada token, um contexto rico para a previsão seguinte. O sinal de aprendizado é muito maior.
Figura 5: um documento original em que a resposta aparece antes do raciocínio dá ao modelo causal pouco contexto para prevê-la; reescrever o documento de forma que o raciocínio venha primeiro produz um sinal de aprendizado muito mais forte.
Vale notar o custo: reescrever exige passar centenas de bilhões de tokens por um modelo gerador, e portanto consome uma fração considerável da computação alocada ao pré-treino. A vantagem é que essa computação é gasta uma única vez, e os documentos reescritos são reutilizados ao longo das múltiplas execuções de pré-treino que fazemos durante o desenvolvimento de cada geração. Pelo volume de documentos a processar, o modelo reescritor que usamos é relativamente pequeno: usar um modelo maior ficaria proibitivamente caro nessa escala. Está em aberto na literatura científica se reescritas feitas por modelos mais capazes, ou estratégias de agregação multi-documento, produziriam ganhos significativos sobre o que já obtemos com um reescritor menor.
Pesquisa publicada nesta linha
Alguns dos artigos que publicamos sobre nossas técnicas de seleção e curadoria de dados de pré-treino, em coautoria com mestrandos e doutorandos afiliados à Maritaca:
- Building High-Quality Datasets for Portuguese LLMs: From Common Crawl Snapshots to Industrial-Grade Corpora, de Thales Sales Almeida, Rodrigo Nogueira, Helio Pedrini. arxiv.org/abs/2509.08824
- Juru: Legal Brazilian Large Language Model from Reputable Sources, de Roseval Malaquias Junior, Ramon Pires, Roseli A. F. Romero, Rodrigo Nogueira. link.springer.com/chapter/10.1007/978-3-032-15984-7_9
- Curió-Edu 7B: Examining Data Selection Impacts in LLM Continued Pretraining, de Thales Sales Almeida, Rodrigo Nogueira, Hélio Pedrini. arxiv.org/abs/2512.12770
- Comparing Knowledge Injection Methods for LLMs in a Low-Resource Regime, de Hugo Abonizio, Thales Almeida, Roberto Lotufo, Rodrigo Nogueira. arxiv.org/abs/2508.06178
- The Interplay Between Domain Specialization and Model Size, de Roseval Malaquias Junior, Ramon Pires, Thales Sales Almeida, Kenzo Sakiyama, Roseli A. F. Romero, Rodrigo Nogueira. arxiv.org/abs/2501.02068
- Measuring Cross-lingual Transfer in Bytes, de Leandro De Souza, Thales Almeida, Roberto Lotufo, Rodrigo Frassetto Nogueira (NAACL 2024). aclanthology.org/2024.naacl-long.418
- Synthetic Rewriting as a Quality Multiplier: Evidence from Portuguese Continued Pretraining, de Thales Sales Almeida, Rodrigo Nogueira, Hélio Pedrini. arxiv.org/abs/2603.24826
SFT (supervised fine-tuning)
O segundo estágio é o fine-tuning supervisionado. Aqui a lógica se inverte: a quantidade de dados é muito menor, e o critério dominante passa a ser a qualidade individual de cada exemplo.
Para cada capacidade que queremos incutir no modelo (por exemplo, “fazer uma análise completa de vários documentos anexados em uma conversa”), construímos um conjunto de respostas de altíssima qualidade. Essas respostas vêm de duas fontes principais:
- Ensembles de modelos fortes: geramos múltiplas respostas com modelos diferentes, identificamos os trechos em que elas concordam e mantemos apenas as partes consideradas robustas.
- Anotação humana especializada: para domínios que exigem julgamento técnico (medicina, direito, redação acadêmica), contratamos profissionais que escrevem ou revisam as respostas.
Tudo passa por filtros automáticos e revisão manual antes de entrar no dataset. A capacidade nova que queremos no modelo, ao final, está concretamente representada por esse conjunto de exemplos.
Aprendizado por reforço
O último estágio é treinamento com aprendizado por reforço, e tem uma vantagem importante: você não precisa explicitar para o modelo como é uma resposta ideal. Em vez disso, define-se uma função de recompensa que pontua cada resposta gerada, e o modelo aprende, ao longo do treino, a gerar respostas com pontuação maior.
Vale destacar uma diferença em relação ao que aparece com mais frequência na literatura de RL para LLMs: grande parte do trabalho recente foca em domínios como matemática e programação, em que a recompensa é programaticamente verificável. Em código, basta executar contra um conjunto de testes; em matemática, basta comparar a resposta final com o gabarito. O sinal de recompensa fica exato, barato e livre de ambiguidade, o que simplifica bastante o treino. Já as tarefas em que mais investimos na Maritaca são justamente as que escapam desse regime: peças jurídicas, recomendações financeiras, planos de estudo, análises de exames médicos, redação acadêmica. Não existe verificador programático que diga “esta peça está correta” ou “esta análise médica está completa”. Por isso, na maior parte dos nossos treinos de RL, a função de recompensa é exatamente o mesmo mecanismo descrito no Passo 2: um LLM-as-a-judge aplicando a rubrica da tarefa, item a item.
Técnicas modernas, como GRPO, levam isso adiante: para cada entrada, o modelo gera várias respostas e a recompensa de cada uma é comparada à média do grupo. A diferença entre a recompensa de uma resposta e essa média é o que chamamos de vantagem. Quanto maior a vantagem, mais os pesos são ajustados para favorecer respostas parecidas com aquela.
Figura 6: o GRPO em detalhe. Para cada entrada, o modelo amostra várias respostas, e o LLM-as-judge pontua cada uma usando a rubrica da tarefa. A vantagem de uma resposta é a sua pontuação menos a média do grupo. Respostas com vantagem positiva são reforçadas, com vantagem negativa são suprimidas, e perto de zero quase não alteram os pesos.
Há um ponto sutil sobre o que cada estágio faz no modelo. O pré-treino é o que introduz o conhecimento abrangente, ou seja, define o repertório de saídas que o modelo é capaz de gerar. O SFT alinha esse repertório aos formatos e padrões de resposta esperados. E o RL atua principalmente reforçando respostas que o modelo já consegue gerar com alguma probabilidade, deslocando massa de probabilidade para as melhores delas. Se o modelo é capaz de descobrir capacidades genuinamente novas durante a amostragem ainda é uma questão em aberto na literatura, mas, na prática, esperar por descobertas via exploração é um processo lento e pouco confiável quando o pré-treino e o SFT não cobriram a habilidade que se quer desenvolver. Se o modelo amostra dez respostas para uma mesma entrada e todas são parecidas, nenhuma se destaca em recompensa, a vantagem fica próxima de zero, os pesos quase não mudam, e o algoritmo passa para o próximo exemplo. Por isso o RL é sempre aplicado depois do pré-treino, e na maioria dos pipelines também depois do SFT, embora haja exceções importantes, como o DeepSeek-R1-Zero, que vai do pré-treino direto para RL sem passar por SFT, e o próprio R1, que alterna ciclos de SFT e RL. O que esses pipelines têm em comum é a exigência de um modelo já com capacidade suficiente para que apareça variação útil entre as amostras.
Quantização para servir
Concluído o treinamento, o modelo ainda precisa ser preparado para produção. Para servir os usuários com latência e custo aceitáveis, ele precisa caber no hardware de inferência e rodar de forma econômica. Por isso, depois de treinado, quantizamos os pesos: a partir da precisão usada no treino, que pode ser BF16 ou FP8 com quantization-aware training (QAT), reduzimos para 8 ou até 4 bits no serving.
A regra é simples: quanto mais agressiva a redução de precisão, mais trabalho de treino é necessário para preservar qualidade. Reduzir para 8 bits ainda costuma ser viável com calibração baseada em estatísticas das ativações, e a degradação tende a ser pequena. Já reduzir para 4 bits é outro patamar: cada peso passa a ter apenas 16 valores possíveis, e isso normalmente não é suficiente para representar bem a distribuição de pesos da rede sem comprometer capacidades importantes do modelo. Por isso, em 4 bits, as técnicas modernas combinam calibração com quantization-aware training, em que o próprio treino simula o efeito da quantização para que o modelo aprenda pesos que toleram a perda de precisão. Quantizar deixa, então, de ser um passo pós-treino barato e passa a ser mais um estágio de treino. Concretamente, no regime de 4 bits:
- Os dados usados importam. Diferentes pipelines combinam QAT durante o treino, calibração pós-treino com um conjunto menor, ou ambos. Há ainda formatos como o NVFP4 da NVIDIA, em que o pré-treino acontece direto em 4 bits e dispensa uma fase de calibração separada. Em todos esses caminhos, os dados (treino ou calibração) precisam refletir as distribuições reais de uso do modelo, incluindo idiomas, domínios, formatos de prompt e comprimentos típicos, já que amostragem aleatória de texto não basta.
- Misturam-se precisões em diferentes partes da rede. Camadas mais sensíveis à perda numérica (atenção, embeddings, normalizações) tendem a ficar em precisão maior (8 bits ou na precisão original). Partes mais redundantes, em particular os experts em modelos MoE (onde o roteamento já dilui o impacto de qualquer expert individual), toleram precisão menor. As combinações específicas variam por equipe e workflow, mas o princípio comum é alocar precisão proporcional à sensibilidade de cada componente.
- A validação usa a bateria completa de benchmarks. Quantização pode parecer inócua em métricas agregadas e ainda assim degradar capacidades específicas como chamada de função, raciocínio matemático e contexto longo. A única forma de pegar isso é rodar a avaliação inteira, o que nos leva de volta ao Passo 2 do ciclo.
Figura 10: precisão mista por componente do bloco transformer. Embeddings, normalizações e o router do MoE ficam em precisão maior (BF16), porque são as partes mais sensíveis a erro numérico. Atenção e cabeça de saída descem para 8 bits com calibração. Os experts do MoE, que concentram a maior parte dos parâmetros do modelo, descem para 4 bits — a redundância intrínseca do roteamento dilui o impacto da redução, e quantizar só eles já corta a maior parte da memória de inferência.
Arquitetura: denso vs Mixture of Experts
Outra escolha relevante na hora de treinar é a arquitetura do modelo. Nas últimas gerações, a opção dominante na fronteira tem sido Mixture of Experts (MoE), caminho que também seguimos na Maritaca.
Modelos densos (todo parâmetro é ativado a cada token) ainda dominam em algumas frentes, especialmente em tarefas de raciocínio puro , onde a capacidade total do modelo importa mais do que sua eficiência por token. Densos também atingem MFU (Model Flops Utilization) de 50–60% em treino, um indicador de eficiência computacional.
Modelos MoE esparsos, por outro lado, ficam tipicamente em MFU de 20–40% quando se considera apenas os parâmetros ativos. Em troca, ganham uma vantagem importante em produção: como apenas uma fração da rede é ativada por token, é possível ter um número total de parâmetros muito maior (e portanto mais conhecimento armazenado) pagando um custo de inferência equivalente ao de um modelo denso muito menor. Para o usuário final, isso significa qualidade de modelo grande pelo preço de modelo pequeno.
Mas MoE traz complicações próprias. A principal é o balanceamento de carga entre experts: como cada token só roteia para um subconjunto dos experts (e a roteação é decidida pela própria rede durante a inferência), na prática alguns experts ficam sobrecarregados enquanto outros ficam ociosos. Isso reduz a utilização efetiva do hardware, mesmo que a fração nominal de parâmetros ativados por token seja pequena. No treino, mitigamos isso com funções auxiliares de perda que penalizam o desbalanceamento; no serving, com despacho dinâmico de tokens entre máquinas e batching consciente da distribuição de experts.
Outro aspecto onde MoE encontra um casamento natural com a infraestrutura moderna é a prefill–decode disaggregation: técnica que separa em máquinas (ou grupos de GPUs) diferentes as duas fases da inferência, que têm perfis computacionais radicalmente distintos:
- Prefill: processar o prompt do usuário de uma vez. É compute-bound: o gargalo é a quantidade de FLOPs disponíveis, e a operação é altamente paralelizável (todos os tokens do prompt entram simultaneamente).
- Decode: gerar um token novo por vez, autoregressivamente. É memory-bandwidth-bound: o gargalo passa a ser a velocidade com que o hardware consegue ler os pesos do modelo e o cache de atenção a cada novo token.
Em vez de rodar as duas fases na mesma máquina (forçando um compromisso de hardware que serve mal as duas), separa-se: as máquinas com perfil “prefill” são otimizadas para FLOPs e batches grandes; as “decode” são otimizadas para largura de banda de memória e batching cruzado de muitos usuários simultâneos. Em MoE, essa separação é especialmente vantajosa porque o all-to-all de roteamento entre experts tem dinâmicas opostas nas duas fases. Em prefill, o all-to-all é orientado a throughput: o batch é homogêneo, a distribuição de carga entre experts é mais previsível, e dá para amortizar latência com batches grandes e agendamento estático. Em decode, o all-to-all passa a ser orientado a latência: cada token de cada usuário precisa ser despachado e aguardar o resultado em um tempo curto, e a distribuição entre experts fica menos balanceada porque há poucos tokens para diluir flutuações de roteamento. Otimizar comunicação, paralelismo e batching para cada um desses regimes separadamente é muito mais simples do que tentar acomodar os dois no mesmo nó.
A consequência prática é simples: todo modelo de fronteira que precisa ser servido em larga escala hoje vai de MoE. A diferença de custo de inferência por unidade de qualidade entregue é grande demais para ignorar.
Infraestrutura: TPUs e GPUs
Nosso stack de treinamento mistura aceleradores diferentes em estágios diferentes: usamos majoritariamente TPUs do Google para pré-treino e SFT, e GPUs para aprendizado por reforço (com uso misto em alguns treinos). Por trás dessa escolha há uma combinação de fatores técnicos, comerciais e operacionais que vale detalhar.
Do lado puramente técnico, TPUs são notoriamente mais difíceis de operar. A comunidade ativa é menor e os frameworks costumam ficar defasados em relação às novidades arquiteturais. Um exemplo é o MaxText, repositório de referência para treino em TPU, que ainda não otimiza adequadamente vários modelos open-source recentes com mecanismos de atenção híbridos. GPUs, por terem comunidade enorme e frameworks como Megatron-LM, NeMo e DeepSpeed sob desenvolvimento ativo de centenas de empresas, costumam ter o stack atualizado em dias ou semanas após o lançamento de um modelo novo. TPUs também tendem a ser proporcionalmente mais caras em FLOPs por dólar do que GPUs em “neoclouds” como Verda, Lambda e CoreWeave.
Por que então preferimos TPUs no nosso fluxo? A resposta não está no treinamento da versão final tomado isoladamente: se fôssemos rodar apenas o treinamento grande, um contrato GPU dedicado provavelmente seria a melhor opção, e bastaria reservar um cluster pelos meses de treino. Acontece que o treinamento da versão final é só a ponta do iceberg. A maior parte do esforço (e do orçamento, como mostraremos adiante) está em centenas de experimentos em escala pequena e dezenas em escala média rodados antes dele. É essa pirâmide de escala que muda a equação a favor das TPUs.
Como escalamos os treinos: do 3B ao 1T
Treinos em modelos de fronteira não são exercícios determinísticos. O que funciona em um modelo de 7B raramente funciona com os mesmos hiperparâmetros em um modelo de 70B, e o que funciona em 70B não escala trivialmente para 1T. Por isso, nossa metodologia é uma pirâmide:
Figura 7: a pirâmide de escala. Toda nova geração do Sabiá começa por centenas de treinos em escala pequena, refinados em uma dezena na escala média, e termina em uma ou duas rodadas no modelo final.
-
Modelos pequenos (3 a 30B parâmetros): fazemos em média ~500 treinamentos por geração. Aqui é onde testamos hipóteses: novas misturas de dados, novas reescritas, novas configurações de SFT, novas funções de recompensa para o RL, novas combinações de hiperparâmetros. Cada treinamento é relativamente barato e pode ser concluído em horas ou poucos dias, o que torna possível esse volume de experimentação. Vale destacar que, nessa escala, boa parte do custo não está no treino em si, mas na avaliação: como a maioria dos nossos benchmarks pede geração de textos longos, rodar a bateria toda demora. Some-se a isso o custo do LLM-as-judge, seja servido localmente em GPU, seja via API externa, seja via nossos próprios modelos Sabiá (que também consome capacidade que poderia estar servindo clientes em produção).
-
Modelos médios (30 a 300B parâmetros): uma vez validadas as ideias, migramos para a escala média e rodamos cerca de uma dezena de treinamentos. Mas por que ainda uma dezena? Não bastaria um único treino, agora que sabemos o que funciona em escala menor? Por dois motivos. Primeiro, vários efeitos só emergem nessa escala: a combinação de learning rate e batch size que funcionava no 3B–30B, mesmo ajustada proporcionalmente segundo as melhores práticas da literatura, ainda exige correções por tentativa e erro. Segundo, nem sempre o modelo open-weights que usamos como base na faixa de 3B–30B é o mesmo da faixa de 30B–300B: às vezes há pequenas diferenças de arquitetura, tokenizador, ou até é uma família completamente diferente. Isso introduz incerteza adicional e exige mais experimentos para recalibrar a receita ao novo ponto de partida.
-
Modelo final (~1T parâmetros): só depois de tudo isso fazemos um ou dois treinamentos no tamanho da versão maior. Mesmo nessa altura, o treino do modelo grande é, em parte, um tiro no escuro: nem todo modelo open-weights está disponível em todas as escalas. O Qwen3.5, por exemplo, vai de 4B até 397B, mas não há checkpoint público de 1T+, o que nos deixa sem ponto de calibração externo justamente na faixa de tamanho que mais nos interessa. O DeepSeek V4 ilustra o oposto: foi divulgado em 298B e 1,6T parâmetros, mas sem versões menores que permitam iteração rápida; partir direto do 298B para experimentar uma nova receita já é caro demais para fazer 500 treinamentos. Em ambos os casos, ao escalar para 1T, ficamos sem boa parte das referências externas que usaríamos para calibrar, e dependemos quase inteiramente do que aprendemos nas escalas menores que conseguimos montar internamente a partir de outros modelos open-weights.
Esse padrão tem uma consequência prática direta para a discussão de infraestrutura: a maioria absoluta dos nossos treinamentos é em escala pequena. Se o stack de treinamento não permitir ciclos rápidos de “subir cluster, testar, desligar, repetir”, esses ~500 treinos pequenos viram o gargalo do projeto inteiro. É por isso que a flexibilidade de provisionamento importa muito mais para nós do que o preço bruto por FLOP.
Ainda assim, o treinamento final em escala de ~1T continua sendo um evento de altíssimo custo. Vale fazer essa conta.
A conta de treinar um modelo de 1T de parâmetros em GPU
Considere o exercício: pré-treinar um modelo MoE com 1,6 trilhões de parâmetros totais e ~49 bilhões de parâmetros ativos por token, em 500 bilhões de tokens com sequence length de 8k. Escala equivalente, em ordem de grandeza, a modelos abertos recentes como o DeepSeek-V4-Pro (1,6T totais / 49B ativos).
A regra prática para a quantidade de operações de ponto flutuante (FLOPs) em pré-treino é 6 × parâmetros × tokens. Para um MoE, o que conta é o número de parâmetros ativos por token (não o total), porque é só essa fração da rede que participa de cada forward/backward:
6 × 4,9 × 1010 × 5 × 1011 ≈ 1,47 × 1023 FLOPs
A B200 da NVIDIA, na versão SXM, entrega cerca de 2,25 PFLOPs/s em BF16 dense por GPU. Em treino real, o que efetivamente se aproveita disso (a Model FLOPs Utilization, MFU) tipicamente fica em torno de 40% para regimes bem otimizados. Ou seja, cada GPU produz ~0,9 PFLOPs/s úteis.
Dividindo, chegamos a algo como ~45 mil GPU-horas para concluir o treino.
Mas computação não é a única restrição que define o tamanho mínimo do cluster. A memória também impõe um limite, e aqui o que importa é o número total de parâmetros, não os ativos: durante o treino todos os 1,6T precisam ficar acessíveis na rede de chips, porque todos os experts são atualizados. Em treino mixed precision (BF16 + otimizador Adam em FP32), a conta de memória por parâmetro é:
- Pesos BF16: 2 bytes
- Gradientes BF16: 2 bytes
- Otimizador Adam (momento FP32 + variância FP32 + master weights FP32): 12 bytes
- Total: 16 bytes por parâmetro
Para 1,6T parâmetros: 1,6 × 10¹² × 16 bytes ≈ 25,6 TB só de estado, sem contar ativações, buffers de comunicação e gradient accumulation. Para as ativações, com activation checkpointing basta guardar a entrada de cada bloco transformer (o restante é recomputado no backward), o que em BF16 dá 2 bytes por token por camada, ou seja:
ativações ≈ camadas × tokens_no_batch × hidden × 2 bytes
Para um modelo dessa escala (~61 camadas, hidden ~7k) com sequence length de 8k, e batch global de ~4M tokens (faixa típica em pré-treino de fronteira), as ativações somam 61 × 4 × 10⁶ × 7168 × 2 ≈ 3,5 TB; com batches maiores (8–15M tokens), entre 7 e 13 TB. Tomando ~5–10 TB como faixa representativa, o total estado + ativações fica em torno de ~30–35 TB. Cada B200 tem 192 GB de HBM, logo são necessárias ~135 B200s só para o estado caber, ou ~150–200 B200s somando ativações com sequence length de 8k.
Combinando os dois requisitos (computação para o prazo desejado e memória para o modelo caber), o mínimo efetivo de B200s para cada cronograma é:
| Prazo | Mín. por compute | Mín. por memória | Mín. efetivo | Custo neocloud (R$ 22/h) | Custo big cloud (R$ 60/h) |
|---|---|---|---|---|---|
| 30 dias | ~63 | ~150 | ~150 | ~R$ 1,0 mi | ~R$ 2,7 mi |
| 14 dias | ~135 | ~150 | ~150 | ~R$ 1,0 mi | ~R$ 2,7 mi |
| 7 dias | ~270 | ~150 | ~270 | ~R$ 1,0 mi | ~R$ 2,7 mi |
Tabela 1: GPU-horas e custo total para pré-treinar um MoE de 1,6T totais / 49B ativos em 500B tokens, considerando ~45 mil GPU-horas (BF16, 40% MFU sobre os parâmetros ativos). Para os prazos longos, a memória é o gargalo: em 30 dias o compute pediria 63 GPUs, mas a memória obriga 150, e o treino acaba terminando em ~13 dias em vez de 30. O custo total fica aproximadamente igual entre prazos porque é função das GPU-horas, não do tamanho do cluster. Premissa: USD/BRL = 5,0.
Em termos de fluxo de caixa diário, um cluster de 150 B200s rodando 24h/dia em neocloud custa ~R$ 79 mil por dia. Em provedor grande tipo Oracle/Azure/GCP/AWS, o mesmo cluster sai por ~R$ 216 mil/dia.
A conta acima é o custo de um único treinamento na escala maior. Como vimos na pirâmide, antes desse treinamento final rodamos ~500 treinamentos em modelos pequenos e ~10 em médios. Quando se soma tudo, o custo da rodada final aparece como uma fração relativamente pequena do orçamento da geração:
| Item | # treinamentos | GPU-horas / treinamento | GPU-horas total | Custo neocloud (R$ 22/h) | % do orçamento |
|---|---|---|---|---|---|
| Treino dos pequenos (3 a 30B) | ~500 | ~300 | ~150 mil | ~R$ 3,3 mi | ~46% |
| Avaliação dos pequenos (LLM-as-judge incluso) | ~500 | ~50 | ~25 mil | ~R$ 0,55 mi | ~8% |
| Médios (30 a 300B), com avaliação | ~10 | ~8 mil | ~80 mil | ~R$ 1,8 mi | ~25% |
| Versão maior (~1T), com avaliação | 1–2 | ~45 mil | ~67 mil | ~R$ 1,5 mi | ~21% |
| Total da geração | ~322 mil | ~R$ 7,2 mi | 100% |
Tabela 2: estimativa de orçamento agregado de uma geração inteira. As avaliações na escala pequena aparecem como linha separada porque rodam ~500 ciclos com benchmarks majoritariamente de geração longa e LLM-as-judge; não dominam o orçamento, mas pesam o suficiente para serem visíveis. Nas escalas média e grande, a avaliação tem um custo proporcionalmente bem menor (poucos treinamentos) e está embutida nos números de cada linha. O treinamento da versão maior, apesar de ser o evento mais visível e estressante (e dependente de cluster maior em curto prazo), representa apenas ~21% do orçamento. A maior parte vai para o ciclo de experimentação na escala pequena: treino + avaliação dos pequenos somam ~54% do custo total. É por isso que a flexibilidade de provisionamento e o custo por hora dos pequenos pesam muito mais do que o pico de chips do treinamento final.
Disponibilidade em larga escala
Os números acima já mostram o primeiro problema: no big cloud, o custo de uma única rodada de pré-treino chega facilmente a R$ 2,7 milhões, quase o triplo do neocloud. E quando se trata de modelos com mais tokens (DeepSeek-V4-Pro foi treinado em 32 trilhões, ~64 vezes mais que o nosso exemplo), os números crescem proporcionalmente. Mas o problema não é só preço. É disponibilidade.
Nos neoclouds, alugar algumas centenas de GPUs por um mês significa pedir que o provedor dedique uma fração significativa da capacidade computacional do cluster a um único cliente por um período curto. Isso afasta os outros clientes do provedor: quando a base nota que não há GPUs disponíveis por dias seguidos, a confiança no serviço cai. Esses provedores naturalmente preferem contratos longos (1+ ano) com múltiplos clientes médios em paralelo. Aluguel curto e enorme não casa com o modelo de negócio deles.
Até pouco tempo atrás (e até onde sabemos), nenhuma cloud de GPU permitia alugar algumas centenas de chips por hora sob demanda. Hoje algumas opções existem, mas a disponibilidade real é irregular: você pode ligar quando precisa e descobrir que só há, digamos, 50 chips livres no cluster naquele momento.
A curva de aprendizado de treinar em 100+ máquinas
Suponha agora que você conseguiu o cluster, alugado por 1 ou 2 meses. O contador de horas começa a correr. E aí entra o segundo problema: frameworks de treino em GPU não estão otimizados para esta escala.
A maior parte da comunidade que usa Megatron, NeMo e similares opera em escalas muito menores: dezenas de chips, não centenas. Vários problemas só aparecem quando você sai de 10 para 100 máquinas. Veja alguns exemplos que vivenciamos:
- Downloads automáticos: instalar Docker ou pacotes pip em paralelo em 100 nós faz o serviço de download enxergar a operação como um ataque DDoS e começar a negar conexões.
- Servidores de coordenação: o nó que coordena os workers segura 10 conexões sem dificuldade; com 100 conexões simultâneas ele vira gargalo, e o treino fica esperando todo mundo sincronizar.
- Monitoramento: cada worker mandando métricas para um serviço de telemetria? Com 100 workers, esse serviço pode rate-limit-ar ou recusar.
- Bugs raros que viram corriqueiros: um erro de hardware com 0,1% de chance por GPU/dia é desprezível em 10 GPUs, mas a partir de algumas centenas vira uma falha a cada poucos dias com alta probabilidade.
Outro passo que consome bastante tempo de cluster (e portanto bastante computação) é a sintonia da partição entre os eixos de paralelismo. São quatro eixos principais: FSDP (sharding de pesos e estado do otimizador entre chips), tensor parallelism (TP, divisão das matrizes de cada camada entre chips), context parallelism (CP, divisão da sequência longa entre chips) e, em modelos MoE, expert parallelism (EP, distribuição dos experts entre chips). Cada combinação de tamanho de modelo, sequence length e quantidade de chips disponíveis exige uma configuração diferente: o TP ideal em 64 GPUs costuma ser subótimo em 128, contextos longos forçam introduzir CP que precisa ser tunado para cada tamanho de modelo, e MoE soma o eixo dos experts. A diferença entre uma configuração bem afinada e uma mediana pode chegar a 15 dias contra 30 dias de treino, e o custo do experimento praticamente dobra quando o tuning não é bem feito.
Cada um desses problemas vira pressão direta de tempo, pois enquanto os engenheiros depuram, as horas de aluguel continuam contando, e o cluster custa dezenas de milhares de reais por dia parado.
A vantagem comercial das TPUs
Aqui aparece a vantagem das TPUs: o modelo de cobrança e provisionamento é completamente diferente. No GCP, TPUs são cobradas por segundo de uso (com mínimo de um minuto), e é possível instanciar (e desligar) clusters grandes sob demanda.
O fluxo de trabalho que isso habilita é distinto: sobe-se o cluster com a configuração que se quer testar, dois ou três engenheiros trabalham lado a lado afinando a otimização e, se nada funciona e as ideias acabam, basta desligar o cluster, discutir internamente e voltar no dia seguinte com uma abordagem nova.
Em GPU, esse fluxo é possível mas significativamente mais difícil nesta escala. Os contratos típicos são de meses, com capacidade reservada paga adiantado: o relógio do contrato não para de correr, e cada falha de execução é tempo a menos disponível para os treinos que de fato importam. Em TPU, o custo de uma tentativa frustrada é proporcional ao tempo efetivamente usado: se algo dá errado e os engenheiros vão dormir, basta desligar o cluster e o pagamento simplesmente para enquanto ninguém estiver usando.
Soma-se a isso uma robustez de infraestrutura difícil de igualar em GPU para esses tamanhos:
- Interconexão consistente: pods de TPU são desenhados de fábrica para o paralelismo distribuído desses treinos, com largura de banda e latência previsíveis entre todos os chips. As melhores neoclouds chegaram a níveis comparáveis, e oferta de clusters bem interconectados está virando padrão da indústria. Mas ainda há variabilidade entre provedores, e existe risco real de cair em um cluster cuja interconexão não atende à carga.
- Rede e CPU dimensionadas para a carga: storage, host CPU e networking ao redor do acelerador são projetados para o regime de treino em larga escala, sem os gargalos que aparecem em provedores menos especializados.
| Aspecto | GPU (B200, neocloud) | TPU (v5/v6) |
|---|---|---|
| FLOPs por dólar | Melhor | Pior (proporcionalmente) |
| Comunidade / frameworks | Megatron, NeMo, DeepSpeed (ativos) | MaxText (pequena, defasada) |
| Aluguel sob demanda em larga escala | Difícil; capacidade irregular | Fácil; cobrança por segundo |
| Custo de “falhar e recomeçar” | Alto (contrato longo, capacidade reservada) | Baixo (sobe, testa, desliga) |
| Otimização para decoding | Excelente | Boa |
| Interconexão pré-dimensionada | Variável por provedor | Garantida no pod |
Tabela 2: GPU vs TPU para treino em larga escala. A escolha não é universal: depende do estágio do treinamento e do perfil de uso.
Preempção e checkpoints
Treinar um LLM em larga escala não é só uma questão de quantos chips você tem. É também o quão interrompível é o seu pipeline. No GCP, TPUs preemptíveis custam metade do preço das on-demand, e na Maritaca todos os nossos pré-treinos rodam em TPU preemptível por padrão. A contrapartida é óbvia: a qualquer momento o GCP pode reaver as máquinas e devolvê-las pra outro cliente.
Pra que isso seja viável sem perder dias de progresso a cada interrupção, o framework de treino precisa fazer uma retomada confiável a partir do checkpoint. Quando a TPU morre, a próxima execução tem que pegar exatamente o estado salvo no último checkpoint e continuar dali. Parece óbvio, mas inclui muito mais do que os pesos: o estado do otimizador, o RNG do dataloader (pra não revisitar nem pular batches), o passo da curva de learning rate, e a posição exata no shuffle do dataset.
Sobra então uma decisão de engenharia: com que frequência salvar checkpoints? É um trade-off direto. Salvar muito raramente faz cada preempção custar muito treino perdido, pois o treino recomeça do mesmo checkpoint que tinha partido. Salvar muito frequentemente esbarra num gargalo menos óbvio.
Os frameworks de treino que usamos são eficientes no save: fazem off-load dos pesos e do estado do otimizador da memória da TPU para a RAM da CPU em segundos, e a TPU já volta a treinar enquanto a CPU faz o resto do trabalho em background, transferindo os bytes da RAM para um armazenamento distribuído remoto. O passo TPU → CPU é rápido, já que tem largura de banda local enorme. O passo CPU → armazenamento é lento, limitado pela rede. Se você dispara um novo checkpoint antes que o anterior tenha terminado a transferência, os pesos do checkpoint novo vão acumulando em RAM em cima dos antigos, e em modelos grandes isso estoura a memória da CPU rapidamente. O resultado prático é que a frequência mínima entre saves é determinada pelo tempo de upload para o armazenamento, não pelo tempo de off-load.
Figura 8: o fluxo de salvamento de checkpoint, com a largura de cada faixa proporcional à banda real entre cada par de componentes. Os pesos saem da TPU para a RAM do host CPU pelo PCIe (~16 GB/s por TPU em v5p), e de lá vão para o armazenamento distribuído remoto pela rede do data center, cuja banda raw está em torno de ~6 GB/s por TPU. Na prática, o gargalo costuma ser ainda maior, porque a throughput efetiva de upload para um bucket de armazenamento depende do backend de storage e raramente atinge o teto da rede. De qualquer forma, o segundo passo domina o tempo de save. Para mais detalhes sobre TPUs e essas bandas, recomendamos o livro Scaling Deep Learning do time de JAX.
Calibramos a frequência pra que o tempo gasto salvando (efetivamente, o tempo bloqueado pela transferência CPU → armazenamento quando ela não termina antes do próximo save), mais o custo esperado de retomar do último checkpoint quando preemptado, seja minimizado. Esse ponto ótimo depende do MTBF (mean time between failures) das TPUs naquela região e janela, e da banda da rede até o armazenamento. Costuma cair em um checkpoint a cada 30–60 minutos.
Por que não usar LoRA para aliviar o problema da memória?
Uma reação natural diante destes números é: por que não usar LoRA (ou outras técnicas de fine-tuning paramétrico-eficiente) para reduzir o requisito de memória, e portanto o tamanho do cluster?
Por dois motivos.
Primeiro: LoRA não funciona bem em treinos grandes. Em LoRA apenas uma fração dos pesos é ajustada (uma matriz de adaptação low-rank substitui a atualização do peso original). Isso funciona bem quando os dados de treino são pequenos, digamos menos de ~1 bilhão de tokens. Mas pré-treinos da Maritaca operam na escala de centenas de bilhões de tokens, e SFTs na escala de dezenas de bilhões. Nesse regime, tanto nossa experiência interna quanto a literatura mostram que modelos treinados com LoRA absorvem menos informação por token do que modelos treinados com full fine-tuning, e isso se traduz em qualidade final inferior, observada de forma clara nos resultados de benchmarks.
Segundo: LoRA não economiza tanta computação quanto a intuição sugere. Como a Thinking Machines mostra com a conta detalhada de FLOPs, LoRA usa cerca de 2/3 das operações por passo que full fine-tuning usa, ou seja, ~30% mais rápido por step, não ordens de magnitude.
A combinação dos dois fatores é o que mata a ideia: mesmo que a menor absorção por token não fosse problema (mas é), os ~30% de aceleração não compensam reduzir o tamanho do cluster proporcionalmente à economia de memória. Em LoRA, o estado do otimizador some para os pesos do modelo base (são congelados), mas os próprios pesos ainda precisam ficar em memória durante o forward. A memória cai de ~25 TB para ~3 TB, e o requisito mínimo de chips por memória vai de ~150 B200s para ~20 B200s. Mas com só 20 GPUs, o treino que levaria ~13 dias na configuração full fine-tuning passaria a levar ~10 semanas mesmo com a aceleração do LoRA. É lento demais para um ciclo de iteração competitivo.
A divisão final entre TPU e GPU
Por tudo isso, na Maritaca o pré-treino e o SFT são feitos em TPU. Para esses estágios, o que importa é throughput sustentado em treinos longos, exatamente onde TPUs brilham.
Para aprendizado por reforço, ainda usamos os dois aceleradores conforme o caso. GPUs têm vantagens reais aqui:
- Geração de tokens é onde GPUs são mais otimizadas. RL precisa amostrar muitas respostas do modelo a cada passo (em GRPO, dezenas de respostas por entrada), e essa fase de inferência domina o tempo total do treino. Pré-treino e SFT não têm esse perfil: só fazem forward+backward.
- A geração escala sem alta interconexão. Um modelo de 1T parâmetros cabe folgado em uma máquina de 8 B200s para inferência, e essas máquinas geradoras podem ser replicadas horizontalmente sem precisar de interconexão InfiniBand entre elas.
- LoRA dá para ser usado em RL sem degradações notáveis em relação ao full fine-tuning. O sinal de aprendizado por exemplo de RL é pequeno (uma escala de vantagem por amostra, não a densidade de informação de um documento de pré-treino), e a redução em capacidade absorvida pelo LoRA deixa de ser um fator limitante nesse regime. O ganho prático é em memória: como apenas as matrizes de adaptação têm gradiente e estado de otimizador, modelos de 1T parâmetros chegam a caber em uma única máquina com 8 B300s para a etapa de update, eliminando a necessidade de paralelismo entre máquinas no atualizador. Ver a análise da Thinking Machines para mais discussão.
A conclusão prática é uma divisão por estágio. Usamos TPU para os estágios de absorção massiva de informação (pré-treino e SFT), e usamos GPU, ou uma combinação dos dois, para o estágio de geração intensiva, que é o RL.
Cluster híbrido: GPUs compartilhadas entre desenvolvimento e produção
Pré-treino e SFT acontecem em TPU. Mas RL, rescritas de dados de pré-treino, avaliações em batch e, o mais importante, servir os modelos para clientes em produção rodam em GPU. A pergunta natural é: você aluga GPUs separadas para inferência e para desenvolvimento?
Nossa estratégia é diferente. Mantemos contratos de GPUs de longa duração, compartilhados entre treino/desenvolvimento e produção/inferência. Nos horários e dias em que o uso de clientes é naturalmente menor (madrugada, finais de semana), as GPUs ociosas rodam rescritas, RL e avaliações. Quando o tráfego sobe, esses processos de desenvolvimento são preemptados: as GPUs voltam pra inferência em produção. É a mesma ideia de TPUs preemptíveis, mas aplicada internamente: o desenvolvimento sempre cede passagem pro cliente pagante.
Figura 9: curva fictícia de carga ao longo de 24 horas. A produção ocupa o pico do dia comercial; à noite e na madrugada, o desenvolvimento (RL, rescritas, avaliações) toma quase todo o cluster. A capacidade contratada permanece constante; o que muda é a divisão entre os dois usos.
O ganho dessa estrutura é direto: a maior parte do tempo, GPUs que estariam ociosas estão produzindo dado de treino ou rodando RL. E a mesma máquina vira inferência sob carga sem precisar de provisionamento extra. O custo: o pipeline de desenvolvimento precisa tolerar exatamente os mesmos requisitos das TPUs preemptíveis, ou seja, checkpoints frequentes e retomada confiável.
Fechando o ciclo
Treinado o modelo, voltamos ao Passo 1. Reabrimos a lista de capacidades que queremos atacar na próxima geração. Parte vem dos benchmarks da rodada que acabamos de rodar, identificando onde o modelo ainda fica abaixo do estado da arte. Outra parte vem das novas funcionalidades e classes de tarefa que decidimos resolver: algumas porque a concorrência acabou de cobri-las, outras porque ninguém ainda atende bem e queremos abrir um diferencial. Esses dois conjuntos juntos alimentam a próxima iteração: mais dados, novas reescritas, um SFT adicional, uma nova função de recompensa. E o ciclo recomeça.
É essa disciplina de medir antes de treinar e iterar até superar a fronteira no benchmark que sustenta nossa filosofia: cada nova versão do Sabiá é o resultado de centenas de pequenas voltas desse ciclo, expandindo o conjunto de tarefas que o modelo resolve bem.
Mas iterar tanto sobre os mesmos benchmarks produz, inevitavelmente, um overfit natural ao alvo da medição. Os ganhos observados podem refletir, em parte, a especialização do modelo nos próprios itens que estamos usando para avaliá-lo, e não uma generalização para tarefas novas dentro da mesma classe. A nossa estratégia para combater isso é criar novos benchmarks de forma constante, priorizando a diversidade dentro de cada capacidade que estamos avaliando, para que cada geração seja colocada em cheque também por avaliações que ainda não influenciaram a receita. Não é um problema que se resolve uma vez: exige esforço contínuo de revisão e crítica dos benchmarks que usamos, e da disposição de abandonar (ou reformular) os que deixam de medir o que importa.
Relatórios técnicos das gerações Sabiá
Para mais detalhes sobre dados, decisões de treino e resultados em benchmarks de cada geração da família Sabiá, consulte os relatórios técnicos:
- Sabiá: Portuguese Large Language Models (2023): arxiv.org/abs/2304.07880
- Sabiá-2: A New Generation of Portuguese Large Language Models (2024): arxiv.org/abs/2403.09887
- Sabiá-3 Technical Report (2024): arxiv.org/abs/2410.12049
- Sabiá-4 Technical Report (2026): arxiv.org/abs/2603.10213