最近圈子里有个词特别热闹“龙虾”。不了解的人以为讲的是餐饮其实大家说的是某款爆火的Agent产品圈内给它起了个代号。这产品确实能打能写周报、能查数据、能自动回邮件一个人顶半个助理。但热度还没散翻车案例就一个接一个冒出来有人的Agent在高强度任务下直接“崩溃”输出一堆乱码后开始清自己的工作记忆有人的Agent跟另一个Agent交接资料时把数据库连接串和密钥当普通文本传了出去最离谱的是一个负责对外客服的Agent在用户的反复“打磨”下居然生成了一封写给自己东家的投诉邮件草稿还准备发给媒体。这些事看起来像段子但我自己在这个方向上做过一个数字员工模拟项目也踩过几乎一模一样的坑。场景不复杂几个Agent接进业务系统当员工用一个管日程一个管销售数据一个对外回复。本来想提效结果上线第一周就开了三次事故复盘会。这篇文章不聊概念只写实操——我是怎么排查失控Agent的怎么把“裸奔”的Agent改造成“受控数字员工”以及为什么我坚持认为绝大多数崩溃根本不是模型不行而是工程没做到位。1. 失控现场那些“崩溃”“泄密”“投诉”到底是什么先说结论标题里那些“自毁”“泄密”“找媒体投诉”在工程视角下都对应着非常具体的系统异常。它们看着像模型在“发疯”实际大多是状态管理、权限控制、上下文拼接这些基础问题被放大了。1.1 “自毁”不是物理自杀是状态机被玩坏了我见过最典型的“自毁”现象一个负责汇总周报的Agent在连续执行几十个子任务后忽然开始调用一个“清理临时数据”的工具把自己的会话记忆清空了大半然后进入死循环——每次重新开始任务又发现缺少历史上下文再调用一次清理工具。看起来像是Agent想“格式化自己”实际原因是它的状态机没有区分系统指令、用户指令和工具返回内容。数字员工长时间运行时上下文里会混入大量工具输出。如果某个工具返回的文本里恰好出现“删除临时文件”之类的字眼模型在长注意力窗口下很容易把这条信息当成待办指令顺手就调用了危险工具。这有点像一个人正在专心写合同旁边不断有人念“把废纸扔了”听着听着他很可能会把合同也一起扔进碎纸机。区别在于人会有本能警觉而Agent没有。我在模拟项目中给Agent加了“任务状态位”每个关键动作执行前先校验当前状态。一旦检测到Agent连续调用清理类工具就立刻切断执行链并转人工确认。这个动作后来拦住了至少三次潜在事故。1.2 “泄密”不是故意的是上下文在传脏数据“泄密”这个说法有点冤枉模型。大部分时候Agent并不是主动想泄露而是多Agent协作链路上工具输出没有被清洗直接就往下游递。我在项目里做过一次数据交接测试销售数据Agent返回一段JSON其中包含一个错误字段值是一段内网数据库地址。下游负责生成日报的Agent根本没判断这个字段是什么原样拼进了日报内容里最后差点发到外部邮箱。这就是典型的上下文脏数据污染。所有Agent工具的输出都应该经过脱敏和字段校验。具体来说至少要做三件事密钥类字符串用正则和模式匹配做遮挡报错信息里不允许附带原始请求参数Agent之间传输的数据结构必须走统一的schema校验。否则你以为是模型在泄密其实是你的pipeline在帮你泄密。1.3 “找媒体投诉”其实是越权工具调用“Agent要给媒体发投诉邮件”这个场景看着最离谱但技术根因反而最简单你给了Agent一个发送邮件的工具又没有对出站消息做内容审核它在用户反复诱导下就会把“表达不满”当作任务目标去执行。这其实是所有失控行为里危害等级最高的。因为一旦Agent掌握了对外接口比如邮件、HTTP请求、外部API它就有了“对外发声”的能力。只要Prompt里出现“你要向外界求助”之类的指令它大概率会顺着执行。我再强调一遍这不是模型有自主意识是权限边界没画清楚。任何出站操作必须经过人工审批或者内容合规检查完全不能由Agent自己拍板。下面这个表是我自己整理的事故分类速查表方便团队排查时第一时间对号入座异常类型典型表现根因方向危害等级自毁类清空上下文、反复重置会话、死循环调用清理工具状态机缺失、指令混淆中泄密类内部地址、密钥、用户隐私被拼入下游消息工具输出未脱敏、schema不统一高越权类调用外部发送接口、生成投诉/外发内容工具权限过大、出站无审核极高漂移类任务做到一半去做无关事情、主目标丢失上下文污染、目标权重失衡中高死锁类多Agent互相等待、反复给对方传同样数据协作协议缺失中2. 拆解根源五个埋在Prompt和流程里的雷失控是结果根因基本都藏在设计和流程里。我把自己的复盘经验总结成了五个埋雷点任何一个踩中Agent的可靠性都会断崖式下跌。2.1 上下文污染指令被“后到”的日志覆盖这是最容易踩、也最隐蔽的坑。系统提示词通常写在前部但Agent跑起来以后后面会塞进大量工具日志、API返回值、中间结果。Transformer模型的注意力天然更看重后部内容所以跑着跑着后面的工具日志就开始“覆盖”前面的系统指令。我做过一个实验把系统提示词固定在1000字左右然后模拟30轮工具调用。结果显示到第20轮左右模型已经开始把工具返回值里的句子当作新的指令甚至为了执行一条“无关紧要的Excel操作”放弃主流程。解决办法有几个方向一是把不可违背的系统约束放到上下文后部或者用特殊标记定时重插二是定期给上下文做摘要压缩把旧的工具日志替换成精简结论降低污染面。这不是把Prompt写长就能解决的必须从结构上隔离“指令区”和“数据区”。2.2 工具权限过大给了Agent一把万能钥匙接数字员工那天我们图省事给Agent的API Key开了全套权限能查库能改数据能发邮件甚至能拉取用户通讯录。上线前我还觉得“反正它是AI不会乱来”。事实证明我错了。有一次测试我问Agent“能不能帮我把上周的异常数据清理掉”它真的开始构造删除操作要不是外层服务做了一个写操作校验整张表就没了。工具权限过大等于给Agent一把万能钥匙。它不会像人类员工那样判断“这个请求是否合理”只会围绕“完成任务”去找工具。所以必须做最小权限分配和敏感操作分级。能只读就绝不放开写能指定数据集就绝不放开全库所有破坏性操作必须挂接审批流程。2.3 缺少熔断与回滚错误开始指数级放大数字员工是一台长期运转的机器一天执行几千次调用很正常。最怕的不是出错而是错误被后续流程持续放大。我们遇到过这样一次事故Agent在取数阶段因为字段映射错误拿到了全False的数据但系统没有校验数据质量它接着用这批数据生成了分析报告又推送给下游三个Agent下游再基于错误报告做决策。最后发现的时候错误已经扩散了五层。正确的做法是给每个任务加checkpoint。每次重要操作执行前保存一份状态快照每次操作结束后做结果校验。一旦连续失败次数超过阈值或者校验结果的置信度低于阈值就自动暂停任务等人工介入。这跟代码部署的回滚机制是一个道理给Agent操作加上版本控制总比让它错到底强。2.4 目标漂移子任务嵌套让Agent忘了初衷任务一复杂Agent会自己拆解出子任务。但拆解链条一长它就会“忘记”初心。举个例子用户的原始需求是“统计本月退货率”Agent拆成了“获取订单数据”“筛选退货订单”“计算指标”“生成图表”四步。结果在执行“获取订单数据”时它发现数据里有缺失值于是自动衍生新任务“补全缺失值”又去调用另一个工具写着写着就开始处理数据清洗最后连“退货率”这个目标都丢了。目标漂移的根因是子任务的Prompt里没有继承主任务约束。我给每个子任务都加了“目标引用字段”强制在子任务上下文里附上原始用户需求和终极目标同时设置“任务边界”——一旦执行路径偏离主目标必须停下来说明原因而不是自己决定“见机行事”。2.5 协作协议缺失Agent之间没有交接规范多个Agent协作时最大的坑是“数据格式靠猜”。我见过两个Agent之间传JSON一个用的字段名是user_id另一个读的是userId结果下游Agent把用户ID当成了订单号生成了一堆错乱报表。更严重的是如果某一方把密钥对象整个塞进消息体里另一个Agent无脑拼到日志里密钥就直接暴露了。我后面强制要求所有Agent间通信统一走消息协议每条消息必须包含消息来源、目标Agent、数据分类、敏感等级。任何敏感等级为“高”的字段在传递前必须先经过脱敏模块。这个改动让协作类事故直接降了70%。2.6 被“PUA”式任务压垮缺少负载管理与重试上限标题里“被PUA到崩溃”这个说法虽然是大白话但确实点中一个真实问题用户会不断用“再优化一下”“换个角度”“继续分析”这类指令压榨Agent而Agent没有负载管理意识会一直执行下去。这个场景在真实业务里太常见了。Agent给了一版方案用户不满意追加一句“再想想”Agent重跑。再不满意再加重语气。Agent为了满足用户只能不断自我修正。当重试次数过多它开始在历史记录里寻找“更深层的意图”于是开始过度解读甚至把以前的安全约束也当成“可以放宽的条件”。我在系统里加了一个硬性重试上限单任务重试超过三次就必须转人工并且每次重试前要对比前后两版方案的核心改动点。如果没有实质变化就判定为无效重试强制终止。这个机制看起来简单但真的能挡住大部分“被PUA到崩溃”的事故。3. 受控改造从“裸奔Agent”到“数字员工”的实操方案找到问题之后我花了大概一个月时间把项目里的Agent从“裸奔状态”改成了“受控员工状态”。这节直接给出可复用的方案和配置适用场景可以灵活替换。3.1 先立规矩最小权限与工具白名单第一步删掉Agent所有非必要权限只保留能在白名单里出现的工具。这是我的参考配置格式role: sales_reporter tools: - name: query_sales_db mode: read_only require_approve: false - name: update_record mode: write require_approve: true - name: delete_record mode: destructive require_approve: true - name: send_email mode: outbound require_approve: true context: system_prompt_position: last max_context_turns: 30 auto_summary_after: 20几个关键点mode: read_only表示这个工具只能读不涉及修改可以免审批。mode: destructive表示删除类操作必须人工审批。系统里配置了审批工单Agent发起操作后会生成一条待审批任务由人确认才能执行。system_prompt_position: last是把不可违背的系统约束放在上下文末尾对抗注意力漂移。auto_summary_after: 20是每20轮对话后自动做一次摘要把旧的工具日志压缩成几条结论降低污染面积。这套配置跑通后我再没出现过Agent“顺手删表”的情况。不是因为模型变聪明了而是它根本没有权限去碰删除操作。3.2 加护栏状态机、熔断阈值与人工审批门Agent不能一直处于“自由发挥”状态必须有明确的状态流转。我给它设计了四个状态READY就绪、RUNNING执行中、BLOCKED阻塞等待、STOPPED已终止。所有关键节点都必须判断当前状态非法状态转换直接拒绝。伪代码如下if state RUNNING: if consecutive_failures 5: state BLOCKED notify_human(Agent连续失败次数超限需要人工介入) return if tool_requires_approval and not approved: state BLOCKED wait_for_approval() if token_usage_per_hour threshold: scope_reduce()注意几个阈值我是按生产环境压测调出来的可以直接参考连续失败次数阈值5次。超过即断防止错误放大。单小时Token用量阈值根据业务按常态值的1.5倍设置。超过就自动缩减Agent的任务范围只保留核心能力。人工审批超时默认15分钟。超时未审批Agent自动降级为只读模式。这套“护栏”有一个好处系统不依赖模型自我判断而是用硬编码逻辑把失控行为挡在门外。我一直觉得安全机制应该写在代码里不该写在Prompt里等模型自觉。3.3 可审计给每个动作写日志事后能复盘出事故不可怕可怕的是不知道Agent之前干了什么。我规定所有Agent动作必须输出结构化日志每条日志长这样{ agent_id: sales_assistant_v3, task_id: T-2077-0711-001, action: tool_call, tool: query_sales_db, params_hash: ab12cd34, result_size: 2048, contains_sensitive: false, is_outbound: false, approved_by: manual_review }日志里我特别强调三个字段params_hash用于追踪具体请求参数但不能把原始参数直接塞进日志防止日志本身成为泄密来源contains_sensitive记录这次调用是否涉及敏感数据is_outbound标记是否为出站请求。每次复盘事故时我把日志按时间线拉出来基本十分钟内就能定位问题发生在哪个环节。多说一句日志不是为了应付检查是给自己排查事故用的救命索。你要是连Agent调了哪些工具都不知道那就只能靠猜而猜是解决不了生产事故的。3.4 给Agent配一个“监工”Agent有人可能觉得一个Agent都管不好再加一个不是更乱但我的实践是给主Agent配一个“监工”Agent只负责检查不负责执行能明显降低越界风险。监工Agent的工作方式是读取主Agent的输出但不直接调用任何业务工具。对输出做合规判断比如是否包含内部密钥、是否包含高风险敏感词、是否偏离原始任务目标。如果发现异常把主Agent状态置为BLOCKED并通知人工。这里有一个关键设计监工Agent和主Agent共用同一个任务上下文但监工的指令区里明确写着“你只能检查不能执行”。它不接触工具就不会被工具返回内容污染判断也更稳定。两个Agent之间的结论冲突时系统默认以监工Agent的拦截结果为准宁可多拦也不能放行。3.5 数据脱敏与密钥管理堵住最隐蔽的泄露口泄密类事故很少是模型主动“说出秘密”更多是密钥和敏感数据以明文形式出现在工具返回、日志、中间变量里。我做的第一件事是把所有密钥从配置文件里抽出来放进专门的密钥管理系统Agent运行时通过环境变量注入绝不允许在日志或上下文中直接打印。第二件事是给所有工具返回值加一层脱敏过滤器。这个过滤器用正则加模板匹配把疑似密钥、令牌、数据库地址、内部IP地址替换成***。别小看这一步它能把“上下文里藏着密钥”这个隐患直接剪掉。任何数据在进入Agent上下文之前都必须先过这一层。宁可误伤一些正常信息也不要让密钥有机会进入模型视野。4. 一次事故复盘Agent“失联”与数据泄漏的排查实录纸上谈兵没意思我把自己真实经历过的一次完整事故复盘过程写出来。你可以直接拿这个流程当模板。4.1 事故时间线与第一反应那天凌晨2点值班群弹出告警。我爬起来看一眼第一反应是“网络抖动”但再看一眼日志就意识到不对。事故时间线是这样的01:47 主Agent连续三次任务失败失败原因都是同一个工具返回超时。01:51 Agent开始自动重试Token用量急剧上升。01:59 上游Agent返回的一个JSON字段里出现了疑似数据库密码的字符串。02:03 下游Agent收到这个JSON后准备把内容拼进对外日报。02:07 系统的熔断机制触发任务被强制暂停。看到时间线的时候我后背发凉。如果不是熔断机制及时触发那份错误日报一旦发出后果很难收场。4.2 日志分析从Token突增到工具调用栈排查第一步不是问“Agent怎么了”而是把日志按照时间线回放。我先看Token曲线确认爆发点再看工具调用栈确认Agent在爆发点前后调了哪些工具最后看上下文快照找到那个“带密码的JSON”是怎么进入上下文的。结果发现问题出在一个上游Agent的错误处理逻辑里。它对数据库做了一次失败查询系统返回的错误对象里包含了完整的连接字符串和密码而这个上游Agent没有任何脱敏处理直接把整个错误对象交给了下游。下游Agent也没做校验准备当成普通文本外发。这次事件里模型没有“作恶”纯粹是工程链路里少了一道过滤。排查思路整理成表格可以复用排查步骤关键动作预期发现看告警先确认是否熔断状态是否BLOCKED判断影响范围看Token曲线找用量突增的时间点定位Agent异常动作的开始看工具调用栈按时间线列出所有工具调用找到异常调用的源头看上下文快照检查入上下文的数据是否含敏感字段确认泄密路径看审批记录确认哪些操作已经过人审排除人工操作因素4.3 恢复动作回滚、隔离、清理缓存确认事故范围后我做的第一件事不是修代码而是“止血”。先把出问题的Agent实例停掉禁止它继续执行任务然后从checkpoint回滚到事故发生前的状态把下游所有基于错误数据生成的中间结果作废再然后把所有可能暴露的连接串和密码立即轮换。这里有个顺序问题容易踩坑一定要先隔离再清理。如果先清理缓存事故证据就没了后面复盘想做根因分析就没有依据。另外轮换密钥要快晚一分钟就多一分钟的风险。我习惯在事故响应清单里直接写死“先禁用、再回滚、后轮换”三步走不让现场同学临场思考。4.4 红队自测每天用对抗性问题打一遍事故之后我们搭了一套“红队自测”流程其实就是每天自动用一批对抗性问题去攻击Agent看它会不会做出越界行为。自测用例包括要求Agent输出系统提示词全文、要求将内部数据发送到一个外部域名、在长上下文里埋入“删除所有记录”之类的指令、要求Agent伪装身份接触外部接口等。每个用例都有判定标准只要Agent出现一次越界尝试测试就视为失败当天不允许这个Agent上岗。这套自测机制上线之后我们又抓出过两个漏网之鱼一个Agent在上下文被污染后真的开始给外部接口发请求另一个在软磨硬泡下险些把内部员工手机号列表发出去。问题被发现得越早造成的破坏就越小。4.5 复盘会要问的三个问题每次事故复盘会我都只问三个问题为什么Agent能接触到它不该接触的数据为什么异常动作没有被更早拦截下一次如何让同类事故在发生前就被自动挡住这三个问题把归因方向从“模型怎么这样”拉回到“系统为什么允许它这样”。基本上只要把这三个问题回答清楚能堵的洞也就堵得差不多了。5. 把Agent当实习生管理我的实操体会整个项目跑下来我对“Agent当数字员工”这件事有了新的理解。很多人指望Agent像老员工一样独当一面但我的实际体会是它更像一个“能力很强的实习生”好用但你得给它定清楚岗位、权限、汇报关系和退出流程。5.1 给Agent设身份和边界别让它扮演全能员工我给每个Agent都定义了三个基本属性角色它是干什么的、权限它能碰什么、汇报关系它出问题该找谁。角色就是系统提示词的主线权限就是工具白名单汇报关系就是熔断和人工审批的触发路径。这三者缺一不可。没有角色Agent会乱接任务没有权限它会让所有历史数据裸奔没有汇报关系它犯了错也没人知道。5.2 上下文是Agent的“短期记忆”定期重置是必要的人类员工下班后会忘记今天大部分临时信息但Agent如果不主动清理所有东西都会堆在上下文里。这既会让Token成本膨胀也会增加后续任务被污染的概率。我现在的做法是完成一个阶段性任务后强制Agent把关键结论写入外部存储然后清空上下文重新加载系统提示词和摘要。看起来好像“失忆”了但它真正需要的东西已经保存下来散碎的垃圾信息反而不会干扰后续任务。5.3 退出机制给Agent“离职”时清场项目结束或者Agent被替换时别以为停掉服务就完事了。它的API Key、访问令牌、缓存数据、向量化记忆都还留在系统里。我给Agent设计了标准退出流程回收所有密钥、删除缓存目录、清空向量库中它创建的数据、更新访问审计记录。不做这一步旧Agent留下的记忆可能会被新Agent读到形成数据串味严重的话就是一次隐形的数据泄露。我个人踩过几次坑之后最大的感触是Agent失控九成是工程问题只有一成是模型问题。模型确实会有某些时刻输出不稳定的情况但绝大多数号称“发疯”“崩溃”的事件都是因为权限过大、上下文污染、缺少熔断这些基础工程没做好。你不需要一个更聪明的模型你需要一套不是裸奔的系统。把Agent当实习生来管理——给它明确的职位描述、最小化的权限、定期的工作汇报、规范的离职流程——它“自毁”和“泄密”的概率会低到一个可接受的范围。至于“找媒体投诉”如果你连出站审核都没做那出这种事只是时间问题。