
1. 先把 agent-skills 这个事说清楚技能不是插件是 Agent 的能力边界这两年只要聊到 Agent绕不开的就是怎么让模型干实事。模型再聪明不接上工具、不落进业务流程它就只是个聊天框。而 agent-skills 这个命名的项目核心解决的正是“怎么把能干的事结构化成 Agent 能理解和执行的能力”简单说就是给 Agent 做一套可注册、可调度、可评估的技能库。先说个我自己的观察。早期做 Agent 的时候大家喜欢把所有逻辑都塞进 system prompt让模型自己发挥。结果就是同一个问题今天答得好明天就拉胯换个模型行为完全漂移。后来开始接工具调用但工具是散的一个模型动辄挂几十个 function描述写不好就互相打架。等到技能Skill这个概念出现我才觉得真正找到了对的抽象层级。技能不是一个函数不是一段提示词而是把一个完整任务域里“什么时候用、用哪些工具、按什么顺序、产出什么”这件事固化成标准件。这个项目名字取得很准agent-skills 强调的就是技能本身。它不是某个具体业务而是承载技能定义、技能注册、技能编排的一套方法论和代码结构。如果你正在做 Agent 类产品或者准备把自己手里的重复工作交出去这套思路值得完整过一遍。我见过很多团队卡在同一个地方模型能力够了工具也写得出来但 Agent 就是一进真实场景就崩。大多数问题根本不是模型笨而是技能边界没划好。技能定义得清晰模型就知道什么时候出手、什么时候该停技能定义得模糊模型就只能瞎猜。所以这篇文我把技能这块从头到尾拆开讲包括技能怎么写、怎么被调度、怎么评估效果附带我这几年踩过的坑。2. 技能目录怎么搭从命名到参数规则越靠前越省心2.1 一套可用的技能声明长什么样技能声明是所有逻辑的地基。常见做法是定义成一个 JSON 结构里面包含技能的名称、描述、输入参数、触发条件以及执行函数。看起来就是个配置文件但这里面的讲究比大多数人想的多得多。先给一个我最常用的技能声明结构你们感受一下{ skill_name: git_commit_review, description: 检查当前git仓库的未提交变更评估变更质量并生成提交说明建议适用于开发者准备提交代码前的自查场景。, tags: [git, code-review, workflow], parameters: { type: object, properties: { scope: { type: string, description: 检查范围可选值为staged或all默认为staged, enum: [staged, all] }, strictness: { type: integer, description: 检查严格程度1-5数字越大越严格, minimum: 1, maximum: 5, default: 3 } } }, handler: skills/git_commit_review/handler.py, required_skills: [git_status_check], timeout_seconds: 30 }这个结构看起来平淡无奇但每一个字段都是我用实际教训填出来的。首先是 description这块一定要写清楚“适用于什么场景”。模型没有场景感它只看到文字。你写“检查git变更”它可能在任何提到 git 的对话里都触发你改成“适用于开发者准备提交代码前的自查场景”它就知道这个技能是有应用前提的。再说 parameters。这里有个容易翻车的习惯能加默认值的都加默认值而且把取值范围卡死。Agent 在执行时会根据用户的需求来填参如果参数是自由文本模型很容易填出你函数根本处理不了的内容。范围限定好模型的选择空间小了错误率自然降低。handler 字段是真正执行代码的路径。我建议一个技能对应一个独立目录把执行逻辑、资源文件、测试用例都收在同一个目录里。有人图省事把多个技能共用一个 handler短期内看着省代码后期想单独调整某个技能的行为牵一发动全身非常痛苦。2.2 技能描述怎么写才能让模型“看得懂”技能描述是整个技能目录里最重要的文本也是大部分人写不好的地方。模型不像人它不会“猜”你的意图它只会从字面意思去匹配。描述写得太宽泛模型会误触发写得太窄模型又找不到该用的技能。这里有个平衡点。我的经验是描述要包含三要素做什么、在什么场景下做、做完产出什么。用一个句式来套就是“当[场景条件]时使用本技能[完成动作]输出[可交付物]”。举例对比一下差“计算加班时长”好“当用户需要核算某段时间的加班小时数且能提供打卡记录或工时明细时使用本技能完成总时长汇总与调休建议输出一份包含每日加班明细的表格”第二种写法里模型能准确判断“现在该不该用这个技能”。我们做过一次实验把技能描述全部按这个句式重写之后技能触发的准确率从 72% 提到了 89%效果非常明显。另外不建议在描述里堆太多术语模型不是行业专家它是文本匹配器。你用内部黑话写描述它匹配不上就瞎猜。宁可多写两行平实的解释也别用只有你自己看得懂的缩写。2.3 技能拆分的粒度直接决定 Agent 的灵活性技能粒度是另一个容易踩的坑。我见过有人把“给客户发邮件”做成一个技能里面包含查联系人、写正文、查附件、发送四个步骤。也有人反过来把“查联系人”做成技能“写正文”又做成技能Agent 需要自己编排它们。两种做法都有问题前者太厚技能复用性差后者太薄模型编排难度大调试起来也累。我自己的经验是把技能的粒度控制在“一个完整但单一的任务”上。什么是完整但单一就是“你要的结果是明确的过程里可能涉及多个工具调用但它的输入输出边界是清晰的”。拿上面那个邮件的例子来说“给客户发邮件”其实拆成两个技能更合理一个“生成邮件草稿”一个“发送邮件”。“生成邮件草稿”需要理解上下文、组织语言“发送邮件”是纯动作。拆开以后“生成邮件草稿”可以被复用到其他场景比如生成周报、生成公告而“发送邮件”也能被别的技能调用。这样技能之间可以通过组合完成更复杂的任务而不是每个新需求都从零开始写代码。3. 技能如何被调度意图路由、前置校验与多技能编排3.1 一次触发到执行的完整链路技能定义的再好调度机制跟不上也是白搭。我现在开发的 agent-skills 方案里整个调用链路分四步意图识别、技能匹配、参数填充、执行与反馈。意图识别是第一步模型拿到用户的输入先判断这个输入属于哪个任务域。这一步一般不做细粒度的技能选择只确定大方向。比如用户说“帮我看看这周代码变更有没有问题”意图识别先把方向定到“代码审查”然后进入技能匹配阶段。技能匹配阶段做的事情是把意图和技能描述做相似度计算再加上一些规则约束。比如某个技能只允许在工作区初始化之后使用那在工作区未初始化时即使模型觉得技能合适也要先被规则挡住。规则优先于模型判断这是我反复强调的一点——模型的概率输出永远不如一条硬规则可靠。参数填充阶段由模型根据用户输入和技能的参数定义生成具体调用参数。这一步最容易出错所以参数定义是否清晰直接影响成功率。匹配通过后进入执行阶段代码真正跑起来拿到结果再返回给模型做最终回答。这套链路最好做成可观测的。我自己的做法是在每个阶段都输出日志记录“当前命中了哪个技能、匹配分数多少、参数怎么填的、执行耗了多久”。没有这套日志出问题的时候你就是盲人摸象只能靠猜。3.2 多技能协作时的优先级怎么定当你的技能库里有几十个技能之后新问题就来了用户提一个请求可能同时命中了三个技能该用哪个模型自己选大概率每次选的都不一样你没法保证体验的一致性。我给 agent-skills 设计了一套优先级机制总结下来就三个层级明确触发词优先。用户直接点名的操作比如“请生成SQL”那么生成SQL的技能拥有最高优先级其他技能全部让路。规则条件次之。比如用户当前正处于某个业务流程的特定阶段那该阶段对应的技能优先。模型语义匹配兜底。前两类都没有命中才使用模型的语义相关度来决定。这套优先级机制的核心思想是“能用规则就不靠模型”。模型可以做决策但不能让它做关键决策关键时刻还是要靠确定性代码把住边界。多技能协作时还有一个常见问题一个技能执行完了要不要自动触发下一个技能我的建议是谨慎。技能链一旦自动串联中间任何一环出问题后面的全废了而且很难定位。我更推荐让 Agent 在技能执行完成后把结果整理给用户由用户确认是否继续下一步。多一步确认体验上慢了两秒但稳定性和可控性提升了一大截。3.3 所谓“技能编排”本质是状态管理技能编排做多以后你会发现它本质上是状态管理。用户在一个任务里来回操作每一步都在改变当前上下文而技能是否可执行、参数怎么补都依赖上下文状态。所以 agent-skills 一定会带一套状态管理器记录当前任务域、已完成步骤、已获取的字段值、当前的跳过条件等。我见过不少人忽略状态管理把所有上下文都塞在对话历史里靠模型自己“记住”进行到哪了。这在两三轮对话内还行对话一长模型就开始糊涂。你问它刚才执行到哪一步它给出的回答自己都不确定。把关键状态显式地存到状态管理器里模型每一步只需要看当前状态不需要去猜历史准确率会明显提升。这里我提供一个简单的状态示意图用代码描述更直接class SkillState: def __init__(self, session_id): self.session_id session_id self.current_domain None self.completed_steps [] self.collected_params {} self.awaiting_confirmation False def mark_step_done(self, skill_name, result): self.completed_steps.append({skill: skill_name, result: result}) def can_execute(self, required_skills): return all(s in self.completed_steps for s in required_skills)这段代码很简陋但它体现了一个关键点状态是显式的不是靠模型“上下文感知”推出来的。代码里记录 completed_steps每当一个技能执行完毕就把结果存进去新技能执行前检查 required_skills 是否都已完成。这样编排逻辑就变得可判断、可调试而不是一团模糊的“模型觉得可以了”。4. 技能质量怎么量化评估集、召回率与回归测试4.1 用“场景-目标-断言”结构沉淀评估集技能光写出来不算完你得知道它能用、好用、一直好用。我一直主张技能项目必须配套评估集而且要像维护代码一样维护评估集。没有评估集的技能库就像没有测试用例的代码库它可能是坏的但你不知道它什么时候坏。我习惯用一个叫做“场景-目标-断言”的三段式来写评估用例场景描述用户输入的上下文包括用户身份、当前状态、历史操作等。目标描述用户希望达到的最终结果。断言描述模型在正确行为下应该输出什么或者技能应该返回什么。举个例子针对“用户查询订单物流”的技能场景用户账号存在多个未完成订单用户没有指定具体订单。目标用户想了解最近订单的物流状态。断言Agent 应主动询问用户指的是哪个订单不能直接返回某个随机订单的信息如果用户补充了订单号则返回该订单的物流信息。这种结构化的评估用例既可以用来自动化跑回归测试也可以在人工复盘时快速定位问题。我每隔一段时间就会跑一遍评估集看看技能的准确率有没有回退。一旦发现回退立刻检查是模型版本升级导致的还是技能描述或代码被改动导致的。4.2 从老项目里快速建技能先抄后改回顾业务日志很多团队不是从零开始做 Agent而是已经有了一堆脚本、服务、流程想把它们“技能化”。这时候不需要推倒重来最好的办法是从历史日志里反推技能边界。我自己做过一次实践把过去三个月的对话日志翻出来找出那些最终成功解决了用户问题的会话标记出其中模型调用了哪些工具、以什么顺序调用、靠什么判断调用时机。然后把这些模式抽出来把共性的部分固化成技能非共性的留作动态流程。这个过程很像考古能从过去成功的经验里看出业务真正的形态。这样做还有一个额外的好处通过回溯日志你能知道用户的高频需求集中在哪技能库的优先级怎么排。不要一上来就想把业务的所有场景全部技能化那是给自己挖坑。先覆盖 80% 的高频需求剩下的 20% 让 Agent 自由发挥跑一段时间再根据日志补技能这样既能快速上线又能逐步完善。4.3 评估指标别只看成功率要拆开看很多人在评估 Agent 技能时只看一个指标最终成功率。也就是用户提了需求Agent 最终有没有完成。这个指标太粗了它会把很多中间层的问题隐藏掉。我至少会拆出四个指标来观察触发准确率该触发的时候有没有触发不该触发的时候有没有误触发。参数填充准确率参数有没有填对、填全。执行成功率技能代码本身有没有抛错。结果满意度技能执行完了返回的结果用户认不认。这四个指标是递进的关系。触发准确率决定 Agent 有没有找对技能参数填充准确率决定它有没有把事说清楚执行成功率决定代码层面有没有 bug结果满意度决定业务层面有没有价值。任何一个环节掉了链子最终结果都不会好。而且这四个指标分开看你才知道该修哪里。5. 常见问题与排查技巧实录5.1 技能不触发、误触发、触发后失败的处理先说技能不触发的问题。模型根本没调用这个技能最常见的原因是技能描述和用户意图之间的语义鸿沟太大。用户说的是“帮我把这份合同的重点标出来”技能描述里写的是“对文本进行摘要提取”模型匹配不上。解决办法不是改模型而是改描述把用户常用的口头说法也吸收进描述中。误触发的情况通常是因为技能描述太宽泛。比如一个“生成报告”的技能描述里写“适用于需要生成报告的场景”这等于没写。几乎所有工作场景都能算“需要报告”。把它改细明确报告的类型、格式、目标受众误触发率会大幅下降。触发后失败一般集中在参数填充和执行代码两个环节。参数填充失败去查模型给出的参数值是不是在枚举范围内如果不在回头把参数定义里的描述再写清楚一点。执行代码失败好好看异常日志Agent 场景下尤其要注意并发和权限问题多个技能同时跑共享状态很容易被意外修改。5.2 我建议每个项目必做的三件小事最后分享三个心得都是实操中砸过坑换来的。第一技能库一定要做版本管理。技能的描述、参数定义、执行代码任何一处的改动都会影响 Agent 的整体行为。没有版本管理你根本不知道是哪一个改动导致了线上行为变化。我的做法是每个技能独立目录整个技能库放到 git 仓库管理每次改动都提交上线前可以随时回滚。第二一定要留足执行日志。日志是排查问题的第一手证据。我在执行链路里把所有关键决策点都打了日志包括模型匹配了哪个技能、置信度多少、选了哪些参数、代码执行耗时、返回结果大小、有没有触发异常。没有这些日志遇到问题只能靠复现而 Agent 的行为是概率性的复现往往非常难。第三给技能设置超时和降级。Agent 技能调用外部服务时超时是常态。我在每个技能定义里都加了 timeout_seconds并在执行器里兜底超时后走降级方案比如返回一个友好提示让用户重试或者换一个备选技能。千万不要让一个技能卡住整个 Agent 的回复用户等不起。我还想再多说一句技能目录的维护是一个持续过程不是上线就完事。业务在变用户的表述在变模型的能力也在变。我自己的节奏是每周看一次执行日志每月跑一轮评估集把变化及时吸收到技能描述和代码里。现在这个技能库经过三轮迭代之后已经明显比最初版本稳定太多这也让我更加确信Agent 这类系统的成败不在于模型的某个瞬间的“灵光一现”而在于你是否把一个一个技能打磨得足够可靠。这些技巧我都在项目里试过尤其是把描述改成“场景-动作-产出”句式之后效果立竿见影。如果你正在做类似的 agent-skills 项目建议从一个小技能开始练手跑通整条链路再慢慢扩充。等你自己亲手填过一个坑就会明白这些规则背后真正的分量。