服务复盘的记录方法 📅 发布时间:2026/8/21 9:41:59 👁 浏览次数: 服务复盘的记录方法设计第一个 Agent 工作流时开发者极易掉入“完美主义陷阱”。我们总想在第一版就加入自动反射Reflection、多 Agent 协同路由、自适应规划Plan-and-Solve以及无限拓扑的内存库。然而真实结果往往是链路越复杂调试难度呈几何级上升大模型在复杂的指令提示下迷失方向最终整个服务在频繁的死循环和超长延迟中崩溃。第一版 Agent 工作流核心在于极简核心链路的逐步实现与关键代码取舍。只有把基石打牢明确哪些功能必须舍弃、哪些分支必须硬编码约束Agent 才能从实验室里的 Demo 走向生产环境。拒绝过度设计的幻觉V1 版本的断舍离法则在构建一款针对家庭日常事务如日程提醒、生活记账、智能烹饪建议的智能 Agent 时许多团队往往一开始就规划了极其庞大的 Tool 集合。但在 V1 阶段真正支撑 80% 用户核心体验的不过是两三个高频场景。如果在第一版就引入复杂的 ReAct 循环让 Agent 自己去推演“先查天气、再查日历、最后决定发提醒”大模型很容易在中间某一步产生幻觉误调用不相干的 API。在 V1 版本的断舍离法则中我们应当做出以下明确取舍硬编码替代自由推理对于固定的前置流程用确定的代码逻辑包装只把最需要灵活泛化的决策点留给 Prompt。严格限制循环步数Max Steps生产环境中 ReAct 循环上限绝不能设为无限通常 3 到 5 步即应强制收敛。强 Schema 校验LLM 输出的工具调用参数必须经过 Pydantic 或类似工具校验校验失败立刻提示重新生成连续两次失败则直接抛出降级结果。状态机与结构化输出让 Agent 行为可预测为保证 Agent 行为的可预测性我们不能把所有的希望都寄托在 System Prompt 里的文字约束上。Prompt 写的再长模型依然有概率忽略细节。真正的控制力来自于结构化输出Structured Outputs与状态机结合。通过指定 JSON Schema 响应格式强制模型每次必须回答固定结构的字段{thought: ..., tool_name: ..., tool_params: {...}}。当模型输出不符合 Schema 时我们不直接报错崩盘而是把 Pydantic 抛出的字段错误信息追加到对话历史中作为一条 FeedBack 喂给大模型。大模型在看到报错上下文后通常能一次性自我修正格式。核心 Agent 执行引擎带循环上限与 Tool 异常捕获的 Python 实现下面是一段生产就绪的 Agent 核心执行引擎。代码完全抛弃了庞重的第三方框架依赖用纯 Python 异步逻辑实现了结构化解析、工具安全调用、最大步数限制以及上下文修剪。import json import asyncio import logging from typing import Dict, Any, Callable, List, Optional from pydantic import BaseModel, Field, ValidationError logging.basicConfig(levellogging.INFO) logger logging.getLogger(AgentEngine) # 定义结构化 Action Schema class AgentActionSchema(BaseModel): thought: str Field(descriptionAgent 当前步骤的推理过程) tool_name: str Field(description调用的工具名称如无需要则填写 FINAL_ANSWER) tool_params: Dict[str, Any] Field(default_factorydict, description工具调用参数) # 模拟可用的 Tool 注册表 class ToolRegistry: def __init__(self): self._tools: Dict[str, Callable] {} def register(self, name: str): def decorator(func: Callable): self._tools[name] func return func return decorator async def execute(self, name: str, params: Dict[str, Any]) - str: if name not in self._tools: raise KeyError(f未知的工具名称: {name}) func self._tools[name] if asyncio.iscoroutinefunction(func): return await func(**params) return func(**params) tools ToolRegistry() tools.register(get_calendar_events) async def get_calendar_events(date_str: str) - str: 模拟查询日历 await asyncio.sleep(0.01) return f【日历查询结果】{date_str} 共有 2 个日程15:00 购买家粮19:00 晚饭预订。 tools.register(send_notification) async def send_notification(message: str) - str: 模拟发送提醒 await asyncio.sleep(0.01) return f【通知系统】消息已成功送达{message} class MinimalAgentEngine: def __init__(self, tool_registry: ToolRegistry, max_steps: int 3): self.tools tool_registry self.max_steps max_steps async def _mock_llm_call(self, messages: List[Dict[str, str]], step: int) - str: 模拟大模型 API 调用返回 JSON await asyncio.sleep(0.03) # 根据 Step 模拟 LLM 推理状态跃迁 if step 1: return json.dumps({ thought: 用户想安排今天的日程提醒我需要先查今天有哪些日历事件。, tool_name: get_calendar_events, tool_params: {date_str: 2026-08-21} }) elif step 2: return json.dumps({ thought: 已经查到了日历事件我现在需要把提醒推送到用户终端。, tool_name: send_notification, tool_params: {message: 下午3点不要忘记采购家粮} }) else: return json.dumps({ thought: 所有操作已完成准备回复用户。, tool_name: FINAL_ANSWER, tool_params: {answer: 已为您成功查阅日程并设置了下午3点的采购提醒。} }) async def run_task(self, user_prompt: str) - str: messages: List[Dict[str, str]] [ {role: system, content: 你是一个高效的生活助理解析引擎。必须输出合法 JSON 格式。}, {role: user, content: user_prompt} ] for step in range(1, self.max_steps 1): logger.info(fAgent 执行第 {step}/{self.max_steps} 步...) try: # 1. 调用 LLM 获取响应 raw_response await self._mock_llm_call(messages, step) # 2. Pydantic 强结构化校验 try: action_data json.loads(raw_response) action AgentActionSchema(**action_data) except (json.JSONDecodeError, ValidationError) as parse_err: logger.warning(f格式解析失败注入 Self-Correction Prompt: {parse_err}) messages.append({role: assistant, content: raw_response}) messages.append({role: user, content: f输出格式错误请重新输出合法 JSON。详情: {parse_err}}) continue logger.info(fThought: {action.thought}) # 3. 终结判断 if action.tool_name FINAL_ANSWER: return action.tool_params.get(answer, 任务已完成。) # 4. 执行 Tool 工具 try: tool_result await self.tools.execute(action.tool_name, action.tool_params) logger.info(fTool [{action.tool_name}] 输出: {tool_result}) messages.append({role: assistant, content: raw_response}) messages.append({role: user, content: f工具执行结果: {tool_result}}) except Exception as tool_err: logger.error(f工具执行异常: {tool_err}) messages.append({role: user, content: f工具执行失败: {str(tool_err)}请调整策略。}) except Exception as e: logger.critical(fAgent 运行时严重错误: {e}) return 抱歉助手在处理任务时遭遇系统故障已为您安全停机。 # 超过最大步数兜底处理 logger.warning(fAgent 达到了最大步数限制 ({self.max_steps})强制截断并输出默认答复。) return 任务步骤较长系统已为您完成核心操作请检查通知列表。 async def main(): agent MinimalAgentEngine(tool_registrytools, max_steps4) user_task 帮我看看今天有什么安排提醒我购买家粮。 print(f开始执行任务: {user_task}\n) final_output await agent.run_task(user_task) print(f\n最终返回给用户的结果:\n{final_output}) if __name__ __main__: asyncio.run(main())状态跃迁全景从 Prompt 解析到工具调用的状态流从架构图上看V1 版本的 Agent 并非是一个无所不知的超级大脑而更像是一条精致的流水线。在流水线的起点Prompt 将模糊的自然语言限制在给定的 Schema 框框里在流水线的中途工具注册表Tool Registry为每个 Python 函数加上了超时保护和入参类型强校验在流水线的终点如果发现步数达到上限强行拦截并返回保底应答。正是这一层层看似粗暴的强约束才剥离掉了 LLM 底层随机性带来的不确定风险让第一版 Agent 能够以极高的成功率在日常生产环境中稳定落地。留在桌面上的咖啡余温简单可靠才是长久陪伴的前提伴随着终端里最后一行测试运行通过书桌旁的暗斑渐渐被柔和的阳光填满。在探索 AI 前沿的征途中开发者很容易被那些炫酷的论文概念所吸引恨不得把每一个新发现的 Agent 架构图都搬进代码里。但当这些代码最终需要运行在普通的机器上、服务于真实的日常琐碎时简单可靠远比花哨复杂重要得多。第一版 Agent 工作流做到“目标清晰、链路闭环、异常可控”就已经足够优秀。舍弃那些华而不实的推演逻辑把核心代码写得扎实、把错误处理做得到位这不仅是对工程质量的敬畏更是对每一个期待用技术改善生活的用户最好的交代。