
Prompt 与 Agent 工作流上线前一份不漏项的验收清单本文围绕“从原型到生产的验收清单”梳理可执行的工程取舍与检查重点。文中的配置、阈值和示例用于说明设计方法接入实际项目时应根据业务场景、监控数据和依赖能力完成验证。将一个 Prompt 原型转化为生产级可用功能本质上是一场从“凭感觉调参”到“严密工程验收”的跨越。生产化转型的四大死角与防范手段在原型验证阶段我们倾向于假设模型总是听话的。但在生产环境中必须假设模型随时可能“不听话”。flowchart TD A[原型阶段单一 Prompt 调试] -- B(生产阻碍: 结构偏移/死循环/幻觉/超时) B -- C[构建结构化 Schema 强制校验] B -- D[引入 Agent 状态机终止条件] B -- E[设计 Prompt 版本对比与回归集] C -- F[上线前 10 维验收清单] D -- F E -- F F -- G[生产级 Agent 稳定运行]针对原型走向生产的常见死角防范手段需要前置到代码架构中死角一结构化输出撕裂。模型偶尔会在 JSON 前后包裹多余的说明文字或漏掉某个关键字段。需要引入 Pydantic 或 JSON Schema 进行严格的强类型校验校验失败触发结构自愈重试。死角二Agent 工具调用的无限递归。当 Agent 发现某个工具返回空结果时它可能会换个参数重新调用导致步数瞬间达到上限。必须在代码层强制注入最大步数计数器与死循环检测器。死角三语气风格的漂移。提示词中简短的一句“语气要温柔”在面对用户抱怨时可能演化为敷衍。需要将语气约束拆解为明确的正反例范本Few-Shot Shots。生产级 Agent 验收的 10 维检查清单在将 Agent 功能合并到主干分支前建立一套客观的验收清单至关重要。这套清单不依赖主观感觉而是用明确的代码指标说话Schema 容错度是否具备 JSON 代码块自动提取与缺失字段默认填充能力最大步数限制单次任务 Agent 最多允许调用几次工具建议上限 5 步幻觉拦截当检索结果为空时模型是否能坦诚告知而非编造答案敏感词与安全性输入与输出是否挂载了安全过滤钩子Prompt 版本跟踪当前提示词是否有 Git 版本的明确映射响应延时分布P95 延时是否被控制在用户可接受的阈值内降级策略模型 API 全线故障时是否有离线模版兜底Token 消耗上限单次 Agent 执行总 Token 是否设置硬性 Limit日志与链路追踪是否记录了 Prompt 的输入、输出及中间工具调用链自动化测试覆盖是否拥有至少 20 个边界 Case 的回归测试集完整工程实现带 Schema 校验与死循环检测的 Agent 框架下面是基于 Python 编写的 Agent 执行引擎实现了结构化输出校验、工具调用步数限制、死循环防护以及自动化验收测试驱动。import json import logging import re from typing import Dict, Any, List, Callable, Optional from pydantic import BaseModel, Field, ValidationError logging.basicConfig(levellogging.INFO, format%(asctime)s - [%(levelname)s] - %(message)s) logger logging.getLogger(AgentProductionEngine) # 1. 定义生产级输出数据结构 class AgentActionSchema(BaseModel): thought: str Field(descriptionAgent 的思考过程) action_name: str Field(description调用的工具名称若完成则为 finish) action_input: Dict[str, Any] Field(default_factorydict, description工具入参) final_response: Optional[str] Field(defaultNone, description最终呈现给用户的温馨回答) class ToolRegistry: Agent 可用工具注册表 def __init__(self): self._tools: Dict[str, Callable] {} def register(self, name: str, func: Callable): self._tools[name] func def execute(self, name: str, params: Dict[str, Any]) - str: if name not in self._tools: return fError: Tool {name} is not registered. try: return self._tools[name](**params) except Exception as e: return fError executing tool {name}: {str(e)} class ProductionAgentRunner: 具备生产验收标准的 Agent 执行引擎 def __init__( self, tool_registry: ToolRegistry, max_steps: int 4, prompt_version: str v1.2.0 ): self.tools tool_registry self.max_steps max_steps self.prompt_version prompt_version def _extract_json(self, raw_output: str) - str: 从模型输出中顽强剥离 JSON 内容 match re.search(r\{.*\}, raw_output, re.DOTALL) if match: return match.group(0) return raw_output.strip() def parse_model_output(self, raw_text: str) - AgentActionSchema: 结构化解析与 Schema 容错校验 clean_str self._extract_json(raw_text) try: data json.loads(clean_str) return AgentActionSchema(**data) except (json.JSONDecodeError, ValidationError) as err: logger.warning(f结构解析失败 ({err})尝试构造纠错 Schema) # 降级将原始文本包装为 finish 操作 return AgentActionSchema( thought解析模型输出失败触发结构降级, action_namefinish, action_input{}, final_responseraw_text.strip() ) async def run(self, user_goal: str, llm_simulator: Callable) - Dict[str, Any]: 执行 Agent 迭代循环内置防死循环机制 history_trace [] visited_actions [] # 用于死循环检测 current_step 0 logger.info(f开启 Agent 任务 [Prompt 对应版本: {self.prompt_version}] | 目标: {user_goal}) while current_step self.max_steps: current_step 1 logger.info(f--- 执行第 {current_step}/{self.max_steps} 步 ---) # 调用 LLM 模拟器或真实 API raw_response await llm_simulator(user_goal, history_trace) action_obj self.parse_model_output(raw_response) history_trace.append({step: current_step, thought: action_obj.thought, action: action_obj.action_name}) # 检查终止条件 if action_obj.action_name finish: logger.info(Agent 顺利完成任务目标。) return { status: success, total_steps: current_step, final_response: action_obj.final_response, trace: history_trace } # 死循环检测如果连续两次调用完全相同的工具和入参 action_signature f{action_obj.action_name}:{json.dumps(action_obj.action_input)} if visited_actions.count(action_signature) 2: logger.error(f检测到死循环重复调用: {action_signature}强制挂起) return { status: loop_detected, total_steps: current_step, final_response: 抱歉正在重新梳理思绪请稍后再试一次吧。, trace: history_trace } visited_actions.append(action_signature) # 执行工具 logger.info(f调用工具: {action_obj.action_name} | 参数: {action_obj.action_input}) tool_result self.tools.execute(action_obj.action_name, action_obj.action_input) history_trace.append({step: current_step, tool_result: tool_result}) # 超过最大步数拦截 logger.warning(f任务超出最大步数上限 ({self.max_steps})启动强制降级) return { status: max_steps_exceeded, total_steps: current_step, final_response: 整理信息花的时间比预想稍长了一些这是目前为你总结好的要点。, trace: history_trace } # 自动化验证与测试 def mock_weather_search(city: str) - str: return f{city} 今天晴朗温度 22℃微风非常适合出门散步。 async def mock_llm_logic(goal: str, trace: List[Dict]) - str: 模拟 LLM 的多步响应行为 if len(trace) 0: return json.dumps({ thought: 用户想了解天气我需要先调用 weather_search 工具, action_name: weather_search, action_input: {city: 杭州} }) else: return json.dumps({ thought: 已获取到天气信息生成最终温馨回复, action_name: finish, action_input: {}, final_response: 杭州今天阳光明媚22℃ 的天气刚刚好。忙完手头的事不妨去窗边晒晒太阳。 }) async def main(): registry ToolRegistry() registry.register(weather_search, mock_weather_search) runner ProductionAgentRunner(tool_registryregistry, max_steps3) result await runner.run(帮我查查杭州的天气并给点建议, mock_llm_logic) print(\n Agent 执行结果汇总 ) print(f执行状态: {result[status]}) print(f耗费步数: {result[total_steps]}) print(f最终输出: {result[final_response]}) if __name__ __main__: asyncio.run(main())建立可持续的测试集用真实数据压测 Prompt在原型阶段我们习惯手动在网页界面里敲几句话测试。但上线后任何一次对 System Prompt 的修改都可能导致原本正常的场景出现退化。一套可落地的生产回归机制应当包含边界 Case 积累库将用户线上曾经触发过报错的输入、极端长文本输入、拼写错误的语句整理成 JSONL 格式的测试集。自动化得分比对每次调整提示词后跑一遍脚本检查结构化解析成功率、敏感词拦截率以及平均耗时。灰度发布与观察期将新版本的 Prompt 先切入 5% 的流量观察日志中的重试率和用户主动重发的比例确认稳定后再全量覆盖。把 Prompt 从随手写的草稿打磨成带有严格类型约束、异常熔断和自动化测试保障的生产功能这才是让 AI 应用稳健落地的工程力量。