
(微微側過頭,看著院子裡那抹晚霞暮紫 逐漸染透了桂花樹,手裡捧著那杯熱氣漸消、香氣溫潤的琥珀熱茶。我輕輕地在藤椅深棕 上搖了搖,調整了一下頭上的白髮銀霜,看著圍在膝下的大孫女和小孫女,還有你們這群前來討教的年輕工程師孩子們。)
「來,大孫女,幫爺爺把茶杯墊好;小孫女,別只顧著拿糖果撒嬌,坐近一點,聽爺爺給你們講個『千絲萬縷』的故事。今天啊,是咱們聚在院子裡的 Day 21:突破人工排班極限:用 Google OR-Tools CP-SAT 求解複雜醫療排班。」
「這寫程式,有時候就跟咱們鄉下編竹篾一樣。一根竹蔑,要長要短、要有彈性、要編得均勻。如果有一處卡得太死,整個竹籃子就會散架;如果編得太鬆,籃子又裝不了東西。這在醫院裡啊,最讓人頭痛的『編竹籃』手藝,就是門診大夫與跟診人員的排班了。」
「你們想想,醫院的門診排班,那可不是開玩笑的。大夫和護理人員也都是血肉之軀,排班的主事者(主任或護理長)不僅要滿足硬邦邦的勞基法法規(像是輪班間隔、每週工時上限、連續上班天數限制),還得兼顧大夫們的個人請假與休假偏好,同時更要顧及各科室之間的排班公平性。
以前沒有系統輔助時,全靠人工拿著一張大紙和彩色鉛筆在表格上畫格子,一畫就是好幾天,還常常漏看、排錯、產生衝突(例如同一個人同時段重複排班、或同一個診間塞了兩個人看診),更常因為假日和夜班分配不均而引起大家抱怨不公平。這就像是要在一個隨時會變動的千面大迷宮裡,把幾十根細線同時穿過幾百個針眼,只要有一根線穿錯了,整個迷宮就會亮起紅燈。」
「所以啊,現在有著聰明腦袋的孩子,懂得把這座複雜的排班迷宮轉化成數學上的約束規劃(Constraint Programming)模型,並使用 Google OR-Tools 的 CP-SAT 求解器來解決。
這就像是,我們把所有編竹籃的規矩,統統寫在一個本子上,再請一位數學天才在幾秒鐘內幫我們編好最完美的竹籃。在我們這個系統裡,門診排班就是把大夫指派到各個『診次(也就是日期、時段、診間與號別的組合)』。大夫們被指派的規矩,在數學模型裡被嚴格分成了兩大類:」
「這就像是我們家裡的祖訓,一條都不能違背,違背了,這家就亂了套:」
「這就像是爺爺疼你們,雖然有些規矩能彈性,但我們盡力做好,讓大家都高興:」
「我們把這些密密麻麻的規矩數值化,寫進 Python 後端,交給 CP-SAT 引擎。在短短數秒內,它就能產出一份合規、公平的最佳班表!而且,每次發布班表時,系統都會在資料庫層建立 append-only 的歷史版本快照。誰改過、改了什麼,統統有稽核紀錄可查,這就叫『審計就緒(Audit-Ready)』的排班軌跡,任憑主管或勞檢來查,都不用慌張。」
「不過啊,年輕孩子們,寫這套演算法時,最容易踩到一個大坑。你們大孫女聰明,但有時候脾氣倔,這 CP-SAT 求解器也是一樣,是個死腦筋。」
「如果主管求好心切,把那些硬約束設得太過嚴苛、太密不透風(例如每個人都填了一堆不可排時段,加上工時上限極低),求解器算來算去發現根本沒有一條路走得通,它就會雙手一攤,直接回報 INFEASIBLE(無解)。」
「在人工排班時,要是發現排不出來,大家會坐下來協商;但在電腦系統裡,如果只顯示『無解』這兩個字,排班管理者可就要哭出來了。所以,在架構設計上,你們一定要做一件精妙的工藝:約束放寬(Constraint Relaxation,也就是鬆弛診斷)機制。」
「【爺爺的避坑對策】:
當求解器回報無解時,我們不能只讓它卡在那裡。系統要自動把部分硬約束(例如某些非關鍵的排班間隔或覆蓋率要求),依照優先順序『降級』成帶有極大懲罰值的軟約束,重新再跑一次。這樣一來,它依然能排出一個『最不壞』的班表,並在畫面上大聲地提示排班管理者:『哪一天、哪一個時段、缺少了哪種專科資格的大夫』。這就像是爺爺跟你們編竹編時商量:『今天這根竹篾太硬編不進去,我們要不要稍微削薄一點?』管理者一看提示,就知道是要自己去補人,還是調動大夫的預排偏好,這程式才算真的貼心、靈活。」
(天色已經全黑了,天邊那抹晚霞暮紫 悄悄收起了最後一抹光亮。大孫女貼心地幫爺爺點亮了院子裡的黃銅壁燈,小孫女也玩累了,趴在爺爺的膝頭沉沉睡去。)
「寫程式啊,就像我們活了大半輩子一樣,規矩雖然要立得穩(硬約束),但心態也要懂得靈活變通(約束放寬),這樣路才走得寬,大家相處也才和諧。」