<!-- title: 技能优先级仲裁：破解多技能冲突 -->

# 技能优先级仲裁：破解多技能冲突

## 概述

当你在 Claude Code 里同时挂着几十甚至上百个 Skills 时，真正难的不是"造一个技能"，而是回答一个问题：**面对同一个请求，Claude 到底会执行哪个技能？** 本教程系统拆解 Skills 的多层仲裁机制——从同名覆盖链、Plugin 命名空间隔离、嵌套 monorepo 限定名，到 description 触发决策、调用权限控制、`skillOverrides` 仲裁层与 compaction 后的生命周期预算。读完你将能精确预测、诊断并解决任意复杂的技能冲突。

**适用人群**：已能独立编写 Skill 的开发者；维护大型 monorepo 或团队共享技能库的工程师；装了大量 Plugin 和社区技能、想理清"到底谁说了算"的重度用户。

## 前置条件

- Claude Code v2.1.145 或更高（新版 frontmatter 字段与 `/skills` 菜单需要此版本）
- 已至少手写过一个可运行的 `SKILL.md`，理解 `description` / `allowed-tools` 等基础字段
- 一个用于实验的 git 项目（嵌套实验需要 monorepo 结构）
- 基础熟悉 `settings.json` 的权限规则语法

---

## 一、先建立正确的认知模型：两层完全不同的"冲突"

很多人把"技能冲突"当成一个单一问题，实际上它发生在**两个正交的维度**上，必须分开诊断：

```mermaid
flowchart LR
    A[一个用户请求进入] --> B{维度一：覆盖解析}
    A --> C{维度二：触发选择}
    B --> B1[同名技能之间<br/>谁替代谁]
    C --> C1[同名之外<br/>Claude 调哪个]
    B1 --> D[确定性规则<br/>可精确预测]
    C1 --> E[基于 description<br/>的概率决策]
    style D fill:#d4edda
    style E fill:#fff3cd
```

- **维度一（覆盖解析，Cover Resolution）**：当多个技能**同名**时，哪个生效、哪个被替代。这是一组**确定性规则**，100% 可预测，与模型无关。
- **维度二（触发选择，Trigger Selection）**：当多个技能**不同名但语义重叠**时，Claude 模型基于 `description` 做的**概率性决策**。它受上下文、措辞、甚至 compaction 状态影响。

混淆这两个维度是排障失败的头号原因。下面逐一拆解。

---

## 二、维度一：同名覆盖链——谁能替代谁

### 1. 五级存储与覆盖优先级

Skills 按存储位置分为多个级别。官方给出的覆盖规则是**单向链条**：

| 级别 | 路径 | 覆盖能力 |
|------|------|---------|
| Enterprise（托管设置） | 见 managed settings | 覆盖所有人，最高 |
| Personal（个人） | `~/.claude/skills/<name>/SKILL.md` | 覆盖 Project 与 Bundled |
| Project（项目） | `.claude/skills/<name>/SKILL.md` | 覆盖 Bundled |
| Plugin | `<plugin>/skills/<name>/SKILL.md` | **独立命名空间，不参与覆盖链** |
| Bundled（内置） | 随 Claude Code 分发 | 被任何自定义同名技能覆盖 |

核心法则一句话：

> **enterprise overrides personal, and personal overrides project. A skill at any of these levels also overrides a bundled skill with the same name.**

这条规则的实战价值极高。一个典型场景：你觉得内置的 `/code-review` 检查项不符合团队规范，只需在项目里建一个 `.claude/skills/code-review/SKILL.md`，它就会**完整替换**内置版——无需改任何全局配置，无需禁用内置项。

### 2. Plugin 的命名空间隔离：永不冲突

Plugin skills 不走覆盖链，而是挂在一个**命名空间**下：

```
my-plugin/skills/review/SKILL.md   →   /my-plugin:review
```

这意味着即便你的项目里也有一个 `review` 技能，两者也能共存——Plugin 版用 `/my-plugin:review` 调用，项目版用 `/review` 调用。这是 Plugin 作为可分发单元的关键设计：**插件作者永远不用担心和用户的本地技能撞名**。

### 3. command 与 skill 同名时

历史遗留的 `.claude/commands/deploy.md` 与新式 `.claude/skills/deploy/SKILL.md` 功能等价（自定义命令已合并进 Skills）。但若两者**同名**，规则明确：**skill 优先**。迁移到 Skills 后建议删除同名 command 文件，消除歧义。

### 4. 实操：验证覆盖行为

```bash
# 1. 在项目内创建一个会覆盖内置 code-review 的技能
mkdir -p .claude/skills/code-review
cat > .claude/skills/code-review/SKILL.md <<'EOF'
---
description: 团队定制代码审查。使用场景：用户请求审查代码、review diff、检查提交前质量。
---

## 审查清单（团队规范 v3）
- 必须检查是否有硬编码密钥
- 必须检查是否有未处理的 Promise
- 必须验证错误码符合 RFC 标准约定
- 不关注代码风格，风格由 lint 处理
EOF
```

**预期结果**：在同一会话内输入 `/code-review`，触发的是上面的团队版而非内置版。注意——由于 Skills 支持**实时变更检测**（live change detection），新建的技能无需重启即可生效，**但前提是该 `.claude/skills/` 目录在会话启动时已存在**；如果是全新创建的顶层 skills 目录，仍需重启 Claude Code 以挂载目录监听。

---

## 三、维度一进阶：嵌套 monorepo 的限定名仲裁

这是覆盖链里最容易被忽略、却最容易引发"为什么跑错了技能"的环节。

在 monorepo 中，子包可以有自己的技能。当一个**嵌套**技能与其它层技能同名时，二者**并存而非互相覆盖**：

```
项目根: .claude/skills/deploy/SKILL.md        → /deploy
子包:   apps/web/.claude/skills/deploy/SKILL.md → /apps/web:deploy
```

仲裁规则：

1. 直接输入 `/deploy` → 永远执行**项目根**的版本。
2. 想执行子包版 → 必须显式输入 `/apps/web:deploy`（目录限定名）。
3. **Claude 自动选择时**：它读取的描述里会标注该技能作用于哪个目录，并依据"当前正在操作的文件所在目录"挑选匹配变体。

**常见问题与解决**：你在 `apps/web/` 下改代码，却感觉 deploy 流程用的是根目录的全局部署脚本。原因正是 Claude 根据文件路径仲裁——若子包技能的 `description` 没有写清"仅适用于 apps/web 前端"，模型就缺少仲裁依据。**修复方式**：给嵌套技能的描述加上明确的作用域声明，例如：

```yaml
description: 部署 apps/web 前端到 CDN。使用场景：在 apps/web/ 目录下工作、用户要部署前端、前端构建产物发布。
```

---

## 四、维度二：触发选择——description 是唯一的决策信号

当不存在同名问题时，Claude 在一堆候选技能中选谁，**完全取决于 `description`（含 `when_to_use`）的语义匹配**。这里没有确定性优先级，只有一个概率模型在匹配你的措辞。

### 1. 一个硬性约束：1536 字符截断

官方文档的关键数字——**`description` 与 `when_to_use` 合并后，在技能列表里被截断到 1536 个字符**。超过的部分模型**根本看不到**。这意味着：

- 把最关键的触发条件、最典型的用户措辞**放在最前面**。
- 别把"使用场景"写成长篇大论堆到末尾——模型可能读不到。
- 这个上限可用 `maxSkillDescriptionChars` 配置项调整。

### 2. 预算耗尽：描述被"整段"省略

更隐蔽的问题：即便单个描述没超 1536，**当你安装了大量技能时，所有描述共享一个总字符预算**。预算不够时，低优先级技能的描述会被省略，模型也看不到它们——这就是排障章节里"Skill descriptions are cut short"的根因。

三个调节旋钮：

| 旋钮 | 类型 | 作用 |
|------|------|------|
| `skillListingBudgetFraction` | settings | 设为 `0.02` 表示把总预算提升到上下文的 2% |
| `SLASH_COMMAND_TOOL_CHAR_BUDGET` | 环境变量 | 直接设定一个固定字符总数 |
| `skillOverrides` 里 `"name-only"` | settings | 让低优先级技能只列名字、不占描述预算 |

### 3. 实操：为仲裁而优化 description

差的描述（语义模糊、易撞）：

```yaml
description: 帮助处理代码。
```

好的描述（高区分度、含触发措辞）：

```yaml
description: 生成符合 Conventional Commits 规范的提交信息。使用场景：用户要求 commit、写提交信息、整理变更说明、询问改了什么需要提交。
```

**原则**：每个技能的描述都应回答"我和隔壁那个功能相近的技能，区别在哪"。区分度越高，仲裁越准。

---

## 五、维度二护栏：三个 frontmatter 字段精准控制调用权

当 description 仲裁不够可靠时，用确定性字段兜底。这三个字段决定了"谁有权发起这次调用"：

| Frontmatter | 用户能否调 | Claude 能否自动调 | 描述是否进上下文 | 典型用途 |
|-------------|-----------|-----------------|----------------|---------|
| 默认 | ✅ | ✅ | ✅ 始终在 | 普通技能 |
| `disable-model-invocation: true` | ✅ | ❌ | ❌ 不进上下文 | 有副作用的动作（deploy/commit） |
| `user-invocable: false` | ❌（菜单隐藏） | ✅ | ✅ 始终在 | 背景知识型技能 |

**两个高频踩坑点**：

1. **`user-invocable: false` 不能阻止程序调用**。它只控制 `/` 菜单的可见性。要真正禁止 Claude 通过 Skill 工具调用某技能，必须用 `disable-model-invocation: true`。
2. **`disable-model-invocation: true` 有连带效应**：它不仅禁止自动触发，还**把该技能从子代理的预加载列表中移除**——这对 `context: fork` 类技能影响很大。

实战示例——一个只允许手动触发、且自动放开 git 权限的安全 commit 技能：

```yaml
---
name: commit
description: 按团队规范暂存并提交当前变更。使用场景：用户明确要求提交、commit、生成提交。
disable-model-invocation: true
allowed-tools: Bash(git add *) Bash(git commit *) Bash(git status *)
---
```

设置 `disable-model-invocation: true` 后，即使你说"代码看起来可以了"，Claude 也不会擅自提交——时序控制权回到你手里。

---

## 六、维度二增强：`paths` 限定——按文件路径仲裁

`paths` 字段是触发仲裁中最被低估的护栏。它用 glob 模式限定技能**只在操作匹配文件时**才被自动加载：

```yaml
---
description: 应用本仓库的 Go 错误处理规范。
paths: "**/*.go"
---
```

价值在于：当你的个人技能库里有几十个技能，但只有进 Go 项目、操作 `.go` 文件时才需要"Go 错误处理规范"。`paths` 让它在不相关项目里**彻底沉默**，不占触发候选、不占描述预算。这对跨语言、跨技术栈的重度用户是减噪利器。

---

## 七、第三层仲裁：`skillOverrides` 与全局开关

有时你想仲裁的技能**不在你能编辑的范围内**——比如团队共享仓库里的技能、MCP 服务器提供的技能。这时用 `settings.json` 的 `skillOverrides` 层，而不是改 `SKILL.md`：

```json
{
  "skillOverrides": {
    "legacy-api-helper": "off",
    "noisy-but-useful": "name-only"
  }
}
```

- `"off"`：完全关闭，从 Claude 上下文中移除。
- `"name-only"`：只保留名字、省略描述，为其它技能腾出预算。
- 缺省项：视为 `"on"`。
- **重要例外**：Plugin skills **不受 `skillOverrides` 影响**，需通过 `/plugin` 管理。

更便捷的操作方式是用 `/skills` 菜单：高亮某技能，按 **Space** 在 `on` / `name-only` / `off` 间循环切换，按 **Enter** 自动写入 `.claude/settings.local.json`。

如果需要**彻底禁用所有内置技能**（`/code-review`、`/debug`、`/loop` 等），用 `disableBundledSkills` 设置；或用权限规则在 `/permissions` 中 deny 整个 `Skill` 工具，也可精细到 `Skill(commit)` 只允许特定技能。

---

## 八、第四层仲裁：compaction 后的生命周期预算

技能内容一旦被调用，就会作为一条消息**留在会话里直到结束**——除非触发 auto-compaction。压缩时的仲裁规则决定了"哪些技能在长会话里仍然有效"：

- 每个被调用过的技能，**最多保留前 5000 tokens**。
- 所有保留技能**共享 25000 tokens 的总预算**。
- 填充顺序：**从最近调用的技能开始**，预算耗尽则更早调用的技能**可能被整段丢弃**。

实战含义：长会话里"技能突然失效了"往往不是 bug，而是它在 compaction 后被挤出了预算。解决方法：在关键节点**重新调用一次**该技能以恢复完整内容；或精简技能正文，让它整体小于 5000 tokens 从而安全存活。

```mermaid
flowchart TD
    Start[用户请求] --> Q1{存在同名技能?}
    Q1 -->|是| Q2{是 Plugin 技能?}
    Q2 -->|是| NS[命名空间隔离<br/>plugin:skill 共存]
    Q2 -->|否| Q3{是嵌套 monorepo 同名?}
    Q3 -->|是| NEST[按目录限定名仲裁<br/>依据当前操作文件]
    Q3 -->|否| CHAIN[覆盖链: 企业>个人>项目>内置]
    Q1 -->|否| Q4{有 disable-model-invocation?}
    Q4 -->|是| MAN[仅用户手动 /name 触发]
    Q4 -->|否| Q5{描述在预算内且未超 1536 字符?}
    Q5 -->|否| MISS[模型看不到<br/>不会触发]
    Q5 -->|是| Q6{paths 限定匹配当前文件?}
    Q6 -->|否| SILENT[沉默不加载]
    Q6 -->|是| MATCH[Claude 用 description 语义匹配]
    MATCH --> EXEC[执行该技能]
    NS --> EXEC
    NEST --> EXEC
    CHAIN --> EXEC
    MAN --> EXEC
    EXEC --> Q7{长会话触发 compaction?}
    Q7 -->|是| BUD[保留每个技能前 5000 token<br/>共享 25000 总预算<br/>从最近调用填充]
    Q7 -->|否| END[正常保留]
    style MISS fill:#f8d7da
    style SILENT fill:#f8d7da
    style EXEC fill:#d4edda
    style BUD fill:#fff3cd
```

---

## 九、实战案例：诊断一个"装了 200 个技能的混乱系统"

场景：一位开发者从社区装了大量 Skills，现在抱怨"该触发的没触发、不该触发的乱触发、长会话里技能经常失效"。按下述流程逐层仲裁诊断。

**Step 1——排除覆盖层噪音**。运行 `/skills`，观察列表。若发现某些技能从未出现，检查是否被同名的高级别技能（个人级覆盖项目级）静默替换，或被 `skillOverrides` 设为 `off`。

**Step 2——检查描述预算**。若技能数量极多，低优先级技能描述大概率被预算截断。临时设环境变量诊断：

```bash
# 把总预算提到一个较大值，看触发是否改善
export SLASH_COMMAND_TOOL_CHAR_BUDGET=60000
```

若改善，说明根因是预算竞争。长期方案：把不常用技能在 `skillOverrides` 里设 `"name-only"`，为核心技能腾出空间。

**Step 3——用基准对比量化触发**。官方给出的判定法是**带对照的基准测试**：收集若干真实提示词，每个在**全新会话**里分别跑"技能可用"和"技能禁用"两次，对比结果。必须用新会话，因为编写技能时残留的上下文会掩盖指令缺陷。

**Step 4——交给 skill-creator 做 description 调优**。`skill-creator` 的 description tuning 能力会自动生成 should-trigger / should-not-trigger 提示词，测量命中率，并给出描述修改建议。这是把"祈祷式触发"升级为"工程化触发"的关键工具。

**Step 5——对有副作用的动作加确定性护栏**。所有 deploy、commit、发消息类技能统一加 `disable-model-invocation: true`，杜绝 Claude 基于语义误判而擅自执行。

---

## 十、触发排障三件套（官方诊断清单）

| 症状 | 根因 | 解决 |
|------|------|------|
| 技能从不触发 | 描述被预算截断 / 被高级别同名技能覆盖 / `paths` 不匹配 / 被 `skillOverrides` 关闭 | 提升预算、精简描述前置关键信息、检查 `paths`、检查 settings |
| 技能触发太频繁 | 描述过宽、与其它技能语义重叠 | 收紧描述、明确边界、必要时 `disable-model-invocation: true` |
| 技能描述被截断 | 总预算不足 / 单条超 1536 字符 | `skillListingBudgetFraction` / `SLASH_COMMAND_TOOL_CHAR_BUDGET` / `maxSkillDescriptionChars` / `name-only` |

一个反直觉的提醒：**"看到技能触发"只证明 Claude 找到了它，不证明它做了你想要的事**。触发命中率和输出符合度是两个独立指标，必须分开测量——这正是基准对比法的价值所在。

---

## 十一、仲裁检查清单

迁移到生产环境前，逐条核对你的技能库：

1. ☐ 是否有同名技能跨级别存在？预期内的是覆盖，意外的需改名或加命名空间。
2. ☐ 有副作用的动作是否都设了 `disable-model-invocation: true`？
3. ☐ 嵌套技能的描述是否写明了作用目录？
4. ☐ 每条描述是否把最关键触发措辞放在前 200 字符内（保险起见远小于 1536）？
5. ☐ 大型技能库是否设置了合理的预算或 `name-only` 策略？
6. ☐ Plugin 技能是否通过 `/plugin` 而非 `skillOverrides` 管理？
7. ☐ 长会话关键技能正文是否控制在 5000 tokens 内，或计划在关键节点重新调用？
8. ☐ 跨技术栈技能是否用 `paths` 限定，避免在不相关项目里噪声触发？

---

## 延伸阅读

- **Claude Code 官方 Skills 文档**：`code.claude.com/docs/en/skills`——所有仲裁规则的权威来源
- **Plugins reference**：`code.claude.com/docs/en/plugins-reference`——Plugin 命名空间与 schema 完整规范
- **skill-creator 技能**：内置的 description tuning 与触发基准测试工具
- **Agent Skills 开放标准**：Claude Code Skills 遵循的跨工具标准，理解它有助于编写可移植技能

掌握这套仲裁模型后，无论你的技能库扩张到多大规模，都能精确回答那个终极问题：**面对这个请求，到底谁说了算。**

## 参考来源

1. [Extend Claude with skills — Claude Code Docs](https://code.claude.com/docs/en/skills) — 覆盖链、命名空间、frontmatter 字段、触发排障与生命周期预算的官方权威定义
2. [Plugins reference — Claude Code Docs](https://code.claude.com/docs/en/plugins-reference) — Plugin skills 的命名空间隔离机制与 schema 完整技术规范
3. [Claude Code Explained (2026): MCP, Skills, Subagents, Hooks & Plugins](https://alexop.dev/posts/understanding-claude-code-full-stack/) — 2026 年 Skills 与其它扩展机制协同关系的实践梳理
4. [Claude Code Skills vs MCP vs Plugins: Complete Guide 2026](https://www.morphllm.com/claude-code-skills-mcp-plugins) — Skills、MCP、Plugins 三者边界与冲突场景的对比分析
5. [Claude Code Skills Ecosystem: The Complete 2026 Guide](https://getbeam.dev/blog/claude-code-skills-ecosystem-guide.html) — 大规模技能生态下的安装、管理与冲突处理经验

## 训练营适用性评估

**适用类型**：中高级开发者训练营、企业内部 Claude Code 推广营、DevOps/平台工程方向的内训。

**前置模块**：建议放在"Skill 基础开发"与"Plugin 打包分发"之后，作为进阶治理模块。

**预计教学时长**：理论讲解 60 分钟 + 动手实验 90 分钟。实验建议给学员一个预置了同名冲突、嵌套冲突和描述撞车的"问题 monorepo"，让他们按本文流程图逐层诊断修复。

**考核点**：能否预测给定配置下的最终生效技能；能否用基准对比法量化触发命中率；能否正确选择 frontmatter 字段而非修改 SKILL.md 来仲裁他人技能。

> [!tip] 51学通信知识星球
> **星主：爱卫生**（微信：gprshome201101）——公众号「51学通信」创办者，19 年通信行业运维与讲师经验，著有《GPRS网络信令实例详解》《EPC原理与实践》《5G核心网原理与实践》三本纸质书（各大电商平台有售）。
> **星球定位**：深耕 5G 核心网、IMS、NFV/AI、云原生等 ICT 领域，主打运维岗位与信令分析。
> **当前规模**：5200 篇主题 / 990 个回答，198 元/年。
> **加入福利**：加入星球后请加爱卫生微信，拉您进知识星球年度陪伴与答疑群——不限量回复您的各种问题，另有群内分享。
> **AI 加持**：51学通信知识星球已作为 skill 接入 WorkBuddy，使用 deepseek-4-flash 在海量星球帖子中精准找贴、找视频、找 FAQ 和案例，做总结、找文档和 PPT 等场景全覆盖。

![51学通信知识星球海报-扫码加入](https://wiki.500nian.com/images/zhixingqiu_qrcode.png)
