Skills de Agentes IA
Skills são capacidades que agentes IA podem chamar durante conversas. Elas executam nativamente dentro da Turn.io, proporcionando execução rápida sem chamadas HTTP externas.
Tipos de Skills
Existem dois tipos de skills:
Skills de Conhecimento retornam conteúdo estático quando chamadas. Use-as para dar ao agente IA acesso a informações de referência como FAQs, políticas, detalhes de produtos ou documentação. A IA chama a skill e recebe o conteúdo para incorporar em sua resposta.
Skills de Código executam código Lua com parâmetros. Use-as quando a IA precisa realizar cálculos, chamar APIs, buscar dados dinâmicos ou executar lógica de negócio.
| Tipo | O que faz | Caso de uso |
|---|---|---|
| Skills de Conhecimento | Retorna conteúdo estático | FAQs, políticas, informações de referência |
| Skills de Código | Executa código Lua | Cálculos, chamadas de API, buscas |
Ambos os tipos podem ser criados na interface da Turn.io ou empacotados com um app Lua.
Skills de Código vs Skills de App
Existem duas formas de criar Skills de Código, com diferentes capacidades:
| Capacidade | Skills de Código (Interface) | Skills de App (empacotadas) |
|---|---|---|
| Criação | Criadas na interface Turn.io | Empacotadas em pacote de app Lua |
| APIs Disponíveis | 5 APIs: HTTP, JSON, Crypto, Encoding, Logger | API completa da plataforma (16+ módulos) |
| Logging | turn.logger (logs da jornada) | turn.logger (logs do app) |
| Acesso a contatos | Somente via tabela context | API turn.contacts disponível |
| Controle de jornadas | Não disponível | API turn.journeys disponível |
| Templates | Não disponível | API turn.liquid disponível |
| Limite de memória | 50MB | Gerenciado pelo app |
| Timeout | 10 segundos | Configurável por chamada |
| Estado | Stateless (limpo a cada chamada) | VM Lua persistente |
Quando usar Skills de Código (Interface):
- Cálculos simples, transformações de dados ou validações
- Buscas em APIs externas que retornam dados para a IA
- Prototipagem rápida sem criar um pacote de app completo
Quando usar Skills de App (empacotadas):
- Skills que precisam ler ou atualizar campos de contato
- Operações que requerem integração com a plataforma (jornadas, templates)
- Skills que compartilham configuração ou estado com outras funcionalidades do app
Skills de Conhecimento
Skills de Conhecimento fornecem conteúdo estático que o agente IA pode recuperar durante conversas. São ideais para FAQs, políticas, informações de produtos ou qualquer conteúdo de referência que a IA precisa acessar.
Criando uma Skill de Conhecimento
Na interface da Turn.io:
- Navegue até Configurações de IA → Skills
- Clique em Criar Skill
- Selecione Conhecimento como o tipo de skill
- Digite um nome (snake_case, ex:
horarios_clinica) - Digite uma descrição que diz à IA quando usar esta skill
- Digite o conteúdo (markdown suportado)
- Salve a skill
Exemplo de Skill de Conhecimento
Nome: politica_devolucao
Descrição: Retorna a política de devolução da empresa quando um cliente pergunta sobre devoluções, reembolsos ou trocas
Conteúdo:
## Política de Devolução
Aceitamos devoluções em até 30 dias após a compra. Os itens devem estar:
- Sem uso e na embalagem original
- Acompanhados do recibo ou confirmação do pedido
**Prazo de reembolso:** 5-7 dias úteis após recebermos o item.
**Trocas:** Disponíveis para o mesmo item em tamanho ou cor diferente.
**Itens não retornáveis:** Cartões-presente, itens personalizados e itens em liquidação final.
Para iniciar uma devolução, responda com o número do seu pedido.
A descrição é importante—ela diz ao agente IA quando chamar esta skill. Escreva-a claramente para que a IA saiba usá-la quando clientes perguntarem sobre devoluções, reembolsos ou trocas.
Skills de Código
Skills de Código executam código Lua quando chamadas. Elas podem aceitar parâmetros, acessar contexto da conversa, chamar APIs externas e retornar resultados dinâmicos.
Escrevendo Skills de Código
Uma Skill de Código é um arquivo Lua com um cabeçalho LDoc que define seu schema, seguido do código de implementação.
Estrutura Básica
--- Breve descrição do que a skill faz
--
-- @param nome_parametro (tipo): Descrição do parâmetro
-- @return (tipo): Descrição do valor de retorno
-- Acessa parâmetros do agente IA
local valor = args.nome_parametro
-- Acessa contexto da conversa
local nome_contato = context.contact.name
-- Retorna dados para o agente IA
return {
temperatura = 22,
condicao = "Ensolarado"
}
Anotações LDoc
O cabeçalho LDoc no topo de cada arquivo de skill é lido pelo bloco de Agente IA da Turn.io para entender como usar sua skill:
- Descrição da skill - A primeira linha (
---) diz ao Agente IA quando chamar esta skill. O Agente IA compara mensagens dos usuários contra esta descrição para decidir se a skill é relevante. - Schema de parâmetros - As anotações
@paramdefinem quais informações o Agente IA deve extrair da conversa e passar para sua skill. - Schema de retorno - A anotação
@returndiz ao Agente IA quais dados esperar de volta, que ele usa para formular sua resposta.
A descrição e os parâmetros são automaticamente extraídos e mostrados ao Agente IA, então escreva-os claramente e especificamente.
Linha de Descrição
A primeira linha de comentário se torna a descrição da skill. O bloco de Agente IA lê isso para decidir quando chamar sua skill:
--- Obtém o clima atual para uma cidade especificada
Escreva descrições que expliquem claramente quando a IA deve usar esta skill. Quando um usuário envia uma mensagem, o Agente IA a compara contra todas as descrições de skills anexadas. Se a descrição da sua skill corresponder à intenção do usuário, o Agente IA a chamará.
Sintaxe de Parâmetros
-- @param nome (tipo): Descrição
-- @param nome (tipo|nil): Descrição -- Parâmetro opcional
Mapeamento de Tipos
| Tipo LDoc | JSON Schema | Descrição |
|---|---|---|
string | string | Valores de texto |
number | number | Números decimais |
integer | integer | Números inteiros |
boolean | boolean | true/false |
table | object | Tabelas Lua (chave-valor) |
array | array | Tabelas sequenciais |
tipo|nil | opcional | Marca parâmetro como opcional |
Valores de Retorno
-- @return (tipo): Descrição
Skills tipicamente retornam uma tabela (objeto) contendo os dados do resultado. O agente IA recebe esses dados e os usa para formular sua resposta.
A Tabela args
Quando o Agente IA chama sua skill, ele extrai valores de parâmetros da conversa baseado nas suas anotações @param e os passa na tabela args. Por exemplo, se um usuário diz "Qual o clima em São Paulo?", o Agente IA extrai "São Paulo" e passa como args.city:
Parâmetros fornecidos pelo Agente IA estão disponíveis na tabela args:
local cidade = args.city -- parâmetro string
local peso = args.weight -- parâmetro number
local expresso = args.express -- parâmetro boolean (pode ser nil se opcional)
Sempre valide ou forneça valores padrão para parâmetros:
local cidade = args.city or "Desconhecido"
local peso = tonumber(args.weight) or 1
local expresso = args.express or false
A Tabela context
A tabela context fornece acesso seguro aos dados da conversa. Sempre use context para dados de contato, chat e sessão—nunca peça ao agente IA para fornecer essas informações como parâmetros.
-- Informações do contato
context.contact.name -- Nome do contato
context.contact.urn -- URN do contato (ex: whatsapp:+5511999999999)
context.contact.uuid -- UUID do contato
context.contact.details -- Campos personalizados do contato (tabela)
-- Informações do chat
context.chat.uuid -- UUID do chat
context.chat.title -- Título do chat
context.chat.state -- Estado do chat
context.chat.state_reason -- Motivo do estado atual
context.chat.owner -- Proprietário do chat
context.chat.assigned_to -- Agente atribuído
-- Informações do número
context.number.uuid -- UUID do número
context.number.display_name -- Nome de exibição do número
context.number.address -- Endereço do número de telefone
context.number.profile_picture -- URL da foto de perfil
-- Variáveis da jornada
context.vars -- Tabela de variáveis da jornada
Nunca defina parâmetros para identificação de contato, tokens de autenticação ou dados de sessão. O agente IA pode alucinar valores ou ser suscetível a injeção de prompt. Sempre use a tabela context para esses dados—ela vem diretamente da plataforma e não pode ser manipulada.
APIs Disponíveis
Skills de Código criadas na interface têm acesso a um conjunto focado de APIs otimizadas para operações rápidas e stateless:
| API | Propósito |
|---|---|
turn.http | Fazer requisições HTTP para APIs externas |
turn.json | Codificar e decodificar dados JSON |
turn.crypto | Criptografia, hashing, assinaturas HMAC |
turn.encoding | Base64, codificação URL, conversão hex |
turn.logger | Logging de debug (visível nos logs da jornada) |
-- Requisições HTTP para APIs externas
local body, status_code, headers = turn.http.request({
url = "https://api.example.com/data",
method = "GET",
headers = { ["Authorization"] = "Bearer sk_live_xxxxx" }
})
-- Codificação/decodificação JSON
local data = turn.json.decode(body)
local json_string = turn.json.encode({ result = data.value })
-- Operações criptográficas
local signature = turn.crypto.hmac_sha256_hex("my_secret", json_string)
local hash = turn.crypto.sha256_hex("data to hash")
-- Utilitários de codificação
local encoded = turn.encoding.base64_encode("binary data")
local url_safe = turn.encoding.url_encode("hello world")
-- Logging (visível na UI de logs da jornada)
turn.logger.debug("Processando requisição...")
turn.logger.info("Dados buscados para: " .. args.account_id)
turn.logger.warning("Limite de taxa se aproximando")
turn.logger.error("Chamada API falhou: " .. tostring(status_code))
Skills empacotadas com apps Lua têm acesso a APIs adicionais incluindo turn.contacts, turn.journeys, turn.liquid, e mais. Veja a Referência da API para a lista completa.
Criando Skills de Código via Interface
- Navegue até Configurações de IA → Skills
- Clique em Criar Skill
- Selecione Código como o tipo de skill
- Digite o nome da skill e o código Lua com anotações LDoc
- Salve a skill
Padrões Comuns
Aqui estão exemplos práticos mostrando padrões comuns de Skills de Código usando as APIs disponíveis.
Chamada de API HTTP
Buscar dados de uma API externa com autenticação:
--- Obtém saldo da conta de API de pagamentos
-- @param account_id (string): O ID da conta para consultar
-- @return (object): Informações do saldo da conta
local body, status_code = turn.http.request({
url = "https://api.example.com/accounts/" .. args.account_id .. "/balance",
method = "GET",
headers = {
["Authorization"] = "Bearer sk_live_xxxxx", -- Sua chave de API
["Content-Type"] = "application/json"
}
})
if status_code ~= 200 then
return { error = "Falha ao buscar saldo", status = status_code }
end
local data = turn.json.decode(body)
return {
account_id = args.account_id,
balance = data.balance,
currency = data.currency
}
Cálculo de Pedido
Calcular totais a partir de parâmetros simples:
--- Calcula total do pedido com impostos
-- @param product_name (string): Nome do produto
-- @param quantity (integer): Número de itens
-- @return (object): Resumo do pedido com total
-- Catálogo de produtos (preços devem vir do seu backend, não do usuário)
local prices = {
["Widget"] = 9.99,
["Gadget"] = 24.99,
["Gizmo"] = 14.99
}
local product = args.product_name or "Widget"
local qty = tonumber(args.quantity) or 1
local price = prices[product] or 9.99
local subtotal = qty * price
local tax = subtotal * 0.1 -- 10% imposto
local total = subtotal + tax
return {
product = product,
quantity = qty,
unit_price = string.format("%.2f", price),
subtotal = string.format("%.2f", subtotal),
tax = string.format("%.2f", tax),
total = string.format("%.2f", total)
}
Tratamento de Erros
Tratar erros de API baseado no status da resposta:
--- Chama API externa com tratamento de erros
-- @param endpoint (string): Endpoint da API para chamar
-- @return (object): Resultado ou informações de erro
local body, status_code = turn.http.request({
url = "https://api.example.com/" .. args.endpoint,
method = "GET",
timeout = 5000
})
if status_code >= 400 then
return {
success = false,
error = "Erro de API",
status = status_code
}
end
return {
success = true,
data = turn.json.decode(body)
}
Debugging com Logging
Use turn.logger para rastrear execução e debugar problemas. Logs aparecem na UI de logs da jornada:
--- Busca inventário de produto
-- @param product_id (string): ID do produto a verificar
-- @return (object): Informações de inventário
turn.logger.info("Buscando inventário para: " .. args.product_id)
local body, status_code = turn.http.request({
url = "https://api.inventory.com/products/" .. args.product_id,
method = "GET",
headers = { ["Authorization"] = "Bearer sk_live_xxxxx" }
})
turn.logger.debug("Status da resposta API: " .. tostring(status_code))
if status_code ~= 200 then
turn.logger.error("Busca de inventário falhou: " .. tostring(status_code))
return { error = "Produto não encontrado", status = status_code }
end
local data = turn.json.decode(body)
turn.logger.info("Encontradas " .. tostring(data.quantity) .. " unidades em estoque")
return {
product_id = args.product_id,
in_stock = data.quantity > 0,
quantity = data.quantity
}
Cálculos e Formatação
Realizar cálculos e retornar resultados formatados:
--- Calcula parcela de empréstimo
-- @param principal (number): Valor principal do empréstimo
-- @param rate (number): Taxa de juros anual (ex: 5.5 para 5.5%)
-- @param years (integer): Prazo do empréstimo em anos
-- @return (object): Parcela mensal e custo total
local principal = tonumber(args.principal) or 0
local annual_rate = tonumber(args.rate) or 0
local years = tonumber(args.years) or 1
-- Converter taxa anual para mensal
local monthly_rate = (annual_rate / 100) / 12
local num_payments = years * 12
-- Calcular parcela mensal usando fórmula de amortização
local monthly_payment
if monthly_rate == 0 then
monthly_payment = principal / num_payments
else
monthly_payment = principal *
(monthly_rate * math.pow(1 + monthly_rate, num_payments)) /
(math.pow(1 + monthly_rate, num_payments) - 1)
end
local total_paid = monthly_payment * num_payments
local total_interest = total_paid - principal
return {
monthly_payment = string.format("R$%.2f", monthly_payment),
total_paid = string.format("R$%.2f", total_paid),
total_interest = string.format("R$%.2f", total_interest),
num_payments = num_payments
}
Requisição POST com Corpo JSON
Enviar dados para uma API externa:
--- Cria um ticket de suporte em sistema externo
-- @param subject (string): Assunto do ticket
-- @param message (string): Descrição do ticket
-- @return (object): Informações do ticket criado
local payload = turn.json.encode({
subject = args.subject,
message = args.message,
customer_name = context.contact.name,
customer_phone = context.contact.urn,
source = "whatsapp"
})
local body, status_code = turn.http.request({
url = "https://api.helpdesk.com/tickets",
method = "POST",
headers = {
["Content-Type"] = "application/json",
["Authorization"] = "Bearer sk_live_xxxxx" -- Sua chave de API
},
body = payload
})
if status_code ~= 201 then
return { error = "Falha ao criar ticket", status = status_code }
end
local ticket = turn.json.decode(body)
return {
success = true,
ticket_id = ticket.id,
ticket_url = ticket.url
}
API com Autenticação por Assinatura
Chamar uma API que requer autenticação por assinatura HMAC:
--- Verifica status da conta com API parceira
-- @param account_id (string): Conta para verificar
-- @return (object): Informações de status da conta
local api_key = "pk_xxxxx" -- Sua chave de API
local api_secret = "sk_xxxxx" -- Seu segredo de API
local timestamp = tostring(os.time())
-- Construir a string para assinar
local request_path = "/accounts/" .. args.account_id .. "/status"
local string_to_sign = "GET" .. request_path .. timestamp
-- Gerar assinatura HMAC
local signature = turn.crypto.hmac_sha256_hex(api_secret, string_to_sign)
local body, status_code = turn.http.request({
url = "https://api.partner.com" .. request_path,
method = "GET",
headers = {
["X-Api-Key"] = api_key,
["X-Timestamp"] = timestamp,
["X-Signature"] = signature
}
})
if status_code ~= 200 then
return { error = "Falha ao verificar conta", status = status_code }
end
local data = turn.json.decode(body)
return {
account_id = args.account_id,
status = data.status,
balance = data.balance,
last_activity = data.last_activity
}
Busca com Fallback
Buscar dados de um sistema externo com fallback gracioso:
--- Obtém informações do cliente do CRM
-- @param customer_id (string): ID do cliente para consultar
-- @return (object): Informações do cliente ou valores padrão
local body, status_code = turn.http.request({
url = "https://api.crm.com/customers/" .. args.customer_id,
method = "GET",
headers = {
["Authorization"] = "Bearer sk_live_xxxxx" -- Sua chave de API
}
})
-- Retornar valores padrão se cliente não encontrado
if status_code == 404 then
return {
found = false,
customer_id = args.customer_id,
name = context.contact.name or "Cliente Valioso",
tier = "standard",
discount = 0
}
end
if status_code ~= 200 then
return { error = "Busca no CRM falhou", status = status_code }
end
local customer = turn.json.decode(body)
return {
found = true,
customer_id = customer.id,
name = customer.name,
tier = customer.loyalty_tier,
discount = customer.discount_percent,
lifetime_value = customer.total_spent
}
Limitações
Skills de Código têm as seguintes restrições:
- Timeout: 10 segundos de tempo máximo de execução
- Memória: 50MB de uso máximo de memória
- Stateless: Cada execução começa do zero (sem estado persistente entre chamadas)
- APIs: Limitado a HTTP, JSON, Crypto, Encoding, Logger (sem Contacts, Journeys)
Para casos de uso complexos que requerem estado persistente ou acesso completo à API da plataforma, use Skills de App em vez disso.
Skills de App
Skills de App são empacotadas com apps Lua e declaradas no manifest.json do app.
Declaração no Manifest
{
"app": {
"type": "lua",
"name": "meu_app",
"title": "Meu App",
"version": "1.0.0",
"description": "App com skills de IA"
},
"skills": [
{"name": "get_weather", "file": "meu_app/skills/get_weather.lua"},
{"name": "lookup_order", "file": "meu_app/skills/lookup_order.lua"}
]
}
Organização de Arquivos
meu_app.zip
├── meu_app.lua # Arquivo principal do app
├── meu_app/
│ └── skills/
│ ├── get_weather.lua
│ └── lookup_order.lua
└── assets/
└── manifest.json
Formato de Referência
Skills de App são referenciadas usando o formato: app:nome_app:nome_skill
Por exemplo: app:meu_app:get_weather
Exemplos Completos
Consulta de Clima (Básico)
Uma skill simples que recebe o nome de uma cidade e retorna dados do clima:
--- Obtém o clima atual para uma cidade especificada
--
-- @param city (string): O nome da cidade para obter o clima
-- @return (object): Informações do clima incluindo temperatura e condições
local nome_cidade = args.city or "Desconhecido"
local solicitado_por = context.contact.name or "Desconhecido"
-- Em produção, chame uma API de clima real aqui
local condicoes = {"Ensolarado", "Nublado", "Chuvoso", "Parcialmente Nublado", "Ventoso"}
return {
city = nome_cidade,
temperature = math.random(10, 35),
condition = condicoes[math.random(1, #condicoes)],
humidity = math.random(30, 90) .. "%",
requested_by = solicitado_por
}
Calculadora de Frete (Parâmetros Opcionais)
Uma skill demonstrando parâmetros booleanos opcionais:
--- Calcula o custo de frete para um pacote
--
-- @param weight (number): Peso do pacote em quilogramas
-- @param destination (string): Tipo de destino - "domestic" ou "international"
-- @param express (boolean|nil): Se deve usar frete expresso (opcional)
-- @return (object): Cotação de frete com custo e prazo estimado de entrega
local peso_pkg = tonumber(args.weight) or 1
local dest = args.destination or "domestic"
local is_expresso = args.express or false
local nome_cliente = context.contact.name or "Cliente"
-- Calcular custo de frete
local custo_base = 5.00
local custo_peso = peso_pkg * 2.50
local multiplicador_destino = (dest == "international") and 3.0 or 1.0
local multiplicador_expresso = is_expresso and 2.0 or 1.0
local total = (custo_base + custo_peso) * multiplicador_destino * multiplicador_expresso
return {
customer = nome_cliente,
weight_kg = peso_pkg,
destination = dest,
express = is_expresso,
cost = string.format("R$%.2f", total),
estimated_days = is_expresso and "1-2 dias úteis" or "5-7 dias úteis"
}
Consulta de Pedido (Uso de Contexto)
Uma skill que usa contexto para personalizar a resposta:
--- Busca o status de um pedido pelo seu ID
--
-- @param order_id (string): O ID do pedido para buscar
-- @return (object): Detalhes do pedido incluindo status e rastreamento
local id = args.order_id or "desconhecido"
local nome_cliente = context.contact.name or "Cliente"
-- Em produção, consulte seu banco de dados de pedidos aqui
local status_lista = {"Processando", "Enviado", "Saiu para Entrega", "Entregue"}
return {
order_id = id,
customer = nome_cliente,
status = status_lista[math.random(1, #status_lista)],
last_updated = os.date("%Y-%m-%d %H:%M"),
items = {
{ name = "Widget A", quantity = 2, price = "R$19,99" },
{ name = "Gadget B", quantity = 1, price = "R$49,99" }
},
total = "R$89,97",
tracking_number = "TRK" .. math.random(100000, 999999)
}
Usando Skills em Agentes IA
Anexando Skills
Ao configurar um card de Agente IA em uma jornada:
- Abra as configurações do Agente IA
- Navegue até a seção Skills
- Selecione skills para anexar:
- Skills de Conhecimento e Skills de Código aparecem por nome
- Skills de App aparecem como
app:nome_app:nome_skill
Comportamento em Tempo de Execução
Durante uma conversa:
- O agente IA analisa a mensagem do usuário e o contexto da conversa
- Se uma skill pode ajudar a atender a solicitação do usuário, o agente a chama
- A skill retorna seu conteúdo (Skills de Conhecimento) ou executa e retorna resultados (Skills de Código)
- O agente incorpora os resultados em sua resposta ao usuário
O agente IA decide quando usar skills com base nas descrições das skills. Escreva descrições claras para que a IA saiba quando cada skill é relevante.
Melhores Práticas
Para Todas as Skills
- Escreva descrições claras: A descrição diz à IA quando usar a skill—seja específico
- Mantenha skills focadas: Cada skill deve fazer uma coisa bem
- Use nomes descritivos:
obter_politica_devolucaoé melhor quepolitica
Para Skills de Código
- Use context para identidade: Nunca peça à IA para fornecer dados de contato como parâmetros—use a tabela
context - Valide parâmetros: Trate valores de
argscomo entrada não confiável - Mantenha execução rápida: Skills devem completar rapidamente para manter o fluxo da conversa
- Trate erros graciosamente: Retorne informações de erro significativas em vez de falhar silenciosamente
Para Skills de Conhecimento
- Mantenha conteúdo atualizado: Revise e atualize o conteúdo de conhecimento regularmente
- Estruture para clareza: Use formatação markdown para tornar o conteúdo fácil de ler
- Seja abrangente: Inclua todas as informações relevantes que a IA pode precisar
Solução de Problemas
Skill Não Está Sendo Chamada
- Verifique se a skill está anexada ao card do Agente IA
- Verifique se a descrição explica claramente quando usar a skill
- Revise o prompt do sistema do agente IA para instruções conflitantes
Problemas com Skills de Código
Erros de parsing de parâmetros:
- Certifique-se de que as anotações LDoc usam sintaxe correta:
-- @param nome (tipo): Descrição - Verifique se os tipos correspondem ao que o agente IA está fornecendo
Dados de contexto ausentes:
- Verifique se você está acessando o caminho correto do contexto (ex:
context.contact.name) - Lembre-se de que alguns campos de contexto podem ser nil
Resultados inesperados:
- Retorne valores intermediários no objeto de resultado para debugging
- Verifique os valores dos parâmetros antes de usá-los
- Use
turn.logger.info()para rastrear a execução (logs aparecem nos logs da jornada)