Agent Skills:把团队里"只会做一遍"的经验,变成 Agent 能反复调用的能力包

刷 GitHub 热榜,前十五名里有一串名字让我停了一下:openclaw 排第 3,ECC 第 8,hermes-agent 第 9,mattpocock/skills 第 12,opencode 第 13。它们干的事各不相同,描述里却反复出现同一个词:skills。ECC 自己的简介写得最直白,说它是 "Skills, instincts, memory, security... for Claude Code, Codex, Opencode, Cursor"。

这不是巧合。2026 年的 Agent 圈,正从"造一堆专用机器人"转向"给一个通用机器人外挂能力包"。这个能力包,就是 Anthropic 在 2025 年底推出来的 Agent Skills。我打算把它讲透:它解决什么真问题,底层怎么省上下文,和 Prompt、MCP 到底差在哪,以及一个写 Java 后端的人该怎么把它接进自己的系统。

一、Agent Skills 到底是什么

Agent Skills 是 Anthropic 提出的一套开放标准。据阿里技术 2026 年 4 月的复盘,Claude Skills 最早在 2025 年 10 月 16 日随 Claude 3.7 作为产品内能力推出;到 2025 年 12 月 18 日,Anthropic 把它开源成跨平台标准,规范叫 Agent Skills Specification V1.0,托管在 agentskills.io,同时放出官方 SDK,支持 Python、TypeScript 和 Java。TechCrunch 当时给了一句评价,说它是"AI 领域的 Dockerfile"。到 2026 年 2 月,公开可用的 Skills 已经超过 8.5 万个,支持该标准的主流平台到了 27 家,Cursor 是第一个全面采用它的 AI IDE,微软 Azure AI Studio 宣布原生支持,GitHub Copilot Workspace 做了实验性支持。

理解它最关键的一句话:MCP 解决"能调什么工具",Skills 解决"怎么把一件事做对"。前者是连接层,后者是知识层,两者互补。

一个 Skill 其实就是由文件组成的:最小形态只需要一个 SKILL.md,里面分两块:开头的 YAML frontmatter(必须含 name 和 description)和下面的 Markdown 指令。复杂一点的会带上 scripts/(可执行的 Python、Bash、JS)、references/(按需查阅的文档)、assets/(模板、图标等静态资源)。name 最多 64 个字符,只能是小写字母、数字和连字符;description 最多 1024 字符,要写清楚"这东西干嘛用、什么时候用"。

为什么需要它?Anthropic 打过一个比方:报税这种事,你愿意交给一个从第一性原理现推的 300 IQ 数学天才,还是一个填过几千份税表的老手?大多数人选老手,不是因为他更聪明,而是他有 accumulated expertise。通用模型今天就像那个数学天才,推理能力强,但缺你公司那套没人写下来的流程。Skills 干的事,就是把老手的经验打包,让通用模型变成某个领域的专家。

二、渐进式披露:为什么塞再多资料也不爆上下文

为什么一个文件夹能装很多东西却不把上下文撑爆?靠的是渐进式披露(progressive disclosure),分三级加载。

第一级是元数据。Agent 一启动,就把所有已安装 Skill 的 name 和 description 预载进系统提示。这部分很轻,每个 Skill 只占几十到一百来个 token,所以你装几百个 Skill 也不会有感知。

第二级是 SKILL.md 正文。只有当模型判断当前任务跟某个 Skill 的 description 匹配时,才通过 bash 把整个 SKILL.md 读进上下文。官方建议正文控制在几千 token 以内(文档给的上限是不超过 5k token)。

第三级是 references/ 和 scripts/ 里的东西。这些文件平时躺在文件系统上,一个 token 都不占;模型觉得需要了,才去读某一个,或者去跑某一个脚本。脚本这一点很妙:当模型执行 scripts/ 里的 Python 时,脚本代码本身永远不会进上下文,只有运行输出(比如"校验通过"或具体的报错)回来。这比让模型现场现编等效代码省 token,而且结果是确定性的。

三级加载画出来就是下面这条链:

三、Skills 和 Prompt、MCP 不是一回事

很多人第一次见 Skill 会以为"不就是高级提示词吗",不是。三者分工不同,我用一张表摆清楚:

维度 Prompt MCP Skills
定位 模型的"一次性指令" 工具调用的"通信协议" 任务执行的"标准能力包"
作用 告诉模型做什么、怎么做的文本 定义模型如何安全发现并调用外部工具 封装一个完整、可复用、可版本化的任务方案
粒度 单次对话上下文内的指令 工具接口的标准化描述(类似给 AI 的 OpenAPI) 跨会话、跨应用的独立功能单元(类似 Docker 镜像)
可复用性 低,靠人工复制粘贴 中,工具可被多个 Prompt 调用 高,任意支持该标准的 Agent 直接加载

更准确地说:Skills 不是 Prompt 的替代品,而是 Prompt 的容器,一个 Skill 里必然包含精心设计的 Prompt,外加脚本、依赖声明和测试用例;Skills 也不是 MCP 的替代品,而是 MCP 的消费者,Skill 里的执行脚本会通过 MCP 去碰真实世界的工具。三者协同时是这样一条链:Prompt 告诉模型"这次要干嘛",模型匹配到合适的 Skill,Skill 加载后通过内部指令调 MCP 拿工具,闭环完成。

Anthropic 自己的厨房比喻很贴切:MCP 是专业厨房(食材、灶具、设备),Skills 是菜谱(一步步怎么做)。没有菜谱,用户连上 MCP 也不知道下一步该干什么。

四、一个能跑的例子:把周报生成固化成 Skill

光讲结构太空,给一个能落地的例子。假设团队每周要从 git 提交记录生成双周报,这个流程完全可以固化成一个 Skill,目录长这样:

objectivec 复制代码
weekly_git_report/
├── SKILL.md
├── scripts/
│   └── fetch_git_commits.py
└── references/
    └── weekly_report_template.md

SKILL.md 的写法,注意 description 要带"什么时候用"的关键词,这是模型自动匹配的依据:

yaml 复制代码
---
name: weekly_git_report
description: 基于近 14 天 git commit 记录生成结构化双周工作周报。当用户要写周报、总结近期工作、或提到 commit/提交记录时使用。
version: 0.1.0
---

# 概述
读取用户所有本地仓库近两周的 commit message,按模块归类,套用模板生成周报。

# 数据获取
运行 scripts/fetch_git_commits.py 拿到提交列表,周报模板见 references/weekly_report_template.md。

# 异常处理
如果一条提交都拿不到,直接写明"本期无实质提交"。

scripts/fetch_git_commits.py 是一段确定性代码,它负责把脏活干了,模型只消费它的输出:

python 复制代码
#!/usr/bin/env python3
import os
import subprocess
from datetime import datetime, timedelta

ROOT = os.path.expanduser("~/code")  # 所有仓库的父目录


def collect():
    since = (datetime.now() - timedelta(days=14)).strftime("%Y-%m-%d")
    rows = []
    for name in os.listdir(ROOT):
        repo = os.path.join(ROOT, name)
        if not os.path.isdir(os.path.join(repo, ".git")):
            continue
        try:
            out = subprocess.check_output(
                ["git", "-C", repo, "log", f"--since={since}", "--pretty=format:%s"],
                stderr=subprocess.DEVNULL, text=True,
            )
            rows.extend(out.splitlines())
        except subprocess.CalledProcessError:
            continue
    return rows


if __name__ == "__main__":
    commits = collect()
    print(f"近 14 天共 {len(commits)} 条提交:")
    for c in commits[:50]:
        print(f"- {c}")

这个例子的价值不在代码多高明,而在它把"怎么写周报"这件事从某个人脑子里的习惯,变成了团队任何人、任何 agent 都能调起的标准能力。新人来了,不用口口相传,加载这个 Skill 就会了。

五、生态版图:谁在吃这套标准

今天热榜上的 ECC 明说支持 Claude Code、Codex、OpenCode、Cursor 四种后端,而它自己就是用 SKILL.md 组织能力的。这意味着你写一份技能描述,可以在这几个 agent 之间复用。底下接的模型,从 Claude(大家口头说的 cc5 那条线)、OpenAI 的 Codex 5.6,到自托管的 Kimi K3、智谱 GLM-5.2 都能挂,前提是那个 harness 支持按 description 自动加载 SKILL.md。前面几篇写过用 vLLM 自托管 Kimi K3 和 GLM-5.2,那种部署形态接进开源 harness 跑同一套技能目录,2026 年已经能做。

顺带一提,OpenClaw 自己的 SKILL.md 技能系统其实比 Anthropic 正式标准化还早几个月,是这套模式在实践里先被验证过,才有后来的开放标准。第三方市场(SkillsMP、AgentPowers.ai、Lobehub)也已经能下载别人写好的 Skill。

六、安全:Skill 不是提示词,是会被执行的代码

Skill 看起来像文档,但它会被执行。Anthropic 自己在文档里写得很重:把 Skill 当作软件来装,只从可信来源取。要审查的不只是 SKILL.md,还有 scripts/ 和 assets/ 里所有的文件,重点找异常的网络调用、文件访问模式、和声明目的对不上的操作。从外部 URL 拉数据的 Skill 风险尤其高,因为拉回来的内容可能夹带恶意指令;即便是可信的 Skill,如果它的外部依赖后来被改,也可能被攻破。工具滥用和数据外泄是两个最实在的后果:一个能碰敏感目录的 Skill,可能被设计成把数据往外发。

这跟我之前写过的提示注入是一体两面,一个是"骗模型说错话",一个是"借技能干坏事",根子都在"模型不区分指令和数据"。生产里接 Skill,至少要做到:只装团队自己写或从官方市场下的;上线前人工过一遍 scripts/;给脚本执行单独划沙箱目录和命令白名单。

七、Java 后端怎么落地:自己写一个 Skill 调度器

作为后端,我更关心怎么把这套机制接进来。Spring AI 2.0(2026-06 GA,配 Spring Boot 4.x,Java 21+)的 ChatClient 已经能把"系统指令 + 用户任务"这套玩法封装得很干净。下面这个例子不依赖任何未公开 API,思路是:扫描技能目录、解析 frontmatter、按任务关键词匹配、把 SKILL.md 正文当 system 提示注入,再调模型。模型可以走 OpenAI 兼容端点接 Kimi K3 / GLM-5.2,也可以走 Anthropic 绑定接 Claude(cc5 线),具体 baseUrl 和模型名以官方文档为准。

先是实体和加载器:

arduino 复制代码
public record Skill(String name, String description, String body) {}

public final class SkillLoader {
    public static List<Skill> loadAll(Path root) {
        List<Skill> out = new ArrayList<>();
        if (!Files.isDirectory(root)) return out;
        try (var dirs = Files.list(root)) {
            for (Path dir : dirs.filter(Files::isDirectory).toList()) {
                Path md = dir.resolve("SKILL.md");
                if (Files.exists(md)) out.add(parse(md));
            }
        } catch (IOException e) {
            throw new IllegalStateException("load skills failed", e);
        }
        return out;
    }

    // 简化版 frontmatter 解析:取 --- 之间的 name / description 与正文
    private static Skill parse(Path md) throws IOException {
        String text = Files.readString(md);
        int start = text.indexOf("---") + 3;
        int end = text.indexOf("---", start);
        String fm = text.substring(start, end);
        String name = grab(fm, "name");
        String desc = grab(fm, "description");
        String body = text.substring(end + 3).trim();
        return new Skill(name, desc, body);
    }

    private static String grab(String fm, String key) {
        for (String line : fm.split("\n")) {
            if (line.trim().startsWith(key + ":")) {
                return line.substring(line.indexOf(':') + 1).trim();
            }
        }
        return "";
    }
}

再是调度器,用 Spring AI 2.0 的 ChatClient 调模型:

scss 复制代码
public class SkillDispatcher {
    private final ChatClient chatClient;
    private final List<Skill> skills;

    public SkillDispatcher(ChatClient chatClient, Path skillsRoot) {
        this.chatClient = chatClient;
        this.skills = SkillLoader.loadAll(skillsRoot);
    }

    public String run(String task) {
        Skill skill = match(task); // 先按 description 关键词命中
        String system = (skill == null) ? "你是一个严谨的助手。" : skill.body();
        return chatClient.prompt()
                .system(system)
                .user(task)
                .call()
                .content();
    }

    private Skill match(String task) {
        return skills.stream()
                .filter(s -> s.description().toLowerCase().contains(task.toLowerCase())
                        || task.toLowerCase().contains(s.name().toLowerCase()))
                .findFirst()
                .orElse(null);
    }
}

要点就两个:技能目录用 git 管版本,和代码一起走评审;匹配逻辑别搞太复杂,先按 description 做关键词命中,命中多了再上向量检索。真要上线,把脚本执行单独扔进 sandbox 目录,命令白名单之外的一律不让跑。

八、我踩过的坑,以及对 Skills 的判断

我们团队踩过的坑,列几个给后来人。

第一个是 Skill 爆炸。一开始什么都想写成 Skill,结果元数据列表本身就变成噪声,模型反而匹配不准。我的做法是先问一句:这件事是不是会被反复做、且步骤固定?不是就别上 Skill,写进 CLAUDE.md 当事实就好。

第二个是 SKILL.md 写成文档而不是操作步骤。模型需要的是"第一步干啥、第二步干啥",不是背景科普。你给一篇洋洋洒洒的原理,它读完照样不会执行。

第三个是脚本白名单。Skill 里的脚本有 bash 权限,如果不限死能跑什么,agent 就可能越权。我们给脚本执行单独划了沙箱目录和命令白名单。

第四个,也是最容易被忽略的:别在 Skill 里塞外部依赖又不锁版本。一个靠某个 SaaS API 的 Skill,对方接口一变你就跟着挂。能本地确定性解决的,尽量用 scripts/ 里的代码解决,少引外部不确定性。

我的判断:Skills 把"AI 工作流"从一道精心设计的填空题,变成了可版本、可分享、可组合的能力资产。小团队别急着造市场,先把两三个高频流程(跑测试套件、发版、生成周报)固化成 Skill,收益就很明显。新人 onboarding 和 CI 一致性都会好一截。Anthropic 的工程博客也建议从"先评估"做起:拿真实任务跑一遍 agent,看它在哪一步掉链子,再把掉链子的环节写成 Skill,比凭空设计一个 Skill 靠谱得多。

九、版本、组合与可移植

三个工程属性让 Skill 比"把提示词存进备忘录"强出一个量级。

可移植。Anthropic 的文档明确说,同一份 Skill 在 Claude.ai、Claude Code 和 API 上行为一致,只要运行环境支持它的依赖。这意味着你为 Claude Code 写的 Skill,理论上不用改就能在别的兼容 harness 上跑。

可组合。Agent 能同时加载多个 Skill,它们应该相互配合,而不是假设自己是场上的唯一能力。比如"发版"Skill 可以顺手引用"跑测试"Skill 产出的结果,而不是各写各的。写 Skill 时要留好这个心眼:别把前提假设写死。

可版本。Skill 就是个文件夹,天然能用 git 管理,改了能回滚、能 review、能团队共享。我们把它和源码放在同一个仓库的子目录里,PR 里一起审,谁改了"怎么发版"一目了然。这点是把经验真正变成资产的关键,否则它又会退回成某个人脑子里的习惯。

给团队一个提醒:Skill 不是越多越好。元数据列表本身会变成上下文噪声,定期清理没人用的 Skill,和清理没人维护的代码一样重要。

十、收个尾

Agent Skills 不性感,没有新模型、没有新算法,就是"用文件夹把领域经验打包"。但 2026 年 agent 生态集体往这上面靠,说明行业想通了一件事:通用模型不缺智商,缺的是你公司那点没人写下来的 know-how。明天我打算把团队内部的代码评审 checklist 也拆成一个 Skill,顺手接进 opencode 跑。

相关推荐
AI搅拌机1 小时前
LoRA训练实战10:Wan2.2人物变火特效LoRA极简训练法,上手指南!
人工智能
京东云开发者2 小时前
别再守着 Claude Code 了——学会指挥它自主干活
人工智能
杨超越luckly2 小时前
Agent应用指南:基于 SPTCC 一卡通数据的上海地铁客流特征分析(2015.04)
html·agent·可视化·一卡通·地图客流
大模型码小白2 小时前
在 Windows 下 Codex 安装、配置与使用详细指南
java·人工智能·windows
MobotStone2 小时前
AI写代码,真的能做出“能用”的产品吗?
人工智能
小保CPP2 小时前
OpenCV C++车型识别2-形状匹配
c++·人工智能·opencv·计算机视觉
hongyucai2 小时前
聊一聊τ和机器人
人工智能·机器人
奋飛2 小时前
AI 应用工程:Tool、MCP、Skill 与 Workflow 如何接入 Agent?——搭建一个可运行的需求影响面分析 Agent
agent·workflow·skill·tool·mcp
PM老周2 小时前
PRD怎么用AI质检?需求预审、人工复核与整改闭环
人工智能·项目管理·产品经理·prd