已开启
[Feature] ReActAgent 运行级 deadline:墙钟总预算、每次调用向下夹逼、soft→hard 两段收尾 #188
yaojun97创建于  4 天前
yaojun97
yaojun97
4 天前 创建

Paired: GitHub #356 ↔ GitCode #188

来自 agent-solution 仓 smartresearch-alpha(agent-core-java 0.1.16 消费者,真 LLM e2e 实测背景)。
涉及分支:930(0.1.16 血统)。

标题:[Feature] ReActAgent 运行级 deadline:墙钟总预算、每次调用向下夹逼、soft→hard 两段收尾

1. 问题

即使有了 per-call timeout(Issue A),maxIterations × per-call 仍无总上界:以 smartresearch-alpha 为例,三相位 ReAct 各 ≤120/60 迭代 × 单调用上界 1200s ⇒ 名义运行上界 40+ 小时。真 LLM 实测中单次任务 10–90 分钟,目前只能靠部署外层的墙钟 timeout 进程级 kill 兜底——无法优雅收尾,任务已写的中间工件状态不可控,消费者也无法在框架内回答「这次调用还剩多少预算」。

具体三个缺口:

  1. 总预算:引擎没有「这次 run 最多跑多久」的概念;
  2. 向下传播:每次模型调用与工具执行拿不到「剩余预算」,无法做 min(per-call, remaining) 夹逼;
  3. 优雅收尾:预算耗尽只有硬中断一种结局——模型没有「知道快到点了、把手头结论写完」的机会。

2. 建议设计(三层,默认关闭零破坏)

① 总预算入口(Builder/引擎配置)

ReActAgent agent = new ReActAgent(card);
// 墙钟总预算(二选一语义均可,建议 Duration 为主、Instant 便于对齐外部期限)
agent.configureDeadline(java.time.Duration.ofMinutes(90));
// 可选:软线比例,默认 0.2
agent.configureSoftDeadlineRatio(0.2);

② 向下夹逼传播(ReAct 主循环内,每次迭代重算)

循环头:remaining = deadline − now
callModel 传给 client 的 callTimeout = min(配置的 per-call, remaining)   // 依赖 Issue A 的配置口
remaining ≤ 0 → 不再派发新迭代,进入 hard 收尾

③ soft → hard 两段收尾

soft(一次性):remaining < ratio × budget 且未通知过 → 向对话注入一条 system/tool 消息
      (建议常量:"Time budget nearly exhausted; finalize with what you have.")
      ——给模型最后一轮收敛机会(写终稿/摘要),此后照常迭代直至自然结束或 hard
hard:remaining ≤ 0 → 抛 AgentDeadlineExceededException
      (建议继承 java.util.concurrent.TimeoutException,语义现成)
      ——fail-fast:已产生的对话与外部工件保持可读,重试/部分交付由调用方决定

④(可选第二步)工具侧可见性:ToolCallInputs(或工具执行上下文)增加 deadlineRemaining()——长退避类工具(如限流检索的 30s×N 退避 sleep)可自行夹逼 min(backoff, remaining),避免预算耗尽前「睡死」。

3. 兼容性

  • 不配置 deadline = 现行为逐字节不变(默认关闭;这是本提案的硬约束);
  • soft 通知是消息注入——对无状态工具无影响;消息文本收在常量里,便于消费者禁用/替换/本地化;
  • hard 异常是新类型,不与既有异常混淆;建议 hard 后再 invoke 抛 IllegalStateException(与一次性任务的 fail-fast 模式一致);
  • Issue A 的 per-call 配置是②夹逼公式的前置,但本 Issue 可独立先行(per-call 暂用全局配置值参与 min)。

4. 测试建议(消费者视角的最小验证集)

  • 无 deadline 对照:stub 模型 N 轮迭代,行为/消息序列与现版本零差异;
  • soft 恰一次:极短预算下软通知只注入一次(第二次迭代起不再注入);
  • 夹逼断言:per-call=10s、remaining=1s 时传到 client 的 timeout=1s(Recording 断言参数);
  • hard 语义:超限抛新异常、已写工件可读、再次 invoke 抛 IllegalStateException。

5. 开源先例

  • langgraph(MIT):图级 recursion_limit 是迭代数总量上界;TimeoutPolicy 提供 run_timeout(总墙钟)+ idle_timeout(进度停滞)双闸——「总量上界 + 停滞检测」的公开组合设计;
  • OpenAI codex(codex-rs,Apache-2.0):重试睡眠与握手预算夹逼(timeout(remaining, sleep(delay)) 形态——退避永远不越过剩余预算);会话级超时旋钮原生配置;
  • openclaw:turn 级超时在任务预算内夹逼计算(min(perTurnMs, deadline − started))——与本提案②的公式同形。

6. 不含(明确出界)

工具实现内部的退避策略本身(各工具自治);分布式/跨进程 deadline 传播(gRPC-style context cancellation 是更重的方案,若本 Issue 落地后再评估)。



(关联:per-call timeout 配置化 Issue A 随后提交,为本文夹逼公式的前置,可独立评审。)

likedislike
OopenJiuwen-bot成员
4 天前 添加了label:sig/sig-agent-core-java
openJiuwen-bot成员
4 天前 评论:

欢迎来到 openJiuwen 社区

Hey @yaojun97 , 感谢你对社区的贡献.

机器人使用手册

有关指令的使用,可以点击 此处 查看详情。开发人员可以在每个PR或Issue下方评论特定指令来触发机器人任务。

联系指引

有疑问可以联系 SIG: sig-agent-core-java ,
维护者是: @shenwei21, @tianmingyong ,
审核者是: @foreach1991, @gcw_xJSJ32Ge, @jeffrey_qiao, @kangquansheng_makeIT, @xiongjie_makeit .

likedislike
Oopenjiuwen-sync成员
4 天前 修改了issue 的描述
xiaoming成员
3 天前 评论:

已基于最新 upstream/develop 将本 issue 的运行级时间预算需求整理为符合仓库需求模板的 #190:ReActAgent 支持单次运行总时间预算与临近截止收尾,包含背景描述、设计思路和测试设计与测试计划。

当前 develop 已有模型请求级超时配置,但 ReAct 单次运行仍缺少总预算。#190 补充了模型重试、流式读取、工具执行、并发调用及中断恢复等边界,并将超时后的具体错误语义和取消保证留给设计评审确认。建议后续围绕 #190 讨论和验收该 feature;本评论不改变 #188 状态。

likedislike