Blog

Fila de revisão humana: escolher quais respostas do agente merecem auditoria

O agente responde quarenta mil vezes por mês e o time tem duas pessoas que conseguem revisar, no máximo, trezentas respostas cada uma. Isso é menos de dois por cento do tráfego, e a decisão que quase todo mundo toma é revisar por amostragem aleatória, porque parece estatisticamente honesto. É honesto para estimar uma taxa de erro global e é péssimo para encontrar erro: numa operação com noventa e cinco por cento de acerto, revisar trezentas respostas aleatórias entrega quinze problemas e duzentas e oitenta e cinco confirmações de que está tudo bem. O revisor gasta a maior parte do turno lendo respostas corretas. Este artigo trata a revisão humana como o recurso escasso que ela é, com o problema formulado de forma útil: dado um orçamento fixo de atenção humana por dia, quais respostas colocar na fila para maximizar o que se aprende, e como impedir que essa fila vire um depósito que ninguém abre.

2026-08-13 / IA Aplicada / 15 min

01

Amostra aleatória e busca de erro são objetivos diferentes

A confusão que produz filas inúteis é tratar como um só problema o que são dois. Estimar a taxa de erro do sistema exige amostra aleatória, sem viés, porque qualquer seleção enviesada destrói a capacidade de generalizar o número para o todo. Encontrar e corrigir erros exige exatamente o contrário: concentrar a atenção onde a probabilidade de erro é maior. As duas coisas são necessárias, e a solução é dividir explicitamente o orçamento entre elas em vez de escolher uma e fingir que ela serve para as duas.

orcamento diario de revisao: 60 respostas

[ 12 ] amostra aleatoria pura ....... estimar a taxa de erro real
[ 30 ] risco alto por sinal ......... encontrar defeito onde ele mora
[ 12 ] fronteira de decisao ......... calibrar limiar de escalonamento
[  6 ] casos novos ou fora do padrao . descobrir o que ainda nao existe

a fatia aleatoria e a unica que produz numero generalizavel
as outras tres produzem correcao, nao estatistica

A divisão acima não é arbitrária e cada fatia responde a uma pergunta distinta. A fatia aleatória é a única que permite dizer "a qualidade é de noventa e quatro por cento" com honestidade, e ela precisa ser pequena mas nunca zero, porque sem ela você perde a régua e passa a medir apenas o que já suspeitava. A fatia de risco alto é onde a correção acontece. A fatia de fronteira serve para calibrar limiares, que é uma tarefa recorrente e que ninguém faz sem dados. E a fatia de novidade é o seguro contra o ponto cego: ela existe para pegar o tipo de caso que ainda não tem sinal associado porque nunca apareceu antes.

Vale ser explícito sobre a consequência estatística de misturar: se você revisar só o que o sistema marcou como arriscado e reportar a taxa de erro dessa fila como taxa de erro do produto, o número vai ser terrível e não vai significar nada. O contrário também acontece: times que revisam só amostra aleatória concluem que a qualidade está ótima enquanto uma falha concentrada num tipo raro de pedido queima clientes silenciosamente todo mês.

02

Os sinais que realmente predizem erro

Escolher o que revisar é um problema de ordenação, e ordenar exige sinal. O erro comum é usar um único indicador, quase sempre a confiança auto declarada do modelo, que é o pior deles isoladamente: modelos são confiantes quando erram e a correlação entre confiança expressa e correção é fraca o suficiente para não sustentar uma fila. O que funciona é combinar sinais baratos de origens diferentes, porque eles falham de formas diferentes e a combinação cobre mais que a soma das partes.

SinalO que ele capturaLimitação que exige combinação
Escore de recuperação baixo no RAGA resposta foi gerada com contexto fraco ou ausentePergunta simples pode não precisar de contexto algum
Divergência entre duas gerações da mesma perguntaInstabilidade: o modelo não tem uma resposta firmeCusta uma chamada extra, então só vale em amostra
Conversa que passou por transbordo para humanoSinal forte e gratuito de que a automação não resolveuChega tarde: o cliente já sentiu o problema
Cliente reformulou a mesma pergunta em seguidaA resposta anterior não serviu, mesmo sem reclamaçãoTambém captura cliente que só mudou de assunto
Ferramenta com efeito colateral foi chamadaErro aqui é caro e irreversível, não só embaraçosoAlto volume: precisa ser cruzado com valor da operação
Resposta muito curta ou muito longa para o tipo de perguntaRecusa disfarçada ou divagação sem conteúdoLimiar depende da vertical e envelhece com o prompt
Assunto raro segundo o histórico de intençõesCauda longa, onde o eval quase nunca tem coberturaRaro não é sinônimo de errado

Repare que três desses sinais são gratuitos, porque já existem nos dados que o sistema produz: transbordo, reformulação e chamada de ferramenta. Começar por eles é a decisão certa quando não há orçamento para instrumentar nada novo, e eles sozinhos já rendem uma fila muito melhor que aleatória. A divergência entre gerações é o sinal mais forte da lista e o único que custa dinheiro, então ele entra depois, aplicado apenas ao subconjunto que já passou pelos outros filtros.

// Pontuacao de prioridade da fila. Sinais somados com peso, todos
// normalizados entre zero e um, para que o peso signifique alguma coisa.

const PESOS = {
  recuperacaoFraca: 0.25,
  transbordo: 0.30,
  reformulacao: 0.15,
  ferramentaComEfeito: 0.20,
  tamanhoAnomalo: 0.10,
};

// Valor de negocio multiplica em vez de somar: um erro numa conversa de
// ticket alto importa mais que o mesmo erro numa consulta trivial.
const fatorValor = (valorConversa, valorMediano) =>
  Math.min(3, Math.max(0.5, valorConversa / Math.max(1, valorMediano)));

export const pontuarParaRevisao = (resposta, contexto) => {
  const sinais = {
    // Escore de recuperacao vira risco invertido: quanto pior o contexto
    // recuperado, maior a chance de a resposta ter sido inventada.
    recuperacaoFraca: resposta.usouRag
      ? Math.max(0, 1 - resposta.escoreRecuperacaoTopo)
      : 0,
    transbordo: resposta.houveTransbordo ? 1 : 0,
    reformulacao: resposta.clienteReformulouEmSeguida ? 1 : 0,
    ferramentaComEfeito: resposta.ferramentasChamadas.some((f) => f.temEfeitoColateral) ? 1 : 0,
    tamanhoAnomalo: contexto.desvioDeTamanho(resposta) > 2 ? 1 : 0,
  };

  const base = Object.entries(PESOS).reduce(
    (soma, [chave, peso]) => soma + peso * sinais[chave],
    0,
  );

  return {
    prioridade: base * fatorValor(resposta.valorConversa, contexto.valorMediano),
    // Guardar os sinais junto da pontuacao e o que permite ao revisor
    // saber por que aquele item chegou na fila dele.
    sinais,
  };
};

Duas escolhas desse código são deliberadas. A primeira é o valor da conversa entrar como multiplicador e não como mais uma parcela: um erro numa negociação de ticket alto merece atenção desproporcional, e somar mais um peso não produz esse comportamento. A segunda é devolver os sinais junto com a pontuação. Um item que chega na fila sem explicação faz o revisor gastar dois minutos entendendo por que está olhando aquilo, e dois minutos vezes trezentos itens é o turno inteiro de uma pessoa.

03

A fila precisa caber no turno de quem revisa

Aqui está o erro operacional que mata mais iniciativas de revisão do que qualquer problema técnico: a fila é dimensionada pela quantidade de itens suspeitos, e não pela capacidade humana disponível. Numa segunda-feira com incidente, o sistema marca oito mil respostas como arriscadas, a fila estoura, o revisor abre, vê o tamanho e fecha. A partir daí a fila está morta, e a próxima conversa sobre revisão humana vai começar do zero em seis meses.

A fila precisa ser um orçamento, não um filtro. Se a capacidade é de sessenta itens por dia, a fila do dia tem exatamente sessenta itens, escolhidos como os melhores sessenta segundo a pontuação e as cotas de cada fatia. O que não entrou não fica pendente: ele é descartado da fila e continua existindo nos dados agregados, onde é contado sem ser lido individualmente. Essa distinção entre "revisado" e "contabilizado" é o que impede a fila de virar dívida.

  1. Meça o tempo real de revisão por item, cronometrado e não estimado, incluindo o tempo de ler o contexto da conversa e não só a resposta final.
  2. Defina a capacidade diária como número de itens, derivada desse tempo e das horas que o time realmente tem, com folga para os itens difíceis que levam o triplo.
  3. Monte a fila do dia por cota: cada fatia recebe um número fixo de vagas e disputa internamente por pontuação, para que a fatia de risco alto nunca engula a de amostra aleatória.
  4. Descarte o excedente explicitamente em vez de acumular, e registre quantos itens ficaram de fora para que o dado de cobertura seja honesto.
  5. Reserve uma faixa da capacidade para itens vindos de incidente aberto, porque durante incidente a prioridade muda e a fila normal fica irrelevante.
// Montagem da fila diaria por cota. A capacidade e o limite superior,
// e o excedente e descartado de proposito para a fila nunca virar deposito.

const COTAS = {
  aleatoria: 0.2,
  riscoAlto: 0.5,
  fronteira: 0.2,
  novidade: 0.1,
};

const pegarMelhores = (itens, n) =>
  [...itens].sort((a, b) => b.prioridade - a.prioridade).slice(0, n);

export const montarFilaDoDia = (candidatos, capacidade, aleatorioSeguro) => {
  const vagas = Object.fromEntries(
    Object.entries(COTAS).map(([fatia, fracao]) => [fatia, Math.floor(capacidade * fracao)]),
  );

  const porFatia = {
    // Amostra aleatoria de verdade: sem ordenacao por pontuacao, ou o
    // numero que ela produz deixa de ser generalizavel.
    aleatoria: aleatorioSeguro(candidatos, vagas.aleatoria),
    riscoAlto: pegarMelhores(
      candidatos.filter((c) => c.prioridade >= 0.6),
      vagas.riscoAlto,
    ),
    // Fronteira: itens perto do limiar de escalonamento, onde a decisao
    // de automatizar ou transbordar e mais dificil e mais calibravel.
    fronteira: pegarMelhores(
      candidatos.filter((c) => Math.abs(c.prioridade - 0.5) < 0.08),
      vagas.fronteira,
    ),
    novidade: pegarMelhores(
      candidatos.filter((c) => c.intencaoRara || c.semCoberturaNoEval),
      vagas.novidade,
    ),
  };

  const vistos = new Set();
  const fila = [];
  for (const [fatia, itens] of Object.entries(porFatia)) {
    for (const item of itens) {
      if (vistos.has(item.id)) continue; // um item pertence a uma fatia so
      vistos.add(item.id);
      fila.push({ ...item, fatia });
    }
  }

  return {
    fila,
    // Descartados nao viram pendencia: entram na metrica de cobertura
    // e desaparecem da fila, que precisa caber no turno de hoje.
    descartados: candidatos.length - fila.length,
    cobertura: candidatos.length === 0 ? 1 : fila.length / candidatos.length,
  };
};

O detalhe do conjunto de itens já vistos importa mais do que parece. Sem ele, um item de risco alto que também é raro aparece duas vezes na fila, o revisor lê o mesmo caso duas vezes e conclui, com razão, que a ferramenta é descuidada. Uma fila de revisão perde a confiança do time por esse tipo de detalhe muito antes de perder por má escolha de sinal.

04

O que o revisor devolve precisa ser reaproveitável

Revisão humana só se paga se o resultado alimentar alguma coisa. O padrão que não se paga é o revisor escrever um comentário livre num campo de texto e marcar o item como visto: isso produz conhecimento que mora na cabeça de quem revisou e num campo que ninguém consulta. O padrão que se paga transforma cada revisão em um registro estruturado que serve como caso de avaliação, evidência para ajuste de prompt ou entrada num relatório de qualidade.

  • Veredito em categoria fechada, não em texto livre: correto, incorreto por informação errada, incorreto por informação faltando, correto mas em tom inadequado, recusa indevida, ação indevida por ferramenta.
  • A resposta que deveria ter sido dada, escrita pelo revisor quando o veredito é negativo, porque é isso que transforma o caso em item de conjunto de avaliação sem trabalho adicional depois.
  • A causa provável apontada entre opções conhecidas: contexto não recuperado, contexto recuperado mas ignorado, instrução ambígua no prompt, ferramenta devolveu dado errado, política mudou e o prompt não.
  • Referência estável para a conversa e para a versão do prompt e do modelo vigentes naquele momento, sem a qual a análise agregada por versão é impossível.
  • Tempo gasto na revisão, que é o dado que permite recalibrar a capacidade diária quando o perfil dos casos muda.

O segundo item é o de maior retorno e o mais negligenciado. Pedir ao revisor que escreva a resposta correta parece aumentar o custo da revisão, e aumenta mesmo, em talvez um minuto por caso negativo. Em troca, cada caso negativo revisado vira automaticamente um item de conjunto de avaliação com entrada e saída esperada, que é exatamente o insumo mais caro de produzir de qualquer outra forma. Sem isso, alguém vai precisar reconstruir esses casos depois, com menos contexto e mais esforço.

// Registro estruturado da revisao. O formato e o que permite reaproveitar
// o trabalho humano como caso de eval sem uma segunda passada.

export const registrarRevisao = async (repo, { item, revisor, veredito }) => {
  const registro = {
    conversaId: item.conversaId,
    respostaId: item.id,
    fatiaDaFila: item.fatia,
    sinais: item.sinais,
    // Versoes vigentes: sem elas nao da para dizer se a regressao veio
    // do prompt novo, do modelo novo ou da base de conhecimento nova.
    promptVersao: item.promptVersao,
    modelo: item.modelo,
    veredito: veredito.categoria,
    respostaEsperada: veredito.respostaEsperada ?? null,
    causaProvavel: veredito.causaProvavel ?? null,
    revisor,
    duracaoSegundos: veredito.duracaoSegundos,
  };

  await repo.salvarRevisao(registro);

  // Caso negativo com resposta esperada preenchida ja nasce como item
  // candidato do conjunto de avaliacao, marcado para curadoria.
  const negativo = veredito.categoria !== 'correto';
  if (negativo && veredito.respostaEsperada) {
    await repo.proporCasoDeEval({
      entrada: item.perguntaCliente,
      contexto: item.contextoRecuperado,
      saidaEsperada: veredito.respostaEsperada,
      origem: 'revisao-humana',
      revisaoId: registro.respostaId,
      // Nunca entra direto no eval: um caso mal escrito envenena a regua
      // por meses, entao passa por curadoria antes de valer nota.
      estado: 'aguardando-curadoria',
    });
  }

  return registro;
};

O estado de espera por curadoria não é burocracia. Um caso de avaliação escrito às pressas por um revisor cansado, com uma resposta esperada que reflete a opinião dele e não a política da empresa, vai valer nota por meses e empurrar o sistema na direção errada. A revisão humana propõe, a curadoria decide, e esse par de etapas custa pouco perto do estrago que um conjunto de avaliação contaminado provoca.

05

Medir se a fila está funcionando

Uma fila de revisão pode consumir duas pessoas em tempo integral e não produzir nada, e o time só descobre isso quando alguém pergunta o que mudou por causa dela. As métricas de uma fila não são sobre quantidade revisada, que é apenas medida de esforço. Elas são sobre densidade de achado e sobre efeito, e as duas precisam aparecer no mesmo painel.

MétricaComo lerAção quando está ruim
Densidade de erro na fatia de risco altoProporção de vereditos negativos entre os itens priorizadosSe está perto da taxa geral, os sinais não predizem nada: revise os pesos
Elevação sobre a aleatóriaDensidade da fatia de risco dividida pela densidade da aleatóriaAbaixo de duas vezes, a priorização não se justifica frente ao custo
Cobertura declaradaItens revisados sobre itens candidatos, sempre visívelSe ninguém sabe que é dois por cento, alguém vai tratar como auditoria total
Casos de eval originados da filaQuantos itens negativos viraram caso curado por semanaZero significa que a revisão está produzindo apenas leitura
Tempo entre revisão e correçãoDa marcação negativa até o ajuste de prompt, base ou ferramentaSe passa de semanas, a fila vira registro histórico e desmotiva o revisor
Concordância entre revisoresProporção de acordo em um lote pequeno revisado em duplicataBaixa concordância indica critério ambíguo, não revisor ruim

A elevação sobre a aleatória é a métrica que justifica toda a máquina, e ela merece cuidado na leitura. Se a fatia de risco alto tem densidade de erro de trinta por cento e a aleatória tem cinco, a elevação é seis: cada hora do revisor rende seis vezes mais achados do que renderia sem priorização. Se a elevação for próxima de um, toda a pontuação, os pesos e o código de fila estão sendo executados para produzir o mesmo resultado que um sorteio, e a resposta honesta é simplificar em vez de adicionar mais um sinal.

A concordância entre revisores é a métrica que quase ninguém coleta e que explica boa parte das discussões improdutivas sobre qualidade. Colocar dez itens por semana na fila de duas pessoas ao mesmo tempo custa dez itens de capacidade e revela se o critério é compartilhado. Quando a concordância é baixa, o problema não está no agente nem no revisor: está numa definição de "resposta correta" que ninguém escreveu, e nenhuma métrica de qualidade construída sobre esse chão significa coisa alguma.

FAQ

Perguntas frequentes

Por que não revisar por amostragem aleatória, que é o método estatisticamente correto?

Porque amostragem aleatória responde uma pergunta diferente da que você tem. Ela é a única forma honesta de estimar a taxa de erro global do sistema, e por isso precisa existir sempre, ocupando uma fatia pequena do orçamento de revisão. Mas ela é péssima para encontrar erro: se a operação acerta noventa e cinco por cento das vezes, o revisor passa noventa e cinco por cento do turno confirmando que respostas corretas estão corretas. Priorizar por sinal concentra a atenção onde o erro mora e costuma render várias vezes mais achados por hora de revisão. A solução não é escolher uma das duas, é dividir o orçamento explicitamente em fatias com propósitos distintos, e nunca reportar a taxa de erro da fatia priorizada como se fosse a do produto.

Que sinais usar quando não há nenhuma instrumentação específica ainda?

Comece pelos três que já existem nos seus dados e não custam nada para coletar: conversas que acabaram em transbordo para atendente humano, clientes que reformularam a mesma pergunta logo depois da resposta, e respostas em que o agente chamou alguma ferramenta com efeito colateral, como emitir segunda via, alterar cadastro ou registrar pedido. Esses três sozinhos já produzem uma fila bem melhor que aleatória. Depois deles, o próximo passo mais barato é o escore de recuperação do RAG, que você já tem se usa busca vetorial. O sinal mais forte, que é a divergência entre duas gerações da mesma pergunta, custa uma chamada extra ao modelo e por isso deve ser aplicado apenas ao subconjunto que já passou pelos filtros anteriores, nunca no tráfego inteiro.

A fila cresce mais rápido do que o time revisa. O que fazer com o acúmulo?

Descartar, explicitamente e todo dia. Uma fila de revisão precisa ser um orçamento de atenção, não um filtro de tudo que parece suspeito: se a capacidade é de sessenta itens por dia, a fila do dia tem sessenta itens e o resto sai. O que não foi revisado individualmente continua existindo nos dados agregados e nas métricas, então não se perde informação, apenas leitura humana. O acúmulo é pior que o descarte por dois motivos: um revisor que abre uma fila com oito mil itens fecha a ferramenta e não volta, e uma fila com pendência antiga faz o time revisar caso de três semanas atrás em vez do caso de ontem, que é o que ainda dá para corrigir. Registre quantos itens ficaram de fora e mostre a cobertura real no painel, para que ninguém confunda a fila com auditoria completa.

Atenção humana é orçamento, não filtro

O erro que inutiliza a maioria das filas de revisão não é técnico, é de enquadramento: elas são construídas como um filtro que separa o suspeito do normal, quando deveriam ser construídas como um orçamento fixo de atenção humana disputado por candidatos. A partir desse enquadramento tudo fica mais simples: a capacidade define o tamanho da fila, as cotas garantem que a fatia aleatória sobreviva à pressão da fatia de risco, o excedente é descartado sem virar dívida, e cada revisão negativa devolve uma resposta esperada que nasce como candidata a caso de avaliação. E a pergunta que decide se a máquina inteira se justifica é uma só: quantas vezes mais defeitos por hora essa fila encontra em comparação com um sorteio. Se a resposta for próxima de uma vez, simplifique, porque a complexidade não está pagando nada.