Como usar o Jev para decidir se vale processar uma página no seu crawler?

O Jev é um modelo da TypeSafe AI lançado em acesso antecipado em 15/09/2026 que não escreve prosa: ele devolve valores tipados com probabilidade, prontos pra outro software consumir. No crawler isso vira um filtro barato antes do pipeline caro: você reduz a página a título, meta, headings e primeiros parágrafos, manda um Noul de relevância e um Choice de categoria numa única requisição, e roteia em código entre relevante, duvidoso e descarte. A entrada custa US$ 0,042 por milhão de tokens e a saída não é cobrada, então filtrar sai muito mais barato que processar lixo
Crawler bom coleta muita página, e coletar é a parte barata da história
O caro vem depois: extração, chunking, embedding, chamada de LLM generativo em cima de página de categoria, paginação, política de privacidade e post de 2014 que não tem nada a ver com o teu tema
Fala aí, beleza? A TypeSafe AI soltou em acesso antecipado, em 15 de setembro de 2026, um modelo chamado Jev que resolve exatamente esse tipo de decisão chata. Ele não gera texto em linguagem natural: retorna valores tipados com estimativas de probabilidade e confiança, feitos pra serem consumidos por outro software. Ou seja, ele não te escreve um parecer bonito sobre a página, ele te dá um número que teu if entende
É um juiz barato na frente da porta do pipeline. Bora montar? 🙂
O que você precisa antes de começar
Conta no console da TypeSafe, em console.typesafe.ai. A fila de espera do Jev caiu em 21 de setembro de 2026, então qualquer pessoa cria conta e recebe US$ 5 de crédito inicial
SDK oficial, se você quiser ir pelo caminho curto:
# Python 3.10+
pip install typesafe-sdk
# ou
uv add typesafe-sdk
# Node 20+
npm install @typesafe-ai/sdk
Os dois SDKs leem a variável de ambiente TYPESAFE_API_KEY e usam jev-latest como modelo padrão. O campo model também aceita ID versionado, tipo jev-1.13.0, que é o que eu recomendo fixar quando o filtro já estiver calibrado em produção (assim uma atualização de modelo não muda teus limiares do nada)
Só pra alinhar o vocabulário antes de seguir: quando eu citar jev-1.13 mais pra frente, é a mesma linha de modelo do jev-1.13.0, é assim que a documentação de jaggedness se refere a ela
Se preferir não falar direto com a API, o Jev também está no Vercel AI Gateway com o identificador typesafe-ai/jev, e ainda em OpenRouter, Netlify AI Gateway e Cloudflare Workers AI
Curso de Jev: Sistemas Mais Inteligentes, Rápidos e Robustos
Desenvolva sistemas mais inteligentes, rápidos e robustos com Jev
E guarda esses tetos num canto da cabeça, porque crawler é justamente o cenário que bate neles:
- 64.000 tokens por requisição
- 32.000 de orçamento pro state mais a pergunta mais longa
- 250.000 tokens por segundo e 1.200 requisições por minuto na conta, ajustados dinamicamente e sujeitos a mudança sem aviso
A TypeSafe informa tempo de resposta ponta a ponta de 70ms a 500ms, o que é a faixa que faz esse filtro caber dentro de um loop de crawling sem virar gargalo
Passo a passo: filtro de relevância antes do pipeline caro
A ideia geral: pra cada página coletada, você manda um pacotinho de texto (o state) e um mapa de perguntas (questions) numa única chamada, lê as probabilidades e decide em código. Simples assim
- Reduza o state em código ANTES de enviar
O state aceita string, objeto JSON ou array de textos, e a entrada é somente texto. Então nada de despejar o HTML inteiro lá dentro
from selectolax.parser import HTMLParser
def montar_state(url: str, html: str) -> dict:
tree = HTMLParser(html)
titulo = tree.css_first("title")
meta = tree.css_first('meta[name="description"]')
headings = [n.text(strip=True) for n in tree.css("h1, h2")][:10]
paragrafos = [n.text(strip=True) for n in tree.css("p")]
paragrafos = [p for p in paragrafos if len(p) > 80][:3]
return {
"url": url,
"title": titulo.text(strip=True) if titulo else "",
"meta_description": meta.attributes.get("content", "") if meta else "",
"headings": headings,
"primeiros_paragrafos": paragrafos,
}
O erro comum deste passo: mandar a página inteira "pra IA ter contexto". A página de jaggedness do jev-1.13 registra que a acurácia cai conforme o state cresce com detalhe não relacionado à pergunta, e a orientação é filtrar antes de enviar, não depois. Menu, rodapé, breadcrumb e bloco de comentários são ruído puro aqui
- Escreva perguntas estreitas e independentes, não uma pergunta guarda-chuva
Em vez de "essa página é boa pro meu projeto?", quebra em critérios:
- Noul: o conteúdo principal desta página trata de desenvolvimento de software e ferramentas de IA?
- Noul: esta página tem conteúdo próprio, em vez de ser uma listagem, índice ou página de navegação?
- Noul: o conteúdo principal está escrito em português?
- Choice: qual categoria descreve melhor o conteúdo principal? (tutorial, notícia, documentação, marketing, outro)
O erro comum deste passo: encadear as perguntas achando que a segunda vai usar a resposta da primeira. Não vai. Todas as perguntas de uma requisição são avaliadas em paralelo contra o mesmo state, de forma independente, e não consomem a resposta uma da outra. Cada pergunta precisa se sustentar sozinha
E se bate a dúvida "mas então perguntar muita coisa não fica caro/lento?": a documentação recomenda justamente fazer muitas perguntas estreitas e independentes sobre o mesmo state numa única requisição, porque decompor não adiciona round trips
- Mande tudo numa chamada só
A API da TypeSafe tem um único endpoint: POST https://api.typesafe.ai/v1/systemone. A requisição é composta pelo state e pelo mapa de questions:
import os, httpx
TEMA = "desenvolvimento de software e ferramentas de IA"
payload = {
"model": "jev-latest",
"state": montar_state(url, html),
"questions": {
"no_tema": {
"type": "noul",
"question": f"O conteudo principal desta pagina trata de {TEMA}?",
},
"tem_conteudo_proprio": {
"type": "noul",
"question": "Esta pagina tem conteudo proprio, em vez de ser apenas uma listagem, indice ou pagina de navegacao?",
},
"em_portugues": {
"type": "noul",
"question": "O conteudo principal desta pagina esta escrito em portugues?",
},
"categoria": {
"type": "choice",
"question": "Qual categoria descreve melhor o conteudo principal desta pagina?",
"options": ["tutorial", "noticia", "documentacao", "marketing", "outro"],
},
},
}
resp = httpx.post(
"https://api.typesafe.ai/v1/systemone",
headers={"Authorization": f"Bearer {os.environ['TYPESAFE_API_KEY']}"},
json=payload,
timeout=10,
)
saidas = resp.json()
Se o teu crawler é Node, dá pra ir pelo Vercel AI Gateway. No AI SDK 7 o Jev é acessado pela API experimental de avaliação, importando experimental_evaluate do pacote ai, com os tipos boolean, choice e score. Se liga nisso: o boolean do AI SDK é o mesmo Noul da API da TypeSafe, muda só o nome do tipo no SDK, a pergunta binária e a leitura da saída são idênticas
import { experimental_evaluate } from 'ai'
const resultado = await experimental_evaluate({
model: gateway.evaluationModel('typesafe-ai/jev'),
state: montarState(url, html),
questions: {
noTema: {
type: 'boolean',
question: 'O conteudo principal desta pagina trata de desenvolvimento de software e ferramentas de IA?'
},
categoria: {
type: 'choice',
question: 'Qual categoria descreve melhor o conteudo principal desta pagina?',
options: ['tutorial', 'noticia', 'documentacao', 'marketing', 'outro']
}
}
})
- Leia as saídas do jeito certo
Esse passo separa quem entendeu o modelo de quem só copiou código
| Tipo | O que é | Como vem a saída |
|---|---|---|
| Noul | sim/não | probabilidade de a resposta ser sim, entre 0 e 1 (perto de 1 é sim claro, perto de 0 é não claro), sem campo de confiança separado |
| Choice | uma opção entre até 255 | probabilidade por opção mais um valor de confiança |
| Score | posição numa escala ordenada de 2 a 10 níveis descrita por você | nível mais um valor de confiança |
A confiança de Choice e Score é derivada da forma da distribuição de probabilidades: distribuição concentrada gera confiança alta, distribuição achatada gera confiança baixa
O erro comum deste passo: procurar um confidence no Noul. Ele não existe ali, a probabilidade JÁ é o sinal. Um Noul em 0,52 está te dizendo "não sei" com todas as letras
- Implemente o roteador de três vias em código
Relevante, duvidoso ou descarte. O Jev entrega o número, a regra é tua:
LIMIAR_RELEVANTE = 0.80
LIMIAR_DESCARTE = 0.35
CONF_MINIMA_CATEGORIA = 0.60
def rotear(saidas: dict) -> str:
p_tema = saidas["no_tema"]["probability"]
p_proprio = saidas["tem_conteudo_proprio"]["probability"]
conf_cat = saidas["categoria"]["confidence"]
if p_tema < LIMIAR_DESCARTE or p_proprio < LIMIAR_DESCARTE:
return "descarte"
if p_tema >= LIMIAR_RELEVANTE and p_proprio >= LIMIAR_RELEVANTE \
and conf_cat >= CONF_MINIMA_CATEGORIA:
return "relevante"
return "duvidoso"
Esses números são chute inicial, não verdade revelada. Rotula umas dezenas de páginas na mão, roda o filtro e sobe ou desce os limiares até a faixa "duvidoso" ficar pequena e honesta
O erro comum deste passo: tratar probabilidade como certeza binária, com um if p > 0.5 e pronto. A faixa do meio é onde mora o prejuízo, e é justamente ela que você quer isolar em vez de fingir que não existe. Esse mesmo desenho de três vias aparece quando você usa o modelo pra moderar conteúdo enviado por usuários, onde o balde do meio vira revisão humana
- Monte a fila de duvidosos, não joga fora
Grava URL, o state que você enviou e as saídas completas. Essa fila é ouro por dois motivos: ela vira teu conjunto de calibração e ela te mostra qual pergunta está mal escrita
def registrar_duvidoso(url, state, saidas):
db.duvidosos.insert({
"url": url,
"state_enviado": state,
"saidas": saidas,
"coletado_em": now(),
})
Depois você reprocessa a fila com um state diferente (mais parágrafos, outra seleção de headings) ou manda pra revisão humana. Descartar duvidoso é jogar informação fora de graça
- Estime o custo por página antes de ligar isso em milhões de URLs
O preço do Jev é US$ 0,042 por milhão de tokens de entrada, com a saída não cobrada. Como a saída não entra na conta, o que define teu custo é só o tamanho do state mais as perguntas
Faz a conta com o teu tamanho médio real. Se o teu state reduzido fica na casa de 1.000 tokens por página, mil páginas dão perto de 1 milhão de tokens de entrada, ou seja, US$ 0,042. Compara isso com o que custa rodar extração, embedding e uma chamada de LLM generativo nas mesmas mil páginas, e o filtro se paga sozinho
Erros comuns ao filtrar páginas com o Jev (e como prevenir)
Sintoma: a probabilidade do Noul balança pra páginas parecidas, sem padrão claro
Causa: context overload. O state foi pro modelo cheio de menu, rodapé, sidebar e comentários, e a página de jaggedness do jev-1.13 registra que a acurácia cai conforme o state cresce com detalhe não relacionado à pergunta
Solução: cortar em código antes de enviar, mandando só os campos que a pergunta precisa. Quando não dá pra filtrar direito no state, a própria documentação sugere usar um Noul pra filtrar relevância
Sintoma: você pergunta uma coisa e sente que o modelo respondeu outra
Causa: o jev-1.13 faz leitura literal, ele responde a pergunta escrita e não a intenção por trás dela
Solução: reescreve a pergunta com o critério explícito. "Esta página é boa?" não quer dizer nada. "O conteúdo principal desta página explica um procedimento passo a passo?" quer
Sintoma: a pergunta sobre quantidade ou sobre "é recente?" dá resultado errado
Causa: a mesma página de jaggedness registra que o modelo não é calculadora, não conta de forma confiável e lê datas como texto
Solução: calcula em código e pergunta só o que é textual. Data de publicação você extrai e compara no Python. Contagem de ocorrências você faz no parser. Pro Jev fica o julgamento semântico, que é onde ele brilha
Sintoma: requisição rejeitada por tamanho
Causa: estourou o teto de 64.000 tokens por requisição, ou os 32.000 de orçamento pro state mais a pergunta mais longa
Solução: truncar o state e, se a página é realmente grande e importante, fatiar em pedaços e avaliar por pedaço. Tome cuidado especialmente com página de fórum e com doc gigante de uma página só
Sintoma: o crawler começa a tomar throttling quando você aumenta a concorrência
Causa: os limites de conta são de 250.000 tokens por segundo e 1.200 requisições por minuto, ajustados dinamicamente e sujeitos a mudança sem aviso
Solução: fila com backoff e retry, em vez de disparar tudo de uma vez. E não deixa esses números hardcoded na lógica do teu worker, já que eles podem mudar
Onde mais esse filtro compensa no pipeline
O padrão "reduz o state, faz perguntas estreitas, roteia em código" não serve só pro crawler. Os cookbooks da TypeSafe mostram três extensões diretas disso
Classificação de passagens de RAG. O cookbook envia, pra cada passagem, uma requisição com várias perguntas sobre o par query-passagem (relevância, utilidade, contradições, instruções) e usa as respostas pra decidir entre adicionar como evidência, marcar como informação conflitante ou descartar. É a mesma lógica de três vias do crawler, só que dentro da recuperação
Re-ranking de shortlist. O cookbook de re-ranking monta shortlists BM25 de 30 passagens para 40 queries jurídicas do CLERC e usa uma pergunta por par query-candidato. A acurácia top-1 subiu de 5% para 18% e a top-10 de 38% para 62%. Ou seja, o barato na frente pode melhorar bastante a ordem do que chega no caro
Busca linha a linha. Aqui o cookbook usa uma pergunta Choice pra ranquear IDs de linha pelo quanto respondem à query, mais um Noul pra checar se o documento contém alguma resposta. Pro crawler isso é muito útil no passo seguinte ao filtro: decidir QUAL trecho da página vale extrair, em vez de mandar a página inteira pro extrator
E fora do pipeline de conteúdo o desenho se repete igualzinho: dá pra usar o mesmo roteador de três vias pra qualificar e priorizar leads, trocando "vale processar essa página?" por "vale a pessoa do comercial olhar esse lead?"
Vídeo: contexto sobre modelos de IA no fluxo de desenvolvimento
Pra começar do zero e situar o cenário de modelos que está rolando agora, esse vídeo do canal mostra o retorno do Fable 5 e o que ele representa dentro do fluxo de desenvolvimento com IA
Próximo passo: rode o filtro em 200 páginas antes de ligar no pipeline
Não pluga isso direto em produção, se liga na sequência:
- Pega uma amostra de páginas que o teu crawler já coletou e rotula na mão como relevante, duvidosa ou descarte
- Roda o filtro em cima dessa amostra e compara com teus rótulos
- Ajusta os limiares até a faixa do meio ficar pequena e os descartes não levarem junto nada que você queria
- Mede quantas páginas caras você evitou e quanto isso representa no orçamento do pipeline
- Só aí liga no crawler de verdade, de preferência com o
modelfixado num ID versionado
O crédito inicial de US$ 5 cobre bastante teste nesse preço de US$ 0,042 por milhão de tokens de entrada, ainda mais com a saída não sendo cobrada. Dá pra calibrar o filtro inteiro sem tirar cartão do bolso
E o ponto mais importante de todos: o Jev te entrega uma probabilidade, não uma decisão. A regra de decisão, os limiares e a fila de duvidosos continuam sendo código teu, versionado, testável e ajustável quando o crawler mudar de tema
Testa com uma amostra pequena, mede, e me conta como foi o corte na tua base =)
até o próximo post!
Perguntas frequentes
Quanto custa rodar o Jev num crawler que processa milhares de páginas por dia?
O Jev cobra US$ 0,042 por milhão de tokens de entrada, e a saída não é cobrada. Como o state de um filtro de relevância costuma ser pequeno (título, meta description, headings e alguns parágrafos), o custo por página fica bem baixo mesmo em volume alto.
O Jev consegue contar quantos parágrafos ou links uma página tem antes de eu decidir processar ela?
Não confie nisso. A página de jaggedness do jev-1.13 registra que o modelo faz leitura literal, não é calculadora, não conta de forma confiável e lê datas como texto. Pra esse tipo de decisão, resolve em código antes de montar o state e deixa pro Jev só as perguntas de julgamento (relevância, idioma, categoria).
Dá pra chamar o Jev direto na API sem instalar o SDK oficial?
Dá sim. A API da TypeSafe tem um único endpoint, POST https://api.typesafe.ai/v1/systemone, que recebe o state e o mapa de questions no corpo da requisição. O SDK só facilita a parte de autenticação e tipagem, mas não é obrigatório.
Qual a diferença prática entre usar Noul e Choice pra filtrar uma página de crawler?
Noul serve pra pergunta binária: o valor retornado já é a probabilidade de a resposta ser sim, sem campo de confiança separado. Choice serve quando você tem várias categorias possíveis (até 255 opções), retornando probabilidade por opção mais um valor de confiança derivado da forma da distribuição.
O Jev só funciona chamando a TypeSafe direto ou dá pra usar por outro provedor?
Além da API própria da TypeSafe, o Jev está disponível no Vercel AI Gateway com o identificador typesafe-ai/jev, e também aparece no OpenRouter, no Netlify AI Gateway e no Cloudflare Workers AI. No AI SDK 7 da Vercel, dá pra acessar via experimental_evaluate combinado com gateway.evaluationModel(‘typesafe-ai/jev’).
Preciso entrar numa fila de espera pra testar o Jev no meu crawler?
Não. A TypeSafe removeu a fila de espera do Jev em 21 de setembro de 2026, então qualquer pessoa cria conta em console.typesafe.ai e já recebe US$ 5 de crédito inicial pra começar a testar.
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.

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.

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.
