把能跑的 Agent Demo 变成能长期承受生产压力的 Agent,真正的难点不是模型推理,而是边界控制、失败兜底、可观测性和权限设计。很多 Agent 项目在本地示例里表现很好,一接到真实业务就出现“执行器不响应”“工具调用结果没有被模型采用”“批量任务跑完后输出对不上”等问题。这类问题大多不是大模型能力不行,而是工程结构一开始就没有按生产要求去设计。下面不打算复述理论,而是围绕生产环境里最容易踩坑的五个环节,整理成五条规则,并补充实际排查顺序。无论你是直接用代码编排,还是引入 Agent 开发框架,甚至只是给现有业务加上一个智能助手,这套判断方式基本都能用上。
1. 规则一:一个 Agent 只负责一条清晰业务链路
很多人把 Agent 等同于“能聊天、能搜索、能调用工具、能操作很多系统”的通用助手。这种想法在做 Demo 的时候没问题,放到生产环境就会立刻失控。生产级 Agent 的第一个要求,不是能力多,而是边界清楚。
1.1 不要一开始就构建“全能助手”
单实例 Agent 承担的职责越多,出问题的概率就越大。每一个新增技能都会往系统提示词里加描述,往工具列表里加接口,往上下文里加示例。当这些内容互相干扰时,模型容易在“该调用哪个工具”“该输出什么格式”“该不该继续追问”之间摇摆。
更稳妥的做法,是把业务拆成单一职责的 Agent。比如:
- 订单售后助手,只处理退换货、物流查询和异常登记。
- 工单分类助手,只负责把用户描述映射到预定义工单类型。
- 代码检查助手,只读取代码仓库并返回检查建议,不做其他操作。
判断边界是否合理,有一个很实用的标准:如果新增一个工具时,你需要反复修改系统提示词,说明职责已经过宽。正常情况应该是加一个工具即可,提示词不需要大改。如果不同业务之间工具高度重叠,就先用一个上层路由 Agent 做分发,再交给各自的执行 Agent,而不是把全部工具塞进同一个 Agent。
1.2 输入、输出、失败标准必须在第一行规则里写死
开始写代码之前,先定义清楚三类问题。
第一,输入范围。用户请求经过前置处理之后,哪些字段允许进入 Agent?哪些字段必填?哪些字段要过滤?如果不做输入限制,用户发一段超长文本、一个恶意指令或者一串不完整 JSON,Agent 会在第一步就开始混乱。
第二,输出格式。不要允许 Agent 输出任意自然语言作为最终结果。生产环境里,最终结果应当是结构化数据,例如 JSON、状态码、消息类型加业务字段。模型输出自然语言可以,但下游系统接收前必须完成解析和校验。
第三,失败标准。到底什么算成功?不是模型回复“好的”就算成功,而是业务系统里的状态发生了变化。比如售后工单确实被创建,或者订单状态确实被更新。什么算失败?超时未响应、重试后仍然失败、输出结构校验不通过、需要人工介入,都要在规则里写清楚。这样后续所有日志、告警和排查才有依据。
注意:很多项目出了问题说不清是模型原因还是链路原因,就是因为一开始没有把“成功”定义清楚。先写死输入、输出和失败标准,再谈 Agent 能力优化。
2. 规则二:先跑通最小闭环,再叠加记忆、知识库和工具编排
Agent 项目的技术栈选择很容易让人上头。MCP、Agent Skill、向量知识库、长期记忆、多 Agent 编排,每个名词听起来都值得研究。但生产落地不是搭积木,功能叠加得越快,定位问题就越难。
2.1 最小闭环至少要包含“接收输入、调用一次工具、返回结果”
很多项目上来就做“多轮对话 + 长期记忆 + 多个工具编排”,结果第一轮对话就卡在工具调用上。问题不是模型看不懂工具描述,而是整个链路里没有单独验证过某一环。
我更建议把第一次测试拆成三层:
- 接收一条用户输入,交给模型。
- 模型输出一次工具调用参数,代码解析并真实调用接口。
- 工具返回结果,模型生成最终回复,代码校验后输出。
这三步跑通,说明基础链路是通的。如果这期间出现超时、参数解析失败、结果截断、响应格式不对,问题都出在最底层,而不是记忆或编排层。先解决底层,再往上分层加。
2.2 记忆和知识库不是越早上越好
Agent 一旦引入记忆模块,就要回答几个问题:
- 记忆存多久?一个会话内,还是一周、一个月、永久?
- 谁可以读?只有当前用户,还是所有用户都共享?
- 能不能删除?用户要求删除历史数据时,系统能不能真正清掉?
- 记忆会不会占满上下文?每次携带所有历史会让模型响应变慢、成本升高,而且未必提升效果。
判断是否需要长期记忆,标准很直接:同一个用户下一轮提问,是否必须依赖上一轮结论。比如售后助手查询工单,用户问完“工单状态”又问“如何处理”,确实需要上下文衔接,这时做会话级记忆就够。如果一个任务每次请求信息完整,不依赖历史,就没必要引入长期记忆。
知识库也是同样逻辑。先确认业务是否需要专业资料检索。如果只是普通规则,写进提示词或工具参数里就够了。真正需要知识库的场景,通常是资料量大、内容更新频繁、用户提问是开放式的,这时才值得引入向量检索。
2.3 Agent Skill 和 MCP 先区分定位再选型
MCP 全称是 Model Context Protocol,属于工具接入层面的协议,它解决的是“模型如何更规范地调用外部工具”。Agent Skill 则更像一组可复用的提示词、工具调用步骤和业务操作封装,解决的是“某个复杂任务怎么做”。
两者不是谁替代谁的关系。如果只是接几个内部 API,用 MCP 风格的工具描述就能搞定,让模型按约定参数调用接口。如果要沉淀一套多步骤能力,比如“审计日志分析”“多标签工单流转”,再把它封装成 Skill,后续其他 Agent 可以直接复用。
选型时不要先问“哪个更主流”,而是先列出业务动作:需要调用哪些接口、有哪些判断步骤、哪些环节允许模型自由发挥、哪些环节必须走固定流程。流程固定度越高,越适合编排;流程开放度越高,越需要模型能力。
3. 规则三:工具调用必须可观测、可重试、可回滚
工具调用是 Agent 生产运行中最容易出问题的部分。模型擅长生成文本,但调用外部系统时,网络超时、参数非法、权限不足、接口返回异常这些情况几乎每天都会遇到。不能把这些都扔给用户,也不能让模型自行处理一切。
3.1 每次工具调用都要留结构化日志
日志不要只记录“成功”或“失败”,要记录完整的调用上下文。我建议至少包含这些字段:
- request_id:一次用户请求的唯一标识。
- agent_step:当前属于哪个执行步骤。
- tool_name:调用的工具名称。
- arguments:传给工具的参数摘要。
- status:成功、失败、超时、重试中。
- error_type:错误分类。
- latency_ms:调用耗时。
- retry_count:重试次数。
示例:
{ "request_id": "req_20250321_001", "agent_step": "tool_call", "tool_name": "query_order", "arguments": { "order_id": "A1001" }, "status": "failed", "error_type": "timeout", "latency_ms": 30500, "retry_count": 2 }有了这样的日志,定位问题时会快很多。没有日志的情况下排查 Agent,基本等于靠猜。
3.2 重试顺序:区分瞬时错误和业务错误
工具调用失败时,不要一律重试。先判断错误类型。
瞬时错误包括网络超时、连接被重置、服务暂时不可用。这类错误可以重试,但一般建议限制次数,比如最多重试 3 次,重试之间加递增间隔。不要无限重试,否则上游服务恢复时,会突然积压大量请求,造成二次雪崩。
业务错误包括参数非法、权限不足、业务规则不允许操作。这类错误重试没有意义,正确做法是返回失败信息,让 Agent 基于失败结果换一种方式,或者直接升级到人工处理。
判断标准很简单:如果同样的参数调用 100 次都会失败,那就是业务错误;如果第一次失败、第二次可能成功,那就是瞬时错误。把两种错误分开处理,整个链路会稳定很多。
3.3 工具返回内容过大时,先截断或摘要再交给模型
大模型上下文窗口有限,工具返回结果不是越多越好。比如查询一个订单详情,可能返回几百行关联记录;查日志可能返回几十 KB 文本。如果全部塞给模型,容易出现两个问题:一是超出上下文长度导致截断,二是无关内容干扰模型判断。
正确的做法是在工具层做处理。比如:
- 查询列表只返回前 20 条和总条数。
- 日志内容先做关键词提取或摘要。
- 数据库查询只返回需要的字段,不 SELECT *。
这步处理不能交给模型自己决定,因为模型无法预知完整数据量。生产环境里,返回内容的裁剪、摘要、分页,都应该在工具接口内部完成。
4. 规则四:并发、队列和长任务资源要提前设计
Agent 任务通常不是一次 HTTP 请求就结束,而是多步推理加多次工具调用,耗时和资源消耗都高于普通接口。如果按照传统 Web 服务的思维去设计,上线后很容易在并发上出问题。
4.1 并发数不是越高越好
假设一次完整 Agent 调用需要 3 次模型推理和 4 次工具调用。这个过程中,CPU、内存、模型服务、外部 API 都在持续工作。如果同时开 50 个并发,模型服务的排队时间会明显增加,外部接口也可能被限流。
建议从很小的并发开始测试。比如同时 2 到 5 个任务,观察成功率、平均延迟、P95 延迟和资源占用。确认稳定之后再逐步上调。如果失败率上升,不要急着加服务器,先看是不是并发数把上游 API 打满了,或者模型服务排队严重。
判断并发是否合理,不要只看“跑没跑完”,要看:
- 平均单任务耗时。
- 任务在队列中的等待时间。
- 模型服务的排队长度。
- 外部 API 的错误率。
- 数据库连接和磁盘读写。
这些指标适合在生产前做一轮压测,不需要太精细,但至少能确认系统在峰值流量下不会崩。
4.2 长任务用队列,不用同步阻塞接口
Agent 任务可能耗时几秒到几分钟。如果客户端一直同步等待,体验会很差,也容易触发网关超时。生产环境里建议把任务改成异步模式:
- 客户端提交请求,服务立即返回 task_id。
- Agent 任务进入队列,后台消费者执行。
- 客户端通过轮询或 Webhook 获取结果。
这个设计不需要一开始就引入重型消息中间件。如果团队已经有 RabbitMQ、Redis、Kafka 可以复用;没有的话,用数据库表存任务状态也可以。核心是“任务状态可查询”。
4.3 任务状态至少要区分“排队、执行中、成功、失败、需人工”
每个任务状态都要有最后更新时间。当任务卡住时,运维人员能够立刻看到问题。
- 排队:任务已进入队列,等待消费。
- 执行中:消费者正在处理。
- 成功:处理完成,结果可查询。
- 失败:重试后仍然失败。
- 需人工:业务无法自动处理,需要人工介入。
执行中状态超过一定时间没有变化,可以视为异常。超时阈值由业务自己定,比如普通售后任务 10 分钟,复杂分析任务 30 分钟。一旦超过阈值,就触发告警,并允许运维手动重试或终止。
注意:任务状态要支持幂等更新。同一任务被重复消费时,不能重复创建工单、重复扣款或重复写入数据。每次调度都带上 task_id 做去重判断。
5. 规则五:安全、权限和输出校验不能放到上线后补
Agent 的能力越强,安全隐患越明显。它能调用工具,意味着它能发起真实操作。如果权限没有控制好,一条恶意指令就可能造成越权操作。这个不能等上线后再补救。
5.1 Agent 的权限要按最小范围授予
不要让 Agent 使用管理员账号调用所有接口。生产环境里应该单独创建服务账号,只给它开通完成业务所必需的权限。
比如:
- 查询订单状态的工具,只需要只读权限。
- 创建工单的工具,只允许写入工单系统,不允许修改其他业务数据。
- 文件读取工具,只允许读取指定目录,不允许遍历磁盘。
判断权限是否合理的标准:如果删掉 Agent 的账号,核心业务还能正常运行,说明权限设计是合适的。反过来,如果 Agent 账号拥有太多权限,一旦提示词被注入或者模型被诱导,风险面会非常大。
5.2 模型输出必须过一道校验层
模型输出的自然语言,不能直接当做业务结果使用。尤其当结果要写入数据库、调用下游 API 或展示给用户时,必须经过校验。
校验至少包括:
- 结构校验:输出是否包含必需的字段,JSON 是否能解析。
- 类型校验:字段值是否在预期范围内。
- 长度校验:输出是否过长,是否需要截断。
- 内容校验:是否包含不合规内容,是否包含敏感信息。
- 业务校验:比如金额字段是否大于零,订单号是否存在。
如果模型输出没有通过校验,需要提前决定是重试、降级还是转人工。不能一直卡在同一处循环重试。
5.3 日志、审计和隐私脱敏一起设计
Agent 在处理任务时接触的数据可能包含用户隐私。日志里不要记录完整手机号、身份证号、密码、Token 等敏感信息,应当脱敏后再落盘。
审计方面,要能回答这些问题:
- 什么时间发起了什么请求?
- 请求来自哪个用户或哪个系统?
- Agent 调用了哪些工具?
- 最终执行了什么操作?
- 结果是什么?
这些日志不是为了事后追责,而是生产事故回溯和问题定位的基础。没有审计链路,Agent 一旦出错,你很难知道它在哪个环节偏离了预期。
6. 生产环境最常见的失败模式与排查顺序
前面五条规则,能覆盖大部分生产 Agent 的工程结构。但实际运行中,总会出现一些看起来很怪的问题。下面列出三种最常见的失败模式,并给出排查重点。
6.1 现象一:Agent 长时间不响应
常见原因有三个:
- 长任务使用同步接口,客户端等待超时。
- 外部 API 没有设置客户端超时时间,导致请求挂死。
- 模型服务排队,请求进入队列后长时间没有结果。
排查时先看任务状态和最后更新时间。如果状态一直在“执行中”,说明任务卡在某个环节。再看日志里最后一次工具调用的耗时和环境信息。如果工具调用迟迟没有返回,优先检查外部 API 的超时设置和限流状态。
不要一上来就重启服务。重启只是掩盖问题,下次还会出现。
6.2 现象二:工具返回正常,但模型没有执行后续动作
工具调用成功,日志显示工具结果正常,但模型没有继续生成后续步骤,而是直接输出了一段文本或者停在那里。
排查顺序:
- 先看模型的原始输出,确认它到底有没有生成工具调用参数。
- 如果模型输出了普通文本,说明它对当前状态的理解出现了偏离,可能是提示词没有交代清楚“拿到结果后必须继续”。
- 如果工具返回结果太长,可能被截断,模型没有拿到核心信息,需要在工具层做摘要。
- 如果上下文太长,模型可能忽略了早期指令,需要压缩历史消息或重新组织提示词。
这类问题不是简单的“模型变笨了”,而是上下文结构和工具返回内容的组织方式需要调整。
6.3 现象三:批量任务跑完后结果对不上
批量任务最常见的坑是并发场景下的共享状态冲突。比如两个任务同时写同一个文件,后写的覆盖先写的;或者两个任务共用同一个内存变量,互相污染;又或者任务重复执行,数据库里生成了多条重复记录。
解决思路:
- 每个任务使用唯一 task_id。
- 中间结果和输出文件按 task_id 命名。
- 写入数据库时使用事务或唯一约束。
- 任务调度时先查重,判断任务是否已经处理过。
批量任务的成功率不能只看“最终有没有输出”,要检查输出是否完整、是否一一对应、有没有重复和遗漏。
6.4 排查顺序与检查清单
| 排查层次 | 优先检查项 | 常见误区 |
|---|---|---|
| 现象 | 报错信息、超时时间、任务状态 | 直接重启服务掩盖真实问题 |
| 输入 | 参数格式、文件编码、路径、输入字段是否完整 | 只改参数,不检查输入样本 |
| 环境 | 依赖版本、权限、资源占用、端口冲突 | 把环境问题当成模型问题 |
| 参数 | 并发数、重试次数、模型温度、上下文长度 | 把参数拉满,反而更不稳定 |
| 工具本身 | 工具版本、接口变更、已知限制 | 忽略版本变更日志和兼容性 |
排查时按这个顺序走,能避免很多无效操作。先看现象,再确认输入,再检查环境,然后调参数,最后才去质疑工具本身。很多看起来像 Agent 能力问题的情况,最后定位出来都是环境变量配错、路径不对或者依赖版本不一致。
生产级 Agent 和 Demo 最大的区别,不在于模型有多强,而在于每一层设计是否留了后路。边界、日志、重试、队列、权限、校验,这些都是听起来枯燥但真正决定能不能长期运行的环节。我个人建议按顺序来做:先定业务边界和成功标准,再跑最小闭环,然后补日志和重试,接着设计队列和并发,最后把权限和校验加上。如果一上来就追求全自动、多工具、强记忆,最后往往会在最普通的地方卡住。