Speech Engine 快速入门

使用 ElevenLabs SDK 为聊天智能体添加语音功能。

本指南将带你使用 Speech Engine 构建语音智能体。首先设置服务器,将 LLM 连接到 ElevenLabs;然后接入浏览器客户端,让用户能与你的智能体进行语音对话。

使用 ElevenLabs Speech Engine skill 为聊天智能体添加语音功能:

npx skills add elevenlabs/skills --skill speech-engine

Speech Engine 的工作原理

Speech Engine 将 LLM 连接到 ElevenLabs,让用户能与智能体对话并听到回应。ElevenLabs 负责语音转文本和文本转语音;服务器提供 LLM 逻辑。

每个 WebSocket 连接代表一段对话。用户说话时,ElevenLabs 会转录音频并将转录文本发送到服务器。服务器将其传给 LLM,再将响应流式传回。ElevenLabs 会将文本转为语音并在浏览器中播放。SDK 负责连接管理、轮次管理和打断检测。

前提条件

本教程使用 OpenAI 的 API 作为 LLM。需要在 OPENAI_API_KEY 环境变量中设置 OpenAI API 密钥。

服务器设置

1

创建 API 密钥

在控制台创建 API 密钥,用于安全地访问 API。

将密钥存储为托管密钥,并根据需要通过 .env 文件将其作为环境变量传递给 SDK,或直接在应用配置中设置。

.env
ELEVENLABS_API_KEY=<your_api_key_here>
2

安装依赖

pip install elevenlabs openai python-dotenv
3

公开服务器

Speech Engine 需要可从公网访问的 URL。使用 ngrok 公开本地服务器。服务器尚未构建完成,但 ngrok 必须先运行,以便获取下一步所需的 URL。

ngrok http 3001

复制转发 URL(例如 https://abc123.ngrok.io)。

4

创建 Speech Engine 实例

使用 SDK 创建 Speech Engine 实例,并将附加 /ws 路径的 ngrok URL 作为 WebSocket URL 传入。

import asyncio
from dotenv import load_dotenv
from elevenlabs import AsyncElevenLabs
load_dotenv()
elevenlabs = AsyncElevenLabs(
api_key=os.getenv("ELEVENLABS_API_KEY"),
)
async def main():
engine = await elevenlabs.speech_engine.create(
name="My Speech Engine",
speech_engine={
# Note we use the wss protocol instead of https
"ws_url": "wss://abc123.ngrok.io/ws",
},
)
print(f"Speech Engine ID: {engine.engine_id}")
if __name__ == "__main__":
asyncio.run(main())

运行此脚本,并复制 Speech Engine ID(例如 seng_8k3m9xr4hjnfg983brhmhkd98n6),供下一步使用。

5

创建服务器

创建名为 server.py 或 server.mts 的文件,并填入以下内容。这会设置服务器,将 Speech Engine 挂载到 /ws 路径,并使用 OpenAI 生成响应。

import asyncio
import os
from dotenv import load_dotenv
from openai import AsyncOpenAI
from elevenlabs import AsyncElevenLabs
load_dotenv()
# Replace with your Speech Engine ID from step 4
SPEECH_ENGINE_ID = "seng_8k3m9xr4hjnfg983brhmhkd98n6"
openai = AsyncOpenAI(
api_key=os.getenv("OPENAI_API_KEY"),
)
elevenlabs = AsyncElevenLabs(
api_key=os.getenv("ELEVENLABS_API_KEY"),
)
def on_init(conversation_id, session):
print(f"Session started: {conversation_id}")
async def on_transcript(transcript, session):
stream = await openai.responses.create(
model="gpt-4o",
instructions="You are a helpful voice assistant. Keep responses concise and conversational.",
input=[
{"role": "assistant" if m.role == "agent" else m.role, "content": m.content}
for m in transcript
],
stream=True,
)
await session.send_response(stream)
def on_close(session):
print(f"Session ended: {session.conversation_id}")
def on_error(err, session):
print(f"Error: {err}")
async def main():
engine = await elevenlabs.speech_engine.get(SPEECH_ENGINE_ID)
await engine.serve(
port=3001,
path="/ws",
debug=True,
on_init=on_init,
on_transcript=on_transcript,
on_close=on_close,
on_error=on_error,
)
if __name__ == "__main__":
asyncio.run(main())

onTranscript / on_transcript 回调会接收完整对话历史和当前会话。TypeScript SDK 还提供 AbortSignal,用户在响应过程中打断时会触发。将 signal 传给 OpenAI 调用,可在打断时自动取消 LLM 请求。

sendResponse() / send_response() 接受字符串、异步可迭代对象,或来自 OpenAI、Anthropic 或 Google Gemini 的流。SDK 会自动提取文本内容。

在上述示例中,用户的完整转录文本会传给 LLM。生产环境中应添加护栏,防范提示词注入或操纵尝试。

6

启动服务器

python server.py

客户端设置

1

安装客户端 SDK

npm install @elevenlabs/react
2

创建令牌端点

添加一个服务端端点来生成对话令牌。这样可避免将 API 密钥暴露在浏览器中,并使用 WebRTC 获得最佳音频质量。

import os
from dotenv import load_dotenv
from flask import Flask, jsonify
from elevenlabs import ElevenLabs
load_dotenv()
app = Flask(__name__)
elevenlabs = ElevenLabs(
api_key=os.getenv("ELEVENLABS_API_KEY"),
)
@app.route("/api/token")
def get_token():
# Replace with your Speech Engine ID from step 4 of the server setup
speech_engine_id = "seng_8k3m9xr4hjnfg983brhmhkd98n6"
response = elevenlabs.conversational_ai.conversations.get_webrtc_token(
agent_id=speech_engine_id,
)
return jsonify(token=response.token)
if __name__ == "__main__":
app.run(port=3002)
3

构建对话 UI

从服务器获取对话令牌,并用它启动会话。

App.tsx
import { useConversation } from "@elevenlabs/react";
import { useCallback } from "react";
async function getToken(): Promise<string> {
const response = await fetch("/api/token");
if (!response.ok) {
throw Error("Failed to get conversation token");
}
const data = await response.json();
return data.token;
}
export default function App() {
const conversation = useConversation({
onConnect: () => console.log("Connected"),
onDisconnect: () => console.log("Disconnected"),
onError: (error: Error) => console.error("Error:", error),
});
const startConversation = useCallback(async () => {
await navigator.mediaDevices.getUserMedia({ audio: true });
const token = await getToken();
await conversation.startSession({ conversationToken: token });
}, [conversation]);
const stopConversation = useCallback(async () => {
await conversation.endSession();
}, [conversation]);
return (
<div>
<p>Status: {conversation.status}</p>
<button onClick={startConversation} disabled={conversation.status === "connected"}>
Start conversation
</button>
<button onClick={stopConversation} disabled={conversation.status !== "connected"}>
End conversation
</button>
</div>
);
}
4

试用

确保以下 3 个进程正在运行:

  1. ngrok - 转发到端口 3001
  2. Speech Engine 服务器 - python server.py 或 npx tsx server.mts
  3. 令牌服务器 - npx tsx token-server.mts 或 python token_server.py

在浏览器中打开客户端应用,然后点击 开始对话。出现提示时授予麦克风访问权限,然后开始说话。你应该会通过扬声器听到智能体的回应。

如果服务器启用了 debug: true,控制台会记录传入的转录文本和传出的响应。

会话事件

事件TypeScript 回调Python 回调说明
user_transcriptonTranscripton_transcript已转录用户语音。包含完整对话历史和中止信号。
initonIniton_init会话已使用对话 ID 初始化。
closeonCloseon_close已与 ElevenLabs 正常断开连接。
disconnectedonDisconnecton_disconnectWebSocket 意外断开。
erroronErroron_error协议或 WebSocket 错误。

配置智能体的首条消息

默认情况下,智能体会等待用户先说话。要让智能体在对话开始时问候用户,请在客户端启动会话时的 overrides 选项中设置首条消息。

1

要让智能体先说话,需要更新 Speech Engine 资源,允许从客户端进行此设置。

engine = await elevenlabs.speech_engine.update(
speech_engine_id="seng_8k3m9xr4hjnfg983brhmhkd98n6",
overrides={
"first_message": True,
},
)
2

然后在客户端 SDK 中配置首条消息。

conversation.startSession({
conversationToken: token,
overrides: {
agent: {
firstMessage: "Hello! How can I help you today?",
},
},
});

连接建立后,智能体会立即说出首条消息。它不会触发服务器上的 onTranscript 回调——完全由 ElevenLabs 端处理。

后续步骤