> This is a page from the ElevenLabs documentation. For a complete page index, fetch https://elevenlabs.io/docs/llms.txt. For the full documentation in a single file, fetch https://elevenlabs.io/docs/llms-full.txt.

# Integra tu propio modelo

> **Note**
>
> Custom LLM te permite conectar tus conversaciones a tu propio LLM mediante una ruta externa.
> ElevenLabs también admite [LLM integrados de forma nativa](/docs/es/eleven-agents/customization/llm)

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:

* [API Chat Completions](https://platform.openai.com/docs/api-reference/chat/create) (`/v1/chat/completions`)
* [API Responses](https://platform.openai.com/docs/api-reference/responses/create) (`/v1/responses`)

> **Info**
>
> 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](https://platform.openai.com/docs/api-reference/chat/create) o [Responses](https://platform.openai.com/docs/api-reference/responses/create) 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:

#### API Chat Completions

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`.

#### API Responses

Devuelve un elemento de salida `reasoning` con el texto del resumen en su campo `summary`.

Con el esfuerzo de razonamiento configurado y Resumen del razonamiento activado, ElevenLabs establece
`reasoning.summary` en `auto` en la solicitud.

Consulta [Resumen del razonamiento](/docs/es/eleven-agents/customization/llm#reasoning-summary) 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`:

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](/docs/_fern-img/83c62b81ef04860b9d884e28e1b4ac7bbceaa6e481e72e15ae82a76ec9bbad8e.webp)

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

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

![Introducir URL](/docs/_fern-img/85ed8154868096a5c8de4c5e1c09d83c861069ea098c7643a960cac1736b67cb.webp)

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".

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`.

#### API Chat Completions

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:

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

#### API Responses

La API Responses usa la ruta `/v1/responses`.

Cada fragmento debe tener el formato `event: {type}\ndata: {json}\n\n` y el stream debe terminar con `data: [DONE]\n\n`. Los eventos mínimos necesarios son:

* `response.output_text.delta`: para transmitir contenido de texto
* `response.completed`: para indicar que se ha completado

**`server.py`**

```python title="server.py"
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_dotenv()

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 InputMessage(BaseModel):
    role: str
    content: str

class ResponseCreateRequest(BaseModel):
    model: str
    input: List[InputMessage]
    instructions: Optional[str] = None
    temperature: Optional[float] = 0.7
    max_output_tokens: Optional[int] = None
    stream: Optional[bool] = False

@app.post("/v1/responses")
async def create_response(request: ResponseCreateRequest) -> StreamingResponse:
    input_messages = [{"role": msg.role, "content": msg.content} for msg in request.input]

    response_stream = await oai_client.responses.create(
        model=request.model,
        input=input_messages,
        instructions=request.instructions,
        temperature=request.temperature,
        max_output_tokens=request.max_output_tokens,
        stream=True
    )

    async def event_stream():
        try:
            async for event in response_stream:
                if event.type == "response.output_text.delta":
                    yield f"event: response.output_text.delta\ndata: {json.dumps({'type': 'response.output_text.delta', 'delta': event.delta})}\n\n"
                elif event.type == "response.completed":
                    yield f"event: response.completed\ndata: {json.dumps({'type': 'response.completed', 'response': {'id': event.response.id, 'status': 'completed'}})}\n\n"

            yield "data: [DONE]\n\n"

        except Exception as e:
            logging.error("An error occurred: %s", str(e))
            yield f"event: error\ndata: {json.dumps({'type': 'error', 'error': {'message': str(e)}})}\n\n"

    return StreamingResponse(event_stream(), media_type="text/event-stream")

if __name__ == "__main__":
    uvicorn.run(app, host="0.0.0.0", port=8013)

```

**`server.ts`**

```typescript title="server.ts"
import express, { Request, Response } from "express";
import OpenAI from "openai";

const app = express();
app.use(express.json());

const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY });

interface InputMessage {
  role: string;
  content: string;
}

interface ResponseCreateRequest {
  model: string;
  input: InputMessage[];
  instructions?: string;
  temperature?: number;
  max_output_tokens?: number;
  stream?: boolean;
}

app.post("/v1/responses", async (req: Request, res: Response) => {
  const request = req.body as ResponseCreateRequest;

  res.setHeader("Content-Type", "text/event-stream");
  res.setHeader("Cache-Control", "no-cache");
  res.setHeader("Connection", "keep-alive");

  try {
    const stream = await openai.responses.create({
      model: request.model,
      input: request.input,
      instructions: request.instructions,
      temperature: request.temperature ?? 0.7,
      max_output_tokens: request.max_output_tokens,
      stream: true,
    });

    for await (const event of stream) {
      if (event.type === "response.output_text.delta") {
        res.write(
          `event: response.output_text.delta\ndata: ${JSON.stringify({ type: "response.output_text.delta", delta: event.delta })}\n\n`
        );
      } else if (event.type === "response.completed") {
        res.write(
          `event: response.completed\ndata: ${JSON.stringify({ type: "response.completed", response: { id: event.response.id, status: "completed" } })}\n\n`
        );
      }
    }

    res.write("data: [DONE]\n\n");
    res.end();
  } catch (error) {
    console.error("An error occurred:", error);
    res.write(
      `event: error\ndata: ${JSON.stringify({ type: "error", error: { message: String(error) } })}\n\n`
    );
    res.end();
  }
});

app.listen(8013, () => console.log("Server running on port 8013"));
```

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

![](/docs/_fern-img/8032697eeac9a62bb084feb13ab05294df2fee44f14a97897f0b7c10ffee813c.webp)

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

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

![](/docs/_fern-img/16d139cc2889d46e026c8aa7578fcdcd8d228dbe0f4df245091ea6de2ceb345a.webp)

### 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.

![](/docs/_fern-img/d57d81e44dffb7e6f581a4eed449d887f6c365b8ceb4f4f0174bd7e2ffd62537.webp)

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:

**`server.py`**

```python title="server.py"
@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")

```

**`server.ts`**

```typescript title="server.ts"
app.post("/v1/chat/completions", async (req: Request, res: Response) => {
  const request = req.body as ChatCompletionRequest;
  const oaiRequest = { ...request };

  if (oaiRequest.user_id) {
    oaiRequest.user = oaiRequest.user_id;
    delete oaiRequest.user_id;
  }

  res.setHeader("Content-Type", "text/event-stream");
  res.setHeader("Cache-Control", "no-cache");
  res.setHeader("Connection", "keep-alive");

  try {
    // Send initial buffer chunk while processing
    const initialChunk = {
      id: "chatcmpl-buffer",
      object: "chat.completion.chunk",
      created: Math.floor(Date.now() / 1000),
      model: request.model,
      choices: [
        {
          delta: { content: "Let me think about that... " },
          index: 0,
          finish_reason: null,
        },
      ],
    };
    res.write(`data: ${JSON.stringify(initialChunk)}\n\n`);

    // Process the actual LLM response
    const stream = await openai.chat.completions.create({
      ...oaiRequest,
      stream: true,
    });

    for await (const chunk of stream) {
      res.write(`data: ${JSON.stringify(chunk)}\n\n`);
    }

    res.write("data: [DONE]\n\n");
    res.end();
  } catch (error) {
    console.error("An error occurred:", error);
    res.write(`data: ${JSON.stringify({ error: "Internal error occurred!" })}\n\n`);
    res.end();
  }
});
```

## Integración de herramientas del sistema

Tu LLM personalizado puede activar [herramientas del sistema](/docs/es/eleven-agents/customization/tools/system-tools) 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](/docs/es/eleven-agents/customization/tools/system-tools)

### Herramientas del sistema disponibles

#### Finalizar llamada

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

```json
{
  "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](/docs/es/eleven-agents/customization/tools/system-tools/end-call)

#### Detección de idioma

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

```json
{
  "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](/docs/es/eleven-agents/customization/tools/system-tools/language-detection)

#### Transferencia de agente

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

```json
{
  "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](/docs/es/eleven-agents/customization/tools/system-tools/agent-transfer)

#### Transferir a una persona

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

```json
{
  "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](/docs/es/eleven-agents/customization/tools/system-tools/transfer-to-number)

#### Omitir turno

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

```json
{
  "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](/docs/es/eleven-agents/customization/tools/system-tools/skip-turn)

#### Detección de buzón de voz

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

```json
{
  "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](/docs/es/eleven-agents/customization/tools/system-tools/voicemail-detection)

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

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

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

#### Parámetros de LLM personalizados

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

#### Python

#### Define los parámetros adicionales

Crea un objeto que contenga tus parámetros personalizados:

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

#### Actualiza la implementación del LLM

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

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

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