ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

LLM生产级架构:Plan→Commit模式如何解决AI随机性问题

2026/8/5 11:07:08 拓冰建站 浏览量
LLM生产级架构:Plan→Commit模式如何解决AI随机性问题 1. 项目概述从“随机诗人”到“可靠工程师”的LLM改造在过去的两年里我深度参与了超过十个将大型语言模型LLM集成到实际生产系统的项目。从最初的惊艳到后来的“惊吓”一个核心痛点反复出现LLM的“随机性”或“创造性”在需要稳定输出的生产环境中常常是灾难的源头。你精心设计的提示词Prompt可能在99次调用中都完美工作但第100次模型却突然“放飞自我”给出了一个格式错误、内容离谱甚至包含敏感信息的回复。这种不确定性让LLM在严肃的业务流程中——比如自动生成合同条款、编写产品代码、生成数据分析报告——变得难以信赖。“Plan→Commit”架构正是为了解决这一核心矛盾而生。它不是一个具体的工具或框架而是一套工程思想与设计模式旨在通过结构化的流程将LLM从一个“才华横溢但行为不羁的诗人”改造为一个“严谨可靠、按章办事的工程师”。其核心在于将一次性的、黑盒式的文本生成拆解为两个明确的、可监控、可干预的阶段规划Plan与提交Commit。在规划阶段LLM的任务是“思考”和“提案”产出的是一个结构化的、可供审查的“计划草案”在提交阶段系统可能是另一轮LLM调用也可能是确定的业务逻辑则基于这个草案执行最终的、格式严格的“提交动作”。这套架构的价值对于使用侧产品、运营、业务方而言是获得了前所未有的可控性与可预测性业务规则得以严格贯彻。对于工程侧开发、算法、运维而言则是将不可控的AI行为纳入了标准的软件工程治理体系实现了可观测、可回滚、可测试。接下来我将结合大量实战中的成功与踩坑案例为你彻底拆解这套生产级架构的落地细节。2. 架构核心Plan与Commit的职责分离与协同为什么简单的“提示词优化”无法根治随机性问题因为单一的生成步骤其输入提示词上下文与输出最终结果之间的映射关系过于复杂和模糊。模型在生成最终答案的每一个token时都同时在处理“逻辑推理”、“内容创作”、“格式遵循”等多个任务任何一步的微小偏差都可能被放大。“Plan→Commit”架构的核心思想就是进行职责分离让LLM专注于它擅长的“思考”而将“执行”的确定性与规范性交给更可控的机制。2.1 Plan阶段让LLM成为“策略分析师”在Plan阶段我们的目标不是得到最终答案而是得到一份关于“如何得到最终答案”的蓝图。这个蓝图必须是结构化的。1. 结构化输出是生命线绝不能依赖自然语言描述的计划。你必须强制LLM以指定的结构化格式输出通常是JSON或YAML。例如一个为电商用户生成个性化邮件的内容生成任务其Plan输出应该是{ intent_analysis: { user_segment: 高价值复购客户, last_purchase_category: 户外装备, potential_interest: 新品徒步鞋 }, content_outline: { greeting: 提及上次购买, body: [新品功能介绍, 专属优惠提及, 使用场景营造], closing: 强化品牌关怀引导点击 }, tone_and_style: 专业且热情带有一对一专属感, key_constraints: [必须包含优惠码字段: {coupon_code}, 禁止使用‘史上最低’等违规词, 链接必须使用UTM跟踪参数] }这个JSON计划本身不包含任何具体的营销话术但它清晰地定义了方向、要素和边界。实现上你需要通过系统提示词System Prompt和强化的输出格式指令如使用JSON Schema描述或通过Few-shot示例来约束模型。实操心得在定义Plan的JSON Schema时我强烈建议增加一个confidence置信度字段和一个alternative_plans备选方案字段。LLM可以为自己的计划打分并可能提供1-2个备选思路。这为后续的人工审核或自动决策提供了宝贵的信息维度。我曾在一个客服工单分类项目中因为模型对某个复杂工单的分类置信度只有65%从而触发了人工复核流程避免了一次严重的错误路由。2. 提供充足的“思考脚手架”LLM在规划时需要上下文。除了用户问题User Query你更应该提供业务规则手册以清晰条文形式定义的不可违反的规则。参考范例几个高质量的计划案例Few-shot Learning。工具/API清单在计划中LLM可以声明它“想要调用”某个数据查询接口或计算工具尽管真正的调用发生在Commit阶段或由系统决定。这实现了“思考”与“行动”的分离。验证清单一份Plan阶段必须自我检查的问题列表例如“是否涵盖了所有用户输入的关键点”“是否违反了任何内容安全政策”。2.2 Commit阶段从“蓝图”到“竣工”Commit阶段是确定性生成的舞台。输入是结构化的Plan输出是符合最终要求的交付物。这里有多种实现模式模式一LLM作为执行者增强确定性这是最常见的模式。你使用另一个LLM调用可以是同一个模型也可以是更小、更快的专用模型其提示词的核心是“请严格且精确地依据以下计划生成最终输出。” 并将Plan作为输入的一部分。系统指令你是一名专业的电商邮件文案师。请严格遵循下方提供的【创作计划】来撰写邮件正文不得偏离计划中的任何要求也不得添加计划中未提及的内容。 用户输入创作计划如下 {plan_json} 请开始生成最终邮件。这种方式极大地压缩了LLM的“自由发挥”空间因为它不需要再思考策略只需要进行“填充”和“润色”其输出随机性显著降低。模式二模板引擎填充完全确定对于格式要求极高、内容模块化的场景如生成SQL、法律文书、固定格式报告Commit阶段可以完全不用LLM。系统可以内置一个模板引擎如Jinja2、Handlebars。Plan中的字段直接作为变量注入到预定义的模板中生成最终结果。// Plan 输出 { report_title: Q3销售数据分析, top_product: 产品A, growth_rate: 15.2%, key_findings: [华东市场增长领先, 线上渠道占比提升至60%] } // Jinja2 模板 # {{ report_title }} 本季度明星产品是 **{{ top_product }}**销售额同比增长 {{ growth_rate }}。 主要发现 {% for finding in key_findings %} * {{ finding }} {% endfor %} // 最终提交Commit结果 # Q3销售数据分析 本季度明星产品是 **产品A**销售额同比增长 15.2%。 主要发现 * 华东市场增长领先 * 线上渠道占比提升至60%这种方式实现了零随机性是生产环境中最可靠的方式但前提是Plan的输出足够结构化且模板能覆盖所有情况。模式三混合模式与业务逻辑集成在实际复杂系统中Commit阶段往往是一个微服务。它接收Plan然后可能调用模板引擎生成草稿。将草稿送入一个轻量级LLM进行语法润色和连贯性检查此时风险已很小。根据Plan中的指示调用外部API获取实时数据并填充。执行最终的业务规则校验如敏感词过滤、合规性检查后才将结果持久化或返回给用户。2.3 阶段间的控制流与裁决机制Plan和Commit并非总是简单的线性关系。一个健壮的生产架构需要处理异常和分支。1. 计划评审Plan Review在进入Commit之前可以对Plan进行自动或人工评审。自动评审编写规则检查Plan的完整性、是否符合Schema、是否触发了某些风险关键词如“自由发挥”、“忽略规则”。如果Plan不达标可以要求LLM重新规划或降级到更简单的流程。人工评审对于高风险任务如涉及金融、法律可以将Plan呈现给人类审核员。审核员可以批准、驳回或修改Plan。因为Plan是结构化的修改起来比修改一大段自然语言文本要容易得多。2. 重试与降级策略如果LLM生成的Plan无法通过校验系统不应直接崩溃。应有标准的重试流程例如将失败原因作为反馈附加到原提示词中让LLM重新生成Plan。重试超过N次后应触发降级策略例如转由更简单的规则引擎处理或直接转人工客服并向用户提示“系统正在优化”。3. 溯源与审计整个Plan→Commit流程的日志必须完整记录原始输入、生成的Plan、评审结果、Commit阶段的输入/输出、调用的外部服务等。这份日志是排查问题、优化提示词、进行模型效果评估的黄金数据。当最终结果出现问题时你可以快速定位是Plan阶段的方向错了还是Commit阶段的执行偏了。3. 工程化落地从设计到部署的全链路实践理解了核心思想后我们需要将其转化为可运行的代码和可维护的系统。这一部分将聚焦于工程侧的具体实现。3.1 系统组件设计与技术选型一个完整的Plan→Commit系统通常包含以下组件你可以根据团队技术栈进行选型组件职责可选技术方案选型考量编排引擎控制Plan→Commit工作流处理重试、降级、分支逻辑。-LangChain / LlamaIndex生态成熟抽象度高开发快。-自研状态机基于Celery、Airflow或 Temporal.io。-低代码平台如微软的Prompt Flow。项目初期或复杂度中等时LangChain能快速搭建原型。当流程非常复杂、定制性要求极高且对第三方依赖敏感时自研状态机是更优选择。我曾在一个金融风控场景中因LangChain的某些默认行为过于“智能”而不可控最终切换到了基于Temporal的自研引擎。提示词管理存储、版本化和管理Plan与Commit阶段的提示词模板。-专用服务如PromptHub Weights Biases Prompts。-配置文件YAML/JSON文件配合配置中心如Apollo, Consul。-数据库将提示词作为资产存入DB提供管理界面。绝对不要将提示词硬编码在代码里。必须实现热更新和A/B测试能力。一个最佳实践是为每个提示词附加元数据创建人、适用模型版本、效果指标如通过率、上次修改时间。模型网关统一对接不同的LLM API如OpenAI, Anthropic, 国内大模型实现负载均衡、熔断、限流、缓存。-自研网关基于FastAPI/Spring集成相关中间件。-云服务如Azure AI Studio 提供开箱即用的网关功能。这是保证系统稳定性的关键。必须实现请求缓存对相同Plan的请求返回缓存结果、失败重试针对网络抖动、以及模型降级当主用模型超时或故障时自动切换至备用模型。结构化输出解析强制LLM输出合规的JSON并处理其可能的不合规响应。-框架内置LangChain的PydanticOutputParser。-直接指导在提示词中明确要求JSON并在代码中使用json.loads()配合try-catch失败时进行文本修复或重试。即使要求输出JSONLLM有时也会在JSON前后添加解释性文字。你的解析器必须足够健壮能通过正则表达式等方式从响应文本中提取出合法的JSON片段。验证与裁决服务对Plan和Commit结果进行业务规则校验。-规则引擎如Drools 用于处理复杂的业务规则。-校验函数编写纯函数进行校验简单直接。-二次模型调用用一个小模型如GPT-3.5-Turbo专门做“评审员”检查输出是否合规。建议分层校验先做轻量的语法和Schema校验再做重量的业务规则校验。对于Plan的校验可以比Commit更严格因为Plan阶段失败的成本更低。3.2 核心流程的代码级实现示例让我们以一个“智能SQL生成”场景为例看看核心流程的伪代码实现。假设用户输入是“帮我查一下上个月销售额超过10万的城市有哪些按销售额排个序。”# 1. 定义Plan的数据结构 (使用Pydantic) from pydantic import BaseModel, Field from typing import List, Optional class SQLGenerationPlan(BaseModel): analysis_of_intent: str Field(description对用户查询意图的分析) identified_entities: List[str] Field(description识别出的关键实体如‘销售额’、‘城市’、‘上个月’) assumed_table_schema: dict Field(description假设的数据库表结构用于确认字段) sql_query_template: str Field(description生成的SQL语句模板时间等变量用占位符) validation_notes: List[str] Field(description自我验证笔记如潜在风险、假设条件) confidence_score: float Field(ge0, le1, description对此计划的置信度) # 2. Plan阶段调用 def generate_plan(user_query: str, db_schema_hint: dict) - SQLGenerationPlan: system_prompt 你是一个资深数据分析师。请根据用户问题分析其意图并生成一个执行SQL查询的【计划】。 请严格按照以下JSON格式输出不要输出任何其他内容 { analysis_of_intent: ..., identified_entities: [..., ...], assumed_table_schema: {...}, sql_query_template: SELECT ... FROM ... WHERE ..., validation_notes: [..., ...], confidence_score: 0.95 } 已知数据库表结构提示如下 {schema_hint} user_prompt f用户问题{user_query} # 调用LLM这里以OpenAI为例 response openai_client.chat.completions.create( modelgpt-4, messages[ {role: system, content: system_prompt.format(schema_hintdb_schema_hint)}, {role: user, content: user_prompt} ], temperature0.1, # Plan阶段使用低温度追求稳定性 response_format{ type: json_object } # 强制JSON输出 ) plan_json json.loads(response.choices[0].message.content) # 使用Pydantic进行解析和验证如果格式错误会抛出异常 plan SQLGenerationPlan(**plan_json) # 自动评审检查置信度 if plan.confidence_score 0.7: raise LowConfidencePlanError(生成的计划置信度过低建议人工复核。) return plan # 3. Commit阶段执行模板填充模式 def commit_sql_generation(plan: SQLGenerationPlan) - str: # 这里我们假设sql_query_template已经是安全的、参数化的模板 # 例如: SELECT city, SUM(amount) as sales FROM orders WHERE date {last_month_start} AND date {this_month_start} GROUP BY city HAVING sales 100000 ORDER BY sales DESC # 在实际系统中这里会从计划中提取变量并从外部获取真实值如计算上个月的日期范围 variables calculate_variables_from_plan(plan) # 使用模板引擎安全地渲染防止SQL注入 from jinja2 import Template template Template(plan.sql_query_template) final_sql template.render(**variables) # 最终提交前可以进行一次轻量级的语法检查例如用另一个LLM或简单的规则 if not perform_final_sql_safety_check(final_sql): raise SafetyCheckFailedError(生成的SQL未通过安全校验。) return final_sql # 4. 主编排流程 def main_workflow(user_query: str): try: # 步骤1: 生成计划 db_hint get_db_schema_hint() # 从配置或元数据服务获取 plan generate_plan(user_query, db_hint) log_plan(plan) # 记录审计日志 # 步骤2: 可选人工评审环节此处省略 # 步骤3: 执行提交 final_sql commit_sql_generation(plan) # 步骤4: 执行SQL并返回结果或返回SQL供用户确认 result execute_sql_safely(final_sql) return {success: True, sql: final_sql, data: result} except LowConfidencePlanError as e: # 降级策略触发人工处理流程或返回一个更保守的通用查询 return {success: False, error: query_too_complex, message: 您的问题较为复杂已转交人工分析师处理。} except ValidationError as e: # Plan解析失败记录并重试或报错 return {success: False, error: invalid_plan, message: 系统内部错误请稍后重试。}这个示例展示了从定义、生成、验证到执行的核心闭环。在实际生产中每个环节都需要更完善的错误处理、日志记录和监控。3.3 监控、可观测性与持续迭代将LLM应用工程化的标志是建立完善的监控体系。对于Plan→Commit架构你需要关注以下指标流程层面各阶段耗时Plan生成耗时、Commit耗时、成功率Plan生成成功率、Commit成功率、重试率。Plan质量层面Plan置信度分布、Plan Schema验证失败原因分布、人工评审介入比例。结果层面最终结果被用户采纳/满意率可通过埋点或反馈、业务规则校验触发率。成本层面各环节的Token消耗分布、不同模型的调用成本。可观测性实践在每个关键步骤Plan生成后、Commit执行后都发出结构化日志和指标。使用Trace ID将一次用户请求的完整生命周期串联起来这样当出现问题SQL时你可以回溯看到是哪个Plan导致了它以及当时的完整上下文是什么。持续迭代循环生产中的坏案例Bad Cases是优化的燃料。建立一个流程定期收集失败或效果不佳的案例。分析是Plan阶段的方向性问题则需要优化Plan提示词或提供更多上下文还是Commit阶段的执行问题则需要调整模板或校验规则。这个“分析-优化-部署-监控”的闭环是系统持续进化的核心。4. 常见陷阱、避坑指南与进阶思考即便架构清晰在实际落地中依然遍布陷阱。以下是我从多个项目中总结出的血泪教训。4.1 使用侧产品/业务的常见误解与应对陷阱一“有了Plan→Commit就能100%准确。”这是最危险的期望错配。该架构大幅提升的是可控性和可预测性而非绝对准确性。LLM的“幻觉”问题在Plan阶段依然可能存在。管理业务方期望的关键在于定义清晰的“责任边界”。向业务方说明系统能保证的是“输出严格遵循既定格式和规则”而“规则本身的完备性”和“Plan阶段推理的逻辑正确性”仍需持续优化和人工监督。应对策略在项目启动初期就建立“置信度通道”概念。例如将结果分为高、中、低置信度通道高置信度结果直接交付中置信度结果需用户确认低置信度结果直接转人工。让业务方理解这是一个有层级的可靠性体系。陷阱二试图用一套架构解决所有问题。Plan→Commit适用于对输出格式、合规性、稳定性要求高的任务型场景代码生成、报告撰写、数据查询。对于纯粹的创意型或探索型场景如头脑风暴、写诗歌、开放式对话强行套用此架构反而会扼杀创造性增加不必要的复杂度。应对策略对应用场景进行清晰分类。在系统中设计不同的处理管道。任务型请求走严谨的Plan→Commit流程创意型请求则走更自由、温度参数更高的直接生成流程。通过路由逻辑将不同需求的请求分发到不同的管道。4.2 工程侧的典型技术难题与解决方案难题一Plan的“结构逃逸”问题。即便使用了response_format{ type: json_object }LLM偶尔仍会输出不合规的JSON或在JSON外加多余描述。解决方案防御性解析编写健壮的解析函数使用正则表达式如rjson\n(.*?)\n尝试从返回文本中提取JSON块。链式修复如果解析失败不要立即报错。将LLM的原始输出和解析错误信息一起发送给同一个或另一个LLM要求它“修复以下文本使其成为合法的JSON”。这通常能解决大部分问题。设置重试预算如果连续修复N次如2次仍失败则判定为该次请求异常触发降级或失败流程避免无限循环。难题二Commit阶段模板的“过度僵化”与“覆盖不全”。使用Jinja2模板能保证确定性但业务需求千变万化模板可能无法覆盖所有Plan输出的情况导致渲染失败。解决方案模板版本化与动态加载为不同类型的Plan关联不同的模板版本。Commit服务根据Plan中的template_version字段加载对应的模板。默认值与条件逻辑在模板中使用丰富的Jinja2语法如{{ value | default(N/A) }}{% if condition %}...{% endif %}使模板能灵活处理Plan中可能缺失或为空的字段。“安全网”模板准备一个最通用、最简单的兜底模板。当主模板因字段缺失等原因渲染失败时自动降级使用兜底模板并记录告警提示开发人员更新模板。难题三系统延迟与成本激增。从一次LLM调用变为至少两次Plan Commit还可能加上评审、重试延迟和成本看似翻倍了。解决方案模型选型差异化Plan阶段需要较强的推理和分析能力可以使用能力强但较贵的模型如GPT-4。Commit阶段如果是简单的填充或格式化完全可以使用更快、更便宜的模型如GPT-3.5-Turbo、Claude Haiku甚至专用的小模型。缓存策略对Plan进行缓存。如果用户输入和上下文相同可以直接复用之前的Plan跳过昂贵的Plan生成步骤。缓存键的设计需要精心考虑要包含可能影响Plan的所有因素用户Query、系统提示词版本、上下文摘要等。异步与流式对于非实时交互场景可以将Plan生成设为异步任务。对于实时场景可以考虑流式输出在Plan确定后Commit阶段可以边生成边返回部分结果提升用户体验。4.3 进阶模式动态工作流与人类协同当基础架构稳定后可以考虑更复杂的模式。动态工作流Plan的输出不仅可以包含“做什么”还可以包含“怎么做”的流程指示。例如一个复杂数据分析任务的Plan其next_step字段可能指示“本计划需先调用API-A获取基础数据再调用LLM进行摘要最后用模板B生成报告”。编排引擎可以解析这个Plan动态地组装和执行一个多步骤的工作流。这使得单个Plan→Commit单元能够应对极其复杂的任务。人类在环Human-in-the-loopPlan→Commit架构天然适合人机协同。Plan本身是人类审核的绝佳对象——它比最终结果更简洁、更结构化。你可以在系统中设置多个审核点关键决策审核对于高价值或高风险任务如审批金额超过阈值的文案将Plan提交给人工审批批准后才进入Commit。模糊案例处理当Plan的置信度低于某个阈值或自动校验规则无法决断时将案例放入人工处理队列。主动学习将人工审核时修改过的Plan和最终结果作为高质量样本反馈给训练数据池用于持续微调模型或优化提示词形成系统自我改进的正循环。从“随机输出”到“可控提交”Plan→Commit架构的本质是将软件工程中经典的“设计-实现”分离思想引入到LLM应用开发中。它通过增加一个结构化的、可审查的中间层Plan牺牲了一点初始的开发便捷性和极致的延迟换来了生产环境梦寐以求的可靠性、可维护性和可进化性。在我经历的项目中凡是接入了这套架构的LLM应用其线上事故率都下降了超过70%而业务方的信任度则显著提升。这不仅仅是技术的改变更是一种工程范式的转变。开始为你的下一个LLM项目设计Plan吧它会是你从原型走向生产最坚实的桥梁。