多數成本控制的直覺模型是一條斜線:用得越多、花得越多,早一點注意到,早一點省。但訊息類 API 常見的計費模型不是斜線,是階梯——月費方案給一個固定額度,用完之前每則都一樣便宜,跨過那一階之後整個月完全發不出去,而且不能臨時加購。
我們的 LINE 官方帳號正踩在這道階梯上。實測當時的用量速度推算,大約每月中旬就會撞到方案上限。撞到之後停擺的不只是即將閒置的免費會員——**所有人的推播都會停,付費會員也不例外。**這篇文章整理我們怎麼決定該關掉誰的推播、怎麼設計一個不會在上線第一天誤傷任何人的狀態機,以及一次差點被誤判成「設計有問題」的真實資料事故。
先把「哪些訊息真的計費」量出來,不要用猜的
動手之前,我們對照 LINE 的用量回報與資料庫,把每個訊息來源逐一核對是否真的計費:
| 來源 | 計費? |
|---|---|
| 排程推播(每日簡報) | ✅ |
| 新手引導卡 | ✅ |
| 對話回覆 | ❌ |
| 後台會員群發 | ❌(走站內通知管道,根本沒碰 LINE) |
第三、四列是核對結果,不是推測。某兩天的排程推播與對話量分別核算後,LINE 回報的實際用量與「只有排程推播計費」的假設完全吻合;如果回覆也計費,數字應該明顯更高。
這條核對救了一次誤判。後台的會員群發紀錄表看起來筆數比排程推播還多,第一眼像是隱藏的大宗成本,但那個管道走的是站內通知、完全沒有用到 LINE 額度。把它算進成本盤點,會得到一個方向完全錯誤的結論——這正是「量到的訊息來源」比「資料庫裡列數最多的表」更值得信任的地方。
門檻不是拍腦袋,是從省量曲線的轉折點挑出來的
決定「幾天沒出現算閒置」時,我們對近期實際送出的推播量,回推不同門檻各能省下多少:
| 門檻 | 佔實際送出量的比例 |
|---|---|
| 14 天 | 64.7% |
| 21 天 | 55.3% |
| 30 天 | 46.4% |
| 45 天 | 13.4% |
| 60 天 | 1.2% |
曲線在 30 天之後崩掉——從 46.4% 掉到 13.4%。30 天正好卡在轉折點上:往前收更兇,只多換到個位數到十幾個百分點;往後放寬到 45 天,幾乎沒有東西可省。門檻選在轉折點,是因為那裡是「多犧牲一點準確度換一點空間」與「多留一點空間換一點準確度」兩條路開始分道揚鑣的地方,再往任一邊移動,投入產出比都會快速惡化。
「全部凍結」的上限,不是機制真正省下的量
上面那張表有個陷阱:它算的是「把所有超過門檻的人一次凍結」能省多少,但我們的機制不會這樣做,實際省下的量要打兩次折。
第一次折扣:閒置用戶只佔每日送出量的一小部分,而且這部分很穩定——用量的成長全部來自新註冊的活躍使用者,閒置族群的絕對量幾乎不變。
第二次折扣:降頻不是凍結。我們選擇的是「先降頻、再凍結」,而大多數超過門檻的人只會從每天發送降到每週三天,不會直接歸零。實際拿正式站資料模擬整套狀態機推進到穩態後:
| 每月則數 | |
|---|---|
| 目前 | 較高的基準值 |
| 完整推進到穩態後 | 較低的穩態值 |
| 實際省下 | 約一成 |
只有極少數使用者會真的走到凍結,多數停在降頻。這套機制擋不住額度上限——穩態下省的量仍然遠不足以應付月費方案的上限。它真正做的是降低成長斜率、換來「不要粗暴地把人切掉」的體驗,真正防止斷線的是另一道額度告警機制與升級方案的決定。把一個緩解措施誤讀成解決方案,會讓人誤以為額度問題已經處理完,而錯過真正該做決定的時間點。
為什麼先降頻再凍結,而不是直接關掉
因為「沒有對話紀錄」是很差的活躍代理指標。
這個產品的核心價值是每天一則自動送達的簡報。一個設好時間、每天讀、卻從不主動聊天的人,正是最貼合產品定位的使用者——他沒有任何理由發起對話或登入後台。用「沒有對話」直接判定他閒置並關掉推播,等於精準地砍掉最重度的使用者。
資料印證了這個顧慮:在啟用中的推播設定裡,設定每天都發的族群中,只有一小部分屬於長期未接觸;反而設定每週只發幾天的族群裡,不活躍比例明顯更高。發送頻率設得越高的人,通常越活躍,不是越該被關掉。
所以中間插一個降頻階段,讓「還收得到訊號」的人有機會在完全斷線之前回來,而不是用一個粗糙的代理指標直接判死刑。
狀態機必須考慮「上線那一刻」,不只是穩態
正常 ──(23 天)──▶ 已預告 ──(7 天)──▶ 已降頻 ──(30 天)──▶ 已凍結
照常發送 改寫發送日、照常發送 跳過不發
任何活躍訊號都會讓狀態機整組還原回正常。
這個狀態機有兩條規則,單獨看像是多餘的工程潔癖:每次只前進一階,而且必須在目前階段待滿到下一階的門檻差距才能繼續前進。
它們存在的理由只跟一個時刻有關:**功能剛上線的那一刻。**狀態機的計算是「距離最後活躍幾天」直接對照門檻,如果沒有這兩條規則,一個已經閒置很久的人在上線當下會被直接算成該凍結——他會在完全沒收到任何預告的情況下,推播突然停止。實測時這種人佔了啟用推播族群的四分之一。整套「先預告、再降頻、最後凍結」給使用者反應時間的設計,會在自己上線的第一天就被繞過。
補上這兩條規則之後:
| 上線第一天會發生的事 | |
|---|---|
| 收到預告(推播照常發,只多一行字) | 一小部分 |
| 其中已達降頻門檻 → 延後到第 8 天才降頻 | 多數 |
| 其中已達凍結門檻 → 延後到第 38 天才凍結 | 極少數 |
| 完全不受影響 | 多數 |
上線第一天,沒有任何人的發送日被改動。
這兩條規則在穩態下是零成本的——照時間正常推進的使用者,第 23 天被標記已預告,到第 30 天剛好待滿 7 天的緩衝期,規則形同不存在。代價只發生在「已經欠了很久的債」被系統第一次看見的那一刻,而那正是唯一需要保護的時刻。這是一個值得記住的一般化原則:任何從某個時間點開始累計狀態的機制,在上線當下都會把「已經存在很久的既有狀態」誤判成「剛剛發生的事」,需要專門補一條規則消化這個落差,而不是假設所有人都是從零開始計算的。
幾個容易犯錯、但代價很低就能避開的設計
| 決策 | 如果不這樣做,會發生什麼 |
|---|---|
| 凍結狀態不能借用使用者自己的開關欄位表達 | 系統覆寫之後,再也分不出「使用者自己關的」與「系統關的」——這兩件事對產品的意義完全相反,使用者會在後台看到推播被關、自己打開、系統下次掃描又關掉,卻永遠不知道為什麼 |
| 降頻時取「原設定」與「降頻後設定」的交集,不是直接覆寫 | 原本只設週末發送的人,會被強制改成週一三五——那不是降頻,是把使用者的設定改掉,而且他原本要收的那天反而收不到了 |
| 預告文字附掛在既有推播上,不另外多發一則 | 一則「你的推播要被降頻了」的通知,會直接抵銷這整套機制想省下的額度,而且收到的人正好是最不可能看的那群人 |
| 門檻天數只在一個地方定義,兩個服務都讀同一份設定 | 兩邊各自寫一份的話,遲早會有人只改一邊,使用者收到的預告文字與系統實際行為對不上 |
這四條沒有一條需要複雜的技術,共通點是先想清楚「這個設計在邊界情況下會不會製造一個使用者解釋不了的狀態」,而不是先想「怎麼實作最簡單」。
一次真實的資料回填事故:預測 50 筆,實際 65 筆
上線後,實際被標記為已預告的筆數比事前模擬的預估值多出三成。差額不是模擬失準,是一個真實的資料品質問題:回填既有使用者最後活躍時間的批次作業,用分頁方式邊改邊翻頁,導致其中一段連號的使用者被跳過,系統只好對他們套用備援邏輯(改用註冊時間),結果讓一批帳號老但實際還活躍的使用者被誤判成閒置。
交叉比對兩群人的結果,把這個推論釘死:**有被正確回填的那群人裡,只有一小部分被標記為已預告;被跳過、套用備援邏輯的那群人裡,卻有絕大多數被標記。**兩者的落差不是誤差範圍內的雜訊,是同一個 bug 的兩種症狀。
這個案例值得記住的不是那個分頁 bug 本身,而是診斷順序:**先問「資料本身可信嗎」,再問「邏輯設計錯了嗎」。**一個上線後偏離預期的數字,直覺常常是回頭檢查規則或門檻,但很多時候問題出在資料的產生過程,而不是消費資料的邏輯。找到兩個對照群體、比較它們的差異,往往比重新推導一遍規則更快找到真正的根因。
驗證這類指令,不要用時間旅行
這支狀態機推進指令會處理整張表,不是只處理測試帳號。用「把系統時鐘往前撥」的方式在共用環境驗證,會把撥動的時間戳真實寫進資料庫——受影響的不是虛構的測試資料,是所有真實使用者當下的狀態。事後就算把時鐘撥回來,那些被寫入的時間戳也不會自動復原,而且往後推進邏輯的判斷還是照著那個被污染的時間戳走。
正確的做法是反過來:**不要調時鐘,調門檻本身。**把門檻天數暫時設成極小值,讓測試帳號自然而然地落在目標階段。驗證完用還原指令收尾,確認所有測試帳號都乾淨地回到初始狀態。任何會寫入真實時間戳的狀態機,時間旅行式測試在共用環境裡都不安全——這條原則不只適用於這一支指令。
可以帶走的原則
- 訊息類計費常常是階梯而不是斜線。設計成本控制前,先確認撞到上限的後果是「變貴」還是「整個月斷線」,兩者需要完全不同的緊迫程度。
- 「哪些訊息真的計費」要逐一核對實測結果,不要用資料庫裡哪張表筆數多來推論——筆數多不代表花錢。
- 門檻要從實際的省量曲線裡找轉折點,而不是選一個聽起來合理的整數。
- 「全部處置的上限」與「機制實際會省下的量」是兩回事,中間至少要打兩次折:多少比例真的會被觸發、觸發之後的處置有多徹底。
- 選擇活躍度的代理指標時,要用資料驗證這個指標有沒有系統性地誤傷你最想留住的那群人。
- 任何從某個時間點開始累計狀態的機制,上線當下都會把舊債誤判成新狀況;穩態下零成本的保護規則,代價只集中在上線那一刻。
- 系統狀態不要覆寫使用者自己的意願欄位;修改使用者設定時用交集而不是覆寫;新增通知盡量搭便車而不是另開一個成本來源。
- 上線後的數字偏離預期時,先驗證資料本身,不要急著檢討規則設計。
- 驗證會寫入時間戳的排程邏輯,改調設定值,不要調系統時鐘。