Modelos maiores, erros mais seguros: o paradoxo da confiança em LLMs
Quanto maior o modelo, mais convicto ele fica, e mais caro fica o erro. Entenda como a calibração falha em escala e o que fazer para não depender de respostas que soam certas.
Novo: Eficify One em beta aberto. Crie seu primeiro ambiente sem cartão.Conhecer a plataforma →

Receita Federal confirmou a transição para CNPJ alfanumérico. Para engenharia, isso não é só uma 'mudança de máscara de input'. É refazer validação, migrar schema, ajustar regex, rever integrações e testar em cascata. Em sistemas legados com 10+ anos de dados, o estrago pode passar despercebido até o primeiro CNPJ com letra chegar em produção. Vamos direto ao que importa: o que muda, onde quebra e o que fazer.
Receita Federal publicou a instrução normativa que oficializa o CNPJ alfanumérico. O formato antigo tinha 14 dígitos (XX.XXX.XXX/XXXX-XX). O novo permite 12 caracteres, misturando números e letras do alfabeto maiúsculas (A-Z, excluindo K, W, Y por enquanto). Para engenharia, isso significa que toda suposição de "CNPJ = 14 números" que existe no seu codebase vai quebrar em algum momento.
Especificamente, o novo dígito verificador usa módulo 11 com pesos que incluem o valor ASCII das letras (convertido para número). Se o seu algoritmo atual faz só operações aritméticas simples em inteiros, ele não vai funcionar.
O algoritmo atual do CNPJ brasileiro usa dois módulos 11 com pesos decrescentes de 2 a 9. Com letras, essa lógica precisa mudar. A Receita Federal definiu que:
// Algoritmo de validação CNPJ alfanumérico (TypeScript)
function mapearValorCaractere(c: string): number {
const mapa: Record<string, number> = {
'A': 0, 'B': 1, 'C': 2, 'D': 3, 'E': 4, 'F': 5, 'G': 6, 'H': 7, 'I': 8, 'J': 9,
'L': 10, 'M': 11, 'N': 12, 'O': 13, 'P': 14, 'Q': 15, 'R': 16, 'S': 17, 'T': 18,
'U': 19, 'V': 20, 'X': 21, 'Z': 22
};
return mapa[c] ?? parseInt(c, 10);
}
function validarCnpjAlfanumerico(cnpj: string): boolean {
const digits = cnpj.replace(/[^A-Z0-9]/gi, '').toUpperCase();
if (digits.length !== 14) return false;
const valores = digits.split('').map(mapearValorCaractere);
// Cálculo do primeiro dígito verificador
const pesos1 = [5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2];
const soma1 = valores.slice(0, 12).reduce((acc, v, i) => acc + v * pesos1[i], 0);
const dv1 = (11 - (soma1 % 11)) % 11;
// Cálculo do segundo dígito verificador
const pesos2 = [6, 5, 4, 3, 2, 9, 8, 7, 6, 5, 4, 3, 2];
const soma2 = valores.slice(0, 13).reduce((acc, v, i) => acc + v * pesos2[i], 0);
const dv2 = (11 - (soma2 % 11)) % 11;
return dv1 === valores[12] && dv2 === valores[13];
}
Repare que o regex de sanitização agora precisa aceitar letras, não só dígitos. Isso impacta tudo que faz replace(/\D/g, '') esperando só números.
CNPJs numéricos frequentemente vivem em NUMBER(14) ou VARCHAR(14) em Oracle, PostgreSQL e MySQL. Com alfanumérico, não tem volta para NUMBER. A migração de NUMBER(14) para VARCHAR(14) pode parecer simples, mas:
WHERE cnpj = 12345678000123 vão quebrar silenciosamente se não houver casting explícito.LENGTH(cnpj) = 14 continuam válidas, mas validações via domínio ou enum que dependam de dígitos específicos vão precisar de update.-- Migração segura de NUMBER(14) para VARCHAR(14)
-- Passo 1: adicionar coluna temporária
ALTER TABLE clientes ADD COLUMN cnpj_novo VARCHAR(18);
-- Passo 2: migrar dados com conversão explícita
UPDATE clientes SET cnpj_novo = LPAD(cnpj::TEXT, 14, '0');
-- Passo 3: verificar consistência antes de trocar
SELECT COUNT(*) FROM clientes WHERE LENGTH(cnpj_novo) != 14;
-- Passo 4: swap com lock mínimo
BEGIN;
ALTER TABLE clientes RENAME COLUMN cnpj TO cnpj_old;
ALTER TABLE clientes RENAME COLUMN cnpj_novo TO cnpj;
ALTER TABLE clientes DROP COLUMN cnpj_old;
COMMIT;
A recomendação prática: vá para VARCHAR(18). Deixa espaço para máscaras e futuras expansões de formato.
A maioria das máscaras de CNPJ usa bibliotecas como inputmask ou cleave.js configuradas para 14 dígitos. Com alfanumérico:
// Máscara antiga (só números)
new Inputmask('99.999.999/9999-99');
// Nova máscara para CNPJ alfanumérico
new Inputmask({ mask: 'AA.AAA.AAAA/AAAA-AA', greedy: false, placeholder: '' });
Validação client-side precisa do mesmo algoritmo do backend. Se você tem duplicação de lógica (validação no frontend diferente do backend), agora é hora de consolidar. Library como utils-cnpj no npm centraliza a regra e elimina inconsistência entre React, Angular ou Vue.
flowchart TD
A[CNPJ Alfanumérico] --> B[Máscara de Formulário]
B --> C[Validação Regex]
C --> D[Algoritmo Dígito Verificador]
D --> E[Banco de Dados]
E --> F[APIs e Integrações]
F --> G[Sistemas Legados]
style A fill:#1565C0,stroke:#0D47A1,color:#fff
style B fill:#1E88E5,stroke:#1565C0,color:#fff
style C fill:#1E88E5,stroke:#1565C0,color:#fff
style D fill:#1E88E5,stroke:#1565C0,color:#fff
style E fill:#1E88E5,stroke:#1565C0,color:#fff
style F fill:#1E88E5,stroke:#1565C0,color:#fff
style G fill:#E65100,stroke:#BF360C,color:#fffA parte mais traiçoeira. CNPJ viaja como parâmetro de query, body JSON, headers, arquivos CSV e mappings de ETL. Em cada ponto, a suposição "14 dígitos numéricos" está codificada:
type: integer ou pattern: "^[0-9]{14}$" vai rejeitar novos CNPJs com letras.CAST(cnpj AS BIGINT) vão dar overflow. Transformações em Apache Airflow, dbt ou Spark que esperam tipo numérico vão falhar.O erro mais caro não é o código novo quebrando. É o sistema legado que recebe um CNPJ alfanumérico, não valida, e insere dado sujo na base que só aparece três meses depois num relatório de compliance.
# □ Algoritmo de dígito verificador atualizado para aceitar letras
# □ Regex de sanitização alterado de \D para [^A-Z0-9]
# □ Biblioteca de validação centralizada (sem duplicação frontend/backend)
# [ ] Banco de dados
# □ Colunas CNPJ migradas de NUMBER para VARCHAR
# □ Índices recompostos após mudança de tipo
# □ Queries com cast explícito revisadas
# □ Constraints de CHECK atualizadas
# □ Dados legados verificados (e conteúdo)
# [ ] Frontend
# □ Máscaras de formulário atualizadas para padrão alfanumérico
# □ Estados de erro de validação ajustados
# □ Comprimento máximo do campo aumentado
# [ ] APIs e integrações
# □ Contratos OAS/AsyncAPI atualizados (tipo string, não integer)
# □ Schemas de serializers ajustados
# □ Data pipelines (Airflow, dbt, Spark) revistos
# □ Consumers de fila com validação de schema testados
# □ Mapeamentos de integração com sistemas externos verificados
# [ ] Testes
# □ Suite de testes com CNPJs alfanuméricos de exemplo
# □ Testes de regressão em workflows de criação/atualização
# □ Testes de performance em queries com novo tipo VARCHAR
# [ ] Monitoramento
# □ Alertas para erros de validação de CNPJ em produção
# □ Dashboard de CNPJs inválidos ou mal formatados
# □ Log de rejeições por tipo de erro
A transição para CNPJ alfanumérico não é cosmeticamente simples. Ela força revisão de validação, schema, integrações e monitoramento. A decisão correta é tratar isso como migration de breaking change, com versioning de API, testes de carga e plano de rollforward. Quem esperar o primeiro CNPJ com letra chegar em produção vai gastar o triplo para corrigir.
No final, o ponto técnico central é este: paramos de tratar CNPJ como número e passamos a tratá-lo como string estruturada. Isso é uma mudança de mentalidade, não só de regex.
Se a sua base tem CNPJs em campos NUMBER(14) ou VARCHAR(18) com máscara, provavelmente tem pontos cegos. Em 30 minutos, podemos mapear onde o risco está e o que precisa mudar antes que vire incidente em produção.
CONTINUE LENDO
Quanto maior o modelo, mais convicto ele fica, e mais caro fica o erro. Entenda como a calibração falha em escala e o que fazer para não depender de respostas que soam certas.
Como projetar sistemas de memória para agentes de IA que escalam sem explodir em custo, preservam privacidade e entregam coerência em conversas longas.
A demo encanta, a produção cobra. Integração, segurança, custo de inferência, RAG e monitoramento: o que separa o piloto de uma solução que funciona todo dia.
VAMOS CONVERSAR
Conte seu cenário e veja como estruturar dados, IA e machine learning que funcionam em produção.
Falar sobre dados e IA