1. 基础语音代理示例
1.1 简单语音助手
import logging
from dotenv import load_dotenv
from livekit.agents import (
Agent,
AgentSession,
JobContext,
RunContext,
WorkerOptions,
cli,
function_tool,
)
from livekit.plugins import deepgram, elevenlabs, openai, silero
load_dotenv()
logger = logging.getLogger("basic-agent")
class MyAgent(Agent):
"""
基础语音代理类
功能说明:
- 继承自Agent基类,提供语音交互能力
- 支持自定义指令和工具函数
- 自动处理用户输入和生成响应
"""
def __init__(self) -> None:
super().__init__(
instructions=(
"你的名字是Kelly。你通过语音与用户交互。"
"请保持回复简洁明了。"
"不要使用表情符号、星号、markdown或其他特殊字符。"
"你很好奇、友好,有幽默感。"
"你会用英语与用户交流"
),
)
async def on_enter(self):
"""
代理进入会话时的回调函数
功能说明:
- 当代理被添加到会话时自动调用
- 根据代理指令生成初始回复
- 启动与用户的对话流程
"""
self.session.generate_reply()
@function_tool
async def lookup_weather(
self,
context: RunContext,
location: str,
latitude: str,
longitude: str
):
"""
天气查询工具函数
参数说明:
- context: 运行时上下文,包含会话状态和用户数据
- location: 用户询问的地点名称
- latitude: 地点的纬度坐标(由LLM自动估算)
- longitude: 地点的经度坐标(由LLM自动估算)
返回值:
- str: 天气信息描述
使用场景:
当用户询问天气相关信息时被LLM自动调用
"""
logger.info(f"查询{location}的天气信息")
# 这里可以调用真实的天气API
# 示例返回固定值
return "今天天气晴朗,温度70华氏度。"
async def entrypoint(ctx: JobContext):
"""
应用程序入口点函数
参数说明:
- ctx: 任务上下文,包含房间连接和配置信息
功能说明:
- 配置并启动代理会话
- 设置语音组件(STT、LLM、TTS、VAD)
- 建立与LiveKit房间的连接
"""
# 设置日志上下文字段
ctx.log_context_fields = {
"room": ctx.room.name,
}
# 创建代理会话,配置各个组件
session = AgentSession(
vad=silero.VAD.load(), # 语音活动检测
llm=openai.LLM(model="gpt-4o-mini"), # 大语言模型
stt=deepgram.STT(model="nova-3"), # 语音转文本
tts=elevenlabs.TTS(), # 文本转语音
preemptive_generation=True, # 预先生成响应
resume_false_interruption=True, # 恢复错误中断
)
# 启动会话
await session.start(
agent=MyAgent(),
room=ctx.room,
)
if __name__ == "__main__":
# 运行应用程序
cli.run_app(WorkerOptions(entrypoint_fnc=entrypoint))
1.2 运行方式
# 开发模式 - 支持热重载
python basic_agent.py dev
# 控制台测试模式 - 终端音频测试
python basic_agent.py console
# 生产模式 - 稳定运行
python basic_agent.py start
2. 动态工具创建示例
2.1 三种工具创建方式
import logging
import random
from enum import Enum
from typing import Literal
from pydantic import BaseModel
from livekit.agents import (
Agent,
AgentSession,
ChatContext,
FunctionTool,
JobContext,
ModelSettings,
function_tool,
)
class DynamicToolAgent(Agent):
"""
动态工具创建代理
功能说明:
- 演示三种不同的工具创建方式
- 支持运行时动态添加和修改工具
- 展示工具的灵活使用模式
"""
def __init__(self, instructions: str, tools: list[FunctionTool]) -> None:
super().__init__(instructions=instructions, tools=tools)
async def llm_node(
self,
chat_ctx: ChatContext,
tools: list[FunctionTool],
model_settings: ModelSettings
):
"""
自定义LLM节点处理函数
参数说明:
- chat_ctx: 聊天上下文,包含对话历史
- tools: 当前可用的工具列表
- model_settings: 模型设置参数
功能说明:
- 方式3:为本次调用临时添加工具
- 在不修改代理配置的情况下动态扩展功能
"""
# 方式3: 为本次LLM调用添加临时工具
async def _get_weather(location: str) -> str:
"""临时天气查询工具"""
return f"{location}的天气是晴天。"
# 将临时工具添加到工具列表
tools.append(
function_tool(
_get_weather,
name="get_weather",
description="获取指定地点的天气信息",
)
)
# 调用默认的LLM节点处理
return Agent.default.llm_node(self, chat_ctx, tools, model_settings)
async def _get_course_list_from_db() -> list[str]:
"""
模拟数据库查询函数
返回值:
- list[str]: 课程列表
功能说明:
在实际应用中,这里应该连接真实的数据库
"""
return [
"应用数学",
"数据科学",
"机器学习",
"深度学习",
"语音代理",
]
async def entrypoint(ctx: JobContext):
"""动态工具创建示例入口点"""
# 方式1: 代理创建时定义工具
courses = await _get_course_list_from_db()
# 动态创建枚举类型(LLM会自动识别)
CourseType = Enum("CourseType", {c.replace(" ", "_"): c for c in courses})
# 使用Pydantic模型定义复杂参数类型
class CourseInfo(BaseModel):
"""
课程信息模型
属性说明:
- course: 课程类型,从动态枚举中选择
- location: 上课方式,在线或面授
"""
course: CourseType # type: ignore
location: Literal["online", "in-person"]
async def _get_course_info(info: CourseInfo) -> str:
"""
获取课程信息工具函数
参数说明:
- info: 课程信息对象,包含课程类型和地点
返回值:
- str: 课程详细信息
"""
logger.info(f"get_course_info调用: {info}")
return f"想象一下关于{info.course}的课程。"
# 创建代理,初始化时包含基础工具
agent = DynamicToolAgent(
instructions="你是一个有用的助手,可以回答问题并帮助完成任务。",
tools=[
function_tool(
_get_course_info,
name="get_course_info",
description="获取课程信息",
)
],
)
# 方式2: 代理创建后使用update_tools()更新工具
async def _random_number() -> int:
"""
随机数生成工具
返回值:
- int: 0-100之间的随机整数
"""
num = random.randint(0, 100)
logger.info(f"random_number调用: {num}")
return num
# 更新代理工具集,添加新工具
await agent.update_tools(
agent.tools + [
function_tool(
_random_number,
name="random_number",
description="生成随机数"
)
]
)
# 创建并启动会话
session = AgentSession(
vad=silero.VAD.load(),
stt=openai.STT(use_realtime=True),
llm=openai.LLM(model="gpt-4o-mini"),
tts=openai.TTS(),
)
await session.start(agent, room=ctx.room)
3. 实时API集成示例
3.1 OpenAI Realtime API
from livekit.agents import Agent, AgentSession, JobContext
from livekit.plugins import openai
class RealtimeAgent(Agent):
"""
实时API代理
功能说明:
- 使用OpenAI的实时API进行低延迟对话
- 支持流式音频处理
- 提供更自然的对话体验
"""
def __init__(self) -> None:
super().__init__(
instructions="你是一个友好的语音助手。",
# 使用实时模型替代传统的LLM + TTS组合
llm=openai.realtime.RealtimeModel(
voice="coral", # 语音类型
temperature=0.8, # 创造性参数
max_response_output_tokens=4096, # 最大输出长度
),
)
async def on_enter(self):
"""代理进入时生成欢迎消息"""
await self.session.generate_reply(
instructions="向用户问好并提供帮助。"
)
async def entrypoint(ctx: JobContext):
"""实时API示例入口点"""
# 使用实时API时,不需要单独配置STT和TTS
session = AgentSession(
# 实时模型已包含语音处理能力
llm=openai.realtime.RealtimeModel(voice="coral")
)
await session.start(
agent=RealtimeAgent(),
room=ctx.room,
)
4. 多代理切换示例
4.1 代理切换机制
from livekit.agents import Agent, AgentSession, JobContext, RunContext
from livekit.agents.llm import function_tool
from livekit.plugins import openai, silero, deepgram
class IntroAgent(Agent):
"""
介绍代理 - 收集用户信息
功能说明:
- 作为对话的入口点
- 收集用户的基本信息
- 完成后切换到其他专门代理
"""
def __init__(self) -> None:
super().__init__(
instructions=(
"你是一个故事讲述者。你的目标是收集一些用户信息"
"来让故事个性化和引人入胜。询问用户的姓名和来自哪里。"
)
)
async def on_enter(self):
"""进入时开始收集信息"""
await self.session.generate_reply(
instructions="问候用户并收集信息"
)
@function_tool
async def information_gathered(
self,
context: RunContext,
name: str,
location: str,
):
"""
信息收集完成工具
参数说明:
- context: 运行时上下文
- name: 用户姓名
- location: 用户所在地
返回值:
- tuple: (下一个代理, 切换消息)
功能说明:
当收集到足够信息时,切换到故事代理
"""
# 保存用户数据到上下文
context.userdata.name = name
context.userdata.location = location
# 创建并返回下一个代理
story_agent = StoryAgent(name, location)
return story_agent, "让我们开始故事吧!"
class StoryAgent(Agent):
"""
故事代理 - 讲述个性化故事
功能说明:
- 使用收集的用户信息
- 讲述个性化故事
- 可以切换到实时API获得更好的体验
"""
def __init__(self, name: str, location: str) -> None:
super().__init__(
instructions=(
f"你是一个故事讲述者。使用用户信息让故事个性化。"
f"用户名字是{name},来自{location}。"
),
# 切换到实时模型获得更好的语音体验
llm=openai.realtime.RealtimeModel(voice="echo"),
)
async def on_enter(self):
"""进入时开始讲故事"""
await self.session.generate_reply()
@dataclass
class StoryData:
"""用户故事数据结构"""
name: str | None = None
location: str | None = None
async def entrypoint(ctx: JobContext):
"""多代理切换示例入口点"""
# 创建用户数据对象
userdata = StoryData()
# 创建支持用户数据的会话
session = AgentSession[StoryData](
vad=silero.VAD.load(),
stt=deepgram.STT(model="nova-3"),
llm=openai.LLM(model="gpt-4o-mini"),
tts=openai.TTS(voice="echo"),
userdata=userdata,
)
# 从介绍代理开始
await session.start(
agent=IntroAgent(),
room=ctx.room,
)
5. 工具函数高级用法
5.1 参数类型注解
from enum import Enum
from typing import Annotated, Literal
from livekit.agents import Agent, function_tool
class RoomName(str, Enum):
"""房间名称枚举"""
LIVING_ROOM = "living_room"
BEDROOM = "bedroom"
KITCHEN = "kitchen"
GARAGE = "garage"
class AdvancedToolAgent(Agent):
"""高级工具使用代理"""
def __init__(self) -> None:
super().__init__(
instructions="你是一个智能家居控制助手。"
)
@function_tool
async def control_light(
self,
room: RoomName, # 枚举类型参数
action: Literal["on", "off", "dim"], # 字面量类型
brightness: Annotated[int, "亮度 (0-100)"] = 100, # 带注解的参数
):
"""
智能灯光控制工具
参数说明:
- room: 房间名称,从预定义枚举中选择
- action: 操作类型,开启/关闭/调暗
- brightness: 亮度级别,0-100之间的整数
返回值:
- str: 操作结果描述
"""
if action == "on":
return f"{room.value}的灯已开启,亮度{brightness}%"
elif action == "off":
return f"{room.value}的灯已关闭"
else: # dim
return f"{room.value}的灯已调暗到{brightness}%"
@function_tool
async def get_number_info(
self,
value: Annotated[float, "数值参数,支持小数"]
):
"""
数值信息获取工具
功能说明:
- 展示如何使用Annotated类型提供参数说明
- LLM可以理解参数的具体含义和约束
"""
return f"数值是{value}。"
5.2 静默工具调用
from livekit.agents import Agent, FunctionToolsExecutedEvent, function_tool
class SilentToolAgent(Agent):
"""
静默工具调用代理
功能说明:
- 演示如何执行不生成回复的工具函数
- 控制何时生成语音响应
- 适用于后台操作和状态更新
"""
def __init__(self) -> None:
super().__init__(
instructions="你是一个语音代理。当用户要求开灯时调用turn_on_light函数。"
)
self.light_on = False
@function_tool
async def turn_on_light(self):
"""
开灯工具 - 静默执行
功能说明:
- 没有返回值的工具不会自动生成回复
- 适用于后台状态更新操作
"""
self.light_on = True
logger.info("灯已开启")
# 没有返回值,不会生成语音回复
@function_tool
async def turn_off_light(self):
"""
关灯工具 - 生成回复
功能说明:
- 有返回值的工具会自动生成语音回复
- 用户会听到确认消息
"""
self.light_on = False
logger.info("灯已关闭")
return "灯已关闭" # 有返回值,会生成语音
async def on_function_tools_executed(self, event: FunctionToolsExecutedEvent):
"""
工具执行后的事件处理
参数说明:
- event: 工具执行事件,包含执行结果
功能说明:
- 可以在此处决定是否取消自动回复
- 实现复杂的回复控制逻辑
"""
# 如果需要,可以取消工具回复
# event.cancel_tool_reply()
pass
6. 环境配置
6.1 环境变量设置
# .env文件内容
# OpenAI配置
OPENAI_API_KEY=your_openai_api_key
# Deepgram配置
DEEPGRAM_API_KEY=your_deepgram_api_key
# ElevenLabs配置
ELEVEN_API_KEY=your_eleven_api_key
# LiveKit配置
LIVEKIT_URL=wss://your-livekit-server.com
LIVEKIT_API_KEY=your_livekit_api_key
LIVEKIT_API_SECRET=your_livekit_api_secret
6.2 依赖安装
# 安装核心库和常用插件
pip install "livekit-agents[openai,silero,deepgram,elevenlabs,turn-detector]~=1.0"
# 或者分别安装
pip install livekit-agents
pip install livekit-plugins-openai
pip install livekit-plugins-deepgram
pip install livekit-plugins-elevenlabs
pip install livekit-plugins-silero
7. 调试和监控
7.1 日志配置
import logging
from livekit.agents import JobContext, metrics, MetricsCollectedEvent
# 配置日志级别
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger("my-agent")
async def entrypoint(ctx: JobContext):
# 设置日志上下文
ctx.log_context_fields = {
"room": ctx.room.name,
"user_id": "user_123",
}
# 使用指标收集器
usage_collector = metrics.UsageCollector()
@session.on("metrics_collected")
def _on_metrics_collected(ev: MetricsCollectedEvent):
"""
指标收集事件处理
功能说明:
- 实时记录和显示性能指标
- 收集使用统计信息
- 支持自定义监控逻辑
"""
metrics.log_metrics(ev.metrics)
usage_collector.collect(ev.metrics)
async def log_usage():
"""记录使用统计"""
summary = usage_collector.get_summary()
logger.info(f"使用统计: {summary}")
# 注册关闭回调
ctx.add_shutdown_callback(log_usage)
7.2 错误处理
from livekit.agents.llm import ToolError, StopResponse
@function_tool
async def risky_operation(param: str):
"""
可能出错的操作示例
功能说明:
- 演示工具函数中的错误处理
- 使用专门的异常类型
"""
try:
# 执行可能失败的操作
result = perform_operation(param)
return result
except ValueError as e:
# 抛出ToolError,LLM可以看到错误信息
raise ToolError(f"参数错误: {e}")
except Exception as e:
# 严重错误时停止响应
logger.error(f"操作失败: {e}")
raise StopResponse()
这些示例展示了LiveKit Agents框架的核心用法和高级特性。每个示例都包含详细的注释和说明,帮助开发者理解框架的工作原理和最佳实践。