2026/10/17 8:15:24

Agent Skills:从概念到工程落地的完整实践指南

Agent Skills:从概念到工程落地的完整实践指南 Agent 圈子里聊得最多的词这两年已经从“提示词工程”悄悄换成了“Agent”本身再往前一步就是“Agent Skills”。我见过不少团队大模型接了一堆工具流程也跑通了但做出来的 Agent 总给人一种“差一口气”的感觉要么任务一复杂就开始乱调度要么换个场景稍微改改需求整个链路就散架了。回头看问题往往不是模型不够强而是没把“技能”这个最小单元想清楚。这篇文章想做的就是把 Agent Skills 从概念到落地完整梳理一遍。不绕弯子不堆概念直接拆开讲它解决什么问题、内部长什么样、怎么一步步做一个能用的 Skill再往深了聊工程上怎么让它稳定扛住生产环境。适合刚接触 Agent 开发的工程师也适合已经上手但总觉得设计上哪里不对劲、想回头重新整理架构的人。读完之后你至少能回答两个问题Agent 的能力边界到底该怎么划一个 Skill 从写好到上线中间要经历哪些环节。1. 先想清楚Agent Skills 到底解决什么问题1.1 为什么 Agent 总是出现“边界失焦”先看一个普遍现象。很多团队早期做 Agent习惯把能力直接封装成“工具函数”暴露给模型。比如天气查询、计算器、发邮件全是扁平的 Tool 列表。模型需要什么就调什么看起来自由度很高实际跑起来问题一大堆。问题集中在几个地方。第一Tool 本身没有任何业务语义模型只知道“有个函数叫 get_weather”不知道这个函数是该在什么场景下优先使用、参数怎么组织才合理、返回结果之后下一步该做什么。第二工具多了之后模型的选择空间变大误调度概率直线上升。真实场景里经常出现用户问“帮我写一篇行业分析报告”模型先去调了某个搜索工具搜了一堆碎片信息然后就不知道下一步该干嘛了。第三每条 Tool 都假设调用方也就是模型已经理解业务上下文这恰恰是最不成立的假设。Agent Skills 的设计初衷就是给模型的“能力”加一层更厚的封装。它不只是告诉模型“你有这个函数可用”而是明确表达“你在什么情境下、为了完成什么目标、可以按什么步骤调用这组能力”。换句话说Tool 是零件Skill 是带着使用说明书和工艺流程的工位。Agent 不再需要从零理解每个函数怎么拼装它只需要识别当前任务匹配哪个 Skill剩下的细节交给 Skill 内部去处理。1.2 Skill 与 Tool、Subtask 的边界和 Agent Skills 容易混淆的概念有不少最常见的是 Tool工具和 Subtask子任务。把这三者的关系理清楚后面的设计才不会跑偏。Tool 是最原子的一层通常就是一个函数、一个 API 接口、一次查询动作。它不做决策没有状态执行完就返回结果。Subtask 则是一个更上层的概念形容的是 Agent 在完整任务中拆分出来的执行阶段比如“收集资料”“分析数据”“生成结论”这些阶段本身可能由多个 Tool 或多个 Skill 组成。Agent Skills 恰好落在两者之间它是一组围绕某个具体目标组织起来的、可独立调用的能力封装。从使用方式上看更直观。Tool 是一次性的、无状态的Skill 是结构化的、可复用的它内部可以包含多个 Tool 调用、一段决策逻辑、Prompt 模板甚至内嵌一套小的状态机。Subtask 是流程层面的编排单位Skill 是能力层面的交付单位。举个例子做一份行业分析报告“查资料”是 Subtask“用某个数据源拉取指定行业过去三年的市场规模并生成趋势描述”就是一个 Skill。前者是任务拆解的逻辑骨架后者是可被复用的能力模块。对比维度ToolAgent SkillSubtask粒度细单次动作中围绕目标组织粗流程阶段是否决策否只执行部分决策内部有逻辑是拆解目标复用性高但无语义高带业务语义低依赖场景典型例子调用一个查询接口“生成行业趋势摘要”“先分析再产出”这三个概念不是互斥的实际系统里它们经常嵌套出现。一个 Subtask 流程里会调用多个 Skill一个 Skill 内部会调用多个 Tool。理解它们各自的定位设计的思路就会清楚很多。2. 拆解一个 Skill 的内部结构2.1 四个核心组成部分把一个 Skill 拆开看它绝不是一个“带说明的函数”。一个设计良好的 Skill通常由四个相互独立又彼此支撑的部分组成。第一部分是技能定义文档Skill Definition。这是给模型看的说明书不是给人看的接口文档。它描述这个 Skill 是做什么的、在什么条件下激活、不适用于什么场景、输入输出大概长什么样、使用过程中有哪些需要特别注意的约束。写得好不好直接决定模型能不能在正确的时机选中它。第二部分是执行器逻辑Executor。这部分是真正干活儿的代码负责调用外部 API、处理数据、完成计算。它不需要理解业务目标只需要按明确的契约执行。执行器应该保持“傻”和“纯”即接收输入、处理、返回结果不持有状态不私自做超出范围的决策。第三部分是输入输出契约IO Contract。Skills 不是给人写的是给模型写的所以输入输出的 schema 必须极度清晰。哪个字段必填、哪个可选、值的格式是什么、超出范围时返回什么错误这些都要提前定好。契约是执行器和模型之间的共同语言契约含糊两端都会乱。第四部分是自省机制与日志链路Traceability。这是最容易被忽略、但生产环境里最重要的一块。每次调用 Skill它的输入摘要、决策路径、中间结果、耗时、报错信息都必须有迹可循。否则一旦 Agent 在复杂任务里行为异常你连定位问题都无从下手。2.2 为什么技能文档比代码更关键很多初学 Agent Skills 的人有个误解把精力全放在写执行器代码上文档随便糊弄几句。代码写得再漂亮如果技能定义文档写得不好模型根本不知道什么时候该用这个 Skill。本质上代码是给人执行的而技能定义文档是给模型做决策的。方向搞反了效果天差地别。写技能文档要遵循一个原则面向模型的决策场景写而不是面向人的阅读习惯写。要写清楚正面触发条件和反面排除条件。比如“当用户需要生成结构化报告摘要时使用此技能”是正面触发“当用户仅要求闲聊或即时回复不涉及深度分析时不要使用此技能”是反面排除。反面排除往往比正面触发更重要它能避免模型在错误场景里硬套 Skill。另一个容易踩的坑是文档里写太多抽象描述缺少具体的输入输出样例。模型不是靠理解抽象概念来调用工具的它靠的是模式匹配和类比。文档里给一个“输入什么、输出什么”的示例比写十句话都管用。凡是我见过的高质量 Skill定义文档里一定会配备至少一两个典型输入输出样例让模型一看就知道这个技能适合处理什么样的任务。3. 从零实现一个真实 Skill完整实战3.1 场景定义与功能边界这一节我用一个实际开发过的场景来走完整流程。模拟项目 X做一个面向内部运营团队的“竞品动态摘要” Agent它需要每天盯着几个竞品的信息源抓取更新生成结构化的摘要报告。拆出来一个核心 Skill“竞品动态周报生成”。先定义功能边界。这个 Skill 的输入很简单竞品名称列表、时间范围、报告语言。输出是一份符合固定模板的周报包含“行业动态”“竞品动作”“风险提示”三个部分。接下来划清楚它不做什么。它不做实时抓取——抓取是另一个数据管道负责的它不做趋势预测——那是另一个分析模型的任务它不做深度报告只做摘要。把边界划清楚才能让模型在合适的时候选中它而不是让它变成一个包揽一切的万能技能。3.2 实现执行器代码功能边界定好之后开始写执行器。按之前的原则执行器要保持“傻”和“纯”只做数据读取、格式化、调用大模型补全摘要这三件事。Python 代码示例如下def execute(competitor_names: list[str], start_date: str, end_date: str, language: str zh) - dict: # 1. 从内部数据管道按时间和范围读取已经抓取入库的竞品信息 raw_items query_competitor_feed(competitor_names, start_date, end_date) if not raw_items: return {status: empty, message: 所选时间范围内没有采集到目标动态} # 2. 拼装摘要 Prompt注意不是让模型自由发挥而是按固定结构输出 prompt build_summary_prompt(raw_items, competitor_names, language) summary call_llm(prompt, temperature0.3, max_tokens1200) # 3. 对模型输出做基础校验防止空内容或格式错乱继续往上走 validated validate_summary_structure(summary) return {status: success, summary: validated, source_count: len(raw_items)}这段代码有几个细节值得注意。第一步查数据时函数返回了空结果是给上层一个明确的“空”信号而不是直接抛异常。因为对 Agent 来说“没有数据”本身也是一个合法结果它可能重新调整时间范围再试而不是整个流程崩掉。第二步拼 Prompt 时temperature 特意调低因为摘要任务需要稳定输出不需要创造性。第三步校验结构防止模型偶尔输出格式乱的文本。3.3 编写技能定义与 Prompt 模板执行器写得再干净模型不知道什么时候用它等于白做。接下来写技能定义文档。## Skill: 竞品动态周报生成 ### 触发条件 当用户需要生成“竞品动态汇总”“竞品最近动作复盘”“按周维度的市场情报梳理”时使用此技能。 适合输入形式竞品名称列表 时间范围。 ### 禁止触发条件 当用户只是询问单条新闻内容、或要求判断某个竞品动作的好坏时不要使用本技能。 本技能不处理实时抓取请求不进行数据采集。 ### 输入参数 - competitor_names: 数组必填至少一个竞品名称 - start_date: 字符串必填格式 YYYY-MM-DD - end_date: 字符串必填格式 YYYY-MM-DD - language: 字符串可选默认 zh支持 zh / en ### 输出格式JSON { status: success | empty, summary: { industry_updates: [...], competitor_moves: [...], risk_alerts: [...] }, source_count: int } ### 示例 输入competitor_names[某竞品A, 某竞品B], start_date2025-01-01, end_date2025-01-07 输出statussuccess包含三段结构化摘要技能定义文档里最值得花心思的是“禁止触发条件”。很多团队写文档只写正面触发结果模型在模棱两可的场景下总是“自信地误用”。把不该用的场景写清楚模型会变得保守很多反而降低了误调度率。Prompt 模板这块我用的原则是“给结构不给自由”。让模型填空式输出而不是开放式写作。模板里直接规定了三个段落industry_updates / competitor_moves / risk_alerts每个段落里最多几条每条多少字以内全部固定死。这样输出质量稳定后处理也好做。3.4 注册、调试与调用代码和文档都写好了下一步是把 Skill 注册到 Agent 的调度体系里。常见的注册方式是通过声明式配置把技能名、技能描述、入口函数、参数 schema 用一个统一清单管理起来。这里有一个很容易被忽略的细节注册时的描述信息也就是技能清单里最显眼的那句话会极大影响模型对技能的选择。技能描述要写成一个“便于检索”的短句而不是长文档。例如registry.register( skill_idcompetitor_weekly_brief, name竞品动态周报生成, description基于已采集的竞品信息生成按周汇总的结构化动态摘要适合周报复盘场景, handlerexecute, input_schemaweekly_brief_input_schema )注册完之后进入调试环节。我第一次调试这个 Skill 的时候直接在真实 Agent 上跑发现问题根本不好定位。后来改成三步走先单独调用执行器函数验证代码逻辑没问题再用一段固定 Prompt 让 Agent 走一次技能选择看它选不选得对最后才放进完整对话流里做端到端测试。分层调试的节奏会比一把梭快很多尤其是当 Agent 流程很长、环节很多的时候。4. 让 Skill 能扛住生产环境工程化要点4.1 技能的版本管理与行为兼容本地跑通的 Skill 和生产环境稳定运行的 Skill中间还差着一大截工程化的问题。第一个绕不开的问题是版本管理。以前用 Tool 的时候函数升级是件很轻量的事改改代码就上线了。但 Skill 不一样它包含文档、Prompt、执行器三部分而且模型的选择行为会随技能定义的改变而产生非线性变化。同一套 Skill把描述里的某个词改掉模型选它的概率可能直接翻倍或者清零。这种高敏感性意味着任何对 Skill 的修改都必须当作一次版本发布来对待。实践里比较稳的做法是给每个 Skill 标版本号并在注册清单和维护文档里保留历史版本。线上运行的一律用固定版本新版本先在测试环境跑一段时间观察技能选择率、执行成功率和下游任务完成率确认稳定之后再全量切换。一旦出现异常能快速回滚到旧版本。版本管理还有个容易忽略的点技能之间可能存在隐式依赖。比如“竞品动态周报生成”这个 Skill 内部依赖“数据管道拉取”这个底层能力如果底层能力做了字段调整上层 Skill 的提示词模板和数据解析逻辑都要跟着变。这要求在技能变更时不只是看单个 Skill 的改动还得检查所有依赖同一数据源的兄弟 Skill 是否受影响。4.2 测试与回归单测只是起点Agent 系统的测试和普通后端服务差别很大。普通服务验证“给定输入输出是否符合预期”Agent 系统要验证的是“给定一个目标Agent 能不能做出正确的中间决策”。Skill 的测试因此分两层执行器层的单测和决策层的回归测试。执行器层的单测相对简单输入造一批构造数据验证输出 JSON 结构、空值处理、超长文本截断这些。这一层能挡住大部分低级错误但它证明不了 Skill 放在 Agent 里好不好用。决策层回归测试才真正考验设计功力。做法是维护一组覆盖典型场景的“对话剧本”每个剧本包含用户的一段模糊需求期望看到 Agent 调用哪个 Skill、走什么顺序、最终交付什么结果。这里的关键是测试集质量。剧本里的需求要接近真实用户的表达方式不能写得太直白比如“请用竞品动态周报生成功能为我生成报告”这种表述任何一个模型都能选对没有测试价值。真实用户的表达往往是“帮我看看最近这两家友商有啥动静简单整理一下。” 这一段话里没有“周报”两个字也没有“竞品动态”这个关键词模型需要结合上下文推理才能选中正确的 Skill。这种模糊输入才是回归测试里最该覆盖的样本。另外回归测试的判定标准也不能只看“有没有调用对 Skill”。要看最终输出报告的结构是否完整、是否包含三个必需段落。很多情况下模型选对了 Skill但 Prompt 组织得不好输出缺失这种情况下应该把问题记下来回去优化 Prompt 模板而不是归因为没有选对。4.3 并发、限流与可观测性生产环境的隐形门槛Skill 一旦放上生产并发和稳定性问题就会冒出来。尤其是在多个 Agent 实例共享同一批 Skill 的场景下不加控制的话某个 Skill 可能同时被几十个会话调用下游数据源接口根本扛不住。我的做法是给 Skill 加三层保护。第一层入参校验先行在代码入口检查参数合法性不合格的请求直接短路返回不消耗下游资源。第二层信号量限流给每个 Skill 设置最大并发数超过后排队或快速失败选择哪种策略取决于业务容忍度。第三层熔断保护当连续调用错误率达到阈值时自动暂停该 Skill 的对外服务避免雪崩效应。可观测性这块重点记录三个链路。第一个链路是“选择链路”也就是模型为什么会选中这个 Skill、输入是什么、置信度如何这个日志能帮你判断技能定义文档写得是否清楚。第二个链路是“执行链路”记录 Skill 内部每一步的耗时、调用中间件返回的状态用于性能调优。第三个链路是“结果链路”记录输出经过模型后置校验的状态验证 Prompt 质量和输出稳定性。建议在做测试阶段就把日志链路搭好。不要等到线上出了问题再补因为生产环境里的日志量大得多缺少链路设计的时候排查一个问题可能要翻半天日志成本非常高。5. 我踩过的坑与排查实录5.1 坑位一技能边界模糊导致模型误选第一次上线“竞品动态周报生成”这个 Skill 时我把技能定义文档里的触发条件写得太宽了。原文档里写的是“当用户需要了解竞品相关信息时使用此技能”结果线上跑起来用户只是随口问一句“那个竞品最近融资了吗”Agent 直接把周报生成流程拉了出来耗时十几秒最后给出的答案反而不如直接检索快。这个问题的根源在于我把“触发条件”写成了“相关条件”。模型的决策逻辑是匹配输入文本和技能描述之间的语义相似度描述越宽泛误匹配的概率越高。修改之后我把触发条件改成了更具操作性的表述“当用户要求梳理一段周期内竞品的结构化动态汇总且给出或隐含了时间范围时使用此技能。单点信息查询不在此范围内。” 改了这一次之后误选率下来了很多。5.2 坑位二提示词模板对格式极度敏感摘要生成这个 Skill 的早期版本Prompt 里写的是“请返回三部分内容行业动态、竞品动作、风险提示”。模型拿到这个 Prompt 之后输出格式三天两头变化有时候用一级标题分节有时候用 Markdown 引用有时候干脆输出一大段连续文字。后处理解析的时候各种兼容最后实在忍不了了。排查下来问题出在 Prompt 的结构约束不够硬。后来我改成明确指定 JSON 输出格式并在 Prompt 里直接贴死在输出里包含哪三个字段、每个字段是数组类型、数组里每一项字符串长度不超过多少。模型对“格式”的跟随能力比对“语义描述”的跟随能力要好很多。给 Prompt 一个明确的结构骨架比你用十句话去解释“什么是结构化”都管用。5.3 坑位三多个 Skill 状态互相污染有一阵子系统里同时上线了“竞品动态周报生成”和“内部数据指标周报生成”两个 Skill两个技能底层调用同一个数据管道。后来发现一个明显的怪现象用户生成竞品周报时摘要里偶尔会带出内部数据的口径说明。一开始以为是 Prompt 泄露排查了很久最后发现是执行器代码里有个全局变量没清理干净两次调用之间共享了缓存数据。这个坑暴露出来的深层问题是Skill 的执行器必须做到无状态。任何需要在多次调用之间保留的数据都应该显式存到外部存储或者作为返回值返回绝不能放进模块级全局变量。后来我写了一套执行器编码规范里面第一条就是“禁止使用模块级可变状态”。5.4 排障速查表现象可能原因排查顺序模型从不选某个 Skill技能描述与真实功能不匹配先看描述前 20 个字再确认有无反面排除条件模型总是乱选 Skill技能边界太宽检查触发条件是否过于“相关化”调用成功但输出格式乱Prompt 缺少硬结构约束改为明确指定 JSON schema输出内容不稳定逻辑跳跃temperature 设太高摘要类任务控制在 0.3 以下多个会话相互干扰执行器存在共享可变状态检查全局变量与缓存调用失败但无日志缺少链路追踪埋点优先补选择链路和执行链路日志这张表是我在实际排障中反复用到的顺序。从下往上排查是一个相对高效的策略因为很多看起来是模型问题的情况往下查两层才发现是文档或者状态问题。Agent 系统的排障和传统的单体服务排障不一样它多了一层“模型决策”的黑盒所以排查时不能只盯着代码要把 Prompt、技能定义、调度策略、执行器状态全链路一起看。写在最后的一个建议Skill 的设计没有绝对的“正确”但有几个方向是踩过坑之后能确定的给模型的文档要写清楚边界执行器要保持无状态输出格式要硬约束日志链路要提前搭。我见过不少人把 Skill 做成“大杂烩”一个技能里塞进五个功能表面上看是省事实际上模型根本判断不清楚什么时候调它。真正能长期稳定运行的 Agent 系统技能往往小而清晰各管一段配合起来才能跑出好的效果。如果你正在重构自己的 Agent 系统可以从选一个最小的技能开始做边界梳理跑通之后你会明显感受到Agent 的“自主性”一下子稳了很多。