多智能体系统如何防止死循环失控?Orkas四重运行守卫与loop_detection完整实现剖析
【免费下载链接】OrkasOrkas is an open-source, local-first AI desktop app: a commander LLM directs specialist sub-agents, and runs your installed coding CLIs — Claude Code, Codex, OpenCode, OpenClaw, Hermes — as local sessions. Agents self-evolve via reflection and skill crystallization. BYO keys. macOS / Windows / Linux.项目地址: https://gitcode.com/gh_mirrors/or/Orkas
Orkas 是一个开源、本地优先的多智能体 AI 桌面应用:由指挥官(Commander)模型统一调度专家子智能体,还能把 Claude Code、Codex 等编码 CLI 当作本地会话来驱动。多智能体系统的头号隐患是"死循环失控"——模型可能反复发起同一个工具调用、或看似在忙却毫无进展,白白烧掉 Token。本文将完整剖析 Orkas 内核中loop_detection的四重运行守卫机制,看看它是如何做到"先劝返、再止损"的 🛡️。
一、为什么多智能体系统必须防止死循环 🕳️
单轮对话出不了大事,但 Agent 的"思考→调用工具→再思考"循环一旦转起来,就可能陷入两类失控:
- 原地打转:模型连续发起完全相同的工具调用(同样的文件、同样的参数),结果毫无变化却反复执行;
- 假装有进展:模型不断变换文件名、游标或搜索词,看起来每步都不同,实际上没有产出任何新信息。
前一种好识别,后一种才是真正难防的——它绕开了朴素的"重复检测"。Orkas 的核心 Agent 循环(core-agent)为此设计了一套分级、分权的守卫体系:有的守卫只"提醒",有的才能"叫停",而且叫停必须有可证明的证据,绝不误杀正常的长任务。
二、四重运行守卫总览:从"提醒"到"强制终止"
整个守卫体系由 LoopGuards 类 统一承载计数与判定逻辑,而循环本身负责消息投递与最终结果的生成。四重守卫层层递进:
| 守卫 | 触发条件 | 权限 |
|---|---|---|
| ① 精确重复检测 | 完全相同的调用连续 3 轮无变化,反馈后再 2 轮 | ✅可终止 |
| ② 近似重复检测(loop_detection) | 仅易变字段(id/时间戳)不同的调用连续 6 次 | ⚠️ 只警告 |
| ③ 进度监察员 | 连续 2 轮无新产出 / 连续 8 轮只读不写 | ⚠️ 只警告 |
| ④ 全局工具循环预算 | 超过maxToolLoops轮次上限 | ✅强制终止 |
这种"提醒"与"终止"分离的设计是本文最值得关注的思路:判定越模糊,权限越低。下面逐层拆解。
三、第一重:精确重复检测——必须有"无进展证据"才能终止 🔍
最直觉的一招:给每次工具调用算一个"签名"(toolCallSignature = 工具名 + 规范化参数),只有完全相同的调用才会撞上同一签名,因此参数有差异的正常操作永远不会误判。
但"重复"本身不等于"失控"——分页读取、轮询任务状态都是合法的重复。所以 Orkas 的终止判定建立在完成证据之上(见 repeat-evidence.ts 的completedRepeatKey):只有当一轮执行可证明没有产生任何新效果、没有读到任何新信息(文件哈希未变、无状态变更、无错误、无持久化输出)时,这一轮才计入"无变化轮次"。
阈值非常克制(loop-guards.ts):
- 连续3 轮(
LOOP_WARN)完成证据均无变化 → 向模型注入一条反馈:"同样的操作已经连续 N 轮没有产生新效果,请换一个方向;反馈后再有 2 轮无变化将终止本次运行"; - 反馈送达后再连续2 轮(
LOOP_HARD - LOOP_WARN)无变化 → 运行被终止(repetitive_tool_calls),并生成一份状态摘要交给用户,而不是静默失败。
四、第二重:近似重复检测——"改了 request_id 的重复"也逃不掉,但只警告
还有一种更狡猾的打转:调用看起来每次都不一样,其实只有request_id、nonce、timestamp这类天然易变的追踪字段在变。
loop_detection为此引入了归一化签名(normalizedToolCallSignature):按键名剔除易变字段(request_id、trace_id、created_at等,见 VOLATILE_ARG_KEY_RE),但刻意保留page、offset、id这类结构性参数——因为分页和不同目标绝不能被视为重复。
关键的设计决策在 observeProposedCalls:连续6 次(NEAR_DUP_LOOP_WARN)近似重复时,只触发一条一次性警告("你已经连续 N 次以几乎相同的参数调用该工具,建议更换目标或汇报已有进展"),绝不终止运行。源码注释里写得很直白:归一化匹配天生比精确匹配"模糊",误报必须是无害的一次性提醒,永远不能成为停止理由——这个历史教训甚至被 回归测试 固化了下来,防止有人"好心"把硬停止偷偷加回来。
五、第三重:进度监察员——抓"变换花样的空转"
对付"假装有进展"的是进度监察员(progress governor)。它不看调用长得像不像,而是对每一轮工具执行按观察到的实际结果分类(五档:productive / discovery / none / unknown / neutral):
- ProgressEvidence 依据已提交的效果判定:文件变更前后哈希是否变化、读取区间是否与之前完全重叠、流式读取的版本号是否前进——"成功返回"本身不算进展,必须有可观测的新产出或新信息;
- 连续2 轮被证明无新产出(
RUN_NO_PROGRESS_NUDGE_ROUNDS)→ 发送一次"无进展"建议; - 连续8 轮只有查找/搜索/读取类操作(
RUN_DISCOVERY_NUDGE_ROUNDS,工具白名单见 DISCOVERY_ONLY_TOOLS)→ 发送一次"探索过久"提醒。
注意两个"宽松"细节:unknown(无法判定的结果)不计入停滞计数——宁可漏报不可误报;用户中途改了指令时会重置停滞窗口,因为"进展"的定义刚刚变了。observeRoundOutcome 的返回结构里stop字段被硬编码为null:建议类守卫从架构上就不具备终止权。
六、第四重:全局工具循环预算 + 三条收敛信号
前三重管"行为",第四重管"总量":每个运行都有maxToolLoops硬上限(runner.ts),达到上限后不再执行任何工具调用,改为生成一份"已完成 / 阻塞点 / 下一步"的状态摘要交付用户。
在撞线之前还有三条渐进式收敛信号,全部通过一次性的请求级控制通道注入(convergenceSignals):
- 接近上限提醒:用到 80% 轮次预算时提醒模型"停止探索,先交付最小可用成果";
- 耗时收敛:运行超过约 8 分钟且轮次 ≥ 8,且近期无新信息 → 提醒模型检查已有结果再动手;
- 压缩打转信号:上下文压缩 ≥ 2 次且轮次预算已用 75%(典型的"上下文被摘要 → 忘记做过什么 → 重做"指纹)→ 提醒模型回到磁盘上的持久化状态重新锚定。
所有触发信号都会记录在运行结果的convergenceSignals元数据里,方便事后审计这次运行到底经历了哪些干预。
七、设计哲学:为什么"劝返"比"掐掉"更重要 🎯
把四重守卫放在一起看,能提炼出三条对任何多智能体系统都适用的原则:
- 权限与判定精度成反比——精确证据才有终止权,模糊信号只能提醒;
- 警告必须是一次性的——同一条提醒对同一"事件"只发一次(
normWarnedForStreak、noProgressEpisodeNudged等标志位),避免守卫本身变成新的噪音循环; - 干预不能污染对话历史——所有守卫消息都走请求级控制通道(
withRequestScopedControls),绝不写入持久化会话,防止"内部提醒"被模型误当成用户的新指令。
八、关键源码文件导航 📂
| 文件 | 职责 |
|---|---|
| loop-guards.ts | 四重守卫的阈值、签名算法与LoopGuards判定逻辑 |
| repeat-evidence.ts | "无变化轮次"的完成证据生成 |
| progress-evidence.ts | 按实际执行效果分类每轮进度 |
| runner.ts | Agent 主循环:守卫接入、提醒投递与终止处理 |
| agent-runner.test.ts | loop_detection 的回归测试(含"近似重复不得硬停"的锁定用例) |
| README.md | Orkas 项目总览与多智能体架构介绍 |
结语
多智能体系统不怕"慢",怕的是"看似在忙、实则空转"。Orkas 给出的答案不是更激进地掐断循环,而是一套证据分级、权限分离的守卫体系:精确证据才配得上终止权,模糊信号只配发一次提醒,总量预算兜住最后的底线。理解这套loop_detection的四重守卫,对任何正在构建自主 Agent 的开发者都是一份实用的"防失控清单" ✅。
【免费下载链接】OrkasOrkas is an open-source, local-first AI desktop app: a commander LLM directs specialist sub-agents, and runs your installed coding CLIs — Claude Code, Codex, OpenCode, OpenClaw, Hermes — as local sessions. Agents self-evolve via reflection and skill crystallization. BYO keys. macOS / Windows / Linux.项目地址: https://gitcode.com/gh_mirrors/or/Orkas
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考