
第一次把几十个工具塞进一个 Agent 的 System Prompt我就后悔了。上下文被塞得满满当当模型开始丢三落四前面定义的规则在后面被悄悄遗忘工具描述之间还经常打架。后来我转向“技能库Skills”这种方式来组织 Agent 的能力把可复用的经验拆成一个个独立、有结构的 Skill 包Agent 不再靠一段超长 Prompt 硬撑而是按需发现、加载、执行。这篇文章想聊的“agent-skills”就是把这项工作沉淀下来的经验技能长什么样、怎么设计、怎么调度、会踩哪些坑。它适合正在做 Agent 应用、被 Prompt 膨胀和工具管理问题困扰的开发者也适合刚接触智能体工程、想建立一套规范的人。我最初以为 Skills 只是换了个马甲的 Prompt 模板真正落地之后才发现它其实是 Agent 工程化里非常重要的一层抽象。技能好不好用直接决定了一个智能体是“看起来聪明”还是“真的稳定可靠”。下面我把整个思路拆开讲。1. 先搞清楚 Agent Skills 到底解决什么问题1.1 从一次真实翻车说起当时我在做一个内部助理 Agent功能有好几块日报生成、报销初审、会议纪要、代码审查。第一版我是这么写的把所有任务描述、调用规则、输出格式、注意事项全部塞进一段 System Prompt然后把所有可用函数通过 function calling 暴露给模型。结果跑了不到两天就出问题。具体表现是输入一长模型就开始“选择性失忆”。比如日报生成规则明明写在前面处理到中间某一步时它却不按规则提取数据而是自由发挥。另一个问题是谁都想抢话——报销初审的描述和财务审核的描述有重叠模型经常把报销单丢给财务技能去处理流程直接错乱。我后来统计了下那段 Prompt 光 System 部分就超过 8000 token每次请求都要全量发送成本和延迟都上去了效果反而更差。换到 Skills 之后变化是结构性的。每个技能是一个独立目录里面有自己的说明文件、脚本和依赖。System Prompt 里只保留一份“技能目录”——也就是每个技能的名字、一句话描述、何时使用。真正的执行手册是懒加载的Agent 先读目录、再根据任务选中一个或多个技能、最后只展开命中技能的完整内容。上下文压力骤降规则不再互相干扰单个技能的调整也不会牵一发动全身。1.2 Skills、Tools 与 MCP三者到底什么关系很多人把 Skills 和 Tools 混为一谈实际它们不在一个抽象层级。Tools也就是 function calling 里的函数是原子的输入输出由代码固定模型只负责填参数而一个 Skill 更像是给 Agent 的“操作手册”它可以包含多个步骤、判断分支、内部决策甚至内部再去调用多个 Tools。MCP 则是一个更底层的协议解决的是“工具如何被发现、如何被调用”的标准化问题可以让 Agent 通过统一接口连上各种外部工具服务。Skills 和 MCP 并不互斥反而可以叠加Skill 描述“做什么、按什么流程做”MCP 负责“底层工具到底怎么连”。我把三者的区别整理成了一张表方便对照维度SkillTool / FunctionMCP本质可复用的任务执行手册含流程、判断与资源单一函数输入输出确定工具发现与调用的标准协议粒度任务级可编排多步原子级协议级是否消耗模型推理是模型按手册逐步执行否执行逻辑在代码里否典型载体SKILL.md scripts 目录JSON Schema 函数实现MCP Server 暴露的工具集抽象层级最高中中低理解了这个关系就不会再做“把所有 Skills 改成 Tools”或者“用 MCP 替代一切”的拍脑袋决定了。它们是配合关系不是替代关系。真正的 Agent 工程结构通常是Skills 在上层做任务编排Tools 在中层做原子操作MCP 在底层做服务接入。1.3 为什么 Skills 正在成为 Agent 工程化的事实标准一个东西能流行往往是因为它在多个维度上同时胜出。Skills 之所以被越来越多团队采用主要赢在四点第一是上下文可控。技能目录是轻量的只有命中才会展开全文Token 消耗从“全量加载”变成“按需加载”这是一个数量级的差别。第二是可维护性。每个技能独立迭代改一个技能不影响其他能力这跟代码里的模块化是同一个道理。第三是可测试性。技能输入输出边界清晰可以像单测一样批量回归不用每次手动把整个 Prompt 重新验证一遍。第四是可复用性。一个团队沉淀出来的“报销审核”技能换个项目可以直接拷贝过去顶多改一些公司专属字段。除此之外Claude Skills、OpenAI 的 Agents SDK、LangChain 等主流生态都开始围绕类似结构做支持说明这不是某个框架的临时设计而是一个被验证过的组织范式。用个不太严谨但贴切的类比如果 Tools 是给实习生提供的“一个个具体小工具”那 Skills 就是一套“带图示和注意事项的作业指导书”。实习生Agent先翻目录选对指导书再照着做而不是把所有工具的说明书全背下来才开始干活。2. 技能库的核心设计粒度、结构与 SKILL.md2.1 技能粒度怎么定才不后悔设计技能库最大的坑是粒度把握不好。我见过两种极端一种把“读取文件”“发送 HTTP 请求”这种原子操作做成了技能另一种把一个“综合办公助手”整个塞进一个技能里。前者让 Agent 陷入无穷的微操作后者又回到了 Prompt 膨胀的老路。我现在的判断标准很简单一个 Skill 应该对应一个“完整交付物”。什么叫完整交付物就是做完这件事用户能拿到一个可以直接用的结果比如“一份会议纪要”“一份报销初审结论”“一个修复后的 JSON 文件”。按这个标准“读取文件”不算技能它只是技能里的一个步骤“整理会议纪要并发送邮件”勉强算一个技能但如果发送邮件逻辑很重我更倾向拆成“整理纪要”和“发送邮件”两个技能由上层编排。另外注意技能之间的边界要互斥。比如“会议纪要”和“访谈纪要”看起来都是整理文字但处理方式和输出模板完全不同。如果两个技能都能被“帮我总结这段对话”触发Agent 就会随机选择。我的做法是把它们合并成一个“结构化纪要整理”技能内部按“会议/访谈/通话”做分支或者用 very explicit 的 when_to_use 字段把场景写死从描述上就隔离掉。2.2 一个标准 Skill 的目录结构与元信息我比较推荐参照 Anthropic Claude Skills 的那套目录规范来做因为它经过大量工程验证结构清晰生态兼容性也好。一个标准技能大致长这样skills/ ├── meeting-summary/ │ ├── SKILL.md │ ├── scripts/ │ │ ├── transcript_clean.py │ │ ├── build_agenda.py │ │ └── export_markdown.py │ ├── assets/ │ │ └── template.md │ └── requirements.txt核心是 SKILL.md它是一个带 YAML frontmatter 的 Markdown 文件。frontmatter 里放机器可读的元信息正文放给模型看的人类可读指令。两者分开很重要元信息是给“技能发现模块”用的可以快速解析、检索、排序正文是给模型推理时读的写得再长也不会影响目录生成。我常用的元信息字段有这些name技能短名建议动词开头比如meeting-summary。description一句话说明技能能力控制在 50 字以内。when_to_use触发场景越具体越好包括同义说法和反例。version语义化版本号方便灰度与回滚。dependencies需要的 Python 包或外部服务比如openai,ffmpeg。正文部分则按照“输入—步骤—输出—注意事项”四段来组织。我后面会给出一个可以直接抄的完整模板。2.3 SKILL.md 指令书写的实操模板指令写得清不清楚基本决定了这个技能是好用还是摆设。我总结了一个经过多轮迭代的模板这里直接放出来--- name: meeting-summary description: 将会议录音或文字转录整理为结构化会议纪要 when_to_use: 用户提供会议录音文件、转录文本或提到“帮我做会议纪要”、“整理会议记录” version: 1.0.0 dependencies: - python 3.10 --- # Meeting Summary ## 目标 把任意形式的会议转录内容整理为包含结论与待办事项的结构化纪要。 ## 输入 - 转录文本推荐纯文本或 markdown - 可选参会人名单、关注议题 ## 处理步骤 ### 1. 文本清洗 - 去掉语气词、重复发言、长时间沉默标记。 - 如果输入是音频先调用 scripts/transcript_clean.py 做语音转写清洗。 ### 2. 内容聚类 - 按议题切分文本每个议题给出标题。 - 如果同一话题被反复讨论合并为一节并在“过程”中保留关键转折点。 ### 3. 生成纪要 - 必须输出到以下固定结构 - 会议主题 - 核心结论3-5 条每条不超过 50 字 - 待办事项负责人、事项、截止时间 - 遗留争议 ### 4. 保存 - 默认导出为 Markdown 文件保存在工作目录下文件名格式 meeting-YYYY-MM-DD.md ## 输出格式 markdown ## 会议主题 一句话 ## 核心结论 - 结论一 - 结论二 ## 待办事项 | 负责人 | 事项 | 截止时间 | | --- | --- | --- | ## 遗留争议 留空或列明争议点注意事项不确定的负责人不要猜测统一标记为“待确认”。寒暄、硬广、无关内容一律省略。如果转录文本质量太差大量乱码、缺行停止处理并向用户说明原因。注意这里有几个细节步骤用了编号模型对这种显式的顺序很敏感输出格式直接给了 Markdown 代码块这比单纯用文字描述格式要可靠得多注意事项里有“停止条件”防止模型在输入质量太差时硬编造结果。我自己实测下来加了“停止条件”之后幻觉率明显下降。 ### 2.4 命名、描述与检索让 Agent 第一时间找到对的技能 技能库超过十个之后最大的问题已经不是“技能怎么写”而是“Agent 能不能找到”。这里有两个抓手。 第一个是命名和描述里的关键词覆盖。技能作者常常把 description 写得像技术文档比如“Transcript preprocessing utilities for meeting data”但用户提问往往是“帮我把今天下午的会整理一下”。要让技能可被发现when_to_use 里要把口语表达和同义词写进去例如“会议纪要”“会议记录”“整理会议”“Meeting Notes 汇总”。 第二个是检索策略。只靠模型从技能目录里翻技能多了就失灵。我推荐“两阶段召回”先做一次 embedding 检索把用户任务和技能目录里的 description 做向量相似度匹配召回 TopK比如 5 个再把召回到的技能描述和用户任务一起交给模型做精排让模型选一个最合适的。这样做的好处是模型不需要逐条读完整目录检索压力被前置到了一套确定的代码逻辑里结果更可控。 我顺便给一个通用发现接口的伪代码示例方便理解整个过程 python def discover_skills(skills_dir, user_task, top_k5): catalog [] for skill_path in skills_dir.iterdir(): md skill_path / SKILL.md meta parse_frontmatter(md) catalog.append({ name: meta[name], description: meta[description], when_to_use: meta[when_to_use], path: skill_path, }) # 先用向量召回再用模型精排 candidates vector_search(user_task, catalog, top_ktop_k) best llm_rerank(user_task, candidates) return best这段代码不是某个框架的官方实现而是我梳理出来的通用逻辑。如果你用的是 Claude Skills 或 LangChain会有现成的加载器和路由组件但底层思路不变。3. 技能是如何被 Agent 发现、加载和执行的3.1 技能发现两种主流匹配方式技能发现是整个执行链路的第一环做得好不好直接影响后续所有环节。目前主流有两种做法。第一种是纯模型路由。把技能目录里每个技能的 name、description、when_to_use 拼成一段 JSON 或 Markdown 放进上下文然后让模型在 ReAct 循环里决定调用哪个技能。这个方案实现简单适合技能数量在 10 个以内的场景。技能一旦多了模型选择的准确率会肉眼可见地下降而且每轮都要把这串目录反复送入上下文。第二种是检索增强路由也就是我在前面提到的两阶段召回。先用 embedding 做粗筛再用模型对候选集精排。这个方案哪怕技能库有几十上百个也能把选择准确率维持得很高。它的代价是要多维护一套向量索引但这点成本跟 Agent 稳定性的收益比起来完全值得。我给一个实操建议可以先跑纯模型路由当技能库超过 15 个或者出现频繁选错时再上检索增强。不要一上来就搞很重的架构技能的维护成本会盖过收益。3.2 上下文加载与 Token 预算控制我相信很多人没认真算过技能库的 Token 账。假设你有 30 个技能一个技能的 SKILL.md 平均 1500 token如果全部塞进上下文那就是 45000 token。这还不算脚本代码和示例。即使你的模型支持 200k 上下文每次请求都在大量无效信息里“大海捞针”注意力和响应质量都会受损。用技能目录机制之后情况完全不一样目录只放元信息假设每个技能 60 token30 个技能只要 1800 token命中的技能完整展开算 1500 token再加上任务本身的输入总上下文中技能相关的部分也就 3300 token 左右。两者差了十倍以上。我习惯给每个 Agent 建立一个简单的 Token 预算表像下面这样阶段内容预算Token固定指令角色、目标、原则800技能目录技能元信息1800命中技能SKILL.md 全文1500用户输入任务上下文2000预留余量工具响应、错误信息1000如果某个技能展开后超过 3000 token我会考虑把它内部的内容精简或者拆成多个子技能。凡是超过预算的技能都要打个问号是不是又回到了“大而全”的 Prompt 写法3.3 执行中的错误处理与兜底再好的技能也会在执行中遇到意外比如脚本报错、输出格式不对、外部服务超时、用户中途改需求。我以前犯过的最大错误是让 Agent 在技能执行失败时自己去“硬编一个结果”它会假装工作已经完成了。后来我加了三条硬规则。第一条是分级退出。技能内部出问题时必须向上层返回一个明确的错误信号而不是返回一段敷衍的文字。至少分三类资源类错误文件找不到、依赖缺失、处理类错误文本质量太差、关键信息缺失、输出类错误生成结果不符合输出模板。上层根据错误类型决定是重试、换技能还是向用户求助。第二条是副作用控制。凡是涉及发邮件、提交工单、修改线上数据的技能必须增加确认步骤。我的做法是让技能先输出“将要执行的动作清单”用户确认后才触发真正的写操作。这个安全网在早期特别有用能避免很多因为模型理解偏差导致的误操作。第三条是可追溯性。每次技能执行都要记录调用日志命中了哪个技能、加载了什么脚本、每一步的输入输出。日志不是为了事后追责而是为了快速定位是技能的锅、模型的锅还是数据的锅。没有日志效果变差时你只能对着空气猜。3.4 技能版本管理与灰度上线技能也是代码我没少因为改了一个技能的描述导致另一个场景的表现突然下滑。后来我把技能库纳入代码管理走 Commit、Review、Release 的流程。每个技能目录下都有一个 version 字段改动后必须升版本号和引用了该技能的 Agent 做引用锁定。灰度上线我通常按用户比例来做。一个技能改完后先让 10% 的流量使用新版本对比新旧版本的完成率、耗时、用户反馈再决定是全量放开还是回滚。这里的关键是量化我在每个技能的日志里埋了 completion是否完成任务、duration执行耗时、escalation是否升级给人工这三个指标有了它们灰度才有依据。有一个容易忽视的细节SKILL.md 的文本改动哪怕只是加一个标点也可能改变模型的执行路径。所以版本管理一定要连正文一起纳入而不是只管理代码脚本。4. 实操案例手写一个 meeting-summary 技能4.1 场景与需求光讲理论容易飘我拿自己最近在用的一个技能做全流程拆解。场景是用户丢给我一段会议录音的转写文本里面可能有大量废话、多人发言、若干个议题混在一起我需要在一分钟内输出一份结构化会议纪要包含结论和待办。这个任务看起来简单但如果没有技能约束模型经常会漏掉某个议题或者把待办事项里的负责人张冠李戴。需求梳理下来有三点一是输入不固定有时是已转写的文本有时是音频文件路径二是输出格式必须稳定方便后续自动归档到知识库三是清洗过程要可靠不能产生多余的主观解读。4.2 准备目录与 SKILL.md我先建立目录mkdir -p skills/meeting-summary/scripts touch skills/meeting-summary/SKILL.md然后把前面那个模板填进去并且在 scripts 下放了一个文本清洗脚本。这个脚本负责把 OpenAI Whisper 转写结果里常见的语气词、时间戳噪声去掉。清洗环节写在技能步骤里但具体实现用代码来完成这样能减少模型在机械操作上犯错的概率。我还会在 SKILL.md 里写清楚一个分支逻辑如果用户给的是音频路径第一步先调用scripts/transcript_clean.py做预处理如果用户直接给文本则跳过这一步直接做内容聚类。这个分支如果写成代码会很啰嗦但用自然语言描述模型反而处理得很好。4.3 演示整个调用链怎么跑通技能写完后实际执行链路是这样的用户输入“帮我整理今天下午跟设计团队的会”和一段转写文本。发现模块先用 embedding 在技能库里召回到meeting-summary技能随后系统把该技能完整加载进上下文。模型开始按 SKILL.md 里的步骤执行清洗文本、按议题聚类、生成固定格式的纪要、保存成meeting-2025-01-12.md文件。我录了一段调试日志简化后大概是这样的[discover] query帮我把今天下午的会整理成纪要 [discover] recall: meeting-summary (0.91), interview-summary (0.72), daily-report (0.30) [discover] rerank: meeting-summary [load] skills/meeting-summary/SKILL.md (token1420) [exec] step1: transcript_clean.py - cleaned.txt (ok) [exec] step2: topic_cluster - 3 topics [exec] step3: generate markdown - meeting-2025-01-12.md [metric] completion1, duration24s, escalation0从日志上可以看到检索阶段把interview-summary作为次优候选也召回了但精排阶段正确选择了meeting-summary。这说明两阶段召回确实能兜住描述重叠的边界场景。4.4 成本与效果评估跑通之后我顺手做了一组对照。旧的“大 Prompt 全量工具”方案单次请求里技能相关 token 约 12000现在的技能方案降到 3200 左右。不仅是省钱响应时间也缩短了接近一半因为模型需要推理的无关内容少了。效果方面我拿 20 份历史会议转写做了回归手工标了“结论是否齐全、待办是否准确、格式是否合规”三个维度。旧方案合规率只有 70%技能方案稳定到 90% 以上。最让我意外的是“待办负责人归属”这个单项正确率从 78% 提到了 96%说明把“不要猜测负责人缺失则标待确认”写进注意事项能非常有效地压制幻觉。5. 常见问题与排查技巧实录5.1 技能加载失败先查路径再查格式我自己和身边朋友遇到最多的就是技能目录建好了但 Agent 始终“看不到”。90% 的原因是路径问题技能目录不在 Agent 配置的扫描范围内或者脚本引用了相对路径换一个工作目录就跑不动。第二个高频原因是 SKILL.md 的 frontmatter 格式不合法YAML 解析失败时整份文件都会被跳过。有一次我因为多余的空格导致version:字段解析错误排查了快半小时。排查的基本套路是三步走第一步确认技能目录在配置的skills_dir下第二步用 YAML 解析器单独校验 SKILL.md 的 frontmatter第三步看运行时日志里有没有“skill not found”之类的记录命中哪个错误类型就翻哪个配置。如果这三步都没问题再看是不是文件名大小写写错了。Linux 环境下SKILL.md和skill.md完全是两个文件这种问题用眼睛看很难发现。5.2 指令写得明明白白模型就是不照着做这类问题我遇到无数次。一开始我以为是模型能力不行后来才意识到是指令形态的问题。如果你的 SKILL.md 只有一段描述性的话没有步骤编号模型大概率会把它当背景信息忽略掉。我给一个改法把“先做什么再做什么最后做什么”改成强制编号步骤并且对每一步给出可直接校验的产物。比如“第 2 步完成后你必须得到一个topics.md文件”这句话比“对不同议题进行聚类”要有效得多。另外负面清单非常重要。我以前写“不要引入主观内容”模型还是时不时加一句“整体来看很有价值”。后来改成具体到格式的负面干预“禁止在核心结论里使用形容词评价只允许陈述事实”。效果立竿见影。如果加了约束还是不行那就检查是否缺少示例。对模型来说一个输入输出 pair 的例子胜过一百句文字规则。5.3 多个技能描述重叠Agent 频繁选错技能多了之后描述重叠是必然的。比如我之前有“会议纪要”和“访谈纪要”两个技能用户说“帮我把今天下午的谈话整理一下”两个技能都被触发模型就随机选。解决思路有两种。第一种是把重叠部分合并成一个技能内部用条件分支处理我大部分时候选这个维护成本最低。第二种是如果业务上确实需要分开那就要把 when_to_use 写成互斥条件明确说“当用户明确提到会议二字选择 meeting-summary当用户提到访谈、采访、面试选择 interview-summary”。这还不够最好在技能描述里加上排除词比如在meeting-summary里写“访谈场景请勿使用”。别小看这句话模型对排他性指示的响应准确率远高于开放性描述。5.4 技能回归测试没有测试就别提优化Skills 是 Prompt 的一种形态天然让人觉得很“软”没法测试。但我的经验是它完全可以像代码一样做回归测试。我会维护一个“黄金测试集”里面包含 30 到 50 条典型任务每个任务都标好了期望输出和边界情况。任何技能改动我都会先跑一遍这个测试集重点看两类变化一是这条任务的完成率有没有下降二是原本能正确完成的任务是否被改崩了。测试输出我用快照比对。每次跑完把输出文件和期望文件做 diff人工只需要关注差异部分。对于依赖模型输出的文字任务我们只对结构化字段做自动断言比如“负责人列是否存在空值”“截止时间是否满足格式要求”。这套机制让我对技能库的修改明显更有底气也让我敢频繁迭代而不是怕改坏了就永远不动。6. 工具选型与生态取舍6.1 主流实现方案横向对比现在做 Agent Skills可以选的路不少我梳理一下主流的四类。第一是 Anthropic 的 Claude Skills。它定义了一套官方规范每个技能一个目录SKILL.md 承载指令scripts 承载脚本对 Claude 系模型做了优化。好处是规范清晰、开箱即用尤其是在 Claude Code 里集成度很高适合团队快速验证。第二是 OpenAI 的 Agents SDK / Assistants。OpenAI 生态没有原生的 SKILL.md 概念但你可以用“Instructions Tools Prompt 文件”自行组织一套技能库。它的优势是模型生态成熟、工具调用能力强劣势是指令和工具的结合需要自己拼装。第三是 LangChain / LangGraph。它们更多是用tool装饰器和 Prompt 模板来组合支持 LangGraph 做流程编排。如果你本来就在 Python 生态里做复杂工作流这套组合很顺但技能的概念需要自己抽象不像 Claude Skills 那样有统一目录规范。第四是 MCP。它解决的是工具互联的标准化不直接定义技能层。如果你要同时接多个外部数据源或办公系统MCP 是很好的基础设施技能则构建在 MCP 之上。方案技能规范与模型绑定生态成熟度适合场景Claude Skills官方 SKILL.md 规范偏向 Claude 系列高快速落地技能库OpenAI Agents SDK需自行组织OpenAI 模型为主高需要强工具调用LangChain / LangGraph需自行抽象模型无关高复杂流程编排MCP不定义技能层模型无关中高多服务工具接入6.2 我的选型建议与常见组合我见过不少团队一上来就纠结“用哪个框架”其实优先级搞反了。我的建议是先定义技能规范再选实现工具。如果你是以 Claude 模型为主直接采用 Claude Skills 的目录结构把规范跑顺。如果你是多模型混合我更推荐自建一套轻量规范以 SKILL.md 为技能载体用代码实现发现和加载再通过 MCP 接入外部工具。这套组合保持了对模型的抽象不会被单一厂商绑死。另外一个务实的建议是成熟度 创新度。技能库这种基础设施稳定性比炫技重要。你可以在主路径上用最成熟的方案把实验性的编排放到旁路。等实验验证了收益再决定要不要提升它的优先级进入主路径。我自己的项目就是这个思路先跑通再优化避免一上来架构很漂亮但实际跑不动。最后说个个人体会。技能库这个东西看似是一个技术问题本质却是一个知识管理问题。它真正沉淀的不是代码而是团队对“一件事怎么做好”的共同理解。所以别急着堆技能数量先把最常用、最容易标准化的二三十个任务做成高质量技能比五百个粗制滥造的技能有用得多。维护技能库要像维护代码库一样有规范、有版本、有测试、有 review。做到这一层你的 Agent 才算真正具备了工程化的骨架而不是一个处处碰运气的大模型玩具。