Skip to main content

Skill Selector

O SkillSelector seleciona automaticamente a skill externa mais adequada para o contexto da conversa usando o LLM. Use quando o agente tem múltiplas skills externas e precisa decidir para qual encaminhar o usuário.

Inicialização

from actions_sdk.core.types.action_context import ActionContext
from actions_sdk.features.conversational.skill_selector import SkillSelector

ctx: ActionContext

selector = SkillSelector(ctx)

# Com timezone para verificação de horário de atendimento
selector = SkillSelector(ctx, timezone="America/Sao_Paulo")

O SkillSelector extrai ctx.external_skills e ctx.messages automaticamente no construtor, e cria internamente um LLMClient.

Parâmetros do construtor:

ParâmetroTipoPadrãoDescrição
ctxActionContextContexto de execução
timezonestr"UTC"Fuso horário para verificação de horário de atendimento das skills

Métodos

select_best_skill()

Seleciona a skill mais adequada para o contexto da conversa usando LLM.

selector = SkillSelector(ctx)
skill_selecionada = selector.select_best_skill()

if skill_selecionada:
return ResponseToAgent(
status=ResponseStatus.SUCCESS,
instruction=f"Encaminhar o usuário para: {skill_selecionada.name}",
functions=[RedirectToSkill(
skill_name=skill_selecionada.name,
reason="Skill selecionada automaticamente.",
)],
)

Parâmetros:

ParâmetroTipoDescrição
external_skillslist[ExternalSkillConfig] | NoneSkills candidatas. Se None, usa as skills do construtor (ctx.external_skills)
messageslist[Message] | NoneHistórico da conversa. Se None, usa ctx.messages
context_hintstr | NoneDica adicional de contexto para auxiliar a seleção
fallback_skillExternalSkillConfig | NoneSkill de último recurso se nenhuma outra se encaixar

Retorna: ExternalSkillConfig | None

Se a seleção falhar (LLM indisponível, erro interno), retorna None silenciosamente — não lança exceção.


get_available_external_skills()

Lista as skills externas disponíveis no momento atual (respeitando horários de atendimento).

skills_disponiveis = selector.get_available_external_skills()
print([s.name for s in skills_disponiveis])

Retorna: list[ExternalSkillConfig]


ExternalSkillConfig

Estrutura que representa uma skill externa:

CampoTipoDescrição
namestrNome da skill
descriptionstrDescrição usada pelo LLM para seleção
opening_hoursdict | NoneHorários de atendimento por dia da semana
opening_hours_exceptionslist | NoneExceções de horário

Erros e Exceções

O SkillSelector é fail-safe: todos os erros internos são capturados e retornam None em vez de lançar exceções. Verifique sempre se o retorno de select_best_skill() é None antes de usar.

skill = selector.select_best_skill()

if skill is None:
return ResponseToAgent(
status=ResponseStatus.ERROR,
instruction="Não foi possível selecionar uma skill automaticamente.",
)

Exemplo completo

Baseado na action skill_selector_selecionar do agente de homologação:

import traceback

from actions_sdk.core.types.action_context import ActionContext
from actions_sdk.core.types.responses import (
RedirectToSkill,
ResponseStatus,
ResponseToAgent,
)
from actions_sdk.features.conversational.skill_selector import SkillSelector
from actions_sdk.features.conversational.state import StateManager
from actions_sdk.features.tracing import ActionSpan

ctx: ActionContext

CHAVE_PROGRESSO = "action.skill_selector.progresso"


def selecionar_skill():
span = ActionSpan(ctx)
state = StateManager(ctx)

span.event("action.skill_selector.inicio", {})

try:
selector = SkillSelector(ctx, timezone="America/Sao_Paulo")
skill = selector.select_best_skill(
context_hint="O usuário parece ter uma dúvida técnica.",
)

if skill is None:
state.update(CHAVE_PROGRESSO, "SEM_SKILL")
return ResponseToAgent(
status=ResponseStatus.ERROR,
instruction="Nenhuma skill adequada encontrada para o contexto atual.",
state_updates=state.get_full_state(),
)

state.update(CHAVE_PROGRESSO, "SUCESSO ✓")
span.event("action.skill_selector.sucesso", {"skill": skill.name})

return ResponseToAgent(
status=ResponseStatus.SUCCESS,
instruction=f"Skill selecionada: {skill.name}. Encaminhar o usuário.",
functions=[
RedirectToSkill(
skill_name=skill.name,
reason=f"Skill '{skill.name}' selecionada automaticamente por LLM.",
)
],
state_updates=state.get_full_state(),
)

except Exception as erro:
state.update(CHAVE_PROGRESSO, "ERRO ✗")
span.event("action.skill_selector.erro", {"erro": str(erro)})
return ResponseToAgent(
status=ResponseStatus.ERROR,
instruction=f"Falha no seletor de skill: {traceback.format_exc()}",
state_updates=state.get_full_state(),
)