Integra tu propio modelo

Conecta un agente a tu propio LLM o aloja tu propio servidor.

Custom LLM te permite conectar tus conversaciones a tu propio LLM mediante una ruta externa. ElevenLabs también admite LLM integrados de forma nativa

Los LLM personalizados te permiten usar tu propia clave de API de OpenAI o ejecutar un servidor de LLM totalmente personalizado.

Descripción general

De forma predeterminada, usamos nuestras propias credenciales internas para modelos populares como OpenAI. Para usar un servidor de LLM personalizado, debe ajustarse a una de las siguientes estructuras de solicitud/respuesta compatibles con OpenAI:

La API Responses es el formato de API más reciente de OpenAI y admite funciones adicionales. Ambos formatos de API son totalmente compatibles con la integración de LLM personalizados.

Las siguientes guías abarcan ambos casos de uso:

  1. Usa tu propia clave de OpenAI: utiliza tu propia clave de API de OpenAI con nuestra plataforma.
  2. Servidor de LLM personalizado: aloja y conecta tu propia implementación de servidor de LLM.

Aprenderás a:

  • Guardar tu clave de API de OpenAI en ElevenLabs
  • Alojar un servidor que reproduzca la ruta de Chat Completions o Responses de OpenAI
  • Dirigir ElevenLabs a tu ruta personalizada
  • Enviar parámetros adicionales a tu LLM cuando sea necesario

Resumen del razonamiento

Tu ruta debe devolver el razonamiento separado de la respuesta final. ElevenLabs no genera el razonamiento a partir de la respuesta final.

Para solicitar razonamiento a una ruta compatible, activa Resumen del razonamiento en la configuración de LLM del agente o establece enable_reasoning_summary mediante la API.

Devolver el razonamiento

Usa el formato que corresponda a tu ruta:

Transmite el razonamiento en el campo reasoning o reasoning_content de cada delta de respuesta.

Para rutas compatibles con Gemini, ElevenLabs solicita pensamientos con google.thinking_config.include_thoughts y lee el contenido marcado con extra_content.google.thought.

Consulta Resumen del razonamiento para conocer el almacenamiento, la entrega y las limitaciones.

Usar tu propia clave de OpenAI

Para integrar una clave de OpenAI personalizada, actualiza la configuración de tu agente en el panel de ElevenLabs para que apunte a tu servidor de LLM personalizado y crea un secreto que contenga tu OPENAI_API_KEY:

1

En la configuración de tu agente del panel de ElevenLabs, selecciona “Custom LLM” en el menú desplegable “LLM” de la derecha.

Añadir secreto

2

Haz clic en el campo situado bajo “LLM” y desplázate hacia abajo para seleccionar “Custom LLM”.

3

Introduce la URL del servidor y el ID del modelo de tu servidor de LLM personalizado.

Introducir URL

4

Haz clic en el menú desplegable bajo “API key” y selecciona “Create new secret”. Asigna a la clave el nombre OPENAI_API_KEY, añádela al campo “value” y haz clic en “Add secret”.

5

Haz clic en el botón “x” para cerrar el modal de LLM y en “Publish” para guardar los cambios.

Servidor de LLM personalizado

Para usar un servidor de LLM personalizado, configura una ruta de servidor compatible siguiendo el estilo de OpenAI. Puedes implementar la API Chat Completions (/v1/chat/completions) o la API Responses (/v1/responses).

Ambas rutas deben devolver respuestas en formato SSE (eventos enviados por el servidor) con Content-Type: text/event-stream.

La API Chat Completions usa la ruta /v1/chat/completions.

Cada fragmento debe tener el formato data: {json}\n\n y el stream debe terminar con data: [DONE]\n\n.

Este es un ejemplo de implementación de servidor:

import json
import os
import fastapi
from fastapi.responses import StreamingResponse
from openai import AsyncOpenAI
import uvicorn
import logging
from dotenv import load_dotenv
from pydantic import BaseModel
from typing import List, Optional
# Load environment variables from .env file
load_dotenv()
# Retrieve API key from environment
OPENAI_API_KEY = os.getenv('OPENAI_API_KEY')
if not OPENAI_API_KEY:
raise ValueError("OPENAI_API_KEY not found in environment variables")
app = fastapi.FastAPI()
oai_client = AsyncOpenAI(api_key=OPENAI_API_KEY)
class Message(BaseModel):
role: str
content: str
class ChatCompletionRequest(BaseModel):
messages: List[Message]
model: str
temperature: Optional[float] = 0.7
max_tokens: Optional[int] = None
stream: Optional[bool] = False
user_id: Optional[str] = None
@app.post("/v1/chat/completions")
async def create_chat_completion(request: ChatCompletionRequest) -> StreamingResponse:
oai_request = request.dict(exclude_none=True)
if "user_id" in oai_request:
oai_request["user"] = oai_request.pop("user_id")
chat_completion_coroutine = await oai_client.chat.completions.create(**oai_request)
async def event_stream():
try:
async for chunk in chat_completion_coroutine:
# Convert the ChatCompletionChunk to a dictionary before JSON serialization
chunk_dict = chunk.model_dump()
yield f"data: {json.dumps(chunk_dict)}\n\n"
yield "data: [DONE]\n\n"
except Exception as e:
logging.error("An error occurred: %s", str(e))
yield f"data: {json.dumps({'error': 'Internal error occurred!'})}\n\n"
return StreamingResponse(event_stream(), media_type="text/event-stream")
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=8013)

Ejecuta este código o el código de tu propio servidor.

Configurar una URL pública para tu servidor

Para que tu servidor sea accesible, crea una URL pública con una herramienta de tunelización como ngrok:

ngrok http --url=<Your url>.ngrok.app 8013

Configurar CustomLLM de ElevenLabs

A continuación, actualiza la configuración de tu agente en el panel de ElevenLabs para que apunte a tu servidor de LLM personalizado.

Dirige la URL de tu servidor a la ruta de ngrok y establece “Limit token usage” en 5000.

Ahora puedes empezar a interactuar con tu agente usando tu propio servidor de LLM.

Optimización para LLM con procesamiento lento

Si tu LLM personalizado tiene tiempos de procesamiento lentos (quizá debido al razonamiento agéntico o a requisitos de preprocesamiento), puedes mejorar el flujo de la conversación implementando palabras de espera en tus respuestas de streaming. Esta técnica ayuda a mantener una prosodia natural mientras tu LLM genera la respuesta completa.

Palabras de espera

Cuando tu LLM necesite más tiempo para procesar la respuesta completa, devuelve una respuesta inicial que termine con "... " (puntos suspensivos seguidos de un espacio). Esto permite que el sistema de Texto a Voz mantenga un flujo natural y que la conversación siga siendo dinámica. Esto crea pausas naturales que enlazan bien con el contenido posterior sobre el que el LLM puede razonar durante más tiempo. El espacio adicional es fundamental para garantizar que el contenido posterior no se añada a ”…”, lo que puede provocar distorsiones de audio.

Implementación

Así puedes modificar tu servidor de LLM personalizado para implementar palabras de espera:

@app.post("/v1/chat/completions")
async def create_chat_completion(request: ChatCompletionRequest) -> StreamingResponse:
oai_request = request.dict(exclude_none=True)
if "user_id" in oai_request:
oai_request["user"] = oai_request.pop("user_id")
async def event_stream():
try:
# Send initial buffer chunk while processing
initial_chunk = {
"id": "chatcmpl-buffer",
"object": "chat.completion.chunk",
"created": 1234567890,
"model": request.model,
"choices": [{
"delta": {"content": "Let me think about that... "},
"index": 0,
"finish_reason": None
}]
}
yield f"data: {json.dumps(initial_chunk)}\n\n"
# Process the actual LLM response
chat_completion_coroutine = await oai_client.chat.completions.create(**oai_request)
async for chunk in chat_completion_coroutine:
chunk_dict = chunk.model_dump()
yield f"data: {json.dumps(chunk_dict)}\n\n"
yield "data: [DONE]\n\n"
except Exception as e:
logging.error("An error occurred: %s", str(e))
yield f"data: {json.dumps({'error': 'Internal error occurred!'})}\n\n"
return StreamingResponse(event_stream(), media_type="text/event-stream")

Integración de herramientas del sistema

Tu LLM personalizado puede activar herramientas del sistema para controlar el flujo y el estado de la conversación. Estas herramientas se incluyen automáticamente en el parámetro tools de tus solicitudes de finalización de chat cuando se configuran en tu agente.

Cómo funcionan las herramientas del sistema

  1. Decisión del LLM: Tu LLM personalizado decide cuándo llamar a estas herramientas según el contexto de la conversación
  2. Respuesta de la herramienta: El LLM responde con llamadas a funciones en el formato estándar de OpenAI
  3. Procesamiento del backend: ElevenLabs procesa las llamadas a herramientas y actualiza el estado de la conversación

Para obtener más información sobre las herramientas del sistema, consulta nuestra guía

Herramientas del sistema disponibles

Objetivo: Finalizar automáticamente conversaciones cuando se cumplan las condiciones adecuadas.

Condiciones de activación: El LLM debe llamar a esta herramienta cuando:

  • Se haya completado la tarea principal y el usuario esté satisfecho
  • La conversación haya llegado a una conclusión natural de mutuo acuerdo
  • El usuario indique explícitamente que quiere finalizar la conversación

Parámetros:

  • reason (cadena, obligatorio): El motivo para finalizar la llamada
  • message (cadena, opcional): Un mensaje de despedida para enviar al usuario antes de finalizar la llamada

Formato de llamada a función:

{
"type": "function",
"function": {
"name": "end_call",
"arguments": "{\"reason\": \"Task completed successfully\", \"message\": \"Thank you for using our service. Have a great day!\"}"
}
}

Implementación: Configúrala como una herramienta del sistema en los ajustes de tu agente. El LLM recibirá instrucciones detalladas sobre cuándo llamar a esta función.

Más información: Herramienta para finalizar llamadas

Objetivo: Cambiar automáticamente al idioma detectado del usuario durante las conversaciones.

Condiciones de activación: El LLM debe llamar a esta herramienta cuando:

  • El usuario hable en un idioma distinto al idioma actual de la conversación
  • El usuario solicite explícitamente cambiar de idioma
  • La conversación necesite compatibilidad con varios idiomas

Parámetros:

  • reason (cadena, obligatorio): El motivo del cambio de idioma
  • language (cadena, obligatorio): El código de idioma al que cambiar (debe estar en la lista de idiomas compatibles)

Formato de llamada a función:

{
"type": "function",
"function": {
"name": "language_detection",
"arguments": "{\"reason\": \"User requested Spanish\", \"language\": \"es\"}"
}
}

Implementación: Configura los idiomas compatibles en los ajustes del agente y añade la herramienta del sistema de detección de idioma. El agente cambiará automáticamente la voz y las respuestas para adaptarse a los idiomas detectados.

Más información: Herramienta de detección de idioma

Objetivo: Transferir conversaciones entre agentes de IA especializados según las necesidades del usuario.

Condiciones de activación: El LLM debe llamar a esta herramienta cuando:

  • La solicitud del usuario requiera conocimientos especializados o capacidades de otro agente
  • El agente actual no pueda gestionar adecuadamente la consulta
  • El flujo de la conversación indique que se necesita un tipo de agente diferente

Parámetros:

  • reason (cadena, opcional): El motivo de la transferencia de agente
  • agent_number (entero, obligatorio): Número indexado desde cero del agente al que transferir (según las reglas de transferencia configuradas)

Formato de llamada a función:

{
"type": "function",
"function": {
"name": "transfer_to_agent",
"arguments": "{\"reason\": \"User needs billing support\", \"agent_number\": 0}"
}
}

Implementación: Define reglas de transferencia que asignen condiciones a ID de agente específicos. Configura a qué agentes puede transferir el agente actual. Los agentes se identifican mediante números indexados desde cero en la configuración de transferencia.

Más información: Herramienta de transferencia de agente

Objetivo: Derivar conversaciones sin problemas a operadores humanos cuando la asistencia de IA no sea suficiente.

Condiciones de activación: El LLM debe llamar a esta herramienta cuando:

  • Haya problemas complejos que requieran criterio humano
  • El usuario solicite explícitamente asistencia humana
  • La IA alcance los límites de sus capacidades para la solicitud específica
  • Se activen protocolos de escalado

Parámetros:

  • reason (cadena, opcional): El motivo de la transferencia
  • transfer_number (cadena, obligatorio): El número de teléfono al que transferir (debe coincidir con los números configurados)
  • client_message (cadena, obligatorio): Mensaje que se lee al cliente mientras espera la transferencia
  • agent_message (cadena, obligatorio): Mensaje para el operador humano que recibe la llamada

Formato de llamada a función:

{
"type": "function",
"function": {
"name": "transfer_to_number",
"arguments": "{\"reason\": \"Complex billing issue\", \"transfer_number\": \"+15551234567\", \"client_message\": \"I'm transferring you to a billing specialist who can help with your account.\", \"agent_message\": \"Customer has a complex billing dispute about order #12345 from last month.\"}"
}
}

Implementación: Configura los números de teléfono y las condiciones de transferencia. Define mensajes tanto para el cliente como para el operador humano que recibe la llamada. Funciona tanto con Twilio como con trunking SIP.

Más información: Herramienta para transferir a una persona

Objetivo: Permitir que el agente pause y espere la intervención del usuario sin hablar.

Condiciones de activación: El LLM debe llamar a esta herramienta cuando:

  • El usuario indique que necesita un momento (“Dame un segundo”, “Déjame pensar”)
  • El usuario solicite una pausa en el flujo de la conversación
  • El agente detecte que el usuario necesita tiempo para procesar la información

Parámetros:

  • reason (cadena, opcional): Motivo de texto libre que explica por qué se necesita la pausa

Formato de llamada a función:

{
"type": "function",
"function": {
"name": "skip_turn",
"arguments": "{\"reason\": \"User requested time to think\"}"
}
}

Implementación: No se necesita configuración adicional. La herramienta simplemente indica al agente que permanezca en silencio hasta que el usuario vuelva a hablar.

Más información: Herramienta para omitir turno

Parámetros:

  • reason (cadena, obligatorio): El motivo para detectar el buzón de voz (por ejemplo, «se ha detectado un saludo automatizado», «no hay respuesta humana»)

Formato de llamada de función:

{
"type": "function",
"function": {
"name": "voicemail_detection",
"arguments": "{\"reason\": \"Automated greeting detected with request to leave message\"}"
}
}

Más información: Herramienta de detección de buzón de voz

Ejemplo de solicitud con herramientas del sistema

Cuando se configuran herramientas del sistema, tu LLM personalizado recibirá solicitudes que incluyen las herramientas en el formato estándar de OpenAI:

{
"messages": [
{
"role": "system",
"content": "You are a helpful assistant. You have access to system tools for managing conversations."
},
{
"role": "user",
"content": "I think we're done here, thanks for your help!"
}
],
"model": "your-custom-model",
"temperature": 0.7,
"max_tokens": 1000,
"stream": true,
"tools": [
{
"type": "function",
"function": {
"name": "end_call",
"description": "Call this function to end the current conversation when the main task has been completed...",
"parameters": {
"type": "object",
"properties": {
"reason": {
"type": "string",
"description": "The reason for the tool call."
},
"message": {
"type": "string",
"description": "A farewell message to send to the user along right before ending the call."
}
},
"required": ["reason"]
}
}
},
{
"type": "function",
"function": {
"name": "language_detection",
"description": "Change the conversation language when the user expresses a language preference explicitly...",
"parameters": {
"type": "object",
"properties": {
"reason": {
"type": "string",
"description": "The reason for the tool call."
},
"language": {
"type": "string",
"description": "The language to switch to. Must be one of language codes in tool description."
}
},
"required": ["reason", "language"]
}
}
},
{
"type": "function",
"function": {
"name": "skip_turn",
"description": "Skip a turn when the user explicitly indicates they need a moment to think...",
"parameters": {
"type": "object",
"properties": {
"reason": {
"type": "string",
"description": "Optional free-form reason explaining why the pause is needed."
}
},
"required": []
}
}
}
]
}

Tu LLM personalizado debe admitir llamadas a funciones para usar las herramientas del sistema. Asegúrate de que tu modelo pueda generar respuestas de llamada a función adecuadas en formato OpenAI.

Funciones adicionales

Puedes pasar parámetros adicionales a tu implementación de LLM personalizada.

1

Define los parámetros adicionales

Crea un objeto que contenga tus parámetros personalizados:

from elevenlabs.conversational_ai.conversation import Conversation, ConversationInitiationData
extra_body_for_convai = {
"UUID": "123e4567-e89b-12d3-a456-426614174000",
"parameter-1": "value-1",
"parameter-2": "value-2",
}
config = ConversationInitiationData(
extra_body=extra_body_for_convai,
)
2

Actualiza la implementación del LLM

Modifica el código de tu LLM personalizado para gestionar los parámetros adicionales:

import json
import os
import fastapi
from fastapi.responses import StreamingResponse
from fastapi import Request
from openai import AsyncOpenAI
import uvicorn
import logging
from dotenv import load_dotenv
from pydantic import BaseModel
from typing import List, Optional
# Load environment variables from .env file
load_dotenv()
# Retrieve API key from environment
OPENAI_API_KEY = os.getenv('OPENAI_API_KEY')
if not OPENAI_API_KEY:
raise ValueError("OPENAI_API_KEY not found in environment variables")
app = fastapi.FastAPI()
oai_client = AsyncOpenAI(api_key=OPENAI_API_KEY)
class Message(BaseModel):
role: str
content: str
class ChatCompletionRequest(BaseModel):
messages: List[Message]
model: str
temperature: Optional[float] = 0.7
max_tokens: Optional[int] = None
stream: Optional[bool] = False
user_id: Optional[str] = None
elevenlabs_extra_body: Optional[dict] = None
@app.post("/v1/chat/completions")
async def create_chat_completion(request: ChatCompletionRequest) -> StreamingResponse:
oai_request = request.dict(exclude_none=True)
print(oai_request)
if "user_id" in oai_request:
oai_request["user"] = oai_request.pop("user_id")
if "elevenlabs_extra_body" in oai_request:
oai_request.pop("elevenlabs_extra_body")
chat_completion_coroutine = await oai_client.chat.completions.create(**oai_request)
async def event_stream():
try:
async for chunk in chat_completion_coroutine:
chunk_dict = chunk.model_dump()
yield f"data: {json.dumps(chunk_dict)}\n\n"
yield "data: [DONE]\n\n"
except Exception as e:
logging.error("An error occurred: %s", str(e))
yield f"data: {json.dumps({'error': 'Internal error occurred!'})}\n\n"
return StreamingResponse(event_stream(), media_type="text/event-stream")
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=8013)

Ejemplo de solicitud

Con esta configuración de mensajes personalizados, tu LLM recibirá solicitudes con este formato:

{
"messages": [
{
"role": "system",
"content": "\n <Redacted>"
},
{
"role": "assistant",
"content": "Hey I'm currently unavailable."
},
{
"role": "user",
"content": "Hey, who are you?"
}
],
"model": "gpt-4o",
"temperature": 0.5,
"max_tokens": 5000,
"stream": true,
"elevenlabs_extra_body": {
"UUID": "123e4567-e89b-12d3-a456-426614174000",
"parameter-1": "value-1",
"parameter-2": "value-2"
}
}