Podłącz własny model

Połącz agenta z własnym LLM lub hostuj własny serwer.

Custom LLM pozwala połączyć rozmowy z własnym LLM przez zewnętrzny endpoint. ElevenLabs obsługuje też natywnie zintegrowane LLM

Własne LLM pozwalają użyć własnego klucza OpenAI API lub uruchomić całkowicie własny serwer LLM.

Omówienie

Domyślnie używamy własnych danych logowania do popularnych modeli, takich jak OpenAI. Aby użyć własnego serwera LLM, musi on być zgodny z jedną z poniższych struktur żądań i odpowiedzi OpenAI:

Responses API to nowszy format API OpenAI, obsługujący dodatkowe funkcje. Oba formaty API są w pełni obsługiwane przy integracji z własnym LLM.

Poniższe przewodniki obejmują oba przypadki:

  1. Użyj własnego klucza OpenAI: użyj własnego klucza OpenAI API na naszej platformie.
  2. Własny serwer LLM: hostuj i podłącz własną implementację serwera LLM.

Dowiesz się, jak:

  • Zapisać klucz OpenAI API w ElevenLabs
  • Hostować serwer odtwarzający endpoint Chat Completions lub Responses od OpenAI
  • Skierować ElevenLabs do własnego endpointu
  • W razie potrzeby przekazywać dodatkowe parametry do LLM

Podsumowanie rozumowania

Endpoint musi zwracać rozumowanie oddzielnie od końcowej odpowiedzi. ElevenLabs nie generuje rozumowania na podstawie końcowej odpowiedzi.

Aby żądać rozumowania z obsługiwanego endpointu, włącz Podsumowanie rozumowania w ustawieniach LLM agenta lub ustaw enable_reasoning_summary przez API.

Zwracanie rozumowania

Użyj formatu zgodnego z endpointem:

Przesyłaj strumieniowo rozumowanie w polu reasoning lub reasoning_content każdej delty odpowiedzi.

W przypadku endpointów zgodnych z Gemini ElevenLabs żąda przemyśleń za pomocą google.thinking_config.include_thoughts i odczytuje treść oznaczoną jako extra_content.google.thought.

Więcej informacji o przechowywaniu, dostarczaniu i ograniczeniach znajdziesz w Podsumowaniu rozumowania.

Używanie własnego klucza OpenAI

Aby zintegrować własny klucz OpenAI, zaktualizuj ustawienia agenta w panelu ElevenLabs, aby wskazywały własny serwer LLM, i utwórz sekret zawierający OPENAI_API_KEY:

1

W ustawieniach agenta w panelu ElevenLabs wybierz “Custom LLM” z menu rozwijanego “LLM” po prawej stronie.

Dodaj sekret

2

Kliknij pole pod “LLM” i przewiń w dół, aby wybrać “Custom LLM”.

3

Wpisz URL serwera i Model ID własnego serwera LLM.

Wprowadź URL

4

Kliknij menu rozwijane pod “API key” i wybierz “Create new secret”. Nazwij klucz OPENAI_API_KEY, dodaj go w polu “value” i kliknij “Add secret”.

5

Kliknij przycisk “x”, aby zamknąć okno LLM, a potem kliknij “Publish”, aby zapisać zmiany.

Własny serwer LLM

Aby użyć własnego serwera LLM, skonfiguruj zgodny endpoint serwera w stylu OpenAI. Możesz wdrożyć Chat Completions API (/v1/chat/completions) albo Responses API (/v1/responses).

Oba endpointy muszą zwracać odpowiedzi w formacie SSE (Server-Sent Events) z Content-Type: text/event-stream.

Chat Completions API używa endpointu /v1/chat/completions.

Każdy fragment musi mieć format data: {json}\n\n, a strumień musi kończyć się na data: [DONE]\n\n.

Oto przykładowa implementacja serwera:

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)

Uruchom ten kod lub kod własnego serwera.

Konfiguracja publicznego URL serwera

Aby udostępnić serwer, utwórz publiczny URL za pomocą narzędzia do tunelowania, takiego jak ngrok:

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

Konfiguracja CustomLLM ElevenLabs

Następnie zaktualizuj ustawienia agenta w panelu ElevenLabs, aby wskazywały własny serwer LLM.

Skieruj URL serwera do endpointu ngrok i ustaw “Limit token usage” na 5000.

Możesz teraz zacząć korzystać z agenta z własnym serwerem LLM.

Optymalizacja pod kątem wolnych modeli LLM

Jeśli twój własny LLM przetwarza dane wolno (na przykład przez rozumowanie agentowe lub wymagania dotyczące wstępnego przetwarzania), możesz poprawić płynność rozmowy, stosując słowa buforujące w odpowiedziach strumieniowych. Ta technika pomaga zachować naturalną prozodię mowy, gdy LLM generuje pełną odpowiedź.

Słowa buforujące

Gdy LLM potrzebuje więcej czasu na przetworzenie pełnej odpowiedzi, zwróć początkową odpowiedź kończącą się na "... " (wielokropek, po którym następuje spacja). Dzięki temu system Text to Speech zachowuje naturalną płynność, a rozmowa pozostaje dynamiczna. Tworzy to naturalne pauzy, które dobrze łączą się z kolejną treścią, nad którą LLM może dłużej się zastanawiać. Dodatkowa spacja jest kluczowa, aby kolejna treść nie została dołączona do „…”, co może powodować zniekształcenia dźwięku.

Implementacja

Tak zmodyfikujesz serwer własnego LLM, aby używać słów buforujących:

@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")

Integracja narzędzi systemowych

Twój własny LLM może uruchamiać narzędzia systemowe, aby kontrolować przebieg i stan rozmowy. Gdy skonfigurujesz je w agencie, narzędzia te są automatycznie dodawane do parametru tools w żądaniach ukończenia czatu.

Jak działają narzędzia systemowe

  1. Decyzja LLM: Twój własny LLM decyduje, kiedy wywołać te narzędzia na podstawie kontekstu rozmowy
  2. Odpowiedź narzędzia: LLM odpowiada wywołaniami funkcji w standardowym formacie OpenAI
  3. Przetwarzanie backendu: ElevenLabs przetwarza wywołania narzędzi i aktualizuje stan rozmowy

Więcej informacji o narzędziach systemowych znajdziesz w naszym przewodniku

Dostępne narzędzia systemowe

Cel: Automatyczne kończenie rozmów po spełnieniu odpowiednich warunków.

Warunki wywołania: LLM powinien wywołać to narzędzie, gdy:

  • Główne zadanie zostało wykonane, a użytkownik jest zadowolony
  • Rozmowa naturalnie dobiegła końca za obopólną zgodą
  • Użytkownik wyraźnie wskazuje, że chce zakończyć rozmowę

Parametry:

  • reason (string, wymagany): Powód zakończenia rozmowy
  • message (string, opcjonalny): Wiadomość pożegnalna wysyłana użytkownikowi przed zakończeniem rozmowy

Format wywołania funkcji:

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

Implementacja: Skonfiguruj jako narzędzie systemowe w ustawieniach agenta. LLM otrzyma szczegółowe instrukcje, kiedy wywołać tę funkcję.

Dowiedz się więcej: Narzędzie do kończenia rozmowy

Cel: Automatyczna zmiana na wykryty język użytkownika podczas rozmowy.

Warunki wywołania: LLM powinien wywołać to narzędzie, gdy:

  • Użytkownik mówi w języku innym niż bieżący język rozmowy
  • Użytkownik wyraźnie prosi o zmianę języka
  • Rozmowa wymaga obsługi wielu języków

Parametry:

  • reason (string, wymagany): Powód zmiany języka
  • language (string, wymagany): Kod języka, na który ma nastąpić zmiana (musi być na liście obsługiwanych języków)

Format wywołania funkcji:

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

Implementacja: Skonfiguruj obsługiwane języki w ustawieniach agenta i dodaj narzędzie systemowe wykrywania języka. Agent automatycznie zmieni głos i odpowiedzi, aby pasowały do wykrytego języka.

Dowiedz się więcej: Narzędzie do wykrywania języka

Cel: Przekazywanie rozmów między wyspecjalizowanymi agentami AI zależnie od potrzeb użytkownika.

Warunki wywołania: LLM powinien wywołać to narzędzie, gdy:

  • Prośba użytkownika wymaga specjalistycznej wiedzy lub innych możliwości agenta
  • Obecny agent nie może odpowiednio obsłużyć zapytania
  • Przebieg rozmowy wskazuje na potrzebę innego typu agenta

Parametry:

  • reason (string, opcjonalny): Powód przekazania do agenta
  • agent_number (integer, wymagany): Numer od zera agenta, do którego ma zostać przekazana rozmowa (na podstawie skonfigurowanych reguł przekazywania)

Format wywołania funkcji:

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

Implementacja: Zdefiniuj reguły przekazywania, które mapują warunki na konkretne identyfikatory agentów. Skonfiguruj, do których agentów obecny agent może przekazywać rozmowy. W konfiguracji przekazywania agenci są wskazywani numerami od zera.

Dowiedz się więcej: Narzędzie do przekazywania do agenta

Cel: Płynne przekazywanie rozmów operatorom, gdy pomoc AI nie wystarcza.

Warunki wywołania: LLM powinien wywołać to narzędzie, gdy:

  • Problem jest złożony i wymaga ludzkiej oceny
  • Użytkownik wyraźnie prosi o pomoc człowieka
  • AI osiąga granice swoich możliwości w przypadku konkretnej prośby
  • Uruchomione zostają procedury eskalacji

Parametry:

  • reason (string, opcjonalny): Powód przekazania
  • transfer_number (string, wymagany): Numer telefonu, na który ma zostać przekazana rozmowa (musi odpowiadać skonfigurowanym numerom)
  • client_message (string, wymagany): Wiadomość odczytywana klientowi podczas oczekiwania na przekazanie
  • agent_message (string, wymagany): Wiadomość dla operatora odbierającego rozmowę

Format wywołania funkcji:

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

Implementacja: Skonfiguruj numery telefonów i warunki przekazywania. Zdefiniuj wiadomości zarówno dla klienta, jak i operatora przejmującego rozmowę. Działa z Twilio i trunkingiem SIP.

Dowiedz się więcej: Narzędzie do przekazywania do człowieka

Cel: Pozwala agentowi zrobić pauzę i czekać na dane od użytkownika bez mówienia.

Warunki wywołania: LLM powinien wywołać to narzędzie, gdy:

  • Użytkownik wskazuje, że potrzebuje chwili („Daj mi sekundę”, „Muszę się zastanowić”)
  • Użytkownik prosi o pauzę w rozmowie
  • Agent wykrywa, że użytkownik potrzebuje czasu na przetworzenie informacji

Parametry:

  • reason (string, opcjonalny): Dowolny powód wyjaśniający, dlaczego potrzebna jest pauza

Format wywołania funkcji:

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

Implementacja: Nie wymaga dodatkowej konfiguracji. Narzędzie po prostu sygnalizuje agentowi, że ma zachować ciszę, dopóki użytkownik ponownie się nie odezwie.

Dowiedz się więcej: Narzędzie do pomijania tury

Parametry:

  • reason (string, wymagany): Powód wykrycia poczty głosowej (np. „wykryto automatyczne powitanie”, „brak odpowiedzi człowieka”)

Format wywołania funkcji:

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

Dowiedz się więcej: Narzędzie do wykrywania poczty głosowej

Przykładowe żądanie z narzędziami systemowymi

Gdy narzędzia systemowe są skonfigurowane, twój własny LLM otrzyma żądania obejmujące narzędzia w standardowym formacie 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": []
}
}
}
]
}

Twój własny LLM musi obsługiwać wywoływanie funkcji, aby korzystać z narzędzi systemowych. Upewnij się, że model może generować prawidłowe odpowiedzi wywołań funkcji w formacie OpenAI.

Dodatkowe funkcje

Możesz przekazać dodatkowe parametry do implementacji własnego LLM.

1

Zdefiniuj dodatkowe parametry

Utwórz obiekt zawierający własne parametry:

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

Zaktualizuj implementację LLM

Zmodyfikuj kod własnego LLM, aby obsługiwał dodatkowe parametry:

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)

Przykładowe żądanie

Przy takiej konfiguracji własnej wiadomości LLM otrzyma żądania w tym formacie:

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