| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353 |
- # 这是提示模板库,不是项目启动入口。主入口在 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())
|