Agent Skill 体系全解:从渐进式披露到生产级管控

一、什么是 Skill:从「硬编码 Prompt」到「可组合的 SOP 包」

在没有 Skill 之前,Agent 工程里最常见的「领域能力复用」就是把一段固定的 Prompt 拼到 System Message 末尾、或者封装成一个 Go/Python 工具函数。这种方式的问题很明显:

  • 上下文爆炸:每个领域 SOP 几百行,10+ 领域一次性全部塞进 system prompt,首轮 token 就爆了。

  • 模型选择刚性:文档解析、代码生成、数据清洗三种工作流可能各自需要不同的模型,但 System Prompt 级别的拼法无法做到"某段流程切模型"。

  • 版本管理混乱:Prompt 写在 Go 字符串里,改一行 SOP = 重新编译发布;跨项目复制粘贴 = 分叉漂移。

Skill(以 SKILL.md 为载体)是 2025 年由 Anthropic 确立、并被 CloudWeGo/eino 等主流 Agent 框架实现的一种开放式 AI 代理构建标准。它本质上是 「一份标准化操作手册(SOP)」+「一组执行策略(元数据)」 的打包体,由框架在运行时按需加载。

一份典型的 Skill 目录结构:

text

复制代码
skills/
├── pdf-batch/
│   ├── SKILL.md          ← 技能定义(YAML FrontMatter + Markdown Body)
│   ├── scripts/
│   │   └── extract.py    ← Skill 正文里引用的辅助脚本
│   └── examples/
│       └── config.yaml   ← Skill 正文里提到的参考文件
└── web-research/
    └── SKILL.md

SKILL.md 采用 YAML FrontMatter + Markdown Body 双段结构:

markdown

复制代码
---
name: pdf-batch
description: 批量 PDF 提取文本并重命名。当用户提到"PDF 提取、批量 PDF2txt、扫描目录 PDF"时使用;单个小 PDF 文件不要使用。
context: fork                      # 执行模式:inline | fork | fork_with_context
agent: worker                     # 交给哪个子 Agent 执行(仅 fork 模式生效)
model: gpt-4o                     # 执行时切换的模型(仅 fork / inline 模式生效)
---

# PDF 批量处理工作流

## 前置检查
先用 ls 确认输入目录存在;不存在先跟用户确认。

## 步骤 1:枚举
ls {input_dir}/*.pdf → 拿到文件列表;>50 个建议先分组并发

## 步骤 2:提取
调用 {BaseDir}/scripts/extract.py --input <abs_path> --output <out_dir>
失败回退:python + pypdf 直接实现

## 步骤 3:命名
从首页提取 Author / Year / Title,格式 {Author}-{Year}-{Title}.txt
重命名冲突先 + (1),不要覆盖用户已有文件

Skill 的双重身份:

  • 对框架来说 :它是 {Name, Description, Context, Agent, Model} + Content + BaseDir 的结构化数据。

  • 对模型来说 :它同时是 「名片」Name+Description 做召回)和 「操作手册」Content 指导后续执行步骤)。

二、完整执行流程:5 个节点串联

抛开所有技术术语,Skill 的完整运行流程可以拆解为 5 个核心节点:

节点 1:启动时扫目录,但只看标题

Agent 启动时,扫描指定的 Skill 存放目录。只做一件事 :把每个 Skill 文件夹的 名字一句话介绍 摘出来,记在一个列表里。绝对不看 那些几百行的详细操作步骤。结果:把这个"名字+介绍"列表放进 Agent 的初始系统提示里,同时在工具箱里只放 1 个名叫 skill 的工具。

节点 2:根据用户问题,选一个匹配的

用户发来一个问题(比如"帮我把这些 PDF 合并一下")。Agent 把这个问题和自己系统提示里的"名字+介绍"列表做比对。如果发现某个 Skill 的"介绍"和用户问题对得上,Agent 就调用那唯一的 skill 工具,并把选中的 Skill 名字作为参数传进去。

节点 3:真正去读操作手册,并决定谁来做

skill 工具被调用后:① 去硬盘里找到对应的 Skill 文件夹,把完整的 SKILL.md 操作手册读出来;② 检查手册头部标注的 context 类型:

  • inline:把读出来的完整操作手册原文,作为结果返回给当前 Agent。

  • fork:新建一个独立的子 Agent,把操作手册丢给它,让它在后台从头做到尾。等子 Agent 做完后,只把最终结果压缩成一段话返回。

  • fork_with_context:同上,但子 Agent 会携带父对话历史。

节点 4:照着操作手册,一步步执行(仅 inline 模式)

当前 Agent 拿到节点 3 返回的完整操作手册(这是它第一次 看到具体步骤)。于是它照着手册里的描述,一步步调用各种基础工具(运行脚本、读文件、写文件等),把手册上的每个步骤都执行完。

节点 5:整理结果,回复用户

Agent 把执行完的所有结果汇总,整理成一段通顺的自然语言,发送给用户。

三、四种注入位置:Skill 向 Agent 传递信息的 4 个通道

注入位置 注入内容 发生时机 作用
① System Prompt <available_skills> 列表(所有 Skill 的 Name + Description) Agent 启动时(节点 1) 让模型知道"有哪些技能可用",做召回决策
② Tool Schema 1 个名为 skill 的工具,参数为 {"skill": string} Agent 启动时(节点 1) 让模型能够通过调用工具来触发 Skill 加载
③ ToolMessage SKILL.md 的完整正文(操作手册) skill 工具被调用后(节点 3,inline 模式) 让模型第一次看到完整步骤,开始执行
④ 子 Agent 初始消息 SKILL.md 的完整正文 + 父对话历史(仅 fork* 模式) skill 工具被调用后(节点 3,fork* 模式) 让子 Agent 直接带着操作手册开始干活

注意一个反直觉事实 :不管你有 10 个还是 100 个 Skill,在 Tools 集合里 都只会出现一个工具 (即②中的 skill 工具)。这是「渐进式披露」的前提条件。

四、三种执行模式:context 字段的三种取值

SKILL.md 头部的 context 字段控制"拿到操作手册后,谁来执行、怎么执行":

模式 执行方式 上下文隔离? 适用场景
inline(默认) 当前 Agent 自己读手册,自己一步步执行 不隔离,所有中间步骤都在主对话里 SOP 需要和用户交互、需要结合其他上下文
fork 新建独立子 Agent,手册丢给它,子 Agent 从头做到尾,只返回最终结果 完全隔离,父 Agent 看不到中间过程 SOP 很重、步骤多、会输出大量中间信息,避免撑爆主上下文
fork_with_context 新建独立子 Agent,但会把父对话历史也一并复制给它 隔离但带上下文 子流程需要知道用户的历史输入(如之前给的路径)

五、渐进式披露:解决 Context Bloat 的核心设计

5.1 为什么要「渐进」

如果不做渐进式披露,支持 100 个 Skill 的系统首轮 System Prompt 就是 100 × 几百行 = 几万 token 起步,同时「Description 太泛 → 模型误选」「Description 太细 → Token 爆炸」的 trade-off 永远无解。

Skill 体系的解法非常克制:只在合适的层级提供合适粒度的信息

5.2 四层披露金字塔

层级 信息内容 展示时机 消费方
L1 名片 Name + 1-3 行 Description 每个模型首轮推理都能看到(节点 1) 模型做召回决策;Token 开销极小
L2 阻塞语义 强制约束"命中时必须先调 skill 工具" 首轮 System + ToolInfo 同时(节点 1) 约束模型不要跳过 Skill 直接干活
L3 操作手册 SKILL.md 的 Markdown Body(完整步骤) 只有成功执行 skill 工具后才注入(节点 3) Agent 拆解具体动作
L4 资源文件 脚本、配置、示例等辅助文件 只有当 SOP 正文提到并触发 execute / read_file 后才被读取 Agent 按需加载,不占上下文

5.3 渐进式披露的两个关键锚点

  • L1 永远只返回名片Backend.List() 只读取 FrontMatter,不读任何 Skill 的 Content

  • L3 才读正文skill 工具的 InvokableRun 内部才调用 Backend.Get(name) 真正读取 SKILL.md

六、敏感操作监测:三层拦截机制

Skill 体系本身不自动监测 敏感操作,而是通过三层人为配置实现拦截:

层级 1:SOP 正文里写死"强制确认"指令

SKILL.md 操作手册里,由编写 Skill 的人主动标注危险步骤:

markdown

复制代码
## 步骤 3:删除临时文件

**⚠️ 危险操作,必须执行确认:**
调用 user_confirm 工具,传入:
  - message: "即将删除目录 /tmp/cache 下所有临时文件,是否继续?"
  - risk_level: "high"

仅当 user_confirm 返回 confirmed=true 后,才执行下一步的 rm 命令。

层级 2:WrapToolCall 中间件拦截

在框架层加一个全局拦截器,在执行任何工具调用之前先检查命令或参数是否包含敏感关键词:

检查维度 敏感关键词示例
命令本身 rm -rftruncatedrop tablekubectl delete
目标路径 /etc//prod//data/live/
工具名称 delete_fileremove_directory

命中后先调用 user_confirm 向用户发起确认请求,收到确认后才放行。

层级 3:Skill Registry 白名单

在节点 1(启动加载)阶段,就不把敏感 Skill 加载给普通用户:

yaml

复制代码
name: db-drop-production
description: 删除生产环境数据库表
permission: admin-only   # 只有管理员才能看到

Backend.List() 根据当前用户角色过滤,不匹配的 Skill 根本不会出现在 <available_skills> 列表里,普通用户连"误选"的机会都没有。

三层如何串联

层级 拦截时机 覆盖范围 谁负责配置
层级 1:SOP 写确认 执行到某一步时 只覆盖写了的步骤 Skill 编写者
层级 2:中间件拦截 任何工具调用前 全局自动覆盖 框架运维者
层级 3:白名单过滤 Agent 启动加载时 整个 Skill 不可见 权限管理员

生产组合方式:层级 3 让普通用户根本看不到高危 Skill;层级 2 在最后关头兜底拦截;层级 1 作为第一道防线,在 SOP 里明确告知 Agent 必须先确认。

七、生产级管控:8 条工程规范

7.1 元数据治理:Description 是召回率生命线

L1 名片是模型唯一的预触发信息。写得好 = 模型选得准;写得差 = 该用不用或乱用。

写 Description 的模板:

yaml

复制代码
description: |
  [触发条件正向]:当用户提到 <关键词> 时使用
  [适配反例]    :不要用于 <明确不适用的场景>(给出替代做法)
  [上下文条件]  :需要 <某个前置配置> 才能工作
  [产物说明]    :产出 <具体产物类型> 到 <约定路径>

7.2 路径治理:让 Agent 绝不写错路径

Agent 执行 execute 时经常忘记加 BaseDir,这是排名第一的 Skill 失败原因:

  • BuildContent 预渲染绝对路径(推荐) :将 {``{BaseDir}}/xxx 在返回前全部替换为 skill.BaseDir + "/xxx"

  • SKILL.md 顶部加硬约束ALL FILE REFERENCES MUST USE ABSOLUTE PATH: <skill.BaseDir>

  • WrapToolCall + cwd 注入 :自动前置 cd <BaseDir> &&

7.3 目录治理:一级子目录约定

Eino 自带的 FilesystemBackend 只扫描 <BaseDir>/*/SKILL.md 的一级子目录。需要分类层级时可:

  • 方案 A :保留一级目录,Name 写 qualified name,如 "office-suite/pdf-batch"

  • 方案 B :自行实现 Backend 接口,递归扫描 **/SKILL.md

7.4 模式选择治理:决策表

场景 推荐模式 不推荐原因
SOP 需要和用户交互、和其他工具混用 inline fork 后父子隔离,做不到澄清
SOP 很重,会输出大量中间信息 fork inline 会把父 Context 撑爆
子流程需要知道用户历史输入 fork_with_context fork 看不到父历史
需要切换专属模型且严格隔离 fork + model inline 模型切换延迟一轮生效

7.5 依赖治理:自检 SOP + 失败回退链

markdown

复制代码
## Step 0:环境自检(必须先跑)
1. 先执行:<BaseDir>/scripts/selfcheck.sh
   - 成功 → 进入 Step 1
   - 失败 → 尝试 pip install xxx;仍失败走降级路径
2. 降级路径:不用脚本,用内联实现
3. 仍失败 → 通知用户,给出三条手动替代命令

7.6 权限治理:Skill 级白名单 + 破坏性操作强制审批

  • 敏感 Skill 只在特定 RBAC 角色下才出现在 <available_skills> 中。

  • 高危命令在 SOP 里明确写"执行前先调用 user_confirm"。

7.7 版本治理:Skill Registry + 变更审计

  • 所有 Skill 放独立 Git 仓库,加 version 字段,发布走 MR/PR。

  • Backendproject + env 拉取不同 tag 的 Skill。

  • 开启 Callbacks 打点,记录 skill_name, skill_version, success/failure, latency,按版本号定位并一键回滚。

7.8 用户体验治理:区分「加载说明书」和「真正执行」

inline 模式下默认返回 Launching skill: xxx,让用户误以为已经在跑。应改写为 Loaded instructions for skill: xxx(下一步将按此步骤执行),并在前端附加轻提示。

八、总结:Skill = Prompt 工程 + 配置管理 + Agent 编排 的交集

维度 Tool(本地函数) MCP(远程函数) SubAgent(task Skill(SKILL.md
本质 可执行函数 远程可执行函数(协议) 拉起一个独立 Agent 端到端跑 一份 Markdown SOP + 运行时策略
被模型看到的方式 每个工具一条 ToolInfo 每个工具一条 ToolInfo 每个 SubAgent 一条 desc 所有 Skill 的 Name+Desc 拼进 1 个 skill 工具的描述
任务执行形态 一次调用 = 一次原子动作 同上 一次调用 = 子 Agent 全流程跑完 inline = 先加载 SOP,后续 N 轮执行;fork* = 内部独立 Agent 跑完
模型切换 不支持 不支持 SubAgent 级别可切 通过 model 字段切换
动态参数注入 通过函数参数 通过 JSON 参数 通过 inputs 传递 通过 CustomToolParams 钩子注入并渲染进 SOP
上下文隔离 不隔离 不隔离 默认隔离 inline 不隔离,fork* 隔离
改动成本 改代码 → 重新编译 改 MCP Server 部署 改配置 + 重新编译 SKILL.md → 发布目录即可

如果把 Tool 比作「螺丝刀」,MCP 是「外采的电动工具」,SubAgent 是「外包同事」,那么 Skill 更像一份放在抽屉里、随时取出、上面还贴着步骤图解和质检清单的 《标准作业指引》 ------它不改变底层工具有多少、同事能力有多强,但把 「怎么组合这些东西能稳定地、合规地、可审计地把一件事做完」 的知识,沉淀到了独立可复用的载体里。

这就是为什么生产级 Agent 体系无论底层框架怎么换,Skill(或类似 SKILL.md 格式的标准载体)一定会成为工程化落地的基础构件。

相关推荐
会周易的程序员1 小时前
唯识学架构的AI:Agent个体意识与佛陀出现可能性的推演
人工智能
weixin_727535621 小时前
Loop 已死,Graph 新生:AI 工作流的范式革命
android·人工智能·rxjava
KaneLogger1 小时前
一套系统,让 AI 写代码的速度变成生产力
人工智能·程序员·代码规范
眼泪划过的星空2 小时前
LangChain 两大基础提示词模板:PromptTemplate 与 ChatPromptTemplate 详解
人工智能·python·langchain
小码哥哥2 小时前
如何评价“构建企业级 AI 知识库“这一趋势?从技术架构到落地实践的完整分析
人工智能·架构
小罗水2 小时前
第18章 接口回归、异常演练与轻量压测
人工智能·数据挖掘·回归
卷福同学2 小时前
AI编程出海第二步:验证关键词能否做站
前端·人工智能·后端
逻辑君2 小时前
ANNA 认知引擎 · Humanoid 机器人训练白皮书
人工智能·深度学习·机器学习·机器人
hans汉斯2 小时前
计算机科学与应用|改进MeanShift算法在智能监控视频中的应用研究
图像处理·人工智能·功能测试·深度学习·算法·音视频