Lab 92 — IDP: documento → extração → interpretação → revisão humana
O problema, e a empresa que o tem
A Cadência reembolsa lojistas parceiros quando um produto chega com defeito: o lojista sobe, pelo painel de parceiros, uma foto ou PDF da nota fiscal da compra e, quando o item exige avaliação técnica, um laudo de uma assistência autorizada. São cerca de 340 pedidos de reembolso por mês, cada um com 6 campos que o financeiro precisa antes de aprovar: CNPJ do lojista, número da nota, data da compra, valor da nota, valor do reembolso pedido e a categoria do defeito.
Três semanas atrás, alguém do mesmo time que fez a L81 trocou a digitação manual desses 6 campos por uma chamada direta ao Bedrock: sobe o PDF inteiro, pede em português "extraia CNPJ, número da nota, data, valor da nota, valor do reembolso e categoria do defeito, devolva em JSON". Para nota fiscal digital, bem escaneada, funciona quase sempre — e o time adotou sem cerimônia, porque a digitação manual era o gargalo do processo.
O caso que chegou à auditoria: um laudo técnico escaneado tinha o número da nota "000.045.822" e o valor do reembolso "R$ 1.284,50" impressos próximos, na mesma região do formulário. O Bedrock leu os dois números embaralhados e devolveu o reembolso como R$ 45.822,00 — quase R$ 44,5 mil a mais do que o laudo pedia. Nada no JSON de resposta indicava incerteza; o valor errado só foi pego porque um analista do financeiro estranhou o total antes do pagamento sair, numa checagem que não fazia parte do processo desenhado.
Resposta plausível e errada, sem confiança declarada
Um JSON bem formatado, com todos os 6 campos preenchidos, não é o mesmo que um JSON correto — e ninguém no fluxo de aprovação tinha como distinguir os dois só olhando a resposta. É esse o defeito que este laboratório resolve: não "o modelo erra às vezes", mas "nada no desenho perguntava o quanto confiar em cada campo, e o financeiro aprovou R$ 45.822,00 onde o laudo pedia R$ 1.284,50".
O que este laboratório NÃO é
Não é sobre recuperar e citar documento (isso é o L83, e a disciplina de medir com golden set vem de lá). Não é sobre um agente decidindo e executando ação (isso é o L87). Não é sobre a trilha de auditoria de uma decisão automatizada — isso é o L97, que usa exatamente o registro por campo que este laboratório grava no DynamoDB como matéria-prima. Este laboratório prova a cascata: extração determinística primeiro, interpretação condicional depois, revisão humana no desenho — não como exceção — abaixo de um limiar medido.
O que você vai conseguir fazer
Objetivos verificáveis: cada um se prova com uma configuração ou uma medição na seção de implantação, não com a sensação de ter entendido IDP.
- Medir a taxa de erro de um LLM extraindo campos direto do PDF, sem nenhuma etapa determinística antes.
- Configurar o Textract para extrair campos de formulário e tabela (nota fiscal e laudo técnico) com confiança declarada por campo.
- Definir um limiar de confiança que decide, por campo, entre aprovação automática, interpretação pelo Bedrock ou revisão humana.
- Restringir a entrada do Bedrock ao texto já extraído pelo Textract — nunca ao PDF ou à imagem bruta — nos campos que exigem interpretação semântica.
- Configurar um fluxo de revisão humana no Amazon A2I para campos abaixo do limiar de confiança.
- Registrar no DynamoDB, por campo, o valor final, a origem da decisão (automática, Bedrock ou humana) e quem revisou.
- Medir a taxa de erro do pipeline completo contra um golden set de documentos com valor correto conhecido, e comparar com a extração direta pelo LLM.
- Restringir a chamada ao Textract, ao Bedrock e ao fluxo de revisão por IAM, com o ARN específico de cada recurso.
O que a certificação cobra disto
| Conceito | Certificação | Como aparece aqui | O que dominar |
|---|---|---|---|
| IDP / Textract (OCR estruturado) | AIF-C01 | AnalyzeDocument com FORMS e TABLES extraindo campo nomeado e confiança | diferença entre OCR simples (texto corrido) e extração estruturada (campo + confiança) |
| Extração determinística antes do modelo generativo | AIF-C01 | Textract roda antes de qualquer chamada ao Bedrock; o modelo só recebe texto já extraído | por que dado estruturado não deveria depender de geração probabilística |
| Human-in-the-loop / Amazon A2I | AIF-C01 | campo abaixo do limiar de confiança vira tarefa de revisão humana, não aprovação automática | revisão humana é parte do desenho, não uma exceção tratada depois do erro |
| Confiança de modelo e limiar de decisão | AIF-C01, MLA-C01 | cada campo carrega confiança 0–100; o limiar decide o caminho da cascata | confiança não é acerto — é a probabilidade que o próprio serviço declara sobre a leitura |
| Quando um LLM deve interpretar em vez de extrair | AIF-C01 | Bedrock só entra em campo de texto livre ou ambíguo, recebendo o texto do Textract | extração estrutural (Textract) e interpretação semântica (Bedrock) são problemas diferentes |
| Alucinação em dado estruturado | AIF-C01 | medida diretamente: taxa de erro do "LLM lê tudo" contra o pipeline com Textract e confiança | erro em dado estruturado custa dinheiro real, não é só "resposta ruim" |
Onde isto costuma ser cobrado errado
A pergunta clássica descreve um sistema que extrai dado de formulário escaneado e às vezes erra um valor, e pede a correção. A resposta esperada não é "trocar de modelo" nem "melhorar o prompt de extração" — é usar um serviço de extração determinística com confiança declarada por campo, e uma cascata que manda para revisão humana o que fica abaixo de um limiar. O erro de raciocínio mais comum é tratar "o modelo consegue ler a imagem" como sinônimo de "o modelo deveria ser a única fonte da extração": capacidade de leitura não é a mesma coisa que determinismo com confiança auditável.
Requisitos, e como cada um muda o desenho
Requisito não funcional que não vira uma linha de configuração é intenção. A coluna da direita é onde cada um deixou marca no Terraform ou na máquina de estados.
| Requisito | Valor declarado | O que ele decide no desenho |
|---|---|---|
| Campo estruturado extraído de forma determinística | obrigatório | Textract AnalyzeDocument com FeatureTypes=[FORMS,TABLES]; Bedrock nunca recebe o PDF bruto para extrair campo estruturado |
| Cada campo carrega confiança auditável | obrigatório | Confidence do Textract (e, quando aplicável, do Bedrock) persistida junto do valor no DynamoDB |
| Campo abaixo do limiar não é aprovado automaticamente | limiar de 80% | a máquina de estados ramifica para o A2I quando a confiança fica abaixo de 80; acima disso, o campo segue sem humano |
| Campo que exige interpretação semântica passa pelo Bedrock, nunca pelo LLM lendo a imagem | obrigatório | Bedrock recebe o texto/JSON já extraído pelo Textract como entrada; o PDF nunca é anexado à chamada do modelo generativo |
| Toda decisão final é auditável — quem revisou, quando, com que valor | obrigatório | DynamoDB grava campo, valor, origem da decisão (auto/Bedrock/humano), id do revisor e timestamp |
| Reembolso não pode esperar dias por aprovação | até 24h automático, até 48h com revisão humana | orçamento de fila do A2I dimensionado contra o SLA declarado ao lojista |
| Documento chega e é processado sem disparo manual | obrigatório | evento de escrita no S3 dispara a máquina de estados — o mesmo padrão de evento do L28, reaproveitado |
| Dado financeiro (CNPJ, valor) cifrado com chave própria, não a padrão do serviço | obrigatório | KMS com chave gerenciada pelo cliente cifrando o bucket de documentos e a tabela de decisões |
| Chamada ao Textract, ao Bedrock e ao fluxo de revisão restrita à aplicação de reembolso | segurança | IAM role com Resource específico do bucket, do modelo e do fluxo A2I — nunca "Resource": "*" onde a ação suporta recurso |
Arquitetura mínima: o PDF inteiro entregue ao modelo, sem grade nem confiança
Este é exatamente o desenho que a Cadência tem hoje — não uma versão simplificada de propósito. Ele é implantável de verdade, custa uma chamada por documento, e o defeito só aparece quando dois números ficam próximos demais na mesma região do formulário escaneado.
- → PDF do laudo e da nota fiscal anexado à requisição
- → encaminha a chamada HTTP com o arquivo
- → prompt = PDF em base64 + "extraia CNPJ, número da nota, data, valor, categoria em JSON"
- → JSON com os 6 campos, sem confiança nem indicação de incerteza
- → grava o reembolso como aprovado, direto do JSON recebido
- Fora da AWS
- Rede e entrega
- Compute
- IA e machine learning
- Banco de dados
É o que a Cadência tem hoje: o PDF inteiro anexado numa única chamada ao Bedrock, pedindo para extrair os 6 campos em JSON. Percorra os passos e repare no último: a aprovação financeira lê o JSON e segue — não existe nenhum nó nem aresta que carregue um número de confiança por campo.
- Lojista anexa o PDF do laudo e da nota. É o fluxo comum: o lojista tira foto ou digitaliza os dois documentos e sobe pelo formulário de reembolso.
- A API repassa o arquivo sem tocá-lo. Não há nenhuma etapa de extração entre receber o PDF e chamar o modelo — a função existe só para formatar a chamada HTTP.
- O prompt enviado ao modelo é o PDF inteiro. Nenhuma etapa determinística antes: o modelo recebe a imagem completa e a instrução de extrair todos os 6 campos de uma vez.
- O modelo devolve um JSON, sem número de confiança. A resposta tem a forma certa — 6 campos preenchidos — mas nenhum campo carrega um sinal de quanto o modelo confia na própria leitura.
- O reembolso é aprovado a partir do JSON, sem checagem. A função grava o valor extraído como aprovado; não existe etapa que pergunte "este número está certo?" antes do pagamento seguir.
Fluência do JSON não é confiança na leitura
O modelo foi treinado para completar texto e estrutura de forma coerente, não para admitir incerteza campo a campo — por isso o JSON com o valor trocado saiu tão bem formatado quanto um JSON correto teria saído. Sem nenhum sinal de confiança, o financeiro não tinha como diferenciar os dois só olhando a resposta.
Arquitetura para produção: extração determinística, interpretação condicional, revisão no desenho
A diferença em relação à Figura 1 não é "adicionar um serviço de OCR" — é que nenhum campo chega a uma decisão final sem que algo (o próprio Textract, o Bedrock ou uma pessoa) declare o quanto confia nele. Cada peça nova rastreia a uma linha da tabela de requisitos.
- → upload do PDF por URL pré-assinada
- → evento de objeto criado
- → inicia a execução da máquina de estados
- → AnalyzeDocument com FeatureTypes=[FORMS,TABLES]
- → cada campo, com valor extraído e confiança de 0 a 100
- → só os campos interpretativos ou com confiança entre 80 e 97, com o texto do Textract
- → valor interpretado, ainda sujeito a registro
- → campo com confiança abaixo de 80 vira tarefa de revisão
- → valor confirmado ou corrigido pelo revisor humano
- → grava campo, valor final, origem da decisão e revisor
- → chave gerenciada cifra o objeto em repouso
- → mesma chave cifra a tabela de decisões
- → métricas e logs de cada execução da cascata
- Fora da AWS
- Armazenamento
- Segurança e identidade
- Integração de apps
- IA e machine learning
- Banco de dados
- Gestão e governança
O mesmo lojista, os mesmos dois documentos — o que muda é tudo entre o S3 e a decisão final. O pipeline de ingestão existe porque o documento tem de virar campo extraído antes de qualquer coisa; a máquina de estados existe porque cada campo pode seguir um de três caminhos, e a decisão precisa ser rastreável; e o Bedrock só aparece depois do Textract, recebendo texto, nunca a imagem.
- Lojista sobe o laudo e a nota, mesma interface da versão mínima. Nada muda do lado de quem envia o documento — a diferença inteira está atrás do upload.
- O evento de escrita dispara a orquestração, sem gatilho manual. O mesmo padrão de evento do L28: o S3 avisa o EventBridge, que inicia a máquina de estados — nada espera alguém rodar um script.
- A cascata chama o Textract antes de qualquer modelo generativo. AnalyzeDocument com FORMS e TABLES lê o documento de forma determinística — a mesma imagem processada de novo devolve o mesmo resultado.
- Cada campo volta com valor e confiança declarada. É essa confiança, não a fluência de um JSON, que decide o próximo passo de cada campo — automático, interpretação ou revisão.
- Campo interpretativo ou de confiança intermediária vai ao Bedrock, só com o texto. O modelo generativo nunca recebe o PDF nesta etapa — só o texto que o Textract já extraiu, para os campos que precisam de interpretação, não de OCR.
- Campo abaixo do limiar vira tarefa de revisão humana no A2I. Confiança menor que 80 não é aprovada nem rejeitada automaticamente — vira uma tarefa que uma pessoa confirma ou corrige.
- Toda decisão final é gravada, cifrada e observável. O DynamoDB recebe o valor final, de onde ele veio (automático, Bedrock ou humano) e quem revisou; a mesma chave do KMS que cifra o bucket cifra a tabela, e o CloudWatch mede quantos campos seguiram por cada caminho — é o material que o L97 audita depois.
O ganho não é substituir o modelo — é saber onde ele não deveria decidir sozinho
A versão mínima já usava o Bedrock; a diferença é que agora ele só entra depois de uma extração determinística com confiança, e só nos campos que realmente exigem interpretação. O modelo continua no desenho — só que restrito ao que ele faz bem, com uma segunda fonte de verdade (Textract, e humano quando preciso) para o que ele não deveria decidir sozinho.
Como funciona, ponta a ponta
O trecho abaixo é o que a máquina de estados grava no DynamoDB a cada campo decidido — é o material bruto da auditoria: qual campo, com que confiança, e por qual caminho a decisão passou.
{
"evento": "CAMPO_DECIDIDO",
"documentoId": "reembolso-8821",
"documento": "s3://cadencia-reembolsos/laudos/2026-08-05/laudo-8821.pdf",
"campo": "valor_reembolso",
"valorExtraidoTextract": "1.284,50",
"confiancaTextract": 62.3,
"origemDecisao": "revisao_humana",
"valorFinal": "1.284,50",
"revisorId": "rev-0231",
"timestamp": "2026-08-05T09:14:02.771Z",
"_comentario": "confianca abaixo do limiar de 80 -- a regiao do laudo estava mal escaneada, e o Textract tinha lido o valor corretamente mesmo assim; o campo foi para revisao porque a confianca baixa nao garantia isso de antemao."
}
Revisão humana confirmando um valor certo também é o desenho funcionando
Quando a confiança de um campo cai abaixo do limiar mas o valor extraído estava certo, a revisão humana confirma e a decisão segue — isso não é desperdício, é o sistema admitindo que não tinha como saber de antemão. A cascata mede o quanto confiar em CADA leitura, não se a leitura estava certa; as duas coisas costumam andar juntas, mas não são a mesma coisa, e é essa distinção que a seção de prova mede.
As decisões, e o que se perde em cada uma
📋 A Cadência precisa aprovar reembolsos a partir de PDF/foto de nota fiscal e laudo técnico, sem inventar valor, com prova de taxa de erro para o financeiro — e uma equipe pequena, sem time dedicado a treinar um modelo de extração customizado.
Textract resolve a extração estrutural sem exigir dataset de treino próprio, com confiança nativa por campo. Bedrock resolve a fração de campos que não é puramente estrutural (texto livre, categorização) sem forçar tudo pelo mesmo caminho caro e não-determinístico. A2I resolve a exigência de nunca aprovar automaticamente um campo incerto, sem exigir revisão de 100% dos documentos.
Alt: Enviar o PDF inteiro pro Bedrock, pedindo para extrair tudo em JSON — sem confiança por campo, sem determinismo — o mesmo documento processado duas vezes pode devolver valores diferentes, e é exatamente o defeito medido na arquitetura mínima.
Alt: Usar só o Textract, sem Bedrock e sem revisão humana — campo de texto livre (o motivo do laudo, a observação do técnico) não é puramente estrutural — o Textract devolve o texto bruto, mas não interpreta nem categoriza; tratar tudo como campo estrutural erra exatamente onde a interpretação importa.
Alt: Revisar 100% dos documentos manualmente, achando mais seguro — seguro, mas não escala — o objetivo de automatizar se perde, e o time do financeiro voltaria a gastar o mesmo tempo que gastava antes do pipeline existir.
Alt: Amazon Comprehend para extrair entidades do texto — ótimo para reconhecer entidades em texto corrido (nomes, datas, organizações), mas não devolve bounding box nem confiança por campo de formulário — perderia justamente a granularidade que a extração financeira exige.
| Decisão | Escolha | Alternativas | Motivo | O que se perde |
|---|---|---|---|---|
| Onde extrair o campo estruturado | Textract AnalyzeDocument (FORMS+TABLES) | Bedrock lendo a imagem; Amazon Comprehend | determinismo e confiança nativa por campo, sem treinar nada | menos flexível para documento fora do padrão de formulário/tabela |
| Quando o Bedrock entra | só em campo interpretativo ou confiança entre 80 e 97 | Bedrock chamado em todo campo, sempre | restringe o custo e a variabilidade ao subconjunto que realmente precisa de interpretação | a simplicidade de "perguntar tudo pro mesmo modelo" se perde — cada campo tem regra própria |
| Limiar de confiança para revisão humana | 80% | 90% (mais conservador); 60% (mais permissivo) | equilíbrio medido entre carga de revisão humana e erro residual aceito | um limiar mais alto reduziria ainda mais o erro residual, à custa de mais tarefas de revisão |
| Onde a interpretação do Bedrock recebe o documento | texto/JSON do Textract | PDF ou imagem anexada diretamente | evita repetir o custo e o não-determinismo da leitura de imagem | perde acesso a pistas visuais (layout, posição na página) que só a imagem carrega |
| Onde registrar a decisão final | DynamoDB, um item por campo | log apenas, sem tabela de decisão | consulta rápida por documento, e é a fonte que o L97 audita depois | modelagem por campo gera mais itens do que um registro único por documento |
A dívida que este laboratório não paga
O golden set de 60 documentos cobre nota fiscal e laudo técnico de reembolso — não cobre documento manuscrito, contrato em prosa livre, nem a possibilidade de fraude deliberada (nota fiscal adulterada). Este laboratório não estende a cascata para esses casos: cada um exigiria recalibrar o limiar contra um acervo diferente, e detectar adulteração é um problema de outra natureza — o de risco e conformidade que o L97 aprofunda.
Construir: o pipeline determinístico (S3 → Textract → cascata de confiança)
O bucket é o mesmo tipo de fonte que o L28 já dispara por evento: aqui ele guarda o PDF do laudo técnico e da nota fiscal, cifrado com uma chave própria porque carrega CNPJ e valor financeiro. A máquina de estados é quem decide, campo a campo, se a leitura do Textract segue automática, passa pelo Bedrock ou vira tarefa de revisão humana.
# pipeline-idp.tf -- bucket cifrado, evento, maquina de estados e tabela de
# decisao que compoem a cascata de confianca. Confira a versao do provider AWS
# antes de aplicar: aws_sfn_state_machine espera a definicao ASL como string
# JSON, e o shape dos blocos de estado muda pouco mas muda.
resource "aws_kms_key" "reembolsos" {
description = "Cifra documentos de reembolso e decisoes por campo da Cadencia"
deletion_window_in_days = 7
enable_key_rotation = true
tags = { squad = "financeiro", projeto = "idp-reembolso", lab = "L92" }
}
resource "aws_s3_bucket" "documentos_reembolso" {
bucket = "cadencia-reembolsos-documentos"
tags = { squad = "financeiro", projeto = "idp-reembolso", lab = "L92" }
}
resource "aws_s3_bucket_versioning" "documentos_reembolso" {
bucket = aws_s3_bucket.documentos_reembolso.id
versioning_configuration { status = "Enabled" }
}
resource "aws_s3_bucket_server_side_encryption_configuration" "documentos_reembolso" {
bucket = aws_s3_bucket.documentos_reembolso.id
rule {
apply_server_side_encryption_by_default {
sse_algorithm = "aws:kms"
kms_master_key_id = aws_kms_key.reembolsos.arn
}
}
}
# Notificacao via EventBridge -- o MESMO padrao do L28, sem reinventar: o
# bucket publica evento de objeto criado, e o EventBridge dirige a execucao.
resource "aws_s3_bucket_notification" "eventos_reembolso" {
bucket = aws_s3_bucket.documentos_reembolso.id
eventbridge = true
}
resource "aws_cloudwatch_event_rule" "documento_recebido" {
name = "cadencia-reembolso-documento-recebido"
event_pattern = jsonencode({
source = ["aws.s3"]
detail-type = ["Object Created"]
detail = {
bucket = { name = [aws_s3_bucket.documentos_reembolso.id] }
}
})
}
resource "aws_cloudwatch_event_target" "dispara_cascata" {
rule = aws_cloudwatch_event_rule.documento_recebido.name
arn = aws_sfn_state_machine.cascata_confianca.arn
role_arn = aws_iam_role.eventbridge_para_sfn.arn
}
resource "aws_dynamodb_table" "decisoes_reembolso" {
name = "cadencia-decisoes-reembolso"
billing_mode = "PAY_PER_REQUEST"
hash_key = "documentoId"
range_key = "campo"
attribute {
name = "documentoId"
type = "S"
}
attribute {
name = "campo"
type = "S"
}
server_side_encryption {
enabled = true
kms_key_arn = aws_kms_key.reembolsos.arn
}
}
resource "aws_cloudwatch_log_group" "cascata_confianca" {
name = "/aws/vendedlogs/states/cadencia-cascata-confianca"
retention_in_days = 90
# 90 dias: prazo suficiente para o financeiro auditar um reembolso contestado
# sem manter log indefinidamente -- retencao maior e custo sem beneficio aqui.
}
resource "aws_iam_role" "cascata_execucao" {
name = "cadencia-idp-cascata-execucao-role"
assume_role_policy = data.aws_iam_policy_document.confianca_step_functions.json
}
resource "aws_iam_role_policy" "cascata_permissoes" {
role = aws_iam_role.cascata_execucao.id
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Sid = "ExtrairComTextract"
Effect = "Allow"
# AnalyzeDocument nao suporta permissao a nivel de recurso -- a AWS nao
# expoe ARN de documento para esta acao. "*" aqui e a unica forma
# valida, nao um atalho de preguica.
Action = ["textract:AnalyzeDocument"]
Resource = "*"
},
{
Sid = "LerDocumentoDoAcervo"
Effect = "Allow"
Action = ["s3:GetObject"]
Resource = ["${aws_s3_bucket.documentos_reembolso.arn}/*"]
},
{
Sid = "InterpretarCampoRestrito"
Effect = "Allow"
Action = ["bedrock:InvokeModel"]
Resource = ["arn:aws:bedrock:us-east-1::foundation-model/anthropic.claude-3-5-haiku-20241022-v1:0"]
},
{
Sid = "DispararRevisaoHumana"
Effect = "Allow"
Action = ["sagemaker:StartHumanLoop"]
Resource = [aws_sagemaker_flow_definition.revisao_campo.arn]
},
{
Sid = "GravarDecisaoPorCampo"
Effect = "Allow"
Action = ["dynamodb:PutItem"]
Resource = [aws_dynamodb_table.decisoes_reembolso.arn]
},
]
})
}
resource "aws_sfn_state_machine" "cascata_confianca" {
name = "cadencia-cascata-confianca-reembolso"
role_arn = aws_iam_role.cascata_execucao.arn
logging_configuration {
log_destination = "${aws_cloudwatch_log_group.cascata_confianca.arn}:*"
include_execution_data = true
level = "ALL"
}
# Definicao completa (ASL) num arquivo separado -- o essencial e o Choice
# que ramifica por campo: confidence >= 98 segue automatico; entre 80 e 97,
# ou campo marcado como interpretativo, vai ao Bedrock; abaixo de 80, A2I.
definition = file("${path.module}/cascata-confianca.asl.json")
}
AnalyzeDocument não suporta permissão por recurso — o "Resource": "*" é legítimo aqui
É a exceção real da regra "nunca Resource: *": a API do Textract para AnalyzeDocument não expõe ARN de documento individual, então a AWS não oferece permissão a nível de recurso para essa ação — restringir por recurso não é possível, só por condição de rede ou por quem assume a role. O acesso ao DOCUMENTO em si continua restrito, pela policy de S3 logo acima na mesma role.
Construir: a decisão que chama Bedrock (C#/.NET 8)
A função abaixo é chamada pela máquina de estados só para os campos que a Choice roteou como interpretativos ou de confiança intermediária — nunca para o campo que já saiu automático do Textract, nem para o que já foi enviado ao A2I. É o ponto do pipeline onde a restrição "nunca a imagem, só o texto" mais importa.
// AvaliadorCampoLambda.cs -- Lambda chamada pela maquina de estados para os
// campos que a Choice roteou como "interpretativo ou confianca intermediaria".
// A diferenca estrutural em relacao a arquitetura minima nao e o SDK do
// Bedrock -- e que esta funcao NUNCA recebe o PDF, so o texto que o Textract
// ja extraiu.
public class AvaliadorCampoLambda
{
private readonly AmazonBedrockRuntimeClient _bedrock = new();
private const string ModeloArn =
"arn:aws:bedrock:us-east-1::foundation-model/anthropic.claude-3-5-haiku-20241022-v1:0";
// Campos que exigem interpretacao mesmo com confianca alta do Textract --
// porque o valor extraido e texto livre, nao um numero ou data que o
// proprio OCR ja resolve sozinho.
private static readonly HashSet<string> CamposInterpretativos = new()
{
"categoria_defeito", "motivo_laudo",
};
public async Task<CampoAvaliado> AvaliarAsync(CampoExtraido campo)
{
// Regra de roteamento: confianca alta E campo puramente estrutural
// segue automatico -- nunca chega aqui, a Choice da maquina de
// estados ja filtrou antes de invocar esta funcao.
bool exigeInterpretacao = CamposInterpretativos.Contains(campo.Nome)
|| (campo.Confianca is >= 80 and < 98);
if (!exigeInterpretacao)
{
throw new InvalidOperationException(
$"Campo '{campo.Nome}' com confianca {campo.Confianca} nao deveria ter " +
"chegado ao avaliador -- verifique a Choice da maquina de estados.");
}
// O prompt recebe SO o texto que o Textract extraiu -- nunca o PDF,
// nunca a imagem. Repetir a leitura de imagem aqui reintroduziria o
// custo e o nao-determinismo que o Textract ja eliminou.
var instrucao =
$"Campo: {campo.Nome}\nTexto extraido pelo Textract: \"{campo.ValorBruto}\"\n" +
"Se o campo for 'categoria_defeito' ou 'motivo_laudo', normalize para uma das " +
"categorias fixas do catalogo. Nunca invente um valor que nao esteja no texto acima.";
var resposta = await _bedrock.InvokeModelAsync(new InvokeModelRequest
{
ModelId = ModeloArn,
Body = MontarCorpo(instrucao),
});
var valorInterpretado = ExtrairTexto(resposta);
// O resultado do Bedrock ainda passa pelo registro de decisao com
// origem "bedrock" -- nao vira aprovacao automatica so por ter
// passado pelo modelo. A auditoria distingue os tres caminhos.
return new CampoAvaliado(campo.Nome, valorInterpretado, origem: "bedrock");
}
}
O ponto que mais separa esta função do cliente da arquitetura mínima não é o SDK usado — é o que a função RECEBE. Na versão mínima, o modelo recebe o PDF inteiro e decide tudo de uma vez. Aqui, ele recebe um único campo, já extraído em texto, e sua única tarefa é interpretar — nunca ler.
Segurança: quem pode extrair, interpretar e revisar
Três papéis distintos participam deste desenho, cada um com privilégio calculado pelo uso real — o mesmo princípio do L41, aplicado a uma cascata em vez de a um banco. A role da máquina de estados (seção de construção anterior) invoca Textract, o modelo específico de interpretação e o fluxo específico de revisão. A role abaixo, de um consumidor externo hipotético que só precisa consultar uma decisão já tomada, nunca invoca `bedrock:*` nem qualquer outro fluxo de revisão que não seja o do reembolso.
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "ChamarModeloDeInterpretacaoRestrito",
"Effect": "Allow",
"Action": ["bedrock:InvokeModel"],
"Resource": [
"arn:aws:bedrock:us-east-1::foundation-model/anthropic.claude-3-5-haiku-20241022-v1:0"
]
},
{
"Sid": "DispararRevisaoNoFluxoCorreto",
"Effect": "Allow",
"Action": ["sagemaker:StartHumanLoop"],
"Resource": ["arn:aws:sagemaker:us-east-1:111122223333:flow-definition/cadencia-revisao-campo-reembolso"]
},
{
"Sid": "GravarSoNaTabelaDeDecisoes",
"Effect": "Allow",
"Action": ["dynamodb:PutItem", "dynamodb:GetItem"],
"Resource": ["arn:aws:dynamodb:us-east-1:111122223333:table/cadencia-decisoes-reembolso"]
},
{
"Sid": "SemAcessoAOutroFluxoDeRevisao",
"Effect": "Deny",
"Action": ["sagemaker:StartHumanLoop"],
"NotResource": "arn:aws:sagemaker:us-east-1:111122223333:flow-definition/cadencia-revisao-campo-reembolso"
}
]
}
Por que o Deny explícito, e não só a ausência de Allow
A instrução negada explicitamente (`NotResource`) fecha uma porta que a ausência de `Allow` não fecha sozinha: sem ela, a mesma credencial poderia, no futuro, ser reusada para disparar revisão humana num outro fluxo criado por outro time — por exemplo, um que revisasse dado de RH. `Deny` explícito bloqueia isso mesmo que uma policy futura, mal escrita, tente abrir — `Deny` sempre vence sobre `Allow` na avaliação do IAM.
Implantar, e provar com número
A prova não é "a cascata parece mais confiável" — é rodar o mesmo conjunto de 60 documentos (360 campos) duas vezes, contra os dois desenhos, e contar.
# prova.sh -- roda o MESMO golden set de 60 documentos (360 campos) contra os
# dois desenhos, e conta. Nenhuma conclusao aqui vem de "o pipeline parece
# mais confiavel".
GOLDEN_SET=golden-set-reembolsos-cadencia.jsonl # 60 documentos, 6 campos cada, valor correto conhecido
# -- Rodada 1: PDF direto pro Bedrock extrair tudo (Figura 1) ----------------
python3 avaliar.py --endpoint extrair-com-llm --golden "$GOLDEN_SET" \
--saida resultado-llm-direto.json
# Resultado medido: 35 de 360 campos errados (9,7%); 0 de 360 com confianca
# declarada; 4 de 60 documentos deram leitura DIFERENTE ao reprocessar o
# mesmo PDF duas vezes -- nao-determinismo medido, nao suposto.
# -- Rodada 2: pipeline com Textract, confianca e revisao (Figura 2) ---------
python3 avaliar.py --endpoint cascata-confianca --golden "$GOLDEN_SET" \
--saida resultado-cascata.json
# Resultado medido: 2 de 360 campos errados (0,6%); 298 de 360 (82,8%)
# aprovados automaticamente; 41 de 360 (11,4%) interpretados pelo Bedrock;
# 21 de 360 (5,8%) foram para revisao humana no A2I.
# -- Diagnostico dos 2 erros residuais ----------------------------------------
jq '.[] | select(.correto == false)' resultado-cascata.json
# 1 caso: revisor confirmou o valor lido pelo Textract sem notar que uma
# assinatura sobre o numero alterava um digito -- erro humano, nao
# do sistema, e por isso a taxa residual nao e zero.
# 1 caso: confianca do Textract em 81%, um ponto acima do limiar de 80, mas
# o campo tinha dois valores proximos na mesma linha -- deveria ter
# caido para revisao e nao caiu por pouco.
| Prova | Antes — LLM direto (Figura 1) | Depois — cascata de confiança (Figura 2) | O que mudou |
|---|---|---|---|
| Taxa de erro por campo (360 campos) | 35/360 — 9,7% | 2/360 — 0,6% | a extração determinística com confiança elimina o erro silencioso; sobra o erro correlacionado a limiar e a revisor |
| Campos aprovados automaticamente | 0/360 — 0% (todo campo passa pela mesma geração) | 298/360 — 82,8% | confiança alta do Textract dispensa Bedrock e humano na maioria dos campos |
| Campos interpretados pelo Bedrock | 360/360 — 100% (todo campo, sempre) | 41/360 — 11,4% | Bedrock restrito ao subconjunto que exige interpretação semântica |
| Campos enviados para revisão humana | 0/360 — nenhuma revisão prevista no desenho | 21/360 — 5,8% | revisão humana no desenho, não como exceção — para o que fica abaixo do limiar |
| Mesmo documento, duas execuções, resultado idêntico | 56/60 — 4 documentos com leitura diferente entre execuções | 60/60 — a extração do Textract é determinística | determinismo deixa de ser esperança e vira propriedade medida |
A taxa de erro aponta ONDE olhar, não conserta sozinha
Os 2 erros residuais não são aleatórios, e por isso são corrigíveis: o caso de assinatura sobre o número pede treinamento do time de revisão, não mudança de arquitetura; o caso de confiança em 81% pede recalibrar o limiar ou refinar a regra para campos com dois valores próximos na mesma linha. Nenhum dos dois se resolve rodando o mesmo teste de novo — cada um exige uma correção diferente, identificada pelo diagnóstico, não pela taxa agregada sozinha.
Quebrar de propósito: quatro falhas, e a que o número de confiança não vê
O erro de R$ 44,5 mil não foi um erro de leitura: os dígitos "45.822" estavam impressos no documento e foram lidos corretamente. As injeções abaixo separam os tipos de erro que este pipeline pode cometer — e a primeira mostra por que um número alto de confiança não protege contra o pior deles.
| Falha injetada | Como injetar | Sintoma enganoso | Diagnóstico correto |
|---|---|---|---|
| Campo trocado, com confiança alta | Submeter um formulário em que número da nota e valor do reembolso ficam próximos, na mesma região da página | O Textract reporta confiança alta para o campo, a cascata deixa passar automático, e o JSON sai sem nenhuma marca de incerteza | A confiança do reconhecimento responde "eu li estes caracteres corretamente?" — e a resposta é sim, porque os dígitos existem mesmo na página. A pergunta que ninguém fez é "estes caracteres pertencem a ESTE campo?", que é associação espacial e semântica, não reconhecimento óptico. Confiança alta sobre o valor errado é o modo de falha central deste laboratório, e a defesa não é aumentar o limiar: é validar o campo contra uma regra que ele precisa obedecer — valor de reembolso não pode exceder o valor da nota, e essa única checagem teria pego os R$ 45.822 |
| Fila de revisão humana sem revisor | Enviar documentos para revisão com a equipe de plantão indisponível | O pipeline não reporta erro. As execuções ficam aguardando, e o painel de falhas continua limpo | Revisão humana é uma dependência com disponibilidade, e o desenho tratou como se fosse instantânea. Do ponto de vista do lojista, o reembolso simplesmente não anda. Precisa existir prazo declarado para a tarefa, alarme de fila envelhecendo, e uma decisão escrita sobre o que acontece quando o prazo estoura — aprovar não é opção, então é escalonamento, e escalonamento precisa de dono |
| A imagem inteira enviada ao modelo em vez do texto extraído | Trocar a entrada da função de interpretação pelo PDF original | Funciona, e às vezes funciona melhor em documento bem escaneado | É exatamente a arquitetura mínima que este laboratório substituiu, voltando por dentro. O pipeline perde a etapa determinística, perde o número de confiança por campo que alimenta a cascata, e volta a produzir extração sem nenhuma marca de incerteza — que é a causa raiz do incidente. Funcionar em documento fácil nunca foi o critério: o critério é o laudo escaneado torto |
| Limiar calibrado num tipo de documento, aplicado em outro | Usar o limiar afinado para nota fiscal digital nos laudos escaneados de assistência técnica | A taxa de envio a revisão humana CAI, e o painel de eficiência melhora | Menos revisão humana com a mesma qualidade seria ótimo; menos revisão humana porque o limiar está frouxo para aquele tipo de documento é dano automatizado. A distribuição de confiança do Textract difere por qualidade de digitalização, e um limiar único trata documentos desiguais como iguais. Limiar é por TIPO de documento, e cada um precisa da sua própria calibração contra amostra revisada |
A regra de negócio pega o que a confiança não pega
A lição mais transferível deste laboratório cabe em uma frase: extração probabilística precisa de validação determinística por cima. Valor de reembolso menor ou igual ao valor da nota, CNPJ com dígito verificador válido, data não futura — três checagens triviais, custo zero, e cada uma pega uma classe inteira de erro que nenhum número de confiança denuncia.
Um atendente do financeiro recebe um JSON do Bedrock com os 6 campos do reembolso preenchidos, extraídos direto de uma foto do laudo técnico. Por que confiar nesse JSON sem nenhuma etapa determinística antes é arriscado, mesmo o modelo conseguindo "ler" a imagem perfeitamente bem em texto corrido?
Observabilidade: as perguntas que o painel tem de responder
Este pipeline tem um instrumento que a maioria não tem: um humano olhando parte das saídas. Isso torna mensurável algo raro — com que frequência o automático estava errado — e é a pergunta mais valiosa do painel.
- Quando um humano revisa, com que frequência ele MUDA o valor? É a taxa de erro real do caminho automático naquela faixa de confiança, medida sem gabarito sintético.
- Como a confiança se distribui por campo e por tipo de documento? Um único limiar sobre distribuições diferentes é a quarta injeção de falha.
- Quantos documentos foram reprovados pela validação de regra de negócio depois de passarem pela confiança? Cada um é um erro que o número de confiança não viu.
- Qual a idade da tarefa mais antiga na fila de revisão? É a métrica que denuncia a segunda injeção, e ela não aparece em nenhum painel de erro.
- Qual o custo por documento processado, separando o caminho automático do caminho com revisão humana?
| Alarme | Limiar inicial | O que ele pega |
|---|---|---|
| TaxaDeCorrecaoHumana | acima de 15% das revisões da semana | o limiar daquele tipo de documento está frouxo — o automático está errando mais do que o desenho assume |
| ReprovacaoPorRegraDeNegocio | qualquer ocorrência acima da linha de base | campo trocado com confiança alta — a primeira injeção acontecendo em produção |
| IdadeDaFilaDeRevisao | acima do prazo declarado para a tarefa | revisão parada por falta de revisor, com o pipeline em silêncio |
| ConfiancaMediaPorTipoDeDocumento | desvio da linha de base daquele tipo | mudança na qualidade de digitalização de uma origem — fornecedor novo, scanner novo |
| CustoPorDocumento | acima do dobro da linha de base | aumento da fração enviada a revisão humana, que é o caminho caro |
Escala: 340 pedidos por mês, 3.400, 34 mil — e o gargalo que não é técnico
| Ordem de grandeza | O que muda no desenho | O que NÃO muda |
|---|---|---|
| 340 pedidos por mês (hoje) | Nada. A máquina de estados absorve, e a revisão humana cabe na rotina do financeiro sem equipe dedicada | A cascata de confiança e a validação por regra — que já eram necessárias em volume baixo, porque o incidente aconteceu com 340 |
| 3.400 pedidos por mês | A revisão humana deixa de caber na rotina e vira função. O limiar passa a ser uma decisão econômica explícita: cada ponto percentual a mais de automação economiza revisor e compra risco | A necessidade de calibrar o limiar por tipo de documento, que fica mais importante, não menos |
| 34 mil pedidos por mês | O gargalo é a fila humana, não o processamento — e nenhuma escolha de arquitetura de nuvem resolve isso. As alavancas passam a ser: melhorar a extração para reduzir a fração revisada, e priorizar a fila por valor em risco, revisando primeiro o que dói mais errar | Que existe um piso de revisão humana. Nenhum limiar leva a fração a zero sem aceitar erro, e a decisão de quanto erro aceitar não é do time de engenharia |
| Perda de uma zona ou da região | Os serviços são regionais e gerenciados; a execução em curso retoma. O que não retoma sozinho é a tarefa humana pendente | Documento pendente de revisão é estado que precisa sobreviver a qualquer falha — e é o único estado deste pipeline que não pode ser reconstruído reprocessando o PDF |
Custo: as quatro linhas, e a que é dez vezes as outras três
A conta deste pipeline tem uma característica incomum na série: o item mais caro não é da AWS. Ignorar isso leva a otimizar a linha errada com afinco.
| Cenário | O que domina | O que ninguém nota |
|---|---|---|
| Hoje — 340 pedidos, revisão diluída na rotina | O custo do revisor está escondido, porque ninguém o contabiliza: é o financeiro fazendo "mais uma tarefa" | Custo invisível não é custo zero. Quando o volume subir, ele aparece de uma vez como pedido de contratação, e a decisão de limiar terá sido tomada meses antes sem esse número na mesa |
| Limiar apertado — 40% dos campos revisados | A revisão humana, com folga sobre extração e modelo somados | Baixar o limiar de 40% para 25% de revisão vale mais em dinheiro que qualquer otimização de prompt — e só é seguro se a taxa de correção humana naquela faixa mostrar que o automático acerta. O painel já mede exatamente isso |
| Limiar frouxo — 10% revisados | A extração e o modelo passam a dominar a fatura, e o custo cai bastante | E o custo do erro sobe. O termo que falta na fórmula é o valor em risco por reembolso aprovado errado — R$ 44,5 mil num único caso. Qualquer conversa sobre baixar o limiar precisa desse número ao lado, senão a comparação é entre um custo medido e um custo ignorado |
O número que decide o limiar
Preço por página processada, por objeto enviado a revisão e por 1.000 tokens muda por região e por modelo. Trate como ordem de grandeza; confirme na página de preços antes de levar a proposta. É a comparação entre o custo do minuto de revisão e o valor esperado do erro — probabilidade de erro naquela faixa de confiança, medida pela taxa de correção humana, multiplicada pelo valor em risco. Os dois lados são mensuráveis com o que este pipeline já instrumenta, e é raro poder tomar uma decisão dessas com dado em vez de opinião.
Well-Architected nos seis pilares
| Pilar | Situação hoje | Risco | Melhoria | Prioridade |
|---|---|---|---|---|
| Excelência operacional | Cascata versionada; limiar como configuração | Limiar único aplicado a tipos de documento com qualidade muito diferente | Limiar por tipo de documento, calibrado contra amostra revisada, com data da última calibração visível | Alta |
| Segurança | Bucket cifrado com chave própria; papéis escopados por etapa | Os documentos carregam CNPJ e valor financeiro, e o texto extraído é uma cópia desses dados em outro lugar | Aplicar ao texto extraído e às tarefas de revisão a mesma classificação e retenção do documento original — a cópia costuma ser esquecida | Alta |
| Confiabilidade | Máquina de estados com retomada; serviços gerenciados | Tarefa de revisão humana pendente é estado que não se reconstrói reprocessando o documento | Tratar a fila de revisão como dado crítico, com alarme de envelhecimento e plano para revisor indisponível | Alta |
| Eficiência de desempenho | Modelo chamado só para campos interpretativos | A latência do caminho com revisão humana é de horas, e a média com o caminho automático não significa nada | Medir os dois caminhos separadamente; a promessa ao lojista é sobre o caminho dele | Média |
| Otimização de custo | Fração revisada definida por um limiar que ninguém recalibrou | O termo dominante da conta é governado por um número escolhido uma vez | Revisar o limiar contra a taxa de correção humana em cadência fixa — é a alavanca de maior retorno financeiro do laboratório | Alta |
| Sustentabilidade | Processamento sob demanda, sem capacidade ociosa | Reprocessamento de documento por falha de validação gasta duas vezes | Validar regra de negócio ANTES de chamar o modelo, quando o campo já vier do caminho determinístico | Baixa |
Onde mais IA entra neste pipeline, e onde ela não pode aprovar
| Ideia | Vale a pena? | Por quê |
|---|---|---|
| Aprender o limiar por tipo de documento a partir das correções humanas | Sim, e é o ganho mais direto | Cada revisão humana produz um rótulo de graça: o valor automático estava certo ou errado. Com alguns meses disso, o limiar deixa de ser um número escolhido e passa a ser derivado da taxa de erro observada por faixa de confiança e por tipo de documento. É a alavanca que governa o termo dominante da conta, ajustada por dado que o pipeline já gera e hoje descarta |
| Um modelo decidindo se o reembolso é aprovado | Não | Extração e decisão são coisas diferentes, e este laboratório trata da primeira. Aprovar pagamento é ato com consequência financeira e responsabilidade nomeada; a pergunta "dá para explicar esta aprovação a um auditor?" não tem resposta boa quando o decisor é um modelo. O pipeline entrega campos confiáveis com incerteza declarada — quem aprova é regra, ou é pessoa |
| Detectar documento fraudado | Não como extensão deste pipeline | É um problema diferente, com dados de treino diferentes e consequências legais próprias, e enxertá-lo aqui contamina a métrica de extração com uma métrica de fraude. Se o risco for real, é laboratório próprio — e começa por medir quantos casos existem, que quase nunca é o número que se imagina |
Anti-padrões deste laboratório
| Anti-padrão | Por que alguém faz | Sintoma em produção | Forma correta |
|---|---|---|---|
| Enviar o PDF inteiro pro LLM extrair tudo | parece mais simples que configurar Textract com forms/tables, até o erro custar dinheiro real num reembolso indevido | campo estruturado lido errado sem nenhum sinal de incerteza, aprovado sem checagem | Textract determinístico primeiro, com confiança declarada por campo |
| Aprovar automático qualquer confiança acima de um número redondo | menos revisão humana parece processo mais rápido no papel | campo com confiança 81% (mal calibrado) aprovado quando o documento tinha ambiguidade real | calibrar o limiar medindo erro residual contra um golden set, não escolher um número por hábito |
| Bedrock decidindo se o próprio valor extraído está certo, sem humano | parece "mais IA", e evita construir um fluxo de revisão | o modelo confirma o próprio erro com aparência de confiança — não há segunda fonte de verdade | revisão humana real via A2I para campo abaixo do limiar, não outro modelo validando o primeiro |
| Revisar 100% dos documentos manualmente, achando mais seguro | elimina o medo de um erro automatizado passar despercebido | a fila de revisão cresce junto com o volume, e o time volta a gastar o tempo que o pipeline deveria economizar | revisão só onde a confiança pede, medida e ajustada pelo limiar |
| Passar a imagem do documento pro Bedrock interpretar, em vez do texto do Textract | parece manter mais contexto visual disponível para o modelo | custo maior por chamada e resultado não-determinístico, repetindo o problema que o Textract já resolveu | Bedrock recebe só o texto/JSON já extraído, nunca a imagem, nos campos que exigem interpretação |
Evolução em níveis: do PDF cru à decisão auditável de ponta a ponta
A terceira arquitetura não é um desenho novo — é a resposta a QUANDO trocar de desenho. Cada nível resolve um risco medido neste laboratório e compra outro no lugar.
Chamada direta ao Bedrock com o PDF inteiro, sem Textract, sem confiança por campo. É o que a Cadência tinha, e sobreviveu 3 semanas sem ninguém notar.Extração determinística com Textract, confiança por campo, Bedrock só nos campos interpretativos, e revisão humana via A2I abaixo do limiar (9,7% → 0,6%).Textract Queries (perguntas específicas por tipo de documento) e classificação automática do tipo antes de escolher o template de extração.Bedrock Guardrails (L86) limitando o escopo da interpretação, e um agente (L87) capaz de solicitar automaticamente um documento complementar ao lojista quando falta.O golden set vira suíte de regressão no CI a cada mudança de limiar ou prompt, com amostragem periódica de decisões automáticas para auditoria — mesmo as que nunca passaram por humano.A trilha de cada decisão (documento, campo, confiança, origem, revisor) vira insumo do L97 — auditoria de conformidade reconstrói, campo a campo, por que um reembolso foi aprovado ou recusado, com explicabilidade sobre a IA envolvida.Por que este laboratório vem antes do L97
A trilha imutável de decisão que o L97 audita (nível 6) pressupõe que já existe uma decisão granular, campo a campo, com origem e revisor registrados — é exatamente o que este laboratório grava no DynamoDB. Quem tenta construir auditoria de conformidade antes de ter uma decisão auditável para auditar está otimizando um rastro que ainda não existe.
Quando algo não funciona
| Sintoma | Causa provável | Como investigar | Log ou métrica | Correção |
|---|---|---|---|---|
| Campo com confiança alta e valor errado | Associação espacial trocada: os caracteres foram lidos certo, do lugar errado | Abrir o documento e localizar de onde vieram os caracteres reportados | Reprovações pela validação de regra de negócio | Validar por regra — reembolso não excede a nota, CNPJ com dígito válido. Aumentar o limiar não resolve, porque a confiança já estava alta |
| Reembolsos parados sem erro no painel | Fila de revisão humana sem revisor disponível | Consultar a idade da tarefa mais antiga pendente | Idade da fila de revisão | Alarme de envelhecimento e caminho de escalonamento declarado. Ausência de erro não é ausência de problema |
| A taxa de revisão caiu e a de reclamação subiu | Limiar de um tipo de documento aplicado a outro, mais difícil | Separar a distribuição de confiança por tipo de documento | Confiança média por tipo; taxa de correção humana por tipo | Calibrar por tipo. Melhora de eficiência sem melhora de qualidade quase sempre é um limiar que afrouxou |
| O modelo devolve JSON que não obedece ao formato | Saída livre em vez de saída estruturada com esquema | Registrar a resposta bruta do modelo para os casos que falharam a desserialização | Falhas de desserialização por campo | Exigir saída estruturada com esquema declarado. Analisar texto livre à mão para extrair JSON é a fonte de defeito mais evitável deste pipeline |
| Custo por documento subiu sem aumento de volume | A fração enviada a revisão humana cresceu — origem nova com digitalização pior | Comparar a distribuição de confiança da semana com a linha de base, por origem | Custo por documento, separado por caminho | Se a origem nova é permanente, ela precisa da própria calibração. O custo subiu porque o pipeline está fazendo a coisa certa com material pior |
Limpeza: o que o destroy não leva
# limpeza.sh -- ordem importa: a maquina de estados referencia o fluxo de
# revisao e a tabela, e o Terraform destroy sozinho nao esvazia bucket
# versionado nem espera tarefa de revisao pendente terminar.
# 1) Confirmar que nao ha tarefa de revisao humana pendente no A2I --
# cancelar o fluxo com tarefa aberta perde o registro de quem estava revisando.
aws sagemaker list-human-loops --flow-definition-arn \
arn:aws:sagemaker:us-east-1:111122223333:flow-definition/cadencia-revisao-campo-reembolso \
--sort-order Descending --query "HumanLoopSummaries[?HumanLoopStatus=='InProgress']"
# Esperado: lista vazia. Se nao estiver, espere a tarefa terminar antes do passo 4.
# 2) Apagar a regra do EventBridge e o alvo antes da maquina de estados
aws events remove-targets --rule cadencia-reembolso-documento-recebido --ids 1
aws events delete-rule --name cadencia-reembolso-documento-recebido
# 3) Esvaziar TODAS as versoes do bucket antes do destroy -- bucket versionado
# com objeto dentro nao e removido por "terraform destroy" nem por
# "aws s3 rb" simples; e o bucket que mais dinheiro esconde depois do laboratorio.
aws s3api list-object-versions --bucket cadencia-reembolsos-documentos \
--query "[Versions,DeleteMarkers][].{Key:Key,VersionId:VersionId}" --output json \
| jq -c '.[]' | while read -r obj; do
aws s3api delete-object --bucket cadencia-reembolsos-documentos \
--key "$(echo "$obj" | jq -r .Key)" --version-id "$(echo "$obj" | jq -r .VersionId)"
done
# 4) terraform destroy cuida do resto: maquina de estados, tabela do DynamoDB,
# grupo de logs, roles do IAM, o bucket ja vazio, e a chave do KMS
# (que so entra em janela de exclusao, nao some na hora)
terraform destroy -auto-approve
# 5) Conferir que a chave do KMS entrou em janela de exclusao, e nao ficou ativa
aws kms describe-key --key-id alias/cadencia-reembolsos --query "KeyMetadata.KeyState"
# Esperado: "PendingDeletion" -- ela continua cobrando ate os 7 dias da janela passarem
O que continua cobrando (ou pendente) depois de "destruir"
Três coisas que `terraform destroy` sozinho não resolve por completo: um bucket S3 versionado com objeto dentro fica preso até esvaziar toda versão manualmente; o grupo de logs da máquina de estados continua com a retenção de 90 dias configurada, cobrando armazenamento até expirar; e a chave do KMS não é apagada na hora — ela entra numa janela de exclusão de 7 a 30 dias, durante a qual continua sendo cobrada. Confira o passo 5 antes de fechar o navegador achando que a fatura zerou.
Resumo: problema, peça e motivo
| Problema | Peça | Motivo |
|---|---|---|
| Campo estruturado lido errado sem aviso | Textract AnalyzeDocument (FORMS+TABLES) | extração determinística com confiança nativa por campo |
| Confiar cegamente na fluência do JSON | Limiar de confiança na Step Functions | decide entre aprovação automática, interpretação e revisão humana |
| Campo de texto livre que Textract não interpreta | Bedrock, só com o texto extraído | interpretação semântica restrita ao que exige, nunca a imagem |
| "IA decide tudo" sem segunda fonte de verdade | Amazon A2I | revisão humana real abaixo do limiar, no desenho, não como exceção |
| Decisão sem rastro para auditoria | DynamoDB, um item por campo | quem revisou, quando, e qual foi o valor final |
| Dado financeiro sem cifra própria | KMS com chave gerenciada pelo cliente | cifra o bucket de documentos e a tabela de decisões |
Perguntas frequentes
❓ Por que o Bedrock não pode simplesmente ler o PDF direto?
❓ Todo campo extraído precisa passar pelo Bedrock antes da decisão?
❓ O que acontece com um campo que fica com confiança abaixo de 80%?
❓ O limiar de 80% de confiança é um valor fixo da AWS?
❓ Revisão humana no A2I garante que o campo final está sempre certo?
❓ Por que o Bedrock recebe o texto do Textract e não a imagem do documento?
❓ Esse pipeline poderia ser usado para qualquer tipo de documento da Cadência?
❓ Por que registrar cada campo no DynamoDB em vez de só o documento inteiro?
Fixando
No pipeline da Cadência, um campo de valor extraído pelo Textract vem com confiança de 76%, abaixo do limiar de 80% configurado na máquina de estados. O que o desenho faz com esse campo?
Depois de implantar a cascata, a taxa de erro no golden set caiu de 9,7% (LLM lendo o PDF direto) para 0,6% (Textract + confiança + revisão humana), mas não chegou a 0%. Os 2 erros residuais vieram de um revisor que confirmou um valor sem notar uma assinatura sobreposta, e de um campo com confiança de 81% — um ponto acima do limiar — que na verdade era ambíguo. O que essa diferença prova sobre a cascata?
Próximo laboratório
Próximo passo: L97 (risco e conformidade de decisão automatizada)
Este laboratório grava, campo a campo, a origem de cada decisão de reembolso — automática, interpretada pelo Bedrock ou revisada por humano — com quem revisou e quando. O L97 usa exatamente esse registro granular como matéria-prima: uma auditoria pergunta por que um reembolso específico foi aprovado ou recusado, e a trilha imutável de decisão precisa reconstruir a resposta de ponta a ponta, campo a campo, sem depender de ninguém lembrar o que aconteceu.
Terminou de ler?
Marcar como concluído registra o XP, mantém sua sequência e coloca 3 cartas deste módulo na fila de revisão espaçada.
Próximos passos sugeridos
Temas deste módulo
Discussão
Carregando comentários…