从单轮到多轮:AI提示词编排实战

从单轮到多轮:AI提示词编排实战 1. 引言在 AI 应用开发中提示词Prompt早已不只是“问一句、答一句”的简单输入。随着大语言模型能力的提升如何通过精心设计的提示词来编排复杂的任务流程已成为构建高效 AI 工作流的关键。本文将带你从最基础的单轮对话出发逐步深入到多轮对话工作流的构建揭示提示词工程在其中的核心作用。文章摘要从一句提示词到一套智能工作流提示词工程如何驾驭LLM完成复杂任务本文以状态管理为线索系统梳理从单轮对话到多轮AI 工作流的演进路径。通过结构化提示词模板、对话记忆机制与意图路由等实战技巧手把手教你构建可维护的多轮问答系统。适合对话系统、智能客服与自动化编排场景的开发者阅读。2. 单轮对话一切的基础单轮对话是 AI 交互的最小单元用户输入一条指令模型返回一次回答。看似简单但一个高质量的单轮交互背后往往需要结构化的提示词设计。2.1 结构化提示词模板一个典型的单轮提示词通常包含以下要素角色设定定义 AI 的身份如“你是一位资深 Python 开发者”。任务描述明确要完成的具体任务如“请为以下函数编写单元测试”。输入数据提供待处理的内容。输出格式指定返回结果的格式如 JSON、Markdown 表格。约束条件限制回答的长度、风格或禁止事项。# 角色 你是一位资深 Python 开发者。 # 任务 为以下函数编写单元测试覆盖正常输入和边界情况。 # 输入函数 def divide(a, b): return a / b # 输出格式 请用 pytest 风格返回完整的测试代码。 # 约束 - 不要使用第三方 mock 库。 - 每个测试用例用 def test_xxx(): 命名。2.2 单轮对话的局限性单轮对话虽然简单直接但在复杂任务中暴露出明显不足上下文有限无法利用历史对话中的信息。无法纠错一次回答出错需要用户重新组织整个问题。缺乏状态无法记住用户偏好或中间结果。这些局限性催生了多轮对话工作流的需求。下面从多个维度对比单轮对话与多轮对话工作流的差异对比维度单轮对话工作流多轮对话工作流上下文能力每次请求独立无法利用历史信息维护对话状态可引用历史上下文状态管理无状态每次从零开始有状态通过状态对象记录进度与已收集信息错误处理出错需用户重新组织完整问题可在后续轮次中追问、纠正或重试适用场景简单问答、一次性翻译、单步工具调用信息收集、多步流程、客服对话、复杂任务编排实现复杂度低只需单次提示词模板较高需设计状态机、记忆模块与分支逻辑用户体验简洁但缺乏连贯性连贯自然能逐步引导用户完成复杂流程3. 多轮对话状态与记忆的引入多轮对话的核心在于状态管理和上下文记忆。AI 需要记住之前说过的话并根据当前状态决定下一步行动。3.1 对话状态的设计在多轮工作流中我们通常用一个结构化的“状态对象”来记录对话进展classConversationState:def__init__(self):self.history[]# 对话历史self.current_step0# 当前步骤self.collected_info{}# 已收集的信息self.pending_questions[]# 待追问的问题每次模型回答后后端解析回答并更新状态再根据状态决定下一轮提示词的内容。3.2 多轮提示词模板示例以下是一个“信息收集型”多轮工作流的提示词模板# 系统角色 你是一位友好的客服助手负责收集用户的订单问题。 # 当前对话状态 - 已收集信息{collected_info} - 当前步骤{current_step} - 待确认项{pending_items} # 对话历史最近3轮 {recent_history} # 指令 请根据当前状态向用户提出下一个问题或确认已收集的信息。 如果所有信息已收集完毕请总结并告知用户。通过动态填充{collected_info}、{current_step}等变量模型就能“记住”当前进度并做出符合流程的回应。4. 实战构建一个多轮问答工作流下面我们用一个具体的例子——智能客服工单系统来演示如何用提示词构建多轮工作流。4.1 工作流定义技术问题账单问题用户发起咨询收集问题类型收集系统版本收集订单号收集错误日志确认账单周期生成工单并回复4.2 核心代码实现importjsonfromopenaiimportOpenAI clientOpenAI()defbuild_prompt(state):根据当前状态构建提示词# 构建系统提示词将当前对话状态序列化为结构化指令system_promptf 你是一个智能客服助手。请根据当前对话状态向用户提出下一个问题。 当前状态 - 问题类型{state.get(issue_type,未确定)}- 已收集信息{json.dumps(state.get(collected, {}), ensure_asciiFalse)} - 当前步骤{state[step]}对话历史{format_history(state[history])}请用中文回复每次只问一个问题。 returnsystem_promptdefrun_workflow():# 初始化对话状态定义步骤流转、问题类型、已收集信息和历史记录state{step:ask_type,# 当前对话阶段控制流程走向issue_type:None,# 用户问题类型用于分支路由collected:{},# 已收集的关键信息逐步累积history:[]# 完整对话历史供提示词构建上下文}# 循环控制只要未到达done状态就持续进行多轮对话whilestate[step]!done:# 根据当前状态动态构建提示词将状态信息注入 LLM 上下文promptbuild_prompt(state)# 调用大模型生成回复responseclient.chat.completions.create(modelgpt-4,messages[{role:system,content:prompt}])replyresponse.choices[0].message.contentprint(fAI:{reply})# 获取用户输入并追加到历史记录维持对话记忆user_inputinput(用户: )state[history].append({role:user,content:user_input})# 解析用户输入并更新状态简化版# 根据当前步骤匹配用户意图驱动状态机向下一个阶段流转ifstate[step]ask_type:# 根据用户回复中的关键词判断问题类型决定下一步分支if技术inuser_input:state[issue_type]技术state[step]ask_version# 切换到版本询问阶段elif账单inuser_input:state[issue_type]账单state[step]ask_order# 切换到订单询问阶段elifstate[step]ask_version:# 收集版本信息后推进到日志收集阶段state[collected][version]user_input state[step]ask_logelifstate[step]ask_log:# 收集日志信息后标记对话完成循环条件将不满足而退出state[collected][log]user_input state[step]done# ... 其他步骤类似if__name____main__:run_workflow()4.3 运行效果示例AI: 您好请问您遇到的是技术问题还是账单问题 用户: 技术问题 AI: 好的请问您使用的系统版本是多少 用户: Windows 11 专业版 23H2 AI: 收到。请提供相关的错误日志或截图。 用户: 错误代码 0x80070005 AI: 感谢您提供的信息。我已为您生成工单工单编号 TK-2024-001预计24小时内会有工程师联系您。5. 进阶技巧提示词编排与分支逻辑在实际生产环境中多轮工作流往往需要更复杂的分支逻辑和条件跳转。5.1 基于意图的路由在每一轮对话中先让模型输出一个结构化的“意图标签”后端根据标签决定下一步请分析用户输入输出以下 JSON 格式 { intent: ask_question | provide_info | request_escalation | end_conversation, extracted_info: { ... }, next_step: step_name }5.2 错误恢复与重试当模型输出不符合预期时如 JSON 解析失败工作流应具备重试机制max_retries3forattemptinrange(max_retries):try:responsecall_llm(prompt)parsedjson.loads(response)breakexceptjson.JSONDecodeError:prompt\n【注意】请严格输出 JSON 格式不要包含其他文字。else:# 降级处理使用默认分支parsed{intent:ask_question,next_step:default}下面是一个更完整的实战示例包含状态回滚、重试提示词优化和用户引导逻辑importjsonfromtypingimportOptional,Dict,AnyclassRetryableWorkflow:带错误恢复与重试的多轮对话工作流def__init__(self,max_retries:int3):self.max_retriesmax_retries self.state{history:[],last_valid_state:None}def_build_retry_prompt(self,original_prompt:str,error_detail:str,attempt:int)-str:根据重试次数动态构建提示词base_instruction(你是一个严格输出 JSON 的助手。请只输出一个 JSON 对象不要包含任何 Markdown 标记、代码块围栏或额外说明文字。)ifattempt1:# 第一次重试温和提醒returnf{original_prompt}\n\n【提示】{base_instruction}elifattempt2:# 第二次重试给出明确格式要求return(f{original_prompt}\n\nf【重要】上次输出格式错误{error_detail}。\nf请严格按照以下格式输出不要添加任何其他内容\nf{{intent: 意图名称, params: {{}}, next_step: 下一步}})else:# 最后一次重试使用 few-shot 示例return(f{original_prompt}\n\nf【最后一次尝试】请参考以下示例输出\nf正确示例{{intent: ask_question, params: {{question: 你好}}, next_step: respond}}\nf正确示例{{intent: search_knowledge, params: {{keyword: Python}}, next_step: search}}\nf请只输出一个 JSON 对象)def_rollback_state(self)-None:回滚到上一个有效状态ifself.state[last_valid_state]isnotNone:self.state[history]self.state[last_valid_state][history]print([状态回滚] 已恢复到上一个有效对话状态)else:print([状态回滚] 无有效历史状态保持当前状态)def_handle_fallback(self,user_input:str)-Dict[str,Any]:优雅降级当所有重试都失败时使用规则解析print([降级处理] 模型输出持续异常切换到规则解析模式)# 简单的规则匹配作为兜底ifany(kwinuser_inputforkwin[你好,嗨,hello]):return{intent:greeting,params:{},next_step:respond}elifuser_input.endswith(?):return{intent:ask_question,params:{question:user_input},next_step:respond}else:return{intent:unknown,params:{raw_input:user_input},next_step:clarify}def_guide_user_retry(self,attempt:int)-str:生成引导用户重新输入的提示guides[请重新描述您的问题我会更仔细地处理。,您可以换一种方式表达或者直接说“帮助”查看可用功能。,看起来遇到了解析问题请用简单的句子重新描述您的需求。]returnguides[min(attempt-1,len(guides)-1)]defprocess_message(self,user_input:str)-Dict[str,Any]:处理用户消息带重试与降级promptself._build_base_prompt(user_input)forattemptinrange(1,self.max_retries1):try:responsecall_llm(prompt)parsedjson.loads(response)# 校验必要字段ifintentnotinparsedornext_stepnotinparsed:raiseValueError(缺少必要字段)# 成功保存当前状态作为有效状态快照self.state[last_valid_state]{history:self.state[history].copy()}self.state[history].append({role:assistant,parsed:parsed})returnparsedexcept(json.JSONDecodeError,ValueError)ase:error_detailstr(e)print(f[重试{attempt}/{self.max_retries}] 解析失败:{error_detail})ifattemptself.max_retries:# 更新提示词并引导用户重新输入promptself._build_retry_prompt(prompt,error_detail,attempt)user_guideself._guide_user_retry(attempt)print(f[引导用户]{user_guide})else:# 所有重试耗尽回滚状态 降级处理self._rollback_state()fallback_resultself._handle_fallback(user_input)self.state[history].append({role:assistant,parsed:fallback_result,fallback:True})returnfallback_resultdef_build_base_prompt(self,user_input:str)-str:构建基础提示词示例return(f对话历史{json.dumps(self.state[history],ensure_asciiFalse)}\nf用户输入{user_input}\n请分析用户意图并输出 JSON。)# 使用示例defcall_llm(prompt:str)-str:模拟 LLM 调用可能返回非法 JSONimportrandom# 模拟前两次返回非法 JSON第三次成功ifrandom.random()0.6:return好的我来回答你的问题。# 非 JSON 输出return{intent: ask_question, params: {question: 示例}, next_step: respond}# 运行演示workflowRetryableWorkflow(max_retries3)resultworkflow.process_message(Python 怎么学)print(f最终解析结果:{result})这个示例的核心改进点动态重试提示词根据重试次数逐步增强约束温和提醒 → 格式要求 → few-shot 示例状态回滚_rollback_state()在重试耗尽后恢复到上一个有效对话状态避免污染后续对话用户引导_guide_user_retry()在每次重试时给出不同的引导文案提升用户体验优雅降级_handle_fallback()使用规则匹配作为兜底方案确保系统不崩溃字段校验不仅检查 JSON 合法性还校验必要字段是否存在6. 总结与展望从单轮到多轮对话提示词工程的核心演进路径是从静态到动态提示词不再是固定文本而是根据状态实时组装。从无状态到有状态引入对话状态对象让 AI 拥有“短期记忆”。从线性到分支通过意图识别和条件跳转实现复杂业务流程。未来随着 Agent 框架和工具调用能力的成熟提示词工作流将进一步与外部 API、数据库、代码执行引擎深度融合构建出真正自主决策的 AI 系统。希望本文能帮助你理解提示词在构建 AI 工作流中的关键作用并动手实践自己的多轮对话应用。