# ADR-005: 营业时间 LLM 解析与 Agent 架构决策 ## 修改记录 | 日期 | 变更 | |------|------| | 2026-07-18 | ADR-005++ 表格化,Planner Agent / 调整端点修正为 🚧,修正回退策略描述 | ## ADR-005++ | 状态 | 项 | 说明 | 验证 | |------|-----|------|------| | ✅ | 节假日/季节优化 | holidays 库查询法定节假日,注入 prompt | `tools.py:17-36` | | ✅ | MCP 迁移预留 | 已迁移至 [ADR-006](006.md),当前维持手写 FC | `tool_call` 两阶段 | | 🚧 | Planner Agent 扩展 | add_poi / remove_poi / adjust_days 函数已实现,未接入前端 | `planner.py:48-152` | | 🚧 | 方案调整端点 | backend adjust_plan + schema 就绪,HTTP 路由已移除 | `pipeline.py:264-373` | | ⏸ | 跨午夜营业时间截断 | 22:00-02:00 截断,仅 LLM prompt 约束 | `parse_biz_hours:195` | ## 状态 ✅ 已采纳 ## 背景 高德 POI API 返回的 `opentime2` 字段格式极其复杂,现有 `_parse_opentime_to_tw()` 纯函数规则解析难以覆盖全部变体: | 格式变体 | 示例 | 规则解析难度 | |---------|------|------------| | 季节分段 | `04/01-10/31 08:30-17:00;11/01-03/31 08:30-16:30` | 高 | | 节假日特例 | `春节,劳动节 08:30-17:00` | 极高(节假日不固定) | | 闭馆日 | `周一 全天不开放` | 中 | | 停止入园 | `08:30-17:00,17:00停止入园` | 中 | | 24小时 | `00:00-24:00` | 低 | | 跨天 | `20:00-02:00` | 中 | | 空/无意义 | `暂无营业时间` / `""` | 低 | 规则引擎每覆盖一种变体都需要新增正则分支,且无法泛化未知格式。 ## 三方案对比 | 方案 | 优点 | 缺点 | 结论 | |------|------|------|------| | **A: 纯 LLM 解析** | 覆盖无限格式变体,成本极低(~0.0003元/次),失败回退零风险 | 依赖 API 可用性,增加毫秒级延迟 | ✅ 采纳 | | **B: 规则增强** | 无外部依赖,零延迟 | 格式变体无限,维护成本持续增长,总有未覆盖的边界 case | ❌ 放弃 | | **C: 规则+LLM 混合** | 常见格式走规则,兜底走 LLM | 两套逻辑增加维护复杂度,规则覆盖的边际效益递减 | ❌ 不推荐 | LLM 成本测算:每次解析约 50-100 token,按 DeepSeek 价格 ~0.5元/百万 token,单次约 0.000025-0.00005 元,即使每日万次调用也仅 ~0.5 元。 ## 决策 ### 决策 1:纯 LLM 解析(方案 A) 采用 LLM 直接解析营业时间,放弃规则增强方案。 原因: - 格式变体无限,规则引擎永远追不上 - LLM 成本极低,失败返回 None 无风险 - 回退策略:后端 `parse_biz_hours` 返回 None,前端 `usePoiSearch.ts:55` 用 `??` 运算符兜底默认值 ### 决策 2:日期/节假日前置计算 `datetime` + `holidays` 库在调用 LLM 前计算出当前日期、星期、是否为法定节假日,注入 prompt 以减小 LLM 的理解负担: ``` 今天:2026-07-06(星期一),法定节假日:否 营业时间原始字符串:周一至周日 09:00-22:00 ``` ### 决策 3:MVP 不上 MCP 手写 Function Calling。当前工具数仅 1 个(`parse_biz_hours`),MCP 协议带来额外复杂度而无收益。等工具数增长到 3-5 个时再增量迁移(已迁移至 [ADR-006](006.md))。 ## 数据流 详见 [`docs/structure/backend.md`](../structure/backend.md) 数据流图 — 营业时间 LLM 解析已内嵌至 `GET /api/poi-lookup` 流程中。 ## 影响范围 | 文件 | 变更 | 说明 | |------|------|------| | `backend/agent/tools.py` | 新增 `parse_biz_hours()` | LLM 调用封装,含 prompt + 回退逻辑 | | `backend/api/schemas.py` | `POILookupItem` 新增 `tw_start`/`tw_end` 字段 | 返回前端展示 | | `backend/data/amap_loader.py` | `get_poi_details` 调用 `parse_biz_hours()` | LLM 解析,旧 `_parse_opentime_to_tw` 代码残留但已不被调用 | | `frontend/src/pages/HomePage.vue` | `confirmPoi()` 不再硬编码 `(480, 1020)` | 使用后端返回的营业时间 |