Como usar o Jev para categorizar o catálogo de produtos do seu e-commerce

O Jev é o primeiro modelo System One da TypeSafe AI: em vez de texto livre, ele devolve decisão tipada com probabilidade por opção, e os valores válidos saem do schema da pergunta. Pra categorizar catálogo de produtos com o Jev, a receita é quebrar a decisão em pedaços: um Choice com a lista completa de categorias (até 255 opções, mais uma de escape), Noul pras flags sim/não e Score pras rubricas ordenadas, tudo numa chamada só. Aí você lê response.answers[id] e grava tipado no banco, mandando os itens de baixa confiança pra revisão humana.
Todo catálogo de e-commerce tem aquele título que ninguém quer categorizar na mão: "kit 3 camiseta masculina algodão premium tam G"
É kit ou item unitário? É vestuário masculino ou é "kits e combos"? O tamanho é atributo ou faz parte do nome? 😅
Categorizar errado custa caro: o produto some do filtro, cai na busca errada, vai pro frete errado e ninguém descobre até o cliente reclamar
O Jev é o primeiro modelo System One da TypeSafe AI, e ele resolve exatamente esse tipo de problema: em vez de cuspir um parágrafo que você depois tem que parsear, ele devolve decisões tipadas com probabilidades calibradas, e os valores válidos são definidos ANTES, no schema da pergunta
Ou seja: o modelo não inventa categoria nova, ele escolhe entre as suas
Neste post vou montar o passo a passo de categorização de catálogo, da montagem do state até a saída tipada que entra direto no banco, incluindo o que fazer com os itens que o modelo não teve certeza
Bora?
O que você precisa antes de começar
Antes do código, o básico:
- Acesso ao modelo: o Jev saiu do stealth em 15/09/2026 e segue em early access, com lista de espera em
typesafe.ai. A TypeSafe vai liberando desenvolvedores em ondas, então esse é o primeiro passo mesmo - Chave de API exportada na variável de ambiente
TYPESAFE_API_KEY, que é o que o cliente lê sozinho - SDK: em Python é
pip install typesafe-sdk(requer Python >= 3.10). Em JavaScript/TypeScript énpm install @typesafe-ai/sdk, com Node 20 ou superior - Modelo: o padrão do cliente Python é o alias
jev-latest, e a versão corrente é ajev-1.13, publicada em 18/09/2026. Dá pra fixar um ID versionado no campomodelse você quiser estabilidade
Os repositórios oficiais são o typesafe-sdk-python e o typesafe-ai/typesafe-sdk-js, e o pacote publicado no PyPI é o typesafe-sdk
Duas limitações que mudam o seu desenho de catálogo:
Essas duas aqui valem ler DUAS vezes antes de arquitetar o pipeline
Primeira: o state aceita só texto. String, objeto JSON ou array de textos
Imagem, áudio e vídeo não são suportados
Traduzindo: a foto do produto não entra na decisão. Se o título é ruim e a descrição é vazia, o Jev tem pouco com o que trabalhar, e isso não é culpa do modelo
Segunda: o orçamento de contexto é de 64.000 tokens para state mais todas as perguntas, com um limite separado de 32.000 tokens para o state mais a pergunta mais longa
Então despejar a descrição HTML inteira do fornecedor no state é pedir dor de cabeça

Domine o Jev e coloque decisões de IA dentro do seu sistema
Você vai aprender a usar o Jev, o System One Model da TypeSafe AI, pra automatizar decisões com resposta tipada e confiança medida, sem depender de chat nem de alguém revisando cada passo. Entre na lista de espera para garantir a condição de lançamento!
Passo a passo: categorizando o catálogo com o Jev
A ideia central é uma só: não faça uma pergunta gigante, faça várias pequenas
Se você conhece aquele papo de função pequena que faz uma coisa só, é exatamente a mesma cabeça aqui, só que pra decisão
- Monte o state a partir da linha do produto
O state é o contexto que o modelo lê. Pra catálogo, o natural é montar um JSON com os campos que você já tem no banco
import os
from typesafe_sdk import Choice, Noul, Score, TypeSafeClient
client = TypeSafeClient() # lê TYPESAFE_API_KEY do ambiente
produto = {
"titulo": "kit 3 camiseta masculina algodao premium tam G",
"descricao": "Kit com 3 camisetas basicas 100% algodao penteado 30.1...",
"marca": "Generica",
"fornecedor_categoria": "MODA / MASC / BASICOS",
}
state = produto
Repara que eu mandei até a categoria porca do fornecedor. Ela é bagunçada, mas é sinal, e sinal ruim ainda é sinal 🙂
O erro comum deste passo: jogar a descrição completa com HTML, tabela de medidas e política de troca dentro do state. Você estoura orçamento de contexto à toa e ainda enche a decisão de ruído. Limpe o HTML e corte o que é boilerplate da loja
- Quebre a categorização em decisões menores
Categorizar produto não é UMA pergunta, são várias:
- qual categoria
- é kit ou unitário
- é infantil
- precisa de bateria
- quão detalhado está o anúncio
Cada uma dessas vira uma primitiva. E tudo que você pergunta ao Jev é uma de três: Choice, Score e Noul
Choice pra escolher entre opções nomeadas, Score pra posição numa rubrica ordenada e Noul pra afirmação sim/não
O erro comum deste passo: tentar resolver categoria, subcategoria, atributos e flags num Choice só com 900 combinações. Além de estourar o limite de opções, você perde a probabilidade individual de cada decisão, que é justamente o que dá o controle depois
- Primeiro Choice: a categoria, com a lista COMPLETA
Um Choice aceita até 255 opções e cada opção custa poucos tokens
Por isso a própria doc recomenda passar a lista completa de categorias em vez de montar um shortlist antes. Deixa o modelo ver todo mundo
E tem um detalhe que salva catálogo: a doc recomenda incluir uma opção de escape, tipo other ou "nenhuma das anteriores", quando a lista pode não cobrir toda entrada
Além disso, instructions, opções de Choice, níveis de Score e critérios de Noul aceitam estrutura JSON. A descrição de uma opção pode ser um objeto dizendo o que ela cobre e o que NÃO cobre
Isso é ouro pra desambiguar fronteira de categoria
categoria = Choice(
criteria="Em qual categoria do catalogo este produto se encaixa?",
options={
"vestuario_masculino": {
"cobre": "camisetas, camisas, calcas e bermudas adulto masculino",
"nao_cobre": "roupa infantil, calcados, acessorios, moda intima",
},
"vestuario_infantil": {
"cobre": "roupas para bebes e criancas",
"nao_cobre": "roupa adulta tamanho P",
},
"calcados": {
"cobre": "tenis, sapatos, sandalias, chinelos",
"nao_cobre": "meias, palmilhas, produtos de limpeza de calcado",
},
# ... o resto da sua taxonomia aqui
"outros": "nao se encaixa em nenhuma das opcoes acima",
},
)
O Choice devolve uma probabilidade para cada opção, mais a opção de maior pontuação, mais um campo de confiança derivado da concentração da distribuição
O erro comum deste passo: esquecer a opção de escape. Sem ela, o produto esquisito é empurrado à força pra categoria menos errada, e você nunca descobre que ele existe
- Atributos e flags: Noul e Score
Noul recebe uma afirmação sim/não e devolve um único número: a probabilidade de ela ser verdadeira
Ele não tem campo de confiança separado, porque a própria probabilidade JÁ é a resposta. Perto de 0,5 é o modelo dizendo "não faço ideia"
Score devolve uma posição nos níveis que você define, calculada como média ponderada por probabilidade
perguntas = {
"categoria": categoria,
"eh_kit": Noul(
criteria="O anuncio vende mais de uma unidade do mesmo item em um pacote (kit/combo)"
),
"eh_infantil": Noul(
criteria="O produto e destinado a bebes ou criancas"
),
"precisa_bateria": Noul(
criteria="O produto precisa de pilha ou bateria para funcionar"
),
"qualidade_anuncio": Score(
criteria="Quao completo esta o anuncio para publicar sem revisao",
levels=[
"so o titulo, sem atributos",
"titulo e descricao curta, faltam atributos",
"titulo, descricao e alguns atributos",
"completo: titulo, descricao, material, tamanho e composicao",
],
),
}
Esse Score de "qualidade do anúncio" é de graça em termos de arquitetura e paga sozinho: ele vira a sua fila de enriquecimento de catálogo
A mesma cabeça de rubrica ordenada aparece quando você usa o Jev para qualificar leads, só muda o objeto da decisão
O erro comum deste passo: escrever Noul com afirmação ambígua, tipo "o produto é bom". Noul é afirmação verificável no texto, não opinião
- Junte tudo numa chamada só
Aqui tá o pulo do gato
Todas as perguntas de uma mesma chamada são avaliadas em paralelo e isoladamente contra o mesmo state. O state é lido UMA vez, e adicionar perguntas quase não muda o tempo de resposta
response = client.system_one(
state=state,
questions=perguntas,
)
No cookbook oficial de perguntas paralelas, juntar 13 perguntas em uma chamada levou 0,27 s contra 2,71 s de 13 chamadas separadas, sem mudar as respostas: 12,2x mais barato e 10,0x mais rápido
O erro comum deste passo: fazer um for em cima das perguntas e disparar uma requisição por atributo. Funciona, mas você paga a leitura do state N vezes e ainda se aproxima do rate limit sem necessidade
- Leia tipado e grave tipado
As respostas saem em response.answers, indexadas pelo ID da pergunta, com a propriedade choice, score ou noul conforme a primitiva
categoria_final = response.answers["categoria"].choice
confianca_categoria = response.answers["categoria"].confidence
eh_kit = response.answers["eh_kit"].noul > 0.8
qualidade = response.answers["qualidade_anuncio"].score
linha = {
"sku": produto_id,
"categoria": categoria_final,
"categoria_confianca": confianca_categoria,
"flag_kit": eh_kit,
"score_qualidade": qualidade,
}
Não tem regex de saída, não tem "o modelo respondeu com markdown de novo", não tem json.loads dentro de try/except rezando pra dar certo
A categoria já vem como uma das chaves que VOCÊ definiu, o que significa que um INSERT direto é seguro
O erro comum deste passo: gravar só o rótulo e jogar a confiança fora. Sem esse número você não consegue calibrar nada depois, e vai ter que reprocessar o catálogo inteiro. Guarda a confiança, sempre
Como descer na taxonomia: hierarquia com beam search
Catálogo sério não tem 30 categorias planas, tem árvore
Departamento, categoria, subcategoria, tipo de produto
O jeito de navegar isso é em loop: depois de escolher o departamento, você faz o próximo Choice com os FILHOS daquele nó como opções e as subárvores como valores, repetindo até chegar na folha
O criteria de cada passo é o nó atual
def descer_taxonomia(client, state, arvore):
caminho = []
no = arvore
while isinstance(no, dict) and no:
pergunta = Choice(
criteria=f"Dentro de '{caminho[-1] if caminho else 'raiz'}', qual o melhor no para este produto?",
options={nome: {"cobre": nome} for nome in no.keys()},
)
r = client.system_one(state=state, questions={"nivel": pergunta})
escolha = r.answers["nivel"].choice
caminho.append(escolha)
no = no.get(escolha, {})
return caminho
Essa versão aí em cima é gulosa: ela escolhe o melhor de cada nível e segue
E guloso tem um problema clássico: errou o departamento, errou tudo pra baixo, sem volta
Por que beam search é melhor aqui:
Existe um cookbook oficial de classificação hierárquica que percorre a taxonomia com beam search em cima das probabilidades do Choice
A ideia: em vez de manter só 1 caminho, você mantém os K melhores, e pontua cada caminho pela média geométrica das probabilidades de aresta, normalizada pelo comprimento:
score = product(edge_probabilities) ** (1 / decisions)
A normalização pelo número de decisões é o que impede que caminho curto ganhe de caminho longo só por ter multiplicado menos números
No comparativo do próprio cookbook, o resultado foi esse:
| Estratégia | Folhas corretas |
|---|---|
| Beam search | 4 de 4 |
| Busca gulosa | 2 de 4 |
O cookbook usa, entre outras taxonomias, a de produtos de varejo da Shopify (versão 2026-02), indo de departamento de loja até o tipo específico de produto
Ou seja: é exatamente o formato de árvore que um catálogo de e-commerce de verdade tem
O erro comum deste passo: montar a lista de opções de cada nível com nome de nó e mais nada. Lembra que a descrição de opção aceita JSON com o que cobre e o que não cobre? É nos níveis intermediários da árvore que isso rende mais, porque é ali que "Acessórios" e "Roupas" brigam pelo mesmo produto
Extraindo atributos numéricos sem depender do modelo para contar
Agora a parte que muita gente erra feio
Voltagem, tamanho, quantidade de peças, medidas em cm, peso
A página de limitações do jev-1.13 é bem clara: o modelo não conta de forma confiável. Caracteres, ocorrências de um termo, itens de uma lista longa, e o erro cresce com o tamanho do que está sendo contado
A mesma página avisa que ele lê datas como texto, não como quantidades ordenadas, e que os níveis do Score são fracos em calibração numérica, então não dá pra reconstruir um número exato interpolando entre dois níveis
Tome cuidado! Se você pedir "quantas peças tem o kit" como Score, você vai levar número errado com cara de número certo
A solução: regex acha, Jev escolhe, código normaliza
Existe um cookbook oficial de extração de valores pré-parseados que resolve isso de um jeito elegante
O regex encontra TODOS os candidatos no texto, o Jev só escolhe qual deles é o trecho pedido, e a normalização do valor literal fica com o código
O modelo faz o que ele é bom (decidir), o regex faz o que ele é bom (achar padrão), e a matemática fica com a linguagem, que nunca erra conta
import re
texto = produto["titulo"] + " " + produto["descricao"]
candidatos = re.findall(r"\d+[.,]?\d*\s?(?:pecas|un|unidades|x)", texto, flags=re.I)
opcoes = {c: {"trecho": c} for c in set(candidatos)}
opcoes["nenhum"] = "nenhum dos trechos indica a quantidade de pecas do kit"
qtd = Choice(
criteria="Qual destes trechos informa a QUANTIDADE DE PECAS incluidas no kit?",
options=opcoes,
)
r = client.system_one(state=state, questions={"qtd": qtd})
trecho = r.answers["qtd"].choice
# a conversao fica com o Python, nao com o modelo
quantidade = int(re.search(r"\d+", trecho).group()) if trecho != "nenhum" else None
Repara que a opção de escape voltou. Ela é obrigatória aqui, porque metade dos títulos de catálogo não tem a informação
O erro comum deste passo: mandar o modelo "extrair o número" em vez de "escolher o trecho". São coisas diferentes: escolher é decisão tipada, extrair é geração de texto, e o Jev não gera texto livre
O que fazer com os itens de baixa confiança
Confiança não é erro, é parte do fluxo
Relembrando: Choice e Score trazem um campo de confiança derivado da concentração da distribuição. Noul não tem campo separado, porque a própria probabilidade é a resposta
Sintoma: metade do catálogo saiu categorizada de um jeito esquisito
Causa: você tratou todas as respostas como iguais e gravou tudo automaticamente
O modelo respondeu a mesma coisa nos dois casos: o item óbvio e o item que ele chutou entre duas categorias parecidas. A diferença estava na distribuição, e você ignorou ela
Tem número público sobre isso. No cookbook de classificação por confiança, um corte em 0,9 divide um conjunto de 60 documentos ao meio: a metade confiante acerta 90%, e a outra metade acerta 40%
Ou seja: com UM campo que você já recebe de graça, dá pra separar o que é seguro do que é aposta
Solução: três faixas de comportamento, que é o que a doc de confiança recomenda:
- Alta: agir automaticamente. Grava a categoria no banco e segue a vida
- Média: prosseguir com cautela. Confirmar, sinalizar para revisão ou buscar mais contexto (puxar a descrição completa do fornecedor, por exemplo)
- Baixa: mandar para humano, pedir esclarecimento ou cair em outro sistema
E o mais importante: o limiar não é um número único
A orientação é testar os limiares plotando confiança contra acurácia nos SEUS dados, e escalar os casos incertos para uma pessoa ou para um modelo de raciocínio mais caro
O 0,9 do cookbook é o corte do cookbook, não o seu. Seu catálogo, seus dados, seu corte
Sintoma: a fila de revisão humana ficou gigante
Causa: você está tratando "incerto" como binário. Ou o item tem categoria folha, ou ele vai pra fila
Solução: o truque do fallback hierárquico
No mesmo cookbook, quando o rótulo é reportado um nível ACIMA na hierarquia, aqueles 40% de acerto viram 70%
Na mesma resposta, sem segunda chamada
Faz todo sentido: o modelo pode não ter certeza se é "camiseta manga curta" ou "camiseta regata", mas ele tem bastante certeza de que é "camiseta"
O cookbook fecha com uma função classify() que devolve o rótulo mais o quão específico ele é, com uma requisição por documento. Quando o modelo não tem certeza do grupo, ele reporta a divisão acima
Na prática do catálogo, isso significa: o produto entra publicado em "Camisetas" em vez de ficar invisível na fila esperando alguém decidir se é regata
E aí a revisão humana vira refinamento, não desbloqueio
O que mais dá para automatizar no catálogo
A doc lista e-commerce e marketplaces entre os casos de uso oficiais, especificamente:
- classificar e normalizar anúncios de catálogos inconsistentes
- extrair atributos de produto de títulos e descrições
- rotear anúncios incertos para revisão humana
O pipeline que você montou aí em cima já cobre os três. O que sobra é derivar mais perguntas em cima do MESMO state, e isso é quase de graça em tempo de resposta
Algumas extensões que caem bem:
- Flags de moderação no anúncio: promessa proibida, termo de marca registrada usado indevidamente, contato fora da plataforma. O raciocínio é o mesmo de quando você usa o Jev para moderar conteúdo de usuários, só que o "usuário" aqui é o seller
- Enriquecimento de filtro de busca: material, ocasião de uso, público, estilo. Cada um vira um Choice com a lista fechada de valores que o seu filtro aceita
- Detecção de duplicata de sentido: flags de "este anúncio é o mesmo produto do fornecedor X" como Noul
A conta de custo e velocidade:
O preço público do Jev cobra só entrada: US$ 0,042 por 1 milhão de tokens de entrada e US$ 0,00 por 1 milhão de tokens de saída
Saída zero muda o desenho, porque a parte cara de LLM normalmente é a geração, e aqui não tem geração
A latência medida em cookbook da própria TypeSafe pra ida e volta de um Choice é de 114 ms em média com jev-latest
E o ganho de juntar perguntas, de novo, pra fixar:
| Formato | Tempo (13 perguntas) |
|---|---|
| 1 chamada com 13 perguntas | 0,27 s |
| 13 chamadas separadas | 2,71 s |
Os números de workflow que a TypeSafe divulga na imprensa são bem maiores (até 193,6x mais rápido e 444,6x mais barato, segundo a própria empresa), mas isso é comparação do fornecedor, então trata como marketing até você medir no seu caso
Pra escala de catálogo, fica o alerta: os limites de taxa são medidos em tokens por segundo E requisições por minuto, e passar de qualquer um dos dois retorna 429 Too Many Requests
Os limites mudam sem aviso durante o early access, então backoff e retry na sua rotina de batch, sempre
Detalhe: a Vercel afirmou que o Jev virou o modelo de adoção mais rápida da história do AI Gateway deles, o que dá uma ideia de quanta gente entrou na fila de uma vez
Vídeo: e-commerce montado com IA em 28 minutos
Pra quem tá começando do zero e quer ver o outro lado da moeda, a loja em si sendo montada com IA, esse vídeo do canal mostra o ANTIGRAVITY criando um e-commerce inteiro a partir de um prompt só, em 28 minutos
Próximo passo
O caminho prático é esse, na ordem:
- Roda o fluxo num lote PEQUENO de produtos, uns que você já sabe a resposta certa
- Guarda rótulo e confiança lado a lado e plota confiança contra acurácia nos seus dados
- Define suas três faixas com base nesse gráfico, não no número de cookbook de ninguém
- Só então liga a gravação automática no banco, e só pra faixa alta
De cabeça pra baixo (ligar o automático primeiro e calibrar depois) você vai passar a semana seguinte escrevendo script de rollback, e isso não é divertido 😅
E se você vive dentro do Claude Code, a TypeSafe publica uma agent skill oficial no repositório typesafe-ai/skills, com instalação própria:
claude plugin marketplace add typesafe-ai/skills
claude plugin install typesafe@typesafe-ai
A invocação é /typesafe:typesafe-ai
Pra carregar atualização, a doc indica reiniciar o Claude Code ou rodar /reload-plugins, e dá pra habilitar auto-update em /plugin > Marketplaces > typesafe-ai > Enable auto-update
Lembrando que o acesso ao Jev segue em early access com waitlist, então se você ainda não entrou, o passo zero é a fila mesmo
Até o próximo post! =)
Perguntas frequentes
Dá pra categorizar um catálogo inteiro em vários níveis, tipo categoria, subcategoria e tipo específico, numa chamada só?
Sim, existe um cookbook oficial de classificação hierárquica que percorre a taxonomia com beam search sobre as probabilidades do Choice, mantendo os melhores caminhos pela média geométrica das probabilidades de cada aresta. Um exemplo desse cookbook usa a taxonomia de produtos de varejo da Shopify, versão 2026-02, indo do departamento até o tipo específico de produto. No comparativo publicado, o beam search acertou 4 de 4 folhas esperadas contra 2 de 4 da busca gulosa.
O que fazer com os produtos que o Jev classifica com baixa confiança?
A doc recomenda três faixas de comportamento: confiança alta age automaticamente, confiança média prossegue com cautela confirmando, sinalizando pra revisão ou buscando mais contexto, e confiança baixa vai pra humano ou pede esclarecimento. Não existe um limiar único, o ideal é calibrar plotando confiança contra acurácia nos seus próprios dados. Um cookbook mostra um corte de 0,9 dividindo 60 documentos ao meio, onde a metade confiante acerta 90% e a outra 40%, e ao reportar um nível acima na hierarquia esses 40% sobem pra 70%.
Categorizar vários atributos do mesmo produto de uma vez sai mais caro?
Pelo contrário. Todas as perguntas de uma mesma chamada são avaliadas em paralelo contra o mesmo state, que é lido uma única vez. No cookbook de perguntas paralelas da TypeSafe, 13 perguntas numa chamada só levaram 0,27 s contra 2,71 s de 13 chamadas separadas, e o próprio cookbook registra que juntar tudo saiu mais barato e mais rápido, sem mudar as respostas.
O Jev consegue extrair o tamanho ou outro atributo direto do título bagunçado do produto?
Sim, existe um cookbook de extração de valores pré-parseados: regex acha os candidatos no texto, tipo ‘G’ ou ‘P’, e o Choice do Jev escolhe qual trecho é o correto. A normalização final do valor fica por conta do seu código, o modelo só aponta o span certo.
Quanto custa categorizar um catálogo grande com o Jev?
O preço público cobra só a entrada: US$ 0,042 por 1 milhão de tokens, e a saída sai a US$ 0,00. Como cada opção de Choice custa poucos tokens e as perguntas de uma chamada rodam em paralelo sobre o mesmo state, categorizar um catálogo inteiro tende a sair barato comparado a um modelo de texto livre respondendo pergunta por pergunta.
O Jev consegue contar quantas peças tem um kit, tipo ‘kit 3 camisetas’?
Não é o ponto forte dele. A página de limitações do jev-1.13 diz que o modelo não conta de forma confiável caracteres, ocorrências de um termo ou itens de uma lista, e o erro cresce com o tamanho do que está sendo contado. Pra confirmar se o ‘3’ do kit é a quantidade certa, o caminho é regex ou validação separada, não perguntar direto pro Jev.
Formações
Formação Claude Code
Domine Claude Code do absoluto zero até o avançado
- 120 aulas
- 4 projetos
- 9h 45min
Blog | Mais populares

Como montar um workflow de automação combinando decisões do Jev em código
Aprenda a montar um workflow com Jev: decisões tipadas encadeadas em código, alta confiança agindo sozinha e casos incertos escalando para revisão.

Para quem o Jev serve (e para quem não serve)?
Jev serve pra roteamento, scoring e guardrails em IA, não pra texto ou código. Veja pra quem o Jev serve e quando evitar.

Jev decide, LLM escreve: como dividir os papéis dentro de um agente de IA
Jev é o modelo que decide, não escreve: entenda como dividir papéis entre Jev e LLM dentro de um agente de IA e quando usar cada um.
