面向 TMC 與 OTA 的代理式 AI 旅遊訂位

訂位代理的高段作法不是更聰明的模型,而是把 LLM 移出控制流程。

我們打造了一個自主旅遊訂位代理,其控制流程是確定性 Python。模型只負責解析行程請求並撰寫回覆。每一步訂位都會登錄補償動作,因此當飯店費率在機票開票後過期時,代理會在 24 小時窗口內作廢機票,並交給旅客誠實的替代方案,而不是讓他們滯留。

100%

終端狀態一致,由建構保證

固定種子、200 情境合成批次,對照 LLM-in-control 基準的 65%

0 / 0

滯留旅客、被呈現的捏造訂位

同一批次,對照基準的 40 與 30

$3.25

每次訂位的平均 GDS 搜尋花費

對照基準 $7.57;GDS 按次搜尋計費,Lufthansa 於 2026 年 1 月 1 日調升費用

所有情境皆為模擬 GDS 與 CRS 上的合成資料;機場代碼與飯店名稱是真實形貌的測試夾具,並非即時庫存或真實訂位。

讓 LLM 掌管一筆交易,會出兩種錯

兩者都不是模型智商失效。兩者都已是 2026 年的缺陷類別。

它讓旅客滯留

代理開了機票,飯店步驟失敗,沒有補償邏輯時它仍說「一切就緒。」有人只拿到機票、沒有房間。再完美的模型,若沒有任何東西作廢機票,仍會讓旅客滯留。

它呈現不存在的庫存

它捏造一間看似合理的飯店並完成訂位。該物業從未存在於 CRS。在到達旅客之前沒有任何檢查,因為在推理迴圈裡,模型既是提案者也是裁判。

更好的模型修不好這件事,因為這些失效是基礎設施與使用事件,與模型品質無關。費率在兩次 API 呼叫之間過期。開票後 hold 被拒絕。搜尋風暴燒光毛利。隨機推理會對此疊加:十個步驟各 90% 可靠度,端到端大約只剩 34%,而 GPT-4 搭配 ReAct 完成真實多日行程的比例為 0.6%(TravelPlanner,OSU NLP,arXiv 2402.01622)。你無法靠提示詞走出疊加的隨機失效。

而且部署者擁有代理所做的每一句陳述。在 Moffatt v. Air Canada(BC Civil Resolution Tribunal,2024 年 2 月 14 日)中,該航空公司因其聊天機器人捏造喪親票政策而被判賠償 $812.02,「AI 是獨立實體」的主張被駁回。

運作方式:代理提供建議,程式碼做出決定

控制流程是手寫的 Python 狀態機,約十個節點。LLM 被限制在兩項葉節點工作。兩者之間的一切都是確定性的。

input → extract(LLM 葉節點)→ search → policy gate → verify gate → hold → ticket → hotel-book → commit

Extract,LLM 唯一的結構化工作

模型將自然語言意圖解析為 Pydantic 型別化的 TripRequest (出發地、目的地、日期、旅客、艙等、飯店)。該型別化物件是 LLM 產出的唯一結構化產物。它可透過 Pydantic AI 替換供應商,並在沒有金鑰時以確定性 stub 完全離線執行。

政策編譯為程式碼

企業政策以純 Python 述詞存在:僅限經濟艙、每航段 $600 票價上限、偏好承運人(United、American、Delta)、每晚 $350 飯店上限。超出政策的選項在實體上無法呈現,因為它們在顯示前就被過濾,而不是事後標記。未知票價家族採失效保護,視為高於政策而非默默當成經濟艙。沒有符合政策的航班時,代理升級到人工佇列,而不是虛張聲勢。

驗證閘道

每一間飯店皆對照 CRS,以 property_id。模型捏造的物業根本不在 CRS 中,因此會被拒絕且永不呈現,訂位進入終端狀態 abstained。閘道拒絕未確認的庫存;它不會要求模型為自己的輸出打分。

Saga,多數示範略過的那一段

每一步向前都會在執行當下登錄其反向動作。例如開票會登錄「作廢機票,24 小時窗口」。步驟 N 失敗時,補償從 N-1 往下到 1 依反向順序執行,然後代理才回報。這就是示範與產品的分野,因為它讓部分失敗不會變成滯留的顧客。

GDS 成本計量表與稽核軌跡

即時計數器以每航段 $3.25 追蹤 GDS 搜尋花費,因為計費的是搜尋,而不只是訂位。L2B 快取與延遲搜尋讓花費持平,而投機代理會反覆再搜尋並燒光毛利。每一筆訂位寫入僅附加的 JSON 事件日誌,可匯出為 audit-<pnr>.json,內容包含模型與版本、型別化行程請求、每一個節點裁決、每一次 Saga 補償、EU AI Act Article 50 揭露旗標,以及終端狀態。

示範呈現什麼

四個按鈕,與同一情境上真實的 LLM-in-control 基準並排。下方每張截圖皆擷取自正在運行的應用程式。

一筆正常訂位,逐節點執行

示範正在執行一筆正常的 ORD 到 SFO 訂位。右側,確定性管線追蹤依序跑過每個節點,從意圖抽取經過政策閘道、CRS 驗證、hold、開票與飯店 commit,以 confirmed 的 PNR 結束,GDS 搜尋花費計量表讀數為 $3.25。左側,標示為 No Tools and No Verification 的面板只回覆一切都已訂妥。

「ORD 到 SFO,下星期二,市中心一晚,公司政策。」狀態機跑過每個節點,依 property_id 對照 CRS 確認 Hyatt Regency SF,搜尋計量表在一次快取搜尋上維持 $3.25。終端狀態:confirmed,附帶 PNR。

驗證閘道拒絕不存在的飯店

CRS 驗證步驟標示為失敗。詳情面板寫著 Tabacon Springs Eco-Lodge 不在 CRS 中,已被拒絕、未經呈現。物業卡片蓋上 REFUSED 戳記,並註明驗證閘道拒絕了它,且未呈現給旅客。

請求點名了一間捏造物業「Tabacon Springs Eco-Lodge」,這個名稱混合兩家真實度假村,依設計沒有 property_id。閘道找不到 CRS 相符項,拒絕呈現。代理誠實棄權:「我無法確認該物業」,而不是再捏造一間。

Saga 回滾,對照 LLM-in-control

開票後飯店費率過期的管線追蹤。三個 Saga 補償步驟反向執行,橫幅寫著 hold 在 commit 前過期,Saga 回滾正在反向補償。結果卡寫著 ROLLED BACK、TRAVELER SAFE,並註明機票已免費作廢,同時提供替代飯店。

飯店費率在機票已經開票後過期。在我們這邊 Saga 觸發:在 24 小時窗口內作廢機票、釋放 hold,並誠實回覆機票已免費作廢,且附上替代方案。終端狀態:rolled back,旅客安全。同一情境的基準讓機票維持已開出、不提供補償,並發出虛假的「一切就緒」,這正是等待發生的 Air Canada 先例。

可匯出的稽核軌跡

主控台底部顯示 Export Audit Trail (JSON) 連結,旁邊是已回滾的結果,說明被 hold 的費率在 commit 前過期、機票已免費作廢,並提供兩間替代飯店,GDS 搜尋花費為 $3.25。

按一下即可匯出 audit-<pnr>.json:模型與版本、型別化行程請求、每一個節點及其確定性裁決、每一次 Saga 補償、EU AI Act Article 50 揭露旗標(透明度義務自 2026 年 8 月 2 日起適用),以及終端狀態。

200 情境基準測試

基準計分板涵蓋固定種子、注入相同失效的 200 筆合成訂位。四張磁貼比較確定性代理與普通 LLM 基準:終端狀態一致為 100% 對 65%、滯留旅客為 0 對 40、被呈現的捏造訂位為 0 對 30、平均 GDS 花費為 $3.25 對 $7.57。結果表列出各情境結果,包括 confirmed、rolled back、abstained、escalated、integrity breach 與 stranded。

同一批 200 筆合成訂位、一個固定種子(42),以及相同注入的基礎設施失效,分別跑過兩種架構。情境組合為 50% 順利、20% hotel-fail-after-ticket、15% hallucinated-entity、15% search-storm。我們的保證由建構成立;基準的失效從同一份資料浮現。

確定性控制流程對照迴圈中的 LLM

基準是在相同情境上運行的真實 ReAct 風格 LLM-in-control 代理,是誠實錨點而非稻草人。下方數字來自固定種子、200 情境合成批次(benchmark.py,seed 42,n=200)。

指標 確定性代理(我們的) 基準(LLM-in-control)
終端狀態一致 100.0% 65.0%
滯留旅客 0 40
被呈現的捏造訂位 0 30
每次訂位的平均 GDS 搜尋花費 $3.25 $7.57

這 100%、0 與 0 是在此固定種子合成批次上由建構成立,並非開放世界的正式環境保證。主張狹窄且耐久:部分訂位永不顯示為 confirmed,旅客永不滯留。$3.25 對 $7.57 的差距是在任何模型品質下都成立的毛利數字。

本示範不做什麼

  • 它不連接到即時 GDS、CRS 或 NDC。GDS 與 CRS、IATA 與 ARC 開票,以及 PCI 付款,皆為 stub 並模擬。測試夾具轉接器是 V1 整合;背後沒有即時的 Amadeus、Sabre 或 Duffel 帳戶。
  • 它不開真實機票、也不移動真實金錢,且 Veriprajna 並非 IATA 或 ARC 認證。機票與付款皆為 stub。
  • 情境、PNR、飯店與旅客皆為合成。「Tabacon Springs Eco-Lodge」是刻意捏造的物業,用來示範失效模式。Hyatt Regency SF 這類真實名稱的飯店是測試夾具庫存,不是真實訂位。
  • 它不主張比 GDS 或 OTA 訂得更多、更便宜或更聰明,也不主張模型零幻覺。LLM 仍起草意圖;保證是閘道拒絕未確認庫存,且 Saga 清理部分失敗。
  • 引擎是手寫的 Python 狀態機,不是 LangGraph。LangGraph 被標為延後的正式環境替換項。LLM 葉節點呼叫使用 Pydantic AI。

買方會問的問題

我能信任 AI 代理訂旅遊、而不讓我的旅客滯留嗎?

保證並非來自信任模型。在本示範中,控制流程是確定性 Python,每一步向前都會在執行當下登錄補償動作。當某一步在開票後失敗,引擎以反向執行那些補償(Saga),在 24 小時窗口內作廢機票,並誠實回報。旅客永不只拿到機票、沒有房間,因為清理不取決於模型決定要不要做。

這會接到 Amadeus、Sabre 或 Duffel 嗎?

不會。本示範中的 GDS、CRS、開票與付款全部是 stub 並模擬。測試夾具轉接器是 V1 整合,背後沒有即時的 Amadeus、Sabre 或 Duffel 帳戶。示範證明的是控制流程架構與補償邏輯,不是正式環境訂位管線。

如果飯店在機票已經開票後失敗,會怎樣?

這正是 Saga 被打造來處理的案例。開票在執行當下登錄自己的反向動作(在 24 小時窗口內作廢機票)。若飯店費率在 commit 前過期,引擎依反向順序觸發補償,免費作廢機票、釋放 hold,並交給旅客誠實的替代方案。終端狀態是 rolled back,不是 confirmed,也不是 stranded。

什麼阻止代理捏造一間不存在的飯店?

驗證閘道在呈現之前,依 property_id 對照 CRS 確認每一個物業。當本示範的請求點名一間捏造物業時,閘道找不到 CRS 相符項,拒絕呈現,代理誠實棄權而不是完成訂位。閘道不是事後標記虛構飯店;它讓該飯店在實體上無法呈現。

這與把 GPT-4 放進帶工具的代理迴圈有何不同?

ReAct 風格代理讓 LLM 掌管交易,因此由它決定何時搜尋、訂位與開票,而且沒有閘道、也沒有補償邏輯。在同一固定種子、200 情境合成批次上,該基準呈現了捏造庫存,並讓機票維持已開出、沒有回滾,發出虛假的「一切就緒」。在這裡,LLM 是只解析意圖並撰寫回覆的型別化葉節點;確定性程式碼擁有流程,每一步都帶著自己的復原。

若代理告訴旅客錯誤的事,誰要負責?

部署者擁有其代理所做的每一句陳述。在 Moffatt v. Air Canada(BC Civil Resolution Tribunal,2024 年 2 月 14 日)中,該航空公司因其聊天機器人捏造喪親票政策而被判賠償 $812.02,「那是 AI 所為」抗辯被駁回。示範匯出每筆訂位的 JSON 稽核軌跡,含模型與版本、每一個節點裁決、每一次 Saga 補償,以及 EU AI Act Article 50 揭露旗標,因此代理做過什麼事後可檢查。

技術研究

支撐本示範的研究——架構、驗證設計,以及企業藍圖。

正在評估一層你不能拿公司去賭的代理式訂位層?

讓旅客滯留、捏造飯店的那些失效,是基礎設施事件,不是模型智商問題。

若你的團隊正在衡量 LLM 在高風險訂位代理中該落在哪裡,以及如何讓部分失敗不變成 Air Canada 式的責任,我們很願意對照彼此的思路。問題是全產業的,答案也會是。

代理架構檢視

  • ✓ 盤點 LLM 目前坐落在你控制流程的何處
  • ✓ 找出需要補償動作的步驟
  • ✓ 壓力測試失效模式:費率過期、開票後 hold、搜尋風暴
  • ✓ 定義營運人員可以信任的終端狀態

確定性代理建置

  • ✓ 擁有搜尋、政策與開票的狀態機
  • ✓ 驗證閘道與 Saga 補償引擎
  • ✓ 政策編譯為程式碼,附失效保護預設值
  • ✓ 可匯出的稽核軌跡,含 Article 50 揭露旗標
社群媒體

同步發佈於