agent-skills:把大模型从“嘴强王者”变成“动手达人”的工程化实践
最近一段时间,团队里讨论最多、落地最密集的一个词,就是 agent-skills。如果你关注大模型应用开发,应该也注意到一个明显趋势:光靠堆提示词让大模型“好好思考”已经不够了,真正拉开差距的是让智能体“会干活”。而 agent-skills 这个概念,恰好就是解决“会干活”这件事的关键抓手。
简单说,agent-skills 就是把原本写在系统提示词里的一堆抽象指令,拆解成一个个可复用、可组合、可测试的专项技能模块。每个模块像是一个“岗位说明书”,告诉模型在什么场景下调用什么工具、按什么步骤执行、遇到异常怎么处理。它解决的痛点非常直接:通用大模型在单轮问答里表现惊艳,但一旦进入多步骤、带工具、需兜底的真实业务流程,就会出现“答非所问”“步骤跳跃”“工具乱调”的问题。业界把这类现象总结为“模型很聪明,但不靠谱”。
这篇文章适合正在做 agent 应用、AI 工作流编排、RAG 系统增强,或者思考怎么把大模型接进业务系统的人。我会从概念拆解、技能设计、工程落地到问题排查,把这一套实践中摸出来的方法论完整梳理一遍。内容基于我自己的项目经验和团队踩坑记录,尽可能把能直接抄作业的细节都掏出来。
1. 内容整体设计与思路拆解
1.1 为什么智能体需要“技能”而不是“提示词”
先聊一个我反复跟人解释的问题:既然大模型已经能理解自然语言指令,为什么还要搞一套类似“技能”的结构化封装?
我自己第一次意识到这个问题,是在做一个自动化工单处理 agent 的时候。最初版本把所有规则都塞进一个超长的 system prompt,包括“你要先读取邮件、提取客户诉求、查询订单系统、判断售后类型、生成回复草稿……”结果模型在真实调用工具时经常乱序:订单还没查到就开始生成回复,或者查询工具用错了参数。后来我把每个环节拆成独立的 skill,比如read_email_skill、query_order_skill、draft_reply_skill,每个 skill 内部写好执行逻辑、输入输出格式、异常分支。效果立刻不一样了,模型不再“自由发挥”,而是像照着 SOP 执行一样稳定。
这个变化背后的逻辑其实很简单。大模型的注意力是有限的,一个塞满 50 条指令的提示词,模型很难分清主次,更别说在每一步都能记得该做什么。而 agent-skills 把“知道要做什么”和“知道怎么做”解耦了:模型的角色从“自己琢磨怎么干活”变成“按技能卡调用正确模块”。
打个生活化的比方,新手厨师拿到一本写满菜谱和厨房规则的书,依然会手忙脚乱;但如果给他几张独立的工序卡,每张卡片只写清一个步骤的原料、火候和时间,他按顺序执行就能做出一桌菜。agent-skills 就是给模型发的工序卡。
1.2 一套可落地的 skill 体系该由什么构成
在设计 agent-skills 体系时,我参考了不少开源社区的做法,也结合自己的业务场景做过几次重构。目前团队里跑得比较稳定的这套结构,主要由四层组成:
- 技能描述层:每个 skill 要有清晰的名称、功能说明、适用场景,方便模型在决策时快速匹配。
- 执行逻辑层:定义 skill 内部的具体步骤,包括调用哪些工具、按什么顺序、参数如何传递。
- 输入输出协议层:明确 skill 的输入参数 schema 和输出格式,确保技能之间可以顺畅衔接。
- 异常处理层:预判执行过程中常见的失败分支,给出兜底逻辑或错误提示。
这四层缺一不可。只写描述没有逻辑,模型还是不知道怎么做;有逻辑但没协议,技能之间无法串联;没有异常处理,一个环节出错整个流程就卡死。
另一个容易被忽略的设计决策是:skill 的粒度。我见过很多团队把 skill 拆得过细,比如一个“发送邮件”的 skill 还分成“写主题”“写正文”“点发送”三个,结果模型在决策时反而增加了负担。反之,颗粒度太粗,一个 skill 里塞了太多步骤,又回到了“大提示词”的老路。目前我用得比较顺的粒度标准是:一个 skill 对应一次完整的工具调用闭环,内部步骤尽量控制在 3–8 步,再多了就考虑拆成二级技能。
1.3 常见的设计误区和选型考量
在 agent-skills 落地过程中,有几个误区我几乎每次分享都会提到。
第一个误区是“用 skill 包装一切”。有些开发者把之前写好的提示词原封不动套上一层 skill 的外壳,这种转型没有任何意义。skill 的核心价值在于“结构化执行”,如果内部逻辑还是模糊的“请你分析一下这个问题”,那它本质上还是个提示词。
第二个误区是“只考虑正向流程,不考虑异常”。真实业务里,工具调用失败、参数格式不对、数据源返回空值,这些情况每天都会发生。skill 设计之初如果没有把这些分支写清楚,模型在遇到异常时就会自己“编”一个结果出来,这在业务场景里是非常危险的。
第三个误区是把 skill 当成一次性资产,不做版本管理。我们的实践是每个 skill 都有独立的版本号,变更后要在测试集上跑回归。否则就会出现“昨天还好好的,今天突然不行了”的情况,最后定位下来是某个 skill 的 prompt 被人改了一句话。
选型方面,如果你做的是轻量级应用,直接用代码里定义函数加描述字符串就能实现最简版 skill;如果团队规模大、技能数量多,建议考虑专门的动作编排框架,这类框架天然支持技能注册、校验和可视化调试。但不管用什么工具,核心设计思路是一致的。
2. 核心细节解析与实操要点
2.1 一个 skill 的内部结构长什么样
拿我们团队实际操作过的document_summarize_skill来拆解。这个 skill 的任务是读取一份外部文档,提取关键信息并按照特定模板输出摘要。
它的内部结构大致如下:
- 名称与描述:写明“对输入文档进行结构化摘要提取,生成不超过 500 字的摘要文本”。
- 输入参数:文档路径(必填)、摘要长度偏好(选填,默认 300 字)、输出语言(选填,默认中文)。
- 执行步骤:
- 读取文档内容,检测编码格式。
- 清理无关信息(页眉页脚、重复段落)。
- 按章节结构提取核心观点。
- 组装摘要文本,按模板输出。
- 异常处理:文档读取失败时返回“无法访问指定文档”;内容为空时返回“文档无有效内容”;输出超时则重试一次。
这样一个 skill 放到 agent 里,模型只需要传入正确的文档路径,剩下的事情由 skill 内部逻辑完成。这对模型来说非常友好,它不需要在每一步都思考“我接下来该干嘛”。
2.2 让 skill 能被模型“准确命中”的写法
在 agent 场景里,模型首先要做一件事:判断当前任务应该调用哪个技能。这个能力取决于 skill 的描述写得好不好。
我总结了一套描述规范,核心原则是“动词开头 + 对象明确 + 结果可验证”。比如“解析PDF提取合同中的甲方乙方信息并返回JSON结构”,就比“处理文档”清晰得多。好的描述可以直接告诉模型三件事:这个技能是干嘛的、输入是什么、输出是什么。
但描述也不要写得太长。我自己测试下来的经验是,描述超过两句话后,模型对多个 skill 的区分能力反而下降,因为关键词被稀释了。最好把“触发条件”也写进去,比如“当用户需要提取合同关键条款时使用”,这会大幅提升命中准确率。
还有一个很实用的小技巧:为每个 skill 准备 2–3 个典型的调用示例,作为 few-shot 注入到模型的决策上下文里。示例的格式是“用户需求 + 对应调用的 skill 名称”,模型学到的是映射关系而非具体内容。
2.3 工具调用与数据流转的注意事项
skill 往往涉及多个工具调用,工具之间的数据流转是容易出问题的地方。拿一个需要“先搜索资料再生成报告”的 skill 来说,搜索步骤的输出必须包含能供后续生成报告使用的结构化信息,而不是单纯的一段文本。我们会在搜索工具的返回 schema 里强制要求输出title、content、source_url字段。
数据流转方面,我强烈建议给每个 skill 的输入输出做 JSON Schema 校验。模型生成的结果格式一旦“飘了”,后续流程跟着崩。校验规则不复杂,核心就是必填字段判断、类型检查、长度限制。有一次我们线上报错,排查半天,发现是模型在输出摘要时多加了一个换行符,导致下游解析器把整个 JSON 都漏掉了。
另外,跨 skill 共享状态时,有些信息是通用的,比如用户 ID、场景上下文、历史消息摘要。如果每个 skill 都重新传一遍,既浪费 token 又容易不一致。我的做法是维护一个全局上下文结构体,每个 skill 只从里面读取自己需要的那部分字段,执行完再把自己的输出写回去。这个设计让技能之间保持了独立性,也能明显降低上下文 token 占用。
2.4 如何给技能做冒烟测试
如果把几十个 skill 直接接入生产环境,不先做验证,风险会非常大。我们的做法是先跑一轮“冒烟测试”,覆盖每类技能至少一组理想输入和一组异常输入,确认执行逻辑和异常分支都能按预期走通。
理想输入测试主要看两件事:步骤是否按顺序执行、最终输出是否符合 schema。异常输入测试则重点观察模型能不能正确触发兜底逻辑,比如工具超时后有没有返回可读的错误信息,而不是陷入“反复重试然后报错”的死循环。
对于涉及多个 skill 组合的复杂任务,我建议额外跑几组“链路演练”。比如一个完整的“用户投诉处理”流程,会依次触发“情感分析 skill -> 工单分类 skill -> 回复生成 skill”,链路演练会验证前一个 skill 的输出能否作为后一个 skill 的有效输入。这个环节最容易暴露字段命名不一致、类型对不上等集成问题。
3. 实操过程与核心环节实现
3.1 从零搭建一个可用技能库的完整步骤
下面以“自动生成项目周报”这个场景为例,完整走一遍 skill 的搭建过程。这个场景比较简单,但能完整体现从需求分析到测试发布的全部环节。
第一步,明确需求边界。我需要一个能读取本周提交记录、按团队维度归并、生成周报文本的技能。输入是时间范围,输出是格式化周报。
第二步,定义输入输出协议。设定输入参数为start_date和end_date,输出为一个包含“团队名”“完成事项”“风险点”“下周计划”四个字段的 JSON 对象。
第三步,设计执行步骤,大约四步:读取提交记录、按提交人分组映射到团队、聚合完成事项、调用本地模板拼接周报文本。
第四步,补全异常处理。如果指定时间范围没有提交记录,返回空数据提示;如果读取接口超时,重试两次后返回可读错误。
第五步,写描述。最终描述定为:“生成指定时间范围内的项目周报,包含各团队完成事项、风险点和下周计划。当你需要汇总团队工作进展时使用。”
第六步,注册到技能库并做冒烟测试。我先用一组最近一周真实数据测一遍,再故意传入一个未来日期,确认空数据处理逻辑正常。
整个流程走下来大概需要三十分钟。如果技能逻辑再复杂些,比如涉及多个数据源联查,时间会翻倍,但步骤框架是不变的。
3.2 配置一个可复用的技能模板实例
为了让技能搭建更高效,我整理了一份技能模板,所有新技能都基于这个模板填写。模板的字段包括:name、description、input_schema、steps、fallback、metadata六部分。
其中steps的写法是结构化的,每个步骤包含“动作类型”(调用工具、解析数据、生成内容)、“具体指令”、以及“成功/失败分支”。这样写的好处是,后续无论是人工审查还是自动化校验,都能清晰地看出执行链条。
metadata这个字段很容易被忽略,但它非常有用。我会在里面记录这个技能的创建人、创建日期、依赖的外部系统列表、最后一次测试通过的用例编号。项目大了以后,这些元信息能帮忙快速排查“某个技能突然变慢或者效果下降”是不是因为上游数据源变动导致的。
下面是模板的简化示例:
name: weekly_report_skill description: 生成指定时间范围内的项目周报,包含团队完成事项、风险点、下周计划。 input_schema: start_date: string end_date: string steps: - action: call_api target: git_commit_api params: start: {input.start_date} end: {input.end_date} on_success: - next_step: group_by_team on_failure: - next_step: retry_once - action: process_data logic: | 按提交人对应的团队字段分组, 去重合并为完成事项列表, 标记带有“blocker”标签的事项为风险点。 - action: generate_text prompt_template: | 基于以下数据生成周报: 团队: {team_name} 完成事项: {done_items} 风险点: {risks} 输出请包含下周计划占位符。 fallback: - 数据为空: "返回提示:当前时间范围内没有提交记录。" - 接口异常: "返回提示:提交记录服务暂不可用,请稍后重试。" metadata: version: 1.2.0 owner: alice dependencies: [git_commit_api, member_mapping_table] last_test_pass: 2024-11-083.3 多技能协同编排的实战方案
一个完整的业务 agent 通常需要多个技能协同工作,而不是只跑一个孤立技能。我们项目里有一个典型场景:客服智能助手收到用户咨询后,先判断用户情绪,再检索知识库,最后生成回复。
这个流程由三个 skill 协同完成:
sentiment_analyze_skill:判断用户消息的情绪极性。knowledge_search_skill:基于用户问题检索最相关的知识条目。response_generate_skill:结合情绪分析结果和知识条目,生成一个自然、符合企业口径的回复。
三个技能之间最容易出问题的地方是接口衔接。比如情绪分析结果如果是“愤怒”,回复生成技能就应该把语气调为更缓和,而不是照本宣科。为了做到这点,我们需要把情感分析技能输出的emotion_level字段传入回复生成技能,作为生成时的约束参数。
编排层面,我会维护一个简单的流程定义文件,描述动作的先后关系和条件分支。虽然用代码也能实现同样的控制流,但把编排信息独立出来,业务人员也能看懂和微调,而不需要每次改动都找开发改代码。
实际运行中,我强烈建议加“超时保护”和“步骤级别日志”。技能一旦卡住,超时保护能自动终止并返回用户可理解的提示;步骤日志则让每次调用过程都可追溯,出了问题能定位到具体是哪一步。
3.4 上线前要跑完的关键验证
我一般不会把没有经过完整验证的技能直接发布到生产环境。验证分为三个层次:单技能验证、链路验证、数据质量验证。
单技能验证比较直接,重点测试技能描述能被模型准确命中、执行逻辑没有漏洞、异常分支生效。链路验证则是把多个技能串联起来,模拟真实业务场景走通一遍。数据质量验证是最容易忽略的一个环节,我会拿一批历史真实数据,人工标注期望结果,再用技能跑一遍,对比输出是否达到预期。
比如对于周报生成技能,我会挑过去四周的数据,先人工预估每周周报的关键字段,再让技能生成,逐项对比。这种验证方式特别适合发现“模型自由发挥”导致的不稳定问题。因为如果技能描述和执行逻辑不明确,模型会对同一输入生成不同风格的内容,数据质量验证能快速暴露这一点。
测试完成之后,还要留出“灰度观察期”。我会先把新技能接入到 10% 的流量中,观察调用成功率、平均耗时、用户反馈(或下游系统报错率),确认稳了再逐步放量。这个习惯帮我避过很多次“全量上线后发现新技能和某个旧模块不兼容”的坑。
4. 常见问题与排查技巧实录
4.1 模型总是选错技能的排查方法
选错技能是 agent 应用里出现频率最高的问题。表现是:用户问一个问题,模型调用了完全不相关的技能,导致整个流程荒腔走板。
第一步,检查技能描述是否足够具体。如果描述里全是“处理”“分析”这类泛化词,模型很容易混淆。我会把描述改成“当用户需要 X 时使用”的句式,命中率会有明显提升。
第二步,检查技能数量是否过多。技能数量一旦超过 20 个,模型在做选择时的困惑度会显著上升。这时候要考虑把多个彼此相关的技能合并成一个大技能,或者增加一个“路由技能”,让模型先决定走哪个方向,再由内部逻辑定位到具体技能。
第三步,检查是不是缺少否定示例。有时候模型偏好的不是“最像”的技能,而是它见过的“高频词”技能。给技能描述加上“不要用此技能处理 XX 场景”,往往能纠正这种误配。
我在实际项目里遇到过一次特别典型的场景:用户问“帮我总结一下这份合同的风险条款”,模型却调用了“合同归档”技能。原因就是归档技能的描述里有“合同”关键词,而总结技能的描述重心放在了“摘要”上。把两个技能描述都补充了使用场景边界之后,问题就解决了。
4.2 技能内部步骤卡死或超时怎么处理
技能执行到一半卡住,除了等待超时之外,更可怕的是模型为了“完成任务”而自己脑补出一个结果。这种情况在涉及外部 API 调用的技能里最常见。
我的处理方案是三步:
- 在技能内部给每个外部调用都设置独立的超时时间,通用设置在 5–10 秒。
- 超时后的分支必须清晰,要么重试一次,要么直接走 fallback,不要给模型“自由发挥”的空间。
- fallback 内容要能让下游技能感知到“此处结果不可信”。比如在返回结果里加一个
reliability: low的字段,下游技能看到这个字段后可以调整自己的策略,比如增加提示语“以下信息可能不完整,仅供参考”。
另外,有些卡死不是因为外部接口慢,而是因为技能内部生成了一个超长中间结果,导致后续处理遇到 token 上限。这种情况需要在步骤之间加一个“结果截断”的逻辑,保证传给下一个步骤的内容在可控长度内。
4.3 技能升级后效果反而变差的归因思路
给技能添加了一个新步骤或改了一个参数后,原本稳定的效果却不稳定了。别急着回滚,先按下面顺序排查。
先看是不是描述和实际逻辑不一致。很多情况下,逻辑改了,但描述没同步更新,或者描述没变但示例还停留在旧行为,模型会按示例走旧路径。
再看是不是输入 schema 发生了变化。如果新增了一个必填字段,但调用方的请求没有传,技能就会报错。我会在 schema 校验失败的日志里加足够详细的错误信息,方便快速定位。
最后看是不是训练数据里曾经包含过相似任务的另一套执行逻辑。这个不好直接排查,一般靠 A/B 对比实验来确认。做法是保留两个版本,分别跑同一批测试用例,看哪个版本更稳定,再决定是保留新版本还是回滚。
4.4 真实项目中的问题速查表
| 问题描述 | 可能原因 | 解决方法 |
|---|---|---|
| 模型频繁选错技能 | 描述过于泛化,技能数量多 | 改写为“当用户需要 X 时使用”;合并相近技能,增加边界说明 |
| 技能调用工具时参数错误 | 输入 schema 定义不严格 | 增加参数校验规则,在描述中给出参数示例 |
| 外部接口超时导致卡死 | 超时未设置或 fallback 缺失 | 为每个外部调用设置 5–10 秒超时,补齐 fallback 分支 |
| 下游技能拿到空值 | 上游技能输出字段名不一致 | 统一字段命名,增加必填字段校验 |
| 模型生成结果格式漂移 | 输出模板约束不足 | 在生成动作中提供强模板,并在步骤尾部做格式校验 |
| 技能升级后变差 | 描述或示例未同步更新 | 检查描述、示例与逻辑是否一致,必要时做 A/B 对比 |
这张表是我在项目中最常参考的排查清单,也建议团队在积累新问题的过程中不断补充完善。每一条都是真实踩过的坑,能帮后入场的人少走不少弯路。
4.5 调优过程中的两个“反直觉”经验
第一,别总想着调 prompt。很多同学遇到技能效果不理想,第一反应是给系统提示词增加内容。但实际经验告诉我,当提示词已经超过一定长度的时候,与其继续加内容,不如拆技能。把一个大技能拆成几个小技能,模型的工作压力会肉眼可见地降下来。
第二,别忽视“示例”的力量。有时候描述怎么写都不够准确,问题可能出在模型本身就难以通过自然语言精确定位这个技能。给两个极端场景的示例,效果通常比重新改写描述要好得多。比如在技能定义里加上“例如用户说 A 时使用,用户说 B 时不要使用”,比反复解释技能边界直接得多。
另外一个经常被忽视的细节是,有些技能对输入文本的语言非常敏感。比如我的某个生成技能,输入是中文时输出质量稳定,但一旦输入夹杂了英文,模型偶尔会切换输出语言。这时候需要在描述或者内部逻辑里加一个“输出语言与输入语言保持一致”的约束。
4.6 如何评估一个技能库的整体健康度
当技能数量增长到一定程度之后,单点的排查就不够用了,还得关注整体层面的健康度。我在团队里定义了几个简单的评估指标,用数据来驱动技能库的演进。
第一个指标是“技能调用覆盖率”。统计一段时间内,全部请求中成功命中某个技能的比例。如果某个技能长期调用次数为零,可能说明它不在业务路径上,或者描述写得让模型永远选不到它。
第二个指标是“技能失败率”,聚集每个技能的工具调用失败、超时、输出校验不通过等异常情况。这个指标能快速定位不稳定模块。
第三个指标是“链路平均耗时”。技能的响应速度直接影响用户体验。对于外部接口调用较多的技能,这是需要持续关注的关键数。
把这些指标做成一张简单的趋势报表,每周看一眼,可以发现很多潜在问题。比如某次我注意到一个技能的平均耗时突然从 2 秒涨到了 15 秒,顺着日志排查后发现是上游接口新增了一个慢查询。如果没有数据监控,这类问题可能直到终端用户开始投诉都发现不了。
5. 技能库可持续演进的路径
5.1 从基础技能到复合技能的分层规划
随着业务复杂度提升,技能库会从二三十个变成上百个。这时候如果还是平铺结构,管理成本会非常高,模型做技能选择的准确率也会下降。
我目前采用的分层思路是:底层是原子技能,类似“调用搜索接口”“读取数据库”“发送邮件”,这部分技能尽量短小通用;上层是业务技能,比如“生成周报”“处理投诉工单”,这类技能内部会组合多个底层技能。
分层的最大好处在于,当底层工具更换时,影响的只是底层技能,业务技能不需要改动。比如团队从某搜索服务迁移到另一个搜索服务,只需要更新原子技能的调用逻辑,所有依赖它的业务技能自动受益。
对应的,在给 agent 配置可用技能时,一般只暴露业务技能,底层的原子技能不让模型直接调用。这样既减少了选择的复杂度,也避免了模型误用底层工具的风险。
5.2 版本管理与回归测试机制
技能是代码,必须用代码的工程规范来管理。我这里强调两点:版本管理和回归测试。
每个技能在合并到主分支之前,都需要通过语法检查、schema 校验和一轮核心用例测试。技能的任何改动都要记录 changelog,方便追溯。我曾经遇到过一个案例:某技能在某个版本后一直返回异常数据,花了半天排查才发现是两周前一次小的 prompt 修改改变了输出语气,导致下游字段解析失败。
回归测试集不需要特别大,但必须覆盖每个技能的真实业务典型场景。我们目前的做法是沉淀了一个“golden set”,里面有几十条真实的用户请求和对应的期望结果。每次技能库有改动,都会把这套 golden set 跑一遍,对比输出是否和预期一致。虽然不能做到百分百覆盖,但对保证上线质量来说已经够用了。
5.3 让业务人员也参与技能维护
最后分享一个另辟蹊径但真实有效的经验:让业务人员参与技能描述和测试,但不要让他们直接写执行逻辑。
很多团队把技能全权交给算法工程师来定义,但算法工程师对业务细节的了解往往不如一线业务人员。你有没有想过,为什么某些技能在测试集上表现很好,但实际业务效果却一般?很大概率是技能里的“业务判断”部分和真实场景有偏差。
我们现在的流程是:由算法工程师给出技能模板和规范,业务人员负责补充场景化的描述、输入示例和边界情况,最后由工程师实现和测试。这一轮协作下来,技能的命中率和实用性都有了明显提升,业务人员也会觉得自己在 AI 项目里有发言权,沟通成本大幅下降。
从这个角度看,agent-skills 不只是技术方案,它其实也是一种团队协作的接口。技能定义的过程,本身就是业务经验标准化和产品化的过程。把这一层做好,整个智能体的上限才会真正被拔高。
对我个人来说,做 agent-skills 最有成就感的一刻,是某个原先完全依赖人工经验才能跑通的业务流程,被拆解成一套技能库后,新同学看一遍技能描述就能接手运维。那一刻我突然意识到,真正有价值的不是某个 prompt 写得有多精美,而是把那些藏在老员工脑子里的“怎么做”沉淀成了系统可以理解和执行的东西。