mock(开发环境,无网络)、plivo(语音 API + XML 转接 +
GetInput 语音)、telnyx(Call Control v2)、twilio(可编程语音 +
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 启动时会记录一条 setup-incomplete 警告,指出缺失的键,并跳过运行时启动。命令、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.allowNgrokFreeTierLoopbackBypass: true仅当tunnel.provider="ngrok"且serve.bind为 loopback(ngrok 本地代理)时,才允许使用无效签名的 Twilio webhook。仅限本地开发。- ngrok 免费套餐的 URL 可能会变化或增加中间页行为;如果
publicUrl发生漂移,Twilio 签名将失败。生产环境:优先使用稳定域名或 Tailscale funnel。
流式连接上限
流式连接上限
streaming.preStartTimeoutMs(默认5000)会关闭从未发送有效start帧的 socket。streaming.maxPendingConnections(默认32)限制未认证、未开始的 socket 总数。streaming.maxPendingConnectionsPerIp(默认4)限制每个源 IP 的未认证、未开始 socket 数。streaming.maxConnections(默认128)限制所有打开的媒体流 socket(待处理 + 活跃)。
旧配置迁移
旧配置迁移
配置解析会自动规范化这些旧键,并记录一条警告,说明替换路径;该兼容层将在未来版本(
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已移除(realtime 上下文现在使用生成的代理提示词)
会话范围
默认情况下,Voice Call 使用sessionScope: "per-phone",因此来自
同一来电者的重复通话会保留对话记忆。若每个运营商通话都应以新的上下文开始,
例如接待、预订、IVR,或 Google Meet bridge 流程中同一电话号码可能
代表不同会议时,请设置为 sessionScope: "per-call"。
Voice Call 会将生成的会话密钥存储在已配置的 agent 命名空间下
(agent:<agentId>:voice:*)。原始的显式集成密钥会解析到同一命名空间:
一个规范化的 agent:<configuredAgentId>:* 密钥会保留其所有者,并遵循核心的
session.mainKey/global-scope 别名规则;外部或格式错误的 agent:*
输入会作为一个不透明密钥,归入已配置的 agent 下;global 和 unknown
则保持为全局哨兵值。
实时语音对话
realtime 为实时通话音频选择一个全双工实时语音提供商。
它与 streaming 是分开的,后者只会把音频转发给实时
转录提供商。
当前运行时行为:
realtime.enabled支持 Twilio 和 Telnyx。realtime.provider为可选项。如果未设置,Voice Call 将使用第一个已注册的实时语音提供商。- 内置实时语音提供商:Google Gemini Live(
google)和 OpenAI(openai),由各自的提供商插件注册。 - 提供商自有的原始配置位于
realtime.providers.<providerId>下。 - Voice Call 默认公开共享的
openclaw_agent_consult实时工具。当呼叫者要求更深入的推理、最新信息或普通 OpenClaw 工具时,实时模型可以调用该工具。 realtime.consultPolicy可选地为实时模型何时应调用openclaw_agent_consult添加指导。realtime.agentContext.enabled默认关闭。启用后,Voice Call 会在会话设置时,将受限的代理身份信息和选定的工作区文件摘要注入实时提供商的指令中。realtime.fastContext.enabled默认关闭。启用后,Voice Call 会先搜索已建立索引的记忆/会话上下文,并在realtime.fastContext.timeoutMs时间内将授权片段返回给实时模型;仅当realtime.fastContext.fallbackToConsult为true时,才会回退到完整的 consult 代理。当前的记忆插件会授权会话转录命中;不具备该能力的插件会对会话命中安全失败,但普通记忆命中仍然可用。- 如果
realtime.provider指向未注册的提供商,或根本没有注册实时语音提供商,Voice Call 会记录警告并跳过实时媒体,而不是导致整个插件失败。 - 当
realtime.enabled为true时,inboundPolicy不能为"disabled";validateProviderConfig会拒绝这种组合。 - 当存储的通话会话可用时,Consult 会话键会复用该会话;否则回退到配置的
sessionScope(默认为per-phone,隔离通话时则为per-call)。
工具策略
realtime.toolPolicy 控制 consult 运行:
realtime.consultPolicy 仅控制实时模型指令:
代理语音上下文
当语音桥需要听起来像配置的 OpenClaw 代理,同时又不想在普通轮次中支付完整 agent-consult 往返成本时,启用realtime.agentContext。上下文胶囊会在实时会话创建时添加一次,因此不会增加每轮延迟。对 openclaw_agent_consult 的调用仍会运行完整的 OpenClaw 代理,并且应当用于工具工作、当前信息、记忆查询或 workspace 状态。
实时提供商示例
- 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是可选项。如果未设置,Voice Call 会使用第一个已注册的实时转录提供商。- 内置实时转录提供商:Deepgram(
deepgram)、ElevenLabs(elevenlabs)、Mistral(mistral)、OpenAI(openai)和 xAI(xai),由其提供商插件注册。 - 提供商专属原始配置位于
streaming.providers.<providerId>下。 - Twilio 发送已接受的 stream
start消息后,Voice Call 会立即注册该流,在提供商连接期间通过转录提供商排队传入媒体,并且只有在实时转录就绪后才开始初始问候语。 - 如果
streaming.provider指向未注册的提供商,或未注册任何提供商,Voice Call 会记录警告并跳过媒体流,而不是使整个插件失败。
流式提供商示例
- OpenAI
- xAI
默认值:API key 为
streaming.providers.openai.apiKey 或
OPENAI_API_KEY;模型为 gpt-4o-transcribe;silenceDurationMs: 800;
vadThreshold: 0.5。通话 TTS
Voice Call 使用核心tts 配置在通话中流式传输语音。
你可以在插件配置下使用相同的结构进行覆盖 —
它会与 tts 深度合并。
- 插件配置内的旧版
tts.<provider>key(openai、elevenlabs、microsoft、edge)会被openclaw doctor --fix修复;已提交配置应使用tts.providers.<provider>。 - 当启用 Twilio media streaming 时,会使用核心 TTS;否则通话会回退到提供商原生语音。
- 如果 Twilio media stream 已经处于活动状态,Voice Call 不会回退到 TwiML
<Say>。如果此状态下电话 TTS 不可用,播放请求会失败,而不会混合两条播放路径。 - 当电话 TTS 回退到次级提供商时,Voice Call 会记录一条警告,其中包含提供商链(
from、to、attempts)以便调试。 - 当 Twilio barge-in 或 stream 终止清空待处理的 TTS 队列时,排队中的播放请求会正常结束,而不会让等待播放完成的呼叫者挂起。
TTS 示例
- 仅使用核心 TTS
- 覆盖为 ElevenLabs(仅通话)
- OpenAI 模型覆盖(深度合并)
呼入电话
呼入策略默认是disabled。要启用呼入电话,请设置:
responseModel、
responseSystemPrompt 和 responseTimeoutMs 进行调优。
按号码路由
当一个 Voice Call 插件接收多个电话号码的来电,并且每个号码都应表现得像不同线路时,请使用numbers。例如,
一个号码可以使用随意的私人助手风格,而另一个使用商务
人设、不同的响应 agent,以及不同的 TTS 声音。
路由会根据服务提供商提供的被拨叫 To 号码进行选择。键必须
是 E.164 格式号码。来电到达时,Voice Call 会解析匹配的
路由一次,将匹配到的路由存储在通话记录上,并在问候语、经典自动响应路径、实时
咨询路径以及 TTS 播放中复用该有效配置。如果没有路由匹配,则使用全局 Voice Call
配置。外拨电话不会使用 numbers;发起通话时请显式传入外拨
目标、消息和会话。
当前支持的路由覆盖项:
inboundGreetingttsagentIdresponseModelresponseSystemPromptresponseTimeoutMs
tts 路由值会覆盖并深度合并到全局 Voice Call tts 配置之上,因此通常只需覆盖提供商语音:
口语输出契约
对于自动响应,Voice Call 会在系统提示中附加一个严格的口语输出契约,要求返回{"spoken":"..."} 的 JSON。Voice Call 会以防御性方式提取语音文本:
- 忽略标记为推理/错误内容的载荷。
- 解析直接 JSON、带围栏的 JSON 或内联
"spoken"键。 - 回退到纯文本,并移除可能的规划/元信息开头段落。
会话启动行为
对于外拨conversation 呼叫,首条消息的处理与实时播放状态相关:
- 只有在初始问候正在播放时,才会抑制插话队列清理和自动响应。
- 如果初始播放失败,通话会回到
listening,并且初始消息会保留在队列中以便重试。 - Twilio streaming 的初始播放会在 stream connect 时立即开始,不会额外延迟。
- 插话会中止当前播放,并清除已排队但尚未播放的 Twilio TTS 条目。被清除的条目会以 skipped 方式解决,因此后续响应逻辑可以继续,而无需等待永远不会播放的音频。
- Realtime 语音会话使用 realtime stream 自己的开场轮次。Voice Call 不会 为该初始消息发布旧版
<Say>TwiML 更新,因此外拨<Connect><Stream>会话会保持连接。
Twilio 流断开宽限期
当 Twilio media stream 断开时,Voice Call 会等待 2000 ms 后才 自动结束通话:- 如果 stream 在该窗口内重新连接,自动结束会被取消。
- 如果宽限期结束后没有新的 stream 重新注册,则通话会结束,以防止卡住的活跃通话。
陈旧通话清理器
使用staleCallReaperSeconds(默认值为 120)来结束那些从未接听、也从未进入实时对话状态的通话,例如通知模式下运营商从未发送终止 webhook 的通话。将其设为 0 可禁用。
清理器每 30 秒运行一次,并且只会结束那些没有 answeredAt 时间戳、且尚未处于终态或实时(speaking/listening)状态的通话,因此已接听的对话永远不会被这个定时器清理;maxDurationSeconds(默认值 300)则是另一项上限,用于结束持续时间过长的已接听通话。
对于通知式流程,如果运营商发送响铃/接听 webhook 的速度较慢,可以将 staleCallReaperSeconds 调高到默认值以上,以免把正常但较慢的通话过早清理;120-300 秒是一个合理的生产环境范围。
Webhook 安全
当代理或隧道位于网关前方时,插件会重建用于签名验证的公共 URL。以下选项用于控制哪些转发头被信任:string[]
允许来自转发头的主机白名单。
boolean
在没有白名单的情况下信任转发头。
string[]
仅当请求的远程 IP 与列表匹配时才信任转发头。
- 对于 Twilio、Telnyx 和 Plivo,Webhook 重放防护已启用。重放的有效 Webhook 请求会被确认,但会跳过副作用处理。
- Twilio 对话轮次会在
<Gather>回调中包含每轮的令牌,因此过期或重放的语音回调无法满足更新的待处理转写轮次。 - 当提供方所需的签名头缺失时,未认证的 Webhook 请求会在读取正文之前被拒绝。
- 语音通话 Webhook 在签名验证之前使用共享的预认证正文读取配置文件(最大 64 KB 正文、5 秒读取超时),并为每个密钥设置进行中的请求上限(默认每个密钥 8 个并发请求)。
CLI
voicecall 的操作命令会委托给由 Gateway 管理的 voice-call 运行时,因此 CLI 不会再绑定第二个 webhook 服务器。如果找不到可用的 Gateway,这些命令会回退到独立的 CLI 运行时。
latency 会从默认的 voice-call 存储路径读取 calls.jsonl。使用 --file <path> 可以指定其他日志文件,使用 --last <n> 可以将分析限制为最后 N 条记录(默认 200)。输出包含轮次延迟和听取等待时间的最小值/最大值/平均值、p50 和 p95。
智能体工具
工具名称:voice_call。
voice-call 插件附带一个匹配的智能体技能。
网关 RPC
dtmfSequence 仅在 mode: "conversation" 时有效;notify 模式的通话
如果需要在连接后发送按键,应在通话建立后使用 voicecall.dtmf。
故障排查
Setup webhook 暴露失败
从运行 Gateway 的相同环境中运行 setup: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,或其他 carrier-grade-NAT 地址段用作 publicUrl。
Twilio notify-mode outbound calls 会在 create-call 请求中直接发送其初始 <Say> TwiML,因此第一条播报消息不依赖于 Twilio 获取 webhook TwiML。即便如此,状态回调、会话通话、预连接 DTMF、实时流以及连接后通话控制仍然需要一个公共 webhook。
使用一种公共暴露路径:
--yes,否则 voicecall smoke 只是一次 dry run。
提供商凭据失败
检查所选提供商以及所需的凭据字段:- 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与提供商配置的公共 webhook URL 不匹配。反向代理可以将该公共路径映射到不同的serve.path,但publicUrl必须保持为面向提供商的 URL。- Gateway 启动后隧道 URL 发生了变化。
- 代理转发了请求,但移除或重写了 host/proto 头。
- 防火墙或 DNS 将公共主机名路由到了 Gateway 以外的位置。
- Gateway 重启时未启用 Voice Call 插件。
webhookSecurity.allowedHosts 设置为公共主机名,或者对已知代理地址使用 webhookSecurity.trustedProxyIPs。仅当代理边界由你控制时,才使用 webhookSecurity.trustForwardingHeaders。
签名验证失败
Twilio and Plivo URL signatures usepublicUrl when it is configured: its
scheme, host, and path are preserved, while the request query is applied.
Without publicUrl, OpenClaw reconstructs the URL from the request. Telnyx
signatures do not include the request URL. If signatures fail:
- 确认提供商 webhook URL 与
publicUrl完全一致,包括 scheme、host 和 path。 - 对于 ngrok 免费层级的 URL,当隧道主机名变化时更新
publicUrl。 - 确保代理保留原始的 host 和 proto 头,或者配置
webhookSecurity.allowedHosts。 - 不要在本地测试之外启用
skipSignatureVerification。
Google Meet Twilio 加入失败
Google Meet 使用此插件来完成 Twilio 拨入加入。首先验证 Voice Call:--dtmf-sequence。电话呼叫本身可能是正常的,但会议会拒绝或忽略错误的 DTMF 序列。
Google Meet 通过带有预连接 DTMF 序列的 voicecall.start 启动 Twilio 电话链路。基于 PIN 生成的序列会包含 Google Meet 插件的 voiceCall.dtmfDelayMs(默认 12000 ms)作为前导 Twilio 等待数字,因为 Meet 的拨入提示可能会延迟到达。随后 Voice Call 会在请求介绍语音之前切回实时处理。
使用 openclaw logs --follow 查看实时阶段追踪。健康的 Twilio Meet 加入日志顺序如下:
- Google Meet 将 Twilio 加入委托给 Voice Call。
- Voice Call 存储预连接 DTMF TwiML。
- 在实时处理之前,Twilio 初始 TwiML 被消耗并提供。
- Voice Call 为 Twilio 呼叫提供实时 TwiML。
- Google Meet 在 post-DTMF 延迟后使用
voicecall.speak请求介绍语音。
openclaw voicecall tail 仍然会显示已持久化的通话记录;它对通话状态和转录很有用,但并不是每个 webhook/实时转换都会出现在那里。
实时呼叫没有语音
确认只启用了一个音频模式:realtime.enabled 和
streaming.enabled 不能同时为 true。
对于实时 Twilio/Telnyx 呼叫,还要验证:
- 已加载并注册实时提供商插件。
realtime.provider未设置,或指定了一个已注册的提供商。- 提供商 API key 对 Gateway 进程可用。
openclaw logs --follow显示已提供实时 TwiML、实时桥接已启动,并且初始问候语已排队。