Esta página documenta o Actions SDK v1. Para a versão atual (v2), consulte a documentação do SDK v2.
Response Objects
O módulo response_objects fornece estruturas padronizadas e type-safe para retornos de Actions. Centraliza todos os tipos de resposta e define como elas são processadas pela engrenagem de conversação.
Visão Geral
O sistema de resposta funciona com dois objetos principais que determinam o fluxo da conversação:
ResponseToUser: Resposta direta ao usuário que interrompe o ciclo de chamada de açõesResponseToAgent: Resposta que retorna ao LLM para nova decisão
🔄 Ciclo de Interação: User → Agent → Action
Antes de detalhar os objetos de resposta, é importante entender como funciona o ciclo de interação no sistema:
🎯 Pontos-Chave do Fluxo:
- 👤 Usuário inicia enviando uma mensagem
- 🤖 Agent/LLM analisa e toma uma decisão:
- Executar Action → Chama uma função específica
- Responder diretamente → Envia resposta imediata
- ⚙️ Action executada retorna um de dois tipos:
- 📋 ResponseToAgent → Instrução volta para o LLM processar
- ✉️ ResponseToUser → Mensagem vai direto para o usuário
- 🔄 Ciclo continua até uma resposta final ser enviada
💡 Implicações Práticas:
- ResponseToAgent: Mantém o LLM no controle, permite múltiplas actions sequenciais
- ResponseToUser: Quebra o ciclo, envia resposta definitiva ao usuário
- Contexto preservado: Cada action contribui para o histórico do LLM
- Flexibilidade: Permite fluxos simples (1 action) ou complexos (múltiplas actions)
Enums e Classes Base
ResponseStatus
Enum que define o status da resposta.
Valores:
SUCCESS: "success" - Operação bem-sucedidaERROR: "error" - Erro na operação
Quando utilizar:
- Para indicar o resultado da operação
- Permitir diferentes comportamentos baseados no status
Exemplo:
# Resposta de sucesso (padrão)
status = ResponseStatus.SUCCESS
# Resposta com erro
status = ResponseStatus.ERROR
ResponseToUser
Descrição e Objetivo
Objeto estruturado que envia mensagem diretamente para o usuário, ativando a flag back_to_user=True. Isso faz com que o Conversation Engine crie uma mensagem direta para o usuário e pare o ciclo atual de interação, sem retornar ao LLM.
Parâmetros
Obrigatórios:
message(str | MessageComponent | List[str | MessageComponent]): Mensagem que será enviada diretamente ao usuário. Aceita texto simples, um componente interativo, ou uma lista combinando ambos, mas recomendamos sempre usar um MessageComponent ou uma lista de MessageComponents. Internamente sempre normalizado paraList[MessageComponent]. Ver MessageComponents para os tipos disponíveis.instruction(str, opcional na prática): Instrução para o histórico do LLM. Quando omitido, é gerado automaticamente a partir do conteúdo de cada componente. Ver Geração automática de instruction.
Opcionais:
status(ResponseStatus): Status da resposta (padrão: SUCCESS)files(List[FileContent]): Arquivos anexados à respostafunctions(List[SystemFunction]): Funções do sistema a serem executadasdetail(str): Detalhes adicionais sobre o statusstate_updates(Dict[str, Any]): Apenas para observabilidade - cria evento no LangFuse mostrando estado atualmemory_updates(Dict[str, Any]): Apenas para observabilidade - cria evento no LangFuse mostrando memória atualmetadata(Dict[str, Any]): Metadados customizados
Quando Utilizar
✅ Use ResponseToUser quando:
- Quiser enviar resposta predefinida e formatada ao usuário
- Não precisar de processamento adicional do LLM
- Quiser finalizar o ciclo de chamada de ações imediatamente
- Tiver mensagem completa e pronta para o usuário
- Quiser controle total sobre a mensagem final
- Precisar enviar um componente interativo (Reply Buttons ou List)
Resultado Esperado
- Duas mensagens criadas pelo Conversation Engine:
- TOOL_RESPONSE:
instructionvai para o histórico do LLM (contexto futuro) - ASSISTANT:
messagevai diretamente para o usuário
- TOOL_RESPONSE:
- Flag
back_to_user=Trueativada no sistema - Quebra do loop de chamada de ações
- Controle não retorna ao LLM
- Ciclo de interação finalizado
Geração automática de instruction
Quando instruction não é fornecido, o sistema gera automaticamente uma instrução a partir de cada componente em message, concatenando o resultado de to_instruction() de cada um. Para TextMessage, isso é o próprio texto. Para InteractiveReplyButtons e InteractiveList, é uma descrição das opções apresentadas.
InteractiveReplyButtons:
return ResponseToUser(
message=InteractiveReplyButtons(
body="Qual período você prefere?",
buttons=[
ReplyButton(id="manha", title="Manhã"),
ReplyButton(id="tarde", title="Tarde"),
]
)
)
instruction gerada automaticamente:
Qual período você prefere?
Opções:
- Manhã
- Tarde
InteractiveList:
return ResponseToUser(
message=InteractiveList(
body="Selecione o plano de sua preferência",
button="Ver planos",
sections=[
ListSection(
title="Planos Mensais",
rows=[
ListRow(id="basico", title="Básico", description="R$ 49,90/mês"),
ListRow(id="pro", title="Pro", description="R$ 99,90/mês"),
]
),
ListSection(
title="Planos Anuais",
rows=[
ListRow(id="basico_anual", title="Básico Anual", description="R$ 39,90/mês"),
ListRow(id="pro_anual", title="Pro Anual", description="R$ 79,90/mês"),
]
),
]
)
)
instruction gerada automaticamente:
Selecione o plano de sua preferência
Opções:
- Básico
- Pro
- Básico Anual
- Pro Anual
Fornecer instruction explicitamente sempre prevalece sobre a geração automática e é recomendado em fluxos complexos ou quando se quer contextualizar o resultado além do componente em si.
⚠️ Importância Crítica do instruction
O campo instruction não é verdadeiramente opcional na prática. Ele é essencial para:
- Manter contexto do LLM sobre o resultado da action
- Permitir decisões futuras baseadas no que aconteceu
- Garantir continuidade do fluxo conversacional
- Debugging e auditoria do que cada tool executou
Problema comum sem instruction adequado:
# ❌ PROBLEMÁTICO - LLM perde contexto
return ResponseToUser(
message="Agora me informe seu CPF"
# instruction não fornecido -> LLM não sabe se telefone foi validado
)
Histórico que o LLM vê:
TOOL_CALL: validar_telefone({"telefone": "11999999999"})
TOOL_RESPONSE: "Agora me informe seu CPF" # ← LLM não sabe o resultado!
ASSISTANT: "Agora me informe seu CPF"
USER: "123.456.789-00"
Solução correta:
# ✅ CORRETO - LLM mantém contexto
return ResponseToUser(
instruction="Telefone 11999999999 validado com sucesso. Prosseguir para coleta de CPF.",
message="✅ Telefone validado!\n\nAgora me informe seu CPF:"
)
Histórico que o LLM vê:
TOOL_CALL: validar_telefone({"telefone": "11999999999"})
TOOL_RESPONSE: "Telefone 11999999999 validado com sucesso. Prosseguir para coleta de CPF."
ASSISTANT: "✅ Telefone validado!\n\nAgora me informe seu CPF:"
USER: "123.456.789-00"
MessageComponents
MessageComponent é a classe base para todos os tipos de conteúdo aceitos em ResponseToUser.message. Ao retornar um componente, o sistema:
- Serializa cada componente para o formato do item de
response.contentda API v2 viato_webhook_content() - Gera uma descrição textual para o histórico do LLM via
to_instruction()(usada na geração automática deinstruction)
Os tipos disponíveis são: TextMessage, InteractiveReplyButtons e InteractiveList.
TextMessage
Wrapper de texto simples. Na prática não é necessário instanciar TextMessage diretamente — qualquer str passada em message é normalizada automaticamente para TextMessage internamente, mas é recomendado para melhor clareza e consistência.
Parâmetros
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
body | str | Sim | Conteúdo textual da mensagem. |
Exemplo
return ResponseToUser(
message=TextMessage(body="Olá! Como posso te ajudar hoje?"),
instruction="Saudação enviada ao usuário."
)
InteractiveReplyButtons
Componente de botões de resposta rápida do WhatsApp (até 3 botões). O usuário toca em um botão e a seleção é recebida como type=interactive na próxima mensagem.
Parâmetros
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
body | str | Sim | Texto principal do componente. Máximo 1024 chars. |
buttons | List[ReplyButton] | Sim | Lista de 1 a 3 botões. Ids e titles devem ser únicos dentro do componente. |
header | TextHeader | ImageHeader | DocumentHeader | VideoHeader | Não | Cabeçalho opcional. |
footer | str | Não | Rodapé opcional. Máximo 60 chars. |
Classe auxiliar ReplyButton
| Parâmetro | Tipo | Descrição |
|---|---|---|
id | str | Identificador do botão. Máximo 256 chars. Deve ser único no componente. |
title | str | Texto exibido no botão. Máximo 20 chars. Deve ser único no componente. |
Classes de header
| Classe | Parâmetro | Descrição |
|---|---|---|
TextHeader | text: str (≤ 60 chars) | Cabeçalho de texto simples. |
ImageHeader | link: str | URL pública de uma imagem. |
DocumentHeader | link: str | URL pública de um documento. |
VideoHeader | link: str | URL pública de um vídeo. |
Exemplos
# Botões simples
def perguntar_periodo():
return ResponseToUser(
message=InteractiveReplyButtons(
body="Qual período você prefere para o atendimento?",
header=TextHeader(text="Agendamento"),
buttons=[
ReplyButton(id="manha", title="Manhã"),
ReplyButton(id="tarde", title="Tarde"),
ReplyButton(id="noite", title="Noite"),
],
footer="Seg a Sex, das 8h às 20h"
),
instruction="Apresentado seleção de período ao usuário. Aguardar resposta antes de prosseguir."
)
# Com cabeçalho de imagem
def confirmar_cancelamento():
return ResponseToUser(
message=InteractiveReplyButtons(
header=ImageHeader(link="https://storage.example.com/banners/cancelamento.png"),
body="Tem certeza que deseja cancelar?",
buttons=[
ReplyButton(id="sim", title="Sim, cancelar"),
ReplyButton(id="nao", title="Não, manter"),
]
)
)
InteractiveList
Componente de lista interativa do WhatsApp — apresenta opções agrupadas em seções. O usuário toca em um botão para abrir a lista e seleciona uma opção.
Parâmetros
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
body | str | Sim | Texto principal do componente. Máximo 4096 chars. |
button | str | Sim | Label do botão que abre a lista. Máximo 20 chars. |
sections | List[ListSection] | Sim | 1 a 10 seções. Total de rows entre todas as seções: máximo 10. |
header | TextHeader | Não | Cabeçalho de texto. Somente texto — constraint WhatsApp. Máximo 60 chars. |
footer | str | Não | Rodapé opcional. Máximo 60 chars. |
Classe auxiliar ListSection
| Parâmetro | Tipo | Descrição |
|---|---|---|
title | str | Título da seção. Máximo 24 chars. |
rows | List[ListRow] | Opções da seção. Mínimo 1 row por seção. |
Classe auxiliar ListRow
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
id | str | Sim | Identificador da opção. Máximo 256 chars. |
title | str | Sim | Título da opção exibido na lista. Máximo 24 chars. |
description | str | Não | Descrição opcional da opção. Máximo 72 chars. |
Exemplos
# Lista de planos com múltiplas seções
def apresentar_planos(ctx):
return ResponseToUser(
message=[
"Temos os seguintes planos disponíveis para você:",
InteractiveList(
header=TextHeader(text="Planos disponíveis"),
body="Selecione o plano de sua preferência",
button="Ver planos",
sections=[
ListSection(
title="Planos Mensais",
rows=[
ListRow(id="basico", title="Básico", description="R$ 49,90/mês"),
ListRow(id="pro", title="Pro", description="R$ 99,90/mês"),
]
),
ListSection(
title="Planos Anuais",
rows=[
ListRow(id="basico_anual", title="Básico Anual", description="R$ 39,90/mês"),
ListRow(id="pro_anual", title="Pro Anual", description="R$ 79,90/mês"),
]
)
],
footer="Valores promocionais por tempo limitado"
)
]
)
Quando o usuário responde a um componente interativo, o sistema popula automaticamente as chaves last_interactive e interactive_history no state da sessão, acessíveis em qualquer action subsequente.
Consulte a documentação completa em State Management — Componentes Interativos.
Exemplos ResponseToUser
# Resposta com validação bem-sucedida
def confirmar_agendamento(data: str, horario: str, protocolo: str):
return ResponseToUser(
instruction=f"Agendamento criado com sucesso: protocolo {protocolo} para {data} às {horario}h. Cliente confirmado e notificado.",
message=f"✅ Agendamento confirmado para {data} às {horario}h!\n\nProtocolo: {protocolo}\nVocê receberá um lembrete 1 hora antes do compromisso."
)
# Resposta com arquivos anexados
def enviar_comprovante(numero_protocolo: str, arquivo_pdf: str):
return ResponseToUser(
instruction=f"Comprovante protocolo {numero_protocolo} gerado e enviado com sucesso. Arquivo: {arquivo_pdf}. Cliente pode prosseguir.",
message="📄 Seu comprovante foi gerado com sucesso!",
files=[
FileContent(
fileId=arquivo_pdf,
fileName=f"comprovante_{numero_protocolo}.pdf",
fileType="application/pdf"
)
]
)
# Resposta com validação bem-sucedida
def finalizar_cadastro(dados_usuario: dict):
return ResponseToUser(
instruction=f"Cadastro do usuário {dados_usuario.get('nome')} finalizado com sucesso. Dados validados e conta ativada. Cliente pode utilizar todos os serviços.",
message="🎉 Cadastro realizado com sucesso!\n\nSua conta está ativa e você já pode utilizar todos os nossos serviços.",
state_updates={
"usuario_cadastrado": True,
"etapa_atual": "completo"
},
)
# Resposta com transferência para humano
def solicitar_suporte_complexo(motivo: str):
return ResponseToUser(
instruction=f"Transferindo cliente para atendimento humano. Motivo: {motivo}. Prioridade alta para suporte especializado.",
message="🤝 Entendo que você precisa de um atendimento mais especializado.\n\nVou transferir você para um de nossos especialistas que poderá ajudar melhor com sua solicitação.",
functions=[
TransferToHuman(
reason=f"Solicitação complexa: {motivo}",
session_info={
"priority": "alta",
"category": "suporte_especializado"
}
)
]
)
# Resposta de erro formatada
def erro_validacao_documento():
return ResponseToUser(
instruction="Falha na validação do documento: critérios não atendidos (legibilidade, validade, autenticidade). Solicitar novo documento ao cliente.",
status=ResponseStatus.ERROR,
message="❌ Documento inválido\n\nO documento enviado não atende aos critérios necessários:\n• Deve estar legível\n• Deve estar dentro da validade\n• Deve ser um documento oficial\n\nPor favor, envie um novo documento.",
detail="Falha na validação automática do documento"
)
ResponseToAgent
Descrição e Objetivo
Objeto estruturado que retorna uma instrução para o LLM, permitindo que o agente tome uma nova decisão baseada na informação fornecida. O Conversation Engine adiciona a instrução ao contexto e solicita um novo completion do LLM.
Parâmetros
Obrigatórios:
instruction(str): Instrução que será enviada de volta ao LLM
Opcionais:
status(ResponseStatus): Status da resposta (padrão: SUCCESS)functions(List[SystemFunction]): Funções do sistema a serem executadasdetail(str): Detalhes adicionais sobre o statusmetadata(Dict[str, Any]): Metadados customizados
Quando Utilizar
✅ Use ResponseToAgent quando:
- Precisar que o LLM processe a informação retornada
- Quiser que o agente tome decisões baseadas no resultado
- A Action for intermediária no fluxo de conversação
- Precisar combinar resultados com outras informações
- Quiser manter o fluxo de chamada de ações ativo
Resultado Esperado
- Instrução adicionada ao contexto do LLM
- Novo completion solicitado ao modelo
- LLM pode fazer novas chamadas de ações baseado na informação
- Fluxo continua até o LLM decidir responder diretamente
Exemplos ResponseToAgent
# Resultado de consulta para análise do LLM
def consultar_saldo_conta(numero_conta: str):
saldo = buscar_saldo_no_banco(numero_conta)
return ResponseToAgent(
instruction=f"Saldo atual da conta {numero_conta}: R$ {saldo:.2f}. Com base nesta informação, analise se o cliente pode prosseguir com a operação solicitada."
)
# Validação que requer decisão do LLM
def validar_idade_usuario(idade: int, servico: str):
if idade >= 18:
return ResponseToAgent(
instruction=f"Usuário tem {idade} anos, está apto para o serviço '{servico}'. Prossiga com o atendimento normalmente."
)
else:
return ResponseToAgent(
instruction=f"Usuário tem {idade} anos, é menor de idade. Para o serviço '{servico}', verifique se precisa de autorização dos responsáveis ou se há restrições específicas.",
state_updates={"usuario_menor_idade": True}
)
# Resultado de API externa para análise
def consultar_cep(cep: str):
try:
endereco = api_viacep(cep)
return ResponseToAgent(
instruction=f"Endereço encontrado para o CEP {cep}: {endereco['logradouro']}, {endereco['bairro']}, {endereco['localidade']}-{endereco['uf']}. Continue o atendimento com essas informações."
)
except Exception as e:
return ResponseToAgent(
status=ResponseStatus.ERROR,
instruction=f"Não foi possível consultar o CEP {cep}. Solicite ao usuário que informe o endereço completo manualmente.",
detail=str(e)
)
# Análise de documento que requer interpretação
def analisar_documento(tipo_documento: str, conteudo: str):
resultado_analise = processar_documento(tipo_documento, conteudo)
return ResponseToAgent(
instruction=f"Análise do {tipo_documento} concluída:\n" +
f"• Status: {resultado_analise['status']}\n" +
f"• Campos encontrados: {resultado_analise['campos']}\n" +
f"• Observações: {resultado_analise['observacoes']}\n\n" +
f"Com base nesta análise, prossiga conforme necessário.",
)
# Integração com sistema externo
def criar_protocolo_atendimento(categoria: str, descricao: str):
protocolo = sistema_externo.criar_protocolo(categoria, descricao)
return ResponseToAgent(
instruction=f"Protocolo de atendimento criado com sucesso: #{protocolo['numero']}.\n" +
f"Categoria: {protocolo['categoria']}\n" +
f"Prioridade: {protocolo['prioridade']}\n\n" +
f"Informe ao usuário o número do protocolo e continue o atendimento.",
state_updates={
"protocolo_ativo": protocolo['numero'],
"categoria_atendimento": categoria
}
)
Classes de Conveniência
System Functions
EndChat
Finaliza a conversa.
Parâmetros:
reason(str): Motivo do encerramentosession_info(dict, opcional): Informações da sessão
Exemplo:
def finalizar_atendimento(motivo: str):
return ResponseToUser(
message="Atendimento finalizado. Obrigado por entrar em contato!",
functions=[EndChat(reason=motivo)]
)
TransferToHuman
Transfere para atendimento humano ou para uma skill externa específica.
Parâmetros:
reason(str): Motivo da transferênciaexternal_skill_name(str, opcional): Nome da skill externa para onde transferirexternal_skill_id(str, opcional): ID (UUID) da skill externa para onde transferirsession_info(dict, opcional): Informações adicionais da sessão.user_id(str, opcional): ID de um operador específico para o usuário
Exemplos:
# Transferência para skill externa específica
def transferir_para_pagamentos(user_id: str):
return ResponseToUser(
instruction="Cliente solicitou suporte para pagamentos. Transferindo para skill externa de Pagamentos.",
message="Vou transferir você para nossa equipe de Pagamentos que poderá ajudar melhor com sua solicitação.",
functions=[
TransferToHuman(
reason="Cliente precisa de suporte especializado em pagamentos",
external_skill_name="Pagamentos",
external_skill_id="123e4567-e89b-12d3-a456-426614174000",
user_id=user_id,
session_info={"priority": "alta"}
)
]
)
# Transferência genérica para atendimento humano
def transferir_para_especialista():
return ResponseToUser(
instruction="Caso complexo que requer atendimento humano especializado. Cliente transferido.",
message="Vou transferir você para um especialista.",
functions=[
TransferToHuman(
reason="Necessita atendimento especializado",
session_info={"priority": "alta"}
)
]
)
RedirectToSkill
Redireciona deterministicamente para outra habilidade interna do agente. Essa função pode ser utilizada tanto em ResponseToUser quanto em ResponseToAgent.
Quando usando via 'ResponseToUser' ocorre o redirecionamento para a habilidade e a mensagem é enviada diretamente para o usuário. Não ocorre um completion na nova habilidade isso só ocorre quando o usuário mandar uma nova mensagem. Isso é útil quando se tem uma mensagem fixa pós redirecionamento.
Parâmetros:
skill_name(str): Nome da skill interna para redirecionamentoreason(str): Motivo do redirecionamentosession_info(dict, opcional): Informações da sessão
Quando utilizar:
- Transferir automaticamente para skill específica baseado em lógica determinística
- Encadear skills para fluxos complexos
- Delegar processamento para skill especializada
Exemplo de uso com ResponseToAgent:
def processar_nome_pirata(name: str):
pirate_name = gerar_nome_pirata(name)
return ResponseToAgent(
instruction=f"Nome pirata '{pirate_name}' gerado para {name}. Agora informe o usuário de forma criativa.",
functions=[
RedirectToSkill(
skill_name="Comunicação Criativa",
reason="Apresentar resultado de forma envolvente"
)
]
)
Exemplo de uso com ResponseToUser:
def processar_nome_pirata_direto(name: str):
pirate_name = gerar_nome_pirata(name)
return ResponseToUser(
instruction=f"Nome pirata '{pirate_name}' gerado para {name}. Usuário já foi informado; próxima skill deve continuar o fluxo se necessário.",
message=f"⚓ Ahoy! Seu nome de corsário é *{pirate_name}*! Bem-vindo(a) a bordo, {name}!",
functions=[
RedirectToSkill(
skill_name="Comunicação Criativa",
reason="Continuar fluxo com skill que cuida do tom criativo pós-apresentação"
)
]
)
RedirectToAgent
Redireciona deterministicamente para outro agente dentro do mesmo team.
Este método só pode ser utilizado dentro de um ResponseToAgent e não em ResponseToUser.
Parâmetros:
agent_id(str): ID (UUID) do agente de destino para redirecionamentoreason(str): Motivo do redirecionamentosession_info(dict, opcional): Informações da sessão
Quando utilizar:
- Transferir automaticamente para agente específico baseado em lógica determinística
- Encadear agentes para fluxos complexos que requerem especialização
Handoff Configuration:
O handoff config permite controlar quais informações são transferidas entre agentes. Ele é configurado no agente de origem (quem está transferindo) e define filtros para state e memory.
Estrutura do Handoff Config:
{
"handoff": {
"7d09cf54-e58e-4bd8-9c60-197d58990903": {
"include_state": {
"keys_filter": [
"perfil",
"carrinho"
]
},
"include_memory": {
"keys_filter": [
"informacoes_usuario"
]
},
"additional_instruction": "Cliente segurado logado precisa prossiga para os próximos passos"
}
}
}
Como funciona:
handoff: Objeto que mapeia agent_id para suas configurações de transferênciaagent_id(chave): ID (UUID) do agente de destinoinclude_state.keys_filter: Lista de chaves do state que serão transferidas. Apenas as chaves especificadas serão passadas para o agente de destino. Se não especificado, todo o state é transferido.include_memory.keys_filter: Lista de chaves da memory que serão transferidas. Apenas as chaves especificadas serão passadas para o agente de destino. Se não especificado, toda a memory é transferida.additional_instruction: ⚠️ NÃO é utilizado quando a transferência é feita via SDK comRedirectToAgent. A instrução que o agente de destino receberá é o campoinstructiondoResponseToAgent.
Exemplo de uso com handoff config:
def transferir_agente_consorcio():
return ResponseToAgent(
instruction=f"Siga as instruções do agente de Consórcio para processar a solicitação, o cliente é um segurado.",
functions=[
RedirectToAgent(
agent_id="7d09cf54-e58e-4bd8-9c60-197d58990903",
reason="Cliente solicitou transferência para agente de Consórcio"
)
]
)
Só é possivel realizar transferência para agentes do mesmo team. No momento o team está sendo configurado via backoffice, solicite ao time de desenvolvimento.
Comparação: Quando Usar Cada Tipo
| Cenário | ResponseToUser | ResponseToAgent |
|---|---|---|
| Confirmação de agendamento | ✅ Resposta final e formatada | ❌ Desnecessário |
| Consulta de saldo | ❌ LLM pode usar a info | ✅ Para análise e decisão |
| Erro de validação | ✅ Resposta direta clara | ❌ LLM pode confundir |
| Resultado de API | ❌ LLM deve processar | ✅ Para análise contextual |
| Transferência para humano | ✅ Mensagem de despedida | ❌ Ação imediata |
| Redirecionamento para skill interna | ❌ Use RedirectToSkill | ✅ Use RedirectToSkill |
| Upload de arquivo | ✅ Confirmação direta | ❌ Ação simples |
| Análise de documento | ❌ LLM deve interpretar | ✅ Para próximas decisões |
| Finalização de processo | ✅ Mensagem de sucesso | ❌ Processo finalizado |
| Apresentar opções ao usuário (botões/lista) | ✅ Use InteractiveReplyButtons ou InteractiveList | ❌ LLM não escolhe o componente |
Boas Práticas
✅ Faça
Para ResponseToUser:
- SEMPRE forneça
instructionclaro sobre o resultado da action — exceto quando usar componentes interativos com geração automática suficiente - Use
messageclara e completa para o usuário - Separe responsabilidades:
instructionpara LLM,messagepara usuário - Documente o resultado da operação no
instruction
Para ResponseToAgent:
- Forneça contexto suficiente para o LLM decidir
- Use linguagem clara nas instruções
- Mantenha instruções concisas mas informativas
❌ Evite
- NUNCA omita
instructionem ResponseToUser de texto simples (LLM perde contexto) - Não misture os propósitos (user vs agent)
- Não use ResponseToUser quando precisar de análise do LLM
- Não use ResponseToAgent para respostas finais simples
- Não inclua informações sensíveis em metadados
- Não crie instruções ambíguas para o LLM