第 29 期 | SKILL.md 结构深度剖析:渐进式披露 (Progressive Disclosure)
🎯 学习目标
学完本期课程,你将能够:
- 深入理解 SKILL.md 的模块化与分层设计,以及其在复杂场景下的重要性。
- 掌握渐进式披露 (Progressive Disclosure) 机制在大模型技能管理中的应用原理。
- 分析大模型与 SKILL.md 之间双向消息通信的工作流程,理解其如何高效利用上下文。
- 设计和优化复杂的 SKILL.md 文件,有效避免大模型上下文溢出,提升性能和成本效益。
📖 核心概念讲解
在大模型应用开发中,SKILL.md 作为承载模型外部技能和知识的关键载体,其设计与管理直接影响着大模型的性能、效率和稳定性。本期我们将深入探讨 SKILL.md 的内部结构,特别是其如何通过“渐进式披露”机制,巧妙地解决了大模型在处理海量技能时面临的上下文爆炸问题。
29.1 SKILL.md 的分层与模块化结构
许多初学者可能认为 SKILL.md 只是一个简单的、线性的 Markdown 文件,其中包含了所有工具的定义、能力描述和使用示例。然而,对于一个拥有数十甚至上百种工具的复杂应用来说,将所有信息一次性载入大模型的上下文窗口是不可行的,这会导致上下文溢出、推理效率低下以及成本急剧增加。
为了解决这个问题,SKILL.md 被设计成一种分层和模块化的结构。它不仅仅是文本的堆砌,更像是一个可索引的知识库,其不同部分承载着不同粒度的信息。
典型的 SKILL.md 结构可能包含以下几个核心模块:
# Skill Name(顶层标题):定义整个技能集的名称和总览。## Overview(概览):提供技能集的简要描述、核心功能和应用场景。这是大模型在首次接触技能时最先读取的部分,用于快速判断该技能是否与当前用户意图相关。## Capabilities(能力列表):列出该技能集所能提供的具体能力,通常以高层次的功能点描述,而非具体的工具方法。例如:“管理项目任务”、“发送即时通知”、“查询数据库记录”等。## Tools(工具定义):详细描述每个工具的名称、用途、API 接口、参数、返回值等。这部分通常是 SKILL.md 中最庞大和最详细的模块,并且每个工具内部也可以进一步细分。### Tool Name(工具名称)#### method_name(param1: type, param2: type)(方法签名及描述)##### Parameters(参数详细说明)##### Returns(返回值详细说明)
## Examples(使用示例):提供具体的用户输入、模型思考过程和工具调用的示例。这些示例对于模型理解如何正确使用工具至关重要,尤其是在处理不明确或复杂的用户请求时。### Example N: [描述]User Input:Thoughts:Tool Call:
分层结构示意图:
SKILL.md
├── # Skill Name
│ ├── ## Overview
│ │ └── (高层描述)
│ ├── ## Capabilities
│ │ └── (能力列表)
│ ├── ## Tools
│ │ ├── ### Tool A
│ │ │ ├── #### Tool A Method 1
│ │ │ │ ├── ##### Parameters
│ │ │ │ └── ##### Returns
│ │ │ └── #### Tool A Method 2
│ │ │ ├── ##### Parameters
│ │ │ └── ##### Returns
│ │ ├── ### Tool B
│ │ │ └── (类似结构)
│ │ └── ...
│ └── ## Examples
│ ├── ### Example 1
│ │ └── (用户输入、思考、工具调用)
│ ├── ### Example 2
│ │ └── (用户输入、思考、工具调用)
│ └── ...
这种结构允许大模型在不同阶段,根据其推理需求,选择性地加载和关注 SKILL.md 的特定部分,而不是一次性处理整个文件。
29.2 渐进式披露 (Progressive Disclosure) 机制
渐进式披露是一个源自用户体验设计领域的概念,其核心思想是:在用户需要时才显示相关信息,避免信息过载。 在 SKILL.md 和大模型的交互中,这一原则被巧妙地应用,成为解决上下文爆炸问题的关键机制。
工作原理:
初始阶段 (高层披露):当大模型首次接收到用户请求时,它不会立即加载整个 SKILL.md。相反,它会优先加载 SKILL.md 的高层信息,例如
## Overview和## Capabilities部分。这些信息通常足够模型初步判断用户意图是否与当前技能集相关。这就像一个图书馆的目录,模型首先查阅目录,而不是直接翻阅所有书籍。需求驱动 (按需披露):如果大模型通过高层信息判断用户意图可能需要使用某个技能,它会进一步深入。例如,如果用户提到了“创建任务”,模型会意识到可能需要项目管理工具。此时,它会向背后的系统(通常是 Agent 框架或一个专门的技能管理模块)发出一个内部请求,要求加载与“任务创建”相关的具体工具定义,例如
### jira_api工具下的create_issue方法。细节补充 (逐步披露):在加载了特定工具的定义后,如果模型在构建工具调用时遇到不确定性(例如,不确定某个参数的含义或需要了解具体的使用场景),它可能会再次向系统请求加载
## Examples中与该工具相关的示例。这些示例提供了具体的输入-输出映射,帮助模型更好地理解和执行工具调用。
为什么这能避免上下文爆炸?
- 聚焦相关性:大模型只将与当前任务最直接相关的信息加载到其有限的上下文窗口中。无关的工具定义、不相关的示例在大多数时候都不会被加载,从而极大地减少了上下文的负担。
- 动态调整:上下文内容是动态变化的。随着对话的推进和任务的演进,模型会不断地“卸载”不再需要的信息,并“加载”新的相关信息。
- 提高效率:由于每次需要处理的信息量更小,模型的推理速度更快,从而提高了整体响应效率。
- 降低成本:大模型的 API 调用通常按 token 数量计费。通过减少每次调用的 token 数量,渐进式披露直接降低了运行成本。
渐进式披露机制并非由大模型本身直接实现,而是由其外部的 Agent 框架或技能管理系统负责。这个系统充当了 SKILL.md 和大模型之间的“智能中介”,根据大模型的意图和当前上下文,动态地检索和提供 SKILL.md 中的相关片段。
29.3 双向消息通信原理与上下文管理
渐进式披露的背后,是一个高效的双向消息通信机制。大模型与外部系统(技能管理模块)之间不仅仅是单向地“读取”SKILL.md,而是一种主动的、交互式的沟通。
通信流程:
大模型发出意图(请求):
- 当大模型接收到用户输入后,它会首先进行初步分析。
- 根据其内部知识和当前上下文,它会形成一个“思考”或“计划”。
- 如果这个思考指向了需要外部技能,大模型会通过一个特殊的机制(例如,一个内部的
request_skill_info或get_tool_definition指令)向外部系统表达其需求。这个需求可能非常抽象(“我需要了解项目管理能力”)或非常具体(“我需要jira_api.create_issue的参数细节”)。 - 这种请求并非直接的 API 调用,而更像是大模型“思考”流程中的一个特殊信号,被外部系统捕获。
外部系统响应(提供信息):
- 外部系统(例如 Agent 框架或一个专门的 SKILL.md 解析器)接收到大模型的请求信号后,会解析其意图。
- 它会根据请求,从预加载的 SKILL.md 库中精确地检索出对应的片段。例如,如果请求是“
jira_api.create_issue的参数细节”,系统会直接定位到SKILL.md中## Tools下### jira_api中#### create_issue的##### Parameters部分,并将这部分 Markdown 文本提取出来。 - 然后,外部系统将这些提取出的相关信息作为新的上下文片段注入回大模型的输入流中,或者作为大模型工具调用的“返回结果”呈现。
大模型利用信息并迭代:
- 大模型接收到外部系统提供的 SKILL.md 片段后,会将其整合到当前的上下文进行进一步的推理。
- 它可能会利用这些信息来完善工具调用的参数、生成更准确的回复,或者基于新信息做出新的决策。
- 如果仍然需要更多信息(例如,发现当前工具定义不足以完成任务,需要查看示例),它会再次发起新的请求,重复上述过程。
上下文管理的关键:
这种双向通信机制结合了检索增强生成 (RAG) 的思想,但更聚焦于结构化技能信息的动态检索。它确保了:
- 最小化上下文载荷:只有在真正需要时才加载信息,且只加载所需部分。
- 精准信息注入:外部系统能够理解大模型的细粒度需求,并提供高度相关的上下文。
- 动态适应性:模型能够根据对话的进展和任务的复杂性,动态地调整其上下文内容。
- 避免冗余:减少了模型在大量无关信息中“大海捞针”的计算成本。
通过这种精妙的机制,即使面对包含数百个工具和数万行描述的庞大 SKILL.md 文件,大模型也能以高效、经济的方式运行,而不会因上下文溢出而崩溃。这是构建真正智能和可扩展 Agent 的基石。
💻 模拟 Claude TUI 交互
以下模拟展示了 Claude 如何通过渐进式披露机制,逐步加载 SKILL.md 中的信息,以响应用户的不同请求。假设我们有一个名为 ProjectPilot 的 SKILL.md,用于管理项目任务。
场景 1: 初步了解技能集概览
用户首次与 Claude 交互,想了解它能做什么。
> 你能帮我做什么项目管理方面的事情?
╭─ Claude ──────────────────────────────╮
│ 根据你的问题,我正在查阅 `ProjectPilot` 技能的概览信息。 │
│ (内部操作:系统向 Claude 注入 `ProjectPilot` SKILL.md 的 `## Overview` 和 `## Capabilities` 部分)│
│ │
│ 好的,我可以使用 `ProjectPilot` 技能协助你进行项目管理。我能帮你: │
│ - 创建新的项目和任务 │
│ - 分配任务给团队成员 │
│ - 更新任务状态和截止日期 │
│ - 生成项目进度报告 │
│ - 查询项目数据(例如,某个成员的任务列表) │
│ │
│ 你有什么具体的项目管理需求吗? │
╰───────────────────────────────────────╯
解释:Claude 并没有加载整个 SKILL.md。它只加载了 Overview 和 Capabilities 部分,这足以让它理解并介绍自己的高层能力。
场景 2: 请求具体工具方法
用户决定创建一个新任务,Claude 需要更详细的工具定义。
> 请帮我在 "Alpha 项目" 中创建一个新任务,名称是 "设计用户界面",分配给 @张三,下周五完成。
╭─ Claude ──────────────────────────────╮
│ 好的,我理解你的需求是创建一个新任务。这需要用到项目管理工具。 │
│ (内部操作:Claude 识别到“创建任务”意图,向系统请求 `ProjectPilot` SKILL.md 中与“创建任务”相关的工具定义,例如 `jira_api.create_issue` 方法的详细信息。系统将 `### jira_api` 下 `#### create_issue` 的参数和描述注入 Claude 上下文。)│
│ │
│ 为了确保任务创建成功,我需要确认一些参数。 │
│ 根据 `jira_api.create_issue` 工具的定义,我需要以下信息: │
│ - `project_key`: 项目的唯一标识符,例如 "ALPHA"。 │
│ - `summary`: 任务的简要标题。 │
│ - `description`: 任务的详细描述(可选)。 │
│ - `issue_type`: 任务类型,例如 "Task", "Bug", "Story"。 │
│ - `assignee_id`: 任务分配给的成员 ID。 │
│ - `due_date`: 任务的截止日期。 │
│ │
│ 你提到的 "Alpha 项目" 是指 `project_key` 为 "ALPHA" 吗?任务类型是 "Task" 吗?│
│ 请提供张三的精确用户 ID。 │
╰───────────────────────────────────────╯
解释:Claude 此时加载了 jira_api.create_issue 方法的具体定义(包括参数说明),并利用这些信息来向用户询问缺失的参数。整个 ProjectPilot SKILL.md 的其他工具或示例仍未加载。
场景 3: 请求使用示例进行澄清
用户对某个参数的格式不确定,Claude 进一步加载示例来帮助理解。
> 我不确定张三的 ID 是什么格式,以及截止日期应该怎么写?
╭─ Claude ──────────────────────────────╮
│ 我明白了,你对 `assignee_id` 和 `due_date` 的格式有疑问。 │
│ (内部操作:Claude 识别到用户对参数格式的困惑,向系统请求 `ProjectPilot` SKILL.md 中与 `jira_api.create_issue` 工具相关的 `## Examples` 部分。系统将相关示例注入 Claude 上下文。)│
│ │
│ 好的,我查阅了相关示例。 │
│ 通常 `assignee_id` 是一个字符串,例如 "zhang.san" 或 "zs001"。你需要根据你的 Jira 系统实际的用户 ID 来填写。│
│ `due_date` 期望的格式通常是 "YYYY-MM-DD",例如 "2023-11-17" 代表 2023 年 11 月 17 日。│
│ │
│ 现在你能提供这些信息来创建任务了吗? │
╰───────────────────────────────────────╯
解释:当需要更多上下文来解决歧义时,Claude 会请求并加载 Examples 部分。这再次证明了其按需加载、渐进披露的机制。每次只加载最相关的信息片段,而不是整个庞大的 SKILL.md。
💻 代码演示
这里我们将展示一个简化的 ProjectPilot.SKILL.md 文件结构,突出其分层和模块化设计。虽然我们无法直接“编写代码”来演示 Claude 的内部加载机制,但我们可以通过清晰的 Markdown 结构来体现其可被渐进披露的特性。
# ProjectPilot Skill: 智能项目管理助手
## Overview
ProjectPilot 是一个强大的项目管理助手技能集,旨在帮助团队高效地规划、执行和跟踪项目。它集成了多种项目管理工具,支持任务创建、状态更新、进度查询和团队协作通知。
## Capabilities
- **任务生命周期管理**: 从任务创建到完成的全面跟踪。
- **团队协作增强**: 通过即时通讯工具发送通知和更新。
- **数据洞察**: 生成项目报告和查询关键指标。
- **资源分配**: 协助分配任务给团队成员。
## Tools
### `jira_api`
与 Jira 项目管理系统交互,用于创建、更新和查询任务及项目信息。
该工具通过 REST API 与 Jira 后端通信。
#### `jira_api.create_issue(project_key: str, summary: str, description: Optional[str], issue_type: str, assignee_id: Optional[str], due_date: Optional[str])`
创建一个新的 Jira 问题(任务、Bug、Story 等)。
##### Parameters:
- `project_key` (string, **required**): Jira 项目的唯一键(例如 "PROJ")。
- `summary` (string, **required**): 问题的简短标题。
- `description` (string, optional): 问题的详细描述。
- `issue_type` (string, **required**): 问题的类型(例如 "Task", "Bug", "Story")。
- `assignee_id` (string, optional): 负责此问题的用户 ID。
- `due_date` (string, optional): 问题的截止日期,格式为 "YYYY-MM-DD"。
##### Returns:
- `issue_id` (string): 创建成功的问题 ID。
- `issue_url` (string): 创建成功的问题在 Jira 中的 URL。
#### `jira_api.update_issue_status(issue_id: str, status: str)`
更新指定 Jira 问题的状态。
##### Parameters:
- `issue_id` (string, **required**): 要更新的问题 ID。
- `status` (string, **required**): 新的状态(例如 "In Progress", "Done", "To Do")。
##### Returns:
- `success` (boolean): 操作是否成功。
### `slack_notifier`
发送消息到 Slack 频道或用户。
该工具用于团队内部的即时沟通和通知。
#### `slack_notifier.send_message(channel: str, message: str)`
向指定的 Slack 频道发送一条文本消息。
##### Parameters:
- `channel` (string, **required**): Slack 频道名称(例如 "#general" 或 "@username")。
- `message` (string, **required**): 要发送的文本消息内容。
##### Returns:
- `success` (boolean): 消息是否成功发送。
## Examples
### Example 1: 创建一个新任务
**User Input**: "在 '营销项目' 里创建一个新任务,叫 '撰写推广文案',分配给 @小李,下周三前完成。"
**Thoughts**: 用户请求创建任务,需要使用 `jira_api.create_issue`。我需要识别项目键、任务标题、负责人和截止日期。假设 '营销项目' 对应 `project_key` 为 "MKT",小李的用户 ID 是 "li.xiaoli"。
**Tool Call**:
```json
{
"tool_name": "jira_api",
"method_name": "create_issue",
"parameters": {
"project_key": "MKT",
"summary": "撰写推广文案",
"issue_type": "Task",
"assignee_id": "li.xiaoli",
"due_date": "2023-11-15"
}
}
Example 2: 更新任务状态并通知团队
User Input: "把 'MKT-123' 任务状态更新为 '已完成',并通知 #营销团队 任务已完成。"
Thoughts: 用户请求更新任务状态并发送通知。这需要 jira_api.update_issue_status 和 slack_notifier.send_message。
Tool Calls:
[
{
"tool_name": "jira_api",
"method_name": "update_issue_status",
"parameters": {
"issue_id": "MKT-123",
"status": "Done"
}
},
{
"tool_name": "slack_notifier",
"method_name": "send_message",
"parameters": {
"channel": "#营销团队",
"message": "任务 MKT-123 (撰写推广文案) 已完成!"
}
}
]
Explanation:
这个 SKILL.md 清晰地展示了不同层级的信息。当 Claude 第一次看到这个文件时,它可能只读取 # ProjectPilot Skill、## Overview 和 ## Capabilities。当用户明确要求创建任务时,系统才会把 ### jira_api 下的 #### jira_api.create_issue 及其参数信息加载到 Claude 的上下文。如果需要更具体的例子,## Examples 中的相关部分才会被提取。这种按需加载的方式,就是渐进式披露的核心体现。
🔧 涉及的 Tools / Commands
本期课程主要探讨的是 SKILL.md 的内部结构及其与大模型交互的机制,因此不涉及具体的 CLI 工具或外部命令。我们主要讨论的是构成这一机制的概念性组件和流程:
| 组件/概念名称 | 用途 | 说明 |
|---|---|---|
| SKILL.md 文件 | 技能和知识的结构化载体 | 包含大模型可用的工具定义、能力描述和使用示例。其分层 Markdown 结构是实现渐进式披露的基础。 |
| SKILL.md 解析器 | 解析和提取 SKILL.md 特定片段的内部组件 | 这是一个假设的内部模块,负责将 SKILL.md 文件解析成可索引的结构(例如,一个抽象语法树或一个章节映射),并根据大模型的请求,精确地提取出所需的 Markdown 片段。 |
| Agent 框架 / 技能管理模块 | 协调大模型与 SKILL.md 交互的外部系统 | 充当大模型和 SKILL.md 之间的智能中介。它接收大模型的意图(请求),调用 SKILL.md 解析器获取相关信息,并将信息注入回大模型的上下文。它负责实现渐进式披露的逻辑。 |
| 上下文管理器 | 动态管理大模型上下文窗口的机制 | 确保只有当前任务最相关的信息被加载到大模型的上下文窗口中。它与 Agent 框架协同工作,负责在必要时添加或移除 SKILL.md 片段,以优化 token 使用和推理效率。 |
| 内部请求/信号机制 | 大模型向外部系统表达信息需求的方式 | 这是一个抽象概念,指大模型在推理过程中,通过其“思考”或特定的内部指令,向 Agent 框架发出获取 SKILL.md 特定部分信息的信号。例如,大模型可能“思考”到需要某个工具的参数,这个“思考”会被外部系统捕获并转化为对 SKILL.md 解析器的调用。 |
| 检索增强生成 (RAG) | 结合检索与生成,提升模型能力 | 渐进式披露是 RAG 在结构化技能知识库场景下的具体应用。它通过从 SKILL.md 中检索相关片段来增强大模型的生成能力,使其能够更准确地理解意图和执行工具调用。 |
📝 本期要点回顾
- SKILL.md 采用分层模块化结构:它不是一个简单的线性文件,而是由
Overview、Capabilities、Tools和Examples等多个可独立访问的模块组成,每个模块内部又可以进一步细分。 - 渐进式披露 (Progressive Disclosure) 是核心机制:大模型不会一次性加载整个 SKILL.md。它会根据任务需求,从高层概览逐步深入,按需加载特定模块或片段。
- 避免上下文爆炸的关键策略:通过只将最相关的信息注入大模型上下文,渐进式披露有效避免了大型