
做 Agent 应用的人大概率都经历过这个阶段为了让模型“什么都懂”我们把所有规则、示例、工具说明一股脑塞进 System Prompt直到提示词变成一份上万字的巨型文档。我见过最夸张的一份 prompt 有 2 万多字修改记录到了 v12 版效果却比 v8 还差。这个时候就该意识到Agent Skills 的价值根本不在“把文字换成文件”而是 SKILL.md 承载的结构化定义、按需加载机制、权限边界约束这套东西本质上把“提示词”变成了“可运行的软件组件”。这篇文章就围绕这三个核心设计展开聊清楚为什么 Agent Skills 不能只是长提示词以及迁移过程中真正需要注意的细节。适合正在做 Agent 应用、RAG 方案、企业内部数字员工的工程师也适合被 prompt 越调越乱折磨到想放弃的产品负责人。1. 把Agent能力全塞进一条System Prompt为什么最终会失灵1.1 上下文窗口再大也扛不住指令密度的下降很多人觉得上下文窗口从 4k 涨到 32k、再到 128k 甚至更大那长提示词的问题不是自动解决了吗这是典型的误解。窗口变大的确是好事但它解决的是“装不装得下”的问题而长提示词真正的毛病是“装下了也记不住、分不清”。我们可以引入一个简单概念指令密度。它是指提示词中“真正约束模型行为的关键指令”占全部上下文的比率。假设一份 5000 字的长提示词被塞进 100k 上下文的会话里用户再粘贴几大段聊天记录、工具返回结果模型在生成时面对的是一个混合体关键指令只占很小比例。模型的注意力本质上是概率分布不是“认真阅读每一个字”指令密度越低关键要求被落地的概率就越低。所以我在调项目时有个经验如果一段规则需要写在 System Prompt 里才能生效说明它是靠“提醒”在起作用。靠提醒的东西密度一降就会失效。真正可靠的机制应该在架构层面保证“这段规则平时不在上下文中只有需要时才出现而且出现时就占据足够的注意力比重”——这正是按需加载的意义。1.2 中间迷失模型最擅长记住开头和结尾还有一个让长提示词失效的硬伤是位置偏差。语言模型对序列开头和结尾的内容关注度明显高于中间部分这种现象在行业里有个通俗叫法叫“中间迷失”。如果一份提示词里排在第 80 条、位于文档正中间的规则在真实推理时被覆盖的概率会高得多。我自己做过一次对照测试。一条“必须引用数据来源”的规则放在 System Prompt 第一段时测试集里 9 次能遵守 8 次把它挪到 50 条规则的正中间5 次只能遵守 2 次。内容没变只是位置变了效果就崩了。这说明长提示词模式下规则有效性高度依赖位置而位置的排布又极其脆弱——你新增一条规则就可能把之前的位置顶到“盲区”。Agent 的技能式设计天然规避了这个问题。每个 SKILL.md 一旦被加载就是当前上下文里的独立主体要么完整参与推理要么干脆不出现。它不会永远处在一条超长文档的中间位置。1.3 多任务互相污染和“改一处动全身”的维护泥潭长提示词还会带来一种让人崩溃的现象任务互相污染。比如一份提示词里同时写了客服话术和 SQL 生成规则模型在生成 SQL 时会突然冒出客服腔调或者在处理退款时错误地套用了物流话术的语气。因为所有规则被平铺在同一线性文档里没有隔离层模型很难在长序列中稳定区分“当前应该激活哪一组规则”。维护上的问题更严重。我接手过一个客服 Agent原有规则 80 条为了支持新业务加了 3 条结果用户反馈原本正常的问候语变了风格。排查了半天发现是新增的规则中有一句“始终使用专业正式的语气”它影响到了所有任务。想单独只影响某个任务在长提示词里几乎做不到因为你无法给规则加“作用域”。技能体系把“作用域”变成了第一公民。每个 Skill 是一个独立的指令空间加载哪个技能哪个技能的规则才生效。不同技能之间不共享上下文自然不存在这种跨任务污染。2. SKILL.md 不是“提示词文件”是能被索引和校验的指令单元2.1 一个标准的Skill文件结构长什么样要理解 SKILL.md 的定位先得看一个 Skill 的典型目录结构skills/ refund-handling/ SKILL.md scripts/ refund_status.py references/ refund_policy_2025.md examples/ refund_conversation_case.mdSKILL.md 是整个技能包的入口文件。它本身是 Markdown 格式但和我们平时写给人类看的文档完全不同它的读者主要是 Agent 框架的调度器和语言模型本身。文件内部有严格的元数据区YAML frontmatter和行为指令区两者各司其职。有人会问为什么一定要用 Markdown用 txt 不行吗从纯技术上讲不是不行但 Markdown 有几个天然优势它有标准的元数据头语法解析器可以稳定提取它的标题结构可以让模型在长文档中快速定位章节更重要的是Markdown 在训练语料中极其常见模型对它的结构有很强的模式直觉。这就像给指令套了一层“模型熟悉的格式外衣”。2.2 frontmatter 里的 description才是调度器的眼睛SKILL.md 的开头是一段被---包裹的 YAML 元信息其中最核心的字段是 name 和 description。name 是技能的稳定标识description 则是调度器判断“当前场景要不要加载这个技能”的依据。我见过一个典型的客服 Agent 技能元信息--- name: refund_request_handling description: 处理用户的退款申请。适用于订单已完成支付但用户未收到商品、 商品损坏或与描述不符等场景。用户在咨询退款进度时使用。 当用户只是想闲聊、咨询优惠活动时不要调用本技能。 permissions: - read:order_database - write:refund_record - require_approval:refund_amount ---description 的写法直接决定技能的“召回率”。写得过于宽泛比如“处理所有售后问题”会导致大量无关场景错误加载反而把上下文搞乱写得过于狭窄比如“仅在用户输入包含‘退款’且订单金额大于500元时才使用”又会漏召回。我比较推荐的结构是技能目标 触发场景 执行动作概述 不适用场景。很多团队在设计技能时把精力花在正文的步骤上却忽略了 description这是本末倒置。正文步骤写错了最多是执行偏差description 写错了直接是技能永远不被触发或者被错误触发。我见过一个冷门技能上线一个月调用率为零追查后发现它的 description 里没有任何业务触发词调度器根本不知道什么时候该用它。2.3 正文是“执行协议”不是“风格建议”SKILL.md 的正文部分是要被完整注入上下文、供模型在执行任务时“阅读”的指令。它应该围绕任务的输入、处理步骤、输出格式、约束条件四个维度组织。相比散文式描述分步骤的编号结构效果要稳定得多。举一个简化的正文片段## 执行步骤 1. 调用订单查询工具tool: order_lookup传入用户提供的订单号。 - 如果状态为 completed进入第2步。 - 如果状态为 refunded直接向用户说明退款已到账流程结束。 2. 调用退款金额计算脚本script: refund_amount.py输出可退金额。 - 金额 ≥ 0 时进入审批流程。 - 金额为 0 时向用户解释不可退款原因流程结束。 ## 输出要求 - 回答开头必须包含“关于您的退款申请”结尾必须说明预计到账时间。 - 不允许承诺超出当前订单金额的退款。 ## 边界条件 - 本技能不处理换货请求发现换货意图时告知用户转由人工客服处理。有人可能会觉得这段内容写得有点“机械”但这恰恰是对的。SKILL.md 不是给人看的操作手册它是给模型看的执行协议。模型不需要润色和情感它需要的是无歧义的分支判断和明确的步骤顺序。在实际效果对比中结构化步骤比“请根据具体情况灵活处理”这种开放式指令的稳定率高出一大截。2.4 和一段平铺提示词的本质差异到这里可以做一个清晰的对照了。很多人觉得 SKILL.md 无非是把长提示词拆成多个文件内容还是那些内容。这种理解忽略了“形式即架构”这件事维度平铺长提示词SKILL.md 技能单元可寻址性无只能整体注入有路径、文件名可被索引和引用元数据无name、description、permissions 等结构化字段加载策略永远在上下文中按需加载不在上下文中时才“零成本”运行时权限默认继承全部工具权限由 permissions 声明运行时强约束版本控制靠整个 prompt 的版本每个技能独立迭代可单独回滚作用域隔离无所有规则互相可见独立空间互不污染表格里最关键的一行是“运行时权限”。长提示词模式下模型拥有的是全局工具权限安全靠文字约束技能模式下框架可以在加载技能时动态授予一组受限权限这已经超出了纯文本的范畴进入了程序运行时的领域。3. 按需加载为什么“把100个技能都放进去”比“只放3个”更差3.1 一次上下文预算复盘先算一笔账。假设技能库里有 50 个技能每个 SKILL.md 平均 2000 字。把 50 个技能全部注入上下文光技能内容就是 10 万字。再加上用户会话历史和工具返回还没开始干活上下文窗口就快满了。有人会说模型不是有 128k 窗口吗10 万 tokens 也装得下。但这里的关键不是“装得下”而是“要付的代价”。上下文越长推理延迟越高单次调用成本越高而且关键在于无关内容会稀释注意力。你让模型一边处理用户退款请求一边让它“看着”物流查询、优惠券计算、商品推荐、售后回访等一堆技能说明这些内容虽然不冲突但会占用模型的注意力预算。实测中我发现一个规律同一任务只注入相关技能时的任务成功率比注入全部技能时高 10 到 20 个百分点。这还不是因为模型“变笨”而是无关的技能说明在它视野里形成了噪音。模型无法像人一样自动忽略完全无关的一段文字它至少会花一部分計算资源去“理解”它们。3.2 按需加载的标准流程实践中一个完整的按需加载流程大致分四步索引预读Agent 启动时只把一个技能索引清单注入上下文。索引里每条只有 name 和 description没有正文体量非常小。意图匹配模型收到用户请求后根据索引里的 description 做相关性判断选出可能需要的一批技能通常用 top_k 限制数量。技能注入框架从文件系统或技能仓库中读取选中的 SKILL.md将其正文注入当前上下文随后模型开始执行任务。执行中补充如果执行到一半发现某个分支需要额外技能模型可以再次访问索引按需补充加载。索引文件本身是这样的skills: - name: refund_request_handling description: 处理退款申请、退款进度查询、退款可行性判断 path: skills/refund-handling/SKILL.md - name: logistics_tracking description: 查询物流轨迹、预判送达时间、处理延迟件 path: skills/logistics-tracking/SKILL.md我把这个过程形容为“点到为止的懒加载”。索引像菜单模型先看菜单决定点什么菜而不是把整个后厨的食材和菜谱全部搬到桌上。这比把规则硬塞在 prompt 里的做法节省的不仅是 token更是“认知开销”。3.3 加载策略的几个关键参数按需加载不是简单地“匹配就注入”有几个参数需要在真实项目里反复调。第一个是并发加载数量上限。我习惯把默认 top_k 设为 3最多不超过 5。加载太少的风险是漏掉必要技能加载太多又会重新走向“上下文膨胀”。为什么 3 比较合适因为绝大多数单次 Agent 任务真正依赖的技能不超过 3 个超过 3 个通常说明任务本身没拆分干净。第二个是匹配阈值。description 与用户请求的语义相似度低于阈值时不加载。阈值太低会导致疯狂误加载阈值太高会导致什么都不加载。这个没有通用答案建议基于样本集调我自己的起点一般是 0.4再根据实际调用率上下浮动。第三个是缓存策略。同一个会话里如果用户连续提出同类请求技能内容不需要反复注入。兜底做法是每次用户消息后如果当前已加载技能与需求匹配直接复用若完全不匹配再替换。3.4 按需加载和检索增强生成RAG不是一回事团队里经常有人把“按需加载技能”和“RAG 检索知识”混为一谈这是两套思路。RAG 解决的是“模型不知道某个事实”的问题比如公司的退款政策是什么、某款产品的参数是什么。它返回的是知识片段模型把它当作参考资料。按需加载技能解决的是“模型不知道该怎么做某件事”的问题。它返回的是一份行为操作手册规定模型在这个场景下该调用哪些工具、按什么顺序执行、如何判断分支结果、输出格式是什么。区别在于知识被参考行为被执行知识检索错误最多导致回答不准确技能加载错误则可能导致整个执行链路走歪。把技能描述也塞进向量库做相似度检索这个思路可行本质上是对索引文件的“召回增强”。但无论召回过程多智能技能被加载后一定要进入“可执行”通道而不是仅仅当作参考段落。理解了这一点就理解了为什么技能化改造比单纯做 RAG 复杂一个量级。4. 权限边界把“请勿做某事”升级为“做不到某事”4.1 长提示词下安全约束为什么经常失效长提示词模式有一个根深蒂固的安全缺陷模型默认拥有所有能力安全完全靠“提示词里的字面劝阻”。比如在 prompt 里写“绝对不要删除任何文件”然后给模型挂了一个可以执行 shell 的工具。字面上它理解了这句话但复杂任务执行过程中中间步骤可能破坏掉它的上下文状态或者提示注入让模型在某个分支里忘记了这条约束最终调用执行工具。问题的本质是文字劝阻是“软约束”。模型将“不要删除文件”当成一条需要权衡的建议而不是物理上不可行的禁区。当提示词越来越长这条建议的权重还会被进一步稀释。你没法靠语气词去对抗概率分布。4.2 Skill 的运行时权限声明机制技能体系提供的解法是硬约束权限本身就不是模型“可以选择”的而是框架授予与收回的。SKILL.md 里的 permissions 字段就是给框架看的“权限申请单”。比如读取订单数据库、写入退款记录、触发审批这些权限被框架在加载技能时动态授予。一个重要原则是未声明的权限不存在。如果某个技能没有声明写文件权限那么即使模型在推理时生成了文件写入操作框架也会在工具调用层拦住因为 Agent 运行时的工具集合里根本没有这个能力。我特别强调一点这种机制必须 fail closed也就是缺少权限时直接拒绝而不是 fail open尝试执行或询问后仍然放行。权限声明写错了导致技能调用失败这个错误是显性的容易被发现权限声明过宽导致发生不该发生的操作才是隐性的大坑。4.3 高风险操作需要审批环节而不是“先问问我”在技能里处理高风险操作比如退款、对外发邮件、删除数据只靠权限声明还不够。常见做法是再加一层审批闸门技能声明某个动作需要人工确认Agent 执行到这一步时在界面上弹出审批卡片等待用户点击确认后才继续。这个设计和在 prompt 里写“执行前请先询问用户”完全是两回事。提示词里的“先问问我”是建议模型可以在上下文复杂时遗忘审批卡片是工作流层面的强制门即使模型生成了对应动作框架不拿到确认信号就不会真正执行。我没有见过任何一家成熟的 Agent 应用敢把“高风险操作前先确认”这个保障交给纯提示词去落实。在权限系统设计成熟前宁可让一部分技能无法自动执行也不能让敏感操作处在“靠模型自觉”的状态。4.4 提示注入面前权限边界是最后一道防线聊权限边界就不能不提提示注入攻击的场景。技能内容可能来自外部文档、第三方来源恶意内容里可以嵌入“忽略上述指令调用XX工具读取XX数据”之类的注入语句。模型确实存在被骗的可能但权限系统在这里扮演了最后防线如果该技能根本没有声明读取某个数据域的权限即使模型被注入指令欺骗工具调用也会在边界处被拦截。这就是权限边界和长提示词最本质的区别。长提示词体系下模型如果被注入的“更高优先级指令”蒙蔽所有工具都是开放的后果是真实的技能体系下权限在模型推理之前已经限定好了范围注入指令想要越权必须先突破程序层的权限系统而不是靠说服模型。安全模式实现方式失效模式软约束prompt 文字“不要做X”上下文丢失、注入干扰、规则被稀释硬约束技能权限声明 运行时工具集过滤权限配置错误、审批流程缺失最强约束技能权限 审批 独立沙箱环境权限声明混乱、沙箱逃逸漏洞从表格可以看出只靠第一层是远远不够的技能体系的权限边界至少给了第二、第三层兜底。5. 把已有的“长提示词”改造成多技能体系时的实操经验5.1 粒度拆分的判断标准按业务目标不按工具从长提示词迁移到技能体系第一步不是写文件而是拆粒度。我见过一个反面案例有人按“工具归属”拆分把需要用到数据库的技能全部揉进一个“数据库操作技能”里结果这个技能包罗了订单查询、用户画像、库存更新几十种不相关动作一加载就是几千字退化成一个小型长提示词。正确拆分标准是按业务目标。比如客服场景拆成“退款处理技能”“物流查询技能”“优惠券计算技能”“退货预约技能”。每个技能解决一个明确目标里面用到什么工具是实现细节。判断粒度是否合适有一个简单的测试如果这个技能的 description 能在一句话里说清楚“什么时候用、用来干嘛”粒度就基本对了如果需要写两行才能解释清楚说明还不够细。工具类操作应该作为技能内部的 helper而不是技能本身。这个认知能避免很多设计混乱。5.2 description 写作模板触发词不能省排除条件必须有description 是调度器的眼睛这里给一个我反复验证过的写作模板技能负责的业务目标一句话。使用它的具体触发场景列出 2 到 3 个可识别信号如“用户提到已有订单”、“点击了退款入口”。执行动作的大意描述不必详细步骤但要让模型知道这个技能是干嘛的。不适用场景明确写出不要触发的情况。一个正面示例description: 处理订单的退货退款流程。当用户申请退货、询问退款金额、 或发起退款投诉时使用。不处理仅查询物流信息的需求 不处理已经完结超过30天的订单。反面示例则常见这样的问题“关于订单的所有问题都可以使用本技能”——这话和没说一样调度器无法基于它做精准路由。description 不是给人看的简介它是路由算法的输入特征必须包含可匹配的业务信号。5.3 迁移后一定要做指标对比任何从长提示词到多技能体系的改造都不能凭感觉判断成功。我建议至少跟踪五个指标技能命中率用户请求是否被正确加载到对应技能、任务成功率最终是否完成用户目标、平均延迟、单次会话 token 消耗、需要人工兜底的次数。实操时可以先跑一周旧方案作为基线然后切换技能体系再跑一周做同期对比。根据我的迁移经验token 消耗下降是最明显的通常在 40% 到 60%因为不再需要把所有规则都塞进每次调用。任务成功率的提升反而没有那么明显因为它还受到技能拆分质量、description 命中率的影响但只要迁移方案合理最终总会向上走。有一个容易被忽略的点是技能命中率不等于任务成功率。命中率高只说明该加载的技能都加载了不代表执行对了。两个指标要分开看先调命中再调执行。5.4 迁移路上的几个坑和对应的调整思路第一个坑是技能描述重叠。两个技能的 description 都提到了“售后”导致一次请求同时加载两个技能彼此间的规则产生摩擦。解决办法是明确各自的边界在 description 里写排除条件比如“不处理退款问题”这种反向往约束。第二个坑是 SKILL.md 正文过长。技能被加载后正文长度直接占用上下文。我建议单个技能的正文控制在 1000 到 2500 字之间。超过 3000 字就要考虑拆子技能或者把长篇参考资料移到 references 目录只在需要时追加读取。第三个坑是版本管理混乱。SKILL.md 一旦上线任何人改动都可能影响线上行为但传统 git 流程对单个文件变更的验证覆盖不足。我的做法是每一个技能的变更都有独立版本号并配套一个最小测试集每次变更后至少跑一遍该技能对应的 5 个典型测试样例防止“改了 A 技能B 技能跟着出问题”的情况。第四个坑是冷门技能从不触发。排查时先看 description 里有没有业务触发词再看匹配阈值是否设置过高。有时候把阈值从 0.6 降到 0.45调用率就上来了。最后说一点个人体会。我前后接触过多个从长提示词转向技能体系的案例最深的感受是很多人抱怨“模型变笨了”其实不是模型的问题而是他们把所有能力都塞进上下文让模型在噪音里找重点。技能体系的三个核心——SKILL.md 结构化定义、按需加载、权限边界——其实都在做同一件事让指令在正确的时机、以正确的形态、在受限的范围内被使用。这套思路迁移到任何需要 Agent 自主决策的场景都能让系统从“一个什么都管但什么都管不好的巨型 prompt”变成一组职责清晰、可独立维护、可安全组合的积木。如果你也在被长提示词困扰我建议先从记录一份现役 prompt 的“规则清单”开始找到那些只在特定场景使用的内容拆出第一个 SKILL.md你会立刻感受到差异。