跳到內容

設定 OpenClaw 語音通話插件:整合 Twilio、Telnyx 與 Plivo

想要讓你的 AI 機器人直接打電話給使用者,或是接聽客戶的詢問嗎?處理語音通話通常很麻煩,要搞定各種 Webhook、串流協議還有不同供應商的 API 差異。OpenClaw 的 Voice Call 插件就是為了簡化這一切而設計的,讓你透過簡單的設定就能賦予機器人說話與聽取語音的能力。

這個插件支援主動撥打通知,也支援帶有入境策略的多輪對話。目前支援的供應商包括:

  • twilio (Programmable Voice + Media Streams)
  • telnyx (Call Control v2)
  • plivo (Voice API + XML transfer + GetInput speech)
  • mock (開發專用,不需網路)

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 免費版 URL 可能會變動或加入中間頁面;如果 publicUrl 跑掉了,Twilio 簽名驗證會失敗。生產環境建議使用固定域名或 Tailscale funnel。
  • 串流安全預設值:
    • streaming.preStartTimeoutMs 會關閉那些從未發送有效 start 幀的 socket。
    • streaming.maxPendingConnections 限制未經身份驗證的預啟動 socket 總數。
    • streaming.maxPendingConnectionsPerIp 限制每個來源 IP 的未經身份驗證預啟動 socket 數量。
    • streaming.maxConnections 限制總共開啟的媒體串流 socket 數量(包含待處理與活動中)。

使用 staleCallReaperSeconds 來結束那些從未收到終端 Webhook 的通話(例如,從未完成的通知模式通話)。預設值為 0(禁用)。

推薦範圍:

  • 生產環境: 通知型流程建議設定為 120–300 秒。
  • 確保這個值高於 maxDurationSeconds,這樣正常的通話才能完成。一個好的起點是 maxDurationSeconds + 30–60 秒。

範例:

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

當 Gateway 前方有代理伺服器或隧道時,插件會重建公開 URL 以進行簽名驗證。以下選項控制哪些轉發標頭 (forwarded headers) 是可信的。

webhookSecurity.allowedHosts 允許來自轉發標頭的特定主機白名單。

webhookSecurity.trustForwardingHeaders 在沒有白名單的情況下信任轉發標頭。

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

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

Twilio 對話輪次在 <Gather> 回呼中包含每輪 token,因此過期或重放的語音回呼無法滿足較新的待處理轉錄輪次。

如果缺少供應商要求的簽名標頭,未經身份驗證的 Webhook 請求會在讀取 body 之前被拒絕。

Voice Call Webhook 使用共享的預認證 body 設定(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 進行深度合併 (deep-merge)。

{
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 視為來電過濾,而非強大的身份認證。

自動回覆使用 Agent 系統。你可以透過以下參數進行微調:

  • responseModel
  • responseSystemPrompt
  • responseTimeoutMs

語音輸出規範 (Spoken output contract)

Section titled “語音輸出規範 (Spoken output contract)”

對於自動回覆,Voice Call 會在系統提示詞中附加一個嚴格的語音輸出規範:

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

隨後 Voice Call 會防禦性地提取語音文本:

  • 忽略標記為推理或錯誤內容的資料。
  • 解析直接的 JSON、fenced JSON 或行內的 "spoken" 鍵。
  • 回退到純文本,並移除可能的規劃或元數據引導段落。

這能確保語音播放集中在面向來電者的文本,避免將規劃過程的文字洩漏到音訊中。

對於撥出的 conversation 通話,首條訊息的處理與即時播放狀態掛鉤:

  • 僅在初始問候語正在播放時,才會抑制插嘴 (barge-in) 隊列清理與自動回覆。
  • 如果初始播放失敗,通話會回到 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)

下一步:

有任何設定上的問題嗎?試試我們的 AI Setup Assistant!

OpenClaw

OpenClaw Expert

還是卡住了?

如果這篇文件沒有解決你的情境,直接問 OpenClaw Expert,拿到可執行步驟。