公路旅行規劃師
產生一個經由腳本檢查的駕駛計畫,確保每個需求和現實事實都可追溯。一個看似合理的行程正是此技能存在所要防止的失敗:在長途駕駛中,一個錯誤的距離或一個已關閉的加油站可能使人們在日落後受困。
為什麼工作流程是這樣的
此方法源自於一個神經符號旅行規劃代理,以下步驟皆源自於這些經驗教訓:
- 大多數錯誤始於翻譯。 將旅客的話語轉化為精確的約束條件比聰明的規劃更重要,因此需求會先被寫下來並複誦確認。
- 一個不依賴模型的檢查器能捕捉模型遺漏的錯誤。 你判斷什麼值得做。腳本則判斷它是否可行。
- 空資料不能算作通過。 檢查結果會回傳 PASS、FAIL 或 UNKNOWN。將 UNKNOWN 報告為未知,絕不能視為沒問題。
- 盲目重試很少解決問題。 修復應針對特定失敗,並盡可能少做更改。
- 編輯不能導致倒退。 只有在沒有讓任何情況變得更糟時,編輯才會被保留。
- 通過檢查器不是最終目標。 更嚴格的評分者能堵住漏洞,而現實是最嚴格的。切勿為了讓檢查變綠而調整數字、設定
night_ok或將事實標記為已驗證。
工作流程
腳本位於此文件旁邊的 scripts/ 目錄中(route_legs.py、order_stops.py、choose_nights.py、verify_trip.py、render_report.py),僅需要標準的 Python 環境。在編寫計畫檔案之前,請先閱讀 references/plan-format.md。將計畫保留為使用者旅行資料夾中的 trip.json,或者如果他們不希望檔案放在那裡,則保留在暫存目錄中。
1. 擷取需求
提取使用者已經說過或提供的內容。如果他們提供了行程,請按原樣匯入,包括其陳述的距離標記為 claimed_km,以便其錯誤浮現而不是被悄悄修正。
然後詢問仍然缺少的資訊。閱讀 references/intake.md 並使用 AskUserQuestion 工具遵循其回合進行。如果目的地或路線尚未決定,請從其第 0 輪開始:提供 2-3 個經過研究的路線選項,每個選項說明其取捨。其他回合涵蓋路線和日期、駕駛人和駕照、飯店品牌、房間和預算、每日距離和節奏、興趣和避開事項、已預訂的項目,以及輸出語言和格式。跳過任何已經回答的問題。在真實旅行中,每個較晚回答的問題(例如飯店品牌、暈船或出發日期)都可能導致完全重建,因此事先多問幾個問題比猜測更省事。
將每個需求記錄為一個帶有類型的約束條件,並使用使用者自己的話語作為 nl,並將剩餘的回答保留在 preferences 中。在據以規劃之前,先用白話文將列表讀回確認。對於類型無法表達的任何內容,使用 manual。將真正的需求與偏好區分開來,因為只有需求屬於 hard_constraints。
2. 從來源收集事實
不要憑記憶規劃任何可能改變或可以查詢的事項:
-
距離和時間: 執行
route_legs.py trip.json。它使用 OpenStreetMap 服務,僅傳送地名和座標。如果路由器計算的路徑不是預期的道路,請將該路徑點作為一個停留點加入。leg_speed警告通常表示地圖點有問題,因此請修正座標並使用--force重新計算路線,而不是接受計算出的時間。 -
參觀順序: 對於任何一天有三個或以上景點的情況,請執行
order_stops.py trip.json --day N。它會建議駕駛距離最短的順序,並保留固定點:起點、飯店,以及任何具有be_by或"fixed": true的停留點。如果順序改變,請使用--write trip_vN.json儲存,重新計算路線,並使用檢查器針對先前的版本進行測試。駕駛時間不是唯一的成本,因為營業時間、10:15 的間歇泉或日落可能比幾分鐘更重要。使用檢查器的判定,而非較短的順序。 -
燃油: 列出偏遠路段上的每個加油站,包含營業時間,並將加油點標記為
refuel。取得該車輛類型的真實續航里程。 -
營業時間和關閉資訊: 搜尋營業時間、季節性關閉、路況和許可證,並記錄每個資訊的來源和日期。對於每個頭號景點,也要搜尋旅行年份內新的預訂規則,例如限時入場、預訂停車位或新費用。搜尋「<景點名> 預訂 要求 <年份>」,而不僅僅是其營業時間。此類規則可能隨時更改:在一個測試旅行前一個月,一個主要沿海觀景點就開始要求預訂。
-
這些確切日期: 搜尋旅行日期期間沿線發生的事情,而不僅僅是概括性的:可能導致城鎮客滿的活動、燃料或補給中斷、道路施工,以及學校或公眾假期。如果匯入的行程是基於某個季節或月份,請根據實際日期重新驗證其氣候和季節性聲明。
-
固定時間: 不要憑空捏造航班或渡輪時間。使用旅客的票券,或引用並標記為假設的時間表。在國際航班降落後,在車輛開始移動之前,預留 60-90 分鐘處理入境、檢疫和租車櫃檯。在起飛前,預留航空公司的報到時間加上還車時間。
-
道路風險和備用計畫: 對於路線上的每一條關鍵道路,檢查其官方關閉頁面或公告,以了解當前問題(例如坍方、車隊管制或道路施工),以及季節性風險(例如積雪、洪水或火災)。當某個風險可能破壞計畫時,建立一個備用路線作為單獨的計畫檔案(
trip_vN_B.json),並像主計畫一樣使用檢查器檢查。如果道路可能在行程中關閉,則添加 C 計畫。在contingencies中記錄每個備用計畫,包含風險、要監控的觸發條件、decide_by日期、計畫和來源。建議在該日期之前,在備用路線上保留可免費取消的房間。有明確日期限制的 A/B 選擇,比「出發前檢查」的警告更有價值。 -
品牌飯店和過夜城鎮: 當旅客想要某個品牌時,使用該連鎖飯店自己的網站,列出其所有位於任何合理路線約 30 公里範圍內的飯店。將每個飯店加入計畫的
overnight_candidates中,同時加入其他可能適合過夜的城鎮(如果有加油站則加上refuel: true)。然後執行choose_nights.py trip.json。它會嘗試每一種夜間安排,並根據品牌飯店住宿晚數對那些在每日駕駛限制內的安排進行排名,品牌晚數相同時則選擇最長一天駕駛時間最短的安排。使用--write儲存最佳方案,重新計算路線,並進行檢查。切勿透過猜測來排除品牌飯店。該腳本還會列出「接近達標」的方案:那些品牌住宿晚數更多,但僅超出某項限制最多 10% 的安排。將最佳接近達標方案作為選項提供給旅客(例如,「多住一晚 IHG 飯店,但有一天駕駛時間是 4 小時 04 分,而不是 4 小時」),並且不要替他們選擇。 -
當地規定: 檢查路線上的租車限制、異地還車費用、邊境和檢疫規定,以及當地時區。將每項記錄在
facts中。 -
預訂、餐飲和準備工作: 閱讀
references/prep-and-bookings.md。將每個需要預訂的項目放入計畫的bookings區塊,並附上基於證據的book_by日期,以便檢查器標記任何逾期或付款尚未確認的項目。為每個長途駕駛日指定一個真實的午餐停留點。根據此行程實際包含的內容,建立出發前檢查清單和打包清單。
如果你無法驗證某項資訊,請將其保留為未驗證狀態。計畫仍然可以繼續進行,但會顯示出這個資訊缺口。
3. 檢查計畫
python3 scripts/verify_trip.py trip.json
退出碼 0 為 PASS,1 為 FAIL,2 為 UNVERIFIED,3 為無效檔案。閱讀每項發現。該腳本會為每個停留點提供其日期和地點的日出和日落時間,因此無需自行估算。
4. 一次修復一個錯誤
對於每個 FAIL,找出其失敗的原因,並選擇最小的現實世界改變:提早出發、刪除或移動一個停留點、更換過夜城鎮。將其儲存為一個新檔案,並針對前一個檔案進行測試:
python3 scripts/verify_trip.py trip_v2.json --baseline trip.json
僅在編輯被接受時才保留它。拒絕會指出哪些方面退步了,因此利用這個資訊來選擇不同的修正方法,而不是重試同一個。當使用者要求進行更改時,請添加 --user-requested:它不需要改善某個指標,但仍然不能使任何方面退步。當編輯新增了一個停留點或飯店時,請添加 --allow-new-unknowns,然後研究它列出未知資訊。
如果沒有編輯能修復某個失敗,則表示該趟旅行不符合指定的約束條件。請如實告知,並提供真正的取捨方案,例如增加一天或刪除一個停留點,而不是自行放寬規則。
5. 報告
書面計畫始終來自 render_report.py,因此每個版本都有相同的章節和順序,且其時間和距離不會與檢查器的結果不一致:
python3 scripts/render_report.py trip.json --out trip_v3_<Label>.pdf
固定的順序是:總覽 → 每日行程 → 預訂和票券 → 飯店 → 待辦事項 → 出發前須知 → 來源。可以根據旅客的意願,在計畫的 report 區塊中(來自訪談第 5 輪)或透過命令列選項進行更改:
lang:任何語言代碼,設定為旅客的選擇。內建en和zh的標籤。對於任何其他語言,執行render_report.py --print-labels,翻譯其值(保留{佔位符}),並儲存為report.labels;渲染器會警告任何它不得不保留英文的標籤,因此在該警告消失之前不要交付報告。report.labels也可以用來覆蓋en或zh中的單個標籤。地名會顯示當地標籤和地圖名稱。如果非拉丁文字的 PDF 顯示空白方框,請將report.font設定為涵蓋該文字的字体({"regular": 路徑, "bold": 路徑});從右到左的腳本以 HTML 或 Markdown 格式渲染效果更好。format:pdf、html或md。也可以從--out檔案的副檔名讀取。detail:full使用每個停留點的note、該日的intro和其tips;brief使用short。layout(僅限 Markdown):phone(Markdown 的預設值)將表格轉為列表,避免橫向滾動。print保留表格。
當旅客要求簡短內容時,設定 detail: brief 和 layout: phone,刪除他們不需要的章節,並將 report.open_items 保持在最多 6 個一行項目。渲染器的長度警告(max_words_per_day,預設 200;max_words_total,預設 1600)然後成為硬性限制:縮短 short 筆記和待辦事項,重新渲染,並且在任何長度警告仍然存在時不要交付。刪減文字,而不是事實。一份很長的報告對於要求簡短報告的旅客來說是失敗的,無論其內容多好。
sections:七個章的任意子集,仍保持固定順序。
你自己在計畫中以旅客的語言編寫文字:每天的 title、intro 和 tips,停留點的 note 和 short,地點的 label,prep.checklist,prep.packing,以及選擇性地使用 report.open_items 來取代自動分組的待辦事項。腳本拒絕編寫包含電子郵件地址的報告。也請將電話號碼、身份證號碼和出生日期排除在計畫之外。如果旅客要求固定章節無法容納的內容,請將其添加到計畫的文字欄位中,而不是手動建立單獨的文件。如果他們希望有不同的外觀,請修改渲染器一次,以便後續每個版本都能保持。
在聊天中,先說明結論以及使用者需要決定或採取哪些行動。然後包括:
- 結論 用白話文說明,並附上計數。「未驗證」表示已根據已知事實進行檢查。
- 發現的問題,按嚴重程度排序,每個問題附上已採取的修復措施或他們需要做出的選擇。
- 時間線 每天:出發、停留點、抵達、日落、公里數和時數,以及長途駕駛日的午餐停留點。
- 接下來需預訂或確認的事項,按
book_by日期排序,每項附上官方連結。同時註明哪些項目在現場出售。 - 仍然未知的事項,以及如何查詢每項資訊。
- 出發前須知: 完整的文件中的客製化出發前檢查清單和打包注意事項。在聊天中保持簡短。
讀者是旅客,因此請翻譯檢查器的輸出:說明什麼是錯的以及該怎麼做,省略發現計數、檢查名稱和諸如「UNKNOWN」或「baseline」之類的術語。將 claimed_km 的分歧顯示為兩個數字的比較。使用旅客選擇的語言書寫,並保持地名易於導航識別(以另一種語言書寫時添加當地名稱)。
檢查器無法告訴你的事項
在相關時請告知使用者。它不知道即時道路封閉、森林火災或洪水情況、某個地方是否真的值得參觀,或駕駛員有多疲勞。其駕駛時間來自路由器加上緩衝區,而日落時間是計算得出的估計值。對於偏遠路線,請告知使用者在出發前不久檢查官方路況服務。
與旅客一起進行多次修改
真實的旅行會經歷數十個版本:路線改變、預訂一筆一筆進來、景點來來去去。這些習慣讓這樣一趟旅行(超過 40 個版本)保持安全:
- 建立版本,從不覆寫。 將每次更改儲存為一個新的計畫,例如
trip_v12_<Label>.json,以及一個新文件,其名稱說明更改的內容。保留所有先前的檔案,因為旅客可能想要回溯。 - 只更改被要求的內容。 「刪除乘船遊覽」表示刪除那一個停留點並重新調整該日的時間。這不表示重新設計這一天。如果更改後產生了空檔,請以問題形式提供填補選項,不要未經詢問就自行加入。
- 將選擇作為問題提供。 當有替代方案時,例如替代景點、過夜城鎮或非品牌飯店之夜,請使用 AskUserQuestion 提供 2-4 個具體選項。為每個選項說明其時間和距離影響,並先提出你的建議。
- 預訂是固定點。 當旅客貼上確認資訊時,記錄其參考編號、日期和時間、房間和床位、價格和貨幣、是否已付款或抵達時付款、取消條款,以及入住或退房時間。然後根據計畫檢查它(日期、地點、時間)並重建文件。指出任何尚未最終確定的事項,例如標記為「待處理」的付款、缺少的飯店名稱或時間衝突。一旦某件事被預訂,就不要
…
[內容因超過長度而被截斷]