iachat/progresso/2026-02-24_faq_guardrail_e_orquestracao.md

3.8 KiB

Ajuste de Orquestração + Guardrail de FAQ (Captain/Jasmine)

Data: 24/02/2026
Autor: Codex (AI Developer)

Objetivo

Garantir que o agente não responda “não sei / não tenho acesso” sem antes consultar FAQ, e evitar que a conversa fique presa em um cenário que ignora FAQ.

Problema Observado

  • Em algumas conversas, o agente respondia corretamente usando FAQ (ex.: preços), mas em outras respostas dizia que “não tinha acesso” (ex.: senha do Wi-Fi).
  • Isso gerava comportamento inconsistente e perda de confiança.

Causa-Raiz

  1. Sticky de cenário no histórico
    O runner podia iniciar o turno no último agent_name do histórico (ex.: cenário de disponibilidade), em vez de iniciar no orquestrador principal.

  2. Guardrail com detecção ampla demais de faq_lookup
    A checagem considerava faq_lookup em result.messages inteiro.
    Se houve faq_lookup em turno anterior, isso podia bloquear o fallback no turno atual.

O que foi implementado

1) Início de turno sempre pelo orquestrador

  • O contexto da execução foi padronizado para iniciar no agente principal (current_agent do assistente).
  • O conversation_history enviado ao runner zera agent_name das mensagens para evitar lock indevido em cenário.

2) Guardrail de FAQ para respostas de incerteza

  • Foi criado um guardrail em AgentRunnerService:
    • Detecta respostas de incerteza (não sei, não tenho, etc.).
    • Se não houve faq_lookup no turno atual, dispara fallback de FAQ via busca semântica (@assistant.responses.approved.search(query)).
    • Se encontrar resposta no FAQ, substitui a resposta final.
    • Se não encontrar, responde explicitamente:
      • “Consultei o FAQ e não encontrei essa informação cadastrada ainda...”
      • Evita resposta genérica “não sei” sem contexto.

3) Correção de escopo do faq_lookup

  • A verificação agora considera apenas mensagens após a última pergunta do usuário do turno atual.
  • Isso evita falso positivo de faq_lookup antigo.

Arquivos Alterados

  • /Users/user/Dev/Produtos/Chatwoot-fazer-ai/fazer-ai-kanban/chatwoot/enterprise/app/services/captain/assistant/agent_runner_service.rb
  • /Users/user/Dev/Produtos/Chatwoot-fazer-ai/fazer-ai-kanban/chatwoot/spec/enterprise/services/captain/assistant/agent_runner_service_spec.rb

Testes e Validação

  • Executado:
    • bundle exec rspec spec/enterprise/services/captain/assistant/agent_runner_service_spec.rb
  • Resultado:
    • 29 examples, 0 failures

Casos cobertos em teste:

  • fallback aplicado quando resposta incerta vem sem faq_lookup;
  • não aplica fallback quando faq_lookup ocorreu no turno atual;
  • aplica fallback quando faq_lookup ocorreu apenas em turno anterior;
  • retorna mensagem explícita de “FAQ não encontrado” quando busca não acha nada.

Observabilidade (logs)

Foram mantidos logs para rastrear guardrail:

  • Trigger do guardrail com query;
  • Quantidade de resultados encontrados na busca FAQ;
  • Falha de fallback (se houver exception).

Impacto Prático

  • O agente deixa de “desistir” sem consultar conhecimento.
  • Reduz respostas incoerentes entre perguntas parecidas.
  • Mantém handoff para humano apenas quando realmente necessário.

Limitações Atuais

  • Se o FAQ estiver mal cadastrado ou com baixa qualidade semântica, o fallback ainda pode não encontrar resposta.
  • O guardrail atua em respostas de incerteza; não corrige respostas erradas factualmente quando o modelo responde com confiança indevida.

Próximos Passos Recomendados

  1. Revisar/normalizar entradas de FAQ críticas (Wi-Fi, horários, políticas, preços).
  2. Adicionar métrica de “fallback guardrail acionado” por inbox/assistente.
  3. Opcional: forçar política “FAQ-first” para intents informativas antes de responder livremente.