
1. 从skills这个热词说起它到底指什么最近一段时间不管是在技术社区还是各类开发者群组里skills这个词出现的频率高得离谱。很多人第一次看到它脑子里冒出来的可能是技能这个通用含义但在当下的技术语境里它已经变成了一个相当具体的概念——Agent Skills也就是给智能体Agent挂载的、可插拔的能力模块。我最初接触这个概念的时候也有点懵。因为技能这个词太泛了泛到几乎可以指代任何东西。但当你真正上手用过几套 Agent Skills 之后就会发现它其实是一个非常务实的设计思路把一个智能体原本需要靠长提示词硬编码才能完成的事情拆成一个个独立、可复用、可组合的小模块每个模块负责一类具体任务需要的时候挂上去不需要的时候摘下来。这个思路解决的核心问题是什么是上下文膨胀和能力复用。你想想如果你要做一个能写代码、能查文档、能跑测试、能生成报告的智能体把所有规则都塞进一个系统提示里那个提示会膨胀到几千甚至上万 token而且每次调用都要重复消耗。更麻烦的是这些规则之间会互相干扰改一处可能影响另一处。Agent Skills 的做法是把这些能力拆开每个 skill 有自己的描述、触发条件和执行逻辑智能体根据当前任务动态加载对应的 skill用完就释放。关键词里提到的 Google Cloud、GKE、Genkit 这几个词其实指向的是这套机制在云端的落地方式。GKE 是 Google Kubernetes EngineGenkit 是 Google 推出的 AI 应用开发框架。把它们和 Agent Skills 放在一起说明这套东西不只是本地玩玩的玩具而是可以部署到生产环境、跑在容器集群上的正经方案。热搜词里还有agent skills测试skills开发skills安装这些说明大家关心的已经从这是什么过渡到了怎么用、怎么自己写、怎么测。这篇文章我打算把 Agent Skills 这件事从头到尾讲清楚。不管你是刚听说这个词想搞明白它到底能干嘛还是已经上手但卡在某个环节我都尽量把原理、实操、踩坑经验都覆盖到。文章会涉及 skill 的结构设计、开发流程、测试方法、部署思路以及在 GKE 和 Genkit 这类环境下的集成要点。内容偏实战代码和配置都会给到能直接抄作业的部分我尽量写细。2. Agent Skills 的核心机制为什么不是简单的函数调用2.1 Skill 和普通工具调用的本质区别很多人第一次接触 Agent Skills会下意识地把它理解成函数调用或者工具调用tool calling。这个理解不算错但不够准确而且容易导致设计上的偏差。我一开始也是这么想的结果写出来的 skill 又臭又长完全没有发挥出这套机制的优势。普通工具调用的逻辑是模型判断需要调用某个工具输出工具名和参数外部执行后把结果返回给模型。这个过程中工具本身是哑的它不知道自己什么时候该被调用也不知道自己适合处理什么场景全靠模型在运行时判断。Agent Skills 不一样。一个 skill 通常包含三个部分元数据metadata、指令instructions和可选的资源resources。元数据里最关键的是name和description这两个字段决定了智能体在什么情况下会加载这个 skill。指令部分是这个 skill 被加载后注入到上下文里的具体内容可以是一段操作指南、一套规则、甚至是一段代码模板。资源部分则是这个 skill 需要用到的附加文件比如脚本、模板、参考文档。这个设计的精妙之处在于skill 的加载是渐进式的。智能体启动时只需要加载所有 skill 的元数据通常很短当它判断当前任务和某个 skill 的描述匹配时才把那个 skill 的完整指令加载进来。这就避免了把所有能力都塞进上下文的问题。我举个具体的例子。假设你要做一个代码审查的智能体。如果用传统方式你会在系统提示里写一大堆审查规则检查命名规范、检查错误处理、检查性能问题、检查安全问题……这个提示会非常长。但如果用 skill 的方式你可以拆成naming-check、error-handling-check、performance-review、security-audit四个 skill每个 skill 的元数据只有一两句话描述智能体在处理具体代码时根据代码特征决定加载哪几个 skill。这样上下文利用率高得多而且每个 skill 可以独立迭代。2.2 渐进式披露Skill 加载的时机与顺序渐进式披露progressive disclosure是 Agent Skills 最核心的设计理念但也是最容易被忽略的一点。我见过不少人写的 skill元数据描述写得含糊不清导致智能体要么该加载的时候不加载要么不该加载的时候乱加载。这里的关键在于description字段的写法。这个字段不是给你看的是给智能体看的。它需要同时回答两个问题这个 skill 能做什么以及什么情况下应该用它。我总结了一个比较实用的写法模板[动作] [对象] [触发条件/场景]比如一个处理 CSV 文件的 skill描述可以写成解析和转换 CSV 文件当用户需要读取、过滤、聚合或导出表格数据时使用。这样智能体在遇到表格相关任务时就能准确匹配到这个 skill。加载顺序也有讲究。当多个 skill 的元数据都匹配当前任务时智能体会根据相关性排序加载。这里有个坑如果你的 skill 之间功能有重叠智能体可能会加载一堆相似的 skill导致上下文里出现互相矛盾的指令。我的做法是在设计阶段就把 skill 的职责边界划清楚宁可拆得细一点也不要让两个 skill 干同一件事。还有一个实践中的细节skill 的指令部分不要写得太长。我见过有人把一个 skill 的指令写成三千字这完全违背了渐进式披露的初衷。一个 skill 的指令控制在几百字以内比较合适如果确实需要很长的说明应该把详细内容放到资源文件里指令部分只写如何找到并使用这个资源。2.3 元数据、指令、资源三层的协作关系把这三层的关系理清楚是写出高质量 skill 的前提。我用一个实际项目里的例子来说明。假设我要做一个生成 API 文档的 skill。三层结构是这样的元数据层name: api-doc-generator description: 根据代码中的路由定义和注释生成 API 文档当用户需要为 REST 接口生成 Markdown 或 OpenAPI 格式文档时使用指令层注入到上下文的操作指南生成 API 文档时按以下步骤操作 1. 扫描指定目录下的路由文件识别所有 HTTP 端点 2. 提取每个端点的路径、方法、参数、返回值 3. 如果代码中有 JSDoc 或 docstring 注释优先使用注释中的描述 4. 按照 templates/api-doc.md 的格式输出 5. 如果发现缺少注释的端点在文档末尾列出并标记资源层templates/api-doc.md文档模板scripts/scan-routes.py路由扫描脚本examples/sample-output.md示例输出这三层各司其职。元数据负责被找到指令负责怎么做资源负责用什么做。我在实际使用中发现把复杂的逻辑放到脚本里让指令层只负责调度效果比把所有逻辑都写在指令里好得多。因为脚本可以测试、可以复用、可以独立调试而指令层的内容每次都要消耗 token。2.4 和 MCP、Function Calling 的边界在哪里这个话题在社区里讨论得很多我说说我的理解。Function Calling 解决的是模型如何调用一个具体函数的问题它关注的是单次调用的参数和返回值。MCPModel Context Protocol解决的是模型如何访问外部资源的问题它关注的是连接的标准化。Agent Skills 解决的是模型如何获得一套完整的工作方法的问题它关注的是能力的组织和复用。三者不是替代关系而是不同层次的东西。一个 skill 内部完全可以用 Function Calling 来调用具体函数也可以通过 MCP 来访问外部数据源。skill 的价值在于把这些底层能力组织成一套有语义、有场景、可组合的工作单元。理解这个边界很重要因为它决定了你什么时候该写 skill什么时候该写函数。我的判断标准是如果一段逻辑需要告诉智能体在什么场景下、按什么步骤、注意什么事项那它适合做成 skill如果只是一次纯粹的数据转换或查询那做成函数就够了。3. 动手写第一个 Skill从目录结构到可运行3.1 目录结构怎么定一个被低估的设计决策很多人写 skill 的时候随手建个文件就开始写结果写到后面发现文件越来越多自己都找不到东西。目录结构这件事看起来简单但它直接影响 skill 的可维护性和可移植性。我经过几个项目的迭代现在固定用这样一套结构skills/ ├── api-doc-generator/ │ ├── SKILL.md # 元数据 指令 │ ├── scripts/ # 可执行脚本 │ │ └── scan-routes.py │ ├── templates/ # 模板文件 │ │ └── api-doc.md │ └── examples/ # 示例 │ └── sample-output.md ├── csv-processor/ │ ├── SKILL.md │ └── scripts/ │ └── transform.py └── code-reviewer/ ├── SKILL.md └── rules/ └── security-rules.md每个 skill 一个独立目录目录名就是 skill 的标识。SKILL.md是入口文件里面用 YAML frontmatter 写元数据正文写指令。其他子目录按需创建不要为了看起来完整而建一堆空目录。这里有个经验skill 目录名用 kebab-case短横线连接不要用下划线或驼峰。因为很多工具链在处理路径时对特殊字符的处理不一致短横线是最安全的。另外目录名要能一眼看出这个 skill 干什么不要用skill-1、my-skill这种名字。3.2 SKILL.md 的写法元数据字段的取舍SKILL.md是整个 skill 的核心。它的结构是 YAML frontmatter 加 Markdown 正文。frontmatter 里最关键的字段是name和description其他字段根据实际需要添加。--- name: csv-processor description: 读取、过滤、聚合和导出 CSV 文件当用户需要处理表格数据、做数据清洗或生成统计报告时使用 version: 1.0.0 author: your-name tags: - data - csv - etl --- # CSV 处理器 ## 使用场景 当任务涉及以下情况时使用本 skill - 需要从 CSV 文件中读取数据 - 需要对表格数据做过滤、排序、分组 - 需要把处理结果导出为 CSV 或 JSON ## 操作步骤 1. 确认输入文件的路径和编码格式 2. 使用 scripts/transform.py 执行实际的数据处理 3. 处理前先检查列名和数据类型避免类型错误 4. 输出结果时保留原始数据的备份 ## 注意事项 - 大文件超过 100MB不要一次性读入内存用分块处理 - 注意 CSV 中的引号转义和换行符问题 - 如果列名包含中文或特殊字符先做规范化处理关于description字段我再强调一次它是智能体判断是否加载这个 skill 的唯一依据。写得太短匹配不准写得太长浪费 token。我的经验是控制在 50 到 150 个字符之间把做什么和什么时候用都覆盖到。version字段看起来可有可无但在团队协作中很有用。当你更新了 skill 的逻辑改一下版本号别人就知道该重新拉取了。tags字段则是为了方便分类和检索skill 多了之后没有标签会很难管理。3.3 指令部分的写作原则给智能体看的说明书指令部分是 skill 被加载后真正注入到上下文里的内容。它的读者是智能体不是人类所以写法上要和普通文档有所区别。第一个原则是步骤化。智能体擅长执行明确的步骤不擅长从大段描述里自己提炼流程。所以指令部分应该尽量用有序列表把操作步骤列出来每一步说清楚做什么和注意什么。第二个原则是边界明确。要告诉智能体这个 skill 能做什么也要告诉它不能做什么。比如本 skill 只处理 UTF-8 编码的 CSV 文件如果遇到其他编码先提示用户转换格式。这样能避免智能体在超出能力范围的任务上硬撑。第三个原则是示例驱动。如果某个步骤容易出错给一个具体的输入输出示例比写三段解释都管用。我在写 skill 的时候经常会在关键步骤后面附一个例如。第四个原则是避免歧义。中文里很多词是有歧义的比如处理可以指清洗、转换、分析等。在 skill 指令里尽量用精确的动词不要用模糊的表述。3.4 一个完整可运行的最小示例光说理论没意思我给一个能直接跑起来的最小示例。这个 skill 的功能是把 Markdown 文件转换成 HTML虽然简单但包含了 skill 的所有核心要素。目录结构skills/md-to-html/ ├── SKILL.md └── scripts/ └── convert.pySKILL.md--- name: md-to-html description: 将 Markdown 文件转换为 HTML当用户需要把 Markdown 文档发布为网页或嵌入到网站时使用 version: 1.0.0 --- # Markdown 转 HTML ## 使用场景 - 用户提供了 .md 文件需要生成对应的 .html 文件 - 需要把 Markdown 内容嵌入到现有网页中 - 需要批量转换多个 Markdown 文件 ## 操作步骤 1. 确认输入文件的路径检查文件是否存在 2. 运行 scripts/convert.py传入输入路径和输出路径 3. 转换完成后检查输出文件的大小是否合理不应为 0 4. 如果转换失败查看脚本输出的错误信息 ## 注意事项 - 脚本依赖 markdown 库如果未安装会提示 - 默认使用 GitHub 风格的 Markdown 语法 - 代码块会保留语言标记方便后续做语法高亮scripts/convert.pyimport sys import markdown def convert(input_path, output_path): with open(input_path, r, encodingutf-8) as f: md_content f.read() html_content markdown.markdown( md_content, extensions[fenced_code, tables, toc] ) with open(output_path, w, encodingutf-8) as f: f.write(html_content) print(f转换完成: {input_path} - {output_path}) if __name__ __main__: if len(sys.argv) ! 3: print(用法: python convert.py input.md output.html) sys.exit(1) convert(sys.argv[1], sys.argv[2])这个示例虽然简单但结构是完整的。你可以照着这个模式把convert.py换成任何你需要的能力。关键是要保持元数据清晰、指令步骤化、逻辑放脚本这个模式。4. Skill 的测试与调试怎么知道它真的能用4.1 测试 Skill 的三个层次写完一个 skill怎么验证它能不能用我一般分三个层次来测。第一层是单元测试针对 skill 里的脚本。这部分和普通代码测试没区别用 pytest 或者 unittest 都行。重点测边界情况空文件、超大文件、格式错误的输入、特殊字符。我踩过的一个坑是脚本在正常输入下跑得好好的遇到一个包含 emoji 的 CSV 文件就崩了因为编码处理没考虑全。第二层是集成测试测 skill 和智能体的配合。这一步要模拟真实的使用场景看智能体能不能正确加载 skill、能不能按指令执行、执行结果对不对。我通常的做法是准备一组测试用例每个用例包含一个用户请求和期望的输出然后跑一遍看结果。第三层是回归测试在你修改了 skill 之后重新跑一遍之前的测试用例确保没有破坏已有功能。这一步最容易被忽略但恰恰最重要。因为 skill 之间可能有依赖关系改了一个可能影响另一个。4.2 用真实任务验证 Skill 的加载逻辑测试 skill 加载逻辑最直接的办法是拿真实任务去跑。我一般会准备这样几类任务任务类型期望行为验证点完全匹配加载对应 skill元数据描述是否准确部分匹配加载最相关的 skill相关性排序是否合理不匹配不加载任何 skill是否误触发多 skill 匹配按需加载多个是否有冲突我遇到过一个典型问题两个 skill 的描述都包含数据处理这个词结果智能体在处理任何数据相关任务时都会同时加载这两个 skill导致上下文里出现重复指令。解决办法是把描述写得更具体一个写CSV 表格数据处理一个写JSON 结构化数据处理这样就不会混淆了。还有一个反直觉的发现描述写得越具体加载准确率越高但召回率会下降。也就是说描述太泛会误加载描述太窄会漏加载。这个平衡点需要根据你的实际场景来调。我的经验是先写一个中等宽度的描述然后根据测试结果微调。4.3 常见加载失败的原因排查Skill 加载失败是新手最常遇到的问题。我整理了一个排查清单按可能性从高到低排列第一frontmatter 格式错误。YAML 对缩进和特殊字符很敏感一个冒号后面少个空格就可能导致解析失败。我建议用 YAML 校验工具先检查一遍。第二description 字段缺失或为空。有些工具链要求 description 必须有值空值会导致 skill 被跳过。第三目录结构不符合规范。不同平台对 skill 目录的要求可能不同有的要求SKILL.md必须在根目录有的允许在子目录。先确认你用的平台的要求。第四文件编码问题。SKILL.md必须是 UTF-8 编码如果用了 GBK 或其他编码中文内容会乱码导致解析失败。第五权限问题。脚本文件如果没有执行权限调用时会失败。在 Linux 和 macOS 上记得chmod x。排查的时候我习惯先看日志。大多数平台在加载 skill 失败时会输出错误信息从错误信息入手比盲目猜测快得多。4.4 调试 Skill 指令的实用技巧调试 skill 指令比调试代码要难因为你看不到智能体脑子里在想什么。我总结了几个实用的技巧。技巧一把指令打印出来看。在加载 skill 之后把注入到上下文里的完整内容打印出来检查格式是否正确、有没有多余的空行、有没有被截断。我遇到过指令太长被截断的情况导致后面的步骤丢失。技巧二用最小任务测试。不要一上来就用复杂任务测先用一个最简单的任务看智能体能不能走完整个流程。简单任务跑通了再逐步增加复杂度。技巧三对比有无 skill 的差异。同一个任务一次加载 skill一次不加载对比输出结果。如果两者差不多说明 skill 没有起到作用指令可能写得太泛或者太模糊。技巧四记录失败案例。每次 skill 没有按预期工作时把输入、期望输出、实际输出都记下来。积累多了之后你会发现失败模式是有规律的针对性地改指令比盲目调整有效得多。5. 把 Skill 部署到云端GKE 与 Genkit 的集成思路5.1 为什么要在云端跑 Skill本地跑 skill 适合开发和调试但真正要对外提供服务还是得部署到云端。原因有几个一是本地环境的资源有限跑不了太多并发二是本地环境不稳定电脑一关服务就断了三是云端可以做版本管理、灰度发布、监控告警这些生产环境必需的事情。关键词里提到的 GKE 和 Genkit正好对应了云端部署的两个层面。GKE 提供的是容器编排能力负责把 skill 跑起来、管起来。Genkit 提供的是 AI 应用开发框架负责把 skill 和模型、工具链整合起来。两者配合可以搭出一套比较完整的生产级方案。5.2 容器化 SkillDockerfile 的关键配置要把 skill 部署到 GKE第一步是把它容器化。我以一个 Python 实现的 skill 为例给一个可用的 DockerfileFROM python:3.11-slim WORKDIR /app # 先复制依赖文件利用 Docker 层缓存 COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt # 复制 skill 内容 COPY skills/ ./skills/ # 设置非 root 用户运行 RUN useradd -m skilluser chown -R skilluser:skilluser /app USER skilluser # 健康检查 HEALTHCHECK --interval30s --timeout3s \ CMD python -c import os; exit(0 if os.path.exists(/app/skills) else 1) CMD [python, -m, skill_server]这个 Dockerfile 有几个关键点值得说。第一先复制 requirements.txt 再复制代码这样改代码的时候不会触发依赖重装构建速度快很多。第二用非 root 用户运行这是安全基本要求。第三加健康检查GKE 靠这个判断容器是否正常。镜像大小也要注意。python:3.11-slim比完整版小很多如果还嫌大可以用 alpine 版本但要注意 alpine 的 musl libc 和某些 Python 包不兼容。我一般用 slim 版本够用且省心。5.3 Genkit 中注册和使用 Skill 的方式Genkit 是 Google 的 AI 应用开发框架它提供了一套定义工具、流程、提示的 API。把 skill 集成到 Genkit 里核心思路是把 skill 包装成 Genkit 能识别的工具或流程。import { genkit } from genkit; import { googleAI } from genkit-ai/googleai; const ai genkit({ plugins: [googleAI()], model: googleai/gemini-pro, }); // 把 skill 注册为工具 const csvProcessor ai.defineTool( { name: csvProcessor, description: 读取、过滤、聚合和导出 CSV 文件, inputSchema: z.object({ action: z.enum([read, filter, aggregate, export]), filePath: z.string(), params: z.record(z.any()).optional(), }), outputSchema: z.any(), }, async (input) { // 这里调用 skill 的实际逻辑 return await executeSkill(csv-processor, input); } ); // 在流程中使用 const dataFlow ai.defineFlow( { name: dataProcessingFlow, inputSchema: z.object({ query: z.string() }), outputSchema: z.string(), }, async (input) { const response await ai.generate({ prompt: input.query, tools: [csvProcessor], }); return response.text; } );这里的关键是把 skill 的元数据映射到 Genkit 工具的name和description把 skill 的指令逻辑放到工具的执行函数里。这样 Genkit 在调度的时候就能根据工具描述决定是否调用这个 skill。5.4 在 GKE 上编排多个 Skill 的注意事项当你有多个 skill 需要部署时GKE 的编排能力就派上用场了。我一般会用一个 Deployment 跑一个 skill 服务然后用 Service 暴露出来再用 Ingress 统一入口。几个实践中的注意事项资源限制要设。每个 skill 容器的 CPU 和内存都要设 requests 和 limits否则一个 skill 跑飞了会影响整个集群。我一般给每个 skill 设 200m CPU 和 256Mi 内存作为起点根据实际负载调整。副本数要合理。无状态的 skill 可以多开几个副本做负载均衡有状态的 skill 要考虑数据一致性。我建议先从 2 个副本开始观察负载后再调整。配置要外置。不要把 API key、数据库连接串这些写死在镜像里用 ConfigMap 和 Secret 管理。这样换环境的时候不用重新构建镜像。日志要集中。GKE 的日志默认会送到 Cloud Logging但格式要规范方便检索。我一般用 JSON 格式输出日志包含时间戳、skill 名、请求 ID、日志级别这些字段。监控要跟上。至少要有请求量、延迟、错误率这三个指标。GKE 自带了一些基础监控但 skill 层面的指标需要自己埋点。6. 踩坑实录那些文档里不会写的经验6.1 Skill 描述写得太聪明反而坏事我刚开始写 skill 的时候总想把描述写得高级一点用一些抽象的词觉得这样显得专业。结果发现智能体根本理解不了加载准确率很低。举个例子我写过一个 skill描述是提供智能化的数据处理能力。这个描述看起来很厉害但智能体完全不知道什么时候该用它。后来改成读取和转换 CSV、JSON、Excel 文件当用户需要处理结构化数据时使用加载准确率立刻上去了。这个坑的本质是智能体不是人它不会意会。描述要具体、要直白、要包含明确的触发词。抽象的词对智能体来说是噪音不是信号。6.2 指令里的隐含假设是最大的坑写指令的时候我们脑子里有很多隐含假设自己觉得理所当然但智能体不知道。比如我写过一个 skill指令里说处理完成后输出结果但没说什么格式、输出到哪里。结果智能体有时候输出到控制台有时候写到文件有时候直接返回行为不一致。后来我学乖了指令里凡是涉及输出的地方都明确写清楚格式是什么、路径是什么、编码是什么。凡是涉及判断的地方都把判断标准列出来。宁可写啰嗦一点也不要留模糊空间。还有一个相关的坑指令里的示例要覆盖边界情况。我写过一个日期处理的 skill示例里只给了正常日期的处理方式结果遇到2024-02-30这种非法日期就出错了。后来在示例里加上了非法日期的处理方式问题就解决了。6.3 多个 Skill 之间的依赖和冲突当 skill 数量多起来之后依赖和冲突就成了大问题。我遇到过一个情况skill A 的指令里说输出用 JSON 格式skill B 的指令里说输出用 Markdown 格式两个 skill 同时加载时智能体就懵了不知道该听谁的。解决这个问题的办法有几个。一是明确 skill 的优先级在元数据里加一个priority字段冲突时按优先级来。二是把公共规则抽出来放到一个基础 skill 里其他 skill 引用它。三是在指令里写明适用范围比如本 skill 的输出格式仅适用于中间结果最终输出格式由调用方决定。我现在设计 skill 的时候会先画一张依赖图看看哪些 skill 之间有交集交集部分怎么处理。这张图看起来麻烦但能省掉后面很多调试时间。6.4 版本升级时的兼容性处理Skill 升级是个容易被忽略的环节。你改了一个 skill 的指令可能影响到所有依赖它的流程。我踩过的坑是升级了一个 skill 的输出格式结果下游的 skill 解析不了整个流程断了。现在的做法是skill 的元数据里加版本号指令里写明兼容性。比如本 skill 输出格式为 v2与 v1 不兼容升级前请确认下游 skill 已适配。另外重大变更时保留旧版本一段时间让下游有时间迁移。还有一个小技巧在 skill 的指令里加一个变更日志部分记录每次修改的内容和原因。这样别人用这个 skill 的时候能快速了解它的演进历史避免踩到已知的坑。7. 从能用到好用Skill 设计的进阶思路7.1 让 Skill 可组合设计时的接口思维单个 skill 能用不难难的是让多个 skill 组合起来解决复杂问题。这需要你在设计单个 skill 的时候就考虑它和其他 skill 的接口。我的做法是每个 skill 的输入输出都定义清楚用结构化的格式。比如一个 skill 的输出是 JSON字段名和类型都固定下来这样下游 skill 就能可靠地解析。不要用自然语言作为 skill 之间的接口因为自然语言有歧义组合起来容易出错。另外skill 的粒度要适中。太粗组合不灵活太细组合起来步骤太多。我的经验是一个 skill 解决一个完整的小任务比如读取 CSV是一个 skill过滤 CSV是另一个导出 CSV是第三个。这样组合的时候可以灵活搭配。7.2 用 Skill 编排复杂工作流当 skill 多起来之后怎么编排它们就成了新问题。我试过几种方式说说各自的优劣。方式一让智能体自己决定。把所有 skill 的元数据给智能体让它根据任务自己选择加载哪些、按什么顺序执行。这种方式最灵活但可控性差复杂任务容易跑偏。方式二预定义工作流。把常用的 skill 组合固化成工作流智能体按工作流执行。这种方式可控性好但灵活性差遇到新场景要改工作流。方式三混合方式。预定义几个基础工作流同时允许智能体在特定环节自由选择 skill。这种方式兼顾了可控性和灵活性是我目前主要用的方式。具体实现上我一般会定义一个编排 skill它的指令里写清楚什么情况下用哪个工作流工作流里每一步调用哪个 skill出错时怎么回退。这个编排 skill 本身不干具体活只负责调度。7.3 性能优化减少不必要的 Skill 加载Skill 加载是要消耗 token 的加载太多会拖慢响应速度、增加成本。优化加载的策略有几个。策略一元数据精简。只保留name和description两个必需字段其他字段按需添加。我见过有人把整个 skill 的指令都塞进元数据里这完全违背了渐进式披露的设计。策略二描述精准。描述越精准误加载越少。我一般会用测试用例来验证描述的精准度确保不该加载的时候不加载。策略三分层加载。把 skill 分成基础层和扩展层基础层的 skill 常驻扩展层的按需加载。这样常用的能力随时可用不常用的不占上下文。策略四缓存已加载的 skill。在同一个会话里已经加载过的 skill 不要重复加载。这个需要平台支持但如果你的平台不支持可以在编排层自己做缓存。7.4 团队协作中的 Skill 管理一个人写 skill 和一群人写 skill 是两回事。团队协作中skill 的命名、版本、文档、测试都需要规范。命名规范我建议用领域-功能的格式比如>