ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Agent Skills技能包实战:从SKILL.md编写到多代理编排

Agent Skills技能包实战:从SKILL.md编写到多代理编排 前几天我整理工作台时把一个本地写好的“json-tidy”技能包从 Claude Code 迁到一个自建的小型 agent 框架里几乎只改了两行路径和一行配置就正常跑通了。放在几个月前这几乎不可想象——我一直觉得 AI 能力就等于“模型权重 提示词”换个客户端、换个框架整套又得从头来。这次迁移让我彻底改观把 agent 的高频行为沉淀成标准的、目录化的 skills 文件比反复调 prompt 要可靠得多。这篇文章到底要解决什么问题一句话我会把“agent-skills”这个看似宽泛的概念落地成一个可以复用的工程方法。你不需要基础就能看懂前半部分但如果你正卡在“代理会做但总不稳、一换环境就废、多任务一多就乱”这几个坎上后半部分的架构拆解和排错记录应该能帮上忙。文章会用一个贯穿始终的真实示例——JSON 清洗与格式化技能完整展示从技能规划、SKILL.md 编写、脚本封装到接入框架、结合记忆与多代理编排的全过程。1. Agent Skills 是什么先把概念摆正1.1 技能包的标准配置长什么样一个技能包本质上是“一组有组织、可独立交付给 AI 代理的能力文件”。它没有玄学就是一个文件夹里面装着指导代理完成某类任务的指令文件和可调用的脚本资源。拿我常用的技能包举例标准结构大概是skill-name/ ├── SKILL.md # 核心指令文件代理最先读它 ├── scripts/ # 可执行脚本比如 Python/Shell ├── data/ # 额外资源比如模板、参考样例 ├── tests/ # 测试用例或验证脚本 └── docs/ # 可选补充原理或操作手册这里最核心的是SKILL.md。它相当于“技能说明书单位 SOP”代理不会自己发明流程它完全按这个文件里的步骤来执行。scripts/是可选但强烈推荐的因为很多技能必须依赖确定性操作——比如文件批量重命名、安装依赖、校验 JSON 格式——让模型写脚本当场执行容易翻车而预先封装好可复述的脚本成功率会高非常多。从作用上看它和传统软件开发里的“函数库”很像但又有本质区别函数库是给程序员调用的技能包是给 AI 代理“阅读后自觉执行”的。模型未必逐行执行脚本它读懂了 SKILL.md就知道该何时触发脚本。更直白地说技能包是让 AI 代理做事的一套“肌肉记忆”。1.2 技能、工具与插件别傻傻分不清很多社区讨论把工具(tools)、技能(skills)、插件(plugins)混在一口锅里炖实际它们在代理体系里的地位和用途完全不同。工具是代理在某个“此刻”能调用的外部功能入口也就是 API比如“搜索网页”“打开文件”“执行 Python”它强调确定性和可程序化输入输出。插件则是宿主环境里的集成点比如 IDE 插件、日历插件它负责打通外部系统和宿主应用。技能是更高一层的抽象。它既有描述性指令给模型看的自然语言也有可执行的工具调用步骤甚至可以指挥代理去调用其他工具。做个生活化类比工具是“螺丝刀”插件是“工具箱的卡扣”而技能是“换灯泡的整套流程——先断电、再拧下旧灯泡、核对型号、装新灯泡、通电测试”。代理需要的是技能而不只是一堆螺丝刀。维度工具插件技能核心载体API / function schema宿主集成代码SKILL.md 脚本资源谁消费模型直接发起调用宿主应用加载模型先阅读再执行确定性高中中低依赖模型能力可跨框架一般需要适配层绑定插件宿主结构性可迁移典型场景图搜索、代码执行绑定设计工具、浏览器自动化多步骤工作流经常有人问“技能会不会被工具替代”。我的判断是短期不会因为大模型本身对“步骤和原则”的理解能力越来越强而技能包的粒度正好让它可以做思维规划。只要 agent 还需要自主决策技能这种“半指令半程序”的形态就有不可替代的价值。1.3 为什么现在必须重视技能沉淀我在多个项目里反复观察到一个规律纯靠系统提示词(system prompt)堆能力的代理项目一复杂必然崩。提示词塞太多模型选择注意力和上下文窗口就会冲突最后啥都干不好。而技能把知识外置了——你不需要在每次会话里把“怎么清洗 JSON”的全部细节写进提示词只需告诉代理“遇到脏 JSON 时调用 json-tidy 技能”。这种“按需加载”的机制有三大红利。第一是成本红利大幅减少每次请求的 token 消耗长期用能省下不少预算。第二是稳定红利技能的 SOP 是反复验证过的不会因为模型版本从 3.5 升到 4.x 就突然变样。第三是资产红利技能包是可积累的这个月写 5 个下个月写 10 个半年后你就有了一个内部能力仓库新项目开工直接装配不用再从零开始调教代理。2. 从第一性原理设计技能架构先想想为什么这么拆2.1 SKILL.md 的核心解剖很多新手写技能上来就堆一大篇自然语言以为写得越详细越好。实际上我见过的成功技能包SKILL.md 都极其克制通常在 30 到 80 行以内。一个我实测下来很好使的模板结构是这样--- name: json-tidy description: 清理和格式化 JSON 数据。当用户输入包含尾逗号、注释、单引号或乱码的 JSON 时使用此技能进行修复和规范化。 version: 1.0.0 author: yourname ---然后是正文指令分成几个固定块# 概述 本技能将任意位置出现的 JSON 数据修复为合法 JSON并按键名排序输出。 # 使用场景 - 用户粘贴了 JSON 片段但无法解析 - 日志中带有注释或自增编号的 JSON - 需要统一 key 顺序以便对比差异 # 执行步骤 1. 读取输入内容识别 JSON 的起始和结束位置。 2. 如果内容包含注释调用 scripts/strip_comments.py 处理。 3. 调用 scripts/tidy_json.py 标准格式化。 4. 如果输入是 JSONL保留逐行处理逻辑。 5. 输出修复、格式化后的内容并报告修复前和修复后的差异数量。 # 注意事项 - 不要修复非 JSON 内容如纯文本或 Markdown。 - 如果输入已是合法 JSON,直接格式化,不改变 key 顺序,除非用户明确要求排序。 - 遇到无法解析的输入时,不要反复猜测,向用户说明失败原因并给出支持格式示例。 # 示例 输入: {id:1,b:2,a:3} 输出: {a:3,b:2,id:1}注意几个细节。description字段必须极端具体因为它决定了技能何时被模型唤起。模糊描述会导致调用率低写得太宽泛又会让模型在根本不该用的时候错误调用。“执行步骤”必须是小颗粒动作每个步骤保持只有一个主语和一次操作不要混合多个任务。最后“注意事项”里的负面约束非常重要它实际是给模型的兜底护栏防止出现自作聪明的灾难操作。2.2 写指令的高杠杆细则小步、明确、可回退我自己改过无数版技能文件最终沉淀出三条硬规则。第一一个技能只解决一个问题。这不是怂是为了降低模型的理解成本。我见过有人把“数据处理”做成一个超级技能里面包含清洗、可视化、特征工程结果代理连该用哪段指令都分不清。拆成json-clean、csv-summary、chart-builder三个独立技能后调用准确率立刻上来了。第二每个步骤都要告诉代理“如果这一步失败下一步怎么办”。比如执行脚本失败应该重试一次还是跳过该步直接报错如果不明确代理可能会无限重试或者编造成功结果。我在不少开源项目里看到过这种问题的原生提示词最后被用户带跑偏。技能文件必须把异常路径写清楚。第三给触发词和案例。在description里明确写上“当用户输入包含尾逗号、注释、单引号或乱码的 JSON 时使用”比一句“修复 JSON”效果翻倍。因为模型是基于语义匹配触发的它需要从你的描述里学到分类边界。2.3 按需加载与上下文预算技能系统里最关键的机制为什么技能包系统比把所有东西都塞进系统提示词强核心在于上下文预算。大模型上下文窗口是有限资源你给的数据越多模型在多轮对话中的注意力更容易被稀释响应质量和速度都会下降。技能系统采用“注册表 按需加载”策略主会话只注入技能包的“描述目录”模型根据用户问题和目录的相似度决定是否加载某个完整技能。相当于你有一个巨大的工具箱但没有把整箱工具摆在桌面上而是只放一张物品清单需要电钻时再从库房拿出来。实现上最朴素的做法是在项目根目录放一个skills/registry.md内容是一张技能名和描述的表格然后告诉 agent“以下是你可用的技能列表。当用户请求涉及其中某项时主动读取对应目录的 SKILL.md 并按步骤执行。”高级一点的框架比如一些开源 agent 项目会做依赖注入和自动路由但核心都是“看一眼描述再决定是否拉全文”。这种机制对 token 的节省非常可观。一个大型技能包可能有 2000 行代码和文档但平时根本不用全部进上下文。只有被触发时才加载一个会话内可能只占几百 token成本压力小得多还能支持更复杂的多技能协作。3. 实操从零创建一个能直接运行的技能包3.1 第一步不是写代码而是规划技能边界很多人先把目录建好、脚本写好再回头补 SKILL.md这个顺序完全反了。我建议先回答三个问题。这个技能服务的核心任务是什么输入是什么形态输出是什么形态哪些场景绝对不处理拿 json-tidy 项目为例我当时就明确写了三句话它只处理 JSON 和 JSONL不做 XML 或 YAML 的转换输入可以是文件路径、标准输入或对话中的文本块输出是修复后格式化好的 JSON 文本附带修复摘要。这个边界一立后面的文件结构、脚本设计全都有了约束SKILL.md 写起来也快。3.2 第二步编写 SKILL.md 与配套脚本先创建目录结构这里我用实际命令演示mkdir -p json-tidy/scripts json-tidy/tests touch json-tidy/SKILL.md然后写上面的 SKILL.md 内容。最关键的一步是配套脚本。我在这里放一个简化版tidy_json.py#!/usr/bin/env python3 import json import re import sys def strip_comments(text: str) - str: # 去掉 // 和 # 开头的行注释,保留字符串内部的 # 和 //。 # 这里用简单状态机处理字符串保护。 lines text.splitlines() clean_lines [] in_string False for line in lines: protected_chars [] i 0 while i len(line): ch line[i] if ch and (i 0 or line[i-1] ! \\): in_string not in_string protected_chars.append(ch) i 1 continue if not in_string and (line[i:].lstrip().startswith(//) or line[i:].lstrip().startswith(#)): break protected_chars.append(ch) i 1 clean_lines.append(.join(protected_chars)) return \n.join(clean_lines) def tidy(data_str: str, sort_keys: bool False) - str: cleaned strip_comments(data_str.strip()) try: obj json.loads(cleaned) except json.JSONDecodeError: # 尝试把单引号替换为双引号,做保守恢复 cleaned re.sub(r(?!\\)(.*?)(?!\\), r\1, cleaned) obj json.loads(cleaned) return json.dumps(obj, indent2, ensure_asciiFalse, sort_keyssort_keys) if __name__ __main__: raw sys.stdin.read() sort_keys --sort in sys.argv result tidy(raw, sort_keys) parsed json.loads(result) print(result) print(f\n# 修复完成: 原始输入长度 {len(raw)},输出 key 数量 {len(parsed)}, filesys.stderr)写脚本的原则是与其让模型现场发挥不如把逻辑固化下来。JSON 解析本身是个确定性很强的事情模型很容易被各种引号搞晕封装成脚本后模型只需要负责把输入喂给脚本、把结果整理给用户。这个分工是整个技能包稳定的关键。3.3 第三步注册技能并验证调用链路技能文件写完了不注册等于白写。不同框架的注册方式不一样。在简化版 self-host agent 里我通常在配置目录写一个registry.yamlskills: - name: json-tidy path: ./skills/json-tidy description: 清理和格式化 JSON。处理注释、尾逗号、单引号替换。 entry: SKILL.md scripts: - scripts/tidy_json.py然后告诉代理系统提示词“你有一个技能档案库。调用技能前先看 registry 里的描述确定调用后读取该技能的 SKILL.md 和脚本按步骤执行。”我没有用什么复杂框架就这么几行就已经能支撑基本使用了。验证环节不能省。我会准备三类测试输入。第一类是干净 JSON应当直接格式化第二类是带注释和尾逗号的脏 JSON应当正确清洗第三类是不可修复的纯文本系统应当优雅报错而不是陷入死循环。跑通这三类技能包才敢说交付了。echo {name:test,version:1,tags:[a,b]} | python3 json-tidy/scripts/tidy_json.py --sort echo {id:1, /* comment */ b:2, a:3,} | python3 json-tidy/scripts/tidy_json.py echo this is not json | python3 json-tidy/scripts/tidy_json.py第一行会输出排序后的格式化 JSON第二行会去掉注释、修复尾逗号后格式化成功第三行应当打印明确的解析错误。如果第三行实际输出了一堆猜测内容说明脚本需要加错误分支不能让模型看到错误后瞎编。3.4 技能交付时的完整自检清单脚本跑通只是第一步交付前我还会过一遍这个清单SKILL.md 里的description已经明确包含了触发场景和反例。执行步骤能在五步以内完成超过就考虑拆技能。每个脚本都有稳定的退出码和输出约定模型能看懂“成功/失败”的信号。测试用例中至少有一个“反例”专门给模型展示不该调用该技能的情况。目录和文件命名规范不出现中文路径、空格或特殊字符。技能文档中标记了依赖库比如requirements.txt或单文件版 Python 脚本。这套清单我每次写新技能都过一遍基本能避免 80% 的交付事故。4. 技能生态与框架选型官方体系、命令行 Agent 与第三方工作台4.1 官方技能体系的标准值得参考当前大模型厂商已经意识到 skills 是 agent 的关键层主流的官方生态主要是把技能标准化。典型方案是约定SKILL.md文件结构、描述让代理能理解技能入口、提供注册机制让技能能被市场分发。官方市场的好处是下载即用不需要自己在内部做复杂适配但坏处也很明显它天然绑定某一套平台一旦想迁移到自建框架技能包的代码可迁移但注册表和加载逻辑往往要重写。我目前对待官方市场的态度是把它当“技能来源”而不是“技能归宿”。从官方市场抄来的技能包我会重新整理一遍 SKILL.md把不必要的平台依赖抽掉然后放进本地通用技能仓库。这样下来既吸收了社区智慧又保留了迁移灵活性。4.2 Codex 与命令行 Agent 的技能形态另一类比较有代表性的技能形态来自命令行 agent比如 Codex CLI 这类工具。它们的特点是技能经常以“可执行命令 说明文件”的形式出现代理可以直接在终端里调用。这带来的好处是执行效率极高还天然的能规避模型幻觉——命令有真实输出模型不用猜。坏处是安全边界更敏感一段如果一个技能带着rm -rf权限还给代理自主执行运营事故只是迟早的问题。所以用这种技能形态我会强制实现“白名单命令”和“危险操作确认”两件事。任何技能脚本涉及的 shell 指令列表必须锁死在白名单里非白名单命令一律拒绝执行。危险操作如删除、覆盖、修改权限等执行前必须向用户输出确认请求。这算是技能安全的底线。4.3 第三方工作台中的技能Obsidian 与各类 Agent 项目社区里还有一派很有意思就是把技能和知识库工具深度绑定比如用 Obsidian 做知识库和任务管理然后用各种 agent 项目接入这些库。这类工作台的特征非常明显技能不只是代码还包括了流程模板、卡片模板甚至方法论。对于像我这样喜欢把一切沉淀为文本的开发者这种风格很舒服——技能文件、说明文档、案例全都在同一个知识库里代理可以同时读取技能 SOP 和项目背景文档上下文更完整。像社区热度高的一些第三方工作台例如 Hermes Agent 的衍生项目、Reasonix 安装新技能的方式以及“Superpower Skills”这类技能组合项目他们做的事本质上是一致的把技能作为积木块提供便捷安装、降级处理和组合方式。真正有区别的是它们对多代理编排的支持程度有的把一个任务拆给多个技能并行有的还是一个主代理串行执行技能。我建议新手先用单代理串行技能跑稳后再上多代理。4.4 我的选型建议不同阶段的框架匹配场景优先方案理由个人助手、轻量使用官方市场 本地自建并存快速验证技能设计同时保留迁移路径企业内部流程自动化自建技能仓库 白名单命令安全可控技能资产归属清晰需要复杂长任务编排多代理调度 技能路由单个代理负责单技能避免上下文互相干扰实验、学习、快速试错第三方工作台如 Hermes Agent、Reasonix社区生态完整安装和组合成本低选型没有万能解。我见过有人什么都不管直接从大而全的 agent 框架开始结果技能包没写几个框架配置先拖垮了精力储备。真正常见有效的路线是先用最简单的方式把第一个技能跑通再慢慢迭代框架复杂度。5. 技能组合、记忆与多代理编排把单个能力变成完整系统5.1 技能的组合模式串行、并联与路由当你的技能库超过 20 个单技能直调就不够用了需要开始考虑组合编排。串行模式最简单一个任务的输出直接成为另一个技能的输入。比如“网页数据抽取技能”输出 JSON然后把 JSON 喂给“图表生成技能”产出可视化埋点。并联模式则是同时触发多个独立技能最后合并结果适合做竞品分析、多源数据收集。路由模式则依赖一个调度 agent。调度 agent 不做具体业务只负责把任务分发给合适的技能。这个设计可以有效防止在长任务里上下文污染。我实际测试下来带路由的架构在任务正确率上能比单 agent 硬跑高 20% 以上代价是多轮调用和 token 消耗也是成倍上涨。要不要路由得根据任务的复杂度和容错需求来判断别为了“架构好看”而不必要地加调度层。5.2 技能作为程序性记忆知识库作为互补技能系统做久了我意识到它其实是 agent 的“程序性记忆”——即知道怎么做事的记忆。而像 Obsidian 这样的知识库承载的是“陈述性记忆”即知道什么是什么。两者配合才能撑起一个真正智能的 agent。我通常的做法是这样把技能 SKILL.md 留在独立技能目录不掺进知识库知识库里只放项目背景、术语表、历史决策记录。代理在执行任务时先通过检索找到相关背景再加载对应技能最后依据技能步骤完成动作。这样职责清晰技能更新不影响知识库知识库扩充也不破坏技能逻辑。5.3 多代理协作实例分配、执行与汇总用一个我实操过的场景来展示组合效果。假设要产出一份“竞品功能矩阵报告”我不靠一个 agent 硬扛而是拆成三个角色主控代理、页面分析代理、数据处理代理。主控先加载 “task-router” 技能把网页列表分发给分析代理分析代理调用“web-extract”技能抓取页面并抽取字段数据处理代理接收结果调用“json-tidy”技能清理数据再调用“matrix-builder”技能生成矩阵。整个过程各代理各管一摊技能模块就像流水线上的工作站。除了初期的编排逻辑复杂一些实际执行速度和稳定性都远超单代理。而且副产物很值钱每个代理执行时留下的日志可以直接沉淀为未来项目的问题库。6. 高频问题和排查思路我踩过的坑你可以少走6.1 技能没生效先检查这几个位置最常碰到的坑是技能文件确实写了但代理完全没调用。排查顺序我建议照着来。第一步打开注册表确认技能的description和触发场景有没有写具体如果描述是“处理 JSON”这种泛泛表达模型很难把它跟“修复尾逗号”这件事关联起来。第二步检查当前会话里有没有把技能目录告知代理没有告知等于没有代理根本不知道你有一个技能包。第三步确认你用的框架有没有限制上下文长度如果系统提示词里指定了“只回答知识范围内内容”代理可能觉得直接回答更省事从而跳过技能调用。6.2 执行中途报错不要慌按日志反推“agent execution terminated due to error”这句应该是不少人的噩梦。我遇到这种报错第一反应不是去看模型输出而是去翻执行日志里的退出码和 stderr。如果是技能脚本本身出错大部分情况是路径不对、依赖缺失、权限不足三个原因。路径问题最常见脚本里用了相对路径但代理执行时的工作目录跟技能目录不一致。我会强制在 SKILL.md 里写“所有脚本必须用绝对路径或从技能根目录的 scripts 目录启动”从源头规避。依赖缺失就用requirements.txt现做防护。权限不足就提前检查脚本可执行位该chmod x就早点做。6.3 token 暴涨技能系统常见的“自我膨胀”技能明明是按需加载为什么 token 还会爆炸我查了几次发现都是技能内部脚本输出和指令的交互导致的。有些代理会把技能目录里的所有文件都加载进会话尤其是存在 big data 样例时。这个解决很简单在 SKILL.md 里明确告诉代理“只读取本文件列出的脚本不要读取 data 目录中的大文件除非执行步骤明确要求。”另一个场景是技能被模型当作“挂载点”它想调用一个技能时把整段历史对话都重新读取一遍这就需要在框架层面限制加载范围。技能系统的“按需”不能只靠模型自觉也需要框架侧做白名单和路径隔离。6.4 常见问题速查表症状可能原因快速修复代理从不调用技能description 不具体重写触发条件和反例调用技能后仍按旧逻辑执行系统提示词把技能目录写错了核对注册表和路径脚本报错找不到文件相对路径问题改为绝对路径或脚本自定位输出格式和 SKILL.md 定义不符模型没按步骤做把步骤拆成小步并加“必须输出 JSON”约束token 突然翻倍技能大文件被全文加载加路径白名单和文件大小限制技能执行后状态回滚多代理并发写同一文件加锁或让每个代理写独立临时目录安全报错危险命令未过白名单检查技能白名单配置阻断高危操作这表我基本贴在工位上每次出新问题就补一行。技能系统的稳定性不是一次写对的而是靠持续维护、持续迭代磨出来的。7. 我的个人习惯与最后想说的话写技能这件事真正改变我工作方式的一点是我开始把“教 AI 做某事”当成“给团队写培训手册”。以前我写提示词想到哪写到哪效果完全看模型心情现在我写技能包会先想清楚边界、异常、回退路径再落到文件。这个习惯转过来之后项目出错率和返工时间直接下降了一大半。如果你现在正带着 agent 在项目里摸爬滚打我强烈建议你从今天开始把自己反复让 AI 做的三件事沉淀成三个技能包。不用一开始就搞大而全的架构先做最小的 SKILL.md哪怕只有十几行跑通了再扩展。等你攒到几个能稳定交付的技能后你会明显感觉到Agent 开发的重心已经不在“调教模型”上而在“定义能力包”上。这个方向我还会继续做下去。后面如果再折腾出好用的技能模板或排错经验我再回来继续补完。
返回列表