AI Agent失控如何自救:看门狗与熔断器构建生产级刹车系统

发布时间:2026/10/5 9:24:28
AI Agent失控如何自救:看门狗与熔断器构建生产级刹车系统 凌晨四点手机屏幕亮起来弹出一条银行扣款短信。我刚从椅子上惊醒看到那串数字的第一反应是是不是被盗刷了第二反应是不对是我自己的服务器在刷。我部署的那个Agent在深夜没人干预的情况下对着同一个问题连续重试了几百次每次重试都会重新调用大模型API一路烧掉了相当于大半个月服务器预算的费用。那一刻我意识到做一个AI提示流编排器不能只负责把任务派发下去还必须回答一个关键问题当Agent失控的时候系统怎么把自己拉住这也是我在开源项目里折腾了很久才搞明白的一件事。很多人把Agent开发的重心放在提示词、工具调用和模型选型上但真正到了生产环境决定你睡得着睡不着的不是Agent有多聪明而是它有没有一套可靠的刹车系统。今天想分享的就是这个刹车系统里最核心的两个组件运行时看门狗和死循环熔断器。它会告诉你Agent到底在哪些场景下会失控、看门狗盯的是哪些指标、熔断器怎么区分正常重试和死循环以及我在开源落地过程中踩过的那些坑。1. 失控链路复盘Agent 刷爆账单的三个典型动作在设计保护机制之前得先把失控这件事拆开看。我复盘了项目上线以来所有出过问题的线上事故Agent 的失控基本可以归为三类它们的表现不一样烧钱的方式也不一样对应的检测策略自然也不同。1.1 语义循环模型把重试当成了万能解药这是最常见的一种。Agent 的某个子任务调用大模型后模型返回的结果在语义上并没有满足任务的退出条件于是 Agent 把重试当成了解药不断把同样的或极其相似的上下文再次发送给模型。每一次调用都在消耗 token每一次返回都认为没有成功然后继续重试。这种循环最阴险的地方在于从 Agent 自己的视角看它并不是没有进展——它在尝试、在努力、在逼近答案。但从系统层面看它只是在同一个语义空间里打转。我的项目里就出现过这样一个案例Agent 被要求从一段文档里抽取结构化字段模型每次返回的字段名都略有差异Agent 的校验规则又要求完全匹配结果它一遍一遍重试始终匹配不上最后把 200 万 token 的上下文预算耗光了。这类循环的典型特征有两个一是重试次数无上限地增长二是每次重试时输入上下文的语义高度相似。前者好理解后者的检测就需要一点技巧了后面讲熔断器的时候我会详细展开。1.2 工具副作用循环一次写操作引发的无限自我强化第二种失控比对模型的重试更隐蔽它涉及到工具调用。Agent 在流程中调用了一个具有副作用的工具——比如写文件、发请求、改数据库——工具执行成功后返回了一个结果Agent 读取到这个结果后又生成了一个新的工具调用而新调用又产生了新的结果如此反复形成一条永不收敛的调用链。我印象最深的一次事故是这样的一个数据清洗 Agent 在处理一批记录时每处理完一条就调用一次写回数据库的工具。写回后它又去读数据库发现还有未处理的记录于是继续处理继续写回继续读取……从单次操作看每一步都成功了但它实际上陷入了一个没有任何退出条件的循环。那次事故里数据库写入次数在半小时内达到了几万次幸好数据库有事务熔断不然就不是烧 API 费用的问题了而是直接把线上数据写坏了。识别这种循环不能只看重试次数还要看工具调用链的模式同一类工具在短时间内被反复调用而且调用参数高度相似只是时间戳不同。1.3 并发放大16 个任务同时失控账单按几何级数膨胀前两种循环如果只是单任务烧钱速度是线性的慢是慢了点但至少还能容忍。真正致命的是并发场景下的放大效应。提示流编排器天然支持并发执行多个任务。假设你的配置是最大并发 16当其中一个任务陷入死循环时调度器并不会停下来等它——如果任务长时间不结束调度器会认为它超时了然后启动一个新的任务来替代它新任务如果也遇到同样的语义问题又陷入循环于是你会发现系统在并发生成越来越多的替代任务每个任务都在疯狂调用模型 API。最终的结果就是本来只有 1 个任务出错最后 16 个任务同时在烧钱账单费用呈几何级数膨胀。我那次凌晨事故的根因就是这个。单个 Agent 的循环只烧了 20 美元左右但并发放大之后整个账单变成了 700 多美元。所以我才下定决心必须把看门狗和熔断器做在编排器层面而不是寄希望于每个 Agent 自己足够聪明。失控类型典型表现成本特征检测难度语义循环同一上下文反复重试线性增长单任务持续消耗 token中需要语义相似度判断工具副作用循环重复调用副作用工具线性增长同时对数据环境造成污染高需要分析调用链模式并发放大调度器不断创建替代任务几何级数增长最快造成账单爆仓中依赖任务级超时与熔断联动这三类失控是串联出现的单个 Agent 的循环是导火索调度器的替代机制是催化剂最终酿成账单事故。所以保护设计不能只做单点必须在编排器层面形成一套完整的监测-熔断-降级链路。2. 运行时看门狗从心跳上报到配额强制回收看门狗不是一个新的概念嵌入式系统里早就用它来检测程序跑飞Linux 内核也有硬看门狗。但在 AI 提示流编排器这个场景里它的职责要更具体既要监测任务的死活也要管住任务的花销。一句话总结就是——不判断对错只判断生死和预算。2.1 看门狗的工作边界它不需要理解 Agent 在干什么这是我在设计之初最容易犯错的地方。最开始我想让看门狗聪明一点比如去分析 Agent 的输出质量、判断它是不是在往正确方向逼近。结果发现这完全走错了路——判断输出质量是一个语义问题需要引入额外的裁判模型成本和复杂度都不可接受而且裁判模型自身也可能陷入循环。后来我把看门狗的职责收敛到了两件事上探活和配额。它不关心 Agent 输出内容对不对只关心两件事任务是否还在按期上报心跳、任务消耗的预算是否超限了。这个定位非常重要它让看门狗的逻辑变得简单、可靠、可测试而且不依赖任何模型推理能力。打个比方看门狗就像大楼里的安保系统它不做这个访客是不是有恶意的判断它只检查访客有没有按时在登记簿上签到、手上的门禁卡权限是否还有效。至于访客进去之后干了什么那是别的手段去管的事。2.2 心跳上报与超时判定节奏感是设计的核心心跳机制是看门狗的骨架。每个由编排器派发的节点Agent、工具调用、检索节点都算需要在上报周期内向看门狗发送心跳消息。上报的内容我不建议只放一个时间戳那样后期排查问题时信息太少了。我在项目里的心跳消息包含了这几个字段{ node_id: agent-doc-parser-001, run_id: task_88723, status: running, timestamp: 1717583023456, context_size: 256000, api_calls: 42, estimated_cost_usd: 3.27 }context_size是为了观察上下文是不是在异常膨胀api_calls和estimated_cost_usd是为了让看门狗在不依赖外部计费系统的情况下就做出配额判断。超时判定要特别注意节奏设计。我见过不少系统把心跳间隔和超时阈值两个参数混为一谈结果要么误杀多要么保护慢。我的经验是超时阈值至少要是心跳间隔的 3 到 5 倍。比如心跳间隔 5 秒那么 25 秒内没收到心跳才判定失联这样即使网络抖动也不会误杀正常的任务。更合理的做法是让每个节点类型有自己的配置后面第 4 章会讲我为这个吃了多大的亏。核心的超时检查逻辑不需要太复杂一组定时扫描就能实现def scan_watchdog(self): now time.time() for node_id, info in self.nodes.items(): elapsed now - info.last_heartbeat timeout self.timeout_for(node_id) if elapsed timeout: self.freeze_node(node_id, reasonheartbeat_timeout) if info.estimated_cost_usd self.budget_for(node_id): self.freeze_node(node_id, reasonbudget_exceeded)这段扫描每隔一个心跳周期执行一次O(n) 的时间复杂度在几千个并发节点的场景下也完全够用。2.3 令牌桶成本配额在调用大模型前就算好账单上限心跳机制管的是任务还活着吗配额机制管的是这个任务还烧得起吗。我把成本配额做成了一个类似令牌桶的机制但桶里装的不是请求次数而是美元金额。任务启动时编排器根据任务类型分配一个预算额度比如这个文档解析任务最多花 5 美元。每次 Agent 发起一次模型调用之前调度层会先做一次预估值计算模型输入 token 数乘以输入单价加上预估输出 token 数乘以输出单价得出本次调用的预估费用然后从令牌桶里预扣。如果桶里的余额不够这次调用会被直接拦下来触发配额熔断。为什么用预估而不是等账单出来因为 API 计费是异步的真实账单可能要等几分钟甚至几小时才回来。等你看到账单再熔断Agent 早就把额度烧穿了。预估值可能有偏差但方向是对的——我们要的不是精确记账而是防止账单爆炸。def try_charge(self, node_id, input_tokens, max_output_tokens, model): unit_price self.model_pricing[model] estimated_cost input_tokens * unit_price.input_per_1k / 1000 \ max_output_tokens * unit_price.output_per_1k / 1000 if self.buckets[node_id].remaining estimated_cost: raise QuotaExceededError(node_id, estimated_cost) self.buckets[node_id].remaining - estimated_cost return estimated_cost不同的模型要维护不同的单价配置。我见过有人把 GPT-4 和廉价小模型的单价写死在一起结果配额熔断完全失效。这里放一个我在项目里的简化配置参考模型输入单价美元/百万 token输出单价美元/百万 token旗舰模型 A3060中型模型 B515小型模型 C0.51.5任务在运行过程中可能切换模型所以配额计算必须以每次调用实际使用的模型为准不能在任务启动时一次性锁死。2.4 超限后的强制回收冻结、降级与终止的三级处理看门狗发现异常后不是所有情况都要直接掐死任务。一刀切地终止会导致很多本可以恢复的任务被误伤而且任务终止后如果需要恢复重新开始的成本可能比预算还高。我的项目里把处理动作分成三级冻结Freeze暂停任务的推进不允许再发起新的模型调用或工具调用但保留任务的完整上下文和状态。通常用于疑似超时或者预算接近临界值的情况等待人工检查或者降级策略的介入。降级Degrade将当前节点的输出替换为结构化的错误信号让流程编排器走降级路径。比如文档解析失败时不重试直接把原始文本塞进raw_text字段让后续节点决定如何处理。这避免了某个节点失败导致整个任务重来的连锁反应。终止Terminate确认任务已经陷入不可恢复的状态比如熔断器触发彻底终止任务释放所有占用的资源并记录完整的现场快照用于事后分析。我在代码里用了一个WatchdogAction枚举来管理这三级的决策。决策依据是看门狗两个信号的综合判断如果只是心跳超时优先冻结如果预算已经超限 140% 以上直接终止如果熔断器已经触发无论心跳是否正常一律终止并降级。这个三级处理的顺序很重要先冻结再尝试降级最后才终止。很多人在设计时上来就终止结果那些只是网络抖动了一下的任务全部被误杀了用户投诉率飙升。记住看门狗的目标不是惩罚失控的 Agent而是以最小的代价避免最大的损失。3. 死循环熔断器状态机、特征识别与半开恢复看门狗管的是生死和预算但有一个场景它管不了任务明明还在心跳预算也还没超限但它的行为模式已经明显是在死循环里打转了。这个时候就需要熔断器出场。熔断器和看门狗的关系就像急诊科医生和体检中心的关系——体检发现指标异常但真正要做决定时还得靠急诊。实际设计里看门狗负责采集数据熔断器负责基于模式识别做出掐断的决策。3.1 循环识别的三个信号重复动作、状态哈希不变、频次越界熔断器的核心难题是怎么区分正常的多次尝试和死循环我的方案是综合三个信号来打分任一信号达到阈值就触发熔断。信号一重复动作对。维护一个滑动窗口记录窗口内所有(agent_id, action_name)动作对的出现次数。如果同一个动作对在窗口内出现超过阈值比如 6 次就认为存在循环倾向。这里的动作对要包含工具名和关键参数比如(agent_parser, call_db_write)而不是只记(agent_parser, tool_call)否则粒度太粗正常的多种工具轮换调用也会被判为重复。信号二状态哈希不变。这是最有效的信号也是实现起来最需要小心的。把 Agent 当前的关键状态做结构化提取然后计算哈希。关键状态包括三部分当前目标、已尝试的动作序列摘要、最近一次工具返回结果的摘要。注意不能把完整上下文拿去做哈希因为模型每轮返回的内容都会有细微差异哈希值永远不同就失去了意义。我实现的时候是这样的在每次 Agent 决定下一步动作之前把上述三个结构字段序列化成 JSON算一个 SHA-256。然后看连续 N 次动作的状态哈希是否完全相同。如果完全相同说明 Agent 在同一个状态里反复打转这是语义循环的铁证。def state_signature(self, agent_ctx): payload { goal: agent_ctx.goal_id, action_seq: agent_ctx.action_history[-5:], last_result: summarize(agent_ctx.last_tool_result), } return hashlib.sha256( json.dumps(payload, sort_keysTrue).encode() ).hexdigest()信号三频次越界。纯粹的频次统计比如同一个 Agent 在 60 秒内发起了超过 30 次模型调用。这个信号最粗暴但也最不容易误判因为它要求的是绝对次数而不是模式的相似性。对于那些上下文变化很快、哈希信号失效的循环比如不断拼接新文本再送回去频次越界是最后的兜底防线。3.2 熔断状态机的落地closed/open/half-open 的实现取舍状态机直接借鉴了微服务熔断器的经典三态但实现上有几个针对提示流场景的调整。状态定义如下Closed关闭一切正常熔断器只统计指标不干预任何请求。Open打开熔断生效所有发往该 Agent/节点的模型调用和工具调用被直接拦截返回熔断错误。Half-open半开熔断器进入试探模式放行有限数量的请求验证问题是否已经缓解。我在实现时做的最重要一个调整是Open 状态下拦截动作发生在调度层不是发生在 Agent 内部。也就是说当熔断器打开时编排器不会再调用 Agent 的执行函数而是直接返回一个CircuitOpenError。这样即使 Agent 自身的代码再怎么失控也无法产生实际的 API 调用和工具副作用。另一个取舍是计数窗口。我选择了滑动时间窗口而不是全局计数器。全局计数器的问题是历史积累太久一个正常运行了几小时的任务重试次数可能自然就超过了一个本来合理的阈值。而滑动窗口只关注最近一分钟内的行为更符合死循环的短时爆发特征。class CircuitBreaker: def __init__(self, threshold6, window_seconds60): self.threshold threshold self.window deque() self.state closed def record_failure(self, signature): now time.time() self.window.append((now, signature)) while self.window and now - self.window[0][0] self.window_seconds: self.window.popleft() recent [s for _, s in self.window] if len(set(recent)) 1 and len(recent) self.threshold: self.state open3.3 熔断后的降级策略宁可返回失败也不放火烧山熔断不是目的降级才是。当熔断器打开后编排器拿到CircuitOpenError需要知道该拿它怎么办。我在项目里为熔断错误设计了独立的错误类型和元数据这样上层流程可以区分模型返回错误工具调用错误熔断保护错误。三类错误的处理路径完全不同。模型错误可以重试或换模型工具错误可以标记该工具故障后续任务跳过它而熔断保护错误说明当前 Agent 的执行策略出了问题此时最合理的降级策略通常有三个选项跳过该节点把流程推进到下一个节点并在最终结果里标注此部分内容未完成原因循环保护熔断。使用缓存结果。如果熔断的节点之前曾经成功输出过相似结果直接用缓存顶上。整条流程终止但保留已完成部分的结果不重新执行。毋庸置疑绝不能做的是熔断后过一会儿再重新执行同一个 Agent——那样熔断就失去了意义十几分钟后它又会开始烧钱。这里也提醒一点熔断器的打开状态要持久化到编排器的状态存储中不能只存在于内存里。否则编排器重启后熔断状态丢失等于白熔断了一半。3.4 半开恢复只放一个请求进来试探熔断器不能一直打开否则一个临时性的问题可能导致某个 Agent 永远不可用。所以需要半开状态来试探。我的实现策略比较保守进入半开状态后只放行一个测试请求等它完整执行完成功或者失败再决定状态转换。为什么只放一个而不放一小批因为试探的目的是验证死循环的问题是否已经消除而不是验证这个 Agent 是否能用。一个请求如果成功并正常收敛说明循环条件已经不存在可能是外部依赖恢复了也可能是参数变了可以关闭熔断器如果这个请求依然在重复动作、哈希不变那就立刻回到 Open 状态并且把熔断时间延长——指数退避比如 10 秒、20 秒、40 秒。我在项目里给熔断器的每个状态都打了结构化日志。Closed-Open 要记录触发信号的具体值重复动作对是什么、哈希出现过几次、频次多少Open-Half-open 要记录休息了多久Half-open 试探的结果也要留档。这些日志在事后排查时是救命稻草第 4 章会展开说这个坑。4. 开源集成踩坑实录三个让看门狗失灵的典型案例设计看起来合理代码也写完了但真正集成到开源项目里跑生产流量的时候我连续踩了三个大坑。每一个都让我意识到保护机制本身的可靠性和业务代码的可靠性同样需要严格审视。下面这三个案例都是我真实遇到过的花了不少时间排查。4.1 心跳间隔太死板长任务被误杀项目里有一个文档批量解析的 Agent单个文档的解析时间有时长达 90 秒。我最初给所有节点配置了统一的心跳间隔 5 秒、超时阈值 15 秒。结果上线第一天这个文档解析 Agent 被看门狗连续冻结了二十多次每次冻结都导致解析任务半途而废产量骤降。排查过程很典型先看日志发现所有冻结记录都集中在文档解析节点报错原因清一色是heartbeat_timeout。再看心跳上报日志发现 Agent 并不是没有上报而是每 10 秒上报一次但单次解析的内部计算耗时超过了 15 秒导致相邻两次心跳的时间差超过了阈值。当时我的第一反应是把超时时间调到 30 秒但这只是治标。真正该做的是让心跳参数变成节点类型可配置的。文档解析节点的计算密集度高、单步耗时自然长它的超时阈值应该按单步最大耗时 x 3来定而在线问答节点延迟要求高阈值反而应该更短。最后我把超时配置改成了按节点类型下发并支持任务级覆盖这个问题才彻底解决。经验是心跳参数永远不要全局统一至少按计算密集型和I/O 密集型两类区分。在真实系统里文档解析、视频处理等长耗时任务非常正常过短的超时阈值会把好任务当坏任务杀掉造成大量无效冻结和恢复开销。4.2 重试收敛被误判成死循环阈值需要看真实分布第二个坑更加隐蔽。我在设计熔断器时把重复动作对的阈值直接设成了 3理由是同一个动作重复 3 次肯定有问题吧。结果上线后多个正常的智能体流程被熔断用户反馈Agent 总是中途停止工作。查日志发现一个规律很多 Agent 在调用一个外部搜索工具时前两次返回的结果质量不高第三次重试才拿到理想结果然后任务就正常继续了。这类2 到 3 次重试后收敛的模式在真实流量里非常普遍。我设置的阈值 3 等于把所有需要 3 次重试才能成功的任务全部误杀了。这个坑的本质是我把设计时的拍脑袋阈值用在了生产环境而没有先统计真实分布。解决方案是先用两周时间收集所有任务中重复动作对的分布数据然后画分位数。最终发现 95% 的正常任务中同一动作对在一个 60 秒窗口内不会超过 5 次超过 6 次的几乎都是死循环。于是我把阈值改成了 6误杀率从 9% 降到了 0.4% 以下。如果你也想抄这个参数我的建议是先从 5 到 6 起步用一段时间的真实数据校准而不是相信任何人的标准值。4.3 熔断记录缺乏现场信息排查时两眼一抹黑第三个坑出现在真正需要排查问题时。某次线上事故一个 Agent 被熔断了我打开日志想看看它到底怎么循环起来的结果发现日志里只有三行熔断器触发、触发信号是signature_repeat、熔断节点是agent-x。至于这个 Agent 在循环前做了什么、哪次工具调用开始变得不对劲、上下文是什么时候开始重复的——完全没有记录。那一次我花了整整一个下午模拟各种可能的输入去复现循环最后也没能完全还原当时的执行路径。从那次以后我给熔断记录加了一个现场快照的字段记录的内容包括{ circuit: agent-x, trigger: signature_repeat, window_counts: {action_pair: 7, signature_equal: 5, frequency: 12}, recent_context_summary: 解析任务第 4 轮模型输出包含 23 个实体与上一轮输出 19 个实体不匹配, recent_actions: [extract_entities, validate_schema, retry_with_enhanced_prompt], token_usage: {input_tokens: 280000, output_tokens: 41000, estimated_cost: 4.2}, full_trace_id: trace_8f31a2c }有了这些记录排查效率提升了一个数量级。每次熔断都带着完整上下文我可以直接定位到是哪一步产生了循环信号甚至能把失败现场做成一个回归测试用例喂给 mock 环境复现。如果你在设计自己的熔断器我强烈建议在实现熔断功能的同时就把现场快照做进去不要等出事了再补——出事后补的往往是最难补的。5. 验证方法与参数调优怎么证明保护机制真的有效如果你认真做了上面这些设计下一步就是验证。不能只在心里觉得应该有效需要用可控的故障注入测试把保护机制的响应能力量化出来。这也是我在开源项目里对每个 PR 的要求任何对看门狗或熔断器的改动都必须附带故障注入测试结果。5.1 故障注入用可控的循环来检验熔断器我的做法是构造一个特殊的测试 Agent它支持两类故障模式一种是固定重试 N 次后进入死循环用于精确测试熔断器在多少次动作后触发另一种是每次工具调用都返回相同结果用于测试状态哈希不变信号的检测能力。测试跑起来之后再配合一个 mock API 来模拟模型响应这样既不会产生真实费用又能完全控制响应行为。测试断言至少包含三条熔断器必须在预期时间内触发触发后不能有新的 mock API 调用产生整个测试过程中预估费用不能超过预设预算。这个测试我会挂在 CI 里每天跑一次防止哪天改动看门狗代码时不小心破坏了保护链路自己还不知道。5.2 关键指标与测试数据熔断响应时间、误杀率、恢复成功率我建议每个部署了保护机制的项目都持续统计三个核心指标熔断响应时间从循环开始到熔断器打开的时间差这个指标决定了烧钱时间的上限。误杀率非循环任务中被熔断的比例。这个指标衡量的是保护机制的误伤程度太高说明参数过严。恢复成功率半开试探后成功关闭熔断器的比例反映的是熔断器在给系统第二次机会这件事上的准确度。我拿一组实际测试数据举个例子用的是一个小型文档解析任务mock 模型模拟了各种响应场景熔断阈值误杀率平均熔断响应时间恢复成功率3 次重复9.2%6.8 秒61%5 次重复2.1%12.5 秒78%6 次重复0.3%15.3 秒83%阈值越低响应越快但误杀率越高。阈值越高误杀越少但烧钱时间越长。对大部分场景我建议以误杀率不超过 0.5% 为底线去选参数钱可以多烧几秒钟但正常任务不能被误伤。5.3 初始推荐参数表与动态调整思路如果你现在想在自己的项目里实施这套机制可以先套用下面这组我调过的参数运行两周后根据真实数据再修正参数初始建议值说明心跳间隔5 秒计算密集型节点可调到 10 秒心跳超时阈值心跳间隔 x 5宁长勿短避免误杀重复动作对阈值6 次 / 60 秒基于 P95 分布校准状态哈希连续不变阈值5 次语义循环的核心信号单 Agent 模型调用频次30 次 / 60 秒兜底信号与模型调用次数相关成本令牌桶初始额度任务预估成本的 2 倍预留波动空间不能收紧到 1 倍熔断器半开试探请求数1 个最保守的方案安全性优先熔断恢复的退避时间10 秒起指数退避每次打开后翻倍上限 300 秒这些参数不要一劳永逸。我在项目里加了一个简单的运行时统计模块每隔 24 小时自动计算最近 7 天的重试分布和任务耗时分布生成参数调整建议。倒不是要全自动调参——AI 系统的行为模式变化太快全自动容易出意外——而是把趋势展示出来让我自己决定要不要调整。结合实际的工程经验还有一个调整思路值得说熔断器和看门狗的参数要跟任务类型绑定而不是全局统一。比如低价值高频率的小任务如标题生成参数可以设得更激进宁可误杀也不让烧钱高价值低频率的深度分析任务如长文总结参数要更宽松给足重试空间。把参数做成任务级覆盖而不是全局配置保护机制的实用性和灵活性会有质的提升。开头我提到的那次凌晨事故现在的系统里已经不可能发生了。因为就算某个任务又开始循环看门狗会在 15 秒内发现心跳异常或者预算超限熔断器会在 30 秒内基于重复信号切断调用链叠加上并发放大限制最坏情况也不会超过一杯咖啡的钱。这个项目的开源版本里目前已经内置了这套看门狗和熔断器的完整实现欢迎大家拿去用或者直接读源码找问题。我的建议很简单别把 Agent 当聪明人来信任要把它当一个能力很强但偶尔会冲动的小孩——你可以给它很大的裁量权但必须在它伸手摸到信用卡的时候雇佣一个可靠的保镖站在旁边。