子代理只有深度上限、没有广度/预算上限:一次会话产生 146 个子代理会话、3.43 亿缓存读取(占我全部历史 62%) #6574
bluechips-zhao
started this conversation in
Ideas
Replies: 1 comment
|
应该只认工作区根目录的AGENTS.md,并控制dsh不能写入它,不然的话很容易被提示词攻击啊 |
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
摘要
maxDepth的递归深度限制是正常工作的(默认 3,我实测确认它生效了),但子代理的"广度"和"总委派预算"完全没有约束。一次"学习一个 zip 文件"的请求,最终扇出成 跨 3 个深度层级的 146 个会话,消耗 343,067,904 缓存读取 token——占我全部会话历史 token 的 62%。两个放大器:
环境
web-desktopdeepseek-flash(100 万上下文窗口)session-9b11f623-af36-4254-8368-216ac5f49189"<workspace>\local.zip",来学习一下这个(25 MB 压缩包)实测影响
父会话
surfaceTokens)subagent工具调用次数委派树
占全部历史比例:该 profile 下 148 个会话合计 550,412,800 缓存读取 → 本次事件占 62.3%。
最贵的单轮:turn 11 —— 一轮 39,109,120 缓存读取(110 步,每步都重新提交约 50 万 token 的上下文)。
做得对的地方(应当肯定)
maxDepth确实被强制执行。dsh-tool-subagent第 269 行:dsh-subagent/lib/types/depth.js会拒绝任何解析出的、超过上限的子深度。与此一致,实测那棵树停在深度 3,深度 4 的会话数为 0——递归预算确实起了作用。我要反馈的不是递归深度问题。缺口 1 —— "广度"没有任何上限(每父的子代理数 / 全树总量)
每次
subagent调用产生一个子代理。没有任何机制限制一个父代理能启动多少个、能并发多少个、或全树累计能有多少个。本次一个父代理直接启动了 26 个子代理,而其中若干子代理又各自启动了 3–17 个:807b0995dcaab4a2fa6f208d71cc34405a992da8e467bf5b73647e78没有任何一层知道全树的实际规模——每个子代理都是独立决定继续往下委派的。深度上限为 3,理论上允许
26 × 54 × 65个会话,而下限没有任何天花板。建议修复:引入全树统一的委派预算(每会话最大子代理数、最大并发子代理数、每棵树最大委派总数),在 spawn provider 调用处强制执行,并向父代理返回明确的拒绝原因。
缺口 2 —— 结算通知逐个下发,导致父代理成本随子代理数量线性增长
dsh-subagent/lib/types/continuation-messages.js(第 85–101 行)为每一个结算的子代理单独构造一条消息:每一条都会被注入父代理作为 user message,并唤醒父代理开启新一轮。当父上下文已达 50 万 token 时,每一条通知的代价都约等于 50 万缓存读取。我的转录里有约 40 条此类通知(其中约 15 条是
failed before it finished),每一条都是一次完整的全上下文请求——失败通知和成功通知一样要父代理付全价。正是这个乘数把"26 次委派"放大成了"数十次 50 万 token 的父请求"。
建议修复:把结算通知合并成一次唤醒一条汇总(或在短时间窗内去抖),并确保失败通知不会各自触发父代理的一轮。
缺口 3 —— 额度耗尽未被当作不可恢复失败
turn 2–12 均以
{"kind":"error","code":"QUOTA","status":402}(Insufficient Balance)结束。dsh-goal-round-driver在agent/error时确实会 disarm(这个设计是对的),但它的turn/end处理只特判了max-tokens和aborted:QUOTA是终态、不可重试的错误,却没有阻断 goal。本次运行中 goal 被反复重新武装(自动续跑了 3 轮)外加多次错误轮。建议修复:把终态类 provider 错误(
QUOTA、鉴权失败、模型非法)归类为 goal 阻断,带blockedReason代码,让 driver 停下而不是继续排队。缺口 4(促成因素)—— 解压产物中的内容被当作代理指令加载
该 zip 内含有
AGENTS.md。解压后它们被作为工作区指令加载(Additional instructions from: <extracted-dir>\skills\reverse\AGENTS.md),把任务从"看看这个包"改写成"完整榨取 409 个 SKILL.md 与 367 万行字典"。随后代理自行调用了create_goal,maxGoalRounds: 12—— 用户从未提出这些要求。我理解对工作区指令文件的这种处理可能是有意设计。如果是,那么建议:把来自解压/下载归档的内容按数据对待,而非指令;或者在采纳"归档内发现的指令文件"之前要求显式确认。这是在任何委派行为发生之前,把一个小请求变成大请求的那一步。
最小复现
SKILL.md类文档,并嵌入一个AGENTS.md。"<zip 路径>,来学习一下这个"。AGENTS.md成为指令 → 代理自行创建多轮 goal → 出现大规模并行委派波次 → 每个子代理还可能继续往下委派。数据可得性
以上所有数字均可从本地会话存储复现:
<DSH_HOME>/sessions/<workspace>/<session-id>/session.v3.jsonl.zstd(多帧 zstd —— 需逐帧解压)<DSH_HOME>/storages/session_projcache/sessions/<session-id>.json如果需要,我可以提供解压后的转录,或一个小脚本,从
subagent/catalog事件中提取每轮usage.cacheReadTokens与委派树。All reactions