75 lines
3.8 KiB
Markdown
75 lines
3.8 KiB
Markdown
# 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.
|