Skip to content
齿轮与路径

五类工具行为缺陷的修复实证

基于 3,207 个主线程的运行数据,记录五类工具行为缺陷的修复实证——glob 搜索爆炸、大输出截断丢失、命令超时挂起、工具名调用失败、后台任务轮询等待。每类给出问题表现、架构设计与指标变化:>100KB 大输出每周 19~41 次降至 4~6 次、not found 调用 8 月归零、轮询等待从 91 次降至 3 次。

编写于 2026-08-09

本文来自 2026-06-05 ~ 08-09 的 peri 运行数据内部调查(threads.db 主库 + metrics 事件日志旁证,快照 2026-08-09)。视角:从智能体行为问题出发,记录修复的架构设计与指标变化——指标为运行数据前后对比,不等同于因果证明。


1. 背景与口径

对运行数据做两件事:统计智能体的工具行为缺陷,把缺陷与代码修复对齐。对齐采用三档判定——【数据可见生效】/【无法证实】/【无数据对应】,本文只收录前者的 5 类场景,其余见文末。两个口径问题先行声明:

  • llm.error 归零是埋点移除,不是错误消失。主路径埋点在 6 月底删除、7 月 16 日客户端重启后停止上报,不能作为效果证据。
  • 消息无时间戳,时间维度按线程创建时间归周。跨周会话整体计入创建周,周边界为近似。

证据分级贯穿全文:【直接观测】(数据直接读到)/【机制推演】(由观测推导)/【未能验证】(有观测但成因未确认)——【数据可见生效】的结论,其因果解释仍可能停留在【机制推演】。


2. 场景一:glob 文件夹过滤限制

问题(智能体行为):智能体使用 glob 时,会直接 glob 到 worktrees 等副本目录和宽 pattern 的搜索结果——一次返回上千条路径,把仓库克隆副本、构建产物整体灌进上下文。>100KB 巨型输出每周 19~41 次,单次最大 167KB;配合超长单行时更严重(07-17 单次 Grep 输出 6.8MB,其中 5 条超长行占 74%)。

架构设计:

  • 源头治理:搜索时跳过 .worktrees 副本目录——副本路径根本不进入结果集,而不是搜回来再截断;
  • 数量/字节双闸互补:结果数上限(1,000)与字节闸(20KB)两个维度互为兜底——文件多但路径短、或文件少但路径超长,任一路径失控都会被封住;
  • 行为引导而非静默限流:触发预算时给出 soft-warn,把”输出被砍”翻译成”请收窄搜索”的反馈,让智能体学会收敛 pattern,而不是盲目重试;
  • 统一预算心智:顺带把 Bash 输出上限收紧至 65KB,让最常用命令与搜索类工具共享同一套输出预算直觉。

指标效果(工具出参,按周):

场景 1 P95

口径:脚本实时计算(weekly 快照);07-13 周为峰值,07-20 周起收敛

指标修补前(W23-W29)修补后(W30 起)变化
>100KB 大输出19~41 次/周4~6 次/周-87%
出参 P9515,496B(6 月平台期)6,957B(08-03 周)-55%(连续 4 周收敛)
周出参总量52.13MB(07-13 周峰值)16.07MB(08-03 周)-69%

关键证据:soft-warn 提示在提交当日即出现在运行数据中,证明机制在运行路径中;但压制效果直到 07-20 周才显现——拐点滞后约 1 个月,与 07-16 Agent+Subagent 重构后的客户端重建吻合,是”输出预算类修复组合”整体生效。

已知缺口(代码与数据互相印证):

  • glob count-guard 分支(results.len() > 1000)不做字节截断——07-22 仍有 125KB Glob 输出(3,791 files)。
  • Grep 无字节上限(head_limit 250 行按行计数,单行可任意长)——08-03 仍有 775KB Cargo.lock 输出。
  • 因此 P95 收敛是”削尾”而非”封顶”:长尾仍在(每周 4-6 次 >100KB),只是频度大降。

结论:【数据可见生效】(部分)——方向与意图一致,但生效滞后、缺口未封闭。


3. 场景二:工具大输出落盘优化

问题(智能体行为):智能体读大文件、抓大页面时,输出一旦被截断就彻底丢失,只能重新调用——高峰期每天大量截断,重复消耗严重。

架构设计:

  • 截断不丢弃:所有工具统一走 persist_truncated_output——输出超限时完整内容落盘,上下文里只保留提示与取回路径,智能体需要时可随时 Read;
  • 一次实现、处处生效:截断落盘收敛为所有工具共用的统一通道,新工具天然继承,无需逐个接入;
  • 内容可精确还原:截断格式自带可辨识标记(前 100,000 字节 + 固定 221 字节包装),边界按 UTF-8 回退,保证落盘内容与原文无损对应。

指标效果(threads.db 消息文本):

场景 2

口径:threads.db 消息文本统计(调查口径,月度;8 月仅 1-9 日)

  • Full output saved 落盘提示:6 月 1,706 次 / 7 月 2,953 次 / 8 月(1-9 日)525 次;窗口起点即每天 42~155 次 → 优化先于数据窗口。
  • Output truncated 提示:6 月 266 次 → 7 月 4,884 次(+18 倍),恰与”工具预算收紧 + 使用量高峰”重叠——截断机制在高峰期承担了主要限流职责,而内容不再丢失。

结论:【数据可见生效】(窗口前)——优化先于数据窗口,窗口内其持续效果可观测。


4. 场景三:异常工具超时设计

问题(智能体行为):智能体跑构建、测试等长命令时,默认 600s 超时意味着一次卡住可挂 10 分钟;且所有工具超时一刀切,读文件等快操作也要等同样久。

架构设计:

  • 超时按工具语义分级:读文件等快操作用短超时,构建/测试等长命令用长超时——超时与工具的时间特性匹配,不再一刀切;
  • 快速失败 + 失败可操作:Bash 默认超时收紧到 15s,超时错误携带引导文本,把”卡死 10 分钟”变成”15 秒内失败 + 下一步怎么做”——超时从惩罚变成反馈信号。

指标效果(错误文本):

  • 07-29 及以前:仅见 Command timed out after 600s(旧客户端);
  • 08-06 起:Command timed out after 15.0s(新默认 15s + 引导文本)——超时收紧生效的直接文本证据;
  • 差异化超时无直接观测,但未引入新错误峰值;08-02 后 bash: timeout: command not found 多次出现(测试环境无 timeout 命令)。

结论:【数据可见生效】——错误文本是强证据,但仅能证明超时收紧本身;Bash 超时不直接改善 token 指标(超时输出通常已截断)。


5. 场景四:工具别名设计

问题(智能体行为):智能体偶尔调用不存在的工具名(Tool 'X' not found/工具 'X' 不存在)。6 月 106 次、7 月 285 次(峰值周 172 次),8 月归零。进一步分析发现 7 月峰值大部分不是 LLM 幻觉,而是工具注册/别名缺失:07-21 前后一天内多工具集体 not found(Bash 235 + TodoWrite 64 + Grep 29 + Glob 28,metrics 侧),属注册链路问题;真正的 LLM 幻觉工具名(Task/Explore/gen-image 等罕见名)全窗口仅约 60 次。

架构设计:

  • 映射收口自声明:工具别名迁移到 BaseTool::aliases() 自声明——“工具名→实现”的映射由每个工具自己宣告,注册表单一可信,消灭分散的硬编码别名与漏注册;
  • 空工具集入口拦截:未声明工具集的 agent 直接拒绝上线,从入口堵死”agent 上线但工具集缺失”这类注册缺失;
  • 注册链路整体收口:配合 Agent/Subagent 架构重构,别名、注册、上线走同一条链路——LLM 记错名字与系统漏注册两类失败一并消除。

指标效果(threads.db,单引号格式):

场景 4 found 调用月度次数

口径:单引号格式 Tool 'X' not found(调查口径,月度;8 月仅 1-9 日)

时段not found 次数会话数主要工具
6 月10670Bash 48、 29、Write 14
7 月285(峰值周 172)165Bash 144、 42、Agent 40
8 月0(5 条均为文本误报)0—

按周:W28(07-0612)172 峰值 → W29 23 → W30 46 → W31(07-2708-02)5 次 → W32 70 次但 59 次为 e2e 测试的冒号格式(单引号格式 8 月为 0)。

关键辨析:

  • 8 月归零是事实,且同期正常使用量 253 会话/周,排除”使用量消失”假象;
  • 拐点(7 月底)晚于 6 月初的早期错误标志修复,与零工具强制及 3.0 重构接近,无法锁定单一提交——是”别名机制 + 注册链路 + 重构”的组合渐进结果。

结论:【数据可见生效】——归零为真,但归因需谨慎:7 月峰值为注册缺失而非幻觉,8 月归零非 6 月单点修复之功。


6. 场景五:Agent 轮询作为等待的机制修复

问题(智能体行为):智能体派发后台任务后不继续干活,而是连续调用 AgentResult/ExecuteExtraTool 轮询结果,还常配合 bash sleep 干等——6 月 91 次轮询事件,最长一次连续 44 次;7 月仍达 75 次、最长 32 次。

架构设计:

  • 推送替代拉取:后台任务完成后由系统经 transport 主动唤醒主 agent(await_wake)——主 agent 不再需要轮询结果,事件驱动取代忙等;
  • 完成语义根治:恢复 Defer 语义、修复唤醒消息丢失根因,保证”任务完成”信号在正确的时机可靠送达;
  • 后台任务统一管理:bg agent / workflow / bg shell 走同一套生命周期,行为一致、无特殊路径;
  • 行为面兜底:prompt 明确禁止 sleep 干等、削弱后台执行的过度鼓励——架构负责”等不到”,prompt 负责”不去等”,双管齐下。

指标效果(同会话同参数 AgentResult/ExecuteExtraTool 连续 ≥3 次):

场景 5

口径:同会话同参数连续 ≥3 次视为轮询(调查口径,月度;8 月仅 1-9 日)

时段轮询事件最长链
6 月9106-08 ExecuteExtraTool×44、06-06 AgentResult×27
7 月7507-09 AgentResult×32、07-24 ×18(最后一次显著长链)
8 月(1-9 日)3均 ≤3 次,疑似 workflow 测试

关键辨析:

  • 渐进修复轨迹清晰:每次修复后最长链仍复现(轮询防护后 ×44、bg 语义修复后 ×32),直到 7-24 ×18 后 8 月归零——没有任何一次修复单独根治;
  • 8 月归零与 prompt 禁 sleep 时间接近,但更可能是 bg 语义修复 + 8 月客户端重建的组合效果;
  • 反证:8 月同工具连续调用(Edit×5~10)仍存在,但均为同文件不同片段编辑,属正常行为。

结论:【数据可见生效】(渐进)——方向确定,因果无法归于单点。


7. 共性观察

  1. 生效拐点高度聚集于两个时点:07-20 周(出参收敛)与 8 月初(幻觉/轮询归零)。前者对应 07-16 Agent+Subagent 重构后的客户端重建,后者对应 3.0 迁移。“客户端重建”是已提交代码的生效放大器——单看提交日期会误判。
  2. 组合生效是常态,单点修复是例外:5 类场景中 3 类(1/4/5)明确为组合;能给出单一改动直接文本证据的仅场景 3(15s 超时文本)。
  3. 同一事件在不同指标上重复出现:07-21 工具注册缺失峰同时驱动场景 4 的 not found 峰值与全库错误率高峰——跨指标解读时须去重,避免重复计功。
  4. 数据陷阱必须显式排除:llm.error 归零(埋点移除)、compact 触发归零(时序反转)均已证明不可作为效果证据;正确证据面是 threads.db 持久化消息 + tool.error。
  5. 已证实场景与代码审计结论一致:场景 1 的缺口(Glob 双层预算已实现、Grep 无字节上限未修复)与代码审计结果完全吻合。

8. 未收录场景及原因

场景判定原因
compact 改进【无法证实】触发归零早于修复提交,时序反转;泄漏修复对象在真实数据仅出现 1 次
渲染优化【无数据对应】无 CPU/帧率事件数据;修复后会话量平稳只是弱证据
重读/白搜(建议项)【无数据对应】= 未修复重读率 40-74% 高位波动;跨窗口稳定(34.0% vs 31.9%)说明是系统性行为,代码审计确认未实现
llm.error 归零【无法证实】= 口径陷阱埋点删除 + 客户端重启,与优化无关

9. 局限

  1. 所有”效果”均为运行数据前后对比,叠加效应无法分离;拐点与提交的时序吻合不构成因果证明。
  2. metrics 埋点窗口残缺(7 月 16 日后 llm.error/agent_turn_end/compact 停止上报),7 月下旬至 8 月的事件级指标缺失。
  3. 8 月数据混杂 e2e 测试流量(W32 的 70 次 not found 中 59 次来自 e2e),归零类判定已剔除但污染持续存在。
  4. 错误统计为下限(threads.db 过滤 is_error 消息),具体数字随埋点恢复可能上修。