Tools para agentes de voz
Herramientas que un agente de voz puede invocar durante una llamada (calendario, email, reprogramar, transferir).
Herramientas que un agente de voz puede invocar durante una llamada (calendario, email, reprogramar, transferir).
En Mitto activas las tools en la ficha del agente (Durante la llamada) y eliges cuáles puede usar cada fase del Guion. La interfaz de Mitto expone las herramientas estándar de campaña; las tools webhook personalizadas descritas más abajo aplican a despliegues avanzados o integraciones gestionadas con soporte.
⚠️ Funcionalidad en Fase Beta
Las Tools para Agentes de Voz están actualmente en fase beta. Si estás interesado en probar esta funcionalidad, contacta con nuestro equipo de soporte.
Las Tools (herramientas) son extensiones que permiten a tus agentes de voz realizar acciones durante las conversaciones, como consultar bases de datos, agendar reuniones, actualizar CRM, verificar disponibilidad de productos, y mucho más.
Una Tool es una función que tu agente de voz puede llamar durante una conversación para:
┌─────────────┐ ┌──────────────┐ ┌─────────────┐
│ Cliente │ ───> │ Agente de Voz│ ───> │ Tu Webhook │
│ (Llamada) │ │ (Decide) │ │ (Tool) │
└─────────────┘ └──────────────┘ └─────────────┘
│ │
│ <─── Respuesta ─────┘
│
▼
Continúa conversación
con la información
Flujo detallado:
Son tools predefinidas por la plataforma Recordari, disponibles para los agentes de voz en Mitto:
ℹ️ Nota: Las tools de sistema no pueden ser editadas ni eliminadas. Solo puedes visualizar su configuración.
Son tools personalizadas que tú creas para tu caso de uso específico:
El nombre debe ser descriptivo y en inglés (snake_case):
✅ Correcto:
- check_product_availability
- get_customer_info
- schedule_meeting
❌ Incorrecto:
- tool1
- mi herramienta
- Check Product
💡 Tip: El nombre se usa internamente. Usa nombres claros que describan la acción.
La descripción es crucial porque el agente la usa para decidir cuándo llamar a la tool.
✅ Buena descripción:
"Verifica la disponibilidad de un producto específico en el inventario.
Devuelve si hay stock, la cantidad disponible y el tiempo estimado de entrega."
❌ Mala descripción:
"Consulta productos"
Mejores prácticas para descripciones:
La URL de tu endpoint que recibirá las llamadas:
https://api.tuempresa.com/tools/check-availability
Requisitos:
Selecciona el método apropiado:
💡 Recomendación: Usa POST para la mayoría de tools, ya que permite enviar parámetros complejos en el body.
Un secreto que se enviará en el header X-Webhook-Secret para autenticar las peticiones:
X-Webhook-Secret: tu_secreto_super_seguro_123
Uso recomendado:
// En tu webhook
app.post('/tools/check-availability', (req, res) => {
const secret = req.headers['x-webhook-secret'];
if (secret !== process.env.WEBHOOK_SECRET) {
return res.status(401).json({ error: 'Unauthorized' });
}
// Procesar la petición...
});
El Input Schema define qué parámetros enviará el agente a tu webhook.
Propiedades del Input Schema:
| Nombre | Tipo | Descripción |
|---|---|---|
product_id | string | ID del producto a consultar |
quantity | number | Cantidad deseada |
location | string | Ubicación del cliente (opcional) |
Petición que recibirás:
{
"product_id": "PROD-12345",
"quantity": 2,
"location": "Madrid"
}
ℹ️ Nota: Próximamente se añadirán más tipos (boolean, array, object).
El Output Schema define qué información devolverá tu webhook al agente.
No, pero es altamente recomendado porque:
Propiedades del Output Schema:
| Nombre | Tipo | Descripción |
|---|---|---|
available | string | "yes" o "no" |
quantity | number | Cantidad disponible |
delivery_days | number | Días hasta la entrega |
message | string | Mensaje para el cliente |
Respuesta que debes devolver:
{
"available": "yes",
"quantity": 15,
"delivery_days": 2,
"message": "Tenemos 15 unidades disponibles con entrega en 2 días"
}
Cuando el agente llama a tu tool, envía una petición con esta estructura:
Headers:
Content-Type: application/json
X-Webhook-Secret: tu_secreto (si lo configuraste)
User-Agent: Recordari-VoiceAgent/1.0
Body:
{
"tool_name": "check_product_availability",
"call_id": "call_abc123",
"agent_id": "agent_xyz789",
"parameters": {
"product_id": "PROD-12345",
"quantity": 2,
"location": "Madrid"
},
"context": {
"customer_phone": "+34612345678",
"conversation_id": "conv_456"
}
}
const express = require('express');
const app = express();
app.use(express.json());
app.post('/tools/check-availability', async (req, res) => {
try {
// 1. Validar el secret
const secret = req.headers['x-webhook-secret'];
if (secret !== process.env.WEBHOOK_SECRET) {
return res.status(401).json({ error: 'Unauthorized' });
}
// 2. Extraer parámetros
const { product_id, quantity, location } = req.body.parameters;
// 3. Consultar tu base de datos
const product = await db.products.findOne({ id: product_id });
if (!product) {
return res.json({
available: 'no',
quantity: 0,
delivery_days: 0,
message: 'Producto no encontrado'
});
}
// 4. Verificar disponibilidad
const available = product.stock >= quantity;
const deliveryDays = calculateDeliveryDays(location);
// 5. Devolver respuesta
return res.json({
available: available ? 'yes' : 'no',
quantity: product.stock,
delivery_days: deliveryDays,
message: available
? `Tenemos ${product.stock} unidades disponibles`
: `Solo tenemos ${product.stock} unidades disponibles`
});
} catch (error) {
console.error('Error:', error);
return res.status(500).json({
error: 'Internal server error',
message: 'No pudimos verificar la disponibilidad'
});
}
});
app.listen(3000, () => {
console.log('Webhook listening on port 3000');
});
from flask import Flask, request, jsonify
import os
app = Flask(__name__)
@app.route('/tools/check-availability', methods=['POST'])
def check_availability():
try:
# 1. Validar el secret
secret = request.headers.get('X-Webhook-Secret')
if secret != os.getenv('WEBHOOK_SECRET'):
return jsonify({'error': 'Unauthorized'}), 401
# 2. Extraer parámetros
data = request.get_json()
product_id = data['parameters']['product_id']
quantity = data['parameters']['quantity']
location = data['parameters'].get('location', 'España')
# 3. Consultar base de datos
product = db.get_product(product_id)
if not product:
return jsonify({
'available': 'no',
'quantity': 0,
'delivery_days': 0,
'message': 'Producto no encontrado'
})
# 4. Verificar disponibilidad
available = product['stock'] >= quantity
delivery_days = calculate_delivery_days(location)
# 5. Devolver respuesta
return jsonify({
'available': 'yes' if available else 'no',
'quantity': product['stock'],
'delivery_days': delivery_days,
'message': f"Tenemos {product['stock']} unidades disponibles"
})
except Exception as e:
print(f'Error: {e}')
return jsonify({
'error': 'Internal server error',
'message': 'No pudimos verificar la disponibilidad'
}), 500
if __name__ == '__main__':
app.run(port=3000)
Tu webhook debe manejar errores gracefully:
// ✅ Buena práctica
return res.status(200).json({
available: 'no',
quantity: 0,
delivery_days: 0,
message: 'No pudimos verificar la disponibilidad en este momento. ¿Puedo ayudarte con algo más?'
});
// ❌ Mala práctica
return res.status(500).json({ error: 'Database error' });
// Esto hará que el agente no sepa qué decir al cliente
Regla de oro: Siempre devuelve un status 200 con un mensaje útil para el cliente, incluso cuando hay errores internos.
Una vez creada la tool, debes asignarla a los agentes que la usarán:
Debes actualizar el prompt del agente para que sepa cuándo usar cada tool:
Eres un asistente de ventas de una tienda de electrónica.
TOOLS DISPONIBLES:
- check_product_availability: Usa esta tool cuando el cliente pregunte
si un producto está disponible o cuántas unidades hay en stock.
- get_customer_info: Usa esta tool cuando necesites información del
cliente (historial de compras, dirección, etc.)
INSTRUCCIONES:
- Cuando el cliente mencione un producto, usa check_product_availability
para verificar el stock antes de confirmar.
- Si el cliente es recurrente, usa get_customer_info para personalizar
la conversación.
- Siempre confirma la información antes de finalizar la venta.
💡 Tip: Sé explícito sobre cuándo y cómo usar cada tool. El agente seguirá tus instrucciones.
Conversación:
Cliente: "Hola, ¿tienen el iPhone 15 Pro en stock?"
Agente: [Llama a check_product_availability]
Agente: "Sí, tenemos 8 unidades del iPhone 15 Pro disponibles.
¿En qué color lo prefieres?"
Tool Call:
{
"tool_name": "check_product_availability",
"parameters": {
"product_id": "IPHONE-15-PRO",
"quantity": 1
}
}
Respuesta:
{
"available": "yes",
"quantity": 8,
"delivery_days": 1,
"message": "Tenemos 8 unidades disponibles con entrega mañana"
}
Conversación:
Cliente: "Me gustaría agendar una demo para el martes a las 3pm"
Agente: [Llama a schedule_meeting]
Agente: "Perfecto, he agendado tu demo para el martes 15 de enero
a las 3pm. Te enviaré un email de confirmación."
Tool Call:
{
"tool_name": "schedule_meeting",
"parameters": {
"date": "2024-01-15",
"time": "15:00",
"type": "demo",
"customer_email": "cliente@example.com"
}
}
Respuesta:
{
"success": "yes",
"meeting_id": "MTG-789",
"calendar_link": "https://calendar.google.com/...",
"message": "Reunión agendada exitosamente"
}
Conversación:
Cliente: "Tengo un código de descuento: VERANO2024"
Agente: [Llama a validate_promo_code]
Agente: "¡Genial! Tu código VERANO2024 te da un 20% de descuento
en toda la tienda. ¿Qué te gustaría comprar?"
Tool Call:
{
"tool_name": "validate_promo_code",
"parameters": {
"code": "VERANO2024",
"customer_id": "CUST-456"
}
}
Respuesta:
{
"valid": "yes",
"discount_percent": 20,
"expires_at": "2024-08-31",
"message": "Código válido: 20% de descuento hasta el 31 de agosto"
}
Crea una llamada de prueba:
Menciona el caso de uso:
Revisa los logs:
Cada llamada a una tool se registra con:
Causa: Tu webhook tardó más de 10 segundos en responder.
Solución:
Causa: Tu webhook no devolvió JSON válido.
Solución:
// ✅ Correcto
return res.json({ available: 'yes' });
// ❌ Incorrecto
return res.send('yes');
Causa: Tu webhook no es accesible públicamente.
Solución:
Causa: El prompt no es claro sobre cuándo usar la tool.
Solución:
Siempre valida el webhook secret:
const secret = req.headers['x-webhook-secret'];
if (secret !== process.env.WEBHOOK_SECRET) {
return res.status(401).json({ error: 'Unauthorized' });
}
Valida todos los parámetros recibidos:
const { product_id, quantity } = req.body.parameters;
if (!product_id || typeof product_id !== 'string') {
return res.json({
available: 'no',
message: 'ID de producto inválido'
});
}
if (!quantity || quantity < 1) {
return res.json({
available: 'no',
message: 'Cantidad inválida'
});
}
Implementa rate limiting para prevenir abuso:
const rateLimit = require('express-rate-limit');
const limiter = rateLimit({
windowMs: 1 * 60 * 1000, // 1 minuto
max: 100 // máximo 100 peticiones por minuto
});
app.use('/tools/', limiter);
Siempre usa HTTPS para tus webhooks:
✅ https://api.tuempresa.com/tools/...
❌ http://api.tuempresa.com/tools/...
Como esta funcionalidad está en fase beta, ten en cuenta:
No hay límite en el número de tools que puedes crear. Sin embargo, recomendamos mantener un número manejable (5-10) para facilitar el mantenimiento.
Sí, puedes editar cualquier tool de tipo USER. Las tools de tipo SYSTEM no pueden ser editadas.
Si tu webhook no responde, el agente continuará la conversación sin la información de la tool y le dirá al cliente que no pudo verificar la información en ese momento.
Sí, puedes asignar la misma tool a múltiples agentes. Esto es útil para tools genéricas como verificación de disponibilidad.
Puedes ver las estadísticas de uso de cada tool en la página de Tools. También puedes revisar los logs de cada conversación individual.
Sí, cada llamada incluye un objeto context con información de la llamada (call_id, agent_id, customer_phone, etc.) que puedes usar para logging o personalización.
Si tu respuesta no coincide con el output schema definido, el agente intentará interpretar la respuesta de la mejor manera posible. Sin embargo, es recomendable siempre seguir el schema definido.
No directamente. Cada tool es independiente. Si necesitas encadenar acciones, debes hacerlo en tu webhook antes de devolver la respuesta.
Puedes usar herramientas como ngrok para exponer tu servidor local con una URL pública temporal:
ngrok http 3000
# Usa la URL https://xxxx.ngrok.io en tu tool
Sí, las tools funcionan independientemente del idioma del agente. Los parámetros se extraen de la conversación en cualquier idioma soportado.
Si necesitas ayuda con las Tools: