ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Mastra xAI Grok 实时语音集成指南:使用 @mastra/voice-xai-realtime 构建低延迟双向语音 Agent

Mastra xAI Grok 实时语音集成指南:使用 @mastra/voice-xai-realtime 构建低延迟双向语音 Agent Mastra xAI Grok 实时语音集成指南使用 mastra/voice-xai-realtime 构建低延迟双向语音 Agent【免费下载链接】mastraMastra is the modern TypeScript framework for AI-powered applications and agents.项目地址: https://gitcode.com/GitHub_Trending/ma/mastramastra/voice-xai-realtime是 Mastra 官方提供的 xAI Grok Voice Agent 实时语音集成包通过 WebSocket 将 Mastra Agent 接入 xAI 的 Realtime API支持低延迟的双向文本与音频对话、服务端语音活动检测server-side VAD、打断处理与实时转写。本文以 voice/xai-realtime-api/README.md 为核心骨架结合该包的 源码、类型定义 与 测试用例完整讲解从安装、配置、连接、语音收发到工具调用function calling的实战路径。一、包定位与适用场景mastra/voice-xai-realtime让 Mastra Agent 具备实时语音对话能力它不是一个普通的文本模型封装而是以XAIRealtimeVoice类实现 Mastra 的实时语音契约realtime voice contract直连 xAI 的 Grok Voice Agent WebSocket 端点。官方 README 明确其适用场景为需要 Agent 具备**实时语音live speech**交互能力需要服务端轮次检测由 xAI 服务端判断用户何时开始/结束说话与打断处理用户说话时可打断 Agent 正在生成的回复需要在一个语音提供商内同时获得实时转写文本realtime transcripts。从源码注释src/index.ts看该 Provider 遵循 Mastra 实时语音契约同时完整保留 xAI 的端点、认证方式、音色、事件命名与工具行为也就是说上层使用统一的 Mastra Voice API底层细节完全向 xAI 对齐。包的基本信息来自 package.json项目值包名mastra/voice-xai-realtime运行时要求Node.js 22.13.0ESMtype: module核心依赖wsWebSocket 客户端、mastra/schema-compat工具 schema 转换可选 peer 依赖zod^3.25.0 或 ^4.0.0用于工具输入 schema默认端点wss://api.x.ai/v1/realtime默认模型grok-voice-think-fast-1.0默认音色eve二、安装与前置条件安装方式与 README 保持一致npm install mastra/voice-xai-realtime需要额外说明的两点均可在 package.json 中确认API Key需要在环境中设置XAI_API_KEY或在构造时通过apiKey参数显式传入。若都不提供connect()会抛出xAI API key is required. Set XAI_API_KEY, pass apiKey, or pass ephemeralToken.错误见 src/index.ts。Node 音频能力README 中的麦克风/扬声器示例还依赖单独发布的mastra/node-audio包提供getMicrophoneStream与playAudio。也就是说mastra/voice-xai-realtime本身只负责与 xAI 的 WebSocket 通信和 PCM 音频编解码实际的麦克风采集与扬声器播放由mastra/node-audio完成。三、快速上手最小可用示例README 给出了完整的可运行示例核心流程为创建语音实例 → 挂载到 Agent → 连接 → 监听扬声器/转写事件 → 播报问候语 → 发送麦克风音频流。以下为完整代码保留原文档全部逻辑并补充注释import { Agent } from mastra/core/agent; import { getMicrophoneStream, playAudio } from mastra/node-audio; import { XAIRealtimeVoice } from mastra/voice-xai-realtime; const voice new XAIRealtimeVoice({ apiKey: process.env.XAI_API_KEY, model: grok-voice-think-fast-1.0, speaker: eve, instructions: You are a concise voice assistant., turnDetection: { type: server_vad }, }); const agent new Agent({ id: voice-agent, name: Voice Agent, instructions: You are a helpful voice assistant., model: xai/grok-4.3, voice, }); await agent.voice.connect(); // 扬声器事件Agent 回复的音频以流式方式持续吐出 agent.voice.on(speaker, audioStream { playAudio(audioStream); }); // writing 事件实时转写/生成文本assistant 生成中、user 语音转写完成时触发 agent.voice.on(writing, ({ text, role }) { console.log(${role}: ${text}); }); // 先主动播报一句问候 await agent.voice.speak(How can I help you today?); // 采集麦克风音频流并持续发送给 xAI 进行实时语音识别与轮次检测 const microphoneStream getMicrophoneStream(); await agent.voice.send(microphoneStream);其中值得注意的运行语义可在源码与测试中找到依据connect()会建立 WebSocket、等待连接打开随后立即发送一次session.update初始化会话配置并冲刷连接建立之前排队的所有事件见 src/index.ts。测试sends the initial session update before queued pre-connect events验证了会话更新永远先于排队事件这一顺序。在connect()之前调用speak()或answer()不会报错事件会被放入内部队列连接成功后按序发送见sendEvent的排队逻辑 src/index.ts。重复调用connect()是安全的connect()内部做了去重并发调用只会建立一个WebSocket测试deduplicates concurrent connect() calls验证。四、配置项全解从构造参数到会话配置XAIRealtimeVoice的完整配置由 src/types.ts 中的XAIRealtimeVoiceConfig定义。在源码的normalizeConfigsrc/index.ts中构造参数会被规范化为三层结构speaker、realtimeConfig含model、apiKey与options保留原始扩展配置。4.1 构造参数XAIRealtimeVoiceConfig参数类型说明默认值apiKeystringxAI API Key连接时优先使用其次读取XAI_API_KEY环境变量无ephemeralTokenstring临时令牌认证见下文 5.1优先级高于apiKey无modelXAIRealtimeModel实时语音模型grok-voice-think-fast-1.0urlstringWebSocket 端点wss://api.x.ai/v1/realtimespeakerXAIVoice会话音色eveinstructionsstring系统指令随session.update下发给服务端无turnDetectionXAITurnDetection轮次检测配置{ type: server_vad }audioXAIAudioConfig输入/输出音频格式输入输出均为 PCM、24000Hz见下serverToolsXAIServerTool[]xAI 服务端工具web_search 等无session部分XAISessionConfig直接透传给服务端的会话字段含tools子字段无debugboolean开启后以 debug 级别日志输出每个服务端事件false4.2 模型与音色模型类型为XAIRealtimeModelgrok-voice-think-fast-1.0 | grok-voice-fast-1.0 | (string {})。常量定义见 src/index.ts。音色XAIVoice内置 5 种getSpeakers()返回的完整列表源码常量XAI_SPEAKERS见 src/index.tsvoiceId名称性别描述eveEvefemale充满活力、明快的默认音色araArafemale温暖、友好的对话式音色rexRexmale自信、清晰的职业音色salSalneutral平稳、均衡的通用音色leoLeomale权威、有力的教学型音色测试initializes with documented xAI defaults and speakers断言getSpeakers()返回的顺序即上表。4.3 音频格式与轮次检测XAIAudioConfigsrc/types.ts控制输入/输出格式支持三种类型audio/pcm线性 PCMLinear16 little-endian采样率可为 8000 / 16000 / 22050 / 24000 / 32000 / 44100 / 48000audio/pcmu与audio/pcma只支持 8000Hz。包默认值见 src/index.ts为输入与输出均为audio/pcm、24000Hz。麦克风采集时需与之匹配或自行覆盖audio配置。XAITurnDetectionsrc/types.ts用于服务端 VAD字段说明typeserver_vad启用服务端语音检测或null关闭thresholdVAD 判定阈值silence_duration_ms判定一次发言结束所需的静音时长prefix_padding_ms发言起始前的保留音频前缀时长4.4 会话配置如何下发连接成功后buildInitialSessionConfig()src/index.ts会把instructions、voice、turn_detection、audio、tools合并进一次session.update事件。默认会话结构可参考测试中的断言src/index.test.ts{ type: session.update, session: { instructions: You are helpful., voice: ara, turn_detection: { type: server_vad }, audio: { input: { format: { type: audio/pcm, rate: 24000 } }, output: { format: { type: audio/pcm, rate: 24000 } } } } }运行中还可以通过addInstructions()动态修改系统指令连接打开时会实时补发一次session.update或通过updateConfig()下发任意session.update字段。五、连接与认证机制5.1 两种认证方式openConnection中的认证逻辑src/index.ts支持两种方式且临时令牌优先API KeyBearerapiKey或环境变量XAI_API_KEY以 HTTP HeaderAuthorization: Bearer apiKey携带Ephemeral TokenWebSocket 子协议ephemeralToken作为 WebSocket 子协议xai-client-secret.token发送适用于服务端先签发临时令牌、客户端持令牌直连的安全场景。测试supports xAI ephemeral token websocket protocol auth与prefers ephemeral token auth when both token and API key are configured验证了该优先级与子协议格式。当两者都未配置时connect()直接抛错测试throws before connect when no xAI auth is configured。模型通过 URL 查询参数传递连接地址形如wss://api.x.ai/v1/realtime?modelgrok-voice-think-fast-1.0见buildUrl与测试断言。5.2 连接生命周期与断线处理XAIRealtimeVoice内部维护closed | connecting | open三种状态并提供connect()建立连接幂等、可并发去重连接失败会清理会话状态并恢复为closedclose()/disconnect()主动关闭触发close事件code: 1000, reason: closed意外断线WebSocketclose时自动清理排队事件、音频流监听器、函数调用挂起状态见cleanupSessionStatesrc/index.ts。值得强调的是陈旧连接隔离所有消息/错误/关闭回调都会校验this.ws ! ws以忽略旧连接的回调见setupEventListeners重连后旧 socket 的残留事件不会污染新会话。测试ignores stale close events from a previous websocket after reconnect与drops stale function outputs after an unexpected websocket close专门覆盖了这类竞态场景。另外close()之后继续调用answer()等发送方法会触发Cannot send event after close()错误事件而非静默失败。六、语音与文本的发送speak / listen / send6.1 speak()文本转语音speak(text)src/index.ts把一段文本构造成conversation.item.createrole: user、content: [{ type: input_text }]随后发送response.create触发模型生成语音回复。它同时支持传入XAIRealtimeSpeakOptions.speaker临时切换音色与当前音色不同时会先下发session.update更新voice传入response对象定制响应参数如模态、指令覆盖等输入为空字符串或纯空白时抛Input text is empty。对应测试creates text turns and response requests from speak()验证其发送的事件序列恰好为conversation.item.create→response.create。6.2 send()流式发送麦克风音频send(audioData)src/index.ts是实时对话的主通道接受两种输入Node.js ReadableStream推荐如getMicrophoneStream()返回的流逐 chunk 转为 base64 并持续发送input_audio_buffer.append。源码会自动挂载data/error/end/close监听并在连接关闭时统一清理Int16Array一次性的 PCM16 数据通过int16ArrayToBase64src/utils.ts按little-endian编码为 base64 后发送。音频流的 chunk 必须是Buffer、ArrayBuffer或 TypedArray否则触发Audio stream chunks must be Buffer, ArrayBuffer, or TypedArray values错误事件并自动解绑监听器测试emits an error and cleans up when live audio stream chunks are not binary。注意send()要求连接已打开未连接时不会入队而是直接发Cannot send audio before connect() is open错误事件测试does not queue realtime audio before connect is open。6.3 listen()一次性音频输入listen(audioData, options)src/index.ts面向非流式场景将整个输入流读取为 base64 后依次发送input_audio_buffer.append、input_audio_buffer.commit并在默认情况下继续发送response.create。通过XAIRealtimeListenOptions可以控制commit?: boolean默认true是否提交音频缓冲createResponse?: boolean默认true是否随即请求响应response?: Recordstring, unknown响应参数定制。6.4 底层音频缓冲操作对应 xAI 协议的细粒度控制方法commitAudioBuffer()发送input_audio_buffer.commit通知服务端这一段语音说完了clearAudioBuffer()发送input_audio_buffer.clear丢弃当前未提交的缓冲cancelResponse()发送response.cancel打断模型正在生成的回复answer()发送response.create主动请求一次模型响应不依赖语音缓冲。测试appends Int16 audio and supports manual commit and clear events验证了以上方法产生的完整事件序列。这四个方法配合使用可实现自定义的轮次控制与打断逻辑。七、事件模型实时音频流、转写与错误处理XAIRealtimeVoice实现 Mastra 的VoiceEventMap并通过on(event, callback)订阅。完整事件类型见 src/types.ts 的XAIRealtimeEventMap服务端事件到 Mastra 事件的映射逻辑在handleServerEventsrc/index.ts事件触发时机与负载来源事件speaker每次响应开始时创建一个音频流PassThrough持续推送该响应的 PCM 音频response_id作为流标识stream.idresponse.createdspeaking每收到一段音频增量负载{ audio(base64), audioData(Buffer), response_id }response.output_audio.delta/response.audio.deltaspeaking.done一段响应的音频播放完毕负载{ response_id }response.output_audio.done/response.audio.donewriting实时文本流role: assistant为模型生成中的增量文本含音频转写增量role: user为用户的语音转写完成文本response.text.delta、response.audio_transcript.delta、conversation.item.input_audio_transcription.completed等error统一错误事件负载{ message, code?, details? }xAIerror事件、本地解析/校验失败tool-call-start工具开始执行负载{ toolCallId, toolName, toolDescription?, args }response.function_call_arguments.donetool-call-result工具执行完成负载新增result字段同上close连接关闭负载{ code, reason }WebSocket close一个关键实现细节每个响应的音频都是一个独立流由createSpeakerStream(responseId)创建、response.done或output_audio.done时结束并清理src/index.ts。纯文本响应同样会创建一个流并在response.done时结束测试ends speaker streams for text-only responses on response.done因此订阅speaker后只需按 README 示例那样playAudio(audioStream)即可无需自己管理流生命周期。八、工具调用把 Mastra Tools 接入实时语音会话8.1 两种工具形态XAITool分为两类src/types.ts函数工具XAIFunctionTool{ type: function, name, description?, parameters }由 Mastra Agent 的工具转换而来执行逻辑在本地跑服务端工具XAIServerTool共四种直接在 xAI 侧执行类型关键字段file_searchvector_store_ids: string[]、max_num_results?web_search无额外必填字段x_searchallowed_x_handles?: string[]限定搜索的 X 账号mcpserver_url、server_label、server_description?、allowed_tools?、authorization?、headers?服务端工具通过构造参数serverTools或session.tools配置测试passes xAI server-side tools through session configuration展示了四种工具混用的完整示例。8.2 Mastra 工具如何转换为 xAI 函数transformToolssrc/utils.ts完成转换优先读取工具的inputSchema其次parameters通过mastra/schema-compat统一转换为 JSON SchemaZod schema 走zodToJsonSchema并移除$schema字段转换失败会抛出带工具名的明确错误没有execute函数的工具会被跳过并通过 logger 发出警告默认console.warn传入语音实例的 logger 时遵循 Mastra 日志级别。转换后的函数工具与serverTools合并随首次session.update一并下发。测试transforms Mastra tools and waits for parallel function calls before continuing验证了 Zod schema 到 JSON Schema 的完整转换结果含required数组。8.3 函数调用的完整生命周期当服务端下发response.function_call_arguments.done包含call_id、name、arguments字符串时执行链路为src/index.ts解析参数 JSON失败则回发{ error }并触发error事件测试emits parse diagnostics for malformed function call arguments发出tool-call-start以(args, { toolCallId, requestContext })调用本地executerequestContext来自connect({ requestContext })完成后发出tool-call-result以conversation.item.createfunction_call_output将结果JSON.stringifyundefined序列化为null回传给服务端在所有函数调用都完成后等待response.done自动补发一次response.create让模型基于工具结果继续生成。这套流程对并行函数调用与乱序事件做了专门处理多个函数调用可以并行执行全部完成后才继续测试waits for every function call listed in a done-first response即使response.done先到、function_call_arguments.done后到也会等待参数到达测试continues when response.done is received before a function call event参数迟迟不到时有30 秒超时FUNCTION_CALL_ARGUMENT_TIMEOUT_MS 30_000超时会为缺失的调用回发错误输出、触发error事件并继续对话测试times out missing function call arguments from a done-first response工具抛错时回发{ error: message }且同样会等待response.done后再继续测试sends function error outputs and waits for response.done before continuing。九、安全与运维注意点结合源码与测试以下行为值得在实际工程中注意密钥不落日志serializeForSpan()序列化时不会包含apiKey测试does not leak API keys through serializeForSpan()会话字段防循环引用updateConfig下发前会深度剔除undefined字段并处理循环引用避免 JSON 序列化抛错测试strips circular session config values instead of throwing during serialization二进制值Buffer/TypedArray会被保留开放 debug设置debug: true后每个服务端事件都会以 debug 级别日志输出音频增量只记录长度不记录内容见 src/index.ts便于排查协议问题关闭清理主动或意外关闭都会清空发送队列与挂起的函数调用状态重连后从干净状态开始测试clears queued events and request context on close before reconnect。十、小结mastra/voice-xai-realtime把 xAI Grok Voice Agent 的 Realtime WebSocket API 完整封装进 Mastra 的 Voice 抽象层开发者只需构造XAIRealtimeVoice并挂到 Agent 的voice字段即可获得speak文本转语音、send/listen语音输入、writing实时转写、server_vad轮次检测、打断处理与原生工具调用能力且 xAI 的音色、模型、服务端工具file_search / web_search / x_search / mcp都能无缝透传。若要深入源码细节建议按顺序阅读 types.ts协议类型、index.ts连接与事件核心实现、utils.ts工具转换与音频编码并以 index.test.ts 作为行为契约参考。【免费下载链接】mastraMastra is the modern TypeScript framework for AI-powered applications and agents.项目地址: https://gitcode.com/GitHub_Trending/ma/mastra创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表