前两篇分别讨论了 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 是两个相互独立、互不关联的工具:
sentry-lint → 静态结构检查,~30s
sentry-trigger → 触发率 AI 模拟(TP/TN),~2min
实际使用中,问题逐渐浮现。
1. 几乎没有人只运行一个
复盘了 20 多次真实测评的调用模式,数据很能说明问题:
- 92% 的情况:用户同时需要两者
- 5% 的情况:仅运行 lint(快速检查结构)
- 3% 的情况:仅运行 trigger(微调 description 后重测)
这便陷入了一种尴尬处境。两个工具意味着需要发起两次进程、两次等待、收取两份回执——但用户在 92% 的时间里,目的只有一个:「帮我评估一下这个 Skill 写得好不好」。用户的意图是完整的,但工具却将它人为割裂成两半。
2. 报告割裂导致用户需自行关联
lint 报告指出“description 过短,缺少不触发场景”,trigger 报告显示“TN 不触发率仅为 40%”。这两句话之间的因果关联,其实一目了然——正因为 description 没有清晰说明“什么情况下不该触发”,导致 AI 判断模棱两可。但两份独立的报告,并不会主动帮用户建立这种逻辑连接。用户只能自己充当侦探。
3. 编排器需额外逻辑决定执行顺序
主编排器必须先运行 lint,再运行 trigger。为什么?因为如果 description 本身就不存在,运行 trigger 完全是徒劳。这种“先后依赖 + 条件跳过”的逻辑,额外增加了编排器的复杂度,属于典型的架构内耗。
合并后的设计
sentry-check:
Part 1: 静态检查,~30s
Part 2: 触发率评估(TP/TN),~2min
支持子模式:
lint → 只跑 Part 1
测触发率 → 只跑 Part 2
check → 两项都跑
同时,原有的 lint 和 测触发率 命令保持兼容,避免老用户措手不及。
合并的判断标准其实很朴素:如果一个工具的功能在超过 80% 的调用场景中总是成双成对出现,并且它们的输入源完全一致(都读取 SKILL.md),那么合并基本就是正确的选择。
第二次演进:sentry-check → sentry-static(状态机阶段)
为什么不继续叫 sentry-check
v7.1 的 sentry-check,本质上是“将两个工具的输出拼接在一起”。用户看到的报告是这样:
## Part 1 · 静态检查
L1: ✅ / ⚠️ / ...
L2: ...
L3: ...
L4: ...
L5: ...
## Part 2 · 触发率评估
TP: 80%
TN: 67%
然后用户必须自己琢磨:“L1 说 description 没问题,但 TN 只有 67%……这说明不触发场景虽然存在,但写得不够精准啊。”这个推理过程,难道不该由工具自动完成吗?
状态机阶段:新增 Sub-step 3:综合建议
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 作为兼容入口保留,但因为有了更好的选择,它不再是推荐入口:
# sentry-check(兼容入口)
此工具已被 sentry-static 替代。如果你是通过旧命令到达这里,请改用 sentry-static。
所有旧命令仍然有效:
- lint → sentry-static --lint-only
- 测触发率 → sentry-static --trigger-only
- check → sentry-static(完整模式)
为什么不直接删除,一了百了?答案很简单:用户(以及 AI 编排器)的肌肉记忆非常顽固。兼容入口就像一个温柔的引导员,可以把所有旧路径零成本地重定向到新地址。
独立模式仍然保留
合并,不等于丧失对手脚的精细控制:
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 次进程启动或等待 | 中信号 |
| 用户分不清两个工具的区别 | 弱信号 |
拆分的信号
| 信号 | 强度 |
|---|---|
| 执行时间差异超过 10 倍 | 强信号 |
| 一个失败不应阻止另一个执行 | 强信号 |
| 不同的输入来源 | 中信号 |
| 权限要求不同 | 中信号 |
| 复用场景完全不同(被不同上游调用) | 弱信号 |
应用到 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。
// 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 到稳定形态的整个演进路线:
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:合规度评级:
≥ 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。
