mock(开发,无网络)、plivo(Voice API + XML 转接 +
GetInput 语音)、telnyx(Call Control v2)、twilio(Programmable Voice +
Media Streams)。
语音通话插件在 Gateway 网关进程内运行。如果使用
远程 Gateway 网关,请在运行 Gateway 网关的机器上安装并配置插件,
然后重启 Gateway 网关以加载插件。
快速开始
1
安装插件
- 从 npm 安装
- 从本地文件夹安装(开发)
2
配置提供商和 webhook
在
plugins.entries.voice-call.config 下设置配置(请参阅下方的
配置)。至少需要:provider、提供商
凭据、fromNumber,以及可从公网访问的 webhook URL。3
验证设置
streaming 或 realtime)。4
冒烟测试
--yes 可发起一次简短的出站
通知通话:配置
如果enabled: true,但所选提供商缺少凭据,Gateway 网关
启动时会记录设置未完成警告,列出缺失的键,并跳过
启动运行时。命令、RPC 调用和智能体工具在使用时仍会返回
确切缺失的配置。
语音通话凭据接受 SecretRef。
plugins.entries.voice-call.config.twilio.authToken、plugins.entries.voice-call.config.realtime.providers.*.apiKey、plugins.entries.voice-call.config.streaming.providers.*.apiKey 和 plugins.entries.voice-call.config.tts.providers.*.apiKey 通过标准 SecretRef 界面解析;请参阅 SecretRef 凭据界面。配置参考
上面未显示的plugins.entries.voice-call.config 下的顶层键:
Twilio 默认使用其 US1 REST 端点。要在受支持的
非美国区域处理通话,请将
twilio.region 设置为 ie1 或 au1,并使用该
区域的凭据。请参阅
Twilio 的非美国区域 REST API 指南。
提供商暴露和安全说明
提供商暴露和安全说明
- Twilio、Telnyx 和 Plivo 都要求使用可从公网访问的 webhook URL。
mock是本地开发提供商(无网络调用)。- Telnyx 要求提供
telnyx.publicKey(或TELNYX_PUBLIC_KEY),除非skipSignatureVerification为 true。 skipSignatureVerification仅供本地测试。- 使用 ngrok 免费层时,请将
publicUrl设置为确切的 ngrok URL;始终强制执行签名验证。 - 仅当
tunnel.provider="ngrok"且serve.bind为环回地址(ngrok 本地智能体)时,tunnel.allowNgrokFreeTierLoopbackBypass: true才允许签名无效的 Twilio webhook。仅供本地开发。 - ngrok 免费层 URL 可能会更改或增加中间页行为;如果
publicUrl发生偏移,Twilio 签名将失败。生产环境:优先使用稳定域名或 Tailscale funnel。
流式连接上限
流式连接上限
streaming.preStartTimeoutMs(默认5000)会关闭从未发送有效start帧的套接字。streaming.maxPendingConnections(默认32)限制未经身份验证的启动前套接字总数。streaming.maxPendingConnectionsPerIp(默认4)限制每个源 IP 未经身份验证的启动前套接字数量。streaming.maxConnections(默认128)限制所有打开的媒体流套接字(待处理 + 活跃)。
旧版配置迁移
旧版配置迁移
配置解析会自动规范化这些旧版键,并记录一条
指明替代路径的警告;此兼容层将在未来版本
(
2026.6.0)中移除,因此请运行 openclaw doctor --fix,将已提交的
配置重写为规范形式:provider: "log"→provider: "mock"twilio.from→fromNumberstreaming.sttProvider→streaming.providerstreaming.openaiApiKey→streaming.providers.openai.apiKeystreaming.sttModel→streaming.providers.openai.modelstreaming.silenceDurationMs→streaming.providers.openai.silenceDurationMsstreaming.vadThreshold→streaming.providers.openai.vadThresholdrealtime.agentContext.includeSystemPrompt已移除(实时上下文现在使用生成的智能体提示词)
会话范围
默认情况下,语音通话使用sessionScope: "per-phone",因此来自
同一来电者的重复通话会保留对话记忆。当每个运营商通话
都应使用全新上下文开始时,请设置 sessionScope: "per-call",例如前台接待、
预订、IVR 或 Google Meet 桥接流程,在这些流程中,同一电话号码可能
代表不同的会议。
语音通话将生成的会话键存储在已配置的智能体命名空间下
(agent:<agentId>:voice:*)。原始的显式集成键会解析到
同一命名空间:规范的 agent:<configuredAgentId>:* 键会保留该
所有者,并遵循核心 session.mainKey/全局范围别名规则;外部或
格式错误的 agent:* 输入会作为不透明键限定在已配置的
智能体下;global 和 unknown 仍是全局哨兵值。
实时语音对话
realtime 为实时通话音频选择全双工实时语音提供商。
它与 streaming 相互独立,后者仅将音频转发给实时
转录提供商。
当前运行时行为:
realtime.enabled支持 Twilio 和 Telnyx。realtime.provider是可选的。如果未设置,语音通话将使用首个已注册的实时语音提供商。- 内置实时语音提供商:Google Gemini Live(
google)和 OpenAI(openai),由各自的提供商插件注册。 - 提供商自有的原始配置位于
realtime.providers.<providerId>下。 - 默认情况下,语音通话会公开共享的
openclaw_agent_consult实时工具。当呼叫者要求进行更深入的推理、获取当前信息或使用常规 OpenClaw 工具时,实时模型可以调用该工具。 realtime.consultPolicy可选择性地添加指导,说明实时模型应在何时调用openclaw_agent_consult。realtime.agentContext.enabled默认关闭。启用后,语音通话会在设置会话时,将有界的智能体身份信息和选定的工作区文件信息包注入实时提供商指令。realtime.fastContext.enabled默认关闭。启用后,语音通话会先在已建立索引的记忆/会话上下文中搜索咨询问题,并在realtime.fastContext.timeoutMs范围内将这些片段返回给实时模型;仅当realtime.fastContext.fallbackToConsult为 true 时,才会回退到完整的咨询智能体。- 如果
realtime.provider指向未注册的提供商,或者根本没有注册实时语音提供商,语音通话会记录警告并跳过实时媒体处理,而不会让整个插件失败。 - 当
realtime.enabled为 true 时,inboundPolicy不得为"disabled";validateProviderConfig会拒绝该组合。 - 咨询会话键会优先复用已存储的通话会话(如果有),然后回退到配置的
sessionScope(默认为per-phone,隔离通话则为per-call)。
工具策略
realtime.toolPolicy 控制咨询运行:
realtime.consultPolicy 仅控制实时模型指令:
智能体语音上下文
如果希望语音桥接听起来像已配置的 OpenClaw 智能体,同时又不想让 普通轮次承担完整的智能体咨询往返开销,请启用realtime.agentContext。
上下文信息包仅在创建实时会话时添加一次,因此不会增加每轮延迟。
调用 openclaw_agent_consult 时仍会运行完整的 OpenClaw 智能体,并且应将其用于
工具操作、当前信息、记忆查找或工作区状态。
实时提供商示例
- Google Gemini Live
- OpenAI
默认值:API key 来自
realtime.providers.google.apiKey、GEMINI_API_KEY
或 GOOGLE_API_KEY;模型为 gemini-3.1-flash-live-preview;
语音为 Kore。sessionResumption 和 contextWindowCompression 默认开启,
以支持更长时间且可重新连接的通话。使用 silenceDurationMs、
startSensitivity 和 endSensitivity 可针对电话音频调节更快的
轮次交接。流式转录
streaming 将 Twilio Media Streams 连接到实时转录提供商。
经典流式传输路径要求使用 provider: "twilio";使用
Telnyx、Plivo 或 mock 的配置会被拒绝。Telnyx 实时音频则使用单独进行
身份验证的 realtime.enabled 路径。
当前运行时行为:
streaming.provider是可选的。如果未设置,语音通话将使用首个已注册的实时转录提供商。- 内置实时转录提供商:Deepgram(
deepgram)、ElevenLabs(elevenlabs)、Mistral(mistral)、OpenAI(openai)和 xAI(xai),由各自的提供商插件注册。 - 提供商自有的原始配置位于
streaming.providers.<providerId>下。 - Twilio 发送已接受的流
start消息后,语音通话会立即注册该流,在提供商连接期间将入站媒体排队交给转录提供商,并仅在实时转录准备就绪后开始初始问候语。 - 如果
streaming.provider指向未注册的提供商,或者没有注册任何提供商,语音通话会记录警告并跳过媒体流式传输,而不会让整个插件失败。
流式传输提供商示例
- OpenAI
- xAI
默认值:API key 为
streaming.providers.openai.apiKey 或
OPENAI_API_KEY;模型为 gpt-4o-transcribe;silenceDurationMs: 800;
vadThreshold: 0.5。通话 TTS
语音通话使用核心tts 配置进行通话中的流式语音合成。
你可以在插件配置下使用相同的结构覆盖它——该配置会与
tts 进行深度合并。
- 插件配置中的旧版
tts.<provider>键(openai、elevenlabs、microsoft、edge)由openclaw doctor --fix修复;提交的配置应使用tts.providers.<provider>。 - 启用 Twilio 媒体流式传输时使用核心 TTS;否则通话会回退到提供商原生语音。
- 如果 Twilio 媒体流已处于活动状态,语音通话不会回退到 TwiML
<Say>。如果在该状态下电话 TTS 不可用,播放请求将失败,而不会混用两种播放路径。 - 当电话 TTS 回退到次要提供商时,语音通话会记录包含提供商链(
from、to、attempts)的警告,以便调试。 - 当 Twilio 插话或流拆除清除待处理的 TTS 队列时,已排队的播放请求会得到结算,而不会导致等待播放完成的呼叫者一直挂起。
TTS 示例
- 仅核心 TTS
- 覆盖为 ElevenLabs(仅通话)
- OpenAI 模型覆盖(深度合并)
呼入通话
呼入策略默认为disabled。要启用呼入通话,请设置:
responseModel、
responseSystemPrompt 和 responseTimeoutMs 进行调整。
按号码路由
当一个语音通话插件接收多个电话号码的来电,并且每个号码应像不同线路一样运行时,请使用numbers。例如,
一个号码可以使用随和的个人助理,另一个号码则使用商务
角色、不同的响应智能体和不同的 TTS 语音。
路由根据提供商给出的被叫 To 号码进行选择。键必须
为 E.164 号码。来电到达时,语音通话插件会解析一次匹配的
路由,将匹配的路由存储到通话记录中,并在问候语、经典自动响应路径、实时
咨询路径和 TTS 播放中复用该有效配置。如果没有匹配的路由,则使用全局语音通话
配置。呼出通话不使用 numbers;发起通话时,应显式传入呼出
目标、消息和会话。
路由覆盖目前支持:
inboundGreetingttsagentIdresponseModelresponseSystemPromptresponseTimeoutMs
tts 路由值会深度合并到全局语音通话 tts 配置之上,因此
通常只需覆盖提供商语音:
语音输出契约
对于自动响应,语音通话插件会在系统提示词末尾附加严格的语音输出契约, 要求返回{"spoken":"..."} JSON 响应。语音通话插件会以防御性方式
提取语音文本:
- 忽略标记为推理/错误内容的负载。
- 解析直接 JSON、围栏 JSON 或内联
"spoken"键。 - 回退到纯文本,并移除可能属于规划/元信息引导的段落。
对话启动行为
对于呼出的conversation 通话,首条消息的处理与实时
播放状态关联:
- 仅在初始问候语正在播放时,才会抑制插话队列清除和自动响应。
- 如果初始播放失败,通话将返回
listening,且初始消息会保留在队列中以供重试。 - Twilio 流式传输的初始播放会在流连接时立即开始,不会增加额外延迟。
- 插话会中止正在进行的播放,并清除已排队但尚未播放的 Twilio TTS 条目。被清除的条目会以“已跳过”状态完成,因此后续响应逻辑可以继续执行,而不必等待永远不会播放的音频。
- 实时语音对话使用实时流自身的开场轮次。语音通话插件不会为该初始消息发送旧版
<Say>TwiML 更新,因此呼出的<Connect><Stream>会话会保持连接。
Twilio 流断开宽限期
当 Twilio 媒体流断开连接时,语音通话插件会等待 2000 ms,然后 自动结束通话:- 如果流在此时间窗口内重新连接,则取消自动结束。
- 如果宽限期过后仍没有流重新注册,则结束通话,以防止通话卡在活动状态。
过期通话清理器
使用staleCallReaperSeconds(默认值为 120)结束从未
接听且从未进入实时对话状态的通话,例如提供商始终未投递终止 Webhook 的通知模式
通话。将其设置为 0 可
禁用此功能。
清理器每 30 秒运行一次,并且仅结束没有
answeredAt 时间戳、且尚未处于终止或实时
(speaking/listening)状态的通话,因此已接听的对话绝不会被此计时器清理;
maxDurationSeconds(默认值为 300)是单独的上限,用于
结束持续时间过长的已接听通话。
对于运营商可能延迟投递响铃/接听
Webhook 的通知式流程,请将 staleCallReaperSeconds 提高到默认值以上,以免正常但缓慢的
通话被过早清理;120-300 秒是合理的生产环境
范围。
Webhook 安全
当 Gateway 网关前置代理或隧道时,插件会重建 用于签名验证的公共 URL。以下选项控制信任哪些 转发请求头:string[]
允许从转发请求头获取的主机列表。
boolean
在没有允许列表的情况下信任转发请求头。
string[]
仅当请求的远程 IP 与列表匹配时才信任转发请求头。
- Twilio、Telnyx 和 Plivo 已启用 Webhook 重放保护。对于重放的有效 Webhook 请求,系统会确认接收,但跳过其副作用。
- Twilio 对话轮次在
<Gather>回调中包含每轮令牌,因此过期或重放的语音回调无法满足较新的待处理转写轮次。 - 当缺少提供商要求的签名请求头时,未经身份验证的 Webhook 请求会在读取正文前被拒绝。
- 语音通话 Webhook 使用共享的身份验证前正文读取配置(正文最大 64 KB、读取超时 5 秒),并在签名验证前应用按键限制的进行中请求上限(默认每个键可同时处理 8 个请求)。
CLI
voicecall 命令
会委托给 Gateway 网关拥有的语音通话运行时,因此 CLI 不会绑定第二个
Webhook 服务器。如果无法连接任何 Gateway 网关,这些命令会回退到
独立的 CLI 运行时。
latency 从默认语音通话存储路径读取 calls.jsonl。使用
--file <path> 指向不同的日志,并使用 --last <n> 将
分析限制为最后 N 条记录(默认 200)。输出包括轮次延迟和收听等待时间的
最小值/最大值/平均值、p50 和 p95。
智能体工具
工具名称:voice_call。
语音通话插件附带一个匹配的智能体技能。
Gateway RPC 参考
dtmfSequence 仅可与 mode: "conversation" 一起使用;如果通知模式通话需要在连接后发送
数字,应在通话建立后使用 voicecall.dtmf。
故障排查
设置因 webhook 暴露失败
在运行 Gateway 网关的同一环境中运行设置:twilio、telnyx 和 plivo,webhook-exposure 必须为绿色。即使已
配置 publicUrl,当它指向本地或私有
网络空间时仍会失败,因为运营商无法回调这些地址。
请勿将 localhost、127.0.0.1、0.0.0.0、10.x、172.16.x-172.31.x、
192.168.x、169.254.x、fc00::/7、fd00::/8 或其他运营商级 NAT
地址范围用作 publicUrl。
Twilio 通知模式的出站通话会在创建通话的请求中直接发送初始 <Say> TwiML,
因此第一条语音消息不依赖 Twilio 获取 webhook TwiML。状态
回调、对话通话、连接前 DTMF、实时流以及
连接后通话控制仍需要公共 webhook。
使用一种公共暴露方式:
--yes,否则 voicecall smoke 仅执行试运行。
提供商凭据失败
检查所选提供商和必需的凭据字段:- Twilio:
twilio.accountSid、twilio.authToken和fromNumber,或者TWILIO_ACCOUNT_SID、TWILIO_AUTH_TOKEN和TWILIO_FROM_NUMBER。 - Telnyx:
telnyx.apiKey、telnyx.connectionId、telnyx.publicKey和fromNumber,或者TELNYX_API_KEY、TELNYX_CONNECTION_ID和TELNYX_PUBLIC_KEY。 - Plivo:
plivo.authId、plivo.authToken和fromNumber,或者PLIVO_AUTH_ID和PLIVO_AUTH_TOKEN。
通话已开始,但未收到提供商 webhook
确认提供商控制台指向准确的公共 webhook URL:publicUrl指向的路径与serve.path不同。- Gateway 网关启动后,隧道 URL 发生了变化。
- 代理转发了请求,但移除或改写了 host/proto 标头。
- 防火墙或 DNS 将公共主机名路由到了 Gateway 网关以外的位置。
- Gateway 网关重启时未启用语音通话插件。
webhookSecurity.allowedHosts 设置为公共主机名,或对已知代理地址使用
webhookSecurity.trustedProxyIPs。仅当代理边界
由你控制时才使用 webhookSecurity.trustForwardingHeaders。
签名验证失败
系统根据 OpenClaw 从传入请求中重建的公共 URL 检查提供商签名。如果签名失败:- 确认提供商 webhook URL 与
publicUrl完全匹配,包括协议、主机和路径。 - 对于 ngrok 免费套餐 URL,当隧道主机名变化时更新
publicUrl。 - 确保代理保留原始 host 和 proto 标头,或配置
webhookSecurity.allowedHosts。 - 除本地测试外,请勿启用
skipSignatureVerification。
Google Meet Twilio 加入失败
Google Meet 使用此插件通过 Twilio 拨号加入。首先验证语音 通话:--dtmf-sequence。电话通话可能正常,
但会议可能会拒绝或忽略错误的 DTMF 序列。
Google Meet 通过 voicecall.start 启动 Twilio 电话链路,并附带
连接前 DTMF 序列。由 PIN 派生的序列会将 Google Meet
插件的 voiceCall.dtmfDelayMs(默认 12000 ms)作为开头的 Twilio
等待数字,因为 Meet 拨号提示可能延迟出现。随后,语音通话会在请求
介绍问候语之前重定向回实时处理。
使用 openclaw logs --follow 查看实时阶段跟踪。正常的 Twilio Meet
加入会按以下顺序记录日志:
- Google Meet 将 Twilio 加入操作委托给语音通话。
- 语音通话存储连接前 DTMF TwiML。
- 在实时处理之前,系统使用并提供 Twilio 初始 TwiML。
- 语音通话为 Twilio 通话提供实时 TwiML。
- Google Meet 在 DTMF 后延迟结束后,使用
voicecall.speak请求介绍语音。
openclaw voicecall tail 仍会显示持久化的通话记录;它适用于查看
通话状态和转录文本,但并非所有 webhook/实时转换
都会显示在其中。
实时通话没有语音
确认仅启用一种音频模式:realtime.enabled 和
streaming.enabled 不能同时为 true。
对于实时 Twilio/Telnyx 通话,还需验证:
- 已加载并注册实时提供商插件。
realtime.provider未设置,或指定了已注册的提供商。- Gateway 网关进程可以使用提供商 API key。
openclaw logs --follow显示已提供实时 TwiML、实时桥接已启动且初始问候语已加入队列。