Przejdź do nawigacji

Zintegruj 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

Custom LLMs pozwala użyć własnego klucza API OpenAI lub uruchomić całkowicie własny serwer LLM.

Custom LLM nie może być używany z modelem Realtime.

Omówienie

Domyślnie używamy własnych wewnętrznych danych uwierzytelniających do popularnych modeli, takich jak OpenAI. Aby użyć własnego serwera LLM, musi on obsługiwać jedną z poniższych struktur żądań i odpowiedzi zgodnych z OpenAI:

Responses API to nowszy format API OpenAI, który obsługuje dodatkowe funkcje. Oba formaty API są w pełni obsługiwane w integracji z Custom LLM.

Poniższe przewodniki obejmują oba zastosowania:

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

Dowiesz się, jak:

  • Zapisać klucz API OpenAI w ElevenLabs
  • Hostować serwer odwzorowujący endpoint Chat Completions lub Responses 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 Reasoning summary w ustawieniach LLM agenta lub ustaw enable_reasoning_summary przez API.

Zwracanie rozumowania

Użyj formatu zgodnego z endpointem:

Strumieniuj rozumowanie w polu reasoning lub reasoning_content każdego delta odpowiedzi.

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

Informacje o przechowywaniu, dostarczaniu i ograniczeniach znajdziesz w Reasoning summary.

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 adres URL serwera i ID modelu własnego serwera LLM.

Wpisz adres URL

4

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

5

Kliknij przycisk „x”, aby zamknąć okno LLM, a następnie 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 zaimplementować 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ę 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 własny kod serwera.

Konfigurowanie publicznego adresu URL serwera

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

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

Konfigurowanie CustomLLM w ElevenLabs

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

Ustaw adres URL serwera na endpoint ngrok i wartość „Limit token usage” na 5000.

Możesz teraz rozpocząć interakcję z agentem korzystającym z własnego serwera LLM.

Optymalizacja dla wolno działających LLM-ów

Jeśli twój własny LLM działa wolno (na przykład ze względu na rozumowanie agentowe lub wymagania dotyczące wstępnego przetwarzania), możesz poprawić płynność rozmowy, stosując słowa buforujące w odpowiedziach strumieniowanych. 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ę "... " (wielokropkiem ze spacją). Dzięki temu system Text to Speech może zachować naturalny rytm, a rozmowa pozostaje dynamiczna. Tworzy to naturalne pauzy, które płynnie przechodzą w kolejne treści, nad którymi LLM może dłużej się zastanawiać. Dodatkowa spacja jest kluczowa, aby kolejne treści nie zostały dołączone do „…”, co może powodować zniekształcenia dźwięku.

Implementacja

Tak zmodyfikujesz serwer własnego LLM-a, aby stosował słowa buforujące:

@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. Po skonfigurowaniu w agencie narzędzia te są automatycznie uwzględniane w parametrze tools żądań ukończenia czatu.

Jak działają narzędzia systemowe

  1. Decyzja LLM-a: 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 backendowe: 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, gdy zostaną spełnione odpowiednie warunki.

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

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

Parametry:

  • reason (ciąg znaków, wymagany): Powód zakończenia rozmowy
  • message (ciąg znaków, 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 zakończenia rozmowy

Cel: Automatyczne przełączanie na wykryty język użytkownika podczas rozmów.

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

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

Parametry:

  • reason (ciąg znaków, wymagany): Powód zmiany języka
  • language (ciąg znaków, wymagany): Kod języka, na który należy przełączyć (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 dopasuje głos i odpowiedzi do wykrytego języka.

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

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

Warunki uruchomienia: 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 (ciąg znaków, opcjonalny): Powód przekazania do agenta
  • agent_number (liczba całkowita, wymagany): Numer indeksowany od zera agenta, do którego należy przekazać rozmowę (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 może przekazywać rozmowy bieżący agent. Agenci są oznaczani numerami indeksowanymi od zera w konfiguracji przekazywania.

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

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

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

  • Występują złożone problemy wymagające ludzkiego osądu
  • Użytkownik wyraźnie prosi o pomoc człowieka
  • AI osiąga granice swoich możliwości w danym zapytaniu
  • Zostają uruchomione procedury eskalacji

Parametry:

  • reason (ciąg znaków, opcjonalny): Powód przekazania
  • transfer_number (ciąg znaków, wymagany): Numer telefonu, na który należy przekazać rozmowę (musi odpowiadać skonfigurowanym numerom)
  • client_message (ciąg znaków, wymagany): Komunikat odczytywany klientowi podczas oczekiwania na przekazanie
  • agent_message (ciąg znaków, wymagany): Komunikat dla ludzkiego 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 komunikaty zarówno dla klienta, jak i odbierającego rozmowę operatora. Działa z Twilio i SIP trunkingiem.

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

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

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

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

Parametry:

  • reason (ciąg znaków, 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, aby zachował ciszę, dopóki użytkownik nie odezwie się ponownie.

Dowiedz się więcej: Narzędzie 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 wykrywania poczty głosowej

Przykładowe żądanie z narzędziami systemowymi

Gdy narzędzia systemowe są skonfigurowane, twój własny LLM otrzyma żądania zawierają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ć poprawne odpowiedzi wywołań funkcji w formacie OpenAI.

Dodatkowe funkcje

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

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

Zmodyfikuj kod własnego LLM-a, 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 tej konfiguracji własnych wiadomości twój 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"
}
}