LiveKit
@mastra/livekit 软件包将 Mastra Agent 连接到 LiveKit Agents 框架。LiveKit 运行音频管线(语音活动检测、语音转文本、轮次检测、文本转语音和插话打断),该软件包则将响应生成桥接到 Mastra Agent 的 stream() 调用。
有关设置和相关概念,请参阅 实时 Voice。
该软件包有三个入口点:
@mastra/livekit:服务端 API,包括liveKitConnectionRoute()、dispatchVoiceSession()、pipeAgentReplyToWriter()、serializeSessionMetadata()和createEndCallTool()。 请从 Mastra 服务端代码导入这些 API。此入口绝不会加载 LiveKit Agents runtime。@mastra/livekit/worker:worker runtime,包括createLiveKitWorker()、runLiveKitWorker()、chatContextToMessages(),以及 session helperspeakGreeting()、waitForAgentDoneSpeaking()和runEndCall()。 仅从 worker 入口文件导入。@mastra/livekit/plugin:LLM 组件插件,包括MastraLLM和createRemoteAgentReplyGenerator()。 请在自行构建voice.AgentSession的 worker 中导入。createRemoteAgentReplyGenerator()也从@mastra/livekit/worker导出,因为它可接入createLiveKitWorker()的generate选项。MastraLLM仅由 plugin 导出。
createLiveKitWorker()createlivekitworker的直接链接
构建使用 Mastra Agent 响应语音 session 的 LiveKit Agent 定义。请将它作为 worker 入口文件的默认导出。
import { fileURLToPath } from 'node:url'
import { createLiveKitWorker, runLiveKitWorker } from '@mastra/livekit/worker'
import { mastra } from './index'
export default createLiveKitWorker({
mastra,
agent: 'support',
stt: 'deepgram/nova-3',
tts: 'cartesia/sonic-3',
turnDetection: 'multilingual',
})
if (process.argv[1] === fileURLToPath(import.meta.url)) {
runLiveKitWorker({ entry: import.meta.url, agentName: 'mastra-voice' })
}
选项选项的直接链接
mastra:
agent?:
workflow?:
workflowInput?:
replyStep?:
resultText?:
generate?:
stt?:
tts?:
vad?:
turnDetection?:
turnHandling?:
sessionOptions?:
memory?:
toolFeedback?:
onTurnComplete?:
configuration?:
greeting?:
consentPolicy?:
endCall?:
stt?:
tts?:
greeting?:
persistGreeting?:
observability?:
voice call span:每个轮次的 Agent 运行嵌套其下,LiveKit 的 STT、TTS、语句结束、VAD 和 LLM 延迟指标成为子 span,最后以按模型汇总的用量关闭该 span。传入 false 可禁用。inputOptions?:
outputOptions?:
onSessionStart?:
runLiveKitWorker()runlivekitworker的直接链接
为 worker 入口文件启动 LiveKit worker CLI(dev、start 和 connect 子命令)。请从默认导出 worker 定义的文件中调用,并添加保护,确保仅在直接执行时运行(worker 会为每个 session 生成一个重新导入同一文件的子进程)。使用 cli.runApp(来自 @livekit/agents)之外的此 helper,可确保 worker runtime 与桥接共享同一份 LiveKit SDK。
选项选项的直接链接
entry:
agentName?:
serverOptions?:
pipeAgentReplyToWriter()pipeagentreplytowriter的直接链接
在 Workflow 响应路径上,将 Mastra Agent 的响应流式传输到 Workflow step 的 writer。它会转发 Agent 的文本增量,使文本转语音可在完整响应就绪前开始;还会转发 Tool 调用分块,从而触发 toolFeedback 并让 onTurnComplete 获取 Tool 列表。仅管道传输 stream.textStream 会静默丢弃 Tool 调用。请将 step 的 abortSignal 传给 agent.stream(),以便插话打断能立即停止生成。
import { pipeAgentReplyToWriter } from '@mastra/livekit'
const generateResponse = createStep({
id: 'generateResponse',
// input and output schemas omitted
execute: async ({ inputData, mastra, writer, abortSignal }) => {
const stream = await mastra.getAgent('support').stream(inputData.turn, { abortSignal })
const reply = await pipeAgentReplyToWriter(stream, writer)
return { reply }
},
})
返回: Promise<string>, 即累积的响应文本。
参数参数的直接链接
agentStream:
writer:
chatContextToMessages()chatcontexttomessages的直接链接
将 LiveKit chat context 转换为 agent.stream() 接受的普通消息,不包括指令和函数调用。在 workflowInput 中使用它,可将完整转写传入无状态 Workflow。
import { createLiveKitWorker, chatContextToMessages } from '@mastra/livekit/worker'
export default createLiveKitWorker({
mastra,
workflow: 'phoneConversation',
workflowInput: ({ chatCtx }) => ({ history: chatContextToMessages(chatCtx) }),
})
返回: VoiceTurnMessage[], 其中每个条目为 { role: 'system' | 'user' | 'assistant'; content: string; id?: string }.
MastraLLMmastrallm的直接链接
由 Mastra Agent 支持的标准 LiveKit LLM plugin(llm.LLM)。当你自行构建 voice.AgentSession 并希望在 llm 槽位使用 Mastra 时,请使用它。createLiveKitWorker() 是托管式替代方案。有关如何选择,请参阅将 Mastra 用作 LLM 组件。
使用 remote 时,plugin 通过 HTTP 使用服务器发送事件(SSE)从 Mastra 服务端流式传输每个轮次。Agent 循环、Tool 和 Memory 在服务端运行;中断 Agent 会中止服务端生成。
import { voice } from '@livekit/agents'
import { MastraLLM } from '@mastra/livekit/plugin'
const session = new voice.AgentSession({
llm: new MastraLLM({
remote: { baseUrl: process.env.MASTRA_URL!, agentId: 'support' },
memory: { thread: callId, resource: userId },
}),
stt: 'deepgram/nova-3',
tts: 'cartesia/sonic-3',
// Required with `memory`: LiveKit enables preemptive generation by default.
turnHandling: { preemptiveGeneration: { enabled: false } },
})
plugin 将 provider 报告为 mastra,将 model 报告为 Agent ID,因此 LiveKit 指标和 fallback adapter 会像识别其他 LLM 一样识别它。
构造函数选项构造函数选项的直接链接
仅提供一个响应来源:remote、agent 或 generate。
remote?:
agent?:
generate?:
memory?:
requestContext?:
toolFeedback?:
onToolCall?:
onTurnComplete?:
不要将 memory 与 session 的 preemptiveGeneration 选项结合使用;在自行构建的 session 中,LiveKit 默认启用该选项。如果推测轮次在 LiveKit 丢弃前完成,会在 thread 中持久化一条用户消息和一条从未播报的响应。请在 session 上设置 turnHandling: { preemptiveGeneration: { enabled: false } }。无状态模式(不使用 memory)可与抢先生成配合使用。
Tool 在 Mastra Agent 上运行Tool 在 Mastra Agent 上运行的直接链接
Tool 在服务端的 Mastra Agent 上定义并执行。plugin 绝不会转发 LiveKit Tool 定义:如果 session 传入非空 toolCtx,它会记录一次警告,列出被忽略的 Tool。每个 Tool 都必须在服务端完成;需要批准或客户端执行的 Tool 会让轮次以描述性错误失败,而不是使通话卡住。
Tool 活动通过 toolFeedback、onToolCall 和 onTurnComplete 传递到 worker。
指令指令的直接链接
LiveKit 会将 voice.Agent 的 instructions 注入每个请求的 chat context。plugin 会丢弃这些指令,因为服务端 Mastra Agent 自身的指令才是权威来源。若要更改提示词,请更改 Mastra Agent。
中断的轮次中断的轮次的直接链接
当用户中断响应时:
- plugin 会取消流。服务端会中止生成,并且不会持久化该轮次的任何内容。
- LiveKit 会在 chat context 中记录用户实际听到的部分,并将其标记为 interrupted。
- 下一轮中,plugin 会在新用户消息前重新发送该仅包含已听内容的片段,使 Memory thread 回填到与通话一致。消息携带 LiveKit 消息 ID,服务端会按 ID 去重,因此重试和重新发送保持幂等。
如果用户在中断后立即挂断,最后的片段不会被记录。如果转写必须捕获该片段,请立即根据 session 事件进行协调;共享的消息 ID 意味着下一轮重新发送时会 upsert,而不会重复:
import { voice } from '@livekit/agents'
import { MastraClient } from '@mastra/client-js'
const client = new MastraClient({ baseUrl: process.env.MASTRA_URL! })
session.on(voice.AgentSessionEventTypes.ConversationItemAdded, ({ item }) => {
if (item.type !== 'message' || item.role !== 'assistant' || !item.interrupted) return
void client.saveMessageToMemory({
agentId: 'support',
messages: [
{
id: item.id,
threadId: callId,
resourceId: userId,
role: 'assistant',
content: item.textContent ?? '',
type: 'text',
createdAt: new Date(),
},
],
})
})
使用量指标使用量指标的直接链接
服务端报告轮次的 token 用量时,plugin 会将其提供给 LiveKit,因此 session 的 metrics_collected 事件会像其他 LLM plugin 一样包含首 token 时间、持续时间和 token 数。同一个 usage 对象(promptTokens、completionTokens、promptCachedTokens、totalTokens)会在 onTurnComplete 中作为 result.usage 到达。
错误和超时错误和超时的直接链接
传输层会抛出 LiveKit 的 APIError 类型(APIStatusError、APIConnectionError、APITimeoutError),因此 session 的重试策略(connOptions.maxRetry)和 FallbackAdapter 故障转移可保持不变。轮次在生成首个 token 后绝不会重试:语音响应快速失败比重播用户只听到一半的内容更合适。
连接和首 token watchdog 使用 session 的 connOptions.timeoutMs(默认 10 秒),因此接受连接但始终不传输内容的服务端不会造成无限期静音。
如果 Mastra 服务端在通话期间宕机,每次响应尝试会在重试后以强类型错误失败;连续数次响应失败后,LiveKit 会关闭 session。在该额度用尽前恢复服务端,通话将在下一轮恢复。
消息内容消息内容的直接链接
消息提取仅处理文本:图像内容会被丢弃,音频内容仅通过其转写文本包含。语音管线不受影响,但你自行注入 chat context 的项目必须包含文本。
createRemoteAgentReplyGenerator()createremoteagentreplygenerator的直接链接
构建一个通过 HTTP/SSE 在远程 Mastra 服务端运行 Agent 循环的响应生成器。MastraLLM 的 remote 模式在内部使用它。也可通过 createLiveKitWorker 的 generate 选项直接使用它,让功能完备的 worker 对接远程服务端:
import { createLiveKitWorker, createRemoteAgentReplyGenerator } from '@mastra/livekit/worker'
import { mastra } from './index'
export default createLiveKitWorker({
mastra, // local instance for logger and worker config; replies come from the remote server
generate: createRemoteAgentReplyGenerator({
baseUrl: process.env.MASTRA_URL!,
agentId: 'support',
}),
memory: ({ metadata, roomName }) => ({ thread: metadata.threadId ?? roomName }),
stt: 'deepgram/nova-3',
tts: 'cartesia/sonic-3',
})
在 generate 路径上,worker 级 toolFeedback 和 onTurnComplete 选项不适用,worker 的结束通话检测也不会触发;请改为将这些 hook 传给生成器。
取消轮次(插话打断)会终止 HTTP 请求,从而中止服务端生成。错误以 LiveKit APIError 类型抛出。retries 选项仅适用于初始连接尝试。轮次在生成第一个分块后绝不会重试。
返回: VoiceReplyGenerator.
选项选项的直接链接
baseUrl:
agentId:
apiPrefix?:
headers?:
fetch?:
timeoutMs?:
retries?:
body?:
toolFeedback?:
onToolCall?:
onTurnComplete?:
speakGreeting()speakgreeting的直接链接
在你拥有的 session 上播报开场问候语,并遵循中断和播放选项。返回 LiveKit SpeechHandle;没有问候文本时返回 undefined。createLiveKitWorker() 在内部将其用于 greeting 配置。
import { speakGreeting } from '@mastra/livekit/worker'
await speakGreeting(session, {
text: "You've reached support. You're speaking with an AI assistant.",
allowInterruptions: false,
awaitPlayout: true,
})
参数参数的直接链接
session:
greeting:
waitForAgentDoneSpeaking()waitforagentdonespeaking的直接链接
当 Agent 不再生成或播放响应,即状态离开 thinking 和 speaking 后 resolve。如果 Agent 已空闲,则立即 resolve;作为安全上限,始终会在 maxWaitMs(默认 30 秒)内 resolve。在拆除 session 前使用它,可让结束语完整播放而不被截断。
import { waitForAgentDoneSpeaking } from '@mastra/livekit/worker'
await waitForAgentDoneSpeaking(session)
runEndCall()runendcall的直接链接
在 Agent 请求挂断后结束通话。它会等待 Agent 的结束语,并不受中断地播报可选的最终 message。随后删除 room 并挂断呼叫方,包括 SIP 呼叫方。job 会连同其已注册的回调一起关闭。
将它与 MastraLLM 的 onToolCall 以及服务端 Agent 上的结束通话 Tool 搭配,可在你拥有的 session 上重新实现 Agent 发起挂断:
import { MastraLLM } from '@mastra/livekit/plugin'
import { DEFAULT_END_CALL_TOOL, runEndCall } from '@mastra/livekit/worker'
let ending = false
const llm = new MastraLLM({
remote: { baseUrl: process.env.MASTRA_URL!, agentId: 'support' },
onToolCall: ({ toolName }) => {
if (toolName !== DEFAULT_END_CALL_TOOL || ending) return
ending = true
void runEndCall(session, ctx, {}, console)
},
})
导出的常量 DEFAULT_END_CALL_TOOL('endCall')、DEFAULT_END_CALL_REASON 和 DEFAULT_END_CALL_MAX_WAIT_MS(30000)保存默认值。
参数参数的直接链接
session:
ctx:
config:
logger:
createEndCallTool()createendcalltool的直接链接
构建 Agent 想结束通话时调用的 Mastra Tool。该 Tool 表明意图,并可执行可选的记录工作。实际挂断由 worker 执行。该 Tool 位于服务端安全的根入口中。请将它添加到服务端代码中定义的 Agent。
import { Agent } from '@mastra/core/agent'
import { createEndCallTool } from '@mastra/livekit'
const supportAgent = new Agent({
id: 'support',
name: 'Support',
instructions:
'Help the caller. When everything is wrapped up, say goodbye and call endCall as your final action.',
model: 'openai/gpt-5-mini',
tools: { endCall: createEndCallTool() },
})
使用 createLiveKitWorker() 时,设置 configuration: { endCall: {} },worker 会监视该 Tool 并挂断。在你拥有的 session 上,可使用 runEndCall() 重新实现挂断。
选项选项的直接链接
id?:
description?:
onEndCall?:
liveKitConnectionRoute()livekitconnectionroute的直接链接
返回一个 API route,用于签发 LiveKit access token,并将语音 Agent 分派到 room 中。前端调用它加入 session。
import { Mastra } from '@mastra/core/mastra'
import { liveKitConnectionRoute } from '@mastra/livekit'
export const mastra = new Mastra({
server: {
apiRoutes: [liveKitConnectionRoute({ agentName: 'mastra-voice' })],
},
})
该路由接受包含可选 agentId、threadId 和 resourceId 字段的 JSON body,并响应 { serverUrl, roomName, participantName, participantToken }。threadId 默认为生成的 room 名称。
选项选项的直接链接
path?:
serverUrl?:
apiKey?:
apiSecret?:
agentName?:
ttl?:
requiresAuth?:
roomName?:
participantIdentity?:
metadata?:
dispatchVoiceSession()dispatchvoicesession的直接链接
以编程方式将 Mastra 语音 Agent 分派到 LiveKit room:适用于外呼等服务端发起的 session。
import { dispatchVoiceSession } from '@mastra/livekit'
await dispatchVoiceSession({
roomName: 'support-call-42',
agentName: 'mastra-voice',
metadata: { agentId: 'support', threadId: 'thread-42' },
})
选项选项的直接链接
roomName:
agentName?:
metadata?:
serverUrl?:
apiKey?:
apiSecret?:
LiveKitSessionMetadatalivekitsessionmetadata的直接链接
通过 LiveKit job 分派从 Mastra 服务端传给 worker 的元数据。
agentId?:
threadId?:
resourceId?:
requestContext?:
元数据以 JSON 字符串形式传输。liveKitConnectionRoute() 和 dispatchVoiceSession() 会代为序列化;通过自己的代码分派时,请使用 serializeSessionMetadata(metadata),也可以在 SIP 分派规则等 LiveKit 侧配置中直接写入 JSON。requestContext 中的条目会在通话的每个轮次传给 Agent 的 runtime 定义指令、Tool 和输入处理器。