ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

从提示词到Skills:AI Agent能力封装的工程实践

从提示词到Skills:AI Agent能力封装的工程实践 先聊个现象。最近跟几个做 AI 应用的朋友对需求大家不约而同都在提同一个词skills。有人把它叫技能包有人叫智能体插件还有人直接说是给模型加了根手指头。这玩意儿现在火到什么程度呢GitHub 上一搜带 skills 的仓库一大半都是这两天新建的。我自己的感受是如果你还在靠一段超长 system prompt 硬撑整个业务逻辑那确实该看看 skills 了——它是目前把会说话的模型变成会干活的系统最顺手的一层封装。这篇文章不聊虚的。我会直接从工程视角拆开skills它解决的到底是什么问题、一个好的 skill 结构长什么样、我是怎么手写一个可复用的 skill 并挂进 Agent 里的以及这几个月实际踩过的坑。适合正在做 AI Agent 应用、或者想优化现有自动化流程的开发者参考哪怕你只是刚接触提示工程也能从这套思路里得到一些启发。1. 从提示词到skills一次能力封装的进化1.1 我理解的 skills 到底是什么先说人话。Skills 本质上是一套结构化的能力模块它告诉模型在什么场景下、按什么步骤、调用什么工具、遵循什么规范去完成某一类特定任务。它不像一段提示词那样只存在于对话上下文里而是以一个可管理、可复用、可独立测试的文件或目录的形式存在。第一次看到这个概念的时候我脑海里冒出来的类比是函数封装。最早写代码都是把逻辑堆在 main 函数里后来发现复用和调试都痛苦才学会了拆函数。提示词工程也经历了同样的过程早期所有指令都堆在 system prompt 里几百行下来模型经常前脚记住后脚就忘加一段需求就得改动全局。Skills 则是把某个领域的一套做法单独拎出来像一个函数一样需要时被加载不需要时不占上下文。从 Agent 的视角看skill 又像是一个岗位说明书。模型本身是通用劳动力它聪明但不专业。你给它一份岗位说明书告诉它你是干这个的遇到这种情况按这么做输出格式是这样它就能迅速进入角色输出质量也稳定得多。本质上skills 就是在给模型做能力上的定向增强。1.2 为什么现在大家都在讨论 skills原因其实很现实重上下文窗口的路线走到头了。早期我们做多步骤任务靠的是把所有背景、规则、示例全部塞进 prompt让模型现场理解再执行。但这种方式有几个绕不开的问题。首先是成本。大模型的计费基本跟着 token 走system prompt 越长每一次请求的基础开销就越高。比如你做了一个社群运营助手把运营手册、历史风格、回复模板全塞进去一次请求光背景就消耗两三千 token。调用量一大费用直接失控。其次是稳定性。prompt 太长会稀释关键指令的权重。模型可能对前面 50 行要求记得很清楚到第 200 行就开始选择性失忆尤其是在输出比较自由的任务里风格漂移特别严重。第三是维护性。改了 A 处的规则可能会让 B 处的行为出现意外变化因为你无法精准定位是哪条 prompt 影响到了当前行为。这跟没有类型系统的代码一样改起来提心吊胆。Skills 的解决思路是按需加载。系统里常驻的是轻量级的路由逻辑只有当用户请求命中某个 skill 的触发条件才加载那一整套指令和资源。相当于从把所有工具都摆在桌面上变成用到哪个拿哪个效率、成本和稳定性都得到了改善。2. skill 的结构设计与建模思路2.1 一个好的 skill 应该包含哪些部分我现在做 skill 的标准结构至少包含四类内容身份与职责、触发条件、执行流程、输出规范。这四样缺一不可少了任何一块skill 的行为都会出现不同程度地不可控。身份与职责是告诉模型你是谁、你负责什么。这里要写得具体且收敛。比如我做了一个代码审查员的 skill身份描述就不是你是一名资深工程师而是你是本项目的前端代码审查者只负责审查 TypeScript 代码关注类型安全、组件复用和性能隐患不涉及后端逻辑和 UI 视觉调整。职责写得越精确模型越不会跑偏。触发条件解决的是什么时候该用你的问题。这个字段我会写得像正则表达式一样紧。宁可触发条件严一点也不要宽泛。宽泛就意味着模型会在不该用的时候强行套用结果反而是负优化。比如日期格式化 skill触发条件可以写成仅当用户输入中出现明确的日期字符串且需要转换格式或计算差值时才使用。加上仅当和且就是明确给模型划边界。执行流程是 skill 的核心它是带步骤的思维链。每一步尽量做到可验证比如第一步从输入中提取所有日期第二步转换为 ISO 8601 格式第三步输出一个 JSON 数组。步骤之间存在依赖关系前一步的输出是后一步的输入。这里特别要注意每一步的指令都应该是行为性的而不是知识性的。你要说提取日期而不是理解日期的含义。输出规范是容易被新手忽略但其实很关键的一块。模型天生是自由表达主义者你不约束格式它就自由发挥。输出规范要精确到结构层面返回 JSON 还是 Markdown字段名是什么枚举值有哪些错误时怎么表示。我在实践里还加了一条自检要求在输出前对照一遍规则确认没有遗漏再返回。2.2 命名、描述与触发条件的隐藏学问很多人在新建 skill 时会忽略一个东西给模型看的描述信息。你给 skill 起什么文件名、写什么描述直接决定模型能不能在合适的时机想到你。我把这一层叫做元信息。模型在判断是否调用某个 skill 时就像人在查字典先看词条标题和释义觉得对路了才往下读正文。如果你的技能描述写得含糊模型可能压根不会触发它。我自己的标准是文件名必须包含明确的任务名词比如 weekly-report-generator 就远比 skills-001 好懂。描述这一栏我会写成当用户需要把一周内的 commit 记录、项目进展、数据变化汇总成结构化周报时使用一句话讲清楚触发场景和功能。描述里最好还加上不适用场景。比如一个会议纪要的 skill描述末尾补一句仅限中文会议英文会议请使用 meeting-minutes-en。这样能有效防止模型在边界情况下的错误调用。还有一个细节触发条件不要只依赖描述。我会在 skill 里附一个触发示例列表写两三条用户可能说的话然后标注命中以上表述时调用本 skill。模型对示例的敏感度远高于抽象描述这是多次实验后确认的经验。2.3 skill 的粒度怎么拿捏做 skill 最纠结的问题就是一个 skill 应该管多宽我在这上面栽过不少跟头总结出两个原则单职责、按场景切分。单职责意味着一个 skill 只解决一类问题。你可能会想做一个全能数据处理 skill既能清洗 CSV又能做数据可视化还能生成分析报告。听起来很省事但实际跑起来你会发现模型在选择该用哪部分能力上就会消耗大量判断力而且每部分能力的指令都因为篇幅限制而变浅最后每个环节都做不精。所以我现在宁愿拆成三个独立的 skill分别负责清洗、绘图、写报告用路由来决定调用哪个效果远好于一个大而全的模块。按场景切分则是从触发频率来考虑。我会把高频、标准化、结果可预期的任务优先做成 skill。比如生成每日站会摘要这种天天用、格式固定的非常适合封装。而低频、需要高度创造性的任务比如策划一场线下活动的创意方案我一般就不做 skill 了让模型自由发挥反而效果更好。粒度拿捏的另一面是skill 太细也会有问题。我之前把销售线索初筛和销售线索打分分别做成两个 skill结果发现它们共享了 80% 的上下文和步骤模型在两个技能之间切换时还容易丢状态。后来合并成一个线索质量评估skill内部分阶段执行效果和效率都明显提升。这个平衡点需要在实际使用中反复调整没有一劳永逸的标准答案。3. 手写一个可复用的 skill完整实操3.1 从一个真实需求出发理论讲再多不如动手做一个。我就用自己的实际项目为例团队里每天有大量技术资料、行业新闻、开源项目更新散落在各个渠道需要有人定期整理成一份结构化的技术情报日报。以前这个活儿靠人肉粘贴费时费力。后来我把它做成了一个 skill让 Agent 每天定时跑一遍输出一份 Markdown 日报。这个例子挺有代表性的因为它涵盖了三类常见能力信息检索读 RSS、读收藏夹、信息筛选判断哪些值得收录、内容组织按分类输出结构化报告。可以说一个复杂 skill 的基本要素它都有了。3.2 目录结构到底怎么搭我目前的 skill 目录结构长这样tech-daily/ ├── SKILL.md ├── assets/ │ ├── sources.txt │ ├── categories.json │ └── templates/ │ └── report_template.md └── scripts/ └── fetch_sources.pySKILL.md 是主文件相当于入口。模型被触发后首先读取的就是这个文件。assets 目录放辅助资源sources.txt 是信息源清单categories.json 是分类定义templates 里放最终输出的模板。scripts 目录放可执行的抓取脚本Agent 需要的时候会调用它获取最新数据。这个结构不是拍脑袋定的。我的原则是主文件负责思考路径资源文件负责领域数据脚本负责外部交互。三者分开维护起来才清晰。你想改分类体系不需要碰主文件想加一个数据源也只需要改 sources.txt。SKILL.md 我用统一的 Markdown 格式写因为模型对 Markdown 的结构化信息解析效果最好。头部的 YAML front matter 用来放元信息正文用中文自然语言写执行逻辑和规范。3.3 SKILL.md 的完整写法与参数说明直接看文件内容--- name: tech-daily description: 当用户需要汇总技术新闻、开源项目、社区热帖等技术情报并生成日报时使用。适用于每日定时的技术信息整理场景。 triggers: - 生成今日技术日报 - 汇总今天的技术情报 - 整理每日技术资讯 --- # 技术情报日报生成助手 ## 职责 你是技术情报整理助手负责从指定信息源抓取内容筛选中高价值信息按分类输出结构化 Markdown 日报。 ## 执行流程 1. 读取 assets/sources.txt获取本轮需要检查的信息源列表。 2. 调用 scripts/fetch_sources.py 拉取各源的最新内容并对每个条目提取标题、链接、摘要、发布时间。 3. 依据 assets/categories.json 中的分类体系对每个条目进行分类打标。 4. 对每条内容进行价值评级A强烈推荐、B值得阅读、C一般浏览。评级标准见下方规则。 5. 按照 assets/templates/report_template.md 的结构填写并输出最终日报。 ## 价值评级规则 - A级与团队当前技术栈直接相关或涉及重大安全更新、重要架构演进。 - B级与团队业务有一定关联或是领域内值得关注的趋势性内容。 - C级泛行业信息或与当前工作关联度低的内容。 ## 输出规范 - 使用 Markdown 格式结构完全遵循 report_template.md。 - 每个分类下若没有内容输出今日暂无更新不要省略该分类。 - C级内容只在其他资讯栏目中输出标题和链接不写摘要。 - 最终输出末尾附上今日共收录 X 条其中 A 级 X 条、B 级 X 条、C 级 X 条的统计行。这里有几个设计细节值得单独说明。触发条件我用了两种形式description 里的场景描述以及 triggers 列表里的具体话术。前者负责泛匹配后者负责精确命中。两者互补能有效减少误触发。执行流程的每一条都是动作指令而非知识描述。我没有告诉模型什么是技术情报而是直接给了它先读列表、再跑脚本、再分类、再评级的操作序列。模型不需要理解任务的意义只需要正确执行步骤。评级规则用与团队技术栈直接相关重大安全更新这类关键词来锚定判断标准。如果你只写判断内容重要性模型会迷失在主观性里。给出具体锚点输出才有一致性。输出规范里我特别写了包含总计统计行这一条。因为数学模型在长输出后面容易忘事明确要求它在最后统计数量能倒逼它在处理过程中做好标记整体准确率会有肉眼可见的提升。3.4 在 Agent 中挂载与实测写好文件之后我把 tech-daily 目录放到了 Agent 的 skills 目录里。不同的 Agent 框架加载方式略有差异有的是扫描固定目录有的是在配置里声明但核心动作是一样的让框架在启动时能扫描到这个 skill并把 SKILL.md 的元信息注册到模型的路由表里。我用的框架加载完成后在测试环境里直接输入生成今日技术日报。第一次输出并不理想——分类是对的但价值评级明显偏差较大几条 C 级内容被标成了 A。我翻了半天原因发现问题出在评级规则里的团队当前技术栈这句话。模型根本不知道我们团队用什么技术栈。这是新手最容易忽略的问题你在 SKILL.md 里写的概念如果模型无法从当前上下文里获知就相当于给了它一个无法解析的变量。解决办法我后面细说。调整之后二次测试输出质量明显好了分类清晰、评级基本合理、格式完全符合模板连末尾的统计行也准确。我又让它连续跑了三次不同时间点的数据每次输出结构一致没有出现格式漂移说明这个 skill 的稳定性是达标的。4. 常见问题与避坑实录4.1 skill 不生效模型根本不理你这是遇到最多的问题但排查起来并不复杂。我总结了一套排查顺序。先确认触发条件是不是太严了。模型在决定是否加载 skill 时本质是一次快速判断你的触发条件如果用了太多当且仅当必须满足以下所有条件这种高门槛描述模型会倾向于不触发因为保守策略比误判的成本更低。改进办法在 SKILL.md 的元信息中写清典型触发话术并给出一两条接近但不完全匹配的示例作为边界参考让模型感知到这是一个宽松匹配。再检查元信息是不是太隐蔽了。有些框架加载 skill 时只读取 description 字段忽略正文里的触发条件说明。如果你的 description 写得模糊比如处理技术信息模型完全无从判断何时该用。把 description 改得更场景化命中率立刻上来了。最后看看是不是 skill 文件本身没被加载。这个问题最尴尬也最常见。有些框架要求 skill 目录名称和 SKILL.md 里的 name 字段完全一致大小写都不能差。我有一次把目录名写成了 tech-dailyname 字段却写的 TechDaily结果框架死活不识别。对完一遍命名规范就好了。4.2 多个 skill 互相打架怎么办当你装了十几个 skill 之后新的问题就来了用户说了一句话好几个 skill 都觉得自己该上场。模型选了这个又觉得那个也有道理最后行为变得不可预测。我遇到的最典型冲突是两个信息处理类 skilltech-daily 和 weekly-report。用户说帮我整理一下这周的进展两个 skill 都被触发了一个输出日报式结果一个输出周报结构格式完全对不上。解决思路是在元信息里增加互斥声明在 SKILL.md 中明确写如果用户请求涉及跨多天的汇总请优先使用 weekly-report如果只是单日情报请使用 tech-daily。这相当于在模型做路由判断时给它一个优先级提示可以显著减少随机选择的情况。另一个办法是按目录分组。在 Agent 框架里给不同 skill 设置独立的触发关键词域让它们在语义空间上尽量不重叠。比如把 tech-daily 的触发限定在日报今日技术情报把 weekly-report 的触发限定在周报本周汇总上。词域分得越开冲突越少。4.3 SKILL.md 写太详尽了反而带崩模型这里讲一个反直觉的经验skill 文件不是越详细越好。我第一次做一个稍微复杂点的 skill 时把执行逻辑写得极其细致包括各种边界情况、规则说明、示例达到将近 500 行。想着信息越全模型越不会出错。谁想到实测效果非常差模型的输出反而变得迟缓且犹豫好像每条输出都要对照所有规则过一遍经常因为规则之间的重叠而互相矛盾。原因是模型的注意力是有限的。一次性给太多约束它会抓不住重点甚至在某些局部产生规则冲突。我的经验是一个 SKILL.md 控制在 100 行以内只保留最核心的执行步骤和输出规范。边界情况不要试图全部穷举而是写一条兜底原则遇到未说明的情况选择对用户最有用的做法并在输出中注明你的假设。这其实是在利用模型的能力而不是对抗它。有些信息模型本身就知道不需要你重复。SKILL.md 只负责提供结构化骨架填充式的内容生成交给模型本身去完成效果反而更好。4.4 别忘了做版本管理与回归测试最后一个坑是关于迭代的。skill 文件的修改非常频繁今天改一句描述明天调一下输出格式都很正常。但如果没有版本管理的意识你很容易陷入一种困境这个 skill 之前明明好用的改完之后反而抽风了。我现在把所有 skill 都放进 Git 仓库里每个 skill 一个目录每次修改都做提交commit message 写清楚改了哪条规则、基于什么原因。这样一旦发现改崩了可以随时回退到上一个可用版本。更重要的是建立一套最小回归测试集。我对每个 skill 准备了几条标准测试输入每次修改后都跑一遍看输出是否仍然符合预期。比如 tech-daily 就准备了三条一条正常请求一条包含大量低价值信息一条完全不相关的请求。只要这三条的输出保持在合理范围内我就认为这次修改没有破坏核心功能。这套流程看起来简单但实际上让我节省了大量排查到底是哪次修改导致问题的时间。如果你打算长期维护一批 skill强烈建议从一开始就建立这个机制。我在实际做 skill 的过程中还有一个体会是不要把它当成一次性的提示词编写而是要当作一个持续维护的工程模块。今天写好的 skill可能过两周因为业务调整就需要改评级规则再过一个月可能信息源都要换一批。保持整个结构的清晰和版本可控才能让 skill 真正成为长期可用的能力资产而不是一次性的实验品。
返回列表