//Receita

Verificar citações contra o documento fonte

Citação certa com contexto contrário é pior que citação inexistente, porque parece verdade. Esta receita separa as duas.

Um assistente responde uma consulta jurídica ou técnica e anexa as fontes: para cada afirmação, a seção do documento e o trecho que a sustenta. O texto fica convincente. Só que algumas dessas citações estão erradas — e as erradas se dividem em dois tipos bem diferentes.

O primeiro tipo é a citação inexistente: o trecho não está no documento. O segundo é pior: o trecho está lá, palavra por palavra, mas o contexto dele diz o contrário da afirmação. Verificar isso à mão significa achar o documento, achar o trecho e ler o entorno. Numa resposta com oito citações, é meia hora.

Por que a solução ingênua falha

A tentação é pedir ao próprio LLM que confira as próprias citações. Isso tem um problema óbvio — quem errou está conferindo — e um menos óbvio: a resposta vem em texto, e alguém tem de interpretar “parece correta” para decidir se publica.

A segunda tentação é resolver tudo com Ctrl+F. Metade funciona: se o trecho não está no documento, a citação é inventada, e nenhum modelo é necessário para descobrir. A outra metade escapa inteira, porque a busca textual não sabe ler contexto. Citação literal com contexto contrário passa no Ctrl+F com nota máxima.

O desenho das perguntas

A receita separa o que é código do que é julgamento.

Etapa 1, em código. Normalize espaços e aspas curvas para o trecho casar mesmo com a quebra de linha do documento, e procure como substring. Se não achar, o veredicto é fabricada — sem chamada de API. Se achar, você ganha de brinde a seção de onde o trecho veio, que é o texto que a etapa 2 vai ler.

Etapa 2, uma pergunta. Um Choice com três opções cobre as três relações possíveis entre uma seção e uma afirmação:

from typesafe_sdk import Choice, TypeSafeClient

PERGUNTAS = {
    "relacao": Choice(
        instructions="Como a seção se relaciona com a afirmação?",
        criteria={
            "sustenta": "A seção afirma o que a afirmação diz, ou implica diretamente que é verdadeira",
            "contradiz": "A seção afirma o oposto da afirmação, ou implica que ela é falsa",
            "nada_diz": "A seção não trata do que a afirmação sustenta, nem a favor nem contra",
        },
    ),
}

ACEITE_AUTOMATICO = 0.8

with TypeSafeClient() as client:
    resposta = client.system_one(
        state={"afirmacao": afirmacao, "secao": secao},
        questions=PERGUNTAS,
    )

relacao = resposta.answers["relacao"]
veredicto = {"sustenta": "verificada", "contradiz": "contradita", "nada_diz": "sem_suporte"}[relacao.choice]
automatico = relacao.confidence >= ACEITE_AUTOMATICO

Três decisões de projeto valem o registro. A opção nada_diz é a válvula de escape que evita forçar a citação em “sustenta” ou “contradiz” quando a seção simplesmente não trata do assunto. A confiança da própria resposta decide o que vai para revisão humana, sem limiar inventado por fora. E o state carrega só a afirmação e a seção — não o documento inteiro —, o que mantém a entrada enxuta.

O que o experimento oficial mediu

O cookbook usa a RFC 7519 (JSON Web Token) como fonte: 58.365 caracteres, 45 seções numeradas, em inglês. As oito citações foram escritas por um LLM contra essa RFC; quatro são exatas e quatro foram alteradas de propósito para falhar. Os números publicados pela TypeSafe, medidos no jev-1.12 em 16 de agosto de 2026:

CitaçãoEtapa 1RelaçãoConfiançaVeredictoAção
Segundos de épocaachadasustenta0,93verificadaautomática
Rejeição por audiênciaachadasustenta0,95verificadaautomática
Relato de assinaturanão achadafabricadaautomática
Tolerância de relógioachadasustenta0,99verificadaautomática
Campo obrigatórioachadacontradiz0,99contraditaautomática
Criptografia de dados pessoaisachadanada diz0,27sem suporterevisão
Data de emissão futurasó seçãonada diz0,56sem suporterevisão
Nomes duplicadosachadasustenta0,99verificadaautomática

As quatro corretas voltaram verificadas com confiança alta, todas acima do limiar de 0,80. A fabricada nunca chegou ao modelo. A mais interessante é a contradita: o trecho está na RFC palavra por palavra, e a mesma seção diz que o uso daquele campo é opcional — então a afirmação de que seria obrigatório é falsa, com confiança 0,99.

E as duas que foram para revisão mostram o mecanismo funcionando na direção certa: 0,27 e 0,56 são o modelo dizendo que não tem certeza. Uma delas é o caso que justifica a receita inteira — o trecho está no documento palavra por palavra, e a seção de onde ele veio não trata da afirmação.

O próprio cookbook registra o limite da etapa 1: a comparação é exata depois de normalizar, então citação truncada ou levemente reescrita volta como fabricada. Quem aceita citação relaxada precisa de comparação aproximada no lugar.

O que muda em português

O documento do experimento é uma RFC em inglês. Em português, a receita encaixa bem em dois casos brasileiros comuns: conferir citação de norma (a seção citada sustenta mesmo a interpretação?) e conferir resumo de contrato contra o contrato.

Dois ajustes práticos. A etapa 1 precisa lidar com a nossa pontuação: normalize aspas curvas, travessões e espaços não separáveis, que aparecem muito em PDF de documento oficial. E a segmentação por seção precisa entender numeração de cláusula (“7.2.1”, “Parágrafo único”) em vez da numeração de RFC. Como a TypeSafe declara que o inglês é a língua principal de treino, teste a etapa 2 com as suas cláusulas antes de baixar o limiar de 0,80.

Onde isso quebra

  • Leitura literal. A afirmação e a seção são lidas ao pé da letra. Afirmação com dupla negativa (“não é verdade que o campo não é obrigatório”) custa acurácia, como descrito nos limites do jev-1.13.
  • Seção grande. Se a seção citada tem páginas, o state cresce e a acurácia cai. Corte para o entorno do trecho.
  • Datas e números na afirmação. “A norma exige notificação em até 72 horas” mistura leitura com comparação numérica. Extraia o número com a receita de extrair valores e compare no código.
  • Documento que muda. A verificação vale para a versão que você leu. Guarde qual revisão do documento foi usada, junto com a probabilidade e a confiança.

Se as citações vêm de um pipeline de RAG, a triagem anterior está em classificar passagens de RAG. O índice completo está em receitas.

Perguntas frequentes

Por que duas etapas em vez de uma?

Porque cada etapa resolve um erro diferente e a primeira é grátis. Comparação de texto acha a citação que não existe no documento, sem chamar modelo nenhum. O que sobra é citação literal, e aí a dúvida passa a ser se o contexto sustenta a afirmação — isso é julgamento.

Quais veredictos a receita produz?

Quatro: verificada, contradita, sem suporte e fabricada. Os três primeiros vêm da pergunta Choice sobre o contexto; o último vem da comparação de texto, sem custo de API.

O que o experimento oficial mediu?

Sobre oito citações geradas por um LLM contra a RFC 7519, quatro exatas e quatro alteradas de propósito: as quatro corretas voltaram verificadas com confiança de 0,93 a 0,99, a fabricada foi pega pela comparação de texto, uma voltou contradita com 0,99 e duas foram para revisão com 0,27 e 0,56.

Por que uma citação literal pode ser contradita?

Porque a frase citada pode existir palavra por palavra e a seção dizer o contrário do que a afirmação sustenta. No experimento, uma citação literal foi marcada contradita com confiança 0,99 porque a mesma seção diz que o uso do campo é opcional.

A comparação de texto tolera citação aproximada?

Não. O cookbook usa correspondência exata depois de normalizar espaços e aspas curvas, então citação truncada ou levemente reescrita volta como fabricada. Um sistema de produção que aceita citação relaxada precisa de comparação aproximada.

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