扇出安全门(deep-research-gate)
任何「要不要扇出一批子 agent / 要不要开深度研究·工作流」的时刻,先读这里、按这里走。
它管两件事,别搞混:① 该并行的有界任务放行别缩;② 会失控放大的深度研究/工作流焊死,要开得经用户同意。
〇、先分清两类扇出(决策从这里开始)
危险的从来不是「子 agent 多」,是「扇出会不会失控放大」。先对号入座:
| 🟢 绿灯·有界并行 | 🔴 红灯·无界/递归/工作流 | |
|---|---|---|
| 数量 | 已枚举、算得出上界(N 个明确子任务) | 不可预知,子 agent 自己决定要不要再扩 |
| 成本 | O(N) 封顶,事前算得出 | 失控放大,事前算不出上界 |
| 任务性质 | 执行已交代清楚的事(模拟 / 只读核验 / 已定的批处理) | 开放式调查:自己去查清某课题、查多深由它定 |
| 递归 | 不递归,子 agent 是叶子 | 子 agent 内部还会再派 / 触发 deep-research / 跑 workflow |
| 怎么办 | 直接并行,不必问、不必缩——串行才是错 | 走 §三 开闸流程 + 经用户同意 |
判据三问,任一为「是」→ 红灯:
- 数量算不出上界?(子 agent 自己决定要不要再派、要查多深)
- 会递归?(子 agent 内部还会再派 agent / 触发 deep-research / 跑 workflow)
- 是开放式调查?(任务是「自己去查清楚某课题」,而非「执行已交代的一件事」)
绿灯典型:「M 个配置 × N 个场景 = 一批模拟」这类——并行单元天然可枚举,靶子与流程全部冻结、零调查、不递归。正确做法是一次全部并行,硬拆成串行是纯浪费。 红灯典型:某个子 agent 为核实一个数据点,自行触发了深度研究,在内部再扇出一整层子 agent。
一、为什么需要这道门(失控是怎么发生的)
单个子 agent 之所以能把整个账号配额打穿,靠的是两层机制叠加,缺一不可:
- 子 agent 默认拿到全权限。 派研究/检索类子 agent 时若不显式指定类型,它默认是通用 agent——手里有完整工具集,能递归再派 agent、能自己触发深度研究 / 工作流。主线程以为自己只派了几个助手,实际上每个助手都能再开一整层。
- 工作流引擎负责放大。 深度研究与大规模递归 fan-out 都由动态工作流引擎驱动。一次触发就可能在内部展开成整层子 agent 与大量工具调用,token 消耗与主线程的预期完全脱钩。
再叠加第三个条件,就会从「贵」变成「静默地贵」:
- 若权限模式配置为跳过确认弹窗,上述触发全程无人拦截——没有弹窗、没有询问,等发现时配额已经见底。
后果形态:一次本该廉价的核查,可以在很短时间内把剩余配额打满并锁死账号,连带打断的是之后所有本可以正常进行的工作。无人值守时段触发尤其致命,因为没人来得及叫停。
根因落点要认准:炸配额的是子 agent 权力过大(能递归、能自开深度调查)+ 工作流引擎放大,不是「主线程派了一批子 agent」这个动作本身。主线程并行派一批有界子 agent 从来不是问题——别从这类事件里学错教训、连累正常并行。
二、硬防护(只焊 workflow 引擎,不碰普通并行)
在 ~/.claude/settings.json 配置:
"disableWorkflows": true,
"workflowKeywordTriggerEnabled": false
disableWorkflows: true—— 引擎级关掉「动态工作流」(深度研究和大规模递归 fan-out 全靠它)。这是开关、不是弹窗:所以「跳过确认」类权限模式吞不掉它、子 agent 也绕不过。触发时当场被拒、零 token 消耗。workflowKeywordTriggerEnabled: false—— 关掉「关键词自动触发工作流」(默认是开的,prompt 里带上特定关键词就会升级成工作流,是隐患入口)。
作用域必须说清(否则会误伤并行):这两个开关焊死的是动态工作流引擎——即深度研究 / 大规模递归 fan-out 的总闸。它管不到、也不该管主线程普通的 Agent 并行调用:🟢 绿灯那种宽度并行根本不经过工作流引擎,这开关对它零影响。所以「开关开着」绝不是「不准并行派 agent」的理由。
三、红灯任务标准流程(开闸 → 跑 → 关闸)
仅当 §〇 判为 🔴 红灯时走这里。🟢 绿灯不经过本节,直接并行。
- 先确认值不值:深度研究一发的代价,是数量级高于普通检索的 token 与时间,且事前算不出上界。先问用户:这次确实要这种重型深挖吗?普通几轮检索 / 几个只读搜索 agent 够不够?够就别开工作流。
- 开闸(临时):把
~/.claude/settings.json里disableWorkflows改成false。 - 跑:执行深度研究,全程盯着,别让它失控扩散。
- 关闸(必做,绝不能忘):跑完立刻把
disableWorkflows改回true,重新焊死。绝不把它留在「开着」的状态过夜——无人值守时的静默触发就是这么发生的。
配置改动即时生效、对所有会话生效(无需重启)。
四、忘记关闸 = 最大残余风险(结构性漏洞,必须当回事)
整个开闸机制的安全性,跨会话可以靠钩子自动兜底(见下),但同一会话内仍完全押在「人不会忘记关闸」上——这是当前最危险的薄弱点:
- gate 一旦改成
false,靠「记得改回来」维持。但会话是阅后即焚的:开闸的会话一旦中断、或人中途走开,gate 就留在开着的状态过夜,正好复刻「无人值守时静默触发」的这类事故。 - 所以纪律:开闸与关闸尽量在同一会话内闭环,关闸先于「报告结果」这一步;能不开就不开(普通几轮检索顶得住,就别开闸)。
兜底机制(强烈建议落地):挂一个 SessionStart 自检钩子——新会话启动时若发现 disableWorkflows 不是 true,立即焊回 true 并告警(说明上一会话忘了关闸)。逻辑只有三步:读 ~/.claude/settings.json → 判断该键 → 不是 true 就改回并打印告警。落地后,「无人值守时静默触发」这条这类事故路径就被堵住了:静默/自动触发也要先经过会话启动,钩子先于任何 Workflow 生效。
但覆盖范围有限,别把它当免罪符:
- 它只在「下一个会话启动」时补救。开闸的当前会话内忘了关,闸就一直开着,钩子不会中途介入。
- 它只在 Claude Code 侧生效——其他运行时没有等价的会话启动钩子,也没有
disableWorkflows这个引擎级开关,关闸完全靠纪律。
所以上面那条纪律不变:开闸与关闸在同一会话内闭环,关闸先于「报告结果」。
五、永久铁律(防复发,每次扇出都守)
- 派「查资料 / 检索 / 调查」类子 agent,一律显式指定只读搜索类型(如
subagent_type: "Explore")。只读搜索 agent 手里没有 Agent / Skill / Workflow 工具,物理上扇不出去、也触发不了深度研究——这一条同时根治了「子 agent 权力过大」。绝不让研究 agent 默认成通用全权限 agent。这是真正的安全闸,优先级最高。 - 深度焊死在 1 层 = 宽度安全的前提。 只允许主线程这一层扇出;任何子 agent 都是叶子,不得在内部再派 agent / 调深度研究 / 跑 workflow。深度锁死在 1 层,宽度再大也只是 O(N) 可控——所以 🟢 绿灯的宽扇出才安全,放心并行。失控的从来是「深度递归」,不是「宽度」。
- 「一个顶仨、能少则少」只约束开放式调查/检索的扇出——每多一个调查 agent 就多一份不可控成本。它不约束有界执行:已枚举的批量模拟 / 只读核验,该并行就并行,硬凑成串行反而是错。
- 会话变巨长就开新会话、拿文件交接——长上下文每轮都在复利烧 token。
六、一句话总结
有人说「深度研究 / 开工作流」时,不是让你立刻 fan-out——先到这儿,认清代价、走开闸、跑完立刻关闸。
但要你并行派一批有界子 agent时(任务已交代清、不调查、不递归),别畏手畏脚:那不是深度研究,该并行就并行,搞成串行才是失职。
两件事别搞混:放行该放的,焊死该焊的。