ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Agent Skills 实战:从零搭建可复用技能模块,解决提示词膨胀与能力耦合

Agent Skills 实战:从零搭建可复用技能模块,解决提示词膨胀与能力耦合 1. 从“skills”这个热词说起它到底是什么为什么突然火了最近几个月不管是在技术社区、开发者群聊还是在做AI应用的朋友圈子里“skills”这个词出现的频率高得离谱。有人叫它 Agent Skills有人叫它 Claude Agent Skills还有人直接简称为 skills。热搜词里甚至出现了“今天学会了skills打开新世界”这种非常情绪化的表达。作为一个在AI应用开发一线摸爬滚打多年的人我一开始也以为这不过是又一个包装概念直到我自己动手把一套 skills 体系跑通、接到实际项目里才意识到这东西确实值得认真聊一聊。先把话说清楚skills 本质上是一种把“能力”模块化、可复用、可组合的封装机制。你可以把它理解成给 AI Agent 准备的“技能包”——每个技能包里面包含了完成某类任务所需的指令、工具调用逻辑、上下文约束和输出规范。Agent 在运行时根据当前任务动态加载对应的 skills而不是把所有能力一股脑塞进一个巨大的提示词里。这个思路听起来简单但它解决的是当前 AI 应用开发中最让人头疼的几个问题提示词膨胀、能力耦合、复用困难、维护成本高。为什么现在火因为大家发现单纯靠堆提示词、堆上下文窗口已经很难让 Agent 稳定完成复杂任务了。你写一个能写论文的 Agent再想让它同时会做分镜、会挖漏洞、会做前端代码审查提示词会膨胀到无法维护而且不同能力之间会互相干扰。skills 的出现本质上是把软件工程里“模块化”和“关注点分离”的思想搬到了 Agent 能力构建上。这个类比很重要后面我会反复用到。这篇文章适合谁看如果你正在做 AI Agent 相关的开发或者你是一个重度 AI 工具使用者想搞清楚怎么让 AI 更稳定地完成特定任务那这篇内容会对你有直接帮助。如果你只是听说过 skills 这个词想知道它到底是不是又一个炒作概念我也会用实际操作的视角给你一个判断依据。全文我会围绕 skills 的设计思路、核心机制、实操落地、常见坑和排查方法展开尽量做到你看完就能动手试。2. skills 的核心设计思路为什么不是“又一个提示词模板”2.1 从“万能提示词”到“技能模块化”的必然转变早期做 Agent 的人包括我自己都经历过一个阶段试图用一个超级提示词解决所有问题。你会在系统提示里写“你是一个资深工程师你会写代码、会审查、会写文档、会做架构设计、会排查问题……”然后下面跟几千字的规则。刚开始效果还行但随着任务复杂度上升你会发现几个致命问题。第一能力之间会互相污染。当你让 Agent 同时具备“写论文”和“挖漏洞”两种能力时写论文时它可能会突然用上安全测试的思维输出一堆风险评估做安全测试时它又可能开始讲究学术引用格式。这不是模型笨而是提示词里的指令在互相竞争注意力。第二维护成本指数级上升。每加一个能力你都要回头检查它会不会影响已有能力。改一处可能崩三处。这种维护体验做过大型提示词工程的人都懂非常痛苦。第三无法复用和共享。你写了一个很好的“代码审查”提示词想分享给同事只能整段复制。同事想把它和自己的“文档生成”能力结合又得手动拼接拼完还得调。整个过程没有任何工程化的痕迹。skills 的设计思路就是针对这三个问题来的。它把每个能力封装成一个独立的 skill 单元每个单元有自己的触发条件、执行逻辑、依赖工具和输出格式。Agent 在运行时根据任务类型动态加载对应的 skill而不是一次性加载所有能力。这就像你电脑上不会同时打开所有软件而是用什么开什么。这个类比虽然简单但非常准确。2.2 skills 的组成结构一个 skill 里到底有什么一个完整的 skill通常包含以下几个部分。不同平台和框架的实现细节会有差异但核心结构是相通的。元信息Metadata包括 skill 的名称、描述、版本、适用场景、触发关键词等。这部分决定了 Agent 在什么情况下会加载这个 skill。元信息写得好不好直接决定了 skill 能不能被正确触发。指令集Instructions这是 skill 的核心告诉 Agent 在执行这类任务时应该遵循什么步骤、注意什么约束、输出什么格式。它类似于一个专门针对某类任务的系统提示但比系统提示更聚焦、更短。工具依赖Tool Dependencies这个 skill 需要调用哪些外部工具或 API。比如一个“代码审查”skill 可能需要读取文件、运行静态分析工具、查询代码规范文档。把这些依赖显式声明出来Agent 在加载 skill 时就能知道需要准备什么。输入输出规范I/O Schema定义这个 skill 接受什么输入、输出什么结果。这是实现 skill 之间组合的关键。如果每个 skill 的输入输出都是自由文本那组合起来就会很混乱有了明确的 schemaskill 之间就可以像函数调用一样串联。示例Examples一些典型的输入输出示例帮助 Agent 更准确地理解这个 skill 的预期行为。示例的质量往往比指令本身还重要因为模型对示例的敏感度很高。我自己的经验是元信息和示例是最容易被忽视但最影响效果的两部分。很多人写 skill 时把大量精力花在指令集上写了几千字规则但元信息就写了一句“用于代码审查”示例一个没有。结果就是 Agent 要么不触发这个 skill要么触发了但输出格式完全不对。后来我调整了策略先把元信息和示例写好指令集反而可以精简很多整体效果提升非常明显。2.3 为什么 skills 比传统插件机制更适合 Agent有人可能会问这不就是插件机制吗以前也有插件为什么现在 skills 又火了这个问题问得好我一开始也有同样的疑惑。仔细对比之后我发现 skills 和传统插件有几个本质区别。传统插件通常是功能导向的它封装的是一个具体功能比如“查天气”“发邮件”“搜索网页”。插件本身不包含太多“怎么用”的智慧它只是把能力暴露出来具体怎么调用、什么时候调用、调用后怎么处理结果全靠 Agent 自己判断。这就导致 Agent 在面对复杂任务时经常不知道该用哪个插件、该怎么组合。skills 是任务导向的它封装的是“完成某类任务的完整方法论”。一个 skill 不仅告诉 Agent 有哪些工具可用还告诉它这类任务的典型流程是什么、有哪些坑、输出应该长什么样。这相当于把人类专家的经验也封装进去了而不仅仅是工具本身。另一个区别是组合方式。传统插件的组合往往需要开发者手动编排或者依赖 Agent 的临场判断。skills 通过明确的输入输出 schema让 skill 之间可以像乐高积木一样拼接。一个“数据清洗”skill 的输出可以直接作为“数据分析”skill 的输入中间不需要人工干预。这种可组合性是 skills 真正强大的地方。还有一个容易被忽略的点skills 是可版本化和可测试的。你可以给每个 skill 写单元测试验证它在给定输入下是否产生预期输出。这在传统提示词工程里几乎做不到因为提示词是一个整体你没法单独测试其中某一部分。skills 把能力拆开之后测试和迭代就变得可行了。这一点对于要把 Agent 用到生产环境的团队来说价值巨大。3. 核心细节解析一个高质量 skill 应该怎么写3.1 元信息设计让 Agent 在正确的时候想起你元信息看起来简单但它是 skill 能否被正确触发的第一道关卡。我见过太多 skill 因为元信息写得太模糊导致 Agent 要么不加载要么在不该加载的时候加载。写元信息时我通常遵循几个原则。第一描述要具体到场景而不是泛泛而谈。比如“用于代码审查”就不如“用于审查 Python 代码中的安全漏洞和性能问题输入为代码文件路径输出为问题列表和修复建议”。后者明确说了语言、审查维度、输入输出形式Agent 匹配起来准确率高很多。第二触发关键词要覆盖同义表达。用户不会总是用同一个词来描述需求。有人会说“审查代码”有人会说“检查代码问题”有人会说“code review”。如果你的触发关键词只写了“代码审查”那其他表达就可能匹配不上。我的做法是列出至少五到八个同义或近义表达覆盖不同用户的语言习惯。第三版本和依赖要写清楚。如果你的 skill 依赖某个特定版本的模型能力或外部工具一定要在元信息里标注。否则换了个环境skill 可能就跑不起来了。我踩过这个坑一个依赖特定文件解析库的 skill换到另一台机器上因为库版本不对直接报错排查了半天才发现是依赖没声明清楚。下面是一个元信息示例用 YAML 格式展示这种格式在多数 skills 框架里都通用name: python-security-review description: 审查 Python 代码中的安全漏洞包括注入风险、敏感信息泄露、不安全的反序列化等 version: 1.2.0 triggers: - 代码安全审查 - Python 安全检查 - 漏洞扫描 - security review - 检查代码安全问题 inputs: - name: code_path type: string description: 待审查的 Python 文件或目录路径 outputs: - name: issues type: array description: 发现的安全问题列表每项包含位置、严重程度、描述和修复建议 dependencies: - python3.9 - bandit1.7这个元信息里触发词覆盖了中英文常见表达输入输出有明确类型依赖也列清楚了。Agent 在匹配时只要用户表达落在这些触发词附近就能准确加载。3.2 指令集编写把专家经验翻译成可执行步骤指令集是 skill 的灵魂。写得好Agent 执行起来像专家写得差Agent 就像刚入行的新手步骤混乱、遗漏关键点。我的经验是指令集要写成“操作手册”而不是“知识百科”。很多人写指令时喜欢堆知识比如“Python 中常见的注入风险包括 SQL 注入、命令注入、模板注入……”这些知识模型本身就有写进去反而占用上下文。真正有价值的是操作步骤先做什么、再做什么、遇到什么情况怎么处理、输出格式是什么。一个实用的指令集结构通常是这样的任务目标一句话说清楚这个 skill 要达成什么。前置检查执行前需要确认什么比如文件是否存在、依赖是否安装。执行步骤按顺序列出每一步做什么每步的预期结果是什么。分支处理遇到不同情况时分别怎么处理比如发现高危漏洞时优先输出发现低危问题时批量汇总。输出规范最终输出什么格式包含哪些字段字段的含义是什么。边界说明什么情况下这个 skill 不适用应该转给哪个 skill 处理。这里有个细节值得展开分支处理是区分普通 skill 和优秀 skill 的关键。普通 skill 只告诉 Agent“做什么”优秀 skill 还告诉它“遇到 A 情况怎么做遇到 B 情况怎么做”。这就像给新员工的培训手册好的手册会把各种异常情况都考虑到新员工遇到问题不会慌。Agent 也是一样有了分支处理它在面对复杂输入时表现会稳定很多。我自己的一个“代码审查”skill指令集里专门有一段处理“如果代码文件超过 500 行”的情况先按函数拆分逐个审查最后汇总。这个分支处理让 skill 在处理大文件时不会因为上下文超限而崩溃。这种细节只有实际跑过、踩过坑的人才会想到写进去。3.3 工具依赖与权限控制别让 skill 变成安全隐患skills 通常会调用外部工具这就带来了权限和安全问题。一个设计不当的 skill可能会让 Agent 执行危险操作比如删除文件、发送网络请求、修改系统配置。我的做法是最小权限原则每个 skill 只声明它真正需要的工具权限不多给。比如一个“代码审查”skill 只需要读文件和运行静态分析工具的权限就不应该给它写文件或执行任意命令的权限。这在元信息里就要声明清楚框架层面也要做校验。另外对外部工具的调用要做输入校验。Agent 生成的工具调用参数不一定总是合法的如果直接传给外部工具可能会出问题。比如一个执行命令的工具如果 Agent 生成的命令里包含了用户输入的未转义内容就可能有注入风险。虽然这是框架层面的事但写 skill 的人也要有这个意识在指令集里明确告诉 Agent 哪些参数需要转义、哪些操作需要二次确认。还有一个实践中的经验给危险操作加确认环节。如果一个 skill 需要执行删除、覆盖、发送这类不可逆操作我会在指令集里要求 Agent 先输出操作计划等确认后再执行。这个确认可以是人工确认也可以是另一个 skill 的校验。多这一步能避免很多误操作。我见过因为 skill 直接执行了覆盖操作把重要文件清空的情况事后排查发现是 Agent 误解了用户意图。加个确认环节这种问题基本就能杜绝。4. 实操过程从零搭建一个可用的 skill 并接入 Agent4.1 环境准备与框架选择动手之前先要把环境搭好。skills 本身是一个概念具体实现依赖你用的 Agent 框架。目前比较常见的有几类一类是云平台提供的 Agent 开发框架比如 Google Cloud 上的相关服务它们通常内置了 skills 管理能力一类是开源框架比如 Genkit 这类工具链可以自己搭建 skills 加载机制还有一类是直接基于模型 API 自己实现 skill 调度逻辑。选哪个取决于你的实际需求。如果你是在做企业级应用需要稳定的托管和运维云平台方案省心但灵活性受限。如果你需要深度定制或者想完全掌控 skill 的加载和执行逻辑自己实现更合适。我自己的项目里因为需要和已有的 GKE 集群集成选择了在容器化环境里自己实现 skill 调度这样能更好地控制资源隔离和权限。环境准备的核心是确定 skill 的存储和加载方式。skill 本质上是一些配置文件加代码可以存在本地文件系统也可以存在数据库或对象存储里。我推荐用文件系统加版本控制的方式每个 skill 一个目录目录里放元信息文件、指令文件、示例文件和测试文件。这样便于版本管理也便于团队协作。目录结构大概长这样skills/ python-security-review/ skill.yaml instructions.md examples/ input1.py output1.json tests/ test_review.py >name: csv-data-cleaning description: 清洗 CSV 数据处理缺失值、重复行、格式不一致和异常值 version: 1.0.0 triggers: - 数据清洗 - 清洗 CSV - 处理缺失值 - 去重 - data cleaning inputs: - name: file_path type: string description: CSV 文件路径 - name: strategy type: string description: 缺失值处理策略可选 drop、fill_mean、fill_median、fill_mode default: drop outputs: - name: cleaned_file_path type: string description: 清洗后的文件路径 - name: report type: object description: 清洗报告包含处理的行数、列数、缺失值数量等 dependencies: - python3.9 - pandas1.5然后写指令集。指令集我用 Markdown 格式因为可读性好模型理解起来也顺畅# 任务目标 对指定的 CSV 文件进行数据清洗输出清洗后的文件和清洗报告。 # 前置检查 1. 确认 file_path 指向的文件存在且为 .csv 格式 2. 确认 strategy 参数在允许范围内 3. 检查 pandas 是否可用 # 执行步骤 1. 读取 CSV 文件记录原始行数和列数 2. 统计每列的缺失值数量和比例 3. 根据 strategy 处理缺失值 - drop删除包含缺失值的行 - fill_mean用列均值填充数值列缺失值 - fill_median用列中位数填充数值列缺失值 - fill_mode用列众数填充分类列缺失值 4. 检测并删除完全重复的行记录删除数量 5. 对字符串列进行去空格和统一大小写处理 6. 对数值列检测异常值超过 3 倍标准差在报告中标记但不自动删除 7. 保存清洗后的文件文件名加 _cleaned 后缀 8. 生成清洗报告 # 分支处理 - 如果文件为空直接返回错误提示不执行后续步骤 - 如果某列缺失值比例超过 80%在报告中特别标记建议用户考虑删除该列 - 如果 strategy 为 fill_mean 但列不是数值类型回退到 fill_mode 并记录警告 # 输出规范 清洗报告为 JSON 格式包含以下字段 - original_rows原始行数 - original_columns原始列数 - missing_values每列缺失值数量 - duplicates_removed删除的重复行数 - outliers_flagged标记的异常值数量 - warnings警告信息列表 # 边界说明 本 skill 仅处理 CSV 格式。如果输入是 Excel、JSON 或其他格式应转给对应的 skill 处理。这个指令集里我特意加了分支处理和边界说明。分支处理让 skill 在面对异常输入时不会直接崩溃边界说明则明确了 skill 的适用范围避免 Agent 在不该用的时候硬用。4.3 测试与调试怎么知道 skill 写对了skill 写完不是就完了必须测试。我通常从三个层面测试单元测试、集成测试和端到端测试。单元测试针对 skill 的核心逻辑。比如数据清洗 skill我会准备几个小 CSV 文件分别测试缺失值处理、去重、格式统一等功能是否按预期工作。单元测试用代码写可以自动化运行每次改完 skill 跑一遍确保没有回归。集成测试验证 skill 和 Agent 的配合。把 skill 加载到 Agent 里用自然语言描述任务看 Agent 是否能正确触发 skill、传入正确参数、处理返回结果。这一步经常能发现元信息或指令集的问题。比如我写过一个 skill单元测试全过但集成测试时 Agent 死活不触发排查发现是触发关键词写得太窄用户换个说法就匹配不上。端到端测试模拟真实使用场景。用完整的任务描述从用户输入到最终输出走一遍看整体体验是否流畅。这一步能发现一些边界问题比如多个 skill 同时被触发时会不会冲突、skill 执行失败时 Agent 有没有合理的降级处理。调试 skill 时我有个习惯把 Agent 的决策过程打印出来。很多框架支持输出 Agent 的思考链能看到它为什么选择某个 skill、为什么传这些参数。这个信息对调试非常有用。有一次我发现 Agent 总是给数据清洗 skill 传错 strategy 参数看了思考链才发现是我在指令集里对 strategy 的描述不够清晰Agent 理解偏了。改清楚描述后问题就解决了。4.4 接入实际项目几个关键配置skill 测试通过后接入实际项目还有几个配置要注意。第一加载策略。是启动时加载所有 skill还是按需动态加载启动时加载简单但 skill 多了会占用大量内存和上下文。按需加载灵活但需要实现匹配逻辑。我的建议是skill 数量少于 20 个时启动时加载全部元信息执行时按需加载完整内容超过 20 个时考虑用向量检索的方式做元信息匹配只加载最相关的几个 skill。第二超时和重试。skill 执行可能失败比如外部工具不可用、网络超时。要给每个 skill 设置合理的超时时间并定义重试策略。我的经验是读操作可以重试写操作要谨慎重试避免重复写入。重试次数一般不超过 3 次超过就报错让上层处理。第三日志和监控。skill 的执行情况要记录日志包括触发时间、输入参数、执行结果、耗时、错误信息。这些日志对排查问题和优化 skill 都很有价值。我一般会把日志按 skill 名称分类方便快速定位是哪个 skill 出了问题。第四版本管理。skill 会迭代不同版本可能行为不同。要在元信息里标注版本并在加载时记录使用的版本。如果发现某个版本有问题可以快速回滚。我吃过这个亏一个 skill 更新后没做好版本管理线上出问题想回滚发现旧版本已经被覆盖了只能紧急修复非常被动。5. 常见问题与排查技巧实录5.1 skill 不触发或触发错误怎么办这是最常见的问题。Agent 该用某个 skill 时没用或者不该用时用了。排查思路如下。先检查元信息的触发关键词。把用户的实际输入和触发关键词对比看是否有匹配。如果没有补充同义表达。如果有匹配但没触发可能是匹配逻辑的问题比如大小写敏感、分词方式不对。这时候要看框架的匹配实现必要时调整。再检查是否有其他 skill 竞争。如果多个 skill 的触发条件重叠Agent 可能选了另一个。这时候要调整元信息让每个 skill 的适用范围更清晰。我的做法是给每个 skill 加一个“优先级”字段冲突时按优先级选择。最后检查指令集里是否有排除条件。有时候 skill 被触发了但指令集里的前置检查没通过Agent 就放弃了。这时候要看前置检查是否过于严格适当放宽。5.2 skill 执行结果不稳定怎么排查同一个 skill同样的输入有时候结果好有时候结果差。这种不稳定通常来自几个方面。输入格式不一致。用户输入可能是自由文本Agent 提取参数时可能提取出不同的结果。解决办法是在指令集里明确参数提取规则或者加一个参数校验步骤。上下文干扰。如果对话历史很长或者同时加载了多个 skill上下文里的信息可能干扰当前 skill 的执行。解决办法是执行 skill 时清理无关上下文只保留必要信息。模型随机性。模型输出本身有随机性同样的输入可能产生不同输出。如果对稳定性要求高可以降低温度参数或者让 Agent 多次执行取一致结果。我在做关键任务时会让 Agent 跑三次取多数一致的结果稳定性提升明显。5.3 skill 之间冲突或循环调用怎么处理多个 skill 组合使用时可能出现冲突或循环调用。比如 skill A 的输出触发了 skill Bskill B 的输出又触发了 skill A形成死循环。解决办法是设置调用深度限制。每个 skill 执行时记录调用链如果发现循环就中断并报错。另外skill 的输入输出 schema 要设计得足够明确避免模糊匹配导致意外触发。还有一个经验给 skill 分组。把功能相关的 skill 放在一组组内 skill 可以互相调用组间调用需要显式声明。这样能减少意外冲突。我在一个项目里把 skill 分成“数据处理组”“分析组”“输出组”组内调用自由组间调用需要经过一个调度 skill冲突问题少了很多。5.4 常见问题速查表问题现象可能原因排查方法解决措施skill 不触发触发关键词不匹配对比用户输入和关键词补充同义表达skill 触发错误多个 skill 竞争检查触发条件重叠调整优先级或范围执行结果不稳定输入格式不一致检查参数提取结果明确提取规则执行超时外部工具慢或卡死查看工具调用日志设置超时和重试循环调用skill 互相触发打印调用链设置深度限制输出格式错误指令集输出规范不清检查输出示例补充格式示例权限报错工具权限未声明检查元信息依赖补充权限声明版本冲突依赖版本不匹配检查依赖声明锁定版本号这张表是我在实际项目中总结的基本覆盖了八成以上的常见问题。遇到问题时先查表能快速定位方向再深入排查。5.5 几个容易踩的坑和独家技巧坑一元信息写得太泛。我见过一个 skill 的描述是“用于处理数据”这种描述等于没描述。Agent 根本不知道什么时候该用它。后来改成“用于清洗 CSV 文件中的缺失值和重复行”触发准确率立刻上去了。坑二指令集里堆知识。前面提过模型本身有知识你堆进去反而占用上下文。把知识换成操作步骤效果更好。坑三忽略示例的作用。示例比指令更能约束模型行为。我现在的习惯是每个 skill 至少配三个示例覆盖正常情况、边界情况和异常情况。示例写好了指令集可以精简一半。技巧一用测试驱动 skill 开发。先写测试用例明确输入输出再写 skill。这样写出来的 skill 目标清晰不容易跑偏。技巧二给 skill 加“自检”步骤。在指令集最后加一步让 Agent 检查自己的输出是否符合规范。这一步能拦截不少格式错误。技巧三定期回顾 skill 使用日志。看看哪些 skill 经常失败、哪些很少被触发。失败的优化不用的清理。保持 skill 库精简高效。技巧四skill 命名要有规律。我用“领域-功能-版本”的命名方式比如“data-cleaning-v1”“code-review-security-v2”。这样一眼就能看出 skill 的用途和版本管理起来方便。6. 关于 skills 生态的一些个人观察skills 这个概念火起来之后各种 skills 市场、skills 推荐、skills 大全也跟着出现了。有人在做 skills 的分享平台有人在做 skills 的自动生成工具还有人把 skills 和特定领域结合比如写论文的 skills、做分镜的 skills、安全测试的 skills。这个生态正在快速形成。我的判断是skills 的价值最终取决于质量而不是数量。一个精心设计的 skill比一百个粗制滥造的 skill 有用得多。现在很多 skills 市场里大量 skill 只是把提示词换了个包装没有真正的模块化设计也没有测试和版本管理。这种 skill 用起来问题很多反而会增加维护负担。如果你打算认真做 skills我的建议是少而精。先把一两个核心场景的 skill 做扎实跑通测试接入实际项目验证效果。有了成功经验再扩展。不要一上来就追求大而全那样很容易做成一个没人用的 skill 库。另外skills 的可组合性是它最大的潜力所在。单个 skill 的能力有限但多个 skill 组合起来能完成非常复杂的任务。我最近在尝试把数据清洗、数据分析、报告生成三个 skill 串起来用户只需要提供一个原始数据文件Agent 就能自动完成从清洗到报告的全流程。这种组合带来的效率提升是单个 skill 无法比拟的。后续我还会继续探索更多 skill 组合的可能性比如把代码审查和自动修复结合把文档生成和翻译结合。这个方向值得投入时间。最后分享一个我在实际使用中的小体会skill 的迭代不要追求一步到位。先写一个能用的版本跑起来收集问题再迭代。我最早的一个 skill 只有十几行指令经过十几次迭代现在有几百行但每一行都是根据实际问题加进去的。这种从实践中长出来的 skill比一开始就设计得很复杂的 skill 更实用、更稳定。
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进