左侧手机界面(接受 / 换一个 / 看详情 / 多轮对话 / 一键执行)+ 右侧 Agent 实时思考链路双栏视图。完整 Tool 实现代码(含 Mock API)见 jxtse/buyu-meituan。
步语 BuYu 面向「周末半天不知道去哪儿」这一高频本地生活场景,把一句含糊需求转化为一条可确认、可解释、可执行的本地生活方案。系统设计的核心不是生成推荐文案,而是把 LLM 放在规划中枢:在真实商户候选、实时可用性与用户反馈之间持续权衡,并把推荐、确认与执行连成闭环。本文聚焦比赛要求的三件事:Planning 策略、工具调用链路、异常处理机制;并补充记忆与技能内化的设计依据。
规划不是一次性吐出整张行程,而是 LLM 作为 tools orchestrator,在 ReAct 循环(Reason → Act → Observe)里分段、软固定、渐进式确认地推进。每一段都是一轮「Reason(结合已知 memory 想清楚这段要什么)→ Act(按需调用地图定位、地点检索、详情、团购、评论、种草帖、查位等工具)→ Observe(读结果、必要时改主意)」。接受、换选、追问、查位和下单都被视作同一条规划链上的状态变化;每一次用户反馈都会写入单会话上下文(Session memory),让下一段推荐继续沿着本次出行的真实意图收敛:
读取当前位置与商圈,作为后续距离计算的原点。
meituan_locate工具调用自然语言 → 结构化约束:场景 / 人群 / 饮食 / 时间窗 / 预算,写入 memory。
LLM · JSONAgent 推理软固定三段「玩→吃→额外」,按约束灵活增删;硬上限 3 段。
segment_planAgent 规划段内检索真实候选 → 结合 memory 权衡 → 选 1 个生成可执行卡片。
dianping_searchReAct 一轮逐站调用下单工具,命中异常当场自动调整。
execute_booking工具调用所有外部能力收敛为一组统一签名的工具(name / description / parameters / invoke()),LLM 作为 tools orchestrator 在 ReAct 循环里按需调度——它读工具描述、自己决定何时调哪个、用上一步的 observation 决定下一步。覆盖地图 / 地点检索 / 地点详情 / 团购套餐 / 用户评论 / 大众点评种草帖 / 实时订位 / 下单全链路。右侧 Agent 链路由事件总线驱动;公网环境下,为避免 SSE 被代理缓冲,关键预设和用户点击动作会随接口响应返回 agent_events,由前端按时间线回放,保证链路与卡片生成同步。商户数据全部走 Mock 美团 / 点评 层,保证无真实交易、可复现、低延迟。
| 阶段 | 工具 | 角色 | 输入 → 输出 |
|---|---|---|---|
| 定位 | meituan_locate | 地图工具 | ∅ → 当前坐标 + 商圈,作为距离原点 |
| 理解 | intent_parse (LLM) | Agent 推理 | query → 结构化约束 JSON,写入 memory(失败则启发式兜底) |
| 检索 | dianping_search | 地点检索工具 | 段 + 场景 + 排除集 → 真实候选(按距离、评分排序,top-6) |
| 决策 | recommend (LLM) | Agent 决策 | 候选集 + memory → 选 1 个 id + 卡片话术(只在候选内选择,不编造地点) |
| 详情 | meituan_detail | 详情 / 团购 / 评论 / 种草帖 | poi_id → 种草帖 / 团购套餐 / 评论 + 同段可切换候选 |
| 查位 | meituan_query_queue | 实时订位工具 | poi_id + 人数 → 实时排队 / 有无可订桌位 |
| 执行 | meituan_buy_ticket / book_table / order_delivery | 下单工具 | 按段类型逐站下单 → 状态 + 订单号 / 确认号 |
规划与执行中遇到的落地障碍,目标是不中断流程、当场自动调整,并把每一次调整显式推给用户(自动调整事件,internal: self_heal),可见、可解释。机制贯穿规划期(风险前置)与执行期(逐站调整)两个阶段。
| 类型 | 触发条件 | 处理策略 | 发生阶段 |
|---|---|---|---|
| 模型降级 | 意图解析 / 对话的 LLM 调用异常或返回非法 JSON | 捕获异常 → 切换启发式规则兜底(关键词判场景/人数),流程继续不报错 | 规划期 |
| 无座 no_table | 下单前查位无可订桌 / 等待 ≥30min,或下单返回满座 | 出卡前预过滤降权高风险店;执行期则在同段候选自动改约,保留时间轴 | 规划 + 执行 |
| 无票 sold_out | 下单返回票 / 名额售罄 | 同段顺路候选自动替换重试,沿用已选时间,成功即写回行程 | 执行期 |
| 时间冲突 conflict | 同一时段已有预约 | 自动错峰 +15min 重排该站,避免撞车 | 执行期 |
| 无候选 | 某段在场景约束下检索为空 | 放宽场景再搜;仍为空则跳过该段,不阻塞整体方案 | 规划期 |
出卡前即调用查位工具,对「评分高但实时落地风险高」的餐厅主动降权, 优先把可订、等待短的候选放进卡片——避免把一个看起来不错、到店却坐不下的选项推给用户。 每一次降权都附带一段思考,解释「我原本会选 A,但实时队列显示它没桌,所以改 B」。
一键执行时逐站下单,命中无座 / 无票立即在同段合法候选里改约重试, 命中时间冲突自动错峰;每次调整推 自动调整(internal: self_heal → self_heal_ok)两段事件, 告诉用户「原选满座,已自动改为 X」。整条链路 Pass@1,不回退到「请稍后再试」。
步语 BuYu 的记忆分两层:会话记忆(运行中)让「这次出行越聊越懂」;参数化技能内化(演进方向)把跨场景复用的通用规划能力沉淀为模型自身的认知基础。两层的分工遵循一条原则——有规律、可复用的通用技能适合内化进参数;精确、易变的事实适合留在外部按需检索。
商户数据全 Mock、不接真实交易;API Key 仅存服务端环境变量,前端零暴露;在线服务经隧道从作者本机暴露,仅供评审试玩,比赛结束后一并下线。