模型为何调用文档里明确禁止的工具?一次 Agent Skill 健康度整改实录

模型为何调用文档里明确禁止的工具?一次 Agent Skill 健康度整改实录

导读:这篇文章用两起真实整改案例回答"模型为何调用文档里明确禁止的工具":对话下单 Skill 健康度仅 38/100、中断率 79.1%,trace 显示未声明乃至被禁用的工具被大量调用(子 agent 占墙钟 62.8%、被明令禁止的检索工具被调 53 次)。核心结论是单一负面禁令不足以约束模型,须改为正向声明"仅允许以下工具"并配合平台侧真移除;案例二补充了"被路由到错误技能时文档还能做什么"。适合治理 Agent Skill 健康度、做 trace 实证归因的工程师阅读。 分类:AI评测 | 标签:Agent、Skill、健康度、实战案例

阅读提示:本文为内部整改案例的脱敏改写。文中所有健康度分数、中断率、耗时、token 数、工具调用次数等量化指标均保留数量级并做了脱敏示意,不代表任何线上真实数值;内部系统名、工具名、域名、业务字段均已用通用说法替代。

从两个"红牌"健康度报告说起

在自研 Agent 平台上做 Skill 治理时,我反复遇到同一种典型场景:模型明明配有详细的 SKILL.md 文档,行为却完全不受文档约束——它会调用文档里没有声明、甚至明确禁止的工具,把一次本应几秒完成的对话,拖到用户放弃等待。

本文用两起真实整改案例完整复盘这件事。案例一回答"模型为何无视文档禁令",案例二补充一个容易被忽视的视角:"当模型被路由到了错误的地方,文档还能做什么"。

案例一:对话下单 Skill,健康度 38/100

1. 结论先行:用户等不到结果

健康度 38/100,判定为不健康。核心矛盾一句话——用户等不到结果:中断率 79.1%(197/249),静默 p95 17.3s,latency p95 84.3s。而结构性慢因是嵌套子 agent:调用 57 次,墙钟 2310.62s,占 trace 的 62.8%。

关键指标一览(建议验收值):

指标 当前值 目标
中断率 79.1%(197/249) <50%
latency p95 84.3s(p50 46.74s) <60s
max_silence p95 17.33s <3s
LLM 次数 mean 6.86(p95 13.05) ≈4
嵌套子 agent 墙钟占比 62.8%(57 次 / 2310.62s) <30%
工具次数 p95 23.05(合计 914) ≈6
版本号上报 缺失(无法对比上版) 每次发布必带

健康度四维拆解(n=257,近 5 自然日):

维度 权重 得分 扣分原因
可靠性 40% 0.21 中断率 79.1%
时延 25% 0.10 p95 84.3s;静默 p95 17.3s
工具健康 20% 1.00 工具错误率 0.0%
循环健康 15% 0.50 LLM 轮次 p95 13.1

几个值得注意的数字:平均用户感知耗时 48.43s(名义上达标 ≤50s,但 79% 的用户根本没等到结果);中断分布为 hard_cancel 175 / client_abort 22 / ok 52;真实错误率 0.0%——链路没有错,就是慢到用户放弃。

耗时结构说明慢在哪里:

环节 独占耗时 占比 说明
模型生成 / 思考 3363.74s(42.05s/trace) 78.4% 含嵌套子 agent 内部影子
异常 span 790.06s(9.88s/trace) 18.4% 0.86 次 / trace
工具执行 129.51s(1.62s/trace) 3.0% 非主要慢因
知识读取 6.61s(0.08s/trace) 0.2% 8.22 次 / trace,次数高耗时低
嵌套子 agent(inclusive) 2310.62s 62.8% 结构性慢因,优先排查

2. trace 实证:模型大量调用文档未声明、甚至明确禁止的工具

看报告只能知道"慢",不知道"为什么慢"。下一步把线上 trace 的 Top 工具与 SKILL.md(v0.3.28)的声明逐项核对:

工具(名称已中性化) 线上次数 工具耗时(占比) SKILL.md 口径
知识读取工具(skill_view) 658 6.61s(4.9%) 声明:包内文档读取方式
订单接口查询工具(HTTP GET) 109 35.95s(26.4%) 声明:主 API 工具 ✓
子任务委派(sub-agent) 57 墙钟 2310.62s(62.8%) 未声明
内部知识检索工具 53 62.3s(45.8%) 明确禁止
命令执行工具 19 26.29s(19.3%) 未声明
网页搜索工具 6 0.95s(0.7%) 未声明
第三方接口调用 / 订单接口提交(HTTP POST) 6 / 3 1.96s / 1.53s POST 已声明 ✓

核对结论非常讽刺:模型在运行时大量调用文档未声明、甚至明确禁止的工具。其中子任务委派恰好就是那个占墙钟 62.8% 的结构性慢因的直接来源;被明令禁止的内部知识检索工具也在偷偷用。

由此得到第一个方法论结论,也是本文标题的答案:

单一负面禁令不足以约束模型。 在文档里写"禁止 X、禁止 Y"并不会让模型听话;必须改为正向声明"仅允许使用以下工具",再配合平台侧把这些工具从模型可见的工具列表里真正移除,约束才能闭环。

3. 问题归因与 Proxy 下沉信号:4/4 命中

按问题类型归因:

类型 线上证据 处理方向
对话理解失败 错误率 0.0%,无意图/槽位失败记录 优化 skill(低优先)
接口拼装失败 错误率 0.0% 无(未命中)
状态判断失败 多轮规划/校验空转:LLM mean 6.86、子任务 57 次、异常 span 0.86 次/trace 收敛轮次与子 agent(P0)
系统能力失败 异常 span 占 18.4% 但真实错误率 0% 定位重试/超时/日志噪音(P1)

同时按"Proxy 下沉"方法论打了 4 个信号,4/4 命中:

信号 证据
LLM 独占 ≥70% 且 p95 轮次高 78.4%(含嵌套影子)· p95 13.05
知识读取次数多但耗时低 8.22 次/trace · 0.08s → 材料应前置缓存或 Proxy prepare
单工具占工具耗时大头 内部知识检索 45.8% + 命令执行 19.3% → 查询编排应下沉进 Proxy
错误率低、感知仍慢 0.0% vs p95 84.3s → 链路过长

方法论上满 3 条信号就应评估把编排逻辑下沉到 Proxy;本轮先做文档级收敛、用数据验证"子 agent 空转"假设,再决定是否动用后端资源。

4. 工作包 W1–W7 与里程碑 M0–M5

围绕交付物拆了 7 个工作包:

编号 工作包 优先级 归属 完成定义
W6 诊断抽样:验证子 agent 与异常来源 P0 分析 诊断结论文档(假设定案)
W7 平台能力验证:流式/进度消息/子 agent 限深/工具移除 P0 平台依赖 能力矩阵(决定 W3 与目标值)
W1 工具边界收敛(正向声明 + 平台白名单) P0 skill 全包 grep 零残留 + 白名单确认
W2 子 agent 与轮次收敛(限深/退出/共享背景前置) P0 skill SKILL.md 轮次约束段 + 主流程 5–8 步
W3 占位话术与静默治理 P0 skill 进度话术段落地
W4 异常与工具调用收敛(退避上限/降级直答/合并查询/读取缓存) P1 skill references 裁剪 + 错误兜底规则
W5 版本上报与发布纪律(zip 校验/RELEASE-NOTES/版本号上报) P0 工程 技能包 + 校验报告 + 版本号可见

关键工作项的要点:

  • W1 工具边界:SKILL.md 加正向铁律——「仅允许使用声明工具(订单接口查询/提交、地址解析、追问用户、知识读取),禁止子任务委派 / 网页搜索 / 命令执行 / 内部知识检索」,沿用复盘结论"负面禁令不足";平台侧确认可否从模型工具列表移除上述违规工具。
  • W2 子 agent 与轮次:子 agent 最多 3 轮、无新信息立即返回、单次工具可完成的子任务不起子 agent;商品库/规则类共享背景一次性写入(不每轮重读);多轮追问合并为一次结构化收集;删除"规划—校验—再规划"重复段。
  • W3 占位话术:任务执行期间推送"正在查询数据 / 核对信息"类进度话术;禁止 3s 以上无输出(平台不支持中间消息时降级为"首条即成品"保证,依赖 W7)。
  • W4 异常与工具收敛:错误分支退避重试上限(约 2 次),失败一次即降级直答、不触发新一轮 LLM 重规划;查询类工具按维度合并;已读材料缓存、同一路径禁重复读取。
  • W5 发布纪律:zip 级断言脚本(根目录 SKILL.md、版本号、禁用词、连续重复行);确认版本号上报链路(当前缺失);RELEASE-NOTES 保持 3 版上限。

里程碑(带退出条件):

里程碑 内容 退出条件
M0 方案确认 用户确认范围 / 验收 / 决策点
M1 诊断与能力验证(W6 + W7) 子 agent 行为结论 + 平台能力矩阵齐备
M2 文档改造(W1–W4) 全包核对零残留 + 静态扫描无新增提示
M3 打包发布(W5) zip 校验通过 + 版本号上报可见
M4 上线观察 5 自然日(同口径取数) 验收表全项达标;未达标回看方案 V2
M5(可选) Proxy 下沉评估(B 阶段) D4 确认后另行立项,以原型验收为准

关键路径为 M0 → M1 → M2 → M3 → M4,其中有一条必须强调的纪律:

M1 是一道门禁:未验证假设,就不改文档。 W6 诊断抽样没完成、平台能力矩阵没拿到之前,不允许进入 M2 的文档改造——否则就是在未经验证的假设上改文档,方向错了全部返工。

支撑 M1 的是三条待验证假设:H1 子 agent 空转(57 次调用多为多轮规划/重复探索);H2 长静默劝退(p95 17.3s 是 hard_cancel 175 次的主因);H3 读取重复(8.22 次/trace 含同路径重复读取)。每一条都有明确的验证方法(查慢 trace、话术上线前后对比、grep + trace 采样)。

5. 决策点与部分砍项

方案里埋了 5 个决策点 D1–D5,用户确认结果如下:

决策点 建议(推荐前置) 确认结果 影响
D1 范围 P0(W1–W3 + W5–W7)先行 只做 P0 先行 W2 / W3 / W5 入本轮;W4(P1)不做
D2 工具收敛 未声明工具全禁 不动(怕影响业务) W1 取消:工具清单与白名单零改动
D3 验收目标值 按报告 AI 建议 上线后跑数据看健康报告 验收判定延后至 M4 数据
D4 Proxy 下沉 A 阶段验证后评估 不做 M5 关闭
D5 版本上报 必做 要加版本号 入 W5 执行

注意 D2 这个"砍项":工具收敛本来是消除 62.8% 慢因的最大杠杆,却因业务顾虑被砍掉,W1 随之取消。这种"证据充分但决策层担心业务风险"的博弈在真实整改里非常常见——文档治理的边界就是把能改的改好、把不能改的写进风险清单,等数据说话。

交付边界趁早说清:只管优化 skill + 打 zip,不部署、不发布、不管理验收。配套的治理规则:本方案为基线,范围/验收/目标值变更须回看并升版(V1 → V2),不静默改基线;取数同口径(观测平台近 5 自然日、全量墙钟),发布后 5 日判定 M4。

风险与备选(精简版):

风险 预警信号 响应动作 / 备选
R1 平台不支持流式/进度消息/工具移除 能力矩阵出现缺口 占位话术降级,静默目标修订为 ≤5s 重新验收;工具移除不可行则退化为"仅限次数"
R2 工具收敛伤业务 业务走查断链或错误率上升 保留必要工具仅限次数/范围,灰度发布观察
R3 client_abort 不可全归因时长 指标达标后中断率仍 >50% 超长任务拆异步通知,或按 hard_cancel 占比修订验收口径
R4 文档改动破坏正确性 回归走查失败 / 错误率上升 灰度 + 回滚至基线包
R5 未验证假设即改造 M1 未完成直接进入 M2 M1 门禁强制,诊断结论先行

6. 执行记录与 zip 级校验

本轮实际落地(版本 v0.3.29):

  • W2 + W3 合并落地:SKILL.md 新增强制规则 17「读取纪律:每会话每文件只读一次,禁止重复读同一文件」、规则 18「一次问全 · 单步完成 · 不空转」;未引入进度占位话术——与既有"零过程句 · 首条必成品"实锤纪律冲突,避免业务风险。
  • W5:版本 0.3.28 → 0.3.29(SKILL.md frontmatter + RELEASE-NOTES,最近更新保持 3 版上限)。
  • W1、W4、W6、W7 未做:分别因 D2 决策、P1 范围、用户直接确认范围、平台/部署不在职责。
  • references 30 个文件与全部业务规则、接口、兜底链零改动(约束:不碰业务)。

打包与校验(zip 级断言脚本):

项 结果
产物 dist/order-skill-prod-v0.3.29.zip
大小 / 文件数 90.3 KB(原 87.5 KB)· 35 项
结构 与线上包 namelist 逐项一致,仅替换 SKILL.md 与 RELEASE-NOTES
zip 级校验 SKILL.md version 0.3.29 ✓ · RELEASE-NOTES version 0.3.29 ✓ · 规则 17/18 在包内 ✓ · 最近更新 3 版上限 ✓

里程碑状态:M0 ✅ · M1 ⏭ 跳过(用户直接确认范围)· M2 ◐ 部分完成 · M3 ✅ · M4 ⏳ 待上线后 5 日数据。

上线后重点对比:LLM 次数 mean(6.86 → ?)、知识读取次数(8.22 → ?)、中断率(79.1% → ?)、latency p95(84.3s → ?),并验证版本号是否真的上报成功;若指标未达标,复审 D2 工具收敛(唯一大杠杆)。

(此后还有一轮 v0.3.30:处理第二份扫描反馈——版本历史归档到独立文件、示例注释补充"线上域同样适用"说明,zip 校验同样通过。细节不展开。)

案例二:订单查询 Skill,健康度 53/100

1. 根因:6 条慢 trace 里 5 条是"被路由错地方"的任务

第二个案例的根因不是文档质量,而是误路由。健康度 53/100,6 条慢 trace 采样中 5 条都是域外任务——日报统计、履约登记、保险引导等。模型被绑定在当前技能后,越界读取包外文件、猜参数反复锤接口、上下文膨胀到 148k–169k tokens,单轮生成从 5s 涨到 23s。

初始健康指标(事实):

指标 当前值 结论
平均耗时 88.03s(基线 50s,+76.1%) 未达标
时延 p95 / p99 254.9s / 327.8s(n=32) ≥180s FAIL,时延维度 0 分
中断率 21.9%(7/32,hard_cancel 4 + client_abort 3) 扣可靠性
LLM 次数 p95 / mean 18.15 / 10.0 循环健康度 0.13
知识读取平均 5.28 次/trace(95 次) 偏高
模型生成 / 思考独占 89.6%(1148.34s / 18 trace) 严重拥堵,唯一大头
工具错误率 1.4%(3/217) 正常
版本上报 未上报版本号 无法与上一版对比

慢 trace 画像(trace id 已省略,诉求与归属已泛化):

样例 时延 LLM 轮 用户诉求(脱敏) 真正归属
慢样例 A 308.8s 16 统计本人名下当日已履约/待履约/发起签单 报表统计域
慢样例 B 210.8s 9 再次统计同上 报表统计域
慢样例 C 90.3s 14 线索履约登记操作 履约操作域
慢样例 D 34.4s 7 单条履约登记 履约操作域
慢样例 E 46.6s 4 保险引导(附截图) 其他业务域
快样例 F 19.3s 4 非本域订单查询 非本域订单(正确拒绝)

6 条中仅 1 条在域内范围边缘;而域内正例(订单列表/详情/换单链)在采样中没有一条慢 trace——慢的全部是"不属于我"的任务。

归纳出的共性失败模式:

  • 误判滞留:模型首轮 reasoning 已指出"这应该由报表统计类技能处理",但被绑定在订单查询子技能无法切换,只能在本技能内硬解。
  • 越界抓取:读取其他技能包目录下的 SKILL.md、INSTRUCTIONS.md 等包外文件。
  • 猜参锤接口:同一参数试 3–4 个候选值、参数在 body/query 间试错、body 误传类型;同一接口重复调用(32 条 trace 内订单接口提交类调用合计 49 次)。
  • 上下文膨胀:单条 trace 输入 token 从 28k 膨胀到 148k–169k,每轮生成 5s → 23s。
  • 用户取消:等待 3–5 分钟无有效输出 → client_abort / hard_cancel(中断率 21.9%)。

2. 方案 A / B / A+ / 不动的决策

摆在面前的是四个选项(决策时点 2026-08-31):

选项 改动范围 成本 / 风险 预期收益
A · 边界治理全套(推荐) 范围小节 + 行为准则 4 条 + 双 description 收紧 + RELEASE-NOTES + 版本 2.2.0 纯文档改动,不碰接口与流程;description 改动对平台召回影响小(保留原触发词) 误路由任务 1–2 轮内转出;LLM p95 降至 8–10;时延 p95 降 40%+
B · 仅范围声明 只加范围小节与 escalate 出口 最低 能减滞留轮次,但模型仍被路由进来后才转出,版本无法对比
A+ · 全套 + 单链读取标注 A + 换单链文档标注"按需读一次、禁重复读" 低 进一步降低域内读取
保持不动 无 无 维持 53/100,慢 trace 与中断持续

最终选 A:范围声明 + escalate 出口、4 条行为准则、双 description 收紧、补版本上报,版本 2.1.0 → 2.2.0。

四条行为准则(复用价值很高):

  1. 禁读包外文件:禁止读取本技能包目录以外的文件;需要其他技能能力时 escalate,不得自行读取其文档。
  2. 参数不猜:同一查询最多尝试 2 种候选参数组合,仍无结果或返回异常即停止并向用户说明口径;禁止连续换参重复调用。
  3. 每会话每文件只读一次:已读文件禁止重复读取。
  4. 一次规划、集中执行:功能链(如换单 12 步)开始前一次性读完所需文档,执行中不再读文档;接口返回后直接构造下一步请求。

范围小节的核心是双向声明:写清楚"属于什么"(已有订单/线索 ID 的单笔查询与操作),更要写清楚"不属于什么——立即 escalate,禁止用本技能接口硬查"(统计/日报/业绩汇总、履约写操作、投保/保险/签约引导、工资发放查询、任何汇总/统计/报表类诉求),并规定 escalate 的 reason 必须写明"应转哪个域 + 用户诉求一句话"。

双 description 收紧:SKILL.md frontmatter 与 skill.json 的 description 均追加范围排除句(保留全部原触发词),降低误路由概率。补版本上报:新增 RELEASE-NOTES(name/version/generated,与平台通用格式一致),修复健康报告"未上报版本号"。

风险与未知,照实写:

  • escalate 依赖平台再分流:其中一条 trace 显示 escalate 后中枢仍把任务委派回本技能——文档只能减少滞留轮次,根治误路由需要平台侧技能路由优化(另行反馈平台)。
  • 域内基线未知:本次 32 条 trace 中域内任务占比低,建议上线后对比下一轮健康报告 p50。
  • description 修改可能轻微影响关键词召回,已采用"保留原触发词 + 追加排除句"策略。
  • client_abort 与平台流式能力相关,长静默根治需平台开启流式输出与占位推送。

3. 09-07 验证:两条兑现、一条未兑现,诚实归因

同口径重跑(近 5 自然日、同等采样规模),已核实线上包版本号较基线推进、v2.2.0 已部署生效。目标兑现核对:

指标 基线 08-31 本轮 09-07 结论
明细覆盖率 52% 98% ✅ 巨型 trace 29→1,上下文膨胀显著缓解
中断率 12.7% 5.7% ✅ 目标达成
时延平均 / p95 93.0 / 258.8s 114.0 / 316.8s ⚠️ 未兑现
LLM 次数 p95 18 22.1 ⚠️ 上升(含统计口径变化:覆盖率提升后最胖 trace 被计入)

两条兑现、一条没兑现,我的建议是如实写:

  • 方案核心目标(误路由快速转出、降上下文膨胀、降滞留轮次)已获实证,明细覆盖率与中断率是直接证据。
  • 时延未兑现,主要归因全局模型因素——同期四个技能的单轮生成 p95 同步翻倍(约 19s→40s),不是文档改动能抵消的;待模型负载恢复后重测。
  • 下一轮重点看 LLM 次数 p95 是否回落、时延是否随全局恢复;对比时同时记录单轮生成耗时基线。(注:验证时按同口径对基线重新取数,其数值与最初抽样报告略有差异属正常。)

复盘:三条可复用的经验

  1. 负面禁令不足,需要正向声明。 两个案例反复印证同一件事:文档里写"禁止 X"几乎没用,要写"仅允许以下工具 / 范围",并尽可能在平台侧把工具从模型可见列表真正移除。案例一里明令禁止的检索工具被偷偷调用 53 次,就是最直接的证据。
  2. 健康度数字只是入口,trace 实证才是证据。 38 分和 53 分都只是红牌;真正指导整改的是"工具 × 声明对照表"和"慢 trace 画像"——前者抓出越权调用,后者抓出误路由。没有 trace 之前,一切归因都是猜测。
  3. M1 门禁:未验证假设不改文档。 "子 agent 空转""静默劝退""重复读取"这些假设被 trace 验证之前,不要动文档。先诊断、再验证、后改造——改错方向的返工成本,远高于诊断成本。

如果你也在治理 Agent Skill 的健康度,希望这两份实录能帮你少踩一个坑:先向 trace 要证据,再让文档说人话。