> For the complete documentation index, see [llms.txt](https://docs.salescaling.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.salescaling.com/guias-practicas/agentes-de-voz-ia/tools-agentes-voz.md).

# Tools (Herramientas) para Agentes de Voz

> ⚠️ **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.

## Introducción

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.

### Beneficios Principales

* 🔧 **Extensibilidad**: Conecta tu agente con cualquier sistema externo
* 🤖 **Automatización inteligente**: El agente decide cuándo usar cada tool
* 🔄 **Integración en tiempo real**: Obtén datos actualizados durante la conversación
* 🎯 **Personalización**: Crea tools específicas para tu negocio
* 📊 **Trazabilidad**: Registra todas las llamadas a tools para auditoría

## ¿Qué es una Tool?

Una **Tool** es una función que tu agente de voz puede llamar durante una conversación para:

1. **Obtener información** de sistemas externos (bases de datos, APIs, CRM)
2. **Realizar acciones** (crear registros, enviar emails, actualizar datos)
3. **Tomar decisiones** basadas en datos en tiempo real

### Cómo Funciona

```
┌─────────────┐      ┌──────────────┐      ┌─────────────┐
│   Cliente   │ ───> │ Agente de Voz│ ───> │  Tu Webhook │
│   (Llamada) │      │   (Decide)   │      │  (Tool)     │
└─────────────┘      └──────────────┘      └─────────────┘
                            │                      │
                            │  <─── Respuesta ─────┘
                            │
                            ▼
                     Continúa conversación
                     con la información
```

**Flujo detallado:**

1. **El cliente habla**: "¿Tienen disponibilidad para el martes a las 3pm?"
2. **El agente analiza**: Detecta que necesita consultar disponibilidad
3. **Llama a tu tool**: Envía una petición HTTP a tu webhook con los parámetros
4. **Tu sistema responde**: Devuelve la información solicitada
5. **El agente continúa**: "Sí, tenemos disponibilidad el martes a las 3pm. ¿Te gustaría agendar?"

## Tipos de Tools

### Tools de Sistema (SYSTEM)

Son tools predefinidas por Salescaling que están disponibles para todos los agentes:

* 🗓️ **Calendar Scheduler**: Agenda reuniones en calendarios integrados
* 📧 **Email Sender**: Envía emails automáticos
* 📝 **Note Creator**: Crea notas en el CRM

> ℹ️ **Nota**: Las tools de sistema **no pueden ser editadas ni eliminadas**. Solo puedes visualizar su configuración.

### Tools de Usuario (USER)

Son tools personalizadas que tú creas para tu caso de uso específico:

* 🔍 **Consultar disponibilidad de productos**
* 💰 **Verificar precios en tiempo real**
* 👤 **Buscar información de cliente en CRM**
* 📦 **Comprobar estado de pedidos**
* ✅ **Validar códigos promocionales**
* 🎫 **Reservar tickets o servicios**

## Crear una Tool

### Paso 1: Navegar a Tools

1. Ve a **Agentes de Voz** en el menú principal
2. Haz clic en la pestaña **Tools**
3. Haz clic en **"Create tool"**

### Paso 2: Configuración Básica

#### Nombre

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.

#### Descripció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:**

* Sé específico sobre qué hace la tool
* Menciona qué información necesita (parámetros)
* Indica qué información devuelve
* Usa un lenguaje claro y directo
* Escribe en español (el agente entiende ambos idiomas)

### Paso 3: Configurar el Webhook

#### URL del Webhook

La URL de tu endpoint que recibirá las llamadas:

```
https://api.tuempresa.com/tools/check-availability
```

**Requisitos:**

* ✅ Debe ser HTTPS (seguro)
* ✅ Debe estar accesible públicamente
* ✅ Debe responder en menos de 10 segundos
* ✅ Debe devolver JSON válido

#### Método HTTP

Selecciona el método apropiado:

* **GET**: Para consultar información sin modificar datos
* **POST**: Para crear o modificar datos (recomendado)
* **PUT**: Para actualizar recursos existentes
* **PATCH**: Para actualizaciones parciales
* **DELETE**: Para eliminar recursos

> 💡 **Recomendación**: Usa POST para la mayoría de tools, ya que permite enviar parámetros complejos en el body.

#### Secret del Webhook (Opcional)

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:**

```javascript
// 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...
});
```

### Paso 4: Definir Input Schema

El **Input Schema** define qué parámetros enviará el agente a tu webhook.

#### Ejemplo: Tool de Disponibilidad de Productos

**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:**

```json
{
  "product_id": "PROD-12345",
  "quantity": 2,
  "location": "Madrid"
}
```

#### Tipos de Datos Soportados

* **string**: Texto (nombres, IDs, descripciones)
* **number**: Números (cantidades, precios, IDs numéricos)

> ℹ️ **Nota**: Próximamente se añadirán más tipos (boolean, array, object).

#### Mejores Prácticas

* ✅ Usa nombres descriptivos en inglés (snake\_case)
* ✅ Añade descripciones claras a cada propiedad
* ✅ Solo incluye parámetros necesarios
* ✅ Considera qué información puede extraer el agente de la conversación

### Paso 5: Definir Output Schema (Opcional)

El **Output Schema** define qué información devolverá tu webhook al agente.

#### ¿Es Obligatorio?

**No**, pero es **altamente recomendado** porque:

* 📊 Documenta qué devuelve tu tool
* 🤖 Ayuda al agente a entender la respuesta
* 🔍 Facilita el debugging
* ✅ Valida que la respuesta sea correcta

#### Ejemplo: Respuesta de Disponibilidad

**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:**

```json
{
  "available": "yes",
  "quantity": 15,
  "delivery_days": 2,
  "message": "Tenemos 15 unidades disponibles con entrega en 2 días"
}
```

## Implementar el Webhook

### Estructura de la Petición

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: Salescaling-VoiceAgent/1.0
```

**Body:**

```json
{
  "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"
  }
}
```

### Ejemplo de Implementación

#### Node.js (Express)

```javascript
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');
});
```

#### Python (Flask)

```python
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)
```

### Manejo de Errores

Tu webhook debe manejar errores gracefully:

```javascript
// ✅ 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.

## Asignar Tools a Agentes

Una vez creada la tool, debes asignarla a los agentes que la usarán:

### Paso 1: Editar el Agente

1. Ve a **Agentes de Voz** > **Agents**
2. Haz clic en el agente que quieres editar
3. Busca la sección **"Tools"**

### Paso 2: Seleccionar Tools

1. Haz clic en **"Add tool"**
2. Selecciona las tools que quieres habilitar
3. Guarda los cambios

### Paso 3: Actualizar el Prompt (Importante)

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.

## Ejemplos de Uso

### Ejemplo 1: Verificar Disponibilidad de Producto

**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:**

```json
{
  "tool_name": "check_product_availability",
  "parameters": {
    "product_id": "IPHONE-15-PRO",
    "quantity": 1
  }
}
```

**Respuesta:**

```json
{
  "available": "yes",
  "quantity": 8,
  "delivery_days": 1,
  "message": "Tenemos 8 unidades disponibles con entrega mañana"
}
```

***

### Ejemplo 2: Agendar Reunión

**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:**

```json
{
  "tool_name": "schedule_meeting",
  "parameters": {
    "date": "2024-01-15",
    "time": "15:00",
    "type": "demo",
    "customer_email": "cliente@example.com"
  }
}
```

**Respuesta:**

```json
{
  "success": "yes",
  "meeting_id": "MTG-789",
  "calendar_link": "https://calendar.google.com/...",
  "message": "Reunión agendada exitosamente"
}
```

***

### Ejemplo 3: Validar Código Promocional

**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:**

```json
{
  "tool_name": "validate_promo_code",
  "parameters": {
    "code": "VERANO2024",
    "customer_id": "CUST-456"
  }
}
```

**Respuesta:**

```json
{
  "valid": "yes",
  "discount_percent": 20,
  "expires_at": "2024-08-31",
  "message": "Código válido: 20% de descuento hasta el 31 de agosto"
}
```

## Testing y Debugging

### Probar tu Tool

1. **Crea una llamada de prueba**:
   * Ve a tu agente
   * Haz clic en "Nueva llamada"
   * Usa tu propio número para probar
2. **Menciona el caso de uso**:
   * Di algo que active la tool
   * Ejemplo: "¿Tienen el producto XYZ disponible?"
3. **Revisa los logs**:
   * Ve a la conversación completada
   * Busca la sección "Tool Calls"
   * Verifica la petición y respuesta

### Logs de Tool Calls

Cada llamada a una tool se registra con:

* ⏰ **Timestamp**: Cuándo se llamó
* 📤 **Request**: Qué parámetros se enviaron
* 📥 **Response**: Qué devolvió tu webhook
* ⏱️ **Duration**: Cuánto tardó
* ✅/❌ **Status**: Si fue exitosa o falló

### Debugging Común

#### Error: "Tool call timeout"

**Causa**: Tu webhook tardó más de 10 segundos en responder.

**Solución**:

* Optimiza las consultas a base de datos
* Usa caché para datos frecuentes
* Considera respuestas asíncronas

#### Error: "Invalid JSON response"

**Causa**: Tu webhook no devolvió JSON válido.

**Solución**:

```javascript
// ✅ Correcto
return res.json({ available: 'yes' });

// ❌ Incorrecto
return res.send('yes');
```

#### Error: "Webhook unreachable"

**Causa**: Tu webhook no es accesible públicamente.

**Solución**:

* Verifica que la URL sea correcta
* Asegúrate de que tu servidor esté corriendo
* Comprueba el firewall y reglas de seguridad
* Usa HTTPS, no HTTP

#### El agente no llama a la tool

**Causa**: El prompt no es claro sobre cuándo usar la tool.

**Solución**:

* Actualiza el prompt con instrucciones explícitas
* Menciona la tool por nombre en el prompt
* Da ejemplos de cuándo usarla

## Mejores Prácticas

### ✅ Hacer

* **Respuestas rápidas**: Optimiza para responder en < 2 segundos
* **Mensajes claros**: Devuelve mensajes que el agente pueda usar directamente
* **Manejo de errores**: Siempre devuelve una respuesta útil, incluso en errores
* **Validación**: Valida los parámetros antes de procesarlos
* **Logging**: Registra todas las llamadas para debugging
* **Idempotencia**: Las mismas entradas deben dar las mismas salidas
* **Documentación**: Documenta qué hace cada tool y cómo usarla

### ❌ Evitar

* **Timeouts largos**: No hagas consultas que tarden > 10 segundos
* **Respuestas técnicas**: No devuelvas mensajes de error técnicos
* **Datos sensibles**: No incluyas información confidencial en respuestas
* **Side effects no documentados**: No hagas acciones no descritas en la tool
* **Dependencias externas**: Minimiza llamadas a APIs externas lentas
* **Respuestas ambiguas**: Sé específico en tus respuestas

## Seguridad

### Autenticación

Siempre valida el webhook secret:

```javascript
const secret = req.headers['x-webhook-secret'];
if (secret !== process.env.WEBHOOK_SECRET) {
  return res.status(401).json({ error: 'Unauthorized' });
}
```

### Validación de Datos

Valida todos los parámetros recibidos:

```javascript
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'
  });
}
```

### Rate Limiting

Implementa rate limiting para prevenir abuso:

```javascript
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);
```

### HTTPS Obligatorio

Siempre usa HTTPS para tus webhooks:

```
✅ https://api.tuempresa.com/tools/...
❌ http://api.tuempresa.com/tools/...
```

## Limitaciones Actuales

Como esta funcionalidad está en **fase beta**, ten en cuenta:

* ⚠️ **Timeout**: Las tools deben responder en < 10 segundos
* 🔢 **Tipos de datos**: Solo string y number (más tipos próximamente)
* 📊 **Llamadas por conversación**: Máximo 10 tool calls por conversación
* 🌍 **Idiomas**: Optimizado para español e inglés
* 📝 **Schemas complejos**: Arrays y objetos anidados próximamente

## Preguntas Frecuentes

<details>

<summary>¿Cuántas tools puedo crear?</summary>

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.

</details>

<details>

<summary>¿Puedo editar una tool después de crearla?</summary>

Sí, puedes editar cualquier tool de tipo USER. Las tools de tipo SYSTEM no pueden ser editadas.

</details>

<details>

<summary>¿Qué pasa si mi webhook está caído?</summary>

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.

</details>

<details>

<summary>¿Puedo usar la misma tool en múltiples agentes?</summary>

Sí, puedes asignar la misma tool a múltiples agentes. Esto es útil para tools genéricas como verificación de disponibilidad.

</details>

<details>

<summary>¿Cómo sé cuántas veces se ha llamado a mi tool?</summary>

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.

</details>

<details>

<summary>¿Puedo pasar contexto adicional a mi webhook?</summary>

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.

</details>

<details>

<summary>¿Qué pasa si devuelvo un formato incorrecto?</summary>

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.

</details>

<details>

<summary>¿Puedo hacer que una tool llame a otra tool?</summary>

No directamente. Cada tool es independiente. Si necesitas encadenar acciones, debes hacerlo en tu webhook antes de devolver la respuesta.

</details>

<details>

<summary>¿Cómo puedo probar mi webhook localmente?</summary>

Puedes usar herramientas como [ngrok](https://ngrok.com/) para exponer tu servidor local con una URL pública temporal:

```bash
ngrok http 3000
# Usa la URL https://xxxx.ngrok.io en tu tool
```

</details>

<details>

<summary>¿Las tools funcionan en todos los idiomas?</summary>

Sí, las tools funcionan independientemente del idioma del agente. Los parámetros se extraen de la conversación en cualquier idioma soportado.

</details>

## Soporte

Si necesitas ayuda con las Tools:

* 📧 **Email**: <support@salescaling.com>
* 💬 **Chat en vivo**: Disponible en la plataforma
* 📚 **Documentación**: [docs.salescaling.com](https://docs.salescaling.com)
* 🔗 **API Reference**: [API de Webhooks](/api/webhooks.md)

### Recursos Relacionados

* [Agentes de Voz de IA](/guias-practicas/agentes-de-voz-ia.md)
* [API de Webhooks](/api/webhooks.md)
* [Gestión de Blacklist](/guias-practicas/gestion-de-blacklist.md)

***


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.salescaling.com/guias-practicas/agentes-de-voz-ia/tools-agentes-voz.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
