Agent de Sinistro Automotivo
Esta jornada usa um case realista de atendimento para abertura de sinistro automotivo em formato menos guiado. A proposta é que você implemente partes importantes por conta própria e valide o resultado no Agent Builder.
Ao longo do conteúdo, cada desafio traz:
- objetivo técnico
- critérios de aceitação
- dicas de implementação
- solução expandível
Você vai construir um fluxo completo com Agent + Skills + Actions
Resultado esperado ao final
Ao concluir todos os desafios, você terá:
- 1 Agent Conversacional configurado no Builder
- Skills em YAML para triagem, coleta, fechamento e exceções
- Actions em Python com
ResponseToUsereResponseToAgent - Uso de
state_managerememory_managerpara controle de fluxo e contexto - Fluxo validado ponta a ponta em cenários de sucesso e exceção
Criar o Agent
Desafio 1: Definir instruções gerais de forma objetiva
Objetivo: escrever as instruções do agent para triar e conduzir abertura de sinistro auto com tom empático e limites claros.
Critérios de aceitação:
- delimita escopo (somente sinistro automotivo)
- define comportamento para fora de escopo
- orienta linguagem clara e acolhedora
- evita instruções longas e ambíguas
Dica: instruções curtas e diretas tendem a funcionar melhor do que textos muito extensos.
Ver solução sugerida
Você é uma assistente virtual especializada em abertura de sinistro automotivo.
Objetivo:
- Coletar os dados necessários da ocorrência com clareza e empatia.
- Conduzir o cliente até a confirmação final da abertura.
Regras:
- Atue apenas em assuntos relacionados a sinistro automotivo.
- Se o tema for fora de escopo, ofereça transferência para atendimento humano.
- Não invente informações e não deduza dados críticos sem confirmação.
- Faça uma pergunta por vez quando faltar informação obrigatória.
- Sempre mantenha linguagem simples, objetiva e acolhedora.
Criar Skills
Desafio 2: Modelar a skill de triagem e roteamento inicial
Objetivo: criar uma skill que classifique o tipo de atendimento inicial e direcione o próximo passo.
Critérios de aceitação:
- skill identifica se é segurado, terceiro ou frota
- usa ação customizada para validar perfil
- prevê saída para atendimento humano quando necessário
- cita system actions por colchetes quando aplicável
Ver solução sugerida
instructions: |
Realize a triagem inicial para abertura de sinistro automotivo.
Confirme o perfil de atendimento antes de avançar para coleta detalhada.
topics:
- Triagem Inicial:
description: Identifica o perfil e direciona o fluxo correto.
steps:
- Coletar Perfil: Pergunte se o atendimento é para segurado, terceiro ou frota.
- Validar Perfil: Use [validar_perfil_atendimento] para validar e classificar o perfil.
- Próximo Passo:
- Se perfil for segurado, redirecione para a skill "Coleta da Ocorrência" com [redirecionar_habilidade].
- Se perfil exigir atendimento especializado, ofereça [transferir_agente_humano].
Desafio 3: Modelar a skill de coleta progressiva da ocorrência
Objetivo: criar um fluxo menos engessado, mas com campos obrigatórios e progresso verificável.
Campos obrigatórios sugeridos:
- data da ocorrência
- hora aproximada
- local da ocorrência
- breve descrição do ocorrido
- veículo envolvido (placa ou modelo)
- existência de terceiros (sim/não)
Critérios de aceitação:
- skill chama action para registrar cada dado
- skill chama action para revisar pendências
- skill evita perguntar
houve_terceirosquando a descrição já indicar envolvimento de outro veículo/pessoa - avança para resumo quando não houver pendências
Ver solução sugerida
instructions: |
Conduza a coleta da ocorrência em pequenos passos.
Registre cada informação recebida e revise pendências com frequência.
topics:
- Coleta da Ocorrência:
description: Coleta e valida dados essenciais para abertura do sinistro.
steps:
- Coletar Dado: Solicite apenas um campo por vez.
- Registrar Dado: Sempre que o usuário informar um campo, use [registrar_dado_ocorrencia].
- Revisar Pendências: Use [revisar_pendencias_ocorrencia] para descobrir próximos campos obrigatórios.
- Regra de Terceiros: Se a revisão inferir `houve_terceiros=sim` pela descrição do acidente, não pergunte novamente sobre terceiros e siga para o próximo campo faltante.
- Transição para Resumo: Quando não houver pendências, redirecione para "Resumo e Conclusão" com [redirecionar_habilidade].
Desafio 4: Criar a skill de resumo e conclusão
Objetivo: consolidar dados, confirmar com o usuário e encerrar com ação de sistema.
Critérios de aceitação:
- skill chama action de resumo
- skill pede confirmação explícita
- em confirmação positiva, usa
[finalizar_conversa] - em negativa, retorna para coleta
Ver solução sugerida
instructions: |
Apresente resumo final de forma clara, confirme com o usuário e conclua o atendimento.
topics:
- Resumo e Conclusão:
description: Consolida os dados da ocorrência e finaliza o atendimento.
steps:
- Gerar Resumo: Use [gerar_resumo_ocorrencia].
- Confirmar Dados: Pergunte se os dados estão corretos para concluir a abertura.
- Se Confirmado: Use [finalizar_conversa] para encerrar cordialmente.
- Se Não Confirmado: Redirecione para "Coleta da Ocorrência" com [redirecionar_habilidade].
Criar Actions
Desafio 5: Implementar validação de perfil de atendimento
Nome da action: validar_perfil_atendimento
Parâmetros sugeridos:
| Nome | Tipo | Obrigatório | Descrição |
|---|---|---|---|
perfil | Texto | Sim | Perfil informado pelo usuário na triagem |
Critérios de aceitação:
- normaliza entradas equivalentes (ex: "cliente", "segurado")
- define próximo passo no
instruction - salva perfil no
state_manager
Ver solução sugerida
def validar_perfil_atendimento(perfil: str):
perfil_normalizado = (perfil or "").strip().lower()
mapa = {
"segurado": "segurado",
"cliente": "segurado",
"terceiro": "terceiro",
"frota": "frota",
}
perfil_classificado = mapa.get(perfil_normalizado)
if not perfil_classificado:
return ResponseToAgent(
instruction=(
"Perfil não reconhecido. Solicite que o usuário informe "
"uma das opções: segurado, terceiro ou frota."
)
)
state_manager.update("sinistro.perfil", perfil_classificado)
if perfil_classificado == "segurado":
return ResponseToAgent(
instruction=(
"Perfil segurado validado. Redirecione para a skill "
"'Coleta da Ocorrência' e inicie a coleta dos campos obrigatórios."
)
)
if perfil_classificado == "terceiro":
return ResponseToUser(
instruction=(
"Perfil terceiro identificado. Informado canal genérico "
"de abertura para terceiros."
),
message=(
"Para abertura de sinistro por terceiro, utilize o canal digital "
"de terceiros da sua operação. Se preferir, posso transferir você "
"para um especialista."
)
)
return ResponseToUser(
instruction="Perfil frota identificado e orientação de canal genérico enviada.",
message=(
"Para abertura por frota, utilize o canal digital de frota "
"da sua operação. Se preferir, posso transferir para um especialista."
)
)
Desafio 6: Implementar registro de dados da ocorrência
Nome da action: registrar_dado_ocorrencia
Parâmetros sugeridos:
| Nome | Tipo | Obrigatório | Descrição |
|---|---|---|---|
campo | Texto | Sim | Nome do campo coletado (data_ocorrencia ou hora_ocorrencia, local_ocorrencia ou descricao_ocorrencia ou veiculo_envolvido ou houve_terceiros) |
valor | Texto | Sim | Valor informado pelo usuário |
Critérios de aceitação:
- valida presença de campo e valor
- normaliza nome de campo
- persiste em
memory_manager - registra progresso em
state_manager
Ver solução sugerida
from datetime import datetime
def registrar_dado_ocorrencia(campo: str, valor: str):
campo_input = (campo or "").strip().lower()
valor_input = (valor or "").strip()
if not campo_input or not valor_input:
return ResponseToAgent(
instruction=(
"Campo ou valor ausente. Solicite novamente um campo válido "
"e o respectivo valor."
)
)
aliases = {
"data": "data_ocorrencia",
"data_ocorrido": "data_ocorrencia",
"hora": "hora_ocorrencia",
"local": "local_ocorrencia",
"descricao": "descricao_ocorrencia",
"veiculo": "veiculo_envolvido",
"terceiros": "houve_terceiros",
}
campo_normalizado = aliases.get(campo_input, campo_input)
memory_manager.update(f"sinistro.dados.{campo_normalizado}", valor_input)
state_manager.update("sinistro.ultima_atualizacao", datetime.utcnow().isoformat())
return ResponseToAgent(
instruction=(
f"Campo '{campo_normalizado}' registrado com sucesso no contexto do sinistro. "
"Use revisar_pendencias_ocorrencia para decidir o próximo passo."
)
)
Desafio 7: Implementar revisão de pendências e resumo final
Nome das actions:
revisar_pendencias_ocorrenciagerar_resumo_ocorrencia
Critérios de aceitação:
- lista campos faltantes de forma determinística
- atualiza etapa do workflow
- resumo final legível para confirmação do usuário
Ver solução sugerida
CAMPOS_OBRIGATORIOS = [
"data_ocorrencia",
"hora_ocorrencia",
"local_ocorrencia",
"descricao_ocorrencia",
"veiculo_envolvido",
"houve_terceiros",
]
def inferir_terceiros_por_descricao(descricao: str) -> bool:
descricao_normalizada = (descricao or "").strip().lower()
if not descricao_normalizada:
return False
gatilhos_terceiros = [
"outro veiculo",
"outro veículo",
"veiculo terceiro",
"veículo terceiro",
"terceiro",
"terceiros",
"foi atingido",
"atingido na traseira",
"colidiu com",
"colisao com",
"colisão com",
"bateu em",
]
return any(gatilho in descricao_normalizada for gatilho in gatilhos_terceiros)
def revisar_pendencias_ocorrencia():
dados = memory_manager.get("sinistro.dados", default={}) or {}
if not dados.get("houve_terceiros") and inferir_terceiros_por_descricao(
str(dados.get("descricao_ocorrencia", ""))
):
memory_manager.update("sinistro.dados.houve_terceiros", "sim")
state_manager.update("sinistro.houve_terceiros_inferido", True)
dados["houve_terceiros"] = "sim"
faltantes = [campo for campo in CAMPOS_OBRIGATORIOS if not dados.get(campo)]
state_manager.update("sinistro.campos_faltantes", faltantes)
if faltantes:
memory_manager.store_workflow_progress(
"abertura_sinistro_auto",
"coleta_em_andamento",
{"faltantes": faltantes}
)
return ResponseToAgent(
instruction=(
"Ainda existem campos pendentes para conclusão da abertura: "
+ ", ".join(faltantes)
+ ". Solicite o próximo campo faltante ao usuário."
)
)
memory_manager.store_workflow_progress(
"abertura_sinistro_auto",
"coleta_concluida",
{"faltantes": []}
)
return ResponseToAgent(
instruction=(
"Todos os campos obrigatórios foram coletados. "
"Agora gere o resumo com a action gerar_resumo_ocorrencia."
)
)
def gerar_resumo_ocorrencia():
dados = memory_manager.get("sinistro.dados", default={}) or {}
if not dados:
return ResponseToAgent(
instruction=(
"Não há dados suficientes para resumo. "
"Retome a coleta de dados da ocorrência."
)
)
resumo = (
"Resumo da ocorrência:\n"
f"- Data: {dados.get('data_ocorrencia', 'não informado')}\n"
f"- Hora: {dados.get('hora_ocorrencia', 'não informado')}\n"
f"- Local: {dados.get('local_ocorrencia', 'não informado')}\n"
f"- Veículo: {dados.get('veiculo_envolvido', 'não informado')}\n"
f"- Houve terceiros: {dados.get('houve_terceiros', 'não informado')}\n"
f"- Descrição: {dados.get('descricao_ocorrencia', 'não informado')}"
)
memory_manager.update("sinistro.resumo_final", resumo)
return ResponseToUser(
instruction=(
"Resumo final gerado e apresentado ao usuário. "
"Solicitar confirmação para concluir abertura."
),
message=(
f"{resumo}\n\n"
"Os dados estão corretos para concluir a abertura do sinistro?"
)
)
Kit final de implementação
Use este kit quando quiser partir de uma base funcional completa.
1) Instruções gerais do Agent
Você é uma assistente virtual especializada em abertura de sinistro automotivo.
Atenda com empatia, objetividade e foco na coleta correta de dados.
Escopo:
- Abrir sinistro automotivo para segurado.
- Coletar, validar e resumir dados da ocorrência.
Regras:
- Não invente informações.
- Solicite um dado por vez quando houver pendências.
- Em assuntos fora de escopo, ofereça transferência para atendimento humano.
- Após resumo e confirmação positiva, conclua o atendimento com [finalizar_conversa].
2) Skills (YAML)
instructions: |
Gerencie abertura de sinistro automotivo em três etapas: triagem, coleta e conclusão.
topics:
- Triagem Inicial:
description: Identifica perfil de atendimento e direciona o fluxo.
steps:
- Coletar Perfil: Pergunte se o atendimento é para segurado, terceiro ou frota.
- Validar Perfil: Use [validar_perfil_atendimento].
- Direcionar:
- Se segurado: redirecione para "Coleta da Ocorrência" com [redirecionar_habilidade].
- Se necessário: ofereça [transferir_agente_humano].
- Coleta da Ocorrência:
description: Coleta e valida dados obrigatórios da ocorrência.
steps:
- Coletar Campo: Solicite um campo por vez.
- Registrar Campo: Use [registrar_dado_ocorrencia] para salvar cada informação.
- Revisar Pendências: Use [revisar_pendencias_ocorrencia] para decidir o próximo campo.
- Regra de Terceiros: Se a action inferir terceiros pela descrição, não repita a pergunta e continue para o próximo campo faltante.
- Concluir Coleta: Quando não houver pendências, redirecione para "Resumo e Conclusão" com [redirecionar_habilidade].
- Resumo e Conclusão:
description: Consolida o resumo, confirma com o usuário e finaliza.
steps:
- Gerar Resumo: Use [gerar_resumo_ocorrencia].
- Confirmar: Pergunte se os dados estão corretos para concluir a abertura.
- Encerrar:
- Se confirmado: use [finalizar_conversa].
- Se não confirmado: redirecione para "Coleta da Ocorrência" com [redirecionar_habilidade].
3) Actions (Python)
from datetime import datetime
CAMPOS_OBRIGATORIOS = [
"data_ocorrencia",
"hora_ocorrencia",
"local_ocorrencia",
"descricao_ocorrencia",
"veiculo_envolvido",
"houve_terceiros",
]
def inferir_terceiros_por_descricao(descricao: str) -> bool:
descricao_normalizada = (descricao or "").strip().lower()
if not descricao_normalizada:
return False
gatilhos_terceiros = [
"outro veiculo",
"outro veículo",
"veiculo terceiro",
"veículo terceiro",
"terceiro",
"terceiros",
"foi atingido",
"atingido na traseira",
"colidiu com",
"colisao com",
"colisão com",
"bateu em",
]
return any(gatilho in descricao_normalizada for gatilho in gatilhos_terceiros)
def validar_perfil_atendimento(perfil: str):
perfil_normalizado = (perfil or "").strip().lower()
mapa = {
"segurado": "segurado",
"cliente": "segurado",
"terceiro": "terceiro",
"frota": "frota",
}
perfil_classificado = mapa.get(perfil_normalizado)
if not perfil_classificado:
return ResponseToAgent(
instruction="Perfil não reconhecido. Solicite: segurado, terceiro ou frota."
)
state_manager.update("sinistro.perfil", perfil_classificado)
if perfil_classificado == "segurado":
return ResponseToAgent(
instruction=(
"Perfil segurado validado. Redirecione para a skill "
"'Coleta da Ocorrência'."
)
)
if perfil_classificado == "terceiro":
return ResponseToUser(
instruction="Perfil terceiro identificado e orientação de canal genérico enviada.",
message=(
"Para abertura por terceiro, utilize o canal digital de terceiros "
"da sua operação. Se preferir, posso transferir para um especialista."
)
)
return ResponseToUser(
instruction="Perfil frota identificado e orientação de canal genérico enviada.",
message=(
"Para abertura por frota, utilize o canal digital de frota "
"da sua operação. Se preferir, posso transferir para um especialista."
)
)
def registrar_dado_ocorrencia(campo: str, valor: str):
campo_input = (campo or "").strip().lower()
valor_input = (valor or "").strip()
if not campo_input or not valor_input:
return ResponseToAgent(
instruction="Campo ou valor ausente. Solicite novamente o dado."
)
aliases = {
"data": "data_ocorrencia",
"hora": "hora_ocorrencia",
"local": "local_ocorrencia",
"descricao": "descricao_ocorrencia",
"veiculo": "veiculo_envolvido",
"terceiros": "houve_terceiros",
}
campo_normalizado = aliases.get(campo_input, campo_input)
memory_manager.update(f"sinistro.dados.{campo_normalizado}", valor_input)
state_manager.update("sinistro.ultima_atualizacao", datetime.utcnow().isoformat())
return ResponseToAgent(
instruction=(
f"Campo '{campo_normalizado}' registrado com sucesso. "
"Use revisar_pendencias_ocorrencia para decidir o próximo passo."
)
)
def revisar_pendencias_ocorrencia():
dados = memory_manager.get("sinistro.dados", default={}) or {}
if not dados.get("houve_terceiros") and inferir_terceiros_por_descricao(
str(dados.get("descricao_ocorrencia", ""))
):
memory_manager.update("sinistro.dados.houve_terceiros", "sim")
state_manager.update("sinistro.houve_terceiros_inferido", True)
dados["houve_terceiros"] = "sim"
faltantes = [campo for campo in CAMPOS_OBRIGATORIOS if not dados.get(campo)]
state_manager.update("sinistro.campos_faltantes", faltantes)
if faltantes:
memory_manager.store_workflow_progress(
"abertura_sinistro_auto",
"coleta_em_andamento",
{"faltantes": faltantes}
)
return ResponseToAgent(
instruction=(
"Há pendências na coleta: "
+ ", ".join(faltantes)
+ ". Solicite o próximo campo faltante."
)
)
memory_manager.store_workflow_progress(
"abertura_sinistro_auto",
"coleta_concluida",
{"faltantes": []}
)
return ResponseToAgent(
instruction=(
"Todos os campos obrigatórios foram coletados. "
"Agora execute gerar_resumo_ocorrencia."
)
)
def gerar_resumo_ocorrencia():
dados = memory_manager.get("sinistro.dados", default={}) or {}
if not dados:
return ResponseToAgent(
instruction="Sem dados suficientes para resumo. Retome a coleta."
)
resumo = (
"Resumo da ocorrência:\n"
f"- Data: {dados.get('data_ocorrencia', 'não informado')}\n"
f"- Hora: {dados.get('hora_ocorrencia', 'não informado')}\n"
f"- Local: {dados.get('local_ocorrencia', 'não informado')}\n"
f"- Veículo: {dados.get('veiculo_envolvido', 'não informado')}\n"
f"- Houve terceiros: {dados.get('houve_terceiros', 'não informado')}\n"
f"- Descrição: {dados.get('descricao_ocorrencia', 'não informado')}"
)
memory_manager.update("sinistro.resumo_final", resumo)
return ResponseToUser(
instruction="Resumo final exibido ao usuário para confirmação.",
message=(
f"{resumo}\n\n"
"Os dados estão corretos para concluir a abertura do sinistro?"
)
)
4) Mapa de vínculos skill-action
- Skill
Triagem Inicial:validar_perfil_atendimentoredirecionar_habilidadetransferir_agente_humano
- Skill
Coleta da Ocorrência:registrar_dado_ocorrenciarevisar_pendencias_ocorrenciaredirecionar_habilidade
- Skill
Resumo e Conclusão:gerar_resumo_ocorrenciafinalizar_conversaredirecionar_habilidade
Casos de teste para validação
Use os casos abaixo para validar o comportamento do agent no Builder ao final da implementação.
Case 1: Segurado (fluxo completo com conclusão)
Objetivo: validar triagem de segurado, coleta progressiva, inferência de terceiros pela descrição, resumo e conclusão.

Resultado esperado:
- o agent inicia coleta de dados obrigatórios em pequenos passos
houve_terceirosé assumido comosima partir da descrição (sem nova pergunta específica sobre terceiros)- o resumo final apresenta os campos coletados e pede confirmação
- após confirmação, o agent conclui a abertura do sinistro com sucesso
Case 2: Frota (roteamento para canal especializado)
Objetivo: validar triagem com perfil frota e encaminhamento correto sem iniciar coleta detalhada.

Resultado esperado:
- o agent identifica perfil de frota na triagem
- responde com orientação de uso do canal digital de frota
- oferece possibilidade de transferência para especialista
- encerra de forma cordial, sem coletar campos da ocorrência
Case 3: Terceiro (roteamento para canal especializado)
Objetivo: validar triagem com perfil terceiro e encaminhamento correto sem iniciar coleta detalhada.

Resultado esperado:
- o agent identifica perfil de terceiro na triagem
- responde com orientação de uso do canal digital de terceiros
- oferece possibilidade de transferência para especialista
- encerra de forma cordial, sem coletar campos da ocorrência