一个文件夹改变 AI 的行为模式

📅 2026/6/29 22:37:04
一个文件夹改变 AI 的行为模式
kill 是一套标准化的、可复用的、跨 Agent 平台共享的「知识包」。它不是系统 prompt 的包装纸不只是给 AI 加一段指令而是一个自带上下文、脚本、参考资料的完整文件夹。一个 Skill 的目录结构长这样my-skill/ ├── SKILL.md # 必需元数据 指令 ├── scripts/ # 可选可执行代码 ├── references/ # 可选参考文档 └── assets/ # 可选模板、图片等资源核心只有一个SKILL.md 文件。它用 YAML frontmatter 声明自己的名字和触发条件正文里写清楚做这件事的步骤和注意事项。一个最简单的 Skill 只需要 10 行--- name: roll-dice description: Roll dice using a random number generator. --- To roll a die, use the following command that generates a random number from 1 to the given number of sides: echo $((RANDOM % sides 1)) Replace sides with the number of sides on the die.就这么简单。但就是这套极简的约定催生了一个 13.6 万星的项目和一个 25 平台的生态系统。为什么「文件夹」这个设计是刻意为之这里有一个设计决策大多数写 Skills 教程的人不会提但我觉得它是整个架构里最聪明的一步渐进式加载Progressive Disclosure。Skill 分三层加载第一层元数据约 100 tokens。Agent 启动时只读取每个 Skill 的name和description够它判断「这个 Skill 能不能用在这里」就行。第二层指令正文推荐 5000 tokens。当 Agent 判断 Skills 匹配当前任务才把完整的 SKILL.md 加载进上下文。第三层附属资源按需加载。scripts/里的脚本、references/里的详细文档只有实际用到的时候才读。这意味着什么意味着你可以在一个项目里放 50 个 SkillAgent 启动时的上下文开销只比放 1 个 Skill 多那么一点点——因为每次只加载元数据。相比之下如果你把同样的 50 段说明书直接塞进系统 prompt上下文早就爆了。这个设计让 Skills 的「可堆叠性」成为现实。你不需要在「功能丰富」和「上下文不够」之间做取舍——这是 MCP Server 和 Plugin 做不到的。一个更贴近真实开发的例子上面那个掷骰子的 Skill 只是一个入门演示。来看看一个真实的、在生产环境里能用的 Skill 长什么样。假设你的团队有一个 Java 项目所有数据库查询都要加deleted_at IS NULL做软删除过滤但新来的 AI Agent 根本不知道这个约定。于是它生成的 SQL 会把已删除的数据也算进来——这种事情在生产环境里发生一次后果不用我说。把这个约定写成 Skill--- name: java-db-query description: Write database queries for our Java project. Use when writing SQL, JPA, or MyBatis queries involving database tables that use soft deletes. --- ## Database Query Conventions ### Soft Delete Rule (CRITICAL) All tables use soft deletes via a deleted_at column. Every SELECT query MUST include WHERE deleted_at IS NULL unless the user explicitly asks for deleted records. ### Gotchas - The users table uses user_id in the DB, but uid in the auth service. Both refer to the same value. Never confuse them. - The /health endpoint returns 200 even if the DB is down. Always use /ready for health checks. ### Example - Correct Query SELECT * FROM orders WHERE user_id ? AND deleted_at IS NULL ORDER BY created_at DESC; ### Example - Wrong (Will Include Deleted Records) SELECT * FROM orders WHERE user_id ?;这个 Skill 放到项目里的.claude/skills/目录下每次 AI 写 SQL 的时候它会自动加载这些约束。一个团队在 CI 里跑了 100 次 SQL 生成的测试有 Skill 的情况下SQL 的正确率从 42% 提升到了 91%。这就是为什么这个「文件夹」值 13.6 万星——它解决的不是一个技术问题而是一个范式问题怎么让 AI 真正理解你的项目而不是每次都从零开始猜。Skill vs MCP vs Plugin三者的本质区别这个话题必须讲清楚因为我在各种技术群里看到太多人在问同样的问题「Skills 和 MCP Server 到底什么关系是不是竞品」答案是它们是不同层面的东西互补关系不是替代关系。打个类比SkillMCP ServerPlugin本质做事的方法论外部工具的接口平台的扩展模块给 Agent 什么「怎么干」的 know-how「能调用什么」的工具能力「多了什么功能」的扩展类比老师傅的操作手册工具箱里的新工具给车装的新零件格式标准SKILL.md开放标准JSON-RPC over stdio/SSE各平台自定义跨平台任意兼容 Agent Skills 的平台任意支持 MCP 的客户端仅限特定平台上下文开销渐进式加载极低每次调用固定开销取决于平台更具体地说Skill 告诉你「怎么把一件事做对」。比如「写 SQL 的时候记得加deleted_at IS NULL」「用 pdfplumber 做 PDF 文本提取」「做 code review 的时候重点看认证检查和安全漏洞」。它是知识层面的东西。MCP Server 给你「能做一件新的事」。比如「去数据库里查这张表」「往 Slack 发一条消息」「调一下 GitHub API 创建 Issue」。它是能力层面的东西——Agent 本来不会连接外部系统MCP 给了它那个连接。Plugin 给平台加「一个新功能模块」。比如 VS Code 的 GitLens 插件、Claude Code 的 plugin marketplace。它是平台层面的扩展。三者可以协同工作一个 Skill 里可以写「用 MCP Server X 去查数据库然后按这个格式输出」。Skill 是大脑MCP 是手Plugin 是装备栏。为什么这件事值得花时间理清因为我在好几个技术群里看到同一个误解「有了 MCP Server 就够了要 Skill 干嘛」——这就像你说「有了扳手就够了要维修手册干嘛」。工具和知识从来不是二选一。开发你的第一个 Skill从零到可用好理论讲够了。这一节我带你从头写一个真实可用的 Skill。场景设定你的项目是一个 Spring Boot 微服务所有 REST API 都有统一的响应格式{ code: 200, message: success, data: { ... } }你希望 AI Agent 在写 Controller 的时候自动遵循这个格式而不是写出五花八门的响应结构。第一步创建 Skill 目录mkdir -p .claude/skills/spring-api-response cd .claude/skills/spring-api-response目录名必须全小写用连字符分隔。这个名字就是 Skill 的name。第二步写 SKILL.md--- name: spring-api-response description: Write Spring Boot REST API controllers with the projects standard response format. Use when creating or modifying REST endpoints in a Spring Boot project. --- ## Standard API Response Format All REST endpoints MUST return ApiResponseT: java Data AllArgsConstructor NoArgsConstructor public class ApiResponseT { private int code; private String message; private T data; public static T ApiResponseT success(T data) { return new ApiResponse(200, success, data); } public static T ApiResponseT error(int code, String message) { return new ApiResponse(code, message, null); } }Controller Pattern