| name | itinerary-optimize |
| description | ⭐ 行程运筹核心壁垒 · 把 Top N POI 池转成"地理顺路 + 体力分配 + 时间窗匹配"的可执行行程。三步走:K-Means 地理聚类分天 → TSP 贪心+2-opt 排顺路 → 体力/营业/用时窗适配。这是通用 AI 完全做不好的事。 |
| version | 1.0.0 |
| author | null |
| tags | ["travel","itinerary","tsp","clustering","optimization","moat"] |
| license | MIT |
| triggers | ["poi-curate 输出 poi_pool 后","用户对某主题路线确认后需要\"具体每天怎么走\""] |
| inputs | [{"name":"poi_pool","type":"object","required":true},{"name":"trip_request","type":"object","required":true},{"name":"user_profile","type":"file","formats":["json"],"required":true},{"name":"hotel_anchor","type":"object","doc":"当天住宿坐标,作为出发/返回锚点","required":true}] |
| outputs | [{"name":"itinerary","type":"object","doc":"N 天行程,每天含时间轴 + POI 顺序 + 路径距离 + 体力指数"}] |
行程运筹(itinerary-optimize)⭐
这是 agent 真正的护城河
通用 AI 排行程:「上午去 A,下午去 B」— 你打开地图一看,A 和 B 跨城市了。
我做的:用真实坐标做运筹,每天的 POI 是真的顺路。
三步算法
Step 1: geo_cluster.py · K-Means 地理聚类分天
输入:N 个 POI 的坐标
输出:duration_days 个簇,每簇 5-7 个 POI
约束:
- 每天总点数 = 1 个早餐 + 1 个午餐 + 1 个晚餐 + 2-3 个景点 + 1 个咖啡/夜市 = 6-8 个
- 同一天的 POI 地理距离 < 15km(大城市)/ < 50km(小城市/跨景区)
- 第一天和最后一天预留交通时间,POI 减半
Step 2: optimize_route.py · TSP 顺路
每个簇内部:
- 锚点 = 当天住宿坐标
- 起点 = hotel
- 终点 = hotel(除非要换酒店)
- 中间点 = 簇内 POI
算法:
- 节点 ≤ 10:枚举所有排列(10! = 3.6M,可接受)
- 节点 > 10:贪心最近邻 + 2-opt 优化
- 距离:haversine 球面距离(已知精度有限但够用),并由经验系数估算驾车/步行时长(市区 1.4×,跨城 1.2×;步行 12 min/km,驾车 30 km/h 市区 60 km/h 跨城)
- v2.0 取消高德距离矩阵依赖,运筹精度从"真实驾车时长"退到"haversine + 经验估算"
Step 3: balance_pace.py · 体力/营业/时间窗适配
输入:顺路后的 POI 序列
输出:带具体时间的行程表
约束:
- 早餐 7:30-9:00
- 上午景点 9:30-12:00(≤ 2 个)
- 午餐 12:00-13:30
- 午休 + 下午景点 14:30-17:30(≤ 2 个)
- 晚餐 18:00-19:30
- 晚间活动(夜市/酒吧/夜景)20:00-22:00(可选)
体力分配规则(按 user_profile.basic.preferred_pace):
- walker_intense:每天上限 5 个景点 + 暴走
- normal:每天 3-4 个景点
- relaxed:每天 2 个景点 + 大块自由时间
营业时间适配:
- 用 online-search 查 POI 营业时间
- POI 营业时间冲突 → 自动调换日期或顺序
- 周一闭馆景点(博物馆类)自动避开
输出 schema
{
"trip_id": "uuid",
"days": [
{
"day_index": 1,
"date": "2026-04-15",
"theme": "市区文化探索",
...
...