前两篇分别处理了 LLM 调用太多和 subagent 切换太贵的问题。效率专题的第三个问题出现在工具入口上:如果用户每次都要判断该跑 lint、trigger 还是 check,系统依然不够顺手。
sentry-static 的入口收敛,解决的不是"少一个命令名"这么简单,而是把用户的一次完整静态分析意图收进一个稳定入口。本文讨论的原则是:工具边界应该按用户意图划分,而不是按内部检查项划分。
回顾:三个版本,三种形态
| 版本 | 工具形态 | 用户操作 |
|---|---|---|
| v5.x-v6.x | sentry-lint + sentry-trigger(两个独立工具) |
说两次、跑两次、看两份报告 |
| v7.1 | sentry-check(两者合并) |
说一次、跑一次、看一份报告(含两部分) |
| 稳定形态 | sentry-static(Lint + Trigger + Summary + 后续检查组) |
说一次、跑一次、看一份报告 + 发布建议 |
表面看只是改了名字、合了入口、加了检查维度,但每次变形背后都有一个工程决策点。
第一次合并:sentry-lint + sentry-trigger → sentry-check(v7.1)
合并前的痛点
v6.x 里 lint 和 trigger 是两个完全独立的工具:
arduino
sentry-lint → 静态结构检查,~30s
sentry-trigger → 触发率 AI 模拟(TP/TN),~2min
实际使用中发现三个问题:
1. 几乎没有人只跑一个
我们复盘过 20+ 次真实测评的调用模式,内部统计显示:
- 92% 的情况:用户同时需要两者
- 5% 的情况:只跑 lint(快速检查结构)
- 3% 的情况:只跑 trigger(微调 description 后重测)
两个工具意味着两次 spawn、两次 yield/resume、两份回执------但用户 92% 的时间里只有一个意图:「帮我看看这个 Skill 写得好不好」。
2. 报告割裂导致用户需要自行关联
lint 报告说「description 太短,缺少不触发场景」,trigger 报告说「TN 不触发率只有 40%」。
这两个结论之间有因果关系------正是因为 description 缺少「不触发场景」描述,导致 AI 在判断是否触发时没有足够的排除信号。但两份独立报告里看不到这种关联。
3. 编排器需要额外逻辑决定先后
主编排器需要先跑 lint、再跑 trigger(因为如果 description 都不存在,trigger 跑了也没意义)。这种「先后依赖 + 条件跳过」逻辑增加了编排器的复杂度。
合并后的设计
xml
sentry-check:
Part 1: 静态检查,~30s
Part 2: 触发率评估(TP/TN),~2min
支持子模式:
lint <Skill名> → 只跑 Part 1
测触发率 <Skill名> → 只跑 Part 2
check <Skill名> → 两项都跑
向后兼容------旧的 lint 和 测触发率 命令继续有效。
合并判断标准:如果两个工具 >80% 的调用场景里总是一起出现,且它们的输入相同(都是读 SKILL.md),合并通常是正确的。
第二次演进:sentry-check → sentry-static(状态机阶段)
为什么不继续叫 sentry-check
v7.1 的 sentry-check 本质上是「把两个工具的输出拼在一起」。用户看到的是:
makefile
## Part 1 · 静态检查
L1: ✅ / ⚠️ / ...
L2: ...
L3: ...
L4: ...
L5: ...
## Part 2 · 触发率评估
TP: 80%
TN: 67%
然后用户自己判断:「L1 说 description 没问题,但 TN 只有 67%,说明不触发场景虽然有,但写得不够精准。」
问题在于:这个推理应该由工具自动完成。
状态机阶段 新增 Sub-step 3:综合建议
vbnet
sentry-static:
Sub-step 1: Lint(静态规则检查)
Sub-step 2: Trigger(TP/TN 触发率评估)
Sub-step 3: Summary(交叉分析 + 综合发布建议)
Sub-step 3 的逻辑:
| Lint 信号 | Trigger 信号 | 综合建议 |
|---|---|---|
| L1 description 完整 | TP ≥ 80%, TN ≥ 80% | ✅ 静态检查通过,建议进入测评 |
| L1 description 完整 | TP ≥ 80%, TN < 80% | ⚠️ 触发精度不足:补充不触发场景描述 |
| L1 description 不完整 | TP < 80% | ❌ 根源:description 信息不足,先补完再测 |
| L2 缺少 HiL | --- | ❌ 安全问题:不可逆操作必须加确认节点 |
| L3 复杂度 > 20 | --- | ⚠️ 建议拆分,否则执行稳定性难保证 |
关键改变:从「给两组数据」变成「给一个判断 + 理由」。用户不需要自己关联两份报告------工具帮你做了。
为什么改名
sentry-check 的语义是「检查」------暗示输出是一堆检查项。sentry-static 的语义是「静态分析」------暗示输出是分析结论。
名字的改变反映了工具定位的变化:从「数据展示」到「分析判断」。
旧 sentry-check 怎么处理
现在的实现里,原 sentry-check 是兼容入口,不是推荐入口:
markdown
# sentry-check(兼容入口)
此工具已被 sentry-static 替代。
如果你是通过旧命令到达这里,请改用 sentry-static。
所有旧命令仍然有效:
- lint <Skill名> → sentry-static --lint-only
- 测触发率 <Skill名> → sentry-static --trigger-only
- check <Skill名> → sentry-static(完整模式)
为什么保留兼容入口而不直接删除?因为用户(和 AI 编排器)可能对 sentry-check 有肌肉记忆。兼容入口起到重定向作用,零成本地处理旧路径。
独立模式仍然保留
合并不意味着失去精细控制:
arduino
sentry-static --lint-only → 只跑 Sub-step 1(~30s)
sentry-static --trigger-only → 只跑 Sub-step 2(~2min)
sentry-static → 三步全跑(~2.5min)
保留独立模式的场景:
- 微调后快速验证:改了 description 后只想验触发率,不需要重跑全部 lint
- CI 集成:CI 环境只需要 lint(确定性检查),trigger 涉及 AI 推理,耗时且结果波动
- 调试单项:某一项不通过时,重跑单项比等全部快
设计决策框架:何时该合并、何时该拆分
从 sentry-lint/trigger → sentry-check → sentry-static 的演进中,我总结出一套判断标准:
合并的信号
| 信号 | 强度 |
|---|---|
| >80% 调用场景里一起使用 | 强信号 |
| 输入完全相同(同一份文件) | 强信号 |
| 输出之间有因果关系需要交叉分析 | 强信号 |
| 合并后可以减少 1 次 spawn/yield | 中信号 |
| 用户分不清两个工具的区别 | 弱信号 |
拆分的信号
| 信号 | 强度 |
|---|---|
| 执行时间差异 >10x | 强信号 |
| 一个失败不应阻止另一个执行 | 强信号 |
| 不同的输入来源 | 中信号 |
| 权限要求不同 | 中信号 |
| 复用场景完全不同(被不同上游调用) | 弱信号 |
应用到 SkillSentry 的例子
为什么 sentry-static 和 cases 步骤不合并?
- 输入不同:static 只读 SKILL.md,cases 还需要 inputs/ 素材
- 失败独立:static 失败(结构有问题)时,用户可能选择修复后才跑 cases
- 时间差异:static ~2.5min,cases ~5-8min
- 调用场景不同:用户可能只想 lint 不想设计用例
三个拆分信号都命中------不合并是正确的。
对 Pipeline 状态机的影响
sentry-static 的引入对 状态机阶段 Pipeline 设计有一个关键影响:
Pipeline 数组的第一步从 check 变成 static:
json
// v7.x(非正式 pipeline)
["check", "cases", "executor", "grader", "report"]
// 状态机阶段+ 正式 Pipeline
["static", "cases", "sync-pull", "sync-push-cases",
"executor-with", "grader", "sync-push-results", "report", "publish"]
状态机只认 Pipeline 数组里的 step name。当工具改名时,Pipeline 数组必须同步更新。这就是为什么当前主流程只写 static,不再把 lint、trigger、check 写成正式 pipeline step。
工具链演进的一般规律
回顾 SkillSentry 从 v5.x 到稳定形态的工具演进:
ini
v5.x: 5 个独立工具(lint, trigger, cases, executor, grader)
v6.x: 5 个 + sync + report = 7 个
v7.1: 合并 → check + cases + executor + grader + report = 5 个
状态机阶段: 重组 → static + cases + executor + grader(含report) + report(独立)
+ comparator + analyzer + openclaw = 8 个
稳定形态: 收敛 → static 是推荐入口;grader-report 是主流程评分报告;
sentry-report 仅用于已有 grading 后独立重出报告
工具数量不是越少越好,也不是越多越好。判断标准是:每个工具对应一个「用户意图的最小完整单元」。
- v6.x 的 7 个工具太碎------lint 和 trigger 不是独立意图
- 如果把所有工具合成 1 个------那就是把「工具」做成了「应用」,失去了可组合性
最终形态是在「原子可组合」和「意图完整」之间找到平衡点。
后续扩展:规则组 6------规范合规检查
入口收敛解决的是"用户只需要记一个静态分析入口":Lint、Trigger、Summary 和后续检查组都收进 sentry-static。下面的 L6 不是新增入口,而是在这个稳定入口内部继续增加的检查维度,用来回答一个更基础的问题:SKILL.md 的结构是否完整?
一个真实案例:某个 Skill 通过了 L1-L5 全部检查,但新人接手时完全不知道它解决什么问题、依赖哪些环境变量、输入输出格式是什么、覆盖/不覆盖哪些场景。这些不是"规则",是"结构"------决定了 Skill 能不能被团队理解和维护。
为什么结构完整度也是质量指标
对照《MIT AI Skill 撰写规范 V1.1-beta》,一份标准 SKILL.md 应该覆盖 13 个章节。每个章节对应一个实际问题:
| 章节 | 对应的实际问题 |
|---|---|
| 问题描述 | 新人看不懂这个 Skill 为什么存在 |
| 触发场景 | AI 不知道什么时候该激活 |
| 交互契约 | Agent 可能自作主张执行危险操作 |
| 架构概览 | 维护者不知道改哪个文件影响什么 |
| 端到端示例 | 开发者不知道"跑一次"长什么样 |
| 输入/输出契约 | 集成方不知道传什么、收什么 |
| 健壮性能力 | 没人知道失败了会怎样 |
| 限制与边界 | 用户以为它什么都能做 |
缺一个章节,就多一个"凭感觉"的环节。
L6 的三层检查
L6a:Frontmatter 9 字段------name、display_name、version、description、author、track、platform、spec、tags。缺 name/version 会影响 CI 缓存命中(sentry_preflight.py 用 name + hash 判断复用)。
L6b:13 章节覆盖率------逐项检查是否存在对应内容(不是看标题,是看实质内容):
- ✅ 存在且实质性
- ⚠️ 散落在其他章节中(建议独立)
- ❌ 完全缺失
L6c:合规度评级:
erlang
≥ 90% → ✅ 合规 70-89% → ⚠️ 基本合规
50-69% → ⚠️ 部分合规 < 50% → ❌ 不合规
和 L1-L5 的关系
L6 不替代 L1-L5。一个 Skill 可以 L1-L5 全绿但 L6 只有 35%------能跑,但别人接不住。反过来 L6 100% 但 L2 红(写操作没确认),也不能发布。六组一起看才是完整的静态质量画像。
CI 中的定位
L6 评级可以写入结构化诊断产物或报告,但不作为 PASS/FAIL 的否决项------它是参考指标,帮助发布决策者判断"这个 Skill 是否已经准备好交给别人用"。已有的、能正常工作的 Skill 不应该因为"文档不全"被卡住。
FAQ
Q:sentry-static 的 Sub-step 3 会不会引入 AI 判断的不确定性?
Sub-step 3 的判断逻辑是规则化的------基于静态检查项和 TP/TN 的数值阈值,不是让 AI 自由发挥。AI 只负责生成自然语言的解释文本,判断本身是确定性的。
Q:从 sentry-check 迁移到 sentry-static 需要改什么?
用户侧:推荐入口统一成 sentry-static。lint、测触发率、check 这类旧说法可以继续被兼容或重定向,但不再作为正式入口推荐。
Pipeline 侧:如果你有自定义的 pipeline 配置,把 step name 从 check 改成 static 即可。
Q:兼容入口会一直保留吗?
当前仍保留兼容入口。是否删除不应按版本号拍脑袋,而应看日志中是否还有旧命令调用;只要仍有调用,就应保留重定向并在文档里明确当前推荐入口是 sentry-static。
来源:sentry-static 设计文档、SkillSentry contract、历史 sentry-check/SKILL.md。