Appearance
22. 规划器模块:将旅行目标分解为任务
如果说整个智能旅行助手是一个宏大的建筑工程,那么规划器(Planner)就是项目的总设计师。它的核心职责,是将客户(用户)一个天马行空的想法,绘制成一张精确、严谨、所有后续工种都能看懂的建筑蓝图。
在本章中,我们将深入探讨如何设计规划器的提示词,这可能是整个项目中最为关键和最具挑战性的一环。因为,蓝图的质量,直接决定了最终建筑的高度。
规划器的角色:从需求到蓝图的翻译官
- 定位:首席行程设计师,整个工作流的起点。
- 输入:一段来自用户的、模糊的自然语言需求。例如:“下个月我想去巴黎和罗马,玩10天,预算2万,对艺术和美食感兴趣。”
- 核心任务:将这个需求,翻译并结构化成一份详细的旅行规划大纲(TOC - Table of Contents)。
- 输出:一个严格定义的 JSON 对象。这份 JSON 就是我们后续所有模块(执行器、综合器)赖以生存的“API 契约”。
让我们通过一个鲜明的“输入 vs 输出”对比,来直观感受规划器的价值:
输入 (Input):
text
下个月我想去巴黎和罗马,玩10天,预算2万,对艺术和美食感兴趣。输出 (Output - 结构化蓝图):
json
{
"title": "巴黎与罗马艺术美食10日探索之旅",
"brief": "一份为期10天,预算2万元人民币,专注于艺术与美食的深度旅行计划。",
"duration_days": 10,
"budget_cny": 20000,
"cities": ["巴黎", "罗马"],
"themes": ["艺术", "美食"],
"daily_plan": [
{
"day": 1,
"city": "巴黎",
"theme": "抵达与艺术初探",
"tasks": [
{"task_id": "day1-flight-search", "type": "flight", "description": "查询并推荐抵达巴黎戴高乐机场的航班"},
{"task_id": "day1-hotel-search", "type": "hotel", "description": "在卢浮宫附近寻找艺术主题酒店"},
{"task_id": "day1-activity-plan", "type": "activity", "description": "规划下午参观卢浮宫的行程"},
{"task_id": "day1-dinner-plan", "type": "restaurant", "description": "推荐一家经典的法式餐厅"}
]
},
{
"day": 2,
"city": "巴黎",
"theme": "蒙马特高地与现代艺术",
"tasks": [
// ... 其他天的任务
]
}
// ... 直到 day 10
]
}看到了吗?规划器将一段话,变成了一个结构清晰、信息完整、机器可读的 JSON 对象。这,就是提示词工程的力量。
规划器提示词的完整解构
要让 LLM 稳定地输出我们期望的 JSON 格式,核心在于“引导”而非“命令”。下面,我们将通过 P.I.C.A. 模型,完整解构这个规划器的提示词。
你是一位世界顶级的旅行规划师和信息架构师。
你的任务是根据用户提供的模糊需求,创建一个逻辑严谨、内容丰富、结构化的旅行计划蓝图。
请严格遵循以下步骤:
1. **深度分析 (Analyze)**:提取用户需求中的关键信息,包括目的地、时长、预算、兴趣主题等。如果信息不足,请根据常识进行合理补充。
2. **行程构建 (Structure)**:将整个旅行分解到每一天,为每一天设定一个主题,并规划出当天需要执行的核心任务(Tasks),例如查询航班、寻找酒店、规划景点、推荐餐厅等。
3. **任务定义 (Define)**:为每一个任务(Task)分配一个唯一的 `task_id` 和明确的 `type`(例如:'flight', 'hotel', 'activity', 'restaurant', 'transport')。
请将你的思考过程放在 `<thinking>` 标签内,这有助于你梳理思路,并让我了解你的决策过程。
最终,请将生成的旅行计划蓝图以一个完整的 JSON 对象形式,放在 `<json>` 标签内。
**约束条件 (Constraints):**
- 最终输出必须是一个可以被解析的、完整的 JSON 对象。
- JSON 对象的根结构必须包含 `title`, `brief`, `duration_days`, `budget_cny`, `cities`, `themes`, `daily_plan` 字段。
- `daily_plan` 是一个数组,其中每个元素代表一天,必须包含 `day`, `city`, `theme`, `tasks` 字段。
- `tasks` 是一个数组,其中每个元素代表一个任务,必须包含 `task_id`, `type`, `description` 字段。
**用户需求如下:**
---
{{USER_REQUEST}}
---提示词设计解析
Persona (角色): “世界顶级的旅行规划师和信息架构师”。我们赋予它双重身份,既懂旅行的浪漫,又懂数据的严谨。
Instruction (指令): 这是提示词的核心。我们没有简单地说“给我一个计划”,而是:
- 分解步骤 (Step-by-Step):明确要求模型遵循“分析 -> 构建 -> 定义”三步走。这极大地稳定了模型的思考路径,避免它天马行空。
- 输出隔离 (Output Isolation):我们创造性地使用了
<thinking>和<json>这两个 XML 标签。这是一种强大的技术,它强制模型将思考过程和最终结果分离开。这样做的好处是:- 我们可以观察模型的思考过程,便于调试和优化提示词。
- 我们的代码可以轻松地、确定性地只提取
<json>标签内的内容,而不用担心被模型的其他“噪音”(如“好的,这是您要的JSON...”)所污染。
Context (情境):
部分,这里会填入用户最原始的输入。Action (输出规范): 整个提示词的结构,特别是最后的 JSON 结构定义和标签要求,共同构成了清晰的输出规范,引导模型生成我们期望的结构化输出。
输出即契约:JSON 作为模块间的通信语言
规划器输出的这份 JSON,并不仅仅是一份大纲,它更是规划器与下游“执行器”(Executor)模块之间神圣的“API 契约”。
在下一章,执行器会读取这份 JSON,遍历 daily_plan 中的每一个 task,并根据其 type 和 description 去调用相应的工具(如航班查询 API、酒店搜索工具等)。
这种“接口先行”的设计思想,是复杂 AI 系统工程化的基石。它确保了多智能体系统可以像乐高积木一样,被清晰地拆分和组合,每个模块只需关心自己的输入和输出是否符合“契约”规定即可。
如果规划器输出的 JSON 格式不稳定,整个流水线就会崩溃。因此,一个健壮的规划器提示词,会包含详细的错误处理和重试机制,例如,如果解析 JSON 失败,就带着错误信息让模型重新生成一次。
现在,我们已经为整个项目设计好了蓝图。接下来,让我们进入下一章,看看“执行器”这位“全能信息搜集员”是如何根据这份蓝图,为我们获取真实世界的数据的。