☰
从“塞提示词”到“拆技能包”:agent-skills 实战复盘
2026/10/8 5:07:39 网站建设 项目流程

从“塞提示词”到“拆技能包”:我实践 agent-skills 的一手记录

最近大半年我一直在折腾 AI Agent 的实际落地,从简单对话到接工具、跑工作流,走得越深越发现:决定一个 Agent 好不好用的,多半不是底层模型有多强,而是你给它搭的“能力骨架”有多合理。这一轮我重点复盘的项目是agent-skills,一句话概括,就是给智能体设计一套可复用的“技能库”——把模型需要掌握的每一项独立能力,打成标准化的技能包,按需加载、组合、更新。这个方向现在社区里很热,很多人拿它和 MCP 放在一起讨论,但其实两者解决的问题完全不同。这篇文章不聊概念,直接讲我从设计、拆解到落地踩坑的完整过程,适合正在做 Agent 应用、被系统提示词越改越长困扰的开发者参考。

1. 从“大而全的指令”到“小而准的技能包”:整体设计思路

1.1 为什么单靠系统提示词行不通

开始动agent-skills之前,我的 Agent 是典型的“系统提示词堆砌型”。一个支持内容写作加数据分析的助理,提示词里塞了写作风格要求、数据格式说明、工具调用规则、输出模板、免责声明……加起来一度超过八千 token。表面看是“全都照顾到了”,实测问题一大堆。

首先是注意力稀释。模型对提示词不同位置的敏感度不一样,也不是每段都会同等对待。八千多 token 塞进去,真正关键的“调用数据分析工具前必须先校验字段格式”反而经常被跳过。其次是维护成本失控。每个需求变更都要改一大段提示词,改完还得全量回归测试,生怕影响了另一个功能。第三是能力无法复用。另一个项目也想让 Agent 做同样的内容风格控制,只能把那段提示词复制过去,两个项目各自维护一份,很快出现漂移。

后来我意识到,这本质上是在用一个“线性文档”承载“组合式能力”。正确做法应该是把能力模块化。就好比公司给新员工培训,如果只发一张写满八百条注意事项的纸,他大概率记不住也用不好;但如果给一套按岗位拆分的作业指导书,用到哪本就翻哪本,效果会好得多。agent-skills就是把“作业指导书”做成标准化格式,让 Agent 自己决定什么场景该翻哪一本。

1.2 技能包到底是个什么东西

agent-skills里的“技能”,官方一点说,是一个包含技能定义文件和配套资源文件的目录。它不是 tool/function 那种“单个 API 函数的精确描述”,也不是 workflow 那种“固定的多步骤执行链路”,它的粒度介于两者之间。

我习惯用一个对比来帮助团队理解:

能力载体核心内容适用场景加载方式类比
系统提示词全局规则与指令全程生效的基础约束常驻上下文工牌上的岗位职责
Tool/Function Call函数签名与调用说明单次精确 API 调用按需传入计算器,按一下出一个结果
Agent Skill目标、流程、规范、资源文件、示例需要一系列步骤和领域知识才能完成的子任务按需读取 SKILL.md作业指导书,翻开后按步骤执行
Workflow多个步骤的有向流程图固定的、端到端的自动化流程流程引擎执行车间流水线

一个技能包通常负责一件完整的事,比如“检查网页可访问性”“做一次合规审查”“整理会议纪要为行动项”。它里面不光告诉模型“要做什么”,还告诉它“判断该不该做、从哪入手、按什么顺序做、有什么禁忌、产出什么格式”。关键在于,技能包默认不占上下文,只有模型判断“当前任务可能适合这个技能”时,才把技能定义加载进来。这对于上下文管理是质的改善。

1.3 思路落点:约定优于配置

我研究完agent-skills相关的几个开源实现,包括把 Claude Skills 设计思路搬到自己项目里时,最大的感受是四个字:约定优于配置。整个体系不靠复杂的中心化注册中心,不靠一堆配置文件互相引用,而是靠一套简单的目录和文件命名约定,让模型和工具都能自动发现技能。

约定核心就两条。第一,每个技能是一个独立目录,目录名就是技能名,全小写加连字符,比如accessibility-check。第二,每个目录里必须有一个SKILL.md,这个文件是技能的“入口文档”,用 Markdown 编写,包含 YAML 格式的 front matter 写明技能名称和描述,正文则用自然语言描述技能的使用场景、步骤、规范和示例。模型扫描技能目录时,先读SKILL.md的 front matter 和开头部分来判断是否调用;决定调用后,再把整个文件甚至配套资源读进来。

为什么这种“约定”比“配置中心”更合适?一个很现实的原因是通用性和渐进式支持。任何支持文件系统访问的 Agent 框架,都能按这个约定扫目录、读文件,不需要引入特定的 SDK。团队协作时,新成员新增一个技能,只需要照着其他人已有的目录结构创建文件即可,不需要理解一套复杂的接口协议。这套约定把“技能的扩展”从“写代码”降级成了“写文档”,门槛一下子就低了。

2. 技能包文件结构拆解:一个技能到底该长什么样

2.1 目录结构与命名规范

先给一个我在项目中实际使用的技能目录示例,这是agent-skills最基础的一层约定:

~/.claude/skills/ ├── accessibility-check/ │ ├── SKILL.md │ ├── scripts/ │ │ ├── check_aria.py │ │ └── audit_report_template.html │ └── references/ │ └── wcag-quick-checklist.md ├── meeting-minutes/ │ ├── SKILL.md │ ├── templates/ │ │ └── action-item.csv │ └── scripts/ │ └── summarize.py └── dependency-audit/ ├── SKILL.md └── scripts/ └── check_outdated.py

这里有几个我后来补上的规则,说清楚可以少走弯路。第一,技能目录名必须是全局唯一 ID,一旦定了尽量别改,因为它会被模型记录在对话上下文里,改名等于让模型重新“认识”这个技能。第二,SKILL.md之外的所有文件,都算配套资源,不建议直接在根目录平铺太多文件,至少按scripts/、templates/、references/分类,否则目录一多根本没法维护。第三,每个技能包的总大小要有上限,我自己实践下来的经验是单个技能包所有文本资源加在一起不要超过 100KB,最好控制在 50KB 以内。原因很简单:技能被调用时这些内容可能被整体读入上下文,包越大,上下文占用越不可控。

2.2 SKILL.md:技能包的灵魂

SKILL.md是整个技能包最核心的文件。它决定了模型能不能正确判断“什么时候该用这个技能”、以及“用了之后能不能按预期执行”。我的通用模板长这样:

--- name: accessibility-check description: 检查网页或 HTML 内容的可访问性问题,识别缺失的 ARIA 标签、对比度不足、表单可访问性缺陷,并给出符合 WCAG 2.1 AA 的修复建议。当用户提到“无障碍”“a11y”“可访问性检查”或给出网页地址/HTML 代码时使用。 --- # 可访问性检查 ## 适用场景 - 用户要求检查某个网页或 HTML 片段的可访问性。 - 代码审查过程中需要评估无障碍标准。 ## 执行步骤 1. 确认输入来源:是 URL、本地 HTML 文件还是粘贴片段。 2. 提取 HTML 内容,若为 URL 建议先抓取正文并清理无关标签。 3. 调用 `scripts/check_aria.py` 生成结构审计结果。 4. 对照 `references/wcag-quick-checklist.md` 逐项核对清单。 5. 输出报告:按严重级别列出问题、位置、违反原则、修复建议。 ## 重要事项 - 不修改用户原始代码,只输出建议。 - 若输入内容不完整,先请求补充而非自行臆测。 - 报告中使用 WCAG 原则代号(如 1.1.1 非文本内容)。

写SKILL.md有几个核心技巧,是我反复测试后总结的。description字段是重中之重,它承担“技能检索”的功能,模型不会把每个技能都读完,很多实现里只把技能名加 description 放进候选列表,让模型先筛一遍。所以 description 里必须包含明确的触发词、主要目标、输入输出形态,比如“当用户提到……时使用”,这比泛泛写“提供可访问性测试服务”有效得多。

正文部分,可以理解成在给一个能力很强但完全没做过该工作的实习生写说明书。要包含:判断条件、执行步骤、禁忌事项、产出格式、以及最好有一个小例子。这里有一个容易被忽略的点:不要只写“做什么”,一定要写“怎么做”和“不怎么做”。模型很容易只按字面执行,省略操作细节或者脑补不存在的规则,一份描述足够具体的 SKILL.md 能极大减少这类问题。

2.3 配套资源:脚本、模板与参考数据的取舍

技能不是纯文档,很多时候需要脚本工具和参考数据来配合。我在agent-skills中把配套资源分成三类,各有各的设计讲究。

第一类是脚本,放在scripts/目录。它们的功能是替模型执行确定性操作,比如解析 DOM、计算对比度、查包版本。写这些脚本时有个原则:把输入输出设计得尽量简单,最好是“接收一个文件路径或标准输入,输出结构化文本或文件”。不要搞成需要交互式命令行参数的复杂程序,因为模型不一定能准确构造复杂参数,但让它“把这段 HTML 存成文件,然后运行python scripts/check_aria.py input.html -o result.txt”是完全可以信赖的。脚本的输出格式也要考虑机器可读性,我通常让脚本输出 JSON 或带标记的 Markdown,这样模型拿回结果后可以直接整理成报告。

第二类是模板,用于规范产出物。比如会议纪要技能里放一个action-item.csv模板,模型在生成行动项时按列输出;审核报告技能里放一个 HTML 模板,保证报告样式统一。模板的用途是降低模型自由发挥的空间——自由发挥在文字类产出上可以,但在有固定结构的产出上往往就是灾难。

第三类是参考数据,放references/目录。它们是被动查阅的资料,比如 WCAG 速查清单、公司内部编码规范摘要、某个框架的版本兼容表。这类文件应保持精简,因为它们是技能被调用时消耗上下文的主要来源。我一般会把长文档压缩成要点列表,超过 80KB 就考虑拆分成多个子文件,让模型按需查。

3. 从零实现一个技能包:完整实操记录

3.1 选场景:为什么第一个技能要做“可访问性检查”

理论讲得再多,不如上手做一个技能来得直观。第一个技能我建议选一个边界清晰、不需要联网依赖、有明确产出物的场景。我选的例子是“网页可访问性检查”(即 a11y),理由有三条:输入很好获取,一段 HTML 或一个 URL 就行;判断标准有现成权威参考,WCAG 2.1 的各项条款是公开且稳定的;产出的报告结构也很固定,方便我们验证技能效果。

这样一来,我们既能验证技能的文件结构设计,又能验证脚本工具是否被正确调用,还能验证最终报告是否保持了统一格式。过程中的每一步踩坑,都会对后面写其他技能有指导意义。

3.2 从零开始搭建技能包文件

第一步,建立目录结构:

mkdir -p skills/accessibility-check/{scripts,references}

第二步,写SKILL.md。我直接把上面模板里的内容细化,加上了更明确的“何时不用”说明,避免模型把普通代码审查也当成可访问性检查来触发。比如我会在 description 后面追加一句:“如果用户只是要求排版美化、功能开发,则不要使用本技能。”

第三步,写辅助脚本scripts/check_aria.py。这个脚本不需要做全量 WCAG 审计,只做一件确定的事:扫描 HTML 里的 img 标签是否有 alt、表单控件是否有关联 label、按钮是否有可访问名称、颜色对比度是否明显不足。输出 JSON 列表,每个问题带severity、element、issue、wcag_ref、suggestion五个字段。

#!/usr/bin/env python3 """轻量 ARIA/可访问性结构检查脚本""" import sys, json, re from html.parser import HTMLParser class A11yParser(HTMLParser): def __init__(self): super().__init__() self.issues = [] self.current_tag = None self.current_attrs = {} def handle_starttag(self, tag, attrs): self.current_tag = tag self.current_attrs = dict(attrs) if tag == 'img' and 'alt' not in self.current_attrs: self.issues.append({...}) if tag in ('input','select','textarea') and \ 'aria-label' not in self.current_attrs and \ 'label' not in self.current_attrs: self.issues.append({...}) # 其余解析逻辑略 if __name__ == '__main__': html = open(sys.argv[1], encoding='utf-8').read() parser = A11yParser() parser.feed(html) print(json.dumps(parser.issues, ensure_ascii=False, indent=2))

第四步,放references/wcag-quick-checklist.md。内容是我从 WCAG 2.1 里挑出来的常见检查项,控制在几十行,重点是“能辅助模型给出正确条款编号”,不追求覆盖全部条款。

3.3 把技能挂载到 Agent:三种方式

技能包建好之后,怎么让 Agent 用起来?根据框架不同,有三种方式我都实践过。

最省事的是目录扫描自动挂载。把skills/目录丢到 Agent 配置指定的技能根目录(比如很多工具默认读~/.claude/skills/),启动时框架自动扫描每个子目录的SKILL.md,把名称和描述注册到候选技能列表。这种方式对个人项目最友好,我日常调试都靠它,新增技能只需要重新启动会话或触发一次技能列表刷新,不需要改代码。

第二种是显式配置接入。适合技能目录不在默认位置,或者只想在特定项目里启用部分技能的场景。比如在项目级配置里写:

[agent.skills] enabled = ["accessibility-check", "meeting-minutes"] skills_path = "./.agent/skills"

显式列好处是可控性强,几十个技能的项目不会因为目录里多了一个实验性技能就全部生效。缺点是每次新增技能都得改配置,有点烦,所以我在正式环境用显式,本地调试用自动扫描。

第三种是运行时临时引入。有些 Agent 框架支持用户在对话中手动引用某个技能文件,比如输入@accessibility-check或 “使用 accessibility-check 技能检查这段 HTML”。这种方式最适合测试单个技能的效果,也是我在没把握时最常用的验证路径:不依赖模型自动判断,强制加载,先看技能本身靠不靠谱,再放开让它自动触发。

无论哪种方式,都要记住一件事:技能本身不是无限上下文菜单,它默认只是候选。框架把技能列表呈现在模型面前,模型自己判断要不要深入阅读某个SKILL.md,这是agent-skills最核心的机制,理解这一点,后面就不会被“技能为啥没生效”折磨太久。

3.4 从“能用”到“好用”的细节打磨

技能包跑通流程只是第一步,我在反复使用中总结了好几个从“能用”到“好用”的关键细节。

第一个细节是技能的 description 要做“正反例测试”。描述里写了“当用户提到可访问性检查时使用”,但用户很可能会说“这个按钮好像读不出来”“颜色看着对比度不够”,这些不包含关键词的请求,模型能不能正确联想到accessibility-check?我发现只在 description 里写严格关键词是不够的,需要把常见同义表达写进去,比如“读屏”“屏幕阅读器”“残障用户能用吗”。反过来,也要写“不适用时避免使用”,防止模型看到谁都像用得上。

第二个细节是设计运行时信息的反馈闭环。技能执行完,应该给 Agent 一个“自我评估”的出口。我在技能里加了一小段后续步骤:“输出报告后,请检查是否所有步骤都已执行,若用户未提供足够信息,请明确指出缺失项。”这是为了预防模型跳步。你可以理解成给流程加了一个轻量级检查点,不会显著增加 token,但可以减少约三成的漏项。

第三个细节是文本引用的格式策略。如果一个技能包有大量参考资源,不建议初版就让 Agent 一次性读入所有references/文件。我实测的做法是把SKILL.md写成主文件,里面给出“按需访问二级文件”的指令。比如:“如果需要确认具体 WCAG 条款编号,请阅读references/wcag-quick-checklist.md。”这样模型先加载的是精简主文件,只有到具体步骤时才去读参考文件,上下文占用能再往下降一截。

4. 常见问题与排查实录

4.1 技能总是不被触发,到底问题出在哪

这是agent-skills项目里被问到最多的问题。我的排查顺序一向固定:先确认技能是否成功注册,再看 description 质量,最后检查输入和技能边界是否匹配。

确认注册这一步,最直接的办法是让 Agent 输出它当前可用的技能列表。很多框架支持类似“/skills”这样能列出已加载技能的命令,看技能在不在列表里。不在,检查目录路径对不对、SKILL.md的 front matter 格式对不对。在但没触发,问题基本出在 description。我在调试时总结出一条经验:description 不能只描述“技能是什么”,而要说清楚“用户说什么/做什么时该用这个技能”。前者是知识目录,后者才是触发索引。比如“检查网页可访问性”和“当用户希望确认页面是否符合无障碍规范时使用,包括处理读屏兼容、表单标签缺失、颜色对比度低等诉求”,后者的召回率明显更高。

还有一个很微妙的坑:有些框架会按“关键词向量相似度”来让模型选择技能,如果某个技能的 description 和你日常对话里的用词离得太远,即便功能完全对口也不会被选中。解决办法不是堆关键词,而是用几组同义表达测试一下,找到能稳定触发的那版描述。

4.2 上下文被技能包污染,对话越聊越乱

技能按需加载的初衷是省上下文,但如果设计不当,反而会让上下文更臃肿。我自己遇到过的典型场景:一旦确认某个技能适用,模型把整个SKILL.md和全部references/文件都读了一遍,那些参考文件加起来可能有七八十 KB,直接把对话历史挤没了。

解决这个问题,建议采纳两个约束。第一,技能主文件默认控制在 2KB 以内,超过的部分都放到二级文件里,用“按需阅读”的方式触发。第二,在SKILL.md里明确写一句“除非用户要求,否则不要输出完整技能内容”,避免模型为了“展示能力”把参考文档整篇引用进回答。还有一点,如果 Agent 框架支持“技能上下文释放”,也就是完成任务后可以解除技能占用,一定要用上——尤其是长期对话里,技能一旦用完还挂在上下文里,后面的对话会被持续干扰。

4.3 两个技能同时命中,互相打架怎么办

技能多了之后,很容易出现“多技能冲突”。举一个我踩过的例子:项目里有两个技能,一个是“前端可访问性检查”,一个是“前端代码安全审计”。用户说“帮我看看这段前端代码有没有问题”,两个技能 description 都命中,模型有时候会同时加载,结果输出既不像可访问性报告也不像安全审计报告,四不像。

处理冲突我有两个方法。第一,在技能描述中增加明确的排他性说明:“如果用户请求偏向安全性(CSP、XSS、依赖漏洞),请使用 dependency-audit 技能;如果偏向无障碍,请使用 accessibility-check;如果不确定,优先请求澄清。”这相当于在技能体系里加了一层路由规则。第二,在框架层面,给技能加上“优先级”或者“互斥标签”的能力。实现方式可能因框架而异,但思路是:当两个技能具备相同触发域,只加载高优先级的一个。我自家项目里直接改成了把 route 信息写进 front matter:

routes: when_ambiguous: "优先请求用户澄清,不要同时加载" mutually_exclusive_with: ["frontend-security-audit"]

这比完全依赖模型自觉靠谱得多。

4.4 版本更新、脚本权限与安全边界

技能包迭代速度很快,随之而来的是版本管理问题。特别是SKILL.md更新后,模型在同一个长会话里可能还持有旧版本的记忆,导致行为和最新文档不一致。最稳妥的做法是:每次更新技能之后,开启新会话验证。如果必须在长会话中更新,最好在技能内容里加上版本号信息,并在更新时明确提示模型“技能已更新,请以最新版本为准”。

另一个容易翻车的是技能包里的脚本权限。Agent 在执行本地脚本时,相当于拿到了一个可执行代码入口。如果技能包是从网上下载来的,安全风险很高。我现在的安全底线是:不轻易运行来源不明的技能包脚本,优先自己做代码审查;技能包必须声明依赖和运行环境;如果有脚本,运行前给 Agent 明确约束“只允许执行scripts/目录下的文件”。可以参考的检查清单如下:

  • SKILL.md中是否包含任何可疑指令,比如“调用任意外部命令”“读取系统敏感文件”。
  • 脚本是否只处理输入给定路径的文件,是否有网络请求、文件删除等高风险操作。
  • 技能包是否声明了生成日期、作者、版本号,没有来源的基线视为不可信。

我自己在正式使用中就是把技能分“可信”和“不可信”两档,加载策略完全不同。可信技能可以自动挂载,不可信技能必须先隔离审查再考虑启用。

4.5 技能维护:写好之后还要持续迭代

技能写完之后不是一劳永逸的。维护阶段我习惯做三件事:看日志里的触发记录、收集漏触发样本、定期精简描述。触发记录很容易看出来,哪些技能天天被用,哪些一个月也用不了几次。用不了几次的技能,我会评估是没写对触发词,还是这个能力根本不值得做成技能——不值得就删,技能库贵精不贵多。

收集漏触发样本是指把“用户提问说得很含糊,但本质上是要触发某个技能”的真实对话记录下来,回头更新到 description 里去。我前前后后迭代了七八版accessibility-check的 description,每次加一组同义表达,触发准确率才稳定到满意的水平。定期精简描述也很重要,description 写太长会吸引模型在候选阶段消耗大量 token 去解析,反而不利于精确触发。

写在最后:我对 agent-skills 的一点实际体会

整个项目做下来,我最大的体会是:技能包的难点不在于写脚本,而在于“描述清楚边界”。同样的能力,描述写得不好,模型要么视而不见,要么乱用一气。一个技能包 70% 的价值在SKILL.md的 description 和执行步骤里,脚本只是锦上添花。所以新手入门,我建议别急着写复杂技能,先整理出自己工作中三五个高频、标准化、可判定的子任务,把它们打成最简技能包,跑通一遍“创建—挂载—触发—迭代”的闭环。等这套节奏形成了,再逐步扩展技能库。技能数量控制在 20 个以内最好,超过之后维护成本和互相干扰的问题会指数上升。

另外还有一个被低估的细节:技能包的命名和描述也是一种“团队接口”。如果多人协作共享一套技能库,命名混乱、描述随意都会导致别人压根不知道有这个技能。我把技能库的 README 当作产品文档来写,每个技能一行描述加示例用法,团队新成员上手速度明显快了很多。这些小经验没什么高深道理,但确实是实实在在被逼出来的。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询