最近在好几个技术社区都看到同一个问题:为什么我给了 AI Agent 一份 3000 字的 Skill 指令,它还是经常“犯低级错误”?底下的回复五花八门,但有一条让我印象深刻——“你这不是在写 Skill,你是在写论文。”
这句话点醒了我。过去大半年,我一直在折腾各种 Agent 项目,从日志分析到 PPT 大纲生成,前前后后写了几十个 Skill。最开始我也走过纯堆指令的路子:把格式要求、语气要求、禁忌事项、输出规范全部塞进去,结果发现指令越长,模型反而越容易“失焦”。后来我慢慢摸索出一个核心原则:写 Skill 的本质是设计注意力,而不是堆叠指令。
这篇文章我想把这段时间积累的经验完整梳理一遍。不管你是刚开始接触 Agent 开发,还是已经写过不少 Skill 但总觉得效果差一口气,这篇内容都值得你花十分钟看完。
1. 为什么堆指令是最容易踩的坑
1.1 指令越长,注意力越分散
先讲一个我早先踩过的例子。当时我在给一个内部用的日志分析 Skill 加功能,需求是让模型从 Nginx 日志里找出 5xx 错误、统计 Top 10 慢接口、识别异常 IP。一开始我写得非常“周到”,把每个子任务的执行步骤、每个指标的计算公式、输出表格的每一列都写进指令里,整个 Skill 文件接近 4000 字。
实测效果出乎意料地差。模型确实能把 5xx 错误挑出来,但表格格式开始“自由发挥”;让它分析慢接口耗时变化,它会一本正经地编造出“环比上升 23%”这种原文里根本没有的数据。
后来我想明白了一个道理:当前模型处理长文本的能力是有上限的。指令越长,每个字被有效注意到的概率就越低。就像你在一个嘈杂的房间里同时喊十个人说话,听众反而谁的话都听不清。堆指令看起来是在“增加约束”,实际效果却是“稀释注意力”。
1.2 冲突性指令制造认知负担
堆指令还有一个更隐蔽的问题:指令之间可能互相冲突。比如你同时写了“分析要全面,覆盖所有维度的数据”和“输出要简洁,不超过 200 字”,这两条在模型看来就是互相矛盾的。模型为了“满足”两者,最后往往交出既不够全面、也不够简洁的四不像结果。
更典型的是“不要做某事”这类否定式指令。我与不少做 Agent 的朋友交流后发现一个共同经验:当你反复强调“不要编造数据”时,模型反而更容易在不确定的地方“编造”。因为“不要编造”这个词本身就把“编造”这个概念推到了注意力前线。这类问题在认知心理学里叫“白熊效应”——越是让你别想白熊,你脑子里越全是白熊。写 Skill 时如果不注意这一点,效果就会同样离谱。
1.3 不可维护的“指令屎山”
纯堆指令还有一个非常现实的代价:维护成本极高。我自己见过一个团队维护的半成品 Skill,文件里有 40 多个 if-else 式的规则段落,每加一个新需求就在末尾追加一节。到后面没有任何人敢动这个文件,因为“删一行都可能弄坏某个隐蔽功能”。
这类层层堆叠的文档,本质上是把“思考责任”全推给了模型,而放弃了自己作为设计者的判断力。真正靠谱的 Skill,应该像一份精美的地图,让模型一眼就看清重点在哪、路径在哪;而不是像一本 500 页的用户手册,翻到后面已经忘了前面讲什么。
2. 设计注意力的底层逻辑
2.1 从“命令式”转向“引导式”思维
如果说堆指令是在“命令”模型做事,那设计注意力就是“引导”模型关注正确的事情。这两者的差别,用一个比方来说:堆指令像是给一个新手司机写了一份“开车注意事项清单”,从“起步要打左转向灯”到“高速上不要猛打方向”全都写上,司机根本记不住;设计注意力则是给他一张清晰的路牌,告诉他“前方 500 米右转进匝道”“下个出口是服务区”,只引导他关注此时此刻最重要的事。
落到 Skill 撰写上,就是不要试图告诉模型“每一步都要怎么做”,而是通过结构调整,让模型自然地把注意力放到“这一步最关键的输入和输出”上。
2.2 用情境信息收窄焦点
模型对 Skill 的理解,很大程度上由它“看到的第一屏内容”决定。所以我现在的每个 Skill 文件都强制要求写上清晰的元信息头,包括:触发条件(什么时候该用)、输入格式(需要什么数据)、输出风格(最终交付形式)。
不要小看这一段像“剧情简介”一样的内容。它相当于在模型工作之前先给它划定了一个工作区间。比如我写过的一个 PPT 大纲 Skill,元信息里写着“本 Skill 适用于输入一段口语化录音转写稿,输出 8-12 页的结构化大纲,每页包含标题、要点、讲解备注三部分”。这短短一句话,就把模型的注意力从“要不要顺便排版、要不要配图建议”这些发散方向拉了回来,集中在“从口语稿提炼结构”这一件核心任务上。
2.3 工作流拆分让注意力随时有锚点
人工作的时候,最怕的是“一堆活儿”一起压过来,没有先后顺序。模型也是一样。你让它一口气干五件事,它就容易“平均用力”,每件事都干得浮于表面。
我常用的解法是:把 Skill 的执行流程拆成 3-5 个显式阶段,每个阶段只交代一个目标。还是拿日志分析来说,我不再写“先分析 A,同时注意 B,最后别忘了 C”,而是拆成:
阶段一:解析日志,识别所有 5xx 和 4xx 状态码。 阶段二:按接口维度聚合耗时,计算平均响应时间和 P95 响应时间。 阶段三:结合时间轴,找出异常波动,给出排查方向。
每个阶段独立成段,模型在一个时间点只需要聚焦一个目标,输出的准确率明显上升,这个改动我实测过很多次,效果特别明显。
3. 动手写 Skill:一步一步实操
3.1 定义触发条件和元信息
一个 Skill 必须让人(或让 Agent 路由系统)一眼就能判断“该不该用这个 Skill”。所以文件开头的那一段元信息,我建议用标准化的结构来写。
我用 YAML frontmatter 的格式,大概是这样的:
--- name: log-anomaly-analysis description: 适用于 Nginx/Apache 访问日志的分析场景。 trigger: 当用户提供一段原始日志或日志文件路径,并期望了解错误状态、接口性能或异常流量时使用。 model_compatibility: claude, codex, deepseek version: 1.2.0 ---各位注意 description 和 trigger 这两段,一定要写得“可被程序化判断”。Agent 系统的路由逻辑通常是靠关键词、语义相似度来匹配 Skill 的,如果你的描述太过文艺(比如“深夜亮起的屏幕前,总有代码在叹息”),模型很可能会跳过这个 Skill,转而用通用能力死磕。描述不是写给人看的文学,而是写给路由器和模型的“路标”。
3.2 用 XML 标签做视觉锚点
把元信息写完之后,正文部分的第一个原则是:不要写长段落,要写短小的、带明确标签的模块。我发现模型对 XML 标签天然敏感。就像人在读文章时会自动注意加粗的标题一样,模型对<context>、<task>、<output_format>这类标签的注意力系数明显比普通文本高。
一个我实际用的日志分析 Skill 核心段长这样:
<context> 用户会提供一段原始访问日志,字段包含:IP、时间戳、请求方法、请求路径、状态码、响应时间、User-Agent。 </context> <task> 识别异常流量和慢请求,给出可操作的排查建议。 </task> <output_format> 使用 Markdown 表格输出。表格必须包含四列:时间范围、异常类型、影响接口、推荐处置方案。 </output_format>编写时请注意:标签之间不要放冗余解释。写“经过分析我们发现,在一般情况下……”这类句子纯属浪费 token。每个标签内部,只放模型决策所必需的信息。
3.3 用 checklist 替代长篇大论
在需要“检查”或“校验”的环节,长段描述远不如 checklist 高效。原因是 checklist 天然带有“逐项核对”的暗示,模型在按项执行时注意力会更集中。
举一个我在“PPT 大纲 Skill”中的校验清单:
<checklist> - 每页标题是否为一句观点明确的短句,而非单纯的“产品介绍”。 - 每页要点是否不超过 3 个,且彼此不重复。 - 讲解备注是否覆盖了“为什么放这页、该页要起什么作用”。 - 全篇是否有至少 1 页涉及风险或待决事项。 </checklist>像这种 4 条以内的短清单,模型执行起来几乎不会跑偏。如果清单超过 7 条,建议拆成多个阶段的子清单,不然模型又会陷入“平均分配注意力”的陷阱。
3.4 用 few-shot 示例代替抽象规则
“写一句抽象规则”和“给一个具体示例”,对模型注意力的引导效果差别极大。抽象规则需要模型自己“翻译”成具体动作,中间就可能跑偏;而具体示例相当于直接给模型划了重点:照着这个样式来。
举一个例子。我在写“会议纪要 Skill”时,最初有一条规则叫“提炼行动项时要注意负责人和截止时间”。模型常常漏项。后来我改成:
参考格式: | 行动项 | 负责人 | 截止时间 | 依赖资源 | |--------|--------|----------|----------| | 完成接口联调 | 张三 | 周五 18:00 | 测试环境 |从此以后,行动项基本没有漏过负责人和截止时间。如果你只能改一个地方来提升 Skill 质量,优先补 few-shot 示例,而不是补规则描述。
4. 如何做减法与验证
4.1 写完 Skill 后先删除 30% 内容
我的一个朋友有个很“狠”的习惯:写完 Skill 初版之后,强制要求删掉 30% 的内容再交付。最初的初衷是嫌文件太长,后来发现这招意外地好用——因为当你被迫删内容时,你会开始思考“哪句话是真的不可替代”。
推荐一个实操顺序:
- 先把 Skill 文件里所有“背景描述”“意义说明”“通用知识”类句子标黄。
- 然后把“类似于”“相当于”“之所以这样是因为”这类解释性语句标黄。
- 接着把与主流程无关的边界案例描述标黄。
- 最后把标黄部分整体删除,再跑一轮测试对比效果。
大多数情况下,删完之后效果不降反升。
4.2 用测试日志反推注意力盲区
Skill 写得好不好,不能靠“感觉”,要靠跑测试。我建议每个 Skill 都配一个简单的手动测试集:3 个标准输入、2 个异常输入、1 个极端输入。每轮修改后都跑一遍,把输出差异记录下来。
如果发现模型在某个环节反复出错,不要急着追加指令去“堵漏”,而是回去检查:是不是这个环节的信息在 Skill 里出现的位置太靠后、被前面的长文本挤占掉了注意力?还是说这个环节缺少一个明确的输出示例?
我曾在“代码审查 Skill”里发现:模型总是忽略“安全漏洞”检查环节。排查了很久,最后发现原因是“安全漏洞”这个词被塞在了一个很长的段落中间,前后全是并发问题、性能问题等其他内容,模型根本没有注意到它。后来我把安全审查单独拆成一个阶段,并在<task>标签里点名,问题立刻消失。
4.3 版本管理与 A/B 测试
像管理代码一样管理你的 Skill 文件。我现在的做法是,每个 Skill 都放进一个 Git 仓库,每次修改提交前必须写清楚变更原因(比如“把阶段数量和输出格式拆成独立段落,减少指令稀释”)。这样三个月后回头看,你能清楚知道哪次改动对效果产生了正面影响。
有条件的话,可以给 Skill 做简单的 A/B 测试:同一组输入,分别跑 v1 和 v2,把输出结果按“完整度、格式符合度、幻觉率、用户体验”四个维度打分。不用打分很精细,1-5 分即可,但要坚持记录。改版方向对不对,跑三轮测试就能看出来。
5. 常见问题与排查技巧实录
5.1 写 Skill 时容易踩的坑自查表
我把自己这一年来遇到的典型问题整理成了下表,读者可以对照自查:
| 现象 | 根本原因 | 解决动作 |
|---|---|---|
| 模型频繁忽略某条重要要求 | 该要求被埋藏在长段落中间,注意力被稀释 | 把它单独拆成一个阶段或标签 |
| 输出格式每次都不一样 | 只写了“请按表格输出”,没有给表格示例 | 给一个具体的 Markdown 表格示例 |
| 模型会编造超出输入范围的数据 | 上下文里缺少“只能基于给定数据回答”的锚点 | 在<context>标签首句明示“禁止外推” |
| “不要做 X”反而导致出现了 X | 否定式指令把 X 推到了注意力中心 | 改成“只做 A、B、C”的肯定式指令 |
| Skill 在其他模型上失效 | 某个模型对特定格式不够敏感 | 用兼容性最强的纯文本格式描述核心流程 |
| 指令一多模型速度明显变慢 | 输入 token 过长,每次调用都消耗大量上下文 | 压缩指令,砍掉背景信息和通用知识 |
5.2 一个“负优化”案例的完整复盘
有一次我把一个“周报生成 Skill”从 v1 改到 v2,自信满满地加了非常多的“输出风格要求”,包括“语言要专业但不冷冰冰”“不要用感叹号”“每段不超过三行”“多用动词开头”等等,总计加了 20 多条。结果 v2 的实测输出反而比 v1 效果差,不仅语言变得生硬,还经常出现“逻辑断裂”——每条输出都像是被格式化机器切成的等长碎片。
复盘后发现,问题恰恰出在我过度堆加了输出风格指令。因为每一条风格规则都消耗一部分注意力,规则总数一多,模型在生成时就要反复“对照规则”,写作的连贯性和自然度被严重破坏。后来我把 20 多条风格规则压缩成两条核心导向:“像资深同事在写文档,不要像机器在填空”和“给结论,再给理由,不要给套话”,v3 的效果立刻恢复。
5.3 如何判断该“加内容”还是“减内容”
新手最容易困惑的问题,是不知道当前 Skill 该加东西还是该减东西。我个人用的是“三连问”判断法:
第一问:模型当前最常犯的错误,是“遗漏了某个关键点”,还是“某个关键点理解偏了”?如果是遗漏,优先考虑增加结构(比如加标签、加阶段、加示例);如果是理解偏了,优先考虑删减冗余描述,把核心定义说得更直接。
第二问:Skill 执行一次需要消耗多少 token?如果动辄上万,大概率是过度设计了。真正好用的 Skill,通常控制在 1000-2000 token 以内,极端复杂任务也不要超过 4000。
第三问:如果让一个完全不了解上下文的新同事拿着这份 Skill 来干活,他能只看一遍就上手吗?如果他需要反复来回读,那说明结构清晰度不够,应该继续拆分,而不是继续解释。
5.4 不同模型对 Skill 的“口味”差异
我在这几个主流模型上都跑过同一套 Skill,讲一下真实体感差异:
Claude 系列对 XML 标签和 Markdown 结构的响应最稳定,给它清晰的标签嵌套,它基本上会严格照做;Codex 系列在“工具调用”和“多文件操作”场景下表现最好,但更容易忽略软性文字描述,所以核心要求必须落到极具操作性的步骤上;DeepSeek 系列对中文语义理解深,但会在长语音记录类任务里倾向于“过度总结”,需要更明确的保留粒度,比如“保留原话中的时间、金额、人名”。
这并不意味着要为每个模型维护一套独立的 Skill 文件,而是在设计时留意“通用结构优先”。先把逻辑框架写稳,再在最外层用一个“模型适配说明”标签,标注不同模型下需要特别注意的执行细节。这样既省维护成本,又不会出现“换个模型就彻底失效”的尴尬。
一些工具链与协作建议
6.1 本地管理 Skill 的目录结构
Skill 文件多了之后,最怕的就是找不着、改不动。我现在使用的目录结构很简单,但非常好用:
skills/ ├── log-anomaly-analysis/ │ ├── SKILL.md │ ├── examples/ │ │ ├── standard-input.txt │ │ ├── edge-input.txt │ │ └── sample-output.md │ ├── tests/ │ │ ├── run-test.sh │ │ └── expected-output.json │ └── CHANGELOG.md ├── ppt-outline-generator/ │ ├── SKILL.md │ ├── examples/ │ └── CHANGELOG.md └── meeting-minutes/ ├── SKILL.md └── CHANGELOG.md每个 Skill 独立一个目录,SKILL.md 是主文件,examples 放输入输出样例,tests 放自动化测试脚本,CHANGELOG 记录每次改版日志。这套结构在个人项目管理、小团队协作里都非常顺手,至少省掉了我一半“找文件”的时间。
6.2 用版本仓库追踪 Skill 的“进化史”
把 skills 目录放进 Git 之后,我养成了一个习惯:每次改完 Skill,提交信息里必须写清楚“我观察到了什么现象,我做了哪个改动,预期解决什么问题”。这看起来是小事,但三个月后回看历史记录时,你会非常感激当时的自己。没有这些记录,你很容易陷入“反复横跳”——今天删了一段,明天又加回来,完全凭感觉。
我还有一个个人偏好:每个月固定抽时间跑一遍所有 Skill 的测试集,把输出结果的变化记下来。模型服务商经常更新底层模型,同样的 Skill 在不同时间点跑出来的结果可能有肉眼可见的差异。日常维护不只是改 Skill 本身,也要关注“环境和版本变化”对 Skill 效果的影响。
6.3 从单点 Skill 走向完整 Agent 能力
写好单个 Skill 只是第一步。真正让 Agent 能力升级的,是多个 Skill 之间的协作方式。比如我的日志分析流程,实际上是三个 Skill 串起来的:第一个 Skill 负责解析日志并提取异常事件,第二个 Skill 负责把异常事件放到时间轴上看趋势,第三个 Skill 负责把结论整理成给管理层的摘要报告。
每个 Skill 都只负责一个窄问题,各自都能保持“注意力高度集中”。串起来之后,整体的分析质量大大超过一个大而全的 Skill。我的体会是:宁可维护三个 800 字的小 Skill,也不要维护一个 3000 字的大 Skill。这一点对任何想深入 Agent 开发的朋友都非常有参考价值。
最后分享一点个人体会
写了这么多 Skill,我最深的一条感受是:好的 Skill 设计者,更像是一个“注意力设计师”,而不是“指令写手”。你要做的,是理解模型如何分配注意力,然后用结构、示例和标签去引导它把注意力放到该放的地方。这个思维方式,比记忆任何具体的写作模板都更重要。
如果你现在手头正有一个效果不太满意的 Skill,我建议先从“删掉 30% 内容”开始试。删完之后跑一轮测试,把输出对比一下,你会发现“少即是多”在 Skill 撰写这件事上,绝大多数时候是成立的。