[Bug] goal-round-driver 无时间节流:轮次按「回合结束」触发,等待外部时钟的目标会在分钟级耗尽 maxGoalRounds 预算 #6169
GuyueHermit
started this conversation in
General
Replies: 0 comments
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.
English TL;DR —
goal-round-driveris triggered byagent/status → idleand immediately callsagent.followup()for the next round. There is no time-based pacing anywhere in the driver (grep forsetTimeout|sleep|delay|throttle|debounce|backoff|Date.now|elapsedreturns nothing). For an objective whose completion depends on wall-clock time (e.g. watching a multi-day experiment on a remote host), every short turn burns one round, somaxGoalRoundsis consumed in minutes. When the budget runs out the driver terminates the goal viactx.goals.block(..., code: "round-limit"), i.e. a budget exhaustion is recorded asblocked. Related but distinct: #6123.现象
一个需要等待外部时钟的目标(监控远端服务器上为期约 7 天的实验),
maxGoalRounds: 40:第二轮同样如此:新建 goal(
maxGoalRounds: 30)后,几分钟内又推进了 8 轮,全部是"检查状态 → 无变化 → 再等"。也就是说:当目标被外部时钟阻塞时,轮次预算不是按"有进展的工作单元"消耗,而是按"回合结束"消耗,模型跑得越快,预算烧得越快。
环境
0.1.5-rc.1,profilewebdeepseek-official/deepseek-flash根因
1) 驱动没有任何时间节流
packages/goal/goal-round-driver/src/index.js(lib/index.js同构):对
dsh-goal-round-driver/lib/index.js搜索setTimeout|setInterval|sleep|delay|throttle|debounce|backoff|cooldown|Date.now|performance.now|wall|clock|elapsed|minInterval|rate→ 零命中。驱动对"回合"与"时间"没有任何关系式。
轮次节奏 == 回合节奏。一个只需要"看一眼、没变化、说一句"的回合(本例中约 8–17 秒)就等于消耗一轮。
2) 轮次提示词本身在推动空转
renderGoalRoundPrompt()生成的固定文本里有:当目标被外部时钟阻塞时,"remains" 永远为真,于是每一轮都被指示"继续",而能做的最多只是轮询一次。提示词与机制在此类目标上互相加强,没有任何一处提示"本轮没有可推进的工作"是一种合法结果。
3) 预算耗尽被记成
blocked目标最终落在
phase: "blocked",blockedReason.code === "round-limit"。但"轮次额度用完"不是阻塞条件,而是预算耗尽;这会污染 blocked 的语义与统计(与 #6123 的第 3 点同源)。4) 模型侧没有合法出口
packages/goal/tool-goal/src/authority.ts:pause/resume需要requireDirectHuman;自主轮次里只剩complete与blocked。complete:目标没达成,不能用。blocked:策略明确禁止——"difficulty, uncertainty, or useful remaining work is not blocked";"等待墙钟时间"也不属于"连续 ≥3 轮存在的具体阻塞条件"。于是模型明知只剩等待、也无法体面停下来,只能让轮次空转到额度耗尽。这一点与 #6123 提出的"自主轮次缺少非 blocker 收尾出口"是同一个结构问题,但 #6123 的症状是"伪造 blocked 理由",本贴的症状是"无法停止空转、预算按回合速度烧完"。
影响
blocked收尾,用户读到的原因是"达到轮次上限",容易被误认为真的出了问题。建议修复
A(针对性,最小改动):给 goal 增加可选节流,例如
minRoundIntervalMs(或让驱动在排队下一轮前await一个基于目标配置的延迟)。这样"每 10 分钟看一眼"可以直接表达,而不必靠把maxGoalRounds设得很大来对冲。B(结构性):引入一个一等公民的"等待外部事件/时钟"状态(
park/waiting),特征:phase: "blocked",不计入 blocked 语义与统计;C(廉价兜底):预算耗尽时不要复用
blocked,给一个独立的终止原因(如code: "round-exhausted"/phase: "exhausted")。D(可选):对"零副作用回合"做退避。如果一轮内没有产生任何工具副作用、也没有改变任何持久状态(本例中每轮只有一次只读查询),驱动可以指数退避而不是立即续轮。这不需要理解目标语义,只需要看回合是否留下了痕迹。
补充
本贴所有结论都对照
@deepseek-ai/dsh@0.1.5-rc.1的已发布产物核实过(node_modules/@deepseek-ai/dsh-goal-round-driver/lib/index.js的行号即上文引用行号),不是对源码仓库的推测。如果需要,我可以补充本 session 的 goal 事件时间线(roundsStarted 与相邻回合的 wall-clock 间隔)。All reactions