自架私有 AI 客服答錄系統:元件、成本與個資法
有人拿一台 AI 接聽整機來報價時,把同樣的流程拆成通道、語音辨識、模型、語音合成與真人接手五段:你租的 VPS 已經能做哪幾段、哪幾段才真的需要 GPU、繁體中文為什麼是最弱的一環,以及通話錄音該怎麼告知與刪除才過得了個資法。成本欄位與量測方法都給你自己填,不抄別人的秒數。
自架私有 AI 客服答錄要蓋的五段
自架私有 AI 客服答錄系統可以拆成五段各自獨立的元件:客人進來的通道、語音辨識(STT,speech to text,把聲音變成文字)、語言模型、語音合成(TTS,text to speech,把文字變成聲音),以及轉給真人的那一刻。五段可以分開做、分開換,也會分開壞。你現在租的那台 VPS 就能把其中幾段做得很好,剩下的才是要花錢的地方。
要不要直接買一台整機,是另一個問題,整機私有 AI 主機與自架的取捨那邊已經把帳算過一遍。這裡只把五段拆開,講清楚每一段在你手上的主機是什麼樣子,以及哪一段會逼你去買顯示卡。
先講結論裡最違反直覺的一件事:最弱的一環不是語言模型。模型這一段現在便宜又穩定。真正難的是繁體中文的語音辨識,和聽起來不像機器的中文語音合成。
第一段:客人是打電話來,還是從 LINE 來
台灣與香港的中小企業,第一次客戶接觸多半不是電話,而是 LINE 官方帳號、WhatsApp 或網站上的聊天視窗。這件事直接決定你的第一版要蓋什麼。
文字通道少掉兩段轉換。沒有語音辨識,就沒有聽錯字的問題;沒有語音合成,就沒有唸錯破音字的問題。出錯的地方只剩模型本身和你的流程設計,所以修起來快,上線也快。成本結構也不一樣:文字通道沒有每分鐘通話費,也沒有號碼月租。
LINE 官方帳號走 Messaging API 的 webhook,你的伺服器要提供一個 https 端點,先用 channel secret 驗證 x-line-signature 這個標頭的 HMAC-SHA256 簽章,確認請求真的來自平台,再回覆訊息。這是一台普通 VPS 最擅長的工作:接 HTTP、查資料、呼叫模型、寫紀錄。
電話那條路值得蓋,但它應該是第二版。如果你的客人一天只打三通電話,而 LINE 一天進來八十則訊息,先做語音是把預算花在流量最小的通道上。
電話那條路:SIP 中繼線要怎麼接進來
以 Asterisk 為例(FreeSWITCH 或 Kamailio 也能做同一件事)。你需要電信商或 SIP 服務商給你一組帳號,Asterisk 用它去註冊,之後打進那個號碼的通話就會落在你的撥號計畫裡。
sudo apt update && sudo apt install -y asterisk ffmpeg opencc; /etc/asterisk/pjsip.conf
[trunk-reg]
type=registration
outbound_auth=trunk-auth
server_uri=sip:sip.example.net
client_uri=sip:0212345678@sip.example.net
retry_interval=60
[trunk-auth]
type=auth
auth_type=userpass
username=0212345678
password=換成服務商給你的密碼
[trunk]
type=endpoint
context=from-trunk
disallow=all
allow=ulaw,alaw
aors=trunk-aor
outbound_auth=trunk-auth
[trunk-aor]
type=aor
contact=sip:sip.example.net
[trunk-identify]
type=identify
endpoint=trunk
match=sip.example.net通話進來之後要交給你自己的程式,Asterisk 這一側用 ARI(Asterisk REST Interface)。撥號計畫把通話丟進 Stasis(),你的程式就接管了這通電話。
; /etc/asterisk/ari.conf
[general]
enabled = yes
[answerbot]
type = user
read_only = no
password = 換成一組夠長的密碼; /etc/asterisk/extensions.conf
[from-trunk]
exten => _X.,1,Answer()
same => n,Playback(custom/recording-notice-zh)
same => n,MixMonitor(${UNIQUEID}.wav,b)
same => n,Stasis(answerbot)
same => n,Hangup()改完設定之後檢查兩件事:
sudo asterisk -rx "pjsip show registrations"
sudo asterisk -rx "ari show apps"第一條指令的 Status 欄位應該是 Registered。出現 Rejected 表示帳密或 client_uri 裡的號碼寫錯,服務商回了 401 或 403;出現 Unregistered 表示註冊封包根本沒送到或沒回來,通常是防火牆擋了 SIP 的 UDP 5060,或者主機商面板上另一層網路防火牆沒開。第二條指令要列出 answerbot,沒列出來就是你的程式還沒連上 ARI,這時通話會進 Stasis() 然後立刻被掛掉。
還有一個幾乎每個人都會遇到的狀況:訊號通了,電話接起來了,但只有一邊聽得到聲音。SIP 訊號和語音資料走不同的路,語音走 RTP,用的是另一段 UDP 埠。單向通話幾乎都是 rtp.conf 裡 rtpstart 到 rtpend 那段埠沒有在防火牆上開,或者主機在 NAT(network address translation,網路位址轉換)後面而 external_media_address 沒設。用 sudo asterisk -rvvv 掛在前景,再下 rtp set debug on,就能看到封包到底有沒有進來。
注意 MixMonitor 放在 Playback 後面,代表錄音提示音本身不會被錄進檔案。如果你希望留下「我們確實告知過」的證據,就把 MixMonitor 移到 Playback 前面。這是一個法務決定,不是技術決定。
第二段:繁體中文語音辨識為什麼是最弱的一環
這一段是整個系統的品質上限。模型再聰明,也只能回答它收到的那串文字。
電話是窄頻音訊。 G.711 的取樣率是 8 kHz,高頻資訊在通道裡就被丟掉了,而 Whisper 這一類模型是用 16 kHz 音訊訓練的。你當然要轉檔,但要知道轉檔只是補格式:
ffmpeg -i call.wav -ar 16000 -ac 1 -c:a pcm_s16le call-16k.wav-ar 16000 把取樣率拉上去,補不回原本沒錄到的頻率。所以同一句話,客人用手機 App 錄下來的辨識率會明顯好過打電話進來的。拿你自己真實的電話錄音去測,不要拿乾淨的朗讀檔。
繁簡字形要自己處理。 Whisper 系列的 language=zh 只管語言,不管字形,輸出經常是簡體,或者繁簡混在同一句裡。兩個做法要一起用:後處理用 OpenCC 轉成台灣用字,前處理用 initial_prompt 餵一段繁體例句去偏移輸出。
opencc -i raw.txt -o raw-tw.txt -c s2twp.jsons2twp.json 這個設定會連詞彙一起換(例如把「軟件」換成「軟體」)。它不會處理你公司的專有名詞,那個要自己維護一份對照表。
中英夾雜和方言。 台灣的客人講話會夾英文品牌名,香港的客人講粵語,而開源模型對粵語的支援普遍比國語差。如果你的客人講粵語,先測這一段再決定要不要做語音。
最重要的資訊最容易錯。 電話裡真正有價值的是人名、地址、訂單號和數字,而這些恰好是辨識錯誤率最高的部分,因為它們沒有上下文可以幫模型猜。工程上沒有辦法把這一段做到完美,所以流程要吸收它:機器一定要把聽到的訂單號和地址複述一次讓客人確認,確認不過就轉真人。
模型選擇、量化與部署方式在自架語音辨識與語音合成那篇講得比較細,這裡只強調一件事:這一段的驗收標準是你自己的錄音,不是別人公布的字錯率。
第三段:語言模型反而是最好解決的一段
文字進、文字出,沒有音訊格式問題,也不需要即時串流。一台普通 VPS 拿來做編排(orchestration)完全夠用:收訊息、查你的商品與營業時間、組 prompt、呼叫模型、把結果寫回工單。
第一版直接用 API。它讓你在不買硬體的前提下驗證整個流程,而且中文能力現在已經不是瓶頸。要控制帳單就把上限設在你自己的程式裡,把 AI 代理的用量天花板先設好是上線前就該做的事,不是超支之後才做。
會讓你改成在地模型的理由只有兩個:合約或內規要求通話內容不得離開你自己的機房,或者用量大到 API 費用超過硬體攤提。這時候才進到 GPU 的討論,在自己的 VPS 上跑 Ollama是最短的起點,而多大的模型塞得進你的記憶體決定你實際能載入什麼。要同時服務多線通話的時候,推論引擎的選擇會比模型選擇更影響結果,Ollama 與 vLLM 在批次與併發上的差別就是這個題目。
在地模型最常見的第一個故障是請求逾時,錯誤訊息長這樣:
Error: post predict: Post "http://127.0.0.1:...": context deadline exceeded它通常代表模型被換出到硬碟、或第一次載入太久,而不是模型壞了。context deadline exceeded 的排查順序有完整步驟。在電話場景裡這個錯誤特別致命,因為客人聽到的是一段無法解釋的沉默。
第四段:中文語音合成聽起來還是像機器
如果你的通道是文字,這一段可以整個不要。要做語音,就要接受目前中文 TTS 的兩個現實。
第一,開源的中文語音數量不多,粵語更少,而且多數聽起來能懂但不自然。第二,錯的地方很固定:破音字(「行」、「重」、「長」)、數字的唸法(電話號碼要一位一位唸,金額要帶單位)、中文句子裡的英文品牌名,以及句子之間的停頓。
可行的做法是把 TTS 的工作量降到最低。開場、確認、結尾、營業時間這些固定句子,找真人錄成音檔,用 Playback() 播放,品質直接跳一級。只有真正動態的內容才交給 TTS。而在送進 TTS 之前,先把數字、日期和地址在程式裡展開成明確的中文讀法,不要期待模型自己猜對。
驗收方式也很土:把你打算上線的句子錄成音檔,放給三位不知道這是機器的同事聽,問他們聽不聽得懂訂單號。聽不懂就是不能上線。
第五段:真人接手,以及轉接失敗的時候
每一通對話都必須有出口。沒有出口的自架客服會用一種很難看的方式失敗:客人重複同一個問題四次,然後掛掉電話再也不回來。
四個應該立刻轉真人的條件:客人直接說要找人、同一個問題連續兩輪沒有解決、對話裡出現投訴或情緒關鍵字、語音辨識或模型的信心值偏低。這些都寫在你的編排程式裡,不要寫在 prompt 裡,因為你需要它百分之百觸發。
轉接本身也會失敗。非上班時間沒人接,上班時間可能全部佔線。這時要有排隊(Asterisk 的 Queue())、留言,以及一個明確的回撥承諾,而不是把電話掛掉。
最後一件事最常被忽略:逐字稿要跟著通話一起交給真人。同事接起來的第一秒就要看到前面機器和客人講了什麼。少了這一步,客人要從頭再講一次,那他會認定整套系統只是在浪費他的時間。
一台普通 VPS 做得好的事,和會逼你買 GPU 的事
普通 VPS 做得很好的部分:SIP 訊號與撥號計畫、編排與狀態機、逐字稿與工單儲存、排隊與回撥、LINE 與網頁的 webhook、呼叫外部模型 API。這些工作是 I/O 密集加少量 CPU,一台幾核心的機器可以撐很久。
會把你推向 GPU 或廠商整機的部分:多線通話同時做即時串流語音辨識、在本機跑語言模型推論、在本機跑品質較好的語音合成,以及「音訊與逐字稿都不得離開自有硬體」這種合約要求。顯示記憶體的容量決定你能載入什麼,而併發數決定你需要幾張卡,這兩個數字要用你自己的話務量去推,一台自架模型主機能同時服務幾個使用者和自己組一台 AI 主機的成本結構是做這個計算的兩份材料。
中間還有一條路常被忘記:語音辨識放在 GPU 主機上,其他全部留在便宜的 VPS 上,兩台之間用內部網路連。你不需要把整套系統搬上顯示卡。
管理介面則不必暴露在公網,用通道把後台接出去而不開對外埠是比開 443 更省事的做法。要注意 SIP 訊號與 RTP 語音走 UDP,這類 HTTP 通道載不了,電話那一側的埠還是得自己在防火牆上處理。
成本怎麼算:一張你自己填的表
截至 2026 年 9 月,SIP 中繼線、號碼月租與模型 API 的報價差異大到在這裡印任何數字都會誤導你。所以這裡給的是欄位,數字請你拿自己的報價單填。
把成本分成四行。固定費:主機月租、號碼月租、憑證與網域。按量費:通話分鐘數、模型的 token 數、TTS 的字元數、語音辨識的音訊分鐘數。人的成本:真人接手的工時、詞表與 prompt 的維護時間。一次性成本:真人錄音、法務審閱、串接的開發時間。
填完之後只算兩個數字:每通對話的平均成本,以及每一次「真的解決了客人問題」的成本。第二個數字才是能跟整機報價比較的東西。用三十天的真實話務量回填,不要用估的。一台整機的報價看起來貴,但如果它省掉的是你兩個月的串接工時,帳不一定站在自架這邊。
每一跳自己量,不要抄別人的秒數
任何人給你的延遲數字都不會在你的硬體上重現,包含這篇。正確的做法是先訂一個你能接受的總預算,再把它切給每一跳。
電話場景的總預算是「客人講完到機器開口之前的那段沉默」。那段沉默太長,客人會以為斷線然後說「喂?」,整個對話就亂了。文字場景寬鬆得多,因為對方看得到輸入中的提示。先決定這個上限,再把它分給音訊收集、語音辨識、模型、語音合成與播放這五跳。
量法是每一跳打時間戳,存進同一筆紀錄。單獨量某個端點的話:
for i in $(seq 1 20); do
curl -s -o /dev/null -w '%{time_total}\n' \
-F 'file=@call-16k.wav' \
http://127.0.0.1:9000/v1/audio/transcriptions
done | sort -n | awk '{v[NR]=$1} END {print v[int(NR*0.5)], v[int(NR*0.95)]}'印出來的兩個數字是中位數和第 95 百分位。要看的是第 95 百分位,因為平均值會被少數很快的請求拉低,而客人記得的是慢的那幾通。同一份測試在你換模型、換量化、換主機之後要重跑一次。要把每一通對話的每一跳都留下來,自架 Langfuse 追蹤代理的每一次呼叫比自己寫 log 解析器省事。
錄音與逐字稿:個資法要求你做到的四件事
通話錄音是個人資料,逐字稿也是,而且逐字稿更好搜尋,所以外洩的傷害更大。台灣看個人資料保護法(個資法),香港看個人資料(私隱)條例的保護資料原則,條文不同,但工程上要做到的事高度重疊。
告知。 錄音開始前要講清楚是誰在錄、為什麼錄、會怎麼使用,以及當事人可以要求查詢、更正與刪除。這段話錄成音檔用 Playback() 播,文字通道則放在對話的第一則訊息裡。
目的限制。 以「客服品質與訂單處理」蒐集的錄音,不能轉去做行銷名單,也不能拿去訓練模型,除非另外取得同意。這一條最常被踩到的方式是工程師覺得「資料都在手上,順便拿來調模型」。
保存期限。 寫下天數,然後讓系統自己刪。刪除必須涵蓋音訊、逐字稿、模型往返紀錄與備份。只刪 .wav 卻留著逐字稿,等於沒刪。
#!/bin/sh
# /usr/local/bin/call-retention.sh
set -eu
DAYS=90
find /var/spool/asterisk/monitor -type f -name '*.wav' -mtime +"$DAYS" -delete
find /srv/answering/transcripts -type f -mtime +"$DAYS" -delete
logger -t call-retention "retention sweep done, days=$DAYS"# /etc/systemd/system/call-retention.timer
[Unit]
Description=Daily call recording retention sweep
[Timer]
OnCalendar=daily
Persistent=true
[Install]
WantedBy=timers.targetsudo systemctl enable --now call-retention.timer
systemctl list-timers call-retention.timerlist-timers 要列出這個 timer 並顯示下一次執行時間。沒有列出來表示 enable 沒生效,而一個沒在跑的清理排程比沒有排程更糟,因為你以為它在跑。logger 那一行會把每次清理寫進系統日誌,稽核的時候你需要證明刪除確實發生過。
誰能碰到。 分成兩層權限:能播放原始錄音的人,和只能看去識別化逐字稿的人。第二層應該涵蓋大部分同事。登入用集中身分驗證,自架 SSO 管理誰能登入哪個後台比在每個服務裡各開一組帳號安全得多,離職的時候也只要關一個地方。
還有兩件事要一起處理。第一,高風險欄位要在寫入儲存前遮罩,身分證字號、金融帳號與病歷這些東西一旦進了逐字稿和模型紀錄,就會跟著備份擴散。第二,用海外的模型 API 就是把通話內容送出境,這時要看對方的資料處理合約,確認能不能關掉「用你的資料改善服務」那個選項。這一點也是最常把小公司推向在地模型的真正原因,跟延遲無關。
雲端主機的磁碟加密要誠實看待:它主要防的是備份與快照外流,不是防主機商。真正敏感到不能讓任何第三方接觸的錄音,不應該存在租來的機器上。
以上是工程上該做到的事,不是法律意見。保存天數、告知文字與同意流程,請你的法務或律師確認過再上線。
上線順序
- 文字通道加模型加真人接手。目標是兩週內讓真客人用到,並且每一通都有出口。
- 逐字稿、量測與保存期限機制。這一步不會讓客人感覺到差別,但少了它你後面每一個決定都是猜的。
- 電話通道與語音辨識。先用真實錄音驗收字錯率,再接上線。
- 語音合成。最後做,固定句子一律用真人錄音。
這個順序的理由很單純:前兩步只花你的時間,後兩步才花錢。把花錢的部分留到你已經知道客人真正問什麼之後。
FAQ
繁體中文的語音辨識,現在做得到能上線的程度嗎?
可以,但要限定範圍。一般對話的辨識足以讓模型判斷客人想做什麼,問題出在人名、地址和訂單號這些沒有上下文的字串。加上 OpenCC 的 s2twp.json 轉換與繁體的 initial_prompt 可以解決字形混雜,卻解決不了聽錯數字。所以流程上一定要複述確認,並在信心值低的時候轉真人。粵語的支援比國語差,香港的讀者要先用自己的錄音測過再決定。
我一定要買 GPU 或整機才能做嗎?
不一定。SIP 訊號、編排、逐字稿、排隊,加上呼叫外部模型 API,這些一台普通 VPS 都做得很好。會逼你買顯示卡的是三種情況以外的另一種安排:多線同時做即時語音辨識、在本機跑模型推論,或者合約要求資料不得離開自有硬體。可行的中間路線是只把語音辨識放到 GPU 主機,其餘留在便宜的 VPS 上。
通話錄音可以保存多久?
法規給的是原則而不是一個天數:目的達成或期限屆至就要停止處理並刪除。實務上的做法是由你的業務需求推出天數(例如訂單爭議處理所需的期間),寫進文件,然後用排程強制執行。重點是刪除範圍必須包含音訊、逐字稿、模型往返紀錄與備份。確切天數請法務確認,因為它會受你所處行業的其他規定影響。
機器把訂單號聽錯了怎麼辦?
把它當成必然會發生的事來設計,而不是當成 bug 來修。機器要把聽到的號碼逐位複述給客人確認,確認不過就再問一次,第二次還不過就轉真人。同時在系統側做檢核:訂單號有格式與檢查碼,查不到就是聽錯了,這時不要讓模型自己編一個合理的答案。
LINE 官方帳號要怎麼接進我自己的伺服器?
走 Messaging API 的 webhook。你的主機要有一個公開的 https 端點,收到請求後先用 channel secret 驗證 x-line-signature 標頭裡的 HMAC-SHA256 簽章,確認來源,再處理訊息並回覆。簽章驗證不能省,少了它任何人都能對你的端點灌假訊息,而你的模型會照著回答並計費。憑證與網域是固定成本裡最便宜的一項,這條路也沒有每分鐘通話費。