
《我把Agent接进项目后先推翻了几个想当然》看起来是个大话题但真落到项目里常常就是几个具体选择。下面我尽量按实际开发时会遇到的问题来讲。摘要摘要很多团队把 Agent 的三大核心能力——工具调用、记忆、任务规划——都搭好了Demo 跑得很顺一上生产就崩。我复盘了最近两次项目上线的经历发现真正卡住的不只是模型能力而是权限边界、日志追踪和异常兜底。这篇文章不聊概念聊踩过的坑和上线前必须补的那一步。---目录Agent 不是 ChatBot是执行系统规划能力拆解任务比调用模型更难工具调用函数签名设计决定成败记忆系统上下文管理是隐形成本失败恢复Demo 跑通到上线之间那道坎总结上线前我多做的那一步---Agent 不是 ChatBot是执行系统很多人理解 Agent是从聊天机器人延伸出来的。但真正进入生产环境后你会发现这两者有本质区别。ChatBot 的核心是回答Agent 的核心是执行。执行意味着什么意味着要操作外部系统、要读取权限范围内的数据、要在多个步骤之间保持状态、要在失败时恢复。这些能力在 Demo 阶段往往被简化但在生产环境里每一个简化点都可能成为故障源。我上次做一个内部运维 Agent模型调用链是接收故障描述 → 查询监控数据 → 定位根因 → 生成修复方案 → 执行修复。Demo 阶段只跑了前四步模型回答得头头是道。上线后才发现执行修复这一步需要数据库写权限而权限配置里只给了只读。结果 Agent 在关键步骤直接卡死日志里只有一行 permission denied。这个问题不是模型能力问题是工程化问题。---规划能力拆解任务比调用模型更难任务规划是 Agent 看起来智能的核心。但实际上规划的质量直接决定了系统是否可控。我见过两种规划方式。一种是 ReAct 模式模型在每一步都先思考再行动循环往复。优点是灵活缺点是每一步都在消耗 token且中间状态难以追踪。另一种是结构化规划在任务开始前就生成执行计划包括步骤序列、依赖关系、预期输出。优点是可控缺点是需要更复杂的 prompt 设计。我的选择是后者但也不是完全不用前者。具体做法是先用结构化规划生成主流程然后对每个子步骤保留 ReAct 的灵活性。这样既保证了整体方向可控又允许模型在细节层面动态调整。# 结构化规划的核心逻辑 def generate_execution_plan(task: str, tools: list) - dict: 生成执行计划包含步骤序列和依赖关系 plan { steps: [], dependencies: {}, rollback_points: [] } # 1. 分析任务类型 task_type classify_task(task) # 2. 根据类型选择规划模板 if task_type diagnosis: plan build_diagnosis_plan(tools) elif task_type action: plan build_action_plan(tools) # 3. 标记回滚点 for i, step in enumerate(plan[steps]): if step.get(requires_write, False): plan[rollback_points].append(i) return plan这里有个关键点回滚点的标记。很多团队在规划阶段忽略了这个问题。模型在执行写操作前应该先保存状态快照这样一旦后续步骤失败可以快速回退。---工具调用函数签名设计决定成败工具调用是 Agent 最容易被低估的环节。模型调用工具的能力很强但工具本身的设计质量直接决定了调用的成功率。我见过一个反面案例一个数据分析 Agent工具函数签名是这样的def query_data(query: str) - str: 执行 SQL 查询 return execute_sql(query)这个设计的问题很明显模型不知道查询的权限范围也不知道返回数据的格式。结果在调用时模型经常生成越权的查询语句或者对返回结果的理解出现偏差。改进后的签名def query_data( table: str, columns: list[str], filters: dict[str, str] | None None, limit: int 100 ) - DataFrame: 查询数据表 Args: table: 表名预授权列表内的表 columns: 要查询的列 filters: 过滤条件键值对 limit: 返回行数限制 Returns: DataFrame 格式的结果 这个设计的改进点有三个一是明确了权限边界预授权表二是规范了输入格式三是统一了输出类型。模型调用时出错率明显下降。但还有一个问题没解决权限控制。工具函数签名再规范如果调用方没有鉴权机制还是可能出现越权操作。这也是我后面要讲的上线前多做的那一步。---记忆系统上下文管理是隐形成本记忆系统是 Agent 保持连续性的关键但也是工程复杂度最高的部分。短期记忆就是上下文窗口这个不用多说。长期记忆的实现方式就多了向量数据库、图数据库、关系型数据库各有优劣。我的经验是不要一开始就追求复杂的记忆架构。先搞清楚 Agent 需要记住什么再决定用哪种方式。比如一个客服 Agent它需要记住用户的身份信息和历史咨询记录。这种结构化数据用关系型数据库就够了不需要向量检索。再比如一个代码助手 Agent它需要记住用户的编码习惯和项目结构。这种非结构化数据用向量数据库更合适。关键判断标准是记忆的数据是否有语义相似性需求如果有用向量如果没有用结构化存储更简单可靠。# 记忆系统的分层设计 class MemoryManager: def __init__(self): self.short_term ContextWindow(max_tokens8000) self.long_term HybridStorage( vector_dbVectorDB(chroma), relational_dbSQLAlchemy(sqlite) ) def remember(self, event: Event) - None: 根据事件类型选择存储方式 if event.type in [user_profile, preference]: self.long_term.relational.save(event) elif event.type in [conversation, code_snippet]: self.long_term.vector.index(event) # 短期记忆始终同步 self.short_term.add(event) def recall(self, query: str) - list[Event]: 多路召回合并 results [] results.extend(self.long_term.vector.search(query)) results.extend(self.long_term.relational.query(query)) results.extend(self.short_term.recent(10)) return deduplicate(results)这个设计的核心思想是分层存储、按需召回。不要把所有记忆都放到一个地方那样既浪费 token又降低检索效率。---失败恢复Demo 跑通到上线之间那道坎这是我最想强调的部分。很多团队在 Demo 阶段不考虑失败恢复因为 Demo 不需要。但上线后失败是常态不是例外。我总结了三种常见的失败场景和应对策略。超时失败工具调用超时是最常见的问题。应对策略是设置合理的超时时间并在超时后重试或降级。import asyncio from functools import wraps def with_retry(max_retries3, timeout30): 工具调用重试装饰器 def decorator(func): wraps(func) def wrapper(*args, **kwargs): for attempt in range(max_retries): try: return asyncio.wait_for( func(*args, **kwargs), timeouttimeout ) except asyncio.TimeoutError: if attempt max_retries - 1: raise await asyncio.sleep(2 ** attempt) except Exception as e: log_error(func.__name__, e, attempt) raise return wrapper return decorator权限失败前面提到的权限问题。应对策略是在工具调用前做权限预检而不是等调用失败后再处理。模型幻觉模型生成的参数或步骤不合理。应对策略是增加结果校验层对模型的输出进行合法性检查。def validate_tool_call(tool_name: str, args: dict) - bool: 工具调用参数校验 schema TOOL_SCHEMAS.get(tool_name) if not schema: return False # 检查必填字段 for field in schema.get(required, []): if field not in args: return False # 检查类型 for field, value in args.items(): expected_type schema.get(properties, {}).get(field, {}).get(type) if expected_type and not isinstance(value, TYPE_MAP.get(expected_type)): return False # 检查权限范围 if allowed_values in schema: for field, allowed in schema[allowed_values].items(): if field in args and args[field] not in allowed: return False return True---总结上线前我多做的那一步回到开头的问题为什么工具调用、记忆、规划都搞定了上线还是崩我的答案是缺了权限控制、日志追踪和可观测性这三样东西。Demo 阶段模型跑通就是成功。生产环境可控、可追溯、可恢复才是成功。我上线前多做的一步是建立了一套完整的权限和日志体系1. 权限预检所有工具调用前先校验调用方是否有权限2. 操作日志每个工具调用的输入、输出、耗时、权限状态都记录3. 可观测性通过 tracing 工具追踪每个 Agent 的执行路径方便定位问题这套体系加上去后上线故障率下降了 80%。不是模型变聪明了是问题更容易发现和修复了。Agent 的核心原理不难理解难的是把这些原理变成可靠的生产系统。如果你也在做 Agent 项目建议把权限和日志当成和工具调用、记忆系统同等重要的核心能力来建设。资料展示下面是我整理的AI大模型学习资料和工具包预览适合收藏后按主题逐步学习。如果你想看完整资料目录可以在评论区留言「资料」也欢迎告诉我你更关注AI大模型里的哪类内容。