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

# 集成自己的模型

> **Note**
>
> 自定义 LLM 可通过外部端点将对话连接到自己的 LLM。
> ElevenLabs 也支持[原生集成的 LLM](/docs/zh/eleven-agents/customization/llm)

**自定义 LLM**让你可以使用自己的 OpenAI API 密钥，或运行完全自定义的 LLM 服务器。

自定义 LLM 无法与 [Realtime 模型](/docs/zh/eleven-agents/customization/realtime-models)搭配使用。

## 概述

默认情况下，我们会为 OpenAI 等热门模型使用内部凭据。要使用自定义 LLM 服务器，其请求和响应结构必须符合以下任一 OpenAI 兼容格式：

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

> **Info**
>
> Responses API 是 OpenAI 较新的 API 格式，支持更多功能。这两种 API 格式都完全支持自定义 LLM 集成。

以下指南涵盖两种使用方式：

1. **使用自己的 OpenAI 密钥**：在平台中使用自己的 OpenAI API 密钥。
2. **自定义 LLM 服务器**：托管并连接自己的 LLM 服务器实现。

你将了解如何：

* 在 ElevenLabs 中存储 OpenAI API 密钥
* 托管一个复刻 OpenAI [Chat Completions](https://platform.openai.com/docs/api-reference/chat/create) 或 [Responses](https://platform.openai.com/docs/api-reference/responses/create)端点的服务器
* 让 ElevenLabs 指向自定义端点
* 按需向 LLM 传递额外参数

## 推理摘要

端点必须将推理内容与最终答案分开返回。ElevenLabs 不会根据最终答案生成推理内容。

要从支持的端点请求推理，请在智能体的 LLM 设置中开启 **推理摘要**，或通过 API 设置 `enable_reasoning_summary`。

### 返回推理内容

请使用与端点匹配的格式：

#### Chat Completions API

在每个响应增量的 `reasoning` 或 `reasoning_content` 字段中流式传输推理内容。

对于兼容 Gemini 的端点，ElevenLabs 通过
`google.thinking_config.include_thoughts` 请求思考内容，并读取标记为
`extra_content.google.thought` 的内容。

#### Responses API

返回一个 `reasoning` 输出项，并在其 `summary` 字段中包含摘要文本。

配置推理强度并启用推理摘要后，ElevenLabs 会在请求中将
`reasoning.summary` 设为 `auto`。

有关存储、传递方式和限制，请参阅[推理摘要](/docs/zh/eleven-agents/customization/llm#reasoning-summary)。

## 使用自己的 OpenAI 密钥

要集成自定义 OpenAI 密钥，请在 ElevenLabs 控制台中更新智能体设置，使其指向自定义 LLM 服务器，并创建一个包含 `OPENAI_API_KEY` 的密钥：

在 ElevenLabs 控制台的智能体设置中，从右侧“LLM”下拉菜单选择“Custom LLM”。

![添加密钥](/docs/_fern-img/83c62b81ef04860b9d884e28e1b4ac7bbceaa6e481e72e15ae82a76ec9bbad8e.webp)

点击“LLM”下方的字段，向下滚动并选择“Custom LLM”。

输入自定义 LLM 服务器的服务器 URL 和模型 ID。

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

点击“API key”下方的下拉菜单，选择“Create new secret”。将密钥命名为 `OPENAI_API_KEY`，在“value”字段中添加密钥，然后点击“Add secret”。

点击“x”按钮关闭 LLM 弹窗，然后点击“Publish”保存更改。

## 自定义 LLM 服务器

要接入自定义 LLM 服务器，请使用 OpenAI 风格设置兼容的服务器端点。你可以实现 Chat Completions API（`/v1/chat/completions`）或 Responses API（`/v1/responses`）。

两个端点都必须以 SSE（服务器发送事件）格式返回响应，并使用 `Content-Type: text/event-stream`。

#### Chat Completions API

Chat Completions API 使用 `/v1/chat/completions` 端点。

每个块必须采用 `data: {json}\n\n` 格式，且流必须以 `data: [DONE]\n\n` 结束。

以下是服务器实现示例：

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

#### Responses API

Responses API 使用 `/v1/responses` 端点。

每个块必须采用 `event: {type}\ndata: {json}\n\n` 格式，且流必须以 `data: [DONE]\n\n` 结束。最低要求的事件为：

* `response.output_text.delta`：用于流式传输文本内容
* `response.completed`：用于表示完成

**`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"));
```

运行此代码或自己的服务器代码。

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

### 为服务器设置公共 URL

要让服务器可访问，请使用 ngrok 等隧道工具创建公共 URL：

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

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

### 配置 ElevenLabs CustomLLM

接下来，在 ElevenLabs 控制台中更新智能体设置，使其指向自定义 LLM 服务器。

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

将服务器 URL 指向 ngrok 端点，并将“Limit token usage”设为 5000。

现在可以使用自己的 LLM 服务器开始与智能体互动。

## 针对处理较慢的 LLM 进行优化

如果自定义 LLM 处理时间较长（可能是因为智能体推理或预处理需求），可以在流式响应中加入 **缓冲词**，改善对话流畅度。该技术可让 LLM 生成完整回复时，语音仍保持自然韵律。

### 缓冲词

当 LLM 需要更多时间处理完整回复时，请返回一个以 `"... "`（省略号后加空格）结尾的初始响应。这样，文本转语音系统便能保持自然流畅，对话也更具动态感。
这会形成自然的停顿，并顺畅衔接 LLM 可进一步推理的后续内容。额外的空格至关重要，可避免后续内容直接附加到 `"..."` 后，从而导致音频失真。

### 实现方式

以下展示如何修改自定义 LLM 服务器以实现缓冲词：

**`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();
  }
});
```

## 系统工具集成

自定义 LLM 可触发[系统工具](/docs/zh/eleven-agents/customization/tools/system-tools)，以控制对话流程和状态。在智能体中完成配置后，这些工具会自动包含在聊天补全请求的 `tools` 参数中。

### 系统工具的工作方式

1. **LLM 决策**：自定义 LLM 根据对话上下文决定何时调用这些工具
2. **工具响应**：LLM 以标准 OpenAI 格式返回函数调用
3. **后端处理**：ElevenLabs 处理工具调用并更新对话状态

如需了解系统工具的更多信息，请参阅[指南](/docs/zh/eleven-agents/customization/tools/system-tools)。

### 可用系统工具

#### 结束通话

**用途**：在满足适当条件时自动结束对话。

**触发条件**：LLM 应在以下情况调用此工具：

* 主要任务已完成，且用户满意
* 双方达成一致，对话自然结束
* 用户明确表示想结束对话

**参数**：

* `reason`（字符串，必填）：结束通话的原因
* `message`（字符串，选填）：结束通话前发送给用户的告别消息

**函数调用格式**：

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

**实现方式**：在智能体设置中配置为系统工具。LLM 将收到有关何时调用此函数的详细说明。

了解更多：[结束通话工具](/docs/zh/eleven-agents/customization/tools/system-tools/end-call)

#### 语言检测

**用途**：在对话中自动切换至检测到的用户语言。

**触发条件**：LLM 应在以下情况调用此工具：

* 用户使用的语言不同于当前对话语言
* 用户明确请求切换语言
* 对话需要支持多种语言

**参数**：

* `reason`（字符串，必填）：切换语言的原因
* `language`（字符串，必填）：要切换至的语言代码（必须在支持的语言列表中）

**函数调用格式**：

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

**实现方式**：在智能体设置中配置支持的语言并添加语言检测系统工具。智能体会自动切换语音和回复，以匹配检测到的语言。

了解更多：[语言检测工具](/docs/zh/eleven-agents/customization/tools/system-tools/language-detection)

#### 智能体转接

**用途**：根据用户需求，在专业 AI 智能体之间转接对话。

**触发条件**：LLM 应在以下情况调用此工具：

* 用户请求需要专业知识或不同的智能体能力
* 当前智能体无法妥善处理该问题
* 对话流程表明需要其他类型的智能体

**参数**：

* `reason`（字符串，选填）：转接智能体的原因
* `agent_number`（整数，必填）：要转接至的智能体从 0 开始的编号（基于已配置的转接规则）

**函数调用格式**：

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

**实现方式**：定义将条件映射到特定智能体 ID 的转接规则。配置当前智能体可转接到哪些智能体。智能体在转接配置中以从 0 开始的编号引用。

了解更多：[智能体转接工具](/docs/zh/eleven-agents/customization/tools/system-tools/agent-transfer)

#### 转接人工客服

**用途**：当 AI 协助不足时，无缝将对话转交给人工客服。

**触发条件**：LLM 应在以下情况调用此工具：

* 问题复杂，需要人工判断
* 用户明确请求人工协助
* AI 的能力无法满足具体请求
* 触发升级处理流程

**参数**：

* `reason`（字符串，选填）：转接原因
* `transfer_number`（字符串，必填）：要转接至的电话号码（必须与已配置的号码匹配）
* `client_message`（字符串，必填）：等待转接期间向客户播报的消息
* `agent_message`（字符串，必填）：发送给接听通话的人工客服的消息

**函数调用格式**：

```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.\"}"
  }
}
```

**实现方式**：配置转接电话号码和条件，并分别定义面向客户和接听通话的人工客服的消息。同时支持 Twilio 和 SIP 中继。

了解更多：[转接人工客服工具](/docs/zh/eleven-agents/customization/tools/system-tools/transfer-to-number)

#### 跳过回合

**用途**：允许智能体暂停并等待用户输入，不发出语音。

**触发条件**：LLM 应在以下情况调用此工具：

* 用户表示需要一点时间（“等我一下”“让我想想”）
* 用户请求暂停对话
* 智能体检测到用户需要时间处理信息

**参数**：

* `reason`（字符串，选填）：说明为何需要暂停的自由文本原因

**函数调用格式**：

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

**实现方式**：无需额外配置。该工具仅会让智能体保持静默，直到用户再次说话。

了解更多：[跳过回合工具](/docs/zh/eleven-agents/customization/tools/system-tools/skip-turn)

#### 语音信箱检测

**参数**：

* `reason`（字符串，必填）：检测到语音信箱的原因（例如，“检测到自动问候语”“无人响应”）

**函数调用格式**：

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

了解更多：[语音信箱检测工具](/docs/zh/eleven-agents/customization/tools/system-tools/voicemail-detection)

### 使用系统工具的请求示例

配置系统工具后，自定义 LLM 将收到包含工具的请求，格式遵循标准 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**
>
> 自定义 LLM 必须支持函数调用才能使用系统工具。请确保模型能够以 OpenAI 格式生成
> 正确的函数调用响应。

# 其他功能

#### 自定义 LLM 参数

可以向自定义 LLM 实现传递其他参数。

#### Python

#### 定义额外参数

创建一个包含自定义参数的对象：

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

#### 更新 LLM 实现

修改自定义 LLM 代码以处理额外参数：

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

### 请求示例

使用此自定义消息设置后，LLM 将收到以下格式的请求：

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