7.9 KiB
Route Stickiness Semântica e Controle Global de Sessão no Agent Framework OCI
Objetivo
A route stickiness semântica evita executar novamente o Enterprise Router quando uma nova mensagem continua claramente sob responsabilidade do agente ativo. A implementação usa um perfil LLM leve e não contém regexes, listas de frases, palavras específicas de idioma ou regras conversacionais por domínio.
A funcionalidade é opcional e preserva integralmente o comportamento anterior quando desabilitada, quando não existe agente ativo, quando a confiança é baixa ou quando ocorre erro na inferência.
Decisão arquitetural
O classificador possui uma responsabilidade transversal e restrita:
CONTINUE: a mensagem continua com o agente ativo;ROUTE: a mensagem deve seguir para o Enterprise Router normal;HUMAN_HANDOFF: o usuário solicitou atendimento humano;END_SESSION: o usuário solicitou ou confirmou o encerramento do atendimento.
Ele não responde ao usuário, não escolhe outro agente, não executa ferramentas e não interpreta regras de negócio. As duas ações globais são encaminhadas para nós próprios do grafo, evitando que cada agente implemente prompts ou regras de sessão.
Fluxo:
Todos os turnos com a funcionalidade habilitada
-> classificador semântico leve
CONTINUE + agente ativo -> agente ativo
ROUTE/baixa confiança/erro -> Enterprise Router
HUMAN_HANDOFF -> nó global human_handoff
END_SESSION -> nó global end_session
No primeiro turno, CONTINUE é normalizado para ROUTE porque ainda não existe agente ativo. Handoff e encerramento podem ser reconhecidos mesmo no primeiro turno.
Por que não há regras determinísticas
A interpretação de linguagem natural por regex exige manutenção contínua para novas construções, idiomas e domínios. Além disso, transfere aos times dos agentes a responsabilidade de manter flags e padrões de continuidade.
Esta implementação mantém no código apenas decisões técnicas inevitáveis:
- funcionalidade habilitada ou desabilitada;
- validação de que
CONTINUEexige agente ativo; - threshold de confiança;
- fallback em timeout, erro ou JSON inválido.
Não existem DEFAULT_FOLLOWUP_PATTERNS, regras de repetição, listas de pronomes ou keywords de continuidade.
Configuração
.env
ENABLE_ROUTE_STICKINESS=true
ROUTE_STICKINESS_LLM_PROFILE=route_continuity
ROUTE_STICKINESS_CONFIDENCE_THRESHOLD=0.90
ROUTE_STICKINESS_HISTORY_TURNS=2
ROUTE_STICKINESS_MAX_TOKENS=80
HUMAN_HANDOFF_MESSAGE=Vou encaminhar seu atendimento para uma pessoa.
END_SESSION_MESSAGE=Atendimento encerrado. Obrigado pelo contato.
ENABLE_ROUTE_STICKINESS: ativa a capacidade.ROUTE_STICKINESS_LLM_PROFILE: perfil existente emllm_profiles.yaml.ROUTE_STICKINESS_CONFIDENCE_THRESHOLD: confiança mínima para bypass.ROUTE_STICKINESS_HISTORY_TURNS: quantidade de turnos recentes enviados ao classificador.ROUTE_STICKINESS_MAX_TOKENS: limite de saída do classificador.HUMAN_HANDOFF_MESSAGE: mensagem devolvida pelo nó global de transferência humana.END_SESSION_MESSAGE: mensagem devolvida pelo nó global de encerramento.
Perfil leve
profiles:
route_continuity:
provider: oci_openai
model: openai.gpt-4.1-mini
temperature: 0
max_tokens: 80
timeout_seconds: 5
O modelo acima é apenas um exemplo. Deve ser substituído pelo menor modelo aprovado e disponível no ambiente OCI. O framework reutiliza o mecanismo já existente de LLM_PROFILES_PATH; não há uma segunda configuração de provider/model específica para a funcionalidade.
Contexto enviado ao modelo
O classificador recebe somente:
- agente ativo;
- descrições das capacidades dos agentes derivadas das intents já existentes;
- intent e domínio anteriores;
- histórico recente limitado;
- mensagem atual.
Não são enviados RAG completo, resultados MCP integrais, prompt do agente ou regras de negócio.
Exemplos
Continuidade
Usuário: Qual é o meu plano?
Agente: Seu plano é Controle 50GB.
Usuário: O que está incluso?
Resultado esperado:
{
"method": "continuity",
"route": "product_agent",
"route_bypassed": true
}
Mudança de domínio
Usuário: Qual é o meu plano?
Agente: Seu plano é Controle 50GB.
Usuário: Agora quero contestar uma cobrança.
O classificador retorna ROUTE e o Enterprise Router seleciona o agente apropriado.
Baixa confiança ou falha
Qualquer resultado abaixo do threshold, timeout ou JSON inválido executa o Enterprise Router. A funcionalidade é fail-safe e nunca força continuidade em caso de dúvida.
Telemetria
Evento router.continuity:
{
"decision": "CONTINUE",
"confidence": 0.97,
"active_agent": "product_agent",
"route_bypassed": true,
"profile_name": "route_continuity"
}
Quando ocorre bypass, route_decision.method é continuity e o estado final contém:
active_agent;route_bypassed;continuity_signal.
Testes
pytest -q tests/unit/test_semantic_route_stickiness.py
Os testes validam:
- continuidade com bypass;
- mudança de assunto com fallback para o router;
- baixa confiança;
- saída inválida;
- primeiro turno sem chamada ao classificador.
Benchmark recomendado
Executar a mesma conversação com a funcionalidade desabilitada e habilitada, registrando por turno:
route_bypassed;route_decision.method;- latência do
llm.route_continuity; - chamadas ao
llm.router; - tokens por perfil;
- latência total p50, p95 e p99.
A redução de tempo total somente deve ser atribuída à stickiness quando houver route_bypassed=true e ausência da geração llm.router no mesmo turno.
Contratos globais
Human handoff
Quando a decisão for HUMAN_HANDOFF, o router retorna:
{
"route": "human_handoff",
"intent": "human_handoff",
"method": "continuity",
"handoff": true,
"metadata": {
"session_control": "HUMAN_HANDOFF",
"route_bypassed": true
}
}
O nó human_handoff produz os campos:
session_control=HUMAN_HANDOFF;human_handoff_requested=true;session_ended=false;next_state=HUMAN_HANDOFF_REQUESTED.
O evento session.human_handoff.requested é emitido para que o Channel Gateway ou a integração do cliente encaminhe a conversa à plataforma humana. O framework não presume uma fila, fornecedor ou protocolo específico.
Encerramento
Quando a decisão for END_SESSION, o router retorna:
{
"route": "end_session",
"intent": "end_session",
"method": "continuity",
"metadata": {
"session_control": "END_SESSION",
"route_bypassed": true
}
}
O nó end_session produz:
session_control=END_SESSION;session_ended=true;human_handoff_requested=false;next_state=SESSION_ENDED.
O evento session.end.requested é emitido antes da persistência. O backend continua responsável por aplicar a política concreta de expiração, fechamento ou limpeza da sessão em cada canal.
Exemplos
| Mensagem | Contexto | Decisão esperada | Destino |
|---|---|---|---|
o que está incluso? |
product_agent ativo |
CONTINUE |
product_agent |
agora quero contestar uma cobrança |
product_agent ativo |
ROUTE |
Enterprise Router |
quero falar com uma pessoa |
com ou sem agente ativo | HUMAN_HANDOFF |
nó human_handoff |
obrigado, pode encerrar |
com ou sem agente ativo | END_SESSION |
nó end_session |
Segurança e fallback
- Somente decisões acima do threshold são aceitas.
CONTINUEsem agente ativo viraROUTE.- JSON inválido, timeout ou erro usa o Enterprise Router.
- Handoff e encerramento não executam agentes de domínio nem ferramentas MCP.
- O classificador não encerra fisicamente conexões nem seleciona filas humanas; ele emite um contrato global para integração.