Skip to content

Voice Call 外掛程式

透過外掛程式為 OpenClaw 提供語音通話功能。支援外撥通知,以及透過內接政策進行的多輪對話。

目前支援的業者:

  • twilio (Programmable Voice + Media Streams)
  • telnyx (Call Control v2)
  • plivo (Voice API + XML 轉接 + GetInput 語音)
  • mock (開發/無網路)

快速概念模型:

  • 安裝外掛程式
  • 重新啟動 Gateway
  • plugins.entries.voice-call.config 下進行設定
  • 使用 openclaw voicecall ...voice_call 工具

Voice Call 外掛程式執行於 Gateway 程序內部

如果您使用遠端 Gateway,請在 執行 Gateway 的機器 上安裝/設定此外掛程式,然後重新啟動 Gateway 以載入它。

Terminal window
openclaw plugins install @openclaw/voice-call

之後重新啟動 Gateway。

選項 B:從本機資料夾安裝(開發用,不進行複製)

Section titled “選項 B:從本機資料夾安裝(開發用,不進行複製)”
Terminal window
PLUGIN_SRC=./path/to/local/voice-call-plugin
openclaw plugins install "$PLUGIN_SRC"
cd "$PLUGIN_SRC" && pnpm install

之後重新啟動 Gateway。

plugins.entries.voice-call.config 下設定:

{
plugins: {
entries: {
"voice-call": {
enabled: true,
config: {
provider: "twilio", // or "telnyx" | "plivo" | "mock"
fromNumber: "+15550001234",
toNumber: "+15550005678",
twilio: {
accountSid: "ACxxxxxxxx",
authToken: "...",
},
telnyx: {
apiKey: "...",
connectionId: "...",
// Telnyx webhook public key from the Telnyx Mission Control Portal
// (Base64 string; can also be set via TELNYX_PUBLIC_KEY).
publicKey: "...",
},
plivo: {
authId: "MAxxxxxxxxxxxxxxxxxxxx",
authToken: "...",
},
// Webhook server
serve: {
port: 3334,
path: "/voice/webhook",
},
// Webhook security (recommended for tunnels/proxies)
webhookSecurity: {
allowedHosts: ["voice.example.com"],
trustedProxyIPs: ["100.64.0.1"],
},
// Public exposure (pick one)
// publicUrl: "https://example.ngrok.app/voice/webhook",
// tunnel: { provider: "ngrok" },
// tailscale: { mode: "funnel", path: "/voice/webhook" }
outbound: {
defaultMode: "notify", // notify | conversation
},
streaming: {
enabled: true,
streamPath: "/voice/stream",
preStartTimeoutMs: 5000,
maxPendingConnections: 32,
maxPendingConnectionsPerIp: 4,
maxConnections: 128,
},
},
},
},
},
}

備註:

  • Twilio/Telnyx 需要一個 公開可存取 的 webhook URL。
  • Plivo 需要一個 公開可存取 的 webhook URL。
  • mock 是一個本機開發用業者(不進行網路呼叫)。
  • 除非 skipSignatureVerification 為 true,否則 Telnyx 需要 telnyx.publicKey(或 TELNYX_PUBLIC_KEY)。
  • skipSignatureVerification 僅供本機測試使用。
  • 如果您使用 ngrok 免費版,請將 publicUrl 設定為確切的 ngrok URL;簽章驗證始終會強制執行。
  • tunnel.allowNgrokFreeTierLoopbackBypass: true 僅在 tunnel.provider="ngrok"serve.bind 為 loopback(ngrok 本機代理程式)時,才允許簽章無效的 Twilio webhook。僅供本機開發使用。
  • Ngrok 免費版網址可能會變更或加入插入式行為;如果 publicUrl 偏移,Twilio 簽章將會驗證失敗。正式環境建議使用穩定的網域或 Tailscale funnel。
  • 串流安全預設值:
    • streaming.preStartTimeoutMs 會關閉從未傳送有效 start frame 的 socket。
    • streaming.maxPendingConnections 限制未經驗證的啟動前 socket 總數。
    • streaming.maxPendingConnectionsPerIp 限制每個來源 IP 的未經驗證的啟動前 socket 數量。
    • streaming.maxConnections 限制總共開啟的媒體串流 socket 數量(處理中 + 作用中)。

使用 staleCallReaperSeconds 來結束從未收到終結 webhook 的通話 (例如,從未完成的通知模式通話)。預設值為 0 (已停用)。

建議範圍:

  • 正式環境: 通知流程為 120300 秒。
  • 將此數值保持在 高於 maxDurationSeconds,以便正常通話能夠 完成一個不錯的起始點是 maxDurationSeconds + 30–60 秒。

範例:

{
plugins: {
entries: {
"voice-call": {
config: {
maxDurationSeconds: 300,
staleCallReaperSeconds: 360,
},
},
},
},
}

當 Proxy 或通道位於 Gateway 前端時,外掛程式會重建用於簽章驗證的 公開 URL。這些選項控制信任哪些轉發標頭。

webhookSecurity.allowedHosts 將轉發標頭中的主機加入允許清單。

webhookSecurity.trustForwardingHeaders 在沒有允許清單的情況下信任轉發標頭。

webhookSecurity.trustedProxyIPs 僅在請求遠端 IP 符合清單時才信任轉發標頭。

Twilio 和 Plivo 已啟用 Webhook 重放保護。重放的有效 Webhook 請求將會被確認,但會跳過副作用。

Twilio 對話回合在 <Gather> 回呼中包含每個回合的權杖,因此 過期/重放的語音回呼無法滿足較新的待處理文字記錄回合。

當提供者所需的簽章標頭缺失時,未經驗證的 webhook 請求會在讀取內文之前被拒絕。

Voice-call webhook 使用共享的預先驗證內文設定檔(64 KB / 5 秒), 以及在簽章驗證之前的每個 IP 進行中請求上限。

具有穩定公開主機的範例:

{
plugins: {
entries: {
"voice-call": {
config: {
publicUrl: "https://voice.example.com/voice/webhook",
webhookSecurity: {
allowedHosts: ["voice.example.com"],
},
},
},
},
},
}

Voice Call 使用核心 messages.tts 設定在通話上進行 語音串流。您可以使用 相同的結構 在外掛設定下覆寫它 — 它會與 messages.tts 深度合併。

{
tts: {
provider: "elevenlabs",
providers: {
elevenlabs: {
voiceId: "pMsXgVXv3BLzUgSXRplE",
modelId: "eleven_multilingual_v2",
},
},
},
}

備註:

  • 外掛程式設定內的舊版 tts.<provider> 金鑰 (openai, elevenlabs, microsoft, edge) 會在載入時自動遷移至 tts.providers.<provider>。建議在提交的設定中優先使用 providers 格式。
  • 語音通話會忽略 Microsoft 語音(電話音訊需要 PCM;目前的 Microsoft 傳輸方式不公開電話 PCM 輸出)。
  • 啟用 Twilio 媒體串流時會使用核心 TTS;否則通話會退回至提供者原生的語音。
  • 如果 Twilio 媒體串流已經啟用,Voice Call 不會退回至 TwiML <Say>。如果在此狀態下無法使用電話 TTS,播放請求將會失敗,而不是混合兩條播放路徑。
  • 當電話 TTS 退回至次要提供者時,Voice Call 會記錄包含提供者鏈 (from, to, attempts) 的警告以供偵錯。

僅使用核心 TTS(無覆寫):

{
messages: {
tts: {
provider: "openai",
providers: {
openai: { voice: "alloy" },
},
},
},
}

僅針對通話覆寫為 ElevenLabs(其他地方保持核心預設):

{
plugins: {
entries: {
"voice-call": {
config: {
tts: {
provider: "elevenlabs",
providers: {
elevenlabs: {
apiKey: "elevenlabs_key",
voiceId: "pMsXgVXv3BLzUgSXRplE",
modelId: "eleven_multilingual_v2",
},
},
},
},
},
},
},
}

僅覆寫通話的 OpenAI 模型(深度合併範例):

{
plugins: {
entries: {
"voice-call": {
config: {
tts: {
providers: {
openai: {
model: "gpt-4o-mini-tts",
voice: "marin",
},
},
},
},
},
},
},
}

來電原則預設為 disabled。若要啟用來電,請設定:

{
inboundPolicy: "allowlist",
allowFrom: ["+15550001234"],
inboundGreeting: "Hello! How can I help?",
}

inboundPolicy: "allowlist" 是一個低保驗證的來電顯示篩選器。此外掛程式會將提供者提供的 From 值標準化,並將其與 allowFrom 進行比較。 Webhook 驗證會驗證提供者傳送和負載的完整性,但它無法證明 PSTN/VoIP 來電號碼的所有權。請將 allowFrom 視為來電顯示篩選,而非強力的來電身份驗證。

自動回應使用代理系統。請透過以下方式調整:

  • responseModel
  • responseSystemPrompt
  • responseTimeoutMs

對於自動回應,Voice Call 會在系統提示詞中附加嚴格的口語輸出合約:

  • {"spoken":"..."}

然後 Voice Call 會防禦性地提取語音文字:

  • 忽略標記為推理/錯誤內容的負載。
  • 解析直接 JSON、圍籬 JSON 或行內 "spoken" 金鑰。
  • 會回退為純文字並移除可能的規劃/元資訊前導段落。

這樣可以保持語音播放專注於面向呼叫者的文字,並避免將規劃文字洩漏到音訊中。

對於 conversation 呼出,首則訊息的處理與即時播放狀態綁定:

  • 插隊佇列清除與自動回應僅在初始問候語正在播放時受到抑制。
  • 如果初始播放失敗,通話會返回 listening 狀態,且初始訊息會保留在佇列中以供重試。
  • Twilio 串流的初始播放會在串流連線建立時立即開始,無額外延遲。

當 Twilio 媒體串流斷線時,Voice Call 會等待 2000ms 才自動結束通話:

  • 如果串流在該期間內重新連線,將取消自動結束。
  • 如果寬限期過後沒有重新註冊串流,將結束通話以防止卡在活躍狀態。
Terminal window
openclaw voicecall call --to "+15555550123" --message "Hello from OpenClaw"
openclaw voicecall start --to "+15555550123" # alias for call
openclaw voicecall continue --call-id <id> --message "Any questions?"
openclaw voicecall speak --call-id <id> --message "One moment"
openclaw voicecall end --call-id <id>
openclaw voicecall status --call-id <id>
openclaw voicecall tail
openclaw voicecall latency # summarize turn latency from logs
openclaw voicecall expose --mode funnel

latency 會從預設的 voice-call 儲存路徑讀取 calls.jsonl。使用 --file <path> 指向不同的日誌,並使用 --last <n> 將分析限制 在最後 N 筆記錄(預設為 200)。輸出包含回合延遲 和聆聽等待時間的 p50/p90/p99 數值。

工具名稱:voice_call

動作:

  • initiate_call (message, to?, mode?)
  • continue_call (callId, message)
  • speak_to_user (callId, message)
  • end_call (callId)
  • get_status (callId)

此儲存庫在 skills/voice-call/SKILL.md 提供了相應的技能文件。

  • voicecall.initiate (to?, message, mode?)
  • voicecall.continue (callId, message)
  • voicecall.speak (callId, message)
  • voicecall.end (callId)
  • voicecall.status (callId)