O 0.3.0 chegou. É uma versão minor no número — mas o que foi corrigido não é trivial.
Alguns padrões estavam errados desde o começo. Não eram visíveis no caminho feliz. São o tipo de coisa que aparece quando o projeto cresce e alguém começa a usar de verdade. Prefiro corrigir agora do que fingir que não vi.
Você não precisa mais escolher um algoritmo
algorithm virou opcional no defineModel().
Antes, você declarava um algoritmo explicitamente. Razoável se você conhece seus dados. Mas na maior parte do tempo — especialmente no início de um projeto — você está chutando. E o chute frequentemente está errado: um random forest pode perder feio pra uma regressão linear no seu dataset específico.
Omitiu o campo? O PrisML chama o FLAML (Fast and Lightweight AutoML, da Microsoft Research). Você passa dados rotulados e um orçamento de tempo — 60 segundos, por exemplo — ele testa combinações de algoritmos e configurações, mantém o que performa melhor e devolve o modelo resultante. É busca sistemática num espaço bem definido, com orçamento explícito.
Na prática, a definição do modelo fica mais limpa:
export const churnModel = defineModel<User>({
name: 'churnRisk',
modelName: 'User',
output: {
field: 'willChurn',
taskType: 'binary_classification',
resolver: (u) => u.cancelledAt !== null,
},
features: {
daysActive: (u) => (Date.now() - u.createdAt.getTime()) / 86_400_000,
loginFrequency: (u) => u.logins.length,
planTier: (u) => u.subscription.tier,
monthlySpend: (u) => u.totalSpend / u.monthsActive,
},
qualityGates: [
{ metric: 'f1', threshold: 0.85, comparison: 'gte' },
],
});
O prisml train te mostra o que foi escolhido:
◉ Treinando churnRisk (FLAML AutoML, 60s)...
✔ Melhor estimador: LGBMClassifier
Esse nome fica armazenado nos metadados do artefato. Se você já fez benchmark e sabe que gbm vence nos seus dados, o override explícito continua funcionando igual.
Features estavam sendo codificadas errado
Dois bugs silenciosos aqui.
Strings. A versão anterior fazia label encoding: "premium" virava 3, "free" virava 7, "enterprise" virava 1. O problema clássico disso: o modelo passa a tratar "enterprise" como mais próximo de "premium" do que de "free", porque os números dizem isso. Essa ordenação não existe. Agora é one-hot encoding — cada categoria vira sua própria coluna binária. Sem relações inventadas.
Números. monthlySpend variando de 5 a 5000, loginFrequency de 0 a 30. Sem escalonamento, a primeira feature domina qualquer modelo baseado em distância só pela magnitude — independente de qual seja mais relevante. O PrisML agora calcula média e desvio padrão no treino e aplica (valor - média) / desvio na inferência. As estatísticas ficam armazenadas nos metadados junto com as listas de categorias. Nada para gerenciar manualmente.
Modelos de árvore são relativamente tolerantes a esses problemas. Mas o FLAML pode escolher um modelo linear ou uma SVM — e aí encoding correto faz diferença real. Vale acertar independente do algoritmo escolhido.
O runtime ONNX estava errado
O PrisML carregava modelos com onnxruntime-web. Esse é o pacote pro browser — roda em WebAssembly, foi projetado pra aba de navegador.
O PrisML roda em Node.js. O pacote correto é onnxruntime-node, com bindings nativos e substancialmente mais rápido. O runtime web executava em Node em algumas condições, por isso nunca explodiu com erro explícito. Mas era a dependência errada, rodando fora do ambiente pra qual foi projetada.
Corrigido. O 0.3.0 depende de onnxruntime-node diretamente.
O hash de schema era amplo demais
Cada artefato carrega um hash do schema Prisma. No carregamento, o schema atual é hasheado e comparado com o valor armazenado. Se divergir, inferência rejeitada. A proteção contra drift de schema funciona bem na teoria.
O problema: estava hasheando o arquivo inteiro. Adicionou uma tabela Log não relacionada? Novo índice em User.email? Todos os artefatos falhavam com SchemaDriftError, mesmo que nada relevante ao modelo tivesse mudado.
Agora o hash cobre apenas o bloco do modelo treinado e os enums que ele referencia. Mudanças em modelos não relacionados não invalidam mais seus artefatos.
Artefatos antigos ainda carregam. O campo metadataSchemaVersion diz ao runtime qual estratégia de hash aplicar. Sem migração necessária.
O que não mudou
A API é a mesma. defineModel, PredictionSession, load, predict, predictBatch, quality gates — nada disso foi tocado. Modelos treinados com 0.1.x ainda carregam.
As únicas mudanças breaking estão nos tipos TypeScript: AlgorithmConfig.version foi removido (nunca era lido de fato), e alguns campos internos em EncodedFeature e ModelMetadata agora são obrigatórios.
O objetivo desta release era simples: corrigir o que estava silenciosamente errado antes de continuar construindo.
npm install @vncsleal/prisml@latest
Código no GitHub.