Skip to main content

Skill Selector

O módulo SkillSelector fornece funcionalidade inteligente para seleção automática de skills externas usando análise de LLM. Permite que tools automaticamente escolham a melhor skill externa baseada no contexto da conversa.

🚀 Características Principais

  • Seleção inteligente - Usa LLM para analisar contexto e escolher a melhor skill
  • Verificação de disponibilidade - Checa horários de funcionamento e exceções
  • Integração automática - Acessa skills da sessão automaticamente
  • Fallback configurável - Permite definir skill de fallback para casos não cobertos

🔧 Disponibilidade Automática

O objeto skill_selector já está automaticamente disponível em seus tools, não sendo necessário instanciá-lo manualmente. Ele vem pré-configurado com todos os atributos necessários (agent, conversation_id, trace, messages) e pronto para uso.

# ✅ Correto - skill_selector já está disponível
available_skills = skill_selector.get_available_external_skills()

# ❌ Não necessário - não precisa instanciar
# skill_selector = actions_sdk.SkillSelector(...)

📋 Métodos Principais

skill_selector.get_available_external_skills()

Converte skills externas do estado da sessão para objetos ExternalSkill.

Retorno:

  • List[ExternalSkill]: Lista de skills disponíveis da sessão

Quando utilizar:

  • Verificar quais skills estão disponíveis na sessão atual
  • Obter lista formatada para uso com outros métodos

Exemplo:

# Obter skills disponíveis
available_skills = skill_selector.get_available_external_skills()

if available_skills:
print(f"Skills disponíveis: {[skill.name for skill in available_skills]}")
else:
print("Nenhuma skill externa configurada")

skill_selector.get_current_external_skill()

Retorna a skill externa atualmente ativa na sessão.

Retorno:

  • Optional[ExternalSkill]: Skill externa atual ou None se não houver skill ativa

Quando utilizar:

  • Verificar se há uma skill externa já ativa antes de fazer transferência
  • Implementar comportamentos diferentes baseados na skill atual
  • Evitar transferências redundantes
  • Criar contexto adicional nas respostas

Exemplo básico:

# Verificar skill atual
current_skill = skill_selector.get_current_external_skill()

if current_skill:
print(f"Usuário está na skill: {current_skill.name} (ID: {current_skill.id})")
else:
print("Nenhuma skill externa ativa")

Exemplo avançado - Evitar transferência redundante:

def transferir_para_vendas():
"""
Transfere para vendas apenas se ainda não estiver lá
"""
# Verificar skill atual
current_skill = skill_selector.get_current_external_skill()

# Se já está em vendas, não transferir novamente
if current_skill and "vendas" in current_skill.name.lower():
return actions_sdk.ResponseToUser(
message="Você já está sendo atendido pela equipe de vendas. Como posso ajudar?",
instruction="Usuário já está na skill de vendas"
)

# Buscar skill de vendas
available_skills = skill_selector.get_available_external_skills()
vendas_skill = next(
(skill for skill in available_skills if "vendas" in skill.name.lower()),
None
)

if vendas_skill:
return actions_sdk.ResponseToUser(
message="Vou transferir você para nossa equipe de vendas.",
functions=[
actions_sdk.TransferToHuman(
reason="Cliente solicitou atendimento de vendas",
external_skill_name=vendas_skill.name,
external_skill_id=str(vendas_skill.id)
)
]
)
else:
return actions_sdk.ResponseToUser(
message="Desculpe, o setor de vendas não está disponível no momento.",
instruction="Skill de vendas não encontrada"
)

skill_selector.is_external_skill_available(external_skill)

Verifica se uma skill externa está disponível baseado em horários de funcionamento e exceções.

Parâmetros:

  • external_skill (ExternalSkill): Skill a ser verificada

Retorno:

  • bool: True se disponível, False caso contrário

Lógica de disponibilidade:

  • Se opening_hours e opening_hours_exceptions são None: sempre disponível
  • Se opening_hours é dict vazio {}: nunca disponível
  • Se horário atual está em período de exceção: não disponível
  • Se horário atual está dentro do horário de funcionamento: disponível
  • Caso contrário: não disponível

Exemplo:

skill = actions_sdk.ExternalSkill(
id=uuid4(),
name="Suporte Técnico",
description="Suporte durante horário comercial",
opening_hours={
"1": ["09:00:00.000Z", "18:00:00.000Z"], # Segunda-feira
"2": ["09:00:00.000Z", "18:00:00.000Z"], # Terça-feira
},
opening_hours_exceptions=[
["2025-12-24T00:00:00.000Z", "2025-12-26T23:59:59.999Z"] # Natal
]
)

is_available = skill_selector.is_external_skill_available(skill)
if is_available:
print("Skill disponível no momento")
else:
print("Skill fora do horário de funcionamento")

skill_selector.select_best_skill()

Seleciona a melhor skill externa usando análise de LLM.

Parâmetros:

  • external_skills (List[ExternalSkill], opcional): Skills disponíveis. Se não fornecido, usa da sessão
  • messages (List[ConversationMessage], opcional): Mensagens para contexto
  • fallback_skill (ExternalSkill, opcional): Skill de fallback como último recurso
  • context_hint (str, opcional): Contexto adicional para ajudar na seleção

Retorno:

  • Optional[ExternalSkill]: Skill selecionada ou None se seleção falhar

Quando utilizar:

  • Transferir usuário para skill mais adequada baseada no contexto
  • Automatizar roteamento baseado na conversa
  • Implementar lógica de escalação inteligente

Exemplos:

# Uso automático com skills da sessão
selected = skill_selector.select_best_skill(
context_hint="Cliente relatou problema com login"
)

if selected:
return actions_sdk.ResponseToUser(
message=f"Vou transferir você para {selected.name}",
functions=[
actions_sdk.TransferToHuman(
reason="Problema técnico requer especialista",
external_skill_name=selected.name,
external_skill_id=str(selected.id)
)
]
)
# Uso manual com skills específicas
skills = [
actions_sdk.ExternalSkill(
id=uuid4(),
name="Suporte Técnico",
description="Problemas técnicos e bugs"
),
actions_sdk.ExternalSkill(
id=uuid4(),
name="Vendas",
description="Questões comerciais e orçamentos"
)
]

selected = skill_selector.select_best_skill(
external_skills=skills,
context_hint="Cliente interessado em plano premium"
)

🎯 Exemplo Completo

Transferência Inteligente para Suporte

def transferir_para_suporte_adequado():
"""
Analisa a conversa e transfere para a skill mais adequada
"""
try:
# Obter skills disponíveis (skill_selector já está disponível)
available_skills = skill_selector.get_available_external_skills()

if not available_skills:
return actions_sdk.ResponseToUser(
message="No momento não temos atendimento especializado disponível.",
instruction="Nenhuma skill externa configurada"
)

# Filtrar apenas skills disponíveis no horário atual
available_now = []
for skill in available_skills:
if skill_selector.is_external_skill_available(skill):
available_now.append(skill)

if not available_now:
return actions_sdk.ResponseToUser(
message="Nosso atendimento especializado está fora do horário de funcionamento. Tente novamente em horário comercial.",
instruction="Todas as skills externas estão fora do horário"
)

# Definir skill de fallback (atendimento geral)
fallback = next(
(skill for skill in available_now if "geral" in skill.name.lower()),
available_now[0] # Primeira disponível como fallback
)

# Selecionar melhor skill baseada no contexto
selected = skill_selector.select_best_skill(
external_skills=available_now,
fallback_skill=fallback,
context_hint="Analisar conversa para determinar tipo de atendimento necessário"
)

if selected:
return actions_sdk.ResponseToUser(
message=f"Vou transferir você para nossa equipe de {selected.name}. Eles poderão ajudar melhor com sua solicitação.",
instruction=f"Usuário transferido para skill {selected.name} baseado na análise da conversa",
functions=[
actions_sdk.TransferToHuman(
reason="Transferência automática baseada em análise de contexto",
external_skill_name=selected.name,
external_skill_id=str(selected.id)
)
]
)
else:
return actions_sdk.ResponseToUser(
message="Houve um problema ao determinar o melhor atendimento. Vou transferir você para nossa equipe geral.",
instruction="Falha na seleção automática, usando fallback",
functions=[
actions_sdk.TransferToHuman(
reason="Fallback após falha na seleção automática",
external_skill_name=fallback.name,
external_skill_id=str(fallback.id)
)
]
)

except Exception as e:
return actions_sdk.ResponseToUser(
message="Desculpe, tivemos um problema técnico. Tente novamente em alguns instantes.",
instruction=f"Erro no SkillSelector: {str(e)}",
status=actions_sdk.ResponseStatus.ERROR
)

Verificação de Skill Atual Antes de Transferência

def verificar_e_transferir():
"""
Verifica se já está em uma skill antes de fazer nova transferência.
Usa o novo método get_current_external_skill() (v1.25.0+)
"""
try:
# Primeiro: verificar se já está em alguma skill
current_skill = skill_selector.get_current_external_skill()

if current_skill:
# Já está em uma skill - informar contexto
return actions_sdk.ResponseToUser(
message=f"Você está sendo atendido por {current_skill.name}. "
f"Posso transferir para outro departamento se necessário. "
f"Para qual área você gostaria de ser direcionado?",
instruction=f"Cliente já está na skill {current_skill.name}"
)

# Não está em skill - prosseguir com seleção inteligente
available_skills = skill_selector.get_available_external_skills()

if not available_skills:
return actions_sdk.ResponseToUser(
message="No momento não temos departamentos especializados disponíveis.",
instruction="Nenhuma skill externa configurada"
)

# Filtrar por disponibilidade
available_now = [
skill for skill in available_skills
if skill_selector.is_external_skill_available(skill)
]

if not available_now:
return actions_sdk.ResponseToUser(
message="Nossos departamentos especializados estão fora do horário de atendimento.",
instruction="Todas skills fora do horário"
)

# Selecionar melhor skill
selected = skill_selector.select_best_skill(
external_skills=available_now,
context_hint="Primeira transferência - analisar necessidade do cliente"
)

if selected:
return actions_sdk.ResponseToUser(
message=f"Perfeito! Vou transferir você para {selected.name}.",
functions=[
actions_sdk.TransferToHuman(
reason="Transferência inicial baseada em análise de contexto",
external_skill_name=selected.name,
external_skill_id=str(selected.id)
)
]
)

except Exception as e:
return actions_sdk.ResponseToUser(
message="Desculpe, houve um erro ao processar sua solicitação.",
instruction=f"Erro no SkillSelector: {str(e)}",
status=actions_sdk.ResponseStatus.ERROR
)

Comportamento Condicional por Skill Atual

def processar_solicitacao():
"""
Implementa lógica diferente dependendo da skill atual.
Demonstra uso prático de get_current_external_skill()
"""
current_skill = skill_selector.get_current_external_skill()

if not current_skill:
# Não está em skill específica - comportamento padrão
return actions_sdk.ResponseToUser(
message="Como posso ajudá-lo hoje?",
instruction="Nenhuma skill específica ativa - fluxo geral"
)

# Lógica específica por skill
skill_name_lower = current_skill.name.lower()

if "suporte" in skill_name_lower or "tecnico" in skill_name_lower:
return actions_sdk.ResponseToUser(
message="Estou aqui para ajudar com questões técnicas. Pode descrever o problema?",
instruction=f"Contexto: skill de suporte técnico ({current_skill.name})"
)

elif "vendas" in skill_name_lower or "comercial" in skill_name_lower:
return actions_sdk.ResponseToUser(
message="Ótimo! Vamos conversar sobre nossos produtos e soluções. O que você procura?",
instruction=f"Contexto: skill de vendas ({current_skill.name})"
)

elif "financeiro" in skill_name_lower or "cobranca" in skill_name_lower:
return actions_sdk.ResponseToUser(
message="Estou aqui para questões financeiras e pagamentos. Como posso ajudar?",
instruction=f"Contexto: skill financeiro ({current_skill.name})"
)

else:
# Skill não reconhecida - comportamento genérico
return actions_sdk.ResponseToUser(
message=f"Você está sendo atendido por {current_skill.name}. Como posso ajudar?",
instruction=f"Skill atual: {current_skill.name}"
)

🌍 Horários e Fusos Horários

Formato de Horários

O sistema suporta dois formatos para horários de funcionamento:

# Formato antigo: array simples [abertura, fechamento]
opening_hours = {
"1": ["09:00:00.000Z", "18:00:00.000Z"] # Segunda-feira
}

# Formato novo: array de intervalos [[abertura, fechamento], [abertura2, fechamento2]]
opening_hours = {
"1": [
["09:00:00.000Z", "12:00:00.000Z"], # Manhã
["14:00:00.000Z", "18:00:00.000Z"] # Tarde
]
}

Dias da Semana

  • "0": Domingo
  • "1": Segunda-feira
  • "2": Terça-feira
  • "3": Quarta-feira
  • "4": Quinta-feira
  • "5": Sexta-feira
  • "6": Sábado

Fuso Horário

Todos os cálculos são feitos no fuso horário America/Sao_Paulo.


💡 Dicas de Uso

Melhores Práticas
  • Context hints específicos: Forneça contexto detalhado para melhor seleção
  • Fallback sempre: Configure skill de fallback para casos não cobertos
  • Verificar disponibilidade: Sempre chece se skills estão no horário antes de transferir
  • Trace habilitado: Use trace para debugging da seleção
Considerations
  • LLM dependency: Seleção depende da qualidade do modelo LLM
  • Timezone: Sistema usa fuso horário brasileiro (America/Sao_Paulo)
  • Error handling: Sempre implemente tratamento de erro para falhas de seleção