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

fluxo de decisão usando o Jev para filtrar páginas relevantes em um crawler
Resposta rápida

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

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

  1. 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

  1. 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

  1. 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']
    }
  }
})
  1. 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

  1. 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

  1. 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

  1. 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:

  1. Pega uma amostra de páginas que o teu crawler já coletou e rotula na mão como relevante, duvidosa ou descarte
  2. Roda o filtro em cima dessa amostra e compara com teus rótulos
  3. Ajusta os limiares até a faixa do meio ficar pequena e os descartes não levarem junto nada que você queria
  4. Mede quantas páginas caras você evitou e quanto isso representa no orçamento do pipeline
  5. Só aí liga no crawler de verdade, de preferência com o model fixado 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.




Escrito por | Matheus Battisti

Matheus Battisti
Fundador da Hora de Codar

Programador apaixonado pelo mundo das tecnologias, sempre buscando em aprender e se aprofundar em linguagens, frameworks e o que mais for necessário para executar um bom trabalho. Agora tem uma nova missão que é de passar seu conhecimento adiante para formar novos programadores e especializar mais os que já são.

Subscribe
Notify of
guest

0 Comentários
Oldest
Newest Most Voted

Formações

Formação Claude Code

Formação Claude Code

Domine Claude Code do absoluto zero até o avançado

  • 120 aulas
  • 4 projetos
  • 9h 48min

Blog | Mais populares