Consulte sinistros em linguagem natural com o Amazon Bedrock Knowledge Bases

O desafio de consultar sinistros em linguagem natural

Quem trabalha com seguros sabe bem o problema: as informações de um sinistro estão espalhadas por relatórios de ajustadores, estimativas de reparo, boletins de ocorrência, registros de pagamento e anexos digitalizados — nunca em um único campo pesquisável. Um segurado quer saber se o sinistro foi aprovado. Um ajustador precisa listar todos os sinistros de automóvel abertos acima de R$ 10.000 do mês passado. Ambas as tarefas exigem encontrar e combinar evidências com rapidez e precisão.

Para resolver isso, a AWS publicou um guia técnico detalhado mostrando como construir um assistente de sinistros com o Amazon Bedrock Knowledge Bases — a capacidade de Geração Aumentada por Recuperação (RAG) totalmente gerenciada do Amazon Bedrock. O serviço cuida de toda a infraestrutura de análise, fragmentação, embeddings e armazenamento vetorial, permitindo criar uma interface conversacional que retorna respostas com citações diretas dos documentos de sinistro.

Vale destacar que o tutorial usa registros sintéticos de sinistros e não descreve um deployment real de produção.

Visão geral da solução

A arquitetura tem dois fluxos principais: ingestão e recuperação.

No fluxo de ingestão, os documentos de sinistro chegam ao Amazon S3 junto com arquivos de metadados auxiliares. Um job de ingestão sincroniza a fonte de dados S3 com a base de conhecimento, que analisa, fragmenta, embute e indexa tudo no armazenamento vetorial gerenciado.

No fluxo de recuperação, a aplicação chama a API AgenticRetrieveStream com a pergunta, o histórico da conversa e filtros de metadados opcionais. Um modelo de fundação cria sub-consultas e repete a recuperação até reunir evidências suficientes. Em seguida, uma verificação de fundamentação contextual bloqueia respostas não suportadas pelos registros recuperados. O Amazon Bedrock transmite a resposta, os eventos de rastreamento e as citações em streaming.

A recuperação agêntica via AgenticRetrieveStream planeja a resposta, decompõe perguntas complexas em sub-consultas e executa uma ou mais rodadas de recuperação — verificando se as evidências são suficientes antes de gerar a resposta final.

Preparando os documentos e metadados

A recomendação é armazenar um documento por sinistro no Amazon S3. A base de conhecimento lê PDFs, documentos Word e arquivos de texto diretamente em seu formato nativo.

Para habilitar filtros, cada documento deve ter um arquivo de metadados auxiliar com o mesmo nome acrescido de .metadata.json. Por exemplo, para CLM-100482.pdf, o arquivo seria CLM-100482.pdf.metadata.json:

{
  "metadataAttributes": {
    "claim_id": "CLM-100482",
    "claim_type": "auto",
    "status": "open",
    "date_filed": 20260709,
    "amount": 14250,
    "region": "us-west",
    "adjuster": "Martha Rivera",
    "policyholder": "Mary Major",
    "policy_number": "POL-AUTO-78432",
    "customer_id": "CUST-MM-1042",
    "household_id": "HHD-MM-1042",
    "document_type": "adjuster_report",
    "carrier": "Example Insurance",
    "has_subrogation": true,
    "has_litigation": false,
    "complexity_tier": "high"
  }
}

O arquivo auxiliar contém valores escalares de string, número e booleano. Alguns pontos importantes de design: datas devem ser armazenadas como inteiros no formato YYYYMMDD, pois os filtros de metadados comparam números, não strings. Isso permite filtros de intervalo como “registrado no mês passado”. Apenas um valor monetário comparável deve ficar no campo amount; reservas, pagamentos e retenções devem permanecer no texto do documento para que seus rótulos fiquem claros. Os arquivos auxiliares têm limite de 10 KB — consulte a documentação Connect to Amazon S3 for your knowledge base para o formato completo.

Criando a base de conhecimento e ingerindo os sinistros

A base de conhecimento é criada com o cliente bedrock-agent. Definindo o tipo como MANAGED, o Amazon Bedrock seleciona e opera o modelo de embedding automaticamente — sem necessidade de configurar um armazenamento vetorial. Veja a referência CreateKnowledgeBase para todos os parâmetros:

import boto3

bedrock_agent = boto3.client("bedrock-agent", region_name="us-west-2")

kb = bedrock_agent.create_knowledge_base(
    name="insurance-claims-kb",
    description="Synthetic insurance claims for the claims assistant",
    roleArn="arn:aws:iam::111122223333:role/InsuranceClaimsKnowledgeBaseRole",
    knowledgeBaseConfiguration={
        "type": "MANAGED",
        "managedKnowledgeBaseConfiguration": {
            "embeddingModelType": "MANAGED"
        },
    },
)
kb_id = kb["knowledgeBase"]["knowledgeBaseId"]

O roleArn é a função de serviço que concede à base de conhecimento permissão para ler o bucket S3 e usar o modelo de embedding gerenciado. Consulte como criar uma função de serviço para o Amazon Bedrock Knowledge Bases. Para criptografar o armazenamento vetorial gerenciado com uma chave gerenciada pelo cliente do Serviço de Gerenciamento de Chaves da AWS (AWS KMS), passe o ARN dela em serverSideEncryptionConfiguration.

Em seguida, conecta-se o bucket S3 como fonte de dados, limitando a ingestão ao prefixo claims/:

data_source = bedrock_agent.create_data_source(
    knowledgeBaseId=kb_id,
    name="claims-s3",
    dataSourceConfiguration={
        "type": "S3",
        "s3Configuration": {
            "bucketArn": "arn:aws:s3:::amzn-s3-demo-insurance-claims",
            "inclusionPrefixes": ["claims/"],
        },
    },
)
data_source_id = data_source["dataSource"]["dataSourceId"]

Com a fonte de dados criada, inicia-se o job de ingestão para analisar, fragmentar, embutir e indexar os documentos. Esse job deve ser executado novamente sempre que documentos forem adicionados ou atualizados:

bedrock_agent.start_ingestion_job(
    knowledgeBaseId=kb_id,
    dataSourceId=data_source_id,
)

O status pode ser verificado com get_ingestion_job ou pelo console do Amazon Bedrock. Quando o job conclui, os sinistros estão pesquisáveis. Veja a referência StartIngestionJob para detalhes.

Consultando sinistros com a API AgenticRetrieveStream

Com os sinistros ingeridos, a chamada à API usa o cliente bedrock-agent-runtime. A requisição tem três partes: messages (turnos da conversa), retrievers (até cinco bases de conhecimento, com filtros e limite de resultados opcionais) e agenticRetrieveConfiguration (modelo de planejamento e limite de iterações). Definindo generateResponse como True, o serviço retorna uma resposta em linguagem natural:

bedrock_agent_runtime = boto3.client("bedrock-agent-runtime", region_name="us-west-2")

response = bedrock_agent_runtime.agentic_retrieve_stream(
    messages=[
        {"role": "user", "content": {"text": "What is the status of claim CLM-100482?"}}
    ],
    retrievers=[
        {
            "configuration": {"knowledgeBase": {"knowledgeBaseId": kb_id}},
            "description": "Synthetic insurance claim records",
        }
    ],
    agenticRetrieveConfiguration={
        "foundationModelType": "MANAGED",
        "maxAgentIteration": 5,
    },
    generateResponse=True,
)

O stream de resposta emite três tipos de eventos: traceEvent (plano de recuperação, sub-consultas, ações de guardrail), responseEvent (texto incremental da resposta) e result (resultados de recuperação deduplicados, resposta completa e citações). O loop abaixo transmite os fragmentos da resposta em tempo real e retém o resultado final para renderizar as citações:

answer = ""
final_result = None

for event in response["stream"]:
    if "traceEvent" in event:
        attributes = event["traceEvent"]["attributes"]
        print(f"[trace] {attributes.get('step')}: {attributes.get('status')}")
    elif "responseEvent" in event:
        chunk = event["responseEvent"]["text"]
        answer += chunk
        print(chunk, end="", flush=True)
    elif "result" in event:
        final_result = event["result"]

Lendo o rastreamento do loop agêntico

A função auxiliar abaixo imprime sub-consultas, buscas de documentos completos e ações de guardrail a partir dos eventos de rastreamento:

def report_trace(trace_event):
    attributes = trace_event.get("attributes", {})
    print(f"[trace] {attributes.get('step')}: {attributes.get('status')}")
    for action in attributes.get("actions", []):
        if "retrieve" in action:
            sub_query = action["retrieve"].get("inputQuery", {}).get("text", "")
            print(f"  sub-query: {sub_query}")
        elif "fullDocumentExpansion" in action:
            document = action["fullDocumentExpansion"].get("documentId", "")
            print(f"  full document: {document}")
    for warning in attributes.get("warnings", []):
        if "guardrail" in warning:
            print(f"  guardrail: {warning['guardrail'].get('action')}")

O loop agêntico funciona assim: o serviço planeja uma estratégia, cria sub-consultas, recupera evidências e verifica se são suficientes. Se necessário, executa outra rodada antes de gerar a resposta citada.

Imagem original — fonte: Aws

Renderizando citações

Cada citação identifica um intervalo de caracteres na resposta e referencia entradas no array de resultados. O código abaixo imprime cada trecho citado ao lado do URI da fonte correspondente:

generated = final_result["generatedResponse"]
results = final_result["results"]

for citation in generated.get("citations", []):
    span = generated["answer"][citation["startIndex"]:citation["endIndex"]]
    for reference in citation["references"]:
        source = results[reference["resultIndex"]]
        source_uri = source.get("metadata", {}).get("x-amz-bedrock-kb-source-uri")
        print(f'"{span}"\n -> {source_uri}')

Perguntas de acompanhamento em conversa multi-turno

Perguntas de acompanhamento dependem de turnos anteriores. Após uma resposta de status, um segurado pode perguntar “Quem é o ajustador responsável?” — e a palavra “responsável” precisa ser resolvida a partir do histórico da conversa. Basta manter o histórico na aplicação e enviá-lo completo a cada chamada:

messages = [
    {"role": "user", "content": {"text": "What is the status of claim CLM-100482?"}},
    {"role": "assistant", "content": {"text": answer}},
    {"role": "user", "content": {"text": "Who is the adjuster assigned to it?"}},
]

response = bedrock_agent_runtime.agentic_retrieve_stream(
    messages=messages,
    retrievers=[
        {"configuration": {"knowledgeBase": {"knowledgeBaseId": kb_id}}}
    ],
    agenticRetrieveConfiguration={"foundationModelType": "MANAGED"},
    generateResponse=True,
)

O serviço usa os turnos anteriores para resolver “it” ao sinistro CLM-100482 e recupera o ajustador desse sinistro.

Escopo de recuperação com filtros de metadados

Filtros de metadados restringem os documentos antes da busca semântica. Para uma consulta direta por ID de sinistro, usa-se um filtro de igualdade:

retrievers = [
    {
        "configuration": {
            "knowledgeBase": {
                "knowledgeBaseId": kb_id,
                "retrievalOverrides": {
                    "filter": {"equals": {"key": "claim_id", "value": "CLM-100482"}}
                },
            }
        }
    }
]

Para sinistros de automóvel abertos acima de $10.000 registrados em julho de 2026, combinam-se condições com andAll:

claims_filter = {
    "andAll": [
        {"equals": {"key": "claim_type", "value": "auto"}},
        {"equals": {"key": "status", "value": "open"}},
        {"greaterThan": {"key": "amount", "value": 10000}},
        {"greaterThanOrEquals": {"key": "date_filed", "value": 20260701}},
        {"lessThanOrEquals": {"key": "date_filed", "value": 20260731}},
    ]
}

response = bedrock_agent_runtime.agentic_retrieve_stream(
    messages=[
        {
            "role": "user",
            "content": {
                "text": "Summarize the outstanding items on the open auto "
                        "claims over $10,000 filed in July."
            },
        }
    ],
    retrievers=[
        {
            "configuration": {
                "knowledgeBase": {
                    "knowledgeBaseId": kb_id,
                    "retrievalOverrides": {
                        "filter": claims_filter,
                        "maxNumberOfResults": 50,
                    },
                }
            }
        }
    ],
    agenticRetrieveConfiguration={"foundationModelType": "MANAGED"},
    generateResponse=True,
)

Como essa consulta pode corresponder a muitos sinistros, maxNumberOfResults é definido como 50 — um limite menor poderia omitir sinistros relevantes do resumo. Os operadores suportados incluem equals, notEquals, comparações numéricas, in, notIn, stringContains, listContains e lógicos andAll/orAll. Consulte Metadados e filtragem para confirmar o suporte a operadores. Se um filtro não retornar documentos, o recomendado é retornar uma mensagem clara como “Nenhum sinistro corresponde a esses critérios”.

Resultados de avaliação

A avaliação foi realizada em um corpus sintético de 30 documentos usando as APIs Retrieve e RetrieveAndGenerate (não AgenticRetrieveStream). O conjunto de 40 perguntas inclui consultas diretas, comparações, aliases, registros substituídos, pagamentos revertidos e texto instrucional dentro de documentos. Os resultados gerais foram:

  • Perguntas respondidas: 40 de 40
  • Respostas com citações: 40 de 40
  • Média de citações por resposta: 3,9
  • Recall de recuperação de fonte esperada: 90,5%
  • Recall de citação de fonte esperada: 81,2%
  • Fragmentos contradizendo o filtro solicitado: 0

Nas 20 perguntas adversariais, o recall de recuperação foi de 96,7% e o recall de citação foi de 90,2%. Perguntas específicas de sinistro tiveram o melhor desempenho. Perguntas amplas de inventário sem filtros produziram os três resultados mais fracos. A cobertura de citações não garante completude da resposta — recomenda-se medir completude separadamente quando isso for relevante. Esses resultados usam documentos sintéticos e classificação automatizada; uma revisão humana no corpus real é necessária antes de expor o assistente a segurados.

Segurança e governança

Filtros de escopo por usuário autenticado

Os filtros de metadados devem ser tratados como limite de acesso. O recomendado é derivar region ou customer_id da sessão autenticada, combiná-los com filtros de consulta usando andAll, e nunca aceitar o limite a partir do texto do usuário. O campo userContext também suporta filtragem de controle de acesso.

Permissões do Gerenciamento de Identidade e Acesso (IAM)

As permissões devem ser concedidas apenas para recuperação agêntica, acesso à base de conhecimento, streaming de modelo e ações de guardrail:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "bedrock:AgenticRetrieveStream",
      "Resource": "*"
    },
    {
      "Effect": "Allow",
      "Action": [
        "bedrock:Retrieve",
        "bedrock:GetDocumentContent"
      ],
      "Resource": "arn:aws:bedrock:us-west-2:111122223333:knowledge-base/*"
    },
    {
      "Effect": "Allow",
      "Action": "bedrock:InvokeModelWithResponseStream",
      "Resource": "*"
    },
    {
      "Effect": "Allow",
      "Action": [
        "bedrock:GetGuardrail",
        "bedrock:ApplyGuardrail"
      ],
      "Resource": "*"
    }
  ]
}

O AWS CloudTrail registra chamadas ao Amazon Bedrock para auditoria. O Amazon S3 criptografa objetos em repouso por padrão — veja como configurar a criptografia padrão. É possível usar chaves AWS KMS gerenciadas pelo cliente tanto para o bucket quanto para o armazenamento vetorial gerenciado. O tráfego de API usa Segurança da Camada de Transporte (TLS).

Fundamentação contextual com Amazon Bedrock Guardrails

Adicionar uma verificação de fundamentação contextual do Amazon Bedrock Guardrails bloqueia respostas abaixo de limiares configurados de fundamentação (consistência com os documentos recuperados) e relevância (alinhamento com a pergunta do usuário). Para sinistros, limiares altos são recomendados — recusar uma resposta é mais seguro do que gerar conteúdo não suportado:

bedrock = boto3.client("bedrock", region_name="us-west-2")

guardrail = bedrock.create_guardrail(
    name="claims-assistant-guardrail",
    description="Contextual grounding for the claims assistant",
    contextualGroundingPolicyConfig={
        "filtersConfig": [
            {"type": "GROUNDING", "threshold": 0.85},
            {"type": "RELEVANCE", "threshold": 0.75},
        ]
    },
    blockedInputMessaging="I can't help with that request.",
    blockedOutputsMessaging="I can only answer questions using the claim records.",
)
guardrail_id = guardrail["guardrailId"]
guardrail_version = bedrock.create_guardrail_version(
    guardrailIdentifier=guardrail_id
)["version"]

O guardrail é passado na chamada principal via policyConfiguration. A recuperação agêntica suporta a ação BLOCK: uma verificação de fundamentação reprovada bloqueia a resposta, e os eventos de rastreamento registram a intervenção. É fundamental manter uma pessoa no ciclo para revisar as evidências citadas e tomar a decisão final sobre o sinistro.

Limpeza dos recursos

Para evitar cobranças futuras, os recursos devem ser removidos ao final:

# Excluir a base de conhecimento (também remove o armazenamento vetorial gerenciado)
bedrock_agent.delete_knowledge_base(knowledgeBaseId=kb_id)

# Excluir o guardrail
bedrock.delete_guardrail(guardrailIdentifier=guardrail_id)

Além disso, é necessário esvaziar e excluir o bucket S3 e remover a função e política IAM da base de conhecimento.

Conclusão

O guia da AWS demonstra como construir um assistente de sinistros com o Amazon Bedrock Knowledge Bases e documentos sintéticos no Amazon S3. A API AgenticRetrieveStream cuida de perguntas multi-parte, histórico de conversa, filtros de metadados, verificações de fundamentação, respostas em streaming e citações. O mesmo padrão se aplica a documentos de subscrição e atendimento de apólices. Para aprofundar, a AWS disponibiliza a documentação de uso de recuperação agêntica para consultar uma base de conhecimento.

Fonte

Query claims in natural language with Amazon Bedrock Knowledge Bases (https://aws.amazon.com/blogs/machine-learning/query-claims-in-natural-language-with-amazon-bedrock-knowledge-bases/)

Comments

Leave a Reply

Your email address will not be published. Required fields are marked *