写 Skill 的心法和手法
从结构、边界和可靠性维度,讨论为 AI Agent 编写 Skill 的通用方法
现在有了一种新的编程方式:给 AI Agent 写一段指令,让它替你在代码库里完成一个任务。这段指令如果足够完整、足够稳定、可以反复使用,就有了一个名字——Skill。
但你很快会发现,写 Skill 和写 prompt 是两件完全不同的事。一个 prompt 只需要让模型在一次调用里产出好的回复。一个 Skill 要管理的是 Agent 在多次调用、多个步骤、面对各种意外输入时的行为。它要处理的不是”这次回答好不好”,而是”这套流程可不可靠”。
这篇文章想讨论的,就是这件事背后的通用问题:Skill 究竟是什么,写 Skill 时你在对抗什么,以及有哪些反复出现的模式可以借鉴。
文中的例子主要来自 UI 设计、代码审查、文档生成等领域,但讨论的问题是跨领域的。
Skill 是一种执行环境#
先做一个区分。
给 Agent 写一条指令”帮我设计这个页面”,你是在写一个 prompt。这条指令的质量取决于你描述得多清楚、上下文给得多充分。但每次用的时候你都要重新描述,Agent 的行为取决于当时怎么理解你的话。
给 Agent 写一个 Skill,你是在定义一套执行环境。Skill 回答的不只是”做什么”,还有”在什么条件下做""做到什么程度算完成""什么情况下停下来问""做错了怎么发现和修正”。Skill 把”一次好的回答”变成了”每次都可预测的执行”。
可以这样理解:Agent 是一个能力很强但不稳定的执行器——类似一个没有操作系统的 CPU。它会执行指令,但你需要自己管理内存、处理中断、保证原子性。写 Skill,本质上是在给这个执行器写一个迷你的操作系统。
这解释了为什么写 Skill 的体验和写 prompt 完全不同。写 prompt 时你在想”怎么表达更清楚”。写 Skill 时你在想”这个边界应该画在哪""这个检查是交给脚本还是留给 Agent 判断""这一步的产物如果丢了,下一步会不会炸”。
问题域彻底变了。
五组张力#
Skill 设计中的所有具体决策,几乎都可以追溯到更底层的结构性问题。这些问题不局限于某个领域,也不局限于某个 Agent 平台。它们是在”用指令约束一个不可靠执行器”这个基本设定下必然出现的张力。
约束与能力#
给 Agent 加约束,它的行为更可预测。但约束越紧,它能处理的场景就越窄。
一个极端的例子:把 Skill 写成固定脚本——“先读 A,再运行 B,再写入 C”——Agent 没有犯错的空间,但它也完全失去了处理意外输入的能力。另一个极端:只给 Agent 一个模糊的目标描述——“让这个页面更好看”——Agent 有最大的灵活性,但产出完全不可控。
设计 Skill 时,这个问题表现为一连串具体的判断:哪些操作需要用户显式授权?哪些决策 Agent 可以自己做?遇到 Skill 没覆盖到的场景,是停下来问还是猜测着继续?
确定与智能#
Agent 能做的事情里,有一部分可以通过传统脚本验证——文件是否存在、HTML 是否合法、颜色对比度是否达标。另一部分只能靠 Agent 自己判断——这个布局好不好、这个交互顺不顺畅、这个文案得不得体。
脚本的结果是确定性的、可重复的、不消耗 token。Agent 的判断是灵活的、能处理模糊情况的、但每次运行结果可能不同。
好的 Skill 不会一刀切地选择某一边。它会精确地标出哪些检查点交给脚本,哪些留给 Agent。标错了地方——把该脚本化的交给 Agent 判断,或者把该 Agent 判断的硬塞进脚本——Skill 的可靠性就会下降。
具体与通用#
一个 Skill 如果只为一个项目、一种场景写,它可以做到极度精确:知道这个项目用的是什么组件库、token 命名规则是什么、代码风格偏好是什么。但它换一个项目就失效了。
一个 Skill 如果要覆盖所有项目、所有场景,它就必须足够抽象:只定义方法论和通用规则,不涉及任何具体技术栈。但抽象到一定程度,它给 Agent 的指导就不够了——Agent 仍然要自己填补大量细节。
这个张力的本质是:Skill 的信息从哪来。一部分是 Skill 写作者预先内置的领域知识(具体但有限),一部分是 Agent 在运行时从项目中读取的上下文(灵活但不可控)。分配多少给预置、多少给运行时推断,是 Skill 设计最核心的取舍之一。
上下文窗口就是这个张力的硬边界。窗口里的每一个 token 都是稀缺资源。你把 Skill 的内置知识写得越详细,留给 Agent 读取项目上下文的空间就越少。Skill 不是在真空中被读取的——它跟项目代码、对话历史、工具输出共享同一个窗口。写 Skill 时你永远在做一个经济决策:这个信息值不值得占窗口。
连续与无状态#
Agent 的每次调用之间没有记忆。上一轮它做了三个步骤、生成了两个文件、发现了一个问题,下一轮调用开始时它什么都不记得。
这迫使 Skill 设计者面对一个基础问题:如果 Agent 是 stateless 的,工作流怎么连续推进?
答案是文件系统。Skill 把 Agent 的行为轨迹、中间产物、状态标记全部写进文件系统里——追踪文件记录每一步做了什么、审计报告记录哪些问题修了哪些没修、蓝图文件记录当前的设计意图。Agent 不需要”记住”,它只需要在每步开始时读文件。
这个设计的副作用是:Agent 的行为变得可追溯了。你不只能看到最终产物,还能看到它每一步做了什么决策、基于什么依据。
单次决策与流程编排#
最后一个张力来自 Agent 的行为模式差异。
把一个问题交给 Agent,有时它能一步到位。AI 的强项是理解模糊意图、处理复杂上下文、一次性生成完整方案。但它有一个系统性的弱点:很容易跳过”想清楚要做什么”直接跳到”做”。问它”设计一个订单页”,它可能直接生成 HTML,没有先分析这个项目已有的组件、tokens 和交互模式。
这意味着,想在 Skill 层面获得可靠的结果,往往需要主动打散 Agent 的单次决策,把它编排成一个多步骤流程:先分析、再规划、再执行、再检查。每一步只让 Agent 做一个相对简单的判断,每一步的产出都写进文件。
这跟 AI 的”直觉优势”是矛盾的——AI 善于一步到位的全局判断,但 Skill 的设计逻辑偏偏要求分步走。这种张力会一直存在:分步越细,可靠性越高,但也越慢、越冗余;分步越粗,效率越高,但每步内的偏差空间也越大。
六种模式#
这些张力不是”解决”掉的——它们是在设计中被反复处理的。在不同领域、不同团队的 Skill 中,逐渐浮现出了一些反复出现的处理方式。它们不是铁律,但理解这些模式能让你在设计 Skill 时少走弯路。
边界先行#
在定义 Agent 能做什么之前,先定义它绝对不能做什么。
这个模式对应的是”约束与能力”的张力。因为 Agent 的默认倾向是”做些什么”,约束往往比鼓励更有效。把不可触碰的区域提前标出来——不修改哪些文件、不调用哪些工具、不问哪些类型的问题——Agent 的行为边界就清晰了。
具体做法包括:指定产物的输出目录、列出不允许的副作用、对高风险操作要求用户显式确认、定义 Skill 不适用的场景并给出拒绝话术。
分类-分支#
在开始做事之前,先判断当前是什么场景,再走对应的分支。
不同项目、不同输入类型、不同用户意图,Agent 应该有不同的行为路径。“设计订单页”在一个有成熟组件库的旧项目里的含义,和在一个全新项目里的含义完全不同。如果 Skill 不先做分类,Agent 就会用同一套逻辑处理所有情况。
这个模式的实现要点是两条:分类标准必须是可操作的具体条件(文件是否存在、配置是否完整、产物是否缺失),不能是”项目是否复杂”这种模糊判断;不同分支的行为差异必须足够大(加载的参考文件不同、检查的前置条件不同、产出的内容不同),否则分类就没有意义。
确定性锚点#
在流程的关键节点插入脚本检查。Agent 负责”做”,脚本负责”验”。
这个模式对应的是”确定与智能”的张力。脚本不替代 Agent 的判断——Agent 仍然要决定用什么颜色、选什么布局、处理哪些状态。但脚本在关键节点上提供了一条不变的地平线:产物是否完整、关键属性是否存在、已知的反模式是否被触发。
脚本的输出应该是结构化的——JSON 或明确的退出码——这样 Agent 能直接消费,不需要”理解”检查结果。Agent 可以对脚本发现的问题做判断(修还是不修、怎么修),但不能否认问题的存在。
渐进加载#
Skill 的信息分层存放,Agent 按需加载。
所有的指令信息都在争夺同一个上下文窗口。把整本操作手册在第一步就全部加载进去,不仅浪费 token,还会稀释关键指令。分层结构让 Agent 在正确的时刻读到正确的信息:入口层定义”能做什么”,参考层定义”具体怎么做”,子技能层定义”遇到特定场景怎么办”。
分层不只节省 token,它改变了 Agent 的行为。Agent 对于刚刚读到的指令有更强的遵循意愿;对于很久以前读到、淹没在大量上下文中的指令,遵循程度明显下降。信息的加载时机和信息的精确度同样重要。
外化状态#
把 Agent 的行为轨迹、中间产物和当前状态全部写进文件系统。
Agent 没有跨调用的记忆,但文件系统有。追踪文件、蓝图文件、审计报告——这些文件的本质是把 Agent 的执行过程变成可持久化的数据结构。下一个步骤的 Agent 读这些文件,就像读数据库一样获取上一个步骤的上下文。
这个模式的副产品是:每个步骤的产出都成了后续步骤的输入,形成了一条自然的产物链。产物链本身就是流程约束——缺了一环,下一步就会因为找不到输入而自动停止。不需要 Agent 自己记得”我做到哪了”,文件系统会告诉它。
先规划再执行#
对复杂任务,拆成两步:先让 Agent 产出一份规划文档,再让它基于规划文档生成最终产物。
Agent 有一种系统性倾向:直接跳到”做”。规划文档是一个干预机制——它迫使 Agent 在动手之前把”我要做什么、用什么做、做到什么程度”写清楚。这份文档之后会被验证、被后续步骤引用,成为整个流程的中枢。
规划文档同时也是人类评审的界面。你不需要读 Agent 生成的几百行 HTML 才能判断设计方向对不对,读一页 shape.md 就够了。方向不对,改规划文档比重做整个产物成本低得多。
发心:写 Skill 时你实际上在做什么#
回到最开始的问题。
写 Skill 和写 prompt 的本质区别是:prompt engineering 的目标是”让模型在这一次调用里产出好东西”,Skill 的目标是”让 Agent 在无数次调用里持续产出可靠的结果”。前者是一个修辞问题,后者是一个系统工程问题。
这意味着 Skill 写作者的思维模型需要从”我怎么描述这个任务”切换到”我怎么设计一个让 Agent 不容易出错的执行环境”。你不再只是一个写指令的人,你开始像一个操作系统设计者那样思考:定义进程的边界、管理状态的生命周期、在关键节点设置检查点、处理各种异常路径。
好消息是,Agent 的能力已经足够强了。它不需要你教它怎么画页面、怎么写代码、怎么审查逻辑——它的模型权重里已经有这些能力。Skill 解决的是另一个问题:如何让这些能力被正确地、一致地、在正确的时机和边界内被调用。
这最终是关于可靠性的。在一个不可靠的执行器之上,一步一步地、一层一层地,构建出一个相对可靠的系统。每一条边界、每一个检查点、每一份追踪文件,都是为了把 Agent 的出界概率再降低一点。
写 Skill 这件事没有银弹,只有持续积累的判断:这里该收紧,那里该放活,这个地方需要一个脚本兜底,那个场景要停下来问用户。一个写了很多 Skill 的人和一个刚开始写的人,差距不在 prompt 技巧,在于做了多少这样的判断,踩了多少坑,对 Agent 的行为模式有多深的体感。