--- summary: "电话 TTS、入站策略、按号码路由和呼叫生命周期计时器" read_when: - "您正在选择呼叫时使用的 TTS 语音" - "您正在启用呼入呼叫或按号码路由" - "您需要调整过时的呼叫收割者或呼叫持续时间上限" title: "语音呼叫 TTS 和呼入电话" sidebarTitle: "TTS 和呼入电话" --- 电话文本转语音、入站策略和每个号码路由、语音输出合同、对话启动和陈旧呼叫收割机。 [语音通话插件](/plugins/voice-call)指南的一部分。 ## 通话 TTS Voice Call 使用核心 `tts` 配置在通话中流式传输语音。 你可以在插件配置下使用**相同的结构**进行覆盖 — 它会与 `tts` 深度合并。 ```json5 { tts: { provider: "elevenlabs", providers: { elevenlabs: { speakerVoiceId: "pMsXgVXv3BLzUgSXRplE", modelId: "eleven_multilingual_v2", }, }, }, } ``` **Microsoft 语音会被通话忽略。** 电话合成需要一个实现 telephony-target 输出的提供商;Microsoft 语音提供商不支持,因此在通话中会被跳过,并改为尝试回退链中的其他提供商。 行为说明: - 插件配置内的旧版 `tts.` key(`openai`、`elevenlabs`、`microsoft`、`edge`)会被 `openclaw doctor --fix` 修复;已提交配置应使用 `tts.providers.`。 - 当启用 Twilio media streaming 时,会使用核心 TTS;否则通话会回退到提供商原生语音。 - 如果 Twilio media stream 已经处于活动状态,Voice Call 不会回退到 TwiML ``。如果此状态下电话 TTS 不可用,播放请求会失败,而不会混合两条播放路径。 - 当电话 TTS 回退到次级提供商时,Voice Call 会记录一条警告,其中包含提供商链(`from`、`to`、`attempts`)以便调试。 - 当 Twilio barge-in 或 stream 终止清空待处理的 TTS 队列时,排队中的播放请求会正常结束,而不会让等待播放完成的呼叫者挂起。 - 恢复的呼叫者语音会丢弃仍在生成的旧自动回复。 Twilio 流媒体对语音开始和部分转录做出反应;当新的语音事件到达时,运营商 Webhook 调用会做出反应。明确的语音请求仍然可用,并且已经接受的代理工作可以完成,而无需说出过时的答复。 ### TTS 示例 ```json5 { tts: { provider: "openai", providers: { openai: { speakerVoice: "alloy" }, }, }, } ``` ```json5 { plugins: { entries: { "voice-call": { config: { tts: { provider: "elevenlabs", providers: { elevenlabs: { apiKey: "elevenlabs_key", speakerVoiceId: "pMsXgVXv3BLzUgSXRplE", modelId: "eleven_multilingual_v2", }, }, }, }, }, }, }, } ``` ```json5 { plugins: { entries: { "voice-call": { config: { tts: { providers: { openai: { model: "gpt-4o-mini-tts", speakerVoice: "marin", }, }, }, }, }, }, }, } ``` ## 呼入电话 呼入策略默认是 `disabled`。要启用呼入电话,请设置: ```json5 { inboundPolicy: "allowlist", allowFrom: ["+15550001234"], inboundGreeting: "Hello! How can I help?", } ``` `inboundPolicy: "allowlist"`是低保证呼叫者-ID屏幕。该插件对提供商提供的 `From` 值进行标准化,并将其与 `allowFrom` 进行比较。 Webhook 验证可验证提供者交付和有效负载的完整性,但它确实 **不证明** 证明 PSTN/VoIP 呼叫者号码所有权。将`allowFrom`视为呼叫者-ID过滤,不强呼叫者身份。 自动响应使用 agent 系统。可通过 `responseModel`、 `responseSystemPrompt` 和 `responseTimeoutMs` 进行调优。 ### 按号码路由 当一个 Voice Call 插件接收多个电话号码的来电,并且每个号码都应表现得像不同线路时,请使用 `numbers`。例如, 一个号码可以使用随意的私人助手风格,而另一个使用商务人设、不同的响应 agent,以及不同的 TTS 声音。 路由会根据服务提供商提供的被拨叫 `To` 号码进行选择。键必须是 E.164 格式号码。来电到达时,Voice Call 会解析匹配的路由一次,将匹配到的路由存储在通话记录上,并在问候语、经典自动响应路径、实时咨询路径以及 TTS 播放中复用该有效配置。如果没有路由匹配,则使用全局 Voice Call 配置。外拨电话不会使用 `numbers`;发起通话时请显式传入外拨目标、消息和会话。 路由覆盖完全支持这些字段: - `inboundGreeting` - `tts` - `agentId` - `responseModel` - `responseSystemPrompt` - `responseTimeoutMs` `tts` 路由值会覆盖并深度合并到全局 Voice Call `tts` 配置之上,因此通常只需覆盖提供商语音: ```json5 { inboundGreeting: "Hello from the main line.", responseSystemPrompt: "You are the default voice assistant.", tts: { provider: "openai", providers: { openai: { speakerVoice: "coral" }, }, }, numbers: { "+15550001111": { inboundGreeting: "Silver Fox Cards, how can I help?", responseSystemPrompt: "You are a concise baseball card specialist.", tts: { providers: { openai: { speakerVoice: "alloy" }, }, }, }, }, } ``` ### 口语输出契约 对于自动响应,Voice Call 会在系统提示中附加一个严格的口语输出契约,要求返回 `{"spoken":"..."}` 的 JSON。Voice Call 会以防御性方式提取语音文本: - 忽略标记为 reasoning/error 内容的有效负载。 - 解析直接 JSON、带围栏的 JSON 或内联 `"spoken"` 键。 - 恢复为纯文本并删除可能的 planning/meta 引入段落。 这可使语音播放专注于面向来电者的文本,并避免将规划文本泄漏到音频中。 ### 会话启动行为 对于外拨 `conversation` 呼叫,首条消息的处理与实时播放状态相关: - 只有在初始问候正在播放时,才会抑制插话队列清理和自动响应。 - 如果初始播放失败,通话会回到 `listening`,并且初始消息会保留在队列中以便重试。 - Twilio streaming 的初始播放会在 stream connect 时立即开始,不会额外延迟。 - 插话会中止当前播放,并清除已排队但尚未播放的 Twilio TTS 条目。被清除的条目会以 skipped 方式解决,因此后续响应逻辑可以继续,而无需等待永远不会播放的音频。 - Realtime 语音会话使用 realtime stream 自己的开场轮次。Voice Call **不会** 为该初始消息发布旧版 `` TwiML 更新,因此外拨 `` 会话会保持连接。 ### Twilio 流断开宽限期 当 Twilio 经典流或实时媒体流断开连接时,语音呼叫会在自动结束呼叫之前等待 **2000 ms**: - 如果 stream 在该窗口内重新连接,自动结束会被取消。 - 如果宽限期结束后没有新的 stream 重新注册,则通话会结束,以防止卡住的活跃通话。 - 实时 bridge/session 资源、排队音频、转录所有权和飞行中咨询工作立即关闭。只有 call/provider 完成等待重新连接。 ## 陈旧通话清理器 使用 `staleCallReaperSeconds`(默认值为 **120**)来结束那些从未接听、也从未进入实时对话状态的通话,例如通知模式下运营商从未发送终止 webhook 的通话。将其设为 `0` 可禁用。 清理器每 30 秒运行一次,并且只会结束那些没有 `answeredAt` 时间戳、且尚未处于终态或实时(`speaking`/`listening`)状态的通话,因此已接听的对话永远不会被这个定时器清理;`maxDurationSeconds`(默认值 300)则是另一项上限,用于结束持续时间过长的已接听通话。 网关服务拥有收割者计划,并在关闭其呼叫管理器之前加入待处理的提供程序挂断。当提供商挂起时,错过的检查会合并。独立的 CLI 调用绑定到其现有可执行文件 CLI 所有者,该所有者将保持活动状态,直到调用运行时关闭。 对于通知式流程,运营商传送 ring/answer webhook 的速度可能很慢,请将 `staleCallReaperSeconds` 提高到默认值以上,这样缓慢但正常的呼叫就不会过早收获; `120`-`300`秒是一个合理的生产范围。 ```json5 { plugins: { entries: { "voice-call": { config: { maxDurationSeconds: 300, staleCallReaperSeconds: 120, }, }, }, }, } ```