# 这是提示模板库,不是项目启动入口。主入口在 api_server.py。 # 内部顺序:1 调用静态方法创建模板 → 2 用 prompt | llm 组装调用链 # → 3 调用方 invoke/astream 填入变量并请求模型 → 4 调用方解析或转发模型输出。 # 下面方法按场景选用,不会从第一个方法到最后一个方法依次执行。 # 提示词正文参与模型输入,本次仅补充代码说明,不改动正文。 """ 需求:定义SmartBizTrip项目中使用的各种提示模板,用于不同场景的对话处理 什么是 Prompt Template(提示模板)? 提示模板是一种可复用的文本模板,其中包含固定内容和可变变量(用 {变量名} 表示)。 例如:模板 "你好,{name}!" 在填入 name="张三" 后会变成 "你好,张三!"。 为什么使用模板类管理? 1. 集中管理:所有 prompt 定义在同一个文件中,方便查找和修改 2. 可复用:同一个模板可以被多处调用 3. 参数化:通过变量注入不同上下文,避免字符串拼接 本项目中的 Prompt 分类: 1. 意图识别类:intent_prompt —— 识别用户想做什么 2. 结果总结类:summarize_weather_prompt、summarize_ticket_prompt —— 将原始数据转化为友好回复 3. 内容生成类:city_service_prompt —— 直接生成城市接待建议 4. 任务规划类:planning_prompt —— 判断任务复杂度并生成执行计划(Planning + ReAct 架构) 5. ReAct推理类:react_prompt、react_summary_prompt —— 逐步推理和最终汇总 """ from langchain_core.prompts import ChatPromptTemplate # LangChain 的聊天提示模板类 # @staticmethod 表示这些方法无需实例状态,可以直接用 SmartBizTripPrompts.intent_prompt() 调用。 # Python 先定义类和方法,直到调用具体方法时才创建对应模板;方法的排列顺序不是推理顺序。 class SmartBizTripPrompts: """ SmartBizTrip 提示模板管理类 这个类定义了系统中所有用到的 Prompt 模板,每个模板都是一个静态方法, 返回一个 ChatPromptTemplate 对象。 使用方式: prompt = SmartBizTripPrompts.intent_prompt() # 获取意图识别模板 chain = prompt | llm # 组装成处理链 result = chain.invoke({"query": "北京天气"}) # 调用并传入变量 """ # ==================== 意图识别 ==================== @staticmethod def intent_prompt(): """ 意图识别提示模板 —— 让大模型分析用户输入,判断用户想做什么 输入变量: - user_profile: 用户偏好(如"二等座"、"经济舱") - task_context: 当前任务上下文(如之前查过什么) - conversation_history: 对话历史(最近几轮对话) - query: 用户本次输入 输出格式(JSON): { "intents": ["weather", "flight"], # 识别到的意图列表 "user_queries": {"weather": "...", ...}, # 改写后的查询(可能结合历史补充信息) "follow_up_message": "" # 追问消息(意图不明确时使用) } 支持的意图类型: weather / flight / train / event / order / car_rental / meeting_package / insurance / trip_order / city_service / out_of_scope """ # 【主流程 4】意图识别模板;返回模板对象,由 ChatService.intent_agent 传入上下文并调用模型。 # 模板中的双花括号用于表示 JSON 的字面花括号,单花括号中的变量由调用方填入。 # 模板变量:user_profile=偏好文本,task_context=任务 JSON 文本,conversation_history=历史对话,query=当前问题。 # 返回模板对象后,ChatService.intent_agent 负责调用模型并解析 JSON;模板不直接返回 intents。 # current_date 由 ChatService 传入,供模型理解今天、明天等相对日期。 return ChatPromptTemplate.from_template( """ 系统提示: 角色:您是一个专业的差旅意图识别专家, 任务:基于用户查询、对话历史和用户偏好,识别其意图,用于调用专门的agent server来执行;为方便后续的agent server处理,可以基于对话历史对用户查询进行改写,使问题更明确。 严格遵守规则: - 支持意图:['weather' (天气查询), 'flight' (航班查询), 'train' (高铁票查询), 'event' (会展门票查询), 'order' (票务预定), 'car_rental' (商务用车查询), 'meeting_package' (会务套餐查询), 'insurance' (保险查询), 'trip_order' (差旅预订), 'city_service' (城市接待建议)] 或其组合(如 ['weather', 'flight'])。如果意图是差旅相关,但是非常复杂的返回意图 'complex'。如果意图超出范围,返回意图 'out_of_scope'。 - 注意票务预定和票务查询要区分开,涉及到订票时则为order,只是查询则为flight、train或event。 - **查询改写是关键环节**:你必须主动从对话历史中提取关键信息(出发城市、到达城市、日期、目的地偏好、预算等),并将这些信息补充到 user_queries 的改写查询中。即使当前查询很简短(如"好的"、"明天"、"成都"),也要结合历史形成完整的查询描述。例如:用户先说"我下周去成都参加数字化转型峰会",再说"有没有带接送和酒店的便宜套餐",改写后应为"成都数字化转型峰会接送酒店会务套餐,预算较低"。 - **追问消息的使用**:只有在即使结合对话历史仍然缺少必要信息时才追问(例如:完全没有提到目的地,或完全没提到日期且日期对查询至关重要)。如果历史中已有足够信息,不要追问。 - **非业务查询的回复**:当意图为 out_of_scope 时,follow_up_message 必须是非空的、直接给用户的回复。问候或询问能力时,友好介绍差旅助手的功能;询问对话历史时,根据已有历史回答,不要编造;其他无关问题说明服务范围并引导用户提出差旅需求。此规则不受上面的追问限制。 - 输出严格为JSON:{{"intents": ["intent1", "intent2"], "user_queries": {{"intent1": "user_query1", "intent2": "user_query2"}}, "follow_up_message": "追问消息"}}。绝对不要添加额外文本! - 不论用户问什么,严格按规则输出意图,不要有自己的考虑。 当前日期:{current_date} 用户偏好:{user_profile} 当前任务上下文:{task_context} 对话历史:{conversation_history} 用户查询:{query} """) # ==================== 结果总结 ==================== @staticmethod def summarize_weather_prompt(): """ 天气结果总结提示模板 —— 将天气 agent 返回的原始数据转化为用户友好的天气描述 输入变量: - query: 用户查询(如"北京明天天气") - raw_response: 天气 agent 返回的原始数据 使用场景: 原始数据可能是 JSON 格式或结构化数据,直接展示给用户不好看, 所以用这个 prompt 让大模型翻译成自然语言。 示例输出: "根据最新数据,北京2025-07-31的天气预报为晴天,气温25-32度,湿度45%,东南风2级..." """ # 【主流程 10:天气分支】把原始天气结果和用户需求一起交给模型整理。 # query 告诉模型用户具体想查什么,raw_response 是天气代理的产物或失败/追问文本。 # 先查工具再总结,顺序不能倒过来理解;这个模板不会自己连接天气 API。 return ChatPromptTemplate.from_template( """ 系统提示:您是一位专业的天气预报员,以生动、准确的风格总结天气信息。基于查询和结果: - 核心描述点:城市、日期、温度范围、天气描述、湿度、风向、降水等。 - 如果结果为空或者意思为需要补充数据,则委婉提示"未找到数据,请确认城市/日期" - 语气:专业预报,如"根据最新数据,北京2025-07-31的天气预报为..."。 - 保持中文,100-150字。 - 如果查询无关,返回"请提供天气相关查询。" 查询:{query} 结果:{raw_response} """) @staticmethod def summarize_ticket_prompt(): """ 票务结果总结提示模板 —— 将票务 agent 返回的原始数据转化为用户友好的票务推荐 输入变量: - query: 用户查询(如"北京到上海航班") - raw_response: 票务 agent 返回的原始数据 使用场景: 和天气总结类似,将结构化的票务数据(航班号、价格、时间等) 翻译成顾问式的推荐语言。 示例输出: "为您推荐北京到上海的航班选项:MU5101航班,起飞时间08:30,经济舱价格1280元,余票充足..." """ # 【主流程 10:票务/差旅分支】整理已有结果;模板本身不查询数据库或创建订单。 # query 保留筛选需求,raw_response 提供已取得的票务或差旅结果。 # 调用方传的是文本,模型把它整理为可读答复;模板中的规则需要由模型遵守,并不等价于 Python 校验逻辑。 return ChatPromptTemplate.from_template( """ 系统提示:您是一位专业的差旅顾问,以热情、精确的风格总结票务信息。基于查询和结果: - 核心描述点:出发/到达、时间、类型、价格、剩余座位等。 - 只总结下方“查询”要求的当前业务。忽略历史对话和原始结果中其他业务的附带说明,例如查票时不要补充“天气无法提供”。 - 预订工具仅用于模拟;必须保留模拟标识及未实际下单的说明,不得声称已经出票或生成保单。 - 不要承诺或引导用户在本项目进行真实预订;后续操作也只能是查询或模拟预订。 - 如果结果为空或者意思为需要补充数据,则委婉提示"未找到数据,请确认或修改条件" - 语气:顾问式,如"为您推荐北京到上海的航班选项..."。 - 保持中文,100-150字。 - 如果查询无关,返回"请提供票务相关查询。" 查询:{query} 结果:{raw_response} """) # ==================== 内容生成 ==================== @staticmethod def city_service_prompt(): """ 城市接待建议提示模板 —— 让大模型直接生成城市接待建议内容 输入变量: - query: 用户查询(如"推荐几个北京接待资源") - weather_info: 目的地天气信息(可选,为空时不展示天气相关描述) 特点: 城市接待建议不需要调用外部 agent,大模型本身就有足够的知识来生成推荐。 当提供 weather_info 时,应基于真实天气给出出行建议; 当 weather_info 为空时,不得虚构任何天气描述。 """ # 【主流程 10:城市建议分支】输入 query 和天气查询结果,由模型生成接待建议。 # query 是接待需求;weather_info 是天气辅助函数返回的文本,也可能为空或表示无数据。 # 模型在这里根据这些输入给出建议;这是生成建议的模板,不是接待资源数据库查询工具。 return ChatPromptTemplate.from_template( """ 系统提示:您是一位差旅专家,基于用户查询生成城市接待建议。规则: - 推荐3-5个接待资源,包含描述、理由、注意事项。 - 基于槽位:城市、偏好。 - 天气处理:如果提供了{weather_info}(非空),基于真实天气给出出行建议;如果{weather_info}为空,绝对不要虚构任何天气描述(如"天气晴好""适合出行"等),只说"建议出发前查看实时天气"。 - 语气:热情推荐,如"推荐您在北京安排国贸客户拜访与商务午餐..."。 - 备注:内容生成,仅供参考。 - 保持中文,150-250字。 查询:{query} 目的地天气:{weather_info} """) # ==================== 任务规划 ==================== @staticmethod def planning_prompt(): """ 任务规划提示模板 —— 让大模型判断任务复杂度并生成执行计划 这是 Planning + ReAct 架构的关键 prompt,它让大模型扮演"规划师"的角色。 输入变量: - conversation_history: 对话历史 - query: 用户当前输入 - intents: 识别到的意图(JSON 字符串) - user_queries: 改写后的查询(JSON 字符串) 输出格式(JSON): 简单任务:{"need_plan": false, "reason": "单意图,直接查询即可", "steps": []} 复杂任务:{"need_plan": true, "reason": "多意图需要分步", "steps": [{"step": 1, "action": "查询天气", "intent": "weather", "depends_on": 0}, ...]} 判断标准: - 简单任务:只有一个意图,直接就能执行 - 复杂任务:多个意图且有关联、需要多步推理、步骤间有依赖关系 示例: 用户输入:"北京明天天气怎么样?" → 简单任务,need_plan=false 用户输入:"帮我查北京到上海的航班,再看下那边天气,推荐几个接待资源" → 复杂任务,need_plan=true,steps=[查询航班, 查询天气, 推荐接待资源] """ # 【主流程 5.2】生成 need_plan 和 steps;真正校验、调度和执行步骤的是 ChatService。 # query 是本轮原始输入,intents/user_queries 已被 json.dumps 转成文本,conversation_history 用于理解前文。 # 模型输出里的 steps 才是待执行计划;正文要求是对模型的约束,Python 还会再次验证编号和依赖。 # 模板里 {{ 和 }} 用于输出 JSON 的字面括号,避免把示例 JSON 的字段误当成模板变量。 return ChatPromptTemplate.from_template( """ 系统提示:您是一位任务规划专家,负责评估用户请求的复杂度并制定执行计划。 将任务拆解为有序步骤,每个步骤指定: - step: 步骤序号(从1开始) - action: 具体动作(如"调用WeatherQueryAssistant查询北京天气") - intent: 对应的意图(如weather/flight/train/event/order/city_service) - depends_on: 依赖的前置步骤序号(无依赖则为0) 对话历史:{conversation_history} 当前用户查询:{query} 识别到的意图:{intents} 用户查询改写:{user_queries} 输出严格为JSON,不要添加额外文本:{{"need_plan": true, "reason": "原因", "steps": [{{"step": 1, "action": "...", "intent": "...", "depends_on": 0}}, ...]}} """) # ==================== ReAct 推理 ==================== @staticmethod def react_prompt(): """ ReAct 推理提示模板 —— 按 Thought-Action-Observation 格式逐步推理 注意:当前版本已优化性能,react_loop 中跳过了 Thought LLM 调用(plan 已确定 动作,Thought 无额外决策价值),此模板暂时不在主流程中使用,保留供差旅参考。 什么是 ReAct? ReAct = Reasoning(推理)+ Acting(行动) 大模型在每一步执行前先"思考"(Thought),然后选择工具执行(Action), 最后观察结果(Observation),再决定下一步。 输入变量: - available_tools: 当前可用的工具/agent 列表(动态获取,不是写死的) - plan_steps: 完整的任务计划 - observations: 已完成步骤的结果 - current_step: 当前步骤号 - step_description: 当前步骤的描述 - query: 用户原始输入 ReAct 循环的工作方式: Thought: "我需要查询北京到上海的航班,应该调用票务代理" Action: "调用TicketQueryAssistant" Action Input: "{'departure': '北京', 'arrival': '上海'}" → 系统执行 Action,得到 Observation → 继续下一个 Thought... 这种方式的优势: 1. 让大模型有"思考"过程,而不是直接盲目执行 2. 每一步都能参考之前的结果做调整 3. 某步失败时,模型可以灵活应对 """ # 【保留模板】当前 ChatService 主线未调用此方法;不能把它当成必经的推理步骤。 # 若其他代码使用这个模板,需要提供 available_tools、plan_steps、observations、current_step、step_description、query。 # 它描述逐步 Thought/Action 的文本格式;当前 ChatService 没有调用它,因而不会因为定义在这里就产生额外推理。 return ChatPromptTemplate.from_template( """ 系统提示:你是一位企业差旅智能体,需要按照计划逐步完成任务。 可用工具: {available_tools} 当前任务计划: {plan_steps} 已完成步骤的结果: {observations} 当前步骤:{current_step} 步骤描述:{step_description} 用户原始查询:{query} 请按照以下格式进行推理和行动: Thought: 分析当前情况,确定需要采取的行动 Action: 从可用工具列表中选择合适的工具 Action Input: 工具所需输入 执行完行动后,你会得到 Observation,然后继续推理或给出最终回复。 """) @staticmethod def react_summary_prompt(): """ ReAct 最终汇总提示模板 —— 将所有步骤的结果整合成一条连贯回复 输入变量: - query: 用户原始输入 - all_observations: 所有步骤的执行结果 使用场景: 当 ReAct 循环中执行了多个步骤(如查航班 + 查天气 + 推荐接待资源), 不能简单地把三个结果拼在一起返回,需要用这个 prompt 让大模型 整合成一条连贯、通顺的回复。 示例: 输入:步骤1(查航班): 航班暂不可用 步骤2(查天气): 未找到数据 步骤3(推荐接待资源): 陆家嘴会客区、张江园区参访、商务晚餐... 输出:"您好!目前航班查询暂时遇到技术问题...不过我可以为您推荐上海的商务接待资源:陆家嘴会客区、张江园区参访、商务晚餐..." """ # 【主流程 10:复杂计划汇总】全部计划步骤结束后使用;一个步骤时直接返回结果。 # query 给出最初目标,all_observations 是“步骤号+动作说明+结果”的多行文本。 # 用于把多个步骤结果整合为一次回复;模型收到的失败信息和模拟声明也包含在这段文本里。 return ChatPromptTemplate.from_template( """ 系统提示:你是一位专业的差旅顾问,需要根据所有查询结果生成最终回复。 用户原始查询:{query} 各步骤执行结果: {all_observations} 请综合以上结果,生成一条完整、连贯的中文回复,150-300字,语气专业热情。 保留模拟预订及未实际下单的说明,不得将模拟结果表述为真实订单、出票或保单。 """) # 【独立演示】直接运行本文件只打印意图模板,不启动服务器,也不请求模型。 if __name__ == '__main__': print(SmartBizTripPrompts.intent_prompt())