跳到主要内容

Mastra 的语音转语音能力

简介
简介的直接链接

Mastra 中的语音转语音(STS)为通过多个 Provider 进行实时交互提供标准化接口。 STS 通过监听 Realtime 模型发出的事件,实现持续的双向音频通信。与分开的 TTS 和 STT 操作不同,STS 会保持连接打开,并持续处理两个方向的语音。

配置
配置的直接链接

  • apiKey:OpenAI API 密钥。未提供时使用 OPENAI_API_KEY 环境变量。
  • model:用于实时语音交互的模型 ID(例如 gpt-5.1-realtime)。
  • speaker:用于语音合成的默认语音 ID。你可以指定语音输出所用的语音。
const voice = new OpenAIRealtimeVoice({
apiKey: 'your-openai-api-key',
model: 'gpt-5.1-realtime',
speaker: 'alloy', // Default voice
})

// If using default settings the configuration can be simplified to:
const voice = new OpenAIRealtimeVoice()

使用 STS
使用 STS的直接链接

import { Agent } from '@mastra/core/agent'
import { OpenAIRealtimeVoice } from '@mastra/voice-openai-realtime'
import { playAudio, getMicrophoneStream } from '@mastra/node-audio'

const agent = new Agent({
id: 'agent',
name: 'OpenAI Realtime Agent',
instructions: `You are a helpful assistant with real-time voice capabilities.`,
model: 'openai/gpt-5.6-sol',
voice: new OpenAIRealtimeVoice(),
})

// Connect to the voice service
await agent.voice.connect()

// Listen for agent audio responses
agent.voice.on('speaker', ({ audio }) => {
playAudio(audio)
})

// Initiate the conversation
await agent.voice.speak('How can I help you today?')

// Send continuous audio from the microphone
const micStream = getMicrophoneStream()
await agent.voice.send(micStream)

有关 Agent 上语音 Provider 的更全面概览,请参阅 Mastra 中的 Voice

在实时会话中使用 Tool
在实时会话中使用 Tool的直接链接

实时语音 Provider 可以使用 Agent 上配置的 Tool。将 Tool 添加到 Agent 定义,然后连接语音 Provider 并通过它发送音频:

import { Agent } from '@mastra/core/agent'
import { OpenAIRealtimeVoice } from '@mastra/voice-openai-realtime'
import { calculate, search } from '../tools'

export const agent = new Agent({
id: 'speech-to-speech-agent',
name: 'Speech-to-Speech Agent',
instructions: 'You are a helpful assistant with speech-to-speech capabilities.',
model: 'openai/gpt-5.6-sol',
tools: {
search,
calculate,
},
voice: new OpenAIRealtimeVoice(),
})

监听实时事件
监听实时事件的直接链接

实时语音 Provider 会发出事件,你可以用它们更新 UI、播放助手音频、记录转录内容以及处理错误:

agent.voice.on('speaking', ({ audio }) => {
playAudio(audio)
})

agent.voice.on('writing', ({ text, role }) => {
console.log(`${role}: ${text}`)
})

agent.voice.on('error', error => {
console.error('Voice error:', error)
})

事件名称和 payload 因 Provider 而异。完整事件列表请查看下面的 Provider 部分或相应 Provider 参考。

为每个会话创建语音实例
为每个会话创建语音实例的直接链接

静态 voice 实例会在所有请求间共享。这适用于一次性文本转语音,但实时和语音转语音 Provider 会存储 WebSocket 连接、Tool、instructions 和请求上下文等会话状态。如果一个 Agent 同时处理多个实时会话,共享实例可能会让一个会话覆盖另一个会话的状态。

当每个实时会话都需要自己的语音实例时,请将 voice 作为 resolver 提供。Mastra 会在每次调用 getVoice() 时运行 resolver,并为该请求上下文返回一个新实例:

import { Agent } from '@mastra/core/agent'
import { RequestContext } from '@mastra/core/request-context'
import { OpenAIRealtimeVoice } from '@mastra/voice-openai-realtime'

export const agent = new Agent({
id: 'support-line',
name: 'Support Line',
instructions: ({ requestContext }) => `Help user ${requestContext.get('user')}.`,
model: 'openai/gpt-5.6-sol',
voice: ({ requestContext }) =>
new OpenAIRealtimeVoice({
apiKey: requestContext.get('apiKey'),
}),
})

const requestContext = new RequestContext()
requestContext.set('user', 'user-123')
requestContext.set('apiKey', process.env.OPENAI_API_KEY)

const voice = await agent.getVoice({ requestContext })
await voice.connect()

使用 resolver 时:

  • 每次调用 getVoice() 都会返回新实例,因此并发会话不会共享状态。
  • Mastra 不会向 resolver 实例添加 Tool 或 instructions。请在 resolver 内部或 Provider 上进行配置。
  • 返回实例的生命周期由你管理,因此请在会话结束时调用 disconnect()close()

agent.voice getter 没有请求上下文,因此当 voice 是 resolver 时会抛出错误。请改用 agent.getVoice({ requestContext })

Google Gemini Live(Realtime)
Google Gemini Live(Realtime)的直接链接

import { Agent } from '@mastra/core/agent'
import { GeminiLiveVoice } from '@mastra/voice-google-gemini-live'
import { playAudio, getMicrophoneStream } from '@mastra/node-audio'

const agent = new Agent({
id: 'agent',
name: 'Gemini Live Agent',
instructions: 'You are a helpful assistant with real-time voice capabilities.',
// Model used for text generation; voice provider handles realtime audio
model: 'openai/gpt-5.6-sol',
voice: new GeminiLiveVoice({
apiKey: process.env.GOOGLE_API_KEY,
model: 'gemini-2.0-flash-exp',
speaker: 'Puck',
debug: true,
// Vertex AI option:
// vertexAI: true,
// project: 'your-gcp-project',
// location: 'us-central1',
// serviceAccountKeyFile: '/path/to/service-account.json',
}),
})

await agent.voice.connect()

agent.voice.on('speaker', ({ audio }) => {
playAudio(audio)
})

agent.voice.on('writing', ({ role, text }) => {
console.log(`${role}: ${text}`)
})

await agent.voice.speak('How can I help you today?')

const micStream = getMicrophoneStream()
await agent.voice.send(micStream)

注意:

  • Live API 需要 GOOGLE_API_KEY。Vertex AI 需要项目/位置和服务账号凭据。
  • 事件:speaker(音频流)、writing(文本)、turnCompleteusageerror

AWS Nova Sonic(Realtime)
AWS Nova Sonic(Realtime)的直接链接

import { Agent } from '@mastra/core/agent'
import { NovaSonicVoice } from '@mastra/voice-aws-nova-sonic'
import { playAudio, getMicrophoneStream } from '@mastra/node-audio'

const agent = new Agent({
id: 'agent',
name: 'Nova Sonic Agent',
instructions: 'You are a helpful assistant with real-time voice capabilities.',
// Model used for text generation; voice provider handles realtime audio
model: 'openai/gpt-5.6-sol',
voice: new NovaSonicVoice({
region: 'us-east-1',
speaker: 'matthew',
// Static credentials are optional. The default AWS credential provider
// chain is used when none are passed.
}),
})

await agent.voice.connect()

// Assistant audio is emitted as 16-bit PCM on the `speaking` event
agent.voice.on('speaking', ({ audioData }) => {
if (audioData) playAudio(audioData)
})

agent.voice.on('writing', ({ role, text }) => {
console.log(`${role}: ${text}`)
})

await agent.voice.speak('How can I help you today?')

const micStream = getMicrophoneStream()
await agent.voice.send(micStream)

注意:

  • 可用区域:us-east-1us-west-2ap-northeast-1
  • 通过标准 AWS 凭据 Provider 链进行身份验证。传入 credentials 可覆盖默认行为。
  • 事件:speaking(Int16Array 音频)、writing(带有 generationStage 的文本)、toolCallinterruptturnCompleteusagesessionerror

Inworld Realtime
Inworld Realtime的直接链接

import { Agent } from '@mastra/core/agent'
import { InworldRealtimeVoice } from '@mastra/voice-inworld'
import { playAudio, getMicrophoneStream } from '@mastra/node-audio'

const agent = new Agent({
id: 'agent',
name: 'Inworld Realtime Agent',
instructions: 'You are a helpful assistant with real-time voice capabilities.',
// Model used for text generation; voice provider handles realtime audio
model: 'openai/gpt-5.6-sol',
voice: new InworldRealtimeVoice({
apiKey: process.env.INWORLD_API_KEY,
model: 'inworld/models/gemma-4-26b-a4b-it',
speaker: 'Sarah',
// Typed Inworld realtime knobs (semantic VAD, playback speed, etc.)
// session: {
// audio: {
// output: { speed: 1.1 },
// input: { turn_detection: { type: 'semantic_vad', eagerness: 'high' } },
// },
// },
}),
})

await agent.voice.connect()

agent.voice.on('speaker', stream => {
playAudio(stream)
})

agent.voice.on('writing', ({ role, text }) => {
console.log(`${role}: ${text}`)
})

await agent.voice.speak('How can I help you today?')

const micStream = getMicrophoneStream()
await agent.voice.send(micStream)

注意:

  • 需要 INWORLD_API_KEY。Inworld API 密钥已经过预先 Basic 编码,请原样粘贴。
  • WebSocket URL 会附加客户端生成的 ?key=...&protocol=realtime。模型通过初始 session.update 配置,而不是在 URL 中配置。
  • Inworld 的线协议采用 OpenAI Realtime GA 规范,因此事件名称与 @mastra/voice-openai-realtime 一致。
  • 类型化 Inworld 实时设置(MCP Tool 路由、语义 VAD eagerness、播放速度、转录模型、输出模态等)通过 session 构造函数字段公开。还提供无类型的 providerData 逃生舱,并通过深度合并为新的 Inworld 功能提供前向兼容性。
  • 事件:speaker(PCM 音频流)、speaking(每个 delta 的音频 Buffer)、writing(文本)、conversation.item.addedconversation.item.donefunction_call.argumentstool-call-starttool-call-resulterror