Skip to content

Agent 对话可配置最大工具调用次数 + Token 优化 + 循环检测升级#1549

Open
cyfung1031 wants to merge 8 commits into
scriptscat:mainfrom
cyfung1031:feat/ai-001
Open

Agent 对话可配置最大工具调用次数 + Token 优化 + 循环检测升级#1549
cyfung1031 wants to merge 8 commits into
scriptscat:mainfrom
cyfung1031:feat/ai-001

Conversation

@cyfung1031

@cyfung1031 cyfung1031 commented Jul 6, 2026

Copy link
Copy Markdown
Collaborator

Checklist / 检查清单

背景

关联 #1545,解决内置 Agent 在长时间、高频 Tool Calling 场景中的三个问题:

  1. 最大迭代次数固定为 50,复杂任务容易被强制中断;
  2. 历史工具结果会在后续请求中重复携带,导致 Token 消耗持续增长;
  3. 检测到重复/循环调用后仅提示模型,无法让用户及时介入。

实现内容

1. 可配置最大工具调用次数,并支持原会话继续执行

  • 新增 AgentConfigRepo,通过 chrome.storage.local 持久化 chatMaxIterations
    • 默认值:50
    • 可配置范围:1–1000
    • 对设置页输入、直接传参和异常/损坏的存储值统一进行取整、范围截断和默认值回退
  • Agent Settings 新增“对话”分类及“最大工具调用次数”配置项。
  • 达到迭代上限时:
    • 持久化带 errorCode: "max_iterations" 的错误消息;
    • UI 显示“继续对话”按钮;
    • 点击后在原会话中追加继续指令,并复用已持久化的历史继续执行,无需新建会话。
  • 重建 LLM 上下文时跳过仅供 UI 展示的错误占位消息,避免将空的 assistant error message 重放给 Provider。

2. 降低长 Tool Loop 的 Token 消耗

Anthropic Prompt Cache

  • 在 Anthropic 请求的最后一条消息上追加 cache_control 断点,使下一轮能够复用已经生成的消息前缀。
  • 与已有的 system、tools 缓存断点配合,减少长 Tool Loop 中重复输入的计费 Token。

execute_script 大结果截断

  • 序列化结果超过 30000 字符时,仅保留首尾各 15000 字符。
  • 返回值附带 truncated: trueoriginal_length,并提示 Agent 缩小返回结果或将大数据写入 OPFS。

Tool Result 滑动窗口裁剪

  • 根据实际上下文占用,在 40%60% 阈值分批触发裁剪;达到 60% 后,每新增 5 轮工具调用再滑动一次窗口。
  • 保留最近 5 轮 assistant/tool 消息原文,更早的 tool result 替换为占位文本。
  • 仅修改当前请求中传给 LLM 的内存消息,不影响 OPFS 中的完整历史和 UI 展示。
  • 80% 以上仍优先使用现有 auto-compact 流程。
  • Anthropic 的上下文占用计算会合并普通输入、cache creation 和 cache read Token,避免缓存用量导致阈值判断失真。

3. Loop Guard 支持用户介入

  • 保留现有 tool_call_guard 的模型提醒和 system_warning 展示。
  • 自上次确认后累计触发 2 次警告时,暂停 UI 对话并询问用户:
    • Continue:继续执行,并重置警告计数;
    • Stop:持久化停止说明并以 done 正常结束,而不是报错。
  • 普通 UI 会话和后台会话均支持该交互;后台会话可在重新 attach 后恢复待回答的问题。
  • 5 分钟无人回答时默认继续,并同步清理过期的 pendingAskUser 状态。
  • 定时任务和子代理不传入交互回调,继续保持“只告警、不暂停”,避免无人值守任务被阻塞。
  • 等待用户回答期间支持通过 AbortSignal 立即停止。

兼容性

  • 默认最大迭代次数仍为 50,未修改设置的用户行为保持不变。
  • 上下文裁剪不改写持久化消息,因此刷新页面、继续对话和历史展示不会丢失原始工具结果。
  • 新增文案已覆盖全部 8 个 locale:zh-CN、en-US、zh-TW、ja-JP、ru-RU、de-DE、vi-VN、tr-TR。

Test plan

  • 按 TDD 流程为新增行为和审查修复补充回归测试
  • npm run test:ci — 3041/3041 tests passed(289 个测试文件)
  • npm run lint — prettier / tsc / eslint 全部通过
  • 覆盖配置边界值、继续对话、Anthropic cache、结果截断、上下文裁剪、Loop Guard 暂停/继续/停止/超时/中止等场景

调查过程与技术方案细节见 issue-1545-proposal.md

cyfung1031 and others added 6 commits July 7, 2026 02:24
针对 scriptscat#1545:UI 对话此前硬编码 50 次工具调用上限且无法调整,达到上限
后用户误以为必须新建对话、丢失已探索的上下文。

- 新增 AgentConfigRepo(chatMaxIterations,默认 50,1-1000),Settings
  页新增"对话"分类可视化配置
- 达到 max_iterations 时持久化 errorCode,聊天界面据此渲染"继续对话"
  按钮,一键复用已持久化的完整历史继续执行
- 全部 8 个 locale 补齐相应文案

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
针对 scriptscat#1545 的 Token 消耗问题:长 tool loop 每轮都全量计费输入 token,
且 execute_script 返回值(如 DOM dump、模块映射)不设上限,被完整保留
并在后续每轮重复发送。

- Anthropic provider 为最后一条消息追加 cache_control 断点,使已产生的
  历史前缀被缓存,下一轮仅新增部分计费(system/tools 断点已存在,此为
  第三个断点,未超过 4 个断点上限)
- execute_script 返回值超过 30000 字符时截断为首尾各 15000 字符并标注
  truncated / original_length,避免超大返回值反复占用上下文

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
针对 scriptscat#1545:在触及 80% 的 autoCompact 阈值之前,长对话的旧 tool 结果
(如 DOM dump)会在后续每一轮都被完整重复发送,进一步放大 Token 消耗。

- 新增 elideOldToolResults:保留最近 5 轮 assistant/tool 消息原文,
  更早的 tool 结果替换为占位文本;只裁剪内存中传给 LLM 的消息,不影响
  chatRepo 持久化与 UI 历史
- 在 40% / 60% 两个上下文占用阈值各触发一次(而非逐轮触发),避免
  频繁重写消息前缀导致 Anthropic 的 prompt cache 断点失效

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
针对 scriptscat#1545 的 Loop Guard 诉求:现有 tool_call_guard 检测到重复/死循环
模式时只向 LLM 注入提醒,LLM 不理会则持续烧 Token,用户无法介入。

- ToolLoopOrchestrator 新增 askUserForGuard 可选回调:循环检测连续命中
  达到 2 次时暂停循环,询问用户"继续"或"停止";回答停止则以 done(非
  error)优雅收尾并持久化提示
- 仅 UI 对话(含后台会话,复用既有 ask_user 事件/resolver 机制,5 分钟
  无人应答默认继续)传入该回调;定时任务与子代理不传,保持原有的
  仅告警不暂停行为,避免无人值守场景被阻塞

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
针对 PR scriptscat#1549 的审查反馈:

1. 【阻断性】继续对话时,历史中 max_iterations 错误占位消息(content
   为空字符串)此前会被完整重放进 LLM 请求,部分 provider(如
   Anthropic)会因空 content 拒绝请求。buildAndPersistUserMessage 现在
   跳过带 error 字段的历史消息,仅用于 UI 展示,不进入 LLM 上下文。

2. 循环检测升级提问 5 分钟无人应答超时后,此前只删除 resolver,未清除
   后台会话的 rc.pendingAskUser,导致后续 attach 的 UI 仍会看到已失效
   的提问,回答会静默无效。超时回调现在同步清除 pendingAskUser。

3. chatMaxIterations 的合法范围此前只在 Settings UI 校验,
   AgentConfigRepo 直接读写未归一化的原始值;损坏的 storage、旧版本
   遗留值或绕过 UI 的写入都可能导致 0/负数/超大值,进而导致循环立即
   报错或失控运行。新增 normalizeChatMaxIterations,在 getConfig /
   saveConfig 中统一归一化到 [1, 1000];ChatService 解析最终值时改用
   ?? 并对结果做同样的兜底截断。

4. 循环检测升级的连续命中计数此前永不重置,用户选择"继续"后,此后
   每一次告警都会重新暂停询问,比"连续命中 2 次暂停"更激进。现在回答
   继续后重置计数,需再次连续命中 2 次才会重新暂停。

均已按 TDD 补充回归测试(先复现失败用例,再修复)。

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@cyfung1031

This comment was marked as outdated.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature] 建议暴露 AI Agent 最大工具调用限制并优化多轮 Tool Calling 下的 Token 消耗

1 participant