//Caso de uso

Triagem de currículos com critério escrito

O ganho aqui não é velocidade. É obrigar a vaga a declarar, por escrito, o que ela considera relevante — e poder revisar isso depois.

Uma vaga com quatrocentos candidatos produz o mesmo resultado em quase toda empresa: alguém olha os cinquenta primeiros com atenção, os cem seguintes por alto, e o resto quase não é lido. Não é descaso; é o limite do tempo disponível. O efeito colateral é que a ordem de chegada pesa mais que o conteúdo.

O Jev, modelo da TypeSafe AI, devolve decisões tipadas com probabilidade em vez de texto gerado. Aplicado a currículos, o ganho principal não é a velocidade: é que a vaga precisa escrever o que considera relevante, em níveis descritos, antes de qualquer avaliação acontecer. Esse texto vira o registro mais honesto do que o processo está medindo.

A parte que precisa ficar dita

Decisão sobre candidatura afeta a vida de uma pessoa. O artigo 20 da Lei 13.709/2018 dá ao titular o direito de solicitar revisão de decisões tomadas unicamente por tratamento automatizado que afetem seus interesses. Este site é de comunidade, não dá orientação jurídica e não substitui a avaliação do jurídico da sua empresa.

O que a arquitetura deve fazer, e é o que descrevemos aqui: usar o modelo para ordenar e sinalizar, nunca para eliminar sozinho; manter a decisão de avançar com uma pessoa; guardar a distribuição, a confiança e a versão do modelo junto com cada avaliação; e ter um caminho de revisão que produza registro. O padrão está em revisão humana no lugar certo.

O desenho das perguntas

Uma chamada por currículo. E, antes dela, um trabalho de limpeza que é parte do desenho: retirar do state os campos que não devem pesar na avaliação.

from typesafe_sdk import Noul, Score, TypeSafeClient

perguntas = {
    "experiencia_na_funcao": Score(
        instructions="Quanta experiência direta na função descrita na vaga o texto evidencia?",
        criteria=[
            "Nenhuma experiência na função.",
            "Contato pontual, em outra função.",
            "Atuou na função em projetos ou por período curto.",
            "Atuou na função como atribuição principal.",
            "Atuou na função com escopo amplo e responsabilidade sobre resultados.",
        ],
    ),
    "profundidade_tecnica": Score(
        instructions="Qual a profundidade técnica evidenciada nas ferramentas exigidas pela vaga?",
        criteria=[
            "Nenhuma menção às ferramentas.",
            "Menciona sem detalhe.",
            "Usou em projetos, com alguma especificidade.",
            "Ferramenta principal, em vários projetos.",
            "Domínio evidente: arquitetura, desempenho, decisões técnicas.",
        ],
    ),
    "evidencia_de_resultado": Score(
        instructions="Quanto o texto descreve resultados concretos, e não apenas atribuições?",
        criteria=[
            "Só lista cargos e períodos.",
            "Descreve atribuições.",
            "Descreve entregas nomeadas.",
            "Descreve entregas com efeito observável descrito pelo candidato.",
        ],
    ),
    "requisito_obrigatorio_presente": Noul(
        instructions="O texto evidencia o requisito obrigatório da vaga: registro profissional ativo no conselho da categoria?"
    ),
    "disponibilidade_declarada": Noul(
        instructions="O candidato declara disponibilidade para o regime de trabalho descrito na vaga?"
    ),
}

Requisito obrigatório é um Noul, não um nível de régua, porque requisito obrigatório não se compensa: nota alta nas outras dimensões não substitui um registro profissional que a lei exige para a função. A diferença entre filtro e peso é o erro conceitual mais comum neste caso, e a discussão está em pontuação composta.

O que o código faz com a resposta

Piso de confiança primeiro. Currículo com formatação estranha, texto extraído de PDF com colunas embaralhadas ou conteúdo muito curto derruba a confiança. Esse caso vai direto para leitura humana, e não para o fim da fila — a diferença importa.

Regras determinísticas depois. requisito_obrigatorio_presente abaixo do corte sinaliza, não elimina: o candidato vai para uma lista à parte onde uma pessoa confirma se o requisito realmente falta ou se apenas não estava escrito.

Combinação por último, e só para ordenar. As duas primeiras réguas têm cinco níveis, então dividem por 4; a terceira tem quatro níveis e divide por 3.

faltou_confianca = any(
    r.answers[k].confidence < PISO
    for k in ("experiencia_na_funcao", "profundidade_tecnica")
)
if faltou_confianca:
    return leitura_humana(cv, motivo="confiança baixa")

if r.answers["requisito_obrigatorio_presente"].noul < 0.4:
    return lista_de_verificacao(cv, motivo="requisito não evidenciado")

exp = r.answers["experiencia_na_funcao"].score / 4
tec = r.answers["profundidade_tecnica"].score / 4
res = r.answers["evidencia_de_resultado"].score / 3

nota = 0.45 * exp + 0.35 * tec + 0.20 * res
registrar(cv, nota=nota, distribuicao={k: r.answers[k].probabilities
                                        for k in PERGUNTAS_COM_DISTRIBUICAO},
          modelo=r.model)
fila_de_leitura(cv, ordem=nota)     # ordena; não elimina

O nome da função final é deliberado: fila_de_leitura, não aprovados. O sistema decide em que ordem uma pessoa lê, e é só isso.

Onde entra a pessoa

Na decisão, sempre. E em mais três lugares:

No topo e no fundo da lista. Ler os melhores colocados é natural; ler uma amostra dos piores é o que detecta régua mal escrita. Se a amostra do fundo revela candidatos fortes, o problema está no criteria, não no candidato.

Na lista de requisito não evidenciado. Um registro profissional pode existir e não estar escrito no currículo. Confirmar é trabalho humano barato e evita descartar alguém por erro de redação.

Na revisão periódica por grupo. Medir a distribuição de notas por origem de candidatura, por formação e por outros recortes que a sua área jurídica e de pessoas considerar relevantes é a única forma de descobrir um viés sistemático da régua. Guardar a distribuição é o que torna essa medição possível depois.

Custo

Assumindo dez mil currículos por mês — suposição deste artigo — e um state de cerca de quatro mil tokens, que é um currículo razoavelmente longo já convertido em texto: ao preço oficial de US$ 0,042 por milhão de tokens de entrada, com saída gratuita, e o dólar estimado em R$ 5,40, cada currículo sai por cerca de R$ 0,00091 e o mês por cerca de R$ 9,07. A fórmula está em quanto custa uma decisão.

Onde isso quebra

Contagem e aritmética de tempo. “Quantos anos de experiência tem?” é exatamente o tipo de pergunta que a documentação desaconselha: o jev-1.13 não conta de forma confiável e lê datas como texto, não como quantidade ordenada. Se os períodos de trabalho vierem estruturados no seu sistema de candidaturas, calcule os anos em código e mande o número. Se estiverem no texto corrido, aceite que essa dimensão é uma estimativa e não a use como corte.

Leitura literal. O modelo responde à pergunta escrita, não à intenção. “Tem experiência com liderança?” e “liderou time com subordinados diretos?” produzem notas diferentes, e a segunda é a que você provavelmente quis perguntar.

State grande e ruidoso. Currículo extraído de PDF vem com cabeçalho, rodapé, tabela quebrada e caracteres soltos. Detalhe irrelevante age como distrator — é um dos nove modos de falha declarados. Limpe antes; o efeito está em context rot.

Conteúdo adversarial. Existe texto branco em fundo branco dentro de currículo, escrito para enganar filtros automáticos. A documentação avisa que o state não é tratado como hostil por padrão. Extrair o texto visível e comparar com o texto completo é uma verificação barata que vale fazer antes da chamada.

O modelo não valida fato nenhum. Ele avalia o que está escrito. Diploma, registro e vínculo anterior se conferem em fonte própria.

A lista completa dos limites está em limites do Jev, e os outros fluxos em casos de uso.

Perguntas frequentes

Posso reprovar candidatos automaticamente?

Este guia não dá orientação jurídica e não recomenda isso. O artigo 20 da Lei 13.709/2018 dá ao titular o direito de solicitar revisão de decisões tomadas unicamente por tratamento automatizado que afetem seus interesses. O desenho que descrevemos ordena e sinaliza, mas mantém a decisão de avançar ou não com uma pessoa.

Como isso é diferente de um filtro por palavra-chave?

Um filtro por palavra-chave elimina quem escreveu diferente. Uma pergunta com níveis descritos avalia a evidência no texto e devolve uma nota com a distribuição, o que dá para auditar, comparar entre candidatos e ajustar mudando um peso em vez de reescrever um regex.

O modelo pode discriminar?

O risco existe em qualquer sistema que lê texto de pessoas, e não some por usar probabilidade. Três defesas de desenho ajudam: tirar do state os campos que não deveriam pesar, escrever critérios que citem evidência relacionada à função, e medir o resultado por grupo antes de confiar na fila.

Como o modelo sabe o que a vaga exige?

Pelo que você escreve nos criteria. O Jev não é ajustado com os seus dados: a documentação diz que os mesmos pesos servem todas as contas e que a adaptação ao domínio acontece pelo state e pela descrição dos níveis e das opções.

Quanto custa avaliar dez mil currículos?

Assumindo um state de cerca de quatro mil tokens, que é um currículo razoavelmente longo em texto, ao preço oficial de US$ 0,042 por milhão de tokens de entrada e com o dólar estimado em R$ 5,40, cada currículo sai por cerca de R$ 0,00091 e dez mil por cerca de R$ 9,07.

Quer dominar decisões com IA em português? O curso da comunidade está em pré-venda.

Garantir pré-venda por R$ 499,00

Pré-venda: R$ 499,00 · Após o lançamento: R$ 799,00