统一数据字典

修改记录

日期

变更

2026-07-18

从引擎内部 5 种类型扩展为全链路数据字典(API → 引擎 → 前端)

单位约定

单位

说明

距离

km

行驶距离

时间

min

旅行耗时、时间窗、停留时长

速度

km/h

旅行速度(默认 1.0——仅测试实验集使用,真实数据由高德驾车 API 提供,不依赖此值)

经纬度

GCJ-02

高德坐标系,x=经度,y=纬度

索引

0=depot

0 索引始终为酒店,景点从 1 开始

时间窗

(start, end)

距午夜分钟数,0=00:00,1440=24:00

一、POI 与地图数据

POIItem(API 请求)

前端传给后端的单个景点参数。定义见 backend/api/schemas.py:6

字段

类型

默认值

说明

name

str

景点名称

lon

float

GCJ-02 经度

lat

float

GCJ-02 纬度

tw_start

float

480

营业开始(8:00)

tw_end

float

1020

营业结束(17:00)

stay

float

0

建议停留时长

expected_arrival

float|None

None

用户期望到达时间

POILookupResponse(API 响应)

POI 查询结果。定义见 backend/api/schemas.py:54

{
  items: POILookupItem[],    // 查询成功列表
  failed: string[]           // 未找到的名称
}

POILookupItem:
  name, lon, lat, address
  tw_start: int | None       // LLM 解析结果,None 表示解析失败
  tw_end: int | None

tw_start/tw_endint | None:若 LLM 无法从高德 opentime2 解析出营业时间,返回 None。前端暂未处理此情况。

PoiCache / PoiCacheItem(引擎内存缓存)

后端内部映射,见 backend/typedefs.py:27

PoiCache:
  hotel: PoiCacheItem
  spots: PoiCacheItem[]

PoiCacheItem:
  name, lon, lat
  tw: (float, float)       // 与 API 不同,这里为元组 (start, end)
  stay: float

SpotDict(引擎求解器核心类型)

引擎内部景点类型,求解器和聚类算法直接使用。定义见 backend/typedefs.py:11

字段

类型

必填

说明

name

str

景点名称

x

float

GCJ-02 经度

y

float

GCJ-02 纬度

tw

(float, float)

有效时间窗 (start, end),经 effective_start / effective_end 收缩后的最终值

stay

float

停留时长(分钟)

original_tw

(float, float)

原始营业时间窗,来自 POI 查询结果,用于对照

lon

float

与 x 重复的兼容字段

lat

float

与 y 重复的兼容字段

expected_arrival

float

期望到达时间,影响 effective_start 计算

tw 的收缩规则在 pipeline.py:97-117effective_start = max(tw_start, expected_arrival, day_start) effective_end = tw_end - stay

二、规划请求

PlanRequest(统一请求体)

适用于 /api/suggest/api/plan 两个端点。定义见 backend/api/schemas.py:67

{
  city: string              // 城市名
  hotel_name, hotel_lon, hotel_lat, hotel_tw_start: 0, hotel_tw_end: 1440
  spots: POIItem[]          // 至少 1 个
  n_days: int | null        // null → 建议模式,有值 → 规划模式
  mode: "fast" | "deep"     // fast=CA求解器,deep=VNS求解器
  day_start: float          // 启程时间,默认 0=午夜
  min_days: int | null      // 建议模式的最小天数,null 时引擎自动推断

  // 矩阵复用(来自 suggest 响应):
  cost_matrix: number[][] | null
  dist_matrix: number[][] | null

  // 惩罚权重:
  penalty_weight: 100       // 迟到惩罚
  early_wait_weight: 0.1    // 早到等待
  late_return_weight: 50    // 晚归
}

PlanAdjustRequest(规划调整)

重新规划请求,见 backend/api/schemas.py:130

{
  spots: dict               // 当前景点字典
  cost_matrix: number[][]
  dist_matrix: number[][]
  routes: list
  adjustments: {            // 调整指令
    balance?: true,         // 均衡天数
    change_days?: 3,        // 改天数
    remove_poi?: "故宫",     // 移除景点
    add_poi?: {...}         // 添加景点
  }
}

三、规划结果

RouteResult(求解器原始输出)

solve_groups 的返回,定义见 backend/typedefs.py:44

字段

类型

说明

routes

list[list[int]]

每组 [0, 3, 1, 0](首尾 depot)

histories

list[list[float]]

收敛历史(可选)

total_cost

float

总成本 min,= total_dist + wait + late + penalty

total_dist

float

总行驶距离 km

wait

float

总等待时间 min

late

float

总迟到时间 min

valid

bool

是否覆盖全部景点

ScheduleItem(每日行程单条)

重建行程的产物,定义见 backend/typedefs.py:63frontend/src/types.ts

{
  name: string              // 景点名称
  arrival: int              // 到达时间(距午夜分钟数)
  departure: int            // 离开时间(距午夜分钟数)
  tw: string                // 营业时间窗 "HH:MM - HH:MM"
  stay: string              // 停留时长 "X min"
  arrival_status: string    // "正常到达" / "早到 X 分钟" / "迟到 X 分钟"
  departure_status: string  // "正常离开" / "迟到 X 分钟离开"
}

后端 staystr(含单位),前端 types.ts 中为 number(纯数值)。

PlanResult(完整规划结果)

run_planning 的最终返回,定义见 backend/typedefs.py:74frontend/src/types.ts

{
  type: string              // "suggestion" 或 "solution"
  solution?: {
    routes, total_cost, total_dist, wait, late, valid
  }
  best_days: int            // 建议天数
  best_m: string            // 最优方法名称
  spots: {                  // 景点字典,key=索引
    "1": { name, x, y, tw, stay, original_tw, ... }
  }
  daily_schedules: [        // 每日行程
    [ScheduleItem, ...],    // Day 1(首尾为酒店出发/返回)
    [ScheduleItem, ...],    // Day 2
  ]
  commentary: string        // AI 评语(仅 solution 模式有)
  cost_matrix: number[][]   // N+1 × N+1 成本矩阵(分钟)
  dist_matrix: number[][]   // N+1 × N+1 距离矩阵(km)
  polylines: {              // 真实路径坐标
    "0_3": "116.39,39.91;116.40,39.92;..."
  }
  amap_api_key: string
  amap_security_code: string
  algo_time: float          // 算法耗时(秒)
}

suggestion 模式会为每条建议调用 _rebuild_schedule,返回 daily_schedulestype="solution" 时额外包含 commentary

SuggestionItem(建议列表条目)

POST /api/suggest 响应中 suggestions[] 的元素类型,见 frontend/src/types.ts

{
  n_days: int
  method: string
  cost: number, total_dist: number, wait: number, late: number
  routes: number[][]
  daily_schedules?: ScheduleItem[][]
}

四、历史记录

HistoryCreate(创建请求)

保存方案到分享站,定义见 backend/api/schemas.py:147

{
  device_id: string | null  // 匿名设备标识,用于删除时鉴权
  note: string | null       // 用户备注
  city: string
  hotel: string | null
  n_days: int
  cost: float | null
  spot_count: int | null
  plan_result: dict         // 完整 PlanResult(JSONB 存储)
  request_params: dict|null // 原始请求参数(buildRequest 产物)
}

HistorySummary(列表项)

分页列表的每条摘要,见 backend/api/schemas.py:165

{
  id: string, city: string, hotel: string|null, n_days: int
  cost: float|null, spot_count: int|null, note: string|null
  created_at: string        // ISO 8601
}

HistoryDetail(完整详情)

单条历史完整数据,见 backend/api/schemas.py:177

{
  id, city, hotel, n_days, cost, spot_count, note, created_at
  plan_result: dict         // 全量 PlanResult
  request_params: dict|null
}

五、数据流映射

前后端类型对应

逻辑概念

API(schemas.py)

后端引擎(typedefs.py)

前端(types.ts)

景点参数

POIItem

SpotDict

POIItem(生成)

POI 查询

POILookupResponse

PoiCache

POILookupResponse(生成)

规划请求

PlanRequest

PlanRequestPayload

求解结果

RouteResult

PlanResultSolution

行程项

ScheduleItem

ScheduleItem

完整结果

PlanResult

PlanResult

建议项

SuggestionItem

历史摘要

HistorySummary

ORM 行

HistorySummary

历史详情

HistoryDetail

ORM 行

HistoryDetail

索引约定

  • 所有数组和字典的 0 索引固定为酒店(depot)

  • routes 序列:[0, 3, 1, 0] 意为酒店 → 景点3 → 景点1 → 酒店

  • 前端构建 PlanResult 时,best_daysdaily_schedules.length 一致

  • polylines 的 key 格式为 "{fromIdx}_{toIdx}",如 "0_3":depot 到景点3

边界与约束

约束

来源

景点数下限

1

PlanRequest.spots

天数范围

[min_days, n_spots]

ca_suggest 循环

天数下界(默认)

max(1, n_spots // 8 + 1)

search.py:174

聚类方法数

6

clustering.py

成本矩阵形状

(N+1, N+1)

N=景点数

VNS 精英池容量

3

vns.py