黑客松提交完隔天,我才有空回頭看整套系統長什麼樣。

整理出來一個有點意外的事。

我們在這 7 天裡,花在「想 architecture」的時間,比寫 code 的時間多一倍

1
2
3
4
Jun 9-11   PRE-EVENT   ← 4 天,純設計
Jun 12     KICKOFF
Jun 13-15  BUILD       ← 3 天,寫 code
Jun 16-18  POLISH      ← 3 天,demo + 提交

Day 9-12 整整 4 天我都在做這幾件事:

  • 跟我媽聊她記帳社接到的催款案例
  • 跟我阿姨聊她 CPA 客戶最痛的 receivables 卡關
  • 做律師費用研究 — 為什麼 $3K-$40K 這個 outstanding 區間沒人服務
  • 列 D-001 到 D-022 的設計決策
  • 畫 drawio v1、v2、v3 一直迭代

到 Day 13 開始寫 code 的時候,整個系統的脊椎已經立好了

寫 code 反而是最不糾結的部分 — 因為前面 4 天我已經把「不該做什麼」想清楚。

這篇就是寫整段設計演進。為什麼選了這些設計、中間遇到什麼問題、又怎麼改、又加了什麼東西。


開頭那個問題 — 「能不能做小企業老闆會推薦給朋友的 AI 催收系統」

我做之前先問了一個問題。

「能不能做一個 AI 催收系統,小企業老闆會主動推薦給朋友的那種?」

不是「能不能做 multi-agent demo」、不是「能不能把 9 個 sponsor 接好」、不是「能不能在 7 天內做出可以提交的東西」。

是 — 能不能做一個小企業老闆會主動推薦給朋友的東西

這個問題有點挑釁。因為 AI 催收這個產業在中小企業老闆心目中通常都是 reputation poison。沒人會推薦「我用了一個 AI 機器人去煩我的客戶」這種事。

但我覺得有可能 — 如果這個 AI 在某些關鍵地方真的尊重邊界、真的不踩雷、真的幫到老闆解決他自己解不掉的痛。

這個問題的設計影響有兩層:

第一層:整套系統的設計重心從「能做什麼」變成「不該做什麼」。

什麼案件不該收(D-031 輕度模式 < $3K 直接放手不追)、什麼話不該講(D-019 LLM 不准寫銀行帳號)、什麼情況不該繼續(D-035 在 988 心理危機訊號前停下來)、什麼時段不該撥電話(美國聯邦假日 + TCPA 法規撥打時段)。

每一條都是「明確說不」。

第二層:整套系統的成功指標不是「成功收到錢的數量」,是「客戶關係維持完整 + 老闆敢推薦給朋友」。

這兩個指標有時候會打架。

收到錢但客戶覺得被機器人 bully 過 — 失敗。 沒收到錢但客戶說「他們很專業跟我聊了一下」 — 成功。

知道哪一邊重要,整個 prompt 就完全寫得不一樣。


為什麼挑「未付餘額」而不是「合約總額」(D-038)

我阿姨是財務,她跟我說了一個讓我整個重新設計的事。

她說 — 大部分跨境催款的爭議,金額其實沒有那麼大

很多客戶會說「我已經付了 50% 訂金啊」、「剩下的我等貨到 3 個月後再給你」、「中間我們有改過合約變更附約你要不要再確認一下」。

從合約總額看 — 是一張 $47K 的發票。 從實際未付看 — 可能是 $23K。

美國律師打開卷宗看 $47K,會說「太小不接,跨境訴訟成本超過 $30K,你算盤打不過來」

但實際我們追的是 $23K — 完全落在我們的甜蜜點 ($3K-$40K)。

那一刻我意識到 — 整個產業都在用錯誤的數字定義甜蜜點

我把這件事寫成 D-038 — 我們追未付餘額,不追合約總額。

這個關鍵決策串穿 5 個 agent:

1
2
3
4
5
Pre-flight     → 用「未付餘額」決定分流(輕度 / 完整 / 交律師三條路)
Reconciler     → 用「未付餘額」做結算判斷(少付 / 剛好 / 多付 / 配不到)
Diplomat       → 寫催款信時講的金額是「未付餘額」,不是「合約總額」
Escalator      → 律師信草稿主張的金額是「未付餘額」
AAA Specialist → 正式律師函引用的金額是「未付餘額」

每個分流邊界都有自動化檢查釘住,避免有人不小心把「合約總額」漏進去。

這是「合約總額 → 未付餘額」的一字之差,但這就是這套系統能在中型市場活下來的關鍵

這是專門讓財務人員省心省力追尾款的工具!


為什麼 9 個 agent 分三層,而不是寫一個「萬能 agent」

很多 multi-agent 系統的做法是 — 寫一個超長 prompt 塞給一個「萬能 agent」,然後祈禱它不出錯。

我們選了相反的方向。這也是我從接觸AI以來始終沒有變的想法,專才做單一工作的AI出錯率更低。

執行者(Doers)可以平凡。守護者(Guardians)必須鐵壁。

為什麼?

催款場景一個錯誤動作 — 一句違反 FDCPA 的話、AI 幻覺出來的銀行帳號、沒經同意的升級 — 就永久毀掉客戶信任。

信任是這個產業的資產。守護者是來守它的。而除了AI守護者來把關之外,所有對外的操作都要經過人類同意。

這也是我貫徹的理念,AI是幫助我們的工具,決策權還是應該抓在人類手上。

整個系統分三層:

Layer 1 — Gatekeepers (守門員)

只有一個 agent:Pre-flight

它做的事是看合約、判斷這個案件該走 Lite / In-Spot / Attorney-Recommended 三條路的哪一條。

它的判斷依據是 D-038 未付餘額金額 + 合約條款(適用法律、仲裁條款、滯納金、訂金 %)。

判斷錯整條流程走錯。所以 Pre-flight 是看門員,必須先把這個做對。

Layer 2 — Doers (執行者)

5 個 agent:Investigator、Diplomat、Voice、Payment、Escalator。

它們的工作很「平凡」— 寫信、查資料、撥電話、走流程。

每一個 agent 都是專注做一件事 + 做完之後等守護者審。執行者自己不對外發任何 email、信件、電話。它們生草稿、傳給 Concierge、等批准。

Layer 3 — Guardians (守護者)

3 個 agent:Concierge、Tone Coach、AAA Specialist。

Concierge 是「對外唯一出口」— 所有對外動作都從這裡出,操作員在 Slack 按 APPROVE / REJECT / REVISE。AI 自己不能對外發任何東西。

Tone Coach 是「跨 agent 語氣守門員」— 它即時掃描 Diplomat、Voice 的草稿,擋下任何違反 FDCPA 的句子(用 Claude 做語氣判斷)。

AAA Specialist 是 Day-65 動態加入 — 一般不在 Room 裡,等案件逾期超過 60 天 Escalator 才透過 Band Platform 的 tools.lookup_peers + tools.add_participant 把它拉進來起草律師信。會做這個腳色的原因,也是因為想到未來在擴展時,可以在合約解析後發現合約依照哪一州法律進行的話,就可以把該州法律專門Agent拉入Room裡協助專案,包含除了美國之外的第三國。

這個三層的設計哲學:執行者出錯由守護者攔下;守護者出錯,整個系統停

寫成這樣有點緊張過頭,但催款場景就是這麼脆弱。一個錯字就毀了 — 不能讓任何單一 agent 有獨自對外的權限。


從丟合約到收到錢 — 一個案件走完全程長什麼樣

寫完三層架構,我自己回頭看也覺得有點抽象。讓我用一個真實案件把整套跑一遍,你就知道 9 個 agent 怎麼接力的。

Step 1 — 丟合約進來 操作員把合約 PDF 丟進系統。Pre-flight 接住,用 Gemini 2.5 Flash-Lite 解析 — 適用法律(德州/加州/紐約)、滯納金條款、仲裁條款、訂金 %、合約有沒有變更附約。把這些寫進案件狀態。

Step 2 — 丟Invoice進來 操作員附上Invoice PDF。系統自動配對到剛才那份合約,把未付餘額算出來(發票金額 − 已收訂金),確定到期日。案件狀態更新。

Step 3 — 建立行事曆提醒 系統根據到期日排好 Day −7 預通知、Day 7 友善提醒、Day 30 較嚴正提醒、Day 55 撥電話、Day 60+ Escalator、Day 65 AAA 動態加入。每個節點都是排程觸發,不需要操作員手動排。

Step 4 — Investigator 跑客戶背景 Investigator(跑 Featherless 的 Qwen)拉這個客戶過去半年的紀錄 — 他有沒有準時付過?有沒有爭議過?他自己的回信有什麼模式?標上「行為標籤」:準時付款型 / 拖款型 / 常爭議型 / 30 天後沉默型之類。

Step 5 — Pre-flight 決定整個案件走哪條路 這一步 Pre-flight 在做的是「整體案件路徑」的分流,不是信件口氣的強度(口氣是 Tone Coach 跟著時間階段在管,後面 Step 7 會講)。

Pre-flight 根據未付餘額 + 客戶行為標籤 + 合約適用法律綜合判斷,把整個案件分流到三條路徑:

  • 輕度模式 (Lite)(< $3K 且客戶配合):整個案件走輕度路徑,1-2 封提醒就放手,連 Voice 撥電話 / 律師信 / USDC 結算這些階段都不會啟動
  • 完整模式 (In-Spot)($3K-$40K 未付餘額):走完整流程,從 Day −7 預通知一路到 Day 65 律師信全部會跑
  • 交律師模式 (Attorney-Recommended)(> $40K 或客戶敵意累積):整個案件直接交給律師,系統不主動再寄信、撥電話

換句話說 Pre-flight 是在問「我要不要陪這個案件走完整套?」,Tone Coach 是後面才在問「這封信寫得對不對?」。兩個 agent 管的是完全不同的層面。

Step 6 — Day −7 預通知 還沒到期就先寄一封友善的提前提醒:「Just wanted to flag this invoice is due in 7 days. Let me know if there’s anything blocking it.」Diplomat 起草、Tone Coach 過、Concierge 推 Slack 等操作員按 APPROVE 後寄出。

Step 7 — Day 7 友善提醒 / Day 30 較嚴正提醒(這裡才是 Tone 強度的分流) 到期沒收到錢,Day 7 寄友善提醒,Day 30 寄較嚴正提醒。這才是「催款態度」的分流 — 它跟著時間階段在升級,不是 Pre-flight 在管。Tone Coach 用 Claude Haiku 審每一封 — 像「kindly remind」這種太軟的字眼會被擋下要求改寫;像「we will sue you」這種太硬的會擋下違反 FDCPA。每一封都帶付款連結 (paylink)。

Step 8 — Day 55 Sarah 撥電話 到 Day 55 還沒回應,Voice Agent 透過 ElevenLabs ConvAI + Twilio 撥電話。先看當地時間是不是在 TCPA 法規允許的撥打時段(週二三四的 10-11 點或 14-15 點)、是不是美國聯邦假日 — 不在範圍就安排時間再撥。(你再也不用配合美國時間打電話催帳了!)

Sarah 在電話裡的可能分流:

  • 客戶答應付款 → 記下具體日期(像「Saturday June 27th」)、排次循環追蹤
  • 客戶說需問老闆 2 天內回信 → Phase 3b「合作分流」,記下具體日期、Concierge 標記「客戶承諾後續回覆」
  • 客戶吼罵 / 提到律師 / 破產 / 心理危機訊號 → 立刻升級,Concierge 把人類拉進來
  • 客戶要求不要再打電話 → 立刻掛斷 + 案件凍結語音路徑

Step 9 — Day 60+ Escalator + Day 65 AAA 動態加入 還是沒回應,Escalator 起律師信草稿(跑 Featherless 的 Llama 70B)。Day 65 透過 Band Platform 的 tools.lookup_peers + tools.add_participant 把 AAA Specialist 拉進 Room — 這時候律師 agent 才第一次出現在對話裡。AAA 用 Claude Sonnet 把律師信措辭再潤色一次。

Step 10 — 付款連結 + USDC 結算 所有對外寄出的信都帶付款連結 (paylink)。D-019 鐵則的關鍵就在這 — LLM 從來不寫銀行帳號。付款連結是寫死的網址,客戶點進去是 Next.js 做的付款頁,從 payment_methods.json 直接讀真實帳號 / SWIFT / Stripe / USDC 錢包。LLM 完全不碰銀行資訊。

這裡我又加入USDC付款的原因是,未來靠AI處理金融的事情,我覺得已經看得到這是必然的趨勢…既然這個系統是AI,那我覺得配置USDC的收付款是很必要的,未來可以演變成每個擁有X402或其他身分驗證的AI可以自行處理相互付款的作業。

客戶選 USDC 付款 → 從自己錢包轉到 Recoverflow 的 Circle ARC 錢包 → 收款偵測器每 10 秒掃一次,看到新交易觸發Payment agent對帳。

Step 11 — 4 種結算狀態自動判斷 比對未付餘額:

  • 剛好 (FULL):金額剛好等於未付餘額 → 關案、Diplomat 寄謝信、催款流程停
  • 少付 (PARTIAL):不到未付餘額 → 記下,次循環追蹤重新追剩餘金額
  • 多付 (OVERPAID):超過未付餘額 → 多收的標記退款、Concierge 通知人類
  • 配不到 (UNMATCHED):這筆錢配不到任何案件 → 進待認領佇列、由操作員手動處理

Step 12 — 通知 + 稽核 不管哪個狀態,都會:寫進稽核紀錄(audit_trail.jsonl,append-only,21,000+ 行)、Resend 寄到帳通知給人類(中英雙語)、如果是「剛好 FULL」的話客戶也收到一封 Thank you 確認信。


整套跑下來,人類在 Slack 只按過幾次 APPROVE / REJECT,但 9 個 agent 從合約解析到 USDC 入帳全部處理完。

每一步都留下稽核紀錄、每個對外動作都有人類審核、每個邊界情境都被鐵則接住。

這就是「執行者弱、守護者強」的具體樣子。


Voice Agent 的演化故事(完整故事看 Day 2)

設計完三層架構之後,最折磨的反而是 Voice Agent。它在 7 天裡演化了三次 — V1 單向通知 → V2 雙向對話 → V3 加 Phase 3b 分支,每一版都 broken 在不同的地方。

V2 我自己撥了一通電話給自己,把「2 天內回信」回給 Sarah,她直接把這個當成「拖延」升級 — 那一刻我才知道 prompt 寫的「理想對話」跟真實人類對話差多遠。

完整的踩雷故事跟 Phase 3b 的誕生我寫在另一篇 《AI 撥了一通電話給我 — Recoverflow 開發日記 Day 2:Voice Agent 的那兩個小時》 裡了,有興趣可以去看那篇。

這篇我想多寫的是 — Voice Agent 真正讓我意識到的是「設計理想場景永遠贏不過真實場景」這件事。它直接帶我去想下一段。


4 個沒人講過的隱藏情境

Voice V3 加完之後,我跟 J 說 — 會不會還有別的邊界情境也是被當成「拖延」升級的?

我們把整個 voice agent 的可能對話場景重新檢視一遍,列了 26 個邊界情境。

其中 4 個比較重的隱藏情境,我覺得是這個系統「會不會毀掉客戶關係」的關鍵:

Q1 — 客戶付一半 (D-028)

買家付一半,承諾「下個月給剩下的」。

很多催款系統不知道怎麼處理這個 — 是當「完成」還是「未完成」?

我們的處理:次循環追蹤。Diplomat 對剩餘金額重新發起催款,節奏重新計時。最多跑 2 個次循環才升級。

這個設計的靈感來自我阿姨的經驗。她說「一半付清的客戶通常是有意願但現金流卡住,給他空間反而會收到剩下的」。

Q2 — 客戶對 AI 吼

買家發現自己在跟語音 agent 對話,開始情緒激動 / 罵髒話。

我們的處理:Tone Coach 即時擋下任何違反 FDCPA 的回應。ConvAI 16 種升級原因列舉把這個案件標「客戶持續敵意」。Concierge 在幾分鐘內把人類叫進來。

Sarah (AI) 永遠不會用情緒回應客戶

Q3 — 心理危機訊號 (988)

買家在電話裡提到自我傷害、憂鬱、「我真的不行了」。

我們的處理:set_anomaly_halt(case_id, “welfare”) 在通知 Concierge 之前先呼叫。案件凍結。988 美國自殺防治專線在對話裡被提及。3 個專屬單元測試釘住這個順序。

生命優先於債務。寫在 code 裡,不是寫在 prompt 裡

Q4 — 客戶要破產

買家提到 Chapter 11(美國破產保護)。

我們的處理:Sarah 溫和確認、用「客戶提到破產」原因升級。觸發法律 claim filing deadline awareness。Concierge 把人類顧問拉進來。


這 4 個情境都不是我寫 prompt 時想到的。

它們是 — 我想像自己是接到這通電話的真人時,可能會說什麼。(這也是我的強項-設身處地+預演各種發生)

媽媽剛走、生意倒了、客戶跑路、現金流斷掉 — 這些瞬間人類會說什麼,有點怎麼回應是 ok 的、什麼回應會毀了人。

如果這個 AI 在這 4 個瞬間踩雷,我媽就不會推薦給朋友。


回頭看 — 我從 7 天學到什麼

寫到這邊我整理了一下 7 天學到的事。

第一:「不該做什麼」比「該做什麼」難想很多。Day 9-12 我們花 4 天列「禁止 / 例外 / 紅線」清單。Day 13-15 寫 code 才 3 天 — 因為前面想清楚之後串接反而很快。如果你發現自己花太多時間在「該做什麼」上,可能是前面那層還沒夠清楚。

第二:執行者弱、守護者強 是這套設計的脊椎。多 agent 系統最常見的失敗模式是「萬能 agent」把所有判斷塞進一個 prompt 然後祈禱不出錯。我們選相反 — 執行者平凡、守護者鐵壁。一旦這個分層成立,你會發現你不再為執行者的 prompt 抓狂,因為守護者會接住。

第三:鐵則必須是「不可違反的硬規定」不是「最佳實作建議」。988 心理危機凍結、D-019 LLM 不准寫銀行帳號、Tone Coach FDCPA 擋字 — 這些都不是建議,是寫死的。「最佳實作」會被「今天時間趕一下就跳過好了」弄丟,鐵則不會。

第四:真實場景永遠贏理想場景。Voice V2 broken 是我自己撥了電話才發現的,4 個隱藏情境是我想像自己接到這通電話的真人才推敲出來的。沒有模擬對話 API、沒有 mock 測試、沒有 dry-run 能取代真的設身處地走一次。

第五:設計時間花得不冤枉。我以為 7 天黑客松「應該」是 6 天寫 code + 1 天提交。實際是 4 天設計 + 3 天寫 code + 3 天 polish。回頭看這個比例對 — 4 天設計的時候我已經知道接下來 3 天每一行 code 該長什麼樣。


結尾

提交黑客松那刻整個系統 9 個 agent、21,000+ 行稽核紀錄、482 個測試全綠、5 個 Circle USDC 真實 ARC-TESTNET 結算,7 家贊助商全部真的在跑。

但回頭看 — 真正讓我自己 proud 的不是這些數字,是這套系統在那 4 個隱藏情境裡會怎麼反應

客戶情緒崩潰、提到 988、提到要破產、付一半承諾下個月給剩下的 — 我希望我媽會推薦這個系統給她那些一樣被卡住的同行朋友。

如果有一天她真的這樣做,那這 7 天就值得了。


剩下還沒寫進系統的東西也很多 — 系統的定價模式還是空的、架構還有沒有完成的部分、還有需要修正的地方…

但鐵則立好了。剩下的可以慢慢來。

設計時間花得不冤枉

參考來源