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

> Documentation Index
> Fetch the complete documentation index at: https://konghayao.github.io/peri-cool/llms.txt
> Use this file to discover all available pages before exploring further.

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

> 本文来自 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](/chart-1-weekly.svg)

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

| 指标 | 修补前(W23-W29) | 修补后(W30 起) | 变化 |
|---|---|---|---|
| >100KB 大输出 | 19~41 次/周 | 4~6 次/周 | **-87%** |
| 出参 P95 | 15,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:截断提示与落盘提示](/chart-2-truncation.svg)

*口径: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:not found 调用月度次数](/chart-4-notfound.svg)

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

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

按周:W28(07-06~12)172 峰值 → W29 23 → W30 46 → W31(07-27~08-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:轮询等待事件数与最长连续链](/chart-5-polling.svg)

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

| 时段 | 轮询事件 | 最长链 |
|---|---|---|
| 6 月 | 91 | 06-08 ExecuteExtraTool×44、06-06 AgentResult×27 |
| 7 月 | 75 | 07-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 消息),具体数字随埋点恢复可能上修。

Source: https://konghayao.github.io/peri-cool/posts/research/tool-behavior-fix-evidence/index.mdx
