前阵子有个朋友跑来找我吐槽,说他在 agent 项目里一口气塞了十几个 Skill,结果真正能用起来的没几个。模型要么根本不理会 Skill 的存在,把指令当成普通对话闲聊,要么就是照着 Skill 里的步骤执行到一半突然开始自由发挥,输出结果跑偏得离谱。我让他把其中一个 SKILL.md 发过来看了一眼,瞬间就明白问题出在哪儿了——那哪是 Skill,分明是一份野心勃勃的“万能 prompt”,既有宏大目标,又有抽象要求,就是没有一条能让模型老老实实照着做的具体指令。
这其实是我见过最多的通病。很多人以为 Agent Skill 就是“把提示词换个文件格式装起来”,实际上完全不是一回事。一个真正好用的 Agent Skill,本质上是一套“可复用的能力包”:它得能被路由系统准确识别,得能被模型稳定执行,得能在不同对话场景里反复复用,还得在出错时有兜底方案。这些东西不设计好,Skill 写得再多也是摆设。
这篇文章我准备从 Skill 的定位讲起,聊聊它的目录结构、描述写法、指令组织方式,再用三个真实场景(论文检索、绘图、语言学习)做完整拆解,最后说说怎么测试和迭代一个 Skill。内容会偏向实操,适合正在做 agent 开发、项目里 Skill 效果不理想、或者刚开始接触 Agent Skills 机制的朋友。看的时候最好手边有个项目,边看边改,效果比单纯读一遍好得多。
1. 先搞明白 Skill 在 Agent 系统里的定位
1.1 Skill 不是提示词,是“能力包”
我们先把概念对齐一下。在 Claude、Codex、OpenCode 这些支持 Agent Skills 的框架里,一个 Skill 通常是一个独立目录,里面放一个 SKILL.md 作为主指令文件,再加上若干辅助资源,比如脚本、参考文档、模板、示例数据。模型在对话过程中会读取这个目录,按照里面的说明来执行任务。
你可以把它理解成给模型配了一个“固定套餐”:用户点了这个 Skill 之后,模型不再自由发挥自己想怎么做,而是按照套餐里写的流程、用套餐里给的工具、最终产出套餐里规定的格式。所以 Skill 解决的核心问题,其实是“不可控”。Prompt 只能告诉模型“你要做什么”,Skill 则进一步规定了“按什么流程做、用什么工具做、交什么格式的作业”。这就是两者最本质的区别。
我在实际项目里见过不少把 Prompt 直接改名成 SKILL.md 的团队,结果自然是不好用。因为普通 Prompt 是在“当前这次对话”里生效的,它的所有假设都建立在“模型已经理解了上下文”这个前提下。而 Skill 是脱离具体对话存在的,它必须自己把一切说清楚:输入是什么、输出是什么、遇到异常该怎么办。这更像是给一个完全不了解业务的新同事写操作手册,而不是给一个资深大佬写需求文档。
1.2 Skill 的三个核心标准:稳定、可测、可复用
既然说 Skill 不是 Prompt,那我们怎么衡量一个 Skill 写得好不好?我自己一般看三个指标。
第一是稳定。同一个 Skill,同样的输入,跑五次,结果应该基本一致,而不是这次输出表格、下次输出纯文本、再下次直接回车换行。稳定性是 Skill 的底线,如果这一点做不到,后面所有东西都免谈。
第二是可测。好 Skill 的设计者会主动给 Skill 准备一组固定测试用例,比如“输入 X 时,必须输出包含 Y 的结果”。这样每次改完 Skill,都能拿这组用例快速回归一遍,而不是每次都在真实对话里手动试错。
第三是可复用。Skill 不能绑定死某一个特定对话场景,它应该能在不同话题、不同上下文里被反复调用。比如“周报生成 Skill”,不管用户这周干了开发、写了文档还是做了测试,它都能工作。如果 Skill 里写死了某些话题假设,那它本质上就是一段一次性 Prompt,没有做成 Skill 的意义。
1.3 为什么说现在是做 Skill 的好时候
这两年 agent 框架的生态变化非常快。以前每个人做 agent 都是自己设计一套提示词工程方案,代码各自为政,技能没法流通。但现在越来越多的 agent 项目开始统一采用 SKILL.md 这个格式,这意味着你写出来的一套技能,换到另一个框架里也可以直接复用,或者稍微改改就能跑起来。社区里甚至已经能看到不少人分享自己的 Skill 仓库,比如有人做了“book to skill”,直接把一本书的内容整理成技能包;也有人做“论文 skill”“语言学习 skill”“前端 skill”之类的垂直技能。
我个人的判断是,Skill 正在慢慢变成 agent 生态里的“标准件”。以后做 agent 开发,核心竞争力不再是你会不会写提示词,而是你能不能设计出稳定、高效、可组合的 Skill 组件。现在把基本功打扎实,后面会省很多事。
2. 写好一个 Skill,先想清楚这三件事
2.1 一个 Skill 只做一件事,别搞“全家桶”
我在拆解别人的 Skill 时,最常见的失败原因就是职责太多。一个 Skill 既想翻译,又想润色,还想做摘要,最后模型根本不知道该优先执行哪条指令。你说做翻译,它顺手给你加了一段“摘要如下”;你说做润色,它把内容风格改得面目全非。原因很简单:指令太多会让模型在决策时产生冲突,而且描述信息也被稀释了,路由系统很难判断这个 Skill 到底该在什么场景下被触发。
正确的做法是坚持单一职责原则——一个 Skill 只解决一类问题。如果你确实需要多种能力,就拆成多个 Skill,让上层 agent 根据用户请求去选择合适的那个组合使用。比如“论文检索 Skill”和“论文精读 Skill”拆开,前者负责找文献、列结构化结果,后者负责对一篇 PDF 做深度分析,两者互不干扰,路由清晰,测试也容易写。
单一职责还有个附带好处:描述信息可以写得很精准,路由命中率自然就高。不信你可以做个对比,一个描述写“用于翻译、润色、摘要、邮件、周报……”,另一个描述写“仅当用户要求将学术论文翻译成中文时使用”,后者被正确调用的概率会明显高出一大截。
2.2 你写的是使用说明书,不是任务书
很多人写 Skill 指令的时候,语气还是“帮我做点事”的命令式。比如:“整理用户的输入内容,生成一份周报。”这种写法的问题在于,它只告诉模型要完成什么,没告诉模型怎么完成。模型拿到这种指令后,只能靠自己的经验猜测,最后的结果自然跟你的预期对不上。
更靠谱的写法是“使用说明书式”的:把执行过程拆成一个个具体、可验证的步骤,每一步都给出明确的输入和产出。比如周报 Skill 可以这样写:
- 接收用户提供的本周工作内容,如果没有提供,请先询问用户。
- 将内容按“开发、测试、文档、沟通、其他”五个类别分类。
- 每个类别输出一条要点,格式为“类别:具体事项”,如果类别下没有事项则省略。
- 最后输出一个 Markdown 表格,表头为“类别 | 事项 | 备注”,不要添加额外说明。
你看,这样写完之后,模型几乎没有自由发挥的空间了,每一步该做什么、做完输出什么格式,全都规定好了。你可以把这个看成是区分“普通 Prompt 作者”和“Skill 设计者”的分水岭——前者给模型派活,后者给模型铺路。
2.3 提前把异常分支写好,别让模型临场发挥
写 Skill 的时候,很多人只写了“正常流程”,完全没考虑异常情况。结果模型遇到不完整输入、找不到信息、权限不足、结果为空这些情况时,就开始自己编造策略。有的模型会假装任务完成,输出一个看起来很像回事但内容全是编的结果;有的模型会直接卡住,反复重复“无法执行”;还有的模型会跳出 Skill 的约束,开始跟用户闲聊。
应对办法是在指令里明确写好“如果……那么……”的兜底分支:
- 如果输入为空,先向用户询问必要信息,而不是猜测。
- 如果搜索结果不足,明确告知“未找到足够结果”,并给出建议关键词。
- 如果脚本执行失败,读取出错信息并尝试修复后再重试,最多重试两次。
- 如果输出格式需要特定字段但字段不存在,用“暂无信息”填充,而不是编造内容。
这些分支在正常流程时看似冗余,但在真实使用中特别管用。它相当于给模型上了一道保险,让它在遇到边界情况时依然有路可走。很多Skill 之所以“时灵时不灵”,往往就是因为这些兜底逻辑没有写全。
3. 从零搭一套标准 Skill:结构、格式与关键字段
3.1 目录结构:SKILL.md 是核心,但别只放一个文件
一个规范的 Skill 目录,我一般建议至少包含三块内容:
my_skill/ ├── SKILL.md # 核心指令文件,模型优先读取的部分 ├── scripts/ # 可执行脚本,用来做确定性计算 │ └── helper.py └── references/ # 参考材料、模板、示例 └── template.mdSKILL.md 是门面,也是模型第一优先读取的文件。它里面写的是“怎么执行任务”的完整指令。scripts 目录放需要确定性计算的逻辑,比如文本解析、数据转换、接口调用,这些事交给模型做容易出错,但交给脚本做就是一行命令的事。references 目录放模板和示例,用来约束输出风格和格式。
很多人写 Skill 只放一个 SKILL.md,其他全靠模型自己发挥。短任务还好,长任务或者需要精确计算的任务就很容易出问题。比如让模型自己算字符数、做日期计算、格式化 JSON,看起来很简单,实际执行时经常出错。把这些逻辑抽到脚本里,是提升 Skill 稳定性的关键一步。
3.2 名称和描述:决定模型“看不看得见你”
Skill 的 name 和 description 是路由系统判断“这个 Skill 该不该被调用”的依据。如果用一句话概括,就是:名称要短,描述要准。
名称方面,我建议用动词开头,比如fetch_papers、generate_chart、weekly_report,这样模型一眼就能看出这个 Skill 是干什么的。避免用太抽象的单词,比如tool、helper、misc,这类名称对路由没有帮助。
描述方面,要写成裁判能直接下判断的句子,包含触发条件、输入要求、输出说明。我见过一个写得不错的描述:
description: 当用户要求检索学术论文、查询文献资料或获取引用信息时使用。输入为研究主题或关键词,输出为结构化论文列表,包含标题、作者、年份、摘要和原文链接。这种描述的好处是,路由模型不需要额外推理,只要看到用户意图和描述匹配,就能直接触发。相比之下,如果描述写成“用于学术相关的各种操作”,那模型很可能在用户问“如何写论文”时误触发,因为“学术相关”的范围太宽泛了。
3.3 指令正文写法:Step by Step,并且每一步都可验证
我们来看一个完整但精简的 SKILL.md 示例,假设我们要做一个“周报生成 Skill”:
--- name: weekly_report description: 当用户要求生成周报、整理本周工作内容时使用。输入为本周工作描述,输出为 Markdown 表格格式的周报。 --- # 周报生成 Skill ## 执行步骤 1. 接收用户提供的本周工作内容。如果用户没有提供,请先询问用户本周的主要工作内容,不要猜测。 2. 将工作内容按“开发、测试、文档、沟通、其他”五个类别进行分类。 3. 对每一个类别,将相关事项整理为一条简洁的描述,不超过 50 字。 4. 输出一个 Markdown 表格,表头为“类别 | 事项 | 备注”。如果没有某一类别的事项,不输出该行。 ## 输入格式 用户输入:一段关于本周工作的自然语言描述,例如“这周我在做登录模块的重构,修复了三个 bug,还写了一份接口文档”。 ## 输出示例 | 类别 | 事项 | 备注 | | --- | --- | --- | | 开发 | 完成登录模块重构 | 无 | | 测试 | 修复三个登录相关 bug | 无 | | 文档 | 编写接口文档 | 无 |注意看几个细节:第一,frontmatter 里的 name 和 description 是给路由用的,要单独写清楚;第二,指令正文用“1. 2. 3.”的步骤列出来,模型执行时天然会按顺序走;第三,我给了输入格式和输出示例,这是最容易被忽略但最有用的部分——模型看到示例比看到抽象规则要理解得快得多;第四,我在每一步里都写了“如果……就……”的兜底逻辑,防止模型瞎猜。
这种写法放到不同 Skill 里都可以直接套用:先接收输入,再定义处理规则,然后规定输出格式,最后补异常分支。
3.4 脚本和参考文件怎么放,才不会被模型“带偏”
先说脚本。在 Skill 里放脚本,核心目的是把模型不擅长的确定性计算抽出去。比如解析 PDF、调用搜索 API、做数据清洗等,这些事用 Python 写脚本,效率和准确率都远高于让模型手写代码再执行。脚本写好后,指令里直接写“运行 scripts/fetch_papers.py --keyword 'xxx'”,模型只需要知道怎么调用,不需要理解脚本内部逻辑。
需要注意几点。第一,脚本要处理异常情况,比如网络超时、API 返回错误,脚本内部要有 try-except 和明确的错误输出,不然模型看到一堆 traceback 就懵了。第二,脚本不要硬编码任何密钥。API key 这类敏感信息一律通过环境变量注入,Skill 文件本身要能公开分发。第三,如果脚本需要安装依赖,记得在目录里放一个 requirements.txt,并且在 SKILL.md 里写清楚安装命令。
参考文献和模板要克制。我见过有人往 Skill 里塞几十个参考文档,看起来很全,但模型在有限的上下文窗口里根本读不完这么多内容,反而拖长了推理时间,还稀释了核心指令的注意力。更合理的做法是,只保留真正影响输出质量的材料,比如一个输出模板、一个示例文件、一张对照表,控制在 2000 字以内就够了。
4. 三个真实场景的 Skill 拆解
4.1 论文检索 Skill:脚本负责“确定性”,模型负责“意图消化”
论文检索是很多人都会用到的场景,我们拿它来拆解一下一个偏工具型的 Skill 应该怎么设计。
首先定义边界:输入是一个研究主题(比如“大语言模型在医疗领域的应用”),输出是五条相关论文的结构化列表。如果直接让模型去“搜索”,它很可能会给你编造出五篇看起来非常真实、但实际上根本不存在的论文——这是大模型最容易犯的错误之一。所以这里的关键决策是:搜索动作必须交给外部 API 处理,模型只负责理解用户意图和整理结果。
架构可以这样设计:
paper_search/ ├── SKILL.md # 指令:先询问关键词,再调用脚本,最后整理输出 ├── scripts/ │ └── search.py # 调用学术搜索引擎 API,返回 JSON 格式结果 └── references/ └── output_template.md # 论文列表的输出模板SKILL.md 里的指令大致是这种流程:
- 从用户输入中提取核心研究主题,如果有多个主题,选择最主要的那个。
- 构造搜索关键词,格式为“主题 + 综述/最新进展”,保留原始主题词。
- 运行
python scripts/search.py --query "关键词" --limit 5。- 检查脚本输出,如果结果为空,尝试用更宽泛的关键词重新搜索。
- 将返回的 JSON 结果按模板整理成 Markdown 列表,务必包含论文标题、作者、年份、来源和摘要。
- 如果脚本执行失败,直接告诉用户“搜索功能暂不可用”,不要尝试让模型自行编造论文列表。
这样设计的好处很明显:结果真不真实由 API 决定,和模型无关;模型只做翻译工作和格式整理,出错空间大大缩小。论文检索最大的坑是“编造引用”,而脚本加外部 API 的组合从机制上杜绝了这个问题。
4.2 绘图 Skill:让脚本兜底坐标计算,别让模型硬抠像素
Agent 画图也是一个很典型的场景。很多人的第一版方案是让模型直接输出 SVG 代码,然后前端渲染。听起来很直接,但实际跑起来你会发现一个问题:模型在计算布局、坐标、对齐这些需要精确数字的事情上非常不靠谱。你让它画三个并排的矩形,它可能给你输出两个在左上角、一个孤零零甩在右下角。
我在做绘图类 Skill 时,采取的策略是“模型描述意图,脚本确定细节”。具体来说:
- 模型负责解析用户的绘图需求,拆解成图形元素列表(矩形、圆形、文字、连线等),并粗略描述相对位置(左边、右边、上方、居中)。
- 模型把这些元素输出为 JSON。
- 一个 layout.py 脚本读取 JSON,根据画布宽度自动计算所有元素的精确坐标和对齐关系。
- 脚本输出最终的 SVG 文件。
这样做的好处是,模型不需要过于精确,只需要给出“大致怎么布局”的高层指令,剩下的数学计算全部交给脚本。这个 Skill 的稳定性会明显好于直接让模型生成 SVG 的版本,因为坐标计算变成了确定性逻辑,而不是概率性输出。
我给这个 Skill 的 SKILL.md 写的关键指令片段是这样:
- 分析用户对图形的描述,提取图形元素(矩形、圆形、文本、箭头),并标注每个元素的“逻辑位置”,例如“左上角”“底部居中”“与第一个矩形右侧对齐”。
- 将元素列表以 JSON 格式写入临时文件 /tmp/layout_input.json。
- 运行
python scripts/layout.py --input /tmp/layout_input.json --output /tmp/result.svg --width 800 --height 600。- 如果脚本运行成功,直接把 SVG 文件路径反馈给用户;如果失败,读取错误信息,修正后重试一次。
注意这里的关键技巧:把“确定性计算”外包给脚本。凡是涉及数字、格式、坐标、日期、统计的内容,都应该走脚本,而不是让模型自己算。模型做得好的部分是意图理解、内容组织和表达润色,这部分就留给模型。
4.3 语言学习 Skill:状态管理和纠错机制是核心
语言学习类 Skill 比前两个要复杂一些,因为它是一个交互式场景,模型需要和用户来回对话,还要跟踪对话状态,比如用户当前的等级、已学的词汇、答错的题目。
这类 Skill 的难点在于:模型很容易把对话变成“无脑夸夸模式”,无论用户说什么都回一句“Great!”。这种体验对语言学习没有任何帮助,用户根本不知道自己的问题出在哪。所以设计这个 Skill 时,我特别强调了“纠错机制”。
SKILL.md 里的核心设计分四步:
- 破冰阶段:了解用户的母语、目标语言、学习水平(初级/中级/高级),然后设定一个语言等级标签。
- 对话阶段:每次只生成一个适合该等级的对话场景(比如“在餐厅点餐”),用户用目标语言回复。
- 纠错阶段:用户每回复一条消息,模型都要做三件事:
- 指出语法错误和用词错误,给出正确表达;
- 对表达的地道程度打分(1-5 分);
- 如果用户连续答对 5 次,自动上升一个难度等级。
- 收尾阶段:如果用户说“结束练习”,输出本次练习的错题回顾列表。
这里的核心设计是“纠错三件事”,它强制模型在每次对话后都要给出结构化反馈,而不是简单地说“很好”。为了让模型能跟踪状态,我在指令里要求它在每次回复时顺便输出一个状态标签,比如“当前等级: B1,连续答对: 3,待复习词汇: ['awkward', 'refund']”,这样即使上下文很长,模型也能基于状态标签继续做判断。
这个 Skill 的难点不再是“写提示词”,而是“设计交互协议”。你需要在指令里定义清楚用户级别怎么变、什么时候升级、怎么记录错题,这些本质上都是在写一套小型的对话状态机,状态定义的越清晰,模型的对话就越稳定。
5. 测试、调试与迭代:好 Skill 都是改出来的
5.1 给 Skill 建一个回归测试集
Skill 和代码一样,需要测试。我习惯在写完一个 Skill 后,立刻准备一组固定测试用例,每个用例包含“输入”和“期望输出特征”。比如:
| 用例 | 输入 | 期望输出特征 |
|---|---|---|
| 周报正常输入 | “这周修复了登录 bug,写了接口文档” | 输出为 2 行表格,包含“开发”和“文档”两类 |
| 周报空输入 | (无输入) | 输出为询问用户周工作内容的提示 |
| 绘图正常输入 | “画一个红色圆在画布中央,下面写标题” | 输出为 SVG 文件路径,且文件内包含 ellipse 和 text 元素 |
| 绘图异常输入 | “画一个很复杂的不规则多边形” | 输出为脚本错误提示或简化图形,不能无限卡住 |
我在改 Skill 时,会拿这组用例反复跑。每改一次指令,就跑一遍所有用例,看有没有引入新的回归问题。这个过程看起来笨重,但它是保证 Skill 稳定性的最有效手段。没有测试集,你根本不知道“这次改好了还是改坏了”,只能凭感觉,那样迭代效率太低了。
5.2 四个报警信号:什么时候说明 Skill 快崩了
我总结了 Skill 失效的四个典型信号,一旦发现,就要立刻检查设计缺陷:
第一个信号是模型开始不由自主地“自由发挥”。比如 Skill 要求它调用某个脚本,它却不调,直接用自己的话说一个结果。这说明指令没有给出足够的限制,模型觉得“靠猜也能完成任务”,这时你需要把指令从“建议”改成“必须”,并明确写出不执行的后果。
第二个信号是输出格式时好时坏。有时候按模板输出,有时候又自己改格式。这通常是模板给的示例不够具体,或者没有强调“严格按照模板输出”。解决办法是在指令里写死输出结构,并补上“不要修改模板字段名”这类约束。
第三个信号是脚本报错但模型视而不见。脚本崩溃时,模型应该读取错误信息并自我修复或降级处理,但很多模型会选择忽略错误,直接把一个不完整的结果输出给用户。解决办法是在指令里写明“如果脚本失败,必须检查错误信息,尝试修复脚本后重试,最多重试两次,超过则告知用户”。
第四个信号是同一个 Skill 在不同上下文长度下表现差异巨大。有时候对话前几轮它还很稳定,随着上下文变长,它开始忘记 Skill 里的要求。这是上下文稀释问题,解决办法是把关键约束在指令里重复强调,或者在需要持久的信息(比如状态标签)里反复带上关键内容。
5.3 像写代码一样做版本迭代
我写 Skill 从来不是一个版本定稿的,而是像写代码一样迭代。第一版只追求主流程能跑通,比如周报 Skill v0.1 就只做“输入内容,输出表格”这一件事,不处理空输入,不做类别缺失判断,一切从简。跑通之后再加边界情况,变成 v0.2,然后测试异常分支,再变成 v0.3,最后加脚本优化,到 v0.4。
每次迭代只改一个东西,改完立刻拿测试集回归一遍,这样出了问题能快速定位。我给自己的规则是:不引入一个新特性,同时测试一个以上的新改动。如果上午改了描述,下午改了指令结构,第二天发现效果变差了,你根本没法定责是哪个改动的问题。
另外,建议把 SKILL.md 放在 git 仓库里管理,每个版本打一个 tag。Skill 是一个会持续演进的东西,有历史版本记录,你就能随时回退到能用的版本,而不是在“新版本好像哪里不对”的焦虑中浪费时间。
5.4 别忽略框架和 harness 对 Skill 的影响
最后特别提醒一句:Skill 不是“一次编写,处处运行”的魔法。不同 agent 框架对 Skill 的支持程度不一样,有的框架把 SKILL.md 当普通文本加载,有的框架对脚本执行有沙箱限制,有的框架会自动注入额外上下文,有的框架则完全不会。你还需要注意“harness”和“agent”的分工——harness 更像是 agent 运行的脚手架,它负责加载模型、管理上下文、执行工具调用,这些都是你能不能在 Skill 里跑脚本、能不能联网的决定性因素。
所以我的建议是:在写 Skill 时,先把框架的版本和限制摸清楚。比如当前框架是否支持工具调用?是否允许执行外部脚本?网络 API 访问有没有限制?这些能力直接影响 Skill 的设计边界。换了一个框架,Skill 的某些部分可能就需要调整。这不是 Skill 写得不好,而是现实约束就是如此。
6. 常见问题速查表
最后整理一份我在实际开发中被问得最多的 Skill 相关问题和排查思路,做成表格方便大家速查。
| 现象 | 可能原因 | 解决办法 |
|---|---|---|
| 路由系统不触发 Skill | description 写得不够具体,模型判断不了适用场景 | 重写 description,加入明确的触发条件和输入要求,删除模糊表达 |
| 模型调用了 Skill 但没按流程走 | 指令正文缺少“必须”级别的约束,模型觉得可有可无 | 用“必须”“不要”“严格”等强约束词,补上不执行的兜底分支 |
| 输出格式不稳定 | 模板示例不足,模型没有参考对象 | 在 references 里放一个完整的输出示例,指令里强制模型对照该示例输出 |
| 脚本执行报错后模型无视错误 | 指令里没有写异常处理流程 | 补充“脚本失败时读取错误信息、修复后重试、最多两次”的指令 |
| Skill 在不同对话里表现忽好忽坏 | 上下文长度变化,指令被稀释 | 在关键步骤重复强调核心约束,或用状态标签反复带出关键信息 |
| 生成了看似正确但实际错误的内容 | 模型在没有外部工具的情况下自行发挥 | 把确定性逻辑(搜索、计算、解析)全部移入脚本,模型只做意图理解和格式整理 |
| Skill 被误用在完全无关的场景 | description 范围太宽 | 收窄 description 的适用范围,列出“不要使用的情况” |
| 密钥硬编码在脚本里 | 开发时图省事放进去了 | 立即改为环境变量注入,附使用说明,避免提交到公开仓库 |
再补一条特别重要的安全底线:Skill 里的脚本要谨慎处理用户输入,对传入给 shell 命令的参数做转义或白名单校验,不要把用户输入直接拼进命令行里。模型本身对安全的理解是有限的,Skill 作者必须替它守住这个环节,这也是 agent 安全里最容易被忽视的一块。
我个人现在的习惯是,每个 Skill 都会在 README 里额外写一小段“设计决策”,记录当初为什么这样拆分职责、为什么选择调脚本而不是让模型直接算、踩过哪些坑。这个习惯让我在几个 Skill 同时迭代时依然能保持清晰的思路,也方便别人拿到我的 Skill 后快速理解设计意图。说到底,Skill 写得好不好,短期看指令写得多细,长期看的是你有没有建立测试和迭代的机制。把这两件事做好了,你的 Agent 才能从“会说话”进化到“会干活”。