
这几年做 AI Agent 相关的事有个感受特别明显真正拉开项目上限的往往不是模型选得多强而是你给 Agent 配了多少高质量的“skills”。前阵子我围绕agent-skills这个思路做了一轮系统梳理和实践从结构设计、开发流程到安全边界都过了一遍。今天把这段时间折腾出来的经验连同踩过的坑一起写出来。这篇文章不聊脱离实际的概念重点放在能直接落地的内容技能到底是什么、和 tools/子 agent 怎么区分、一个技能的内部结构该怎么搭、从零开发一个技能要走完哪些步骤、以及部署和调试时最容易翻车的几个点。无论你是刚接触 agent 开发还是已经在调多 agent 系统这篇文章应该都能给你一些参考。1. Skills 的本质Agent 能力模块化的关键拆解1.1 先搞清楚Skills 到底解决什么问题用大白话说skills 就是给 Agent 装上的“可复用技能包”。你不需要每次对话都重复把一整套专业流程塞进提示词而是把它封装成一个独立模块Agent 在合适的场景下自动调用。这件事为什么重要因为大模型的上下文窗口再大也是有限的。如果你把所有专业知识、操作步骤和约束条件都堆在 system prompt 里有几个实际后果长上下文会让推理速度明显下降token 成本也跟着涨。提示词中的关键指令容易被大量无关信息稀释Agent 在关键环节的表现反而变差。更新一套业务规则得去改全局提示词改动风险非常大。Skills 把这些内容挪到独立文件里按需加载。Agent 判断当前任务需要某项能力时再读取对应技能包。这个模式和人类的工作方式很像你上手术台时会调用外科手术技能写代码时会调用工程技能日常聊天时那些技能都处于休眠状态不会占用你的“思考带宽”。1.2 Skills、Tools、子 Agent 的功能边界很多人第一个问题是skills 和 function calling工具调用有什么区别我最初也把这两个概念混在一起直到踩了坑才彻底想清楚。Function calling 是模型与外部系统交互的通信协议核心是让模型输出结构化的调用参数。它更接近“接口层”解决的是“模型如何请求某个动作”的问题。Skills 则是一个完整的“能力单元”一个技能可以包含多个工具调用也可以不调用任何工具而只做知识检索或文本处理。比如“代码审查技能”就可能调用静态分析工具、运行测试脚本、检索项目规范文档最后把结果汇总。这是一整套流程不是一个孤立的函数。子 agent 则是由主 Agent 动态创建的运行实例有自己的上下文和提示词。通常在任务需要独立的工作空间或上下文隔离时使用。举一个直观的例子来说明三者的关系你让 Agent 写一份市场分析报告。function calling 负责“查数据”“生成图表”这些单一动作一个“市场分析”技能负责把这套流程串起来数据搜集、指标计算、行业对比、生成结论如果任务是“同时分析海外和国内两个独立市场”那可能拆成两个子 agent 并行处理各自维护独立的上下文。1.3 为什么 Agent Skills 越来越受重视从我的实践观察来看这波趋势的驱动力很实际。过去 Agent 项目做完一个 demo 容易但生产环境落地很难。原因在于Agent 的表现不稳定性、调试成本高、效果不可控。Skills 的模块化特性恰好从几个方向缓解了这些问题稳定性把专业流程固化成可预期的步骤而不是让模型临场发挥。可维护性技能独立更新不影响系统其他部分。可复用性一次封装多处使用甚至能在不同 Agent 之间共享。逐步构建生态技能包可以跨项目、跨团队、甚至跨组织共享类似 GitHub 上的开源代码库。这也是为什么像 Claude 的 Agent Skills 规范、Codex 的技能体系、各种 skills 平台会接连出现本质上大家都在推动 Agent 能力的“组件化”和“标准化”。2. 一个优质 Skills 的结构拆解核心细节与设计规范2.1 技能文件的基本组成一个规范的 Agent Skill 通常是一个独立目录里面包含核心三件套技能描述文档SKILL.md、脚本或代码文件、辅助资源。我平时常用的目录结构是这样的skill-name/ ├── SKILL.md ├── main.py或 main.js ├── assets/ │ ├── templates/ │ └── reference/ ├── requirements.txt或 package.json └── config.json各文件的作用SKILL.md是整个技能的“说明书”包含触发条件、使用场景、执行流程、注意事项。Agent 会根据这份文档判断何时调用该技能、怎么调用。脚本文件是具体逻辑的实现。assets存放辅助材料比如报告模板、参考数据、图片素材。依赖文件声明技能运行需要的第三方库。2.2 SKILL.md 的写法决定技能使用效果的关键SKILL.md 写得好不好直接影响 Agent 是否会在正确时机调用技能、能否正确执行完整流程。好的 SKILL.md 有四个层次的内容身份定义技能叫什么名字、核心功能、适用场景。要写得具体不要模糊。比如“本技能用于生成月度营销数据报告包含渠道数据抓取、趋势分析、异常告警”就比“本技能用于处理营销数据”好用得多。触发条件明确告诉 Agent 什么时候调用。这十分关键因为模型需要判断当前用户请求是否落在技能能力范围内。我一般会写 both positive triggers什么情况下应该用和 negative triggers什么情况下不要用。比如一个“合同审查技能”就要写明“当用户提供合租文本且要求审查风险时使用”同时写明“当用户仅询问合同范本时请勿使用”。执行流程用清晰的步骤序列描述技能的完整工作流要具体到每一步的输入输出、处理逻辑、判断标准。注意事项包括边界条件、已知限制、需要避免的误操作。写 SKILL.md 时最容易犯的错误是写得过于简略。有些人觉得模型能“理解意图”随便写两句话就行。但在实际测试中含糊的描述会导致 Agent 在关键决策点上的表现随机整个技能的效果大打折扣。2.3 技能代码的设计原则做小而专的执行器技能的核心代码应当遵循一个原则必要时才自己动手算判断交给描述文档执行交给脚本。这意味着脚本文件要尽量做“确定性”的工作数据读取、格式转换、API 调用、文件操作、计算汇总。复杂的决策逻辑尽量显式地写在代码分支里降低模型的决策自由度。举个例子一个“日志分析技能”的脚本里核心流程应该是接收日志文件路径或文本。按预定义规则解析日志格式。统计错误码频率、延迟分位数、异常模式。生成结构化输出。这些步骤一旦写成代码行为就是确定的。这样做的好处是Agent 的输出质量不再依赖模型临场发挥而是依赖代码正确性。2.4 依赖与资源配置技能可移植的关键为了让技能可以被共享和复用依赖管理要重视。我的做法是用requirements.txt或package.json明确声明依赖库及版本。在 SKILL.md 中写明运行环境要求Python 版本、Node 版本、系统依赖。将静态资源放在assets目录中避免硬编码外部路径。所有外部服务的密钥从环境变量读取不要写进代码或配置文件。还有一个容易被忽略的点技能要设计成“可重入的”。也就是说同一个技能在一次任务中可能被多次调用脚本不能依赖全局状态每次运行都应当是独立的。我在开发中遇到过一次事故某个技能使用了一个全局配置文件来保存中间态结果并发调用时数据互相污染排查了很久才发现问题。3. 实操全流程从零开发一个可复用的 Agent Skill3.1 阶段一需求分析与边界划定正式动手前先想清楚两个问题这个技能解决什么问题、什么时候不需要用它。以我最近做的一个“Redis 异常诊断技能”为例。项目背景是我们有一套自建的 Redis 集群经常出现内存突刺和延迟抖动每次排查都要人工看几十项指标。最开始想训练一个专门的模型来做诊断后来想想太重了。最终方案是把经验固化成一个技能配合监控数据让 Agent 自动完成诊断流程。需求分析阶段我把“诊断流程”拆成了四个子模块基础健康检查连接状态、CPU 使用率、内存占用。慢查询分析找出耗时最长的命令。内存分析查看 key 过期策略、大 key 分布、内存碎片率。延迟归因梳理可能导致延迟升高的因素。同时也定好了边界条件这个技能不做变更操作只做诊断和建议。因为一旦放宽边界去执行写操作风险就完全不同了。3.2 阶段二细拆执行步骤定义输入输出需求明确后接下来把整个执行流程落成文档。我在 SKILL.md 里把流程写成了这样接收目标 Redis 实例的连接参数host、port、password。执行基础指标采集脚本。针对发现的异常指标执行对应的专项诊断。汇总所有数据按模板生成诊断报告。输出报告包含异常结论、详细证据、可行的修复建议。每一步的输入输出都定义清楚。比如“基础指标采集”这一步输出的是序列化的 JSON 数据后续步骤从 JSON 里读取字段做判断这样的数据契约让整体流程非常明确Agent 也能把注意力放在步骤编排上避免临场发挥。3.3 阶段三编码实现的关键细节编码阶段最大的挑战不是写业务逻辑而是设计可靠的执行环境。我遇到了一个实际问题技能脚本运行在一个沙箱环境很多系统命令不可用直接运行 redis-cli 会失败。解决方案是用 Python 的redis库代替命令行工具来采集指标。核心代码的逻辑直接又实用import redis import json def collect_base_metrics(conn_params): client redis.Redis(**conn_params) info client.info() metrics { connected_clients: info.get(connected_clients), used_memory_human: info.get(used_memory_human), used_memory_peak_human: info.get(used_memory_peak_human), mem_fragmentation_ratio: info.get(mem_fragmentation_ratio), total_commands_processed: info.get(total_commands_processed), instantaneous_ops_per_sec: info.get(instantaneous_ops_per_sec), rejected_connections: info.get(rejected_connections), } return metrics这只是基础采集部分。完整的技能还包含慢日志读取、大 key 扫描、命令统计等模块。值得注意的是大 key 扫描必须使用SCAN命令而非KEYS否则在生产环境下会导致 Redis 阻塞这个细节在开发时就得想清楚。3.4 阶段四测试与效果验证技能开发完成后测试是必做的一步。我的测试策略分三层单元测试直接对脚本做单元测试验证输入输出是否符合预期。全流程模拟编写模拟的“对话剧本”按用户在不同场景下的提问方式测试 Agent 能否正确调用技能并得到合理结果。这一步能发现 SKILL.md 中触发条件描述不清晰的问题。生产灰度经过前两步验证后放在真实场景小范围试用。测试中我发现一个很有意思的问题SKILL.md 里写的“当用户提到内存突增或内存占用过高时使用本技能”但用户实际描述问题的用词可能很随意。后来我把触发条件写得更宽泛加入了“Redis 性能下降”“查慢的情况”“诊断 Redis”等多种描述效果好了很多。我把这样的前后版本测试对比记录在一个速查表中测试场景原版触发词优化后触发词命中率变化直接命令式“诊断 Redis”“诊断 Redis”原始已命中症状描述式“帮我看看 Redis 为什么慢”补充“Redis 变慢、延迟高”从 62% 升到 95%间接提问式“我们线上缓存频繁出问题”补充“缓存抖动、内存爆炸”明显改善3.5 阶段五发布与迭代技能测试通过后将它收进技能库并在配置文件中注册。我的做法是在主 Agent 的配置里维护一份技能索引标明该技能的关键触发描述和关联场景。这样主 Agent 在思考时能快速扫描候选技能集不用加载所有技能。发布之后仍要持续观察。技能上线后我会定期从 Agent 日志中抽取出调用记录分析哪些请求激活了技能、哪些请求本应触发但没有触发、有哪些误用。每个迭代周期都根据日志反馈调整 SKILL.md 的描述词语和触发条件。这个环节说实话花的时间比开发本身还要多但效果提升是最显著的。4. 从架构视角看 Skills定位、协同与安全边界4.1 Skills 在 Agent 系统中的定位在我的架构视图里一个完整的 Agent 系统可以抽象成几层记忆层保存长期信息和状态。工具层封装原子操作对外提供接口。技能层组合工具与知识形成半自动化的任务执行能力。编排层思考、计划、决策调度技能和工具。Skills 正好处在工具之上、编排之下的位置。它既不像裸工具那样单一也不像编排层那样需要完全动态的智能。它相当于是“半成品”的活动模块执行路径大体固定但在具体参数、分支选择、汇总方式上保留灵活性。这个分层的价值在于把稳定的工作流固化成技能把不确定的创造性任务留给编排层。这样整个系统的行为是可预期的同时又保留了智能调度的弹性。4.2 多 Agent 协作与 Skills 的协同关系在多 Agent 场景下我对 skills 的使用有一个重要原则每个 Agent 应当有自己擅长的技能集同时可以按需共享通用技能。比如我曾经构建过一个数据处理项目包含三个 agent数据采集 Agent负责从多个数据源获取数据拥有各数据源的抓取技能。数据分析 Agent负责数据清洗和统计建模拥有数据处理技能。报告生成 Agent负责生成业务报告拥有报告撰写技能。每个 Agent 的知识库中装配相应的技能避免把所有技能都塞给一个 Agent。这样做的好处很实际各 Agent 的上下文更精简决策质量提高。技能的安全边界更清晰不会出现“分析数据时误触发了写操作”的情况。技能库可以独立演进某类技能更新不会影响其他 Agent。4.3 安全边界Skills 可能带来哪些风险这是必须认真讨论的问题。技能给了 Agent 更强的执行能力但同时也放大了潜在危险。我在实战中总结了几个高风险点权限过度技能以 Agent 的身份执行数据库操作、文件写入、外部 API 调用。如果技能代码里包含高危操作删除表、批量写文件而触发条件又过于宽泛就有误操作的可能。务必要在技能代码里做二次确认。上下文注入技能处理外部输入的数据时可能被恶意内容引导偏离预期行为。比如一个网页抓取技能如果抓取到的页面内容里嵌入了“忽略之前的指令”这类引导文案模型可能中招。解决方案是尽量把数据处理逻辑代码化减少模型直接接触原始文本的环节严格隔离指令和数据。资源滥用过于复杂的技能可能消耗大量 token 或执行时间。一个常见的问题是 Agent 在没有必要的情况下反复调用技能。我在配置技能时通常会加入一层调用频率的约束并在 SKILL.md 中提醒 Agent“只有在确实需要时才调用”。信息泄露技能可能接触到用户的敏感信息API 密钥、业务数据。在技能输出阶段要加入脱敏策略日志系统里也不能打印完整的敏感字段。总结一句我认为比较重要的话技能给 Agent 的“手”但“手”能做什么取决于你在代码和描述文档里设定的边界。5. 常见问题与排查技巧实录5.1 触发时机不准这是技能开发中最常见的问题。表现为用户明明需要某种能力Agent 却不调用对应的技能或者不需要时频繁误调用。排查思路也比较统一检查 SKILL.md 中的触发条件是否过于严苛或过于宽泛尽量使用贴近真实用户语言的描述。观察 Agent 的“思考过程”看它当时是否已经识别到了技能但没有调用可能是技能的描述不足以让它产生足够信心。简化技能描述的开头部分让模型快速理解核心功能。5.2 技能内部报错技能代码在沙箱环境中运行时经常会遇到环境依赖不完整、权限不足、路径错误等问题。经验是在技能目录中放一个自检脚本验证依赖是否完整、系统命令是否可用、关键路径是否存在。这样 Agent 在启用技能前可以先运行自检把问题提前暴露出来避免中途才报错。5.3 输出格式不稳定技能返回的结果有时候被模型重新加工导致格式漂移。我用的方法是让技能返回严格结构的 Markdown 或 JSON并在 SKILL.md 里强调“直接使用技能输出结果作为最终回答的主体不要随意删改”。同时在输出层做一个格式校验如果不符合预期就重新调用技能。5.4 上下文过长和 token 消耗偏高如果你的技能在每次调用时都要塞入大量参考文档token 消耗自然会上去。选用方案是通过索引只加载相关片段而不是全量大文件。设置缓存的机制同一会话内多次调用同一技能时复用初次加载的中间结果。把大段辅助资料放进 assets按需引用不要塞进主上下文。5.5 常见问题排查速查表症状排查方向处理建议技能完全不触发SKILL.md 触发条件描述不匹配用用户高频话术重写触发条件技能触发后中途卡住代码依赖缺失或运行环境受限添加自检脚本预先检查依赖技能结果被模型乱改输出契约约束不够强返回结构化数据并强约束使用方式同一技能会话内重复执行缺少调用状态记录以会话 ID 维度维护调用的幂等标志多个技能互相干扰全局状态污染或描述混淆提高技能隔离性独立上下文和配置写在最后的一点个人体会这几轮 agent-skills 的实践做下来我最大的体会是技能开发与其说是写代码不如说是在想办法把含糊的需求“讲清楚”。SKILL.md 写得越清楚Agent 的行为就越稳定。任何一个模糊的词都可能成为生产环境里的一个意外。如果你准备在自己的项目里引入 skills我的建议是起步时不要贪多。先把手头最频繁、最容易出错的三五个任务抽出来做成专门的技能运行一段时间观察效果再迭代扩展。技能不是越多越好而是越准确越好。开始阶段慢一点后面系统的运行会越来越顺畅。后续如果有机会我还会继续分享技能库的跨项目复用方案、更复杂的多技能协同编排以及更细致的测试方法论。希望这波内容对正在做 Agent 开发的朋友有实际帮助。