乾貨 | 10分鐘給上萬客服排好班,攜程大規模客服排班算法實踐

{"type":"doc","content":[{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"一、背景"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"客戶服務部門是攜程以服務質量贏得客戶信賴的基石,其擁有上萬名一線的客服,每天進線量巨大;且伴隨着業務量的起伏,每一週甚至每一天的不同時段都有需求量上的巨大變化。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如何在各個時段滿足客戶服務指標,同時儘量提高客服的工作體驗,提升整體工作效率?這裏自然而然就產生了對智能排班的需求。排班問題的核心是用更少的客服資源,既保證用戶的服務質量,又儘可能保障客服班次體驗。在這樣的背景下,今天我們要探討的排班算法就成了優化服務質量與成本的一個重要課題。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"二、應用效果"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"攜程的客服團隊歷史悠久,在很長一段時期裏,排班使用人工調整的方式,已經形成了一整套完整的更新流程。但是各個部門的邏輯又有很大的區別,比如歐洲的客服需要覈對時區的變化;有些部門以人爲單位排班,而有些部門的管理架構要加一層小組的概念來排班。這些不同的邏輯和概念,是爲了更好的管理和協調整個服務部門的資源,在攜程幾十年的歷史中發揮了重要的作用。但也爲算法的落地帶來了大量不一的約束。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"現在智能排班已經爲攜程的多個部門提供班表生成服務,在十分鐘內提供優質的班表,並且符合各部門各個工種對不同工作場景的約束需求。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/d7\/d712dd776445ac374e69ecadf8c270b1.jpeg","alt":"圖片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":"center","origin":null},"content":[{"type":"text","text":"某段指定時期的驗證數據"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"三、問題分析"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"排班問題,實際上就是一個帶大量軟硬約束的超大規模最優化問題。這是一個整數規劃問題,這類問題一般都是NP難的。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"解決這類問題,傳統的方法有:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"1)精確算法,主要有割平面法,分支定界法。這類算法解決的問題有一些特點:一般針對的問題規模都較小;優勢是求解出來的必定是最優解。不過我們遇到的問題規模極其龐大,此方法的效率太低,無法滿足業務需求。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"2)近似算法,根據問題使用一些技巧自己設計出來。需要給出算法的近似比,複雜度分析,具有很強的推理能力。這類算法放棄獲得最優解,提升了一些性能,不過同1一樣,這類算法所能求解的問題規模依然比較受限制。在我們這個場景下,問題規模依然過於龐大,無法滿足業務需求。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"3)啓發式算法,和前兩種算法相比,啓發式算法沒有足夠嚴格的理論分析,是算法設計者們根據經驗或者觀察性質設計出來的。沒有嚴格的理論分析,通過啓發式算法獲得解,我們無法知道其是否是最優解,甚至無法精確得到其離最優解還有多遠的距離,但是其性能上的優勢十分明顯,即使我們這種大規模的問題,也可以在數十分鐘內獲得非常令人滿意的結果。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"由於攜程客服數以萬計,再加上數十種基本班次,整體問題規模十分龐大。傳統方法在可接受的時間範圍內無法給出可接受的解。因此我們最終選擇了啓發式算法來解決問題。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"       "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"針對這類啓發式優化問題,問題的建模是個十分重要的步驟,這一步的好壞將直接決定問題最終的解決效果。"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"3.1 Nurse Rostering Problem"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"遇到問題,首先想要找類似的問題。我們找到了一個有一些相似的護士排班問題(Nurse Rostering Problem,後文簡稱NRP),NRP可以很好地幫助我們理解問題。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"護士排班問題是說在給定的時間內爲特定的一組護士安排班次,並使該排班方案滿足各種硬性約束條件,同時儘量滿足各種軟性約束條件。但爲了方便後續理解,這裏以the International Nurse Rostering Competition 2010的規則爲例,簡要介紹一下這個問題,這部分規則約束十分核心。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"NRP問題的核心約束分軟硬兩類:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"硬約束:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"班次全部分配:每個班次都需要分配給一名員工。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"班次不能衝突:員工每天只能輪班一次。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"軟約束:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這些約束實際情況中經常違反,因此這裏決定將這些約束定義爲軟約束。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"工作感受約束:"}]},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"班次分配範圍分配:每位員工需要工作超過a個班次且少於b個班次(取決於合同或約定)。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"連續工作天數:每位員工需要連續工作c至d天(取決於合同或約定)。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"連續休息天數:每位員工需能連續休息e到f天(取決於合同或約定)。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"連續工作週末數:每位員工可以連續工作的週末數在g到h間(取決於合同或約定)。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"儘量保持週末完整:員工如果需要在週末上班,那就週末兩天都值班,放休就要儘量兩天都放休。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"週末上班班次一致:同一個員工在週末兩天都上班的情況下,週末班次儘量保持一致。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"不人性化的排班模式:儘量避免前後班次間隔時間太短,或連續上太辛苦的班次。例如:第一天上晚班,第二天接着上早班;或者連續上3天早晚班。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"員工對班次的一些臨時期望:"}]},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"要求安排班次:某位員工想在指定的一天進行工作,儘量不要放休。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"希望放休:某位員工指定某一天希望能給其放休,不要安排班次。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"希望指定班次:員工希望能分配給其特定的班次。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"希望避免班次:員工不希望被分配到特定的班次。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"技能要求:儘量安排上班的護士已熟練掌握該班次所需的技能。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"看完約束,NRP問題的描述就很明瞭了。即在數值化定義好各個約束的重要性後,在儘量平衡所有約束的情況下,不停調整班表,獲得最好的排班。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如下圖,是一個最爲簡單的調整示例:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/ba\/ba1b048081517e818980a8d631f0f33f.png","alt":"圖片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"而最終的目標是得到一份最終班表,表示所有護士每天的班次安排。要注意在NRP問題中,調整的最小顆粒度是班次,這裏將引出攜程客服排班問題和NRP問題的最大不同。"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"3.2 攜程集團客服排班"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如開篇所述,攜程的業務量每天都有着巨大的變化,加之我們的用戶電話進線等待時間按秒計算,爲了保證服務質量,對業務的控制需要細化到15分鐘級別,才能保證服務質量,給用戶帶來最好的客服體驗。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"       "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"因此我們無法像NRP問題將排班簡化爲一天3個班次,而是細化到每天96個時段。由於整體安排的顆粒度細化到分鐘級,就不能再僅僅安排班次,需要提高一個維度,額外計算員工的會議,休息,加班,放休等對每分鐘業務量和應答量的影響。這導致整個問題複雜程度成指數級上升。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"       "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"而且現實中的核心約束遠比NRP複雜地多,總共近百條各種規則約束,對約束設計也提出了挑戰。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"       "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"約束設計需要數值化,但是數十上百的約束,兩兩之間的比例關係要恰當。這就要求數千的比例關係都要詳細論證並且恰當,才能得到最終合適的班表,如若不然,很容易導致約束失衡,最終導致班表的不可用。比如,如果我們設計不合理,可能在業務量無法滿足的基礎上,安排部分員工超時加班,這將導致這部分員工的工作體驗極差;或者在不需要的情況下,安排員工進行意義很小的加班,導致人員的浪費。"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"貨幣化約束設計     "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"約束的數值化設計是問題的重點,但是問題的複雜性導致整個約束設計幾乎非人力可爲。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"針對這一問題,我們提出了一種貨幣化的思路。所謂貨幣化,就是將單獨的分數設計轉換爲一種標準分值(在這個場景下就類似於貨幣),統一貨幣化後,我們就可以直接將約束進行對比。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"很多約束是天然可以貨幣化的,比如加班成本、津貼等等。餘下無法天然貨幣化的部分,積極溝通,從業務角度給出一個初始的設計,再在算法使用中做微調,即可得到可用的約束設計與最終結果。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"四、建模與設計"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"4.1 基礎結構"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如前所述,排班問題是一個超大規模的優化問題,解決這種問題我們選用啓發式算法。根據以往經驗,用啓發式算法解決現實複雜問題的時候,最核心的是對問題進行建模,模型建立的好壞將直接決定後續系統的整體效果。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"       "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"客服排班實際上就是要安排員工在每個時間段的工作狀態(可能包括工作,休息,開會,加班等等),以及每個時段員工所做的技能工種。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"       "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"因此,我們先抽象出一個最基礎的模型,包含三個維度:員工,工種以及時間,這樣就形成了一個三維度的空間。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" "}]},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/67\/67a1a61dfa5c1d50bb5363f4d194185c.png","alt":"圖片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":"center","origin":null},"content":[{"type":"text","text":"三維空間中的每一塊就是最小的工作狀態安排單元"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"       "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如上圖所示,在這個模型下我們的目標就是填滿整個空間,在儘量滿足約束條件的情況下,給每個最小單元安排上工作狀態(工作,下班,休息等),這樣就獲得了班表。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"       "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這樣的結果邏輯上可行,但實際呢?"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"4.2 結構優化"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們先不考慮喫飯,開會等等複雜的設定條件,簡單設定每個最小單元的工作狀態爲三種:工作,下班,休息。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"       "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"按照基本結構直接進行排班是否可行呢?答案是肯定的。只需要通過算法調整每個最小單元的狀態,在這三種狀態中選擇一個,然後設定合理的約束條件就能開始跑起來了,理論上也可以得到我們想要的結果。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"不過設定好一切你會發現,根本得不到一個優秀的解,甚至一個合法的解都很難得到。這是因爲按照這個模型去啓發式搜索,搜索空間太廣。我們可以簡單算一下,設排班人數爲100人,有2種不同的工種可以安排,安排一週的班次,時間顆粒度爲30分鐘。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"圍棋一共個19×19=361點,每個點由3種狀態(黑,白,空),而真實情況遠比這假設要複雜的多,整個問題的複雜度也是指數上升,無法算出合適的結果。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"       "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"因此需要在基礎結構上做一些優化,加一層結構。首先,變量由每個最小時間單元改爲工作區間,設上班時間都是整點,那一天最多24個班次,加上本休不上班,一共25種可能。休息開會等可以抽象爲上班時間內的整點“中斷”,這樣整體複雜度可以下降爲大約:"}]},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/7f\/7fe7fe7de78b43a8245a17cbd0c88270.jpeg","alt":"圖片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":",這樣總體看起來就是一個可解決的問題了。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"五、算法流程"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在有了模型的前提下,需要做一些算法選擇與流程設計。我們首先做了一些基準測試,然後對整個算法流程做一個統一的規劃與設計。"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"5.1 基準測試"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們獲取了一個簡化的業務場景,保存下來後,以此爲基準搭建了一個基準測試。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"首先測試了常見的算法,包括:FirstFit,Hill Climbing,Tabu Search,Late Acceptance,Great Deluge,Simulated Annealing。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"以下是幾個算法的部分測試結果:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/83\/83cf1db452d31f7054860e9ac31401ce.png","alt":"圖片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":"center","origin":null},"content":[{"type":"text","text":"硬約束結果對比"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":" "}]},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/42\/42ad6b559120ee62601de6eec5f0d3c9.png","alt":"圖片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":"center","origin":null},"content":[{"type":"text","text":"軟約束結果對比"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"     "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"可以看到幾種主要算法總體能得到的效果差異不大。從理論上來說,即使採用暴力搜索(Brute Force)的方式,只要時間夠長,也總能得到一個不錯的解。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"而在實際的業務場景中,對於班表的計算速度是有很嚴苛的要求的。有時我們發現預測的業務量產生偏差,這時候就需要立刻重新生成當天之後的班表,並及時下發。對時間的要求是分鐘級的,因此也要測試一下算法的運行速度。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"幾個重要算法的部分測試結果:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/c7\/c754bb27fd6c21674896142394288e77.png","alt":"圖片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":"center","origin":null},"content":[{"type":"text","text":"算法時間測試結果"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"       "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"而幾個算法的提升速度,測試下來短期Tabu Search的結果提升較快,不過後續乏力,整體略遜於另外兩個算法。"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"5.2 應用"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這裏的算法基準測試只是初步篩選一下可能有用的算法,整個計算流程中,從班次的確定,再到休息,加班,放休等的安排,實際是分多個層次的。從邏輯上講,順序應該是:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"確定班次"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"確定加班放休安排"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"確定休息,喫飯等當天安排"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"確定週會安排"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們算法流程設計上也必須遵循一定的順序,畢竟在班次沒確定的情況下,我們也沒辦法安排當天的餐休。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"因此流程上:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"先安排了First Fit,快速得到一個不太差的初始解。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"接下來選擇能夠短時快速提升的Tabu Search,僅僅針對班次,快速搜索找到一片高分區域。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"最後利用LAHC或Simulated Annealing等算法針對全部變量搜索一個較優解。"}]}]}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"5.3 性能優化     "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在我們的業務場景中,問題規模很大,正常計算需要數小時甚至數天才能得到最終的結果,這一場景下是不可接受的。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"一般的算法系統框架都是單機甚至單核的,這裏首先要對算法系統進行多核支持,啓發式算法的流程分爲:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"選擇待選步驟"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"各步驟嘗試"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"確定下一步(或者找不到下一步)。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"對整個流程進行梳理後,我們判斷整個算法性能消耗最多的地方是第二步,也就是各個步驟的嘗試部分,在這一步加入多線程的支持,在選擇了待選步驟後,對各個待選項進行多線程的並行嘗試。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"事實證明,這一步將性能提升10倍以上。"}]},{"type":"heading","attrs":{"align":null,"level":4},"content":[{"type":"text","text":"5.4 分佈式多機並行"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"但在有些場景下依然不能滿足目標性能的需求,無法在30分鐘內得到班表。因此我們不得不利用分佈式計算的思想,將問題進行切分,嘗試在多機上進行並行計算,最後將結果彙總,在主機上進行彙總計算。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"瞭解啓發式算法的同學應該清楚,這樣每臺單機都獲得的是問題的一個子集,缺點是無法全局考慮問題,最終結果和單機運算相比會略有下降。但是性能確實成倍的提升,在多工種的特殊場景中,我們通過這種思路,實現了複雜工種技能下的混合排班。並且最終效果也依然能夠達到我們對擬合度的要求。在啓發式搜索問題中,這是一種損失少量效果而大幅提升速度的有效技巧。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"六、平臺結構"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在算法的基礎上,我們搭建了一套智能排班中臺作爲項目目標,使用戶可以輕鬆訪問服務,得到靈活的班表。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"整體架構示意圖:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/infoq\/ed\/ed7dc3d4821346ccd65692e7d487e3be.png","alt":"圖片","title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"整個系統包含多個模塊,互相協調保證攜程各個部門的靈活調用。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"總體調用流程如下:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"1)各個BU通過系統對接排班系統,將數據做清洗和標準化"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"2)進行基本的數據校驗,在實際環境中,各種各樣隱藏的矛盾錯誤數據,都需要在這一步識別出來。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"3)合併人工錄入的部分數據,考慮到部分數據的時效性以及一些偶發需求,我們需要開放人工信息的錄入平臺,讓用戶可以錄入部分數據"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"4)建立模型"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"5)算法求解得到優質解"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"6)生成班表"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"7)(可選)人工微調"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"8)生成班表,並對接回各個業務系統"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"七、結語    "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"隨着越來越多的BU接入到智能化排班的系統中,算法平臺發揮着更大的作用。在不斷接觸不同部門的過程中,我們也發現了模型建立中和算法設計中的各種問題。在我們長期的開發過程中,也走過不少彎路和死衚衕,最終發現,需要全局的去看待一個業務問題,並提出解決方案,抓住真實痛點,才能最終落地。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"作者簡介"},{"type":"text","text":" "}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"博天,攜程高級研發經理,關注大規模約束優化問題的建模和算法設計。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"本文轉載自:攜程技術(ID:ctriptech)"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"原文鏈接:"},{"type":"link","attrs":{"href":"https:\/\/mp.weixin.qq.com\/s\/gJRszlTa4CdPWZYB3HgJ0A","title":"xxx","type":null},"content":[{"type":"text","text":"乾貨 | 10分鐘給上萬客服排好班,攜程大規模客服排班算法實踐"}]}]}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章