ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

Agent Skills:让智能体从“能聊天”到“能干活”的工程关键

Agent Skills:让智能体从“能聊天”到“能干活”的工程关键 Agent Skills让智能体真正“学会干活”的那层关键结构先直接说结论Agent Skills智能体技能是当前 AI Agent 从“能聊天”走向“能干活”的关键一层。业界讨论很多的一个现象是同样一个底层大模型接上合理的 Skill 体系之后在执行真实任务时的成功率可以翻倍甚至数量级提升。这不是魔法而是工程结构带来的确定性收益。我一直很关注智能体领域的落地实践这几年从 AutoGPT 式自由发挥到 LangChain 式工作流编排再到如今的 Skill 体系工具范式几乎一年一个大版本。但直到 Agent Skills 这类思路逐渐清晰起来我才感觉到“智能体真正像个员工而不是像个试用期实习生”这件事开始有了解法。这篇文章会把我在项目实践中对 Agent Skills 的理解掰开来讲包括它解决什么问题、核心结构怎么设计、技能怎么构建与测试、有哪些常见的坑以及一套可以直接抄的落地路径。这篇文章适合三类人正在搭建 Agent 应用的工程师准备把智能体接进业务系统的技术负责人以及纯粹想搞懂“为什么现在的 Agent 一会儿好用一会儿不好用”的产品经理或研究者。不需要你有很深的算法背景但如果你写过一点代码、调过任何大模型 API读起来会非常顺。1. 内容整体设计与思路拆解1.1 Agent Skills 是什么一个可复用的行为单元先给一个精确但不晦涩的定义Agent Skills 是把一段可以被学习和复用、能够与环境交互、有明确输入和输出的行为逻辑封装成智能体可调用的独立功能模块。举个例子。你希望智能体能帮你查快递。如果直接用 Prompt 说“你是一个物流助手”大模型大概率会一本正经地编一个单号状态。你给它接上快递查询 API它也只是会在对话里调用 API 而已。但如果你把“查询快递”这件事做成一个 Skill——包含 API 地址、参数格式、返回解析规则、异常处理逻辑、调用前置条件——那么智能体就能以较低的理解成本完成这件事并且这个 Skill 可以被复用在客服问答、订单管理、售后分析等多个场景中。用生活里的话说Agent Skills 就是一个“岗位说明书”加“操作手册”的组合体。它不是让模型多背几条规则而是把一项工作所需的所有上下文、边界、步骤和注意事项打包成一个可插拔的模块。模型不用每次都在对话里猜“用户到底要我做什么”它只需要识别“这个任务属于哪个 Skill”然后按 Skill 内置的路径去执行。这里有个值得注意的点Skills 和 Function Calling函数调用不是一回事。Function Calling 通常只解决“模型如何触发一段预设函数”的问题它是一个协议层的机制而 Skills 是任务层的抽象它包含了触发逻辑、工具选择、参数映射、结果处理、异常恢复和上下文管理。你可以理解成Function Calling 是“打电话这个动作”Skills 是“和某个供应商对接的一整套流程”。很多团队会走进一个误区先把大模型 Prompt 写得巨长希望把各种边界情况都写在对话指令里然后发现模型上下文窗口根本不够用或者指令之间互相冲突。Skills 的思路恰恰是反过来的——把那些稳定的、可标准化的操作逻辑从 Prompt 里抽出来让 Prompt 只负责“理解任务、选择技能、串联执行”。这样既缓解了上下文压力也让行为逻辑更容易演进和测试。1.2 为什么是现在Agent 落地中的三个死结你可能会问Skills 这个概念不算新为什么最近才被广泛关注我先说几个背景变化。第一纯靠 Prompt 驱动的 Agent 遇到了明显的“编码飞轮失效”。早些年大家把任务拆解交给模型自由发挥发现它在简单任务上表现惊艳但在长链路、高复杂度的任务上错误率指数级上升。模型开头说错一个条件后面所有步骤都会跑偏且很难自我纠正。这种模式下代码逻辑和模型行为是解耦的出了问题你根本不知道是模型笨还是 Prompt 没写清。第二可靠性成为上生产环境的硬门槛。对话场景里模型说错一句可以容忍业务系统里模型算错一个数就是事故。业界越来越意识到必须把模型的行为约束在一个可控的边界内而这个边界不能依赖模型“自觉”必须由工程结构强制划定。第三Agent 所需处理的真实场景逐渐收敛。早期大家喜欢让 Agent “什么都会”后来发现真实业务里 80% 的任务类型是反复出现的。既然任务是重复的那就应该把“怎么做好这个任务”沉淀为一种可复用的能力而不是每次让模型从零思考。这正是 Skills 的经济学基础技能一旦沉淀边际成本越低复用价值越高。有意思的是这个演进路径让我想起软件工程里的“过程抽象”。早期大家写程序全是流水账后来发现重复代码太多就抽象出函数函数多了就沉淀出类库类库多了就形成框架。Agent Skills 本质上就是大模型应用时代的“函数库”它把模型的能力从一次性消耗品变成了可积累的资产。1.3 一个 Skill 应由哪些部分构成我的实践里一个可用的 Skill 至少需要五个部分缺一个都会在落地时露馅。第一是行为描述。这部分告诉模型“这个技能是干什么的、什么时候用、什么时候不用”。描述写得好不好直接决定了模型能不能正确触发这个技能。这里有个常见的坑描述里写太多技术实现细节模型反而抓不住重点。更好的做法是写“干了什么”和“边界条件”而不是写“怎么调用”。第二是调用协议。包括输入参数定义、输出格式定义、可能的异常码。参数定义最好用明确的 JSON Schema而不是自然语言描述。因为模型天然对结构化定义的解析成功率更高。输出部分同理最好严格规定返回结构让上层逻辑可以无脑解析。第三是内置逻辑。这是 Skills 区别于普通 Prompt 的关键技能内部可以包含一段确定性代码、一个决策树、一个条件分支、一个前置校验逻辑。比如“查快递”这个 Skill 里你可以内置“单号为空时先向用户索要”的逻辑而不是把这一步抛给模型临场发挥。第四是上下文契约。说明执行这个技能需要多少上下文会消耗哪些上下文以及执行后如何更新对话状态。上下文契约是维持技能可复用的关键否则技能执行一次后会把对话上下文搅乱导致后续技能误判。第五是测试用例。一个 Skill 应该自带至少一组最小验证用例包括正常路径、边界路径和异常路径。这一条我在后面会专门讲因为很多团队把“能不能跑通”当成了“是否可靠”的标准这是大忌。这五个部分构成一个完整的技能单元既可以单独被调用也可以通过编排层组合成复杂流程。我认为这是 Agent 工程里最接近“模块化”概念的设计模式。2. 核心细节解析与实操要点2.1 如何评价一个 Skill 的质量三个核心指标有朋友问过我“我随便写一段 Prompt 放在系统里是不是就算一个 Skill”严格来说不算。我评估一个 Skill 是否合格会从三个可量化的维度来看。第一个维度是触发准确率。给模型十句不同意图的用户输入其中五句应该触发该技能、五句不该触发看模型判断正确的比例。如果该触发时没触发说明行为描述有问题如果不该触发时触发了说明边界条件没写明白。第二个维度是执行成功率。在技能被正确触发后它能否在规定的参数和约束下完成任务。这个指标要特别注意“标准输入场景”和“脏输入场景”分开测。很多技能在理想输入下成功率奇高稍微来点口语化表达就崩了。第三个维度是上下文副作用。执行完技能后当前对话的上下文是否还保持干净会不会把临时变量、中间结果、错误日志残留在上下文里影响后续任务这指标特别容易被人忽略但往往是生产中后期最难收拾的问题。有人统计过Agent 轮次越长任务成功率越低其中一个重要因素就是上下文被逐步污染。我自己在建 Skill 库的时候会为每个指标设定最低达标线触发准确率不低于 90%执行成功率不低于 95%上下文副作用为“零残留或者有明确隔离机制”。低于这个线的技能不上生产环境。2.2 构建技能的三个核心原则隔离、委托、可观测在具体写 Skill 时有三个原则是我一直当铁律来执行的。隔离原则技能内部逻辑不要直接修改主对话上下文所有中间变量放在技能的局部作用域里只在结束时通过明确的返回值更新主流程。这就像一个函数不应该随便修改全局变量一样否则技能之间的调用顺序一变行为就不可预测了。我见过太多团队因为“图省事”让技能直接往对话上下文中写状态最后查 bug 查了两天罪魁祸首就是把临时信息留在了上下文里。委托原则凡是能用确定性代码实现的逻辑就不要交给模型去“理解”。比如参数格式校验、范围检查、必填项判断这些都是确定性的规则写代码判断既快又准没必要让模型做选择题。模型的强项是处理语义不确定的任务弱项是高精度执行重复性计算。Skill 的设计应该把模型和代码各自的强项组合起来。提示这里可以做一个简单类比你请了一个助理你会在助理出门前把路线、预算上限、备选方案都给定好而不是让助理临场“判断怎么最省钱”。Agent Skill 就是那个“行程单”。可观测原则技能执行的每一步关键节点尽量输出结构化日志包括触发条件是否满足、输入参数是什么、走的是哪个分支、输出结果是什么、耗时多久、消耗了多少 token。这些日志在调试和复盘时是救命稻草。为什么强调结构化因为普通自然语言日志只能给人看结构化日志可以给分析程序看能自动聚合出“哪个技能成功率最低”“哪类用户输入最容易触发误判”等关键结论。2.3 技能描述写作少写过程多写边界这是我觉得最需要刻意练习的部分。为 Skill 写行为描述时大多数人容易写成一篇文章描述模型“应该如何一步步完成任务”但这里有个反直觉的点模型恰恰不需要你教它怎么一步步做它需要的是明确的边界信号。边界信号包括三类信息何时启用、何时禁用、与其他技能如何区分。给你一个正面例子一个“查天气”技能的描述当用户询问当前或未来的天气情况、气温、降水概率、空气质量等信息时启用。若用户询问的是历史天气数据统计或气候长期变化趋势禁用应转给“气候数据分析”技能。当用户询问“今天冷不冷”这类体感问题时依然启用本技能但需额外获取用户所在城市。这个描述里没有说“调用天气 API解析返回结果”这类过程因为这些写在调用协议里就够了。描述的重点在于什么算天气类需求、什么不算、边界在哪里。模型有了清晰的边界命中率才会高。反过来看一个常见病某团队为“发票报销”技能写的描述是“当用户需要报销时调用请根据用户提供的发票信息进行报销操作注意金额要和发票一致如果缺少信息请询问用户”。这个描述的问题在于“报销”的含义在不同场景下差异巨大——是提交报销单还是查询报销进度还是修改报销金额模型很可能混淆。更好的写法是拆成三个技能或者至少在描述里把子场景逐一列清。2.4 上下文契约与 Token 预算控制上下文契约是 Skill 设计里技术含量最高的部分。一个执行良好但上下文消耗极大的技能长期跑下来会让整个 Agent 的成本失控而且会拉低后续任务的精度。为什么因为大模型的注意力会随着上下文长度增加而分散。你只带了三句话进新任务时模型是“专注模式”如果在执行技能之前上下文里堆了两千行无关日志模型在后续任务上就像是“重度分心模式”。所以我在设计每个 Skill 时都会规定“上下文预算”这个 Skill 执行前需要多少上下文、执行中最多增加多少上下文、执行后哪些信息必须从主上下文中清除。举个例子“订单查询” Skill 的输入可以只保留“订单号 用户ID”而“订单历史对话摘要”并不需要全部灌给这个技能。在编排层我可以用摘要替换完整对话把无关信息挡在技能之外。这个设计理念其实和微服务很像每个服务只接收它处理任务所需的最小信息集。Skills 也应该这样设计输入最小化输出结构化中间过程对主流程不可见。3. 实操过程与核心环节实现3.1 从需求到 Skill 的转化流程先上一套我自己反复使用的需求转化流程。当业务方提一个“希望智能体能做 X”的需求时我不急着动 Prompt而是走这几步。第一步任务类型识别。这个任务是“一次性任务”还是“高频复用任务”如果是前者优化 Prompt 效率更高如果是后者值得做 Skill。判断标准很简单同一类任务一周内出现三次以上就应该技能化。第二步边界场景穷举。和业务方至少做一轮头脑风暴列出“这个任务所有的例外情况”。比如“查快递”要考虑单号格式不对怎么办快递公司查不到怎么办用户同时给了三个单号怎么办这些边界场景一个个列出来先别管怎么处理列全了再设计。第三步确定模型与代码的分工。排序哪些步骤适合模型做意图理解、语义提取、模糊匹配哪些步骤适合代码做校验、计算、格式转换、API 调用。设计目标是把模型的不可控性压缩到最小范围。第四步设计输入输出协议。这一步直接决定 Skills 的可复用性。我的习惯是输入输出全部用 JSON Schema 定义字段类型尽量收窄可选字段必须有默认值所有错误分支必须有明确的错误码。第五步写行为描述与边界说明配置上下文契约。第六步构建测试用例库。第七步独立运行调试、集成测试、影子模式试运行、全量上线。这套流程看着繁复但每一步都有它存在的理由。尤其是第二步的边界场景穷举最容易偷懒也最致命——你少想一个例外上线时模型就会用一种完全想不到的方式“自由发挥”。3.2 一个可落地的 Skill 仓库结构建议我在中大型项目里推荐的仓库结构是这样的。每个 Skill 独立成一个目录包含以下文件skills/ order_query/ skill.yaml # 技能行为描述、边界条件、上下文契约、元信息 schema.py # 输入输出参数定义与校验 logic.py # 内置确定性逻辑API 调用、规则处理、格式化 prompts.py # 给模型的动态指令片段如果有 tests/ test_normal.json # 正常路径用例 test_edge.json # 边界用例 test_error.json # 异常路径用例skill.yaml 是整个技能的定义中心schema.py 和 logic.py 是执行实体tests 目录是质量保障。这个结构既适合几个工程师的小团队也适合几十个工程师的大团队因为每个人的工作边界是清晰的改 Skill 内部逻辑不碰其他模块改测试用例不动生产代码。有朋友问过“为什么不直接用 LangChain 的 Tool 或 OpenAI 的 Function Calling 格式”我的回答是那些格式定义的是“模型与函数的交互协议”而 Skill 目录是“完整的工程模块”。你可以把 Skill 内部的逻辑最终暴露为 LangChain Tool 或 Function Calling 的接口但不能用一层协议定义替代完整的模块设计。就好比你不能用“接口文档”替代“微服务工程”一样。3.3 关键编排技能选择与串行执行策略一个 Skill 仓库里有几十个技能之后最核心的问题就变成了模型如何从技能列表里选出正确的技能然后正确地串联执行关于技能选择业界主流有两类做法一类是“全量列表匹配”——把几十个技能描述一次性灌给模型让它选择另一类是“两阶段检索”——先用轻量级索引召回候选技能再把候选技能描述交给模型做最终决策。我强烈建议技能超过 15 个后选择两阶段方案。为什么因为技能描述列表越长模型选出正确答案的准确率下降越快而且每个技能描述都会抢占上下文预算。与其让模型在 30 个技能里纠结不如先用一个 Embedding 检索或关键词索引把潜在候选缩减到 3-5 个再做精细判断。这类做法的额外收益是技能库扩容时不需要重新设计 Prompt只需要更新检索索引。再说串行执行。如果用户请求本质上需要两个技能依次执行比如先“查订单”再“发起退款”有两种策略一种是模型自主编排让模型自己决定先调哪个后调哪个。这种策略灵活但不可控。另一种是编排层用确定性流程或半确定性流程定义技能调用顺序通过一个流程模板固定“先查询、校验状态、再退款”的顺序。实践证明对于规则明确的业务流程确定性编排的成功率远高于模型自由编排。只有在规则不明确的复杂任务中才让模型动态规划步骤。3.4 最小可用技能编写实例查询客户余额我直接用一个简化版示例来说明一个技能实际长什么样示例为“查询客户余额”技能。第一步明确技能名称与行为描述。在 skill.yaml 中name: customer_balance_query description: 查询指定客户的账户余额。当用户询问“还剩多少钱”、“余额多少”、 “账户里还有多少”等涉及金额余额问题时启用。 当用户询问的是“历史消费记录”或“账单明细”时禁用应转至 transaction_history 技能。 本技能仅支持人民币金额查询其他币种请返回错误码 BAL_CUR_UNSUPPORTED。 input_schema: type: object required: - customer_id properties: customer_id: type: string description: 客户编号格式为 CUS 8 位数字。 include_frozen: type: boolean default: false description: 是否包含冻结金额默认不包含。 output_schema: type: object required: - balance - currency - as_of properties: balance: type: number description: 查询时间点的可用余额。 currency: type: string description: 固定为 CNY。 as_of: type: string description: ISO 8601 格式的时间戳。 context_contract: input_required: - customer_id context_injected: false max_output_tokens: 200 cleanup_after: true这里最关键的是context_injected: false和cleanup_after: true。前者的意思是执行该技能时不需要把整段对话历史注入技能上下文只传递输入参数后者的意思是技能执行结束后中间过程不保留在主对话中。这两条设定极大降低了上下文污染风险。第二步是核心逻辑。在logic.py里写确定性代码负责调用余额查询 API、解析响应、做异常映射。模型的部分只负责从用户的话中抽取customer_id和include_frozen参数其余全部交给代码。第三步是构建测试用例。我用三个测试文件分别覆盖正常输入一条客户编号、边界输入带了多余的自然语言“帮我查一下”和异常输入客户编号格式错误。三条用例全部通过且无上下文残留这个技能才算初步合格。注意这里给模型的任务越“窄”越好。与其让模型在技能内部做复杂推理不如让它只做“参数抽取”这一件事。这样万一出错你知道是模型的问题还是代码的问题排查路径清晰得多。3.5 对抗幻觉内置校验与兜底策略的配合对抗幻觉的方式很多但最可靠的一定是工程手段而不是重复写“请勿编造”的 prompt。我把 Skill 内部对幻觉的对抗分成三层。第一层参数正则与前置校验。模型把抽取好的参数交给技能时先走一层硬校验。customer_id不符合格式直接报错不走 API不产生结果。这一层能拦截大量“模型自信地编了一个错误参数”的情况。第二层结果语义校验。API 返回的数据如果通过了解析但明显不符合常识比如余额为负数、时间戳是未来时间技能应该自动标记为“可疑结果”并追加一步确认逻辑。这里的常识规则要写得越具体越好不要写抽象的“检查结果是否合理”模型不擅长这种模糊指令代码擅长。第三层兜底回复。当技能不确定输出是否可靠时可以向用户输出“根据现有信息无法准确查询请核对客户编号后重试”之类的话。很多团队不敢这么做觉得会影响体验但实际上“坦诚不知道”比“一本正经编答案”对信任的伤害小得多。4. 常见问题与排查技巧实录4.1 LLM 不按 Skill 描述走怎么办这是大家反馈最多的问题之一我明明在 Skill 描述里写了“仅在 X 时启用”模型还是会在 Y 的场景误触发这个技能。排查这类问题时我先不看 Prompt 措辞而是先看用户输入样本和触发日志。很多时候不是描述不清而是训练数据里本来就存在大量“相似但不同”的语义关联。比如“查询天气”技能的描述里出现了“温度”这个词模型在看到“测量体温”这句输入时也会幻想触发天气技能。我的排查步骤是先收集 20 条误触发样本观察它们的共性然后往技能描述的“禁用条件”里补充更具体的反例。比如上面例子就在描述里加一句“当用户询问体温、发冷发烧等健康相关问题时禁用”。如果加了反例还是误触发那就考虑调整技能名称或者改用检索式召回从机制上限制它被错误模型决策拉进去。4.2 技能返回结果正确但主流程判断异常还有一种很隐蔽的问题技能本身执行没问题API 也正常返回了但主流程接下来的决策出错了。排查这类问题时我几乎总能定位到同一个根源——技能输出结果的结构太“自由”。如果技能的返回是一个长自然语言段落模型在后续步骤中解析这个段落的成功率远远低于解析结构化 JSON。所以技能的输出必须强结构化为字段级数据。这和我们前面提到的输出 Schema 有关。如果你发现主流程频繁出错先别急着怀疑别的环节去检查一下技能输出的字段是不是存在同义表达比如“amount”和“total_amount”混用或者某些字段是否只在部分情况下返回。规范化输出结构是解决这类问题的低成本高收益手段。4.3 技能测试通过联调就翻车有一位朋友跟我抱怨过他的技能在单测场景下跑得很好怎么接到对话系统里就各种出错后来让他调日志发现测试时他用的都是干净、标准的用户输入而真实输入是口语化的自然语言比如用户说“帮我看看那个订单到哪了”——这个句式里既没有明确的“查询”指令也没有给出订单号。问题不在于技能实现而在于“意图路由”环节缺失。对真实用户输入需要先做一层“口语到结构化请求”的转换把“看看那个订单到哪了”转成intentorder_query, order_idnull, need_locationtrue再交给技能。很多失败的案例并不是技能不够好而是少了一个“输入适配层”。做技能库建设时一定要预留这一层的位置并且单独测试“口语化输入”到“结构化触发”的准确率。4.4 技能死锁与循环调用当技能库大了以后会出现一种让人头疼的场景技能 A 触发后给了技能 B 不太满意的输入B 试图请求 A 再给一次A 又生成一个格式不太标准的输入……两个技能像两个人互相踢皮球直到 token 耗尽或时间超时。针对这类循环我的方案是三种组合拳第一为每个技能限制最大调用次数超过次数强制转人工兜底或返回明确错误第二在技能间传递参数时强制走规范化校验输入不合法直接报错而不是转回上游第三在编排层加一个“循环检测器”跟踪一段时间内重复出现的技能调用序列一旦检测到相同模式超过两次立即打断并重新路由。4.5 回归测试与技能版本管理Skills 是会持续进化的你修改了一个技能的行为描述可能影响其他技能的触发准确性。所以我强烈建议每个技能库维护一套“全量回归测试集”任何技能变更都要跑全套测试而不是只跑被修改的那个。回归测试集的设计有三个层级第一层每个技能自身的用例集第二层跨技能的组合用例集专门覆盖“技能 A 的输出作为技能 B 输入”的链路第三层全局冒烟集模拟真实用户端到端流程的经典路径。这三个层级任何一个不过变更就不允许合入主分支。技能版本管理方面我推荐的模式是“YAML 代码同库管理”用普通的 Git 仓库管理技能定义、测试用例和编排配置。变更要有 PR 和 Code Review上线要有灰度。不要追求前卫做法稳定可追溯比技术上的酷重要一百倍。5. 技能库的长期演进资产化与组织协同技能库积累到一定规模就不再只是代码仓库它更像是团队的核心资产。我见过一些团队把“技能覆盖度”纳入路线图管理核心业务场景有多少比例已经沉淀为可复用技能、每个技能的成功率如何、哪些技能长期低效需要重构。这种把 SKills 当做资产经营的思路是 Agent 应用从“做出来”走向“做得稳”的必然路径。在组织协同上技能库也需要定义“维护责任”每个技能有 ownerowner 负责该技能的成功率和质量回退。技能改动需要经过测试不能“能用就行”。我还建议定期开“技能复盘会”把各技能的运行日志抖一抖触发率是否下降、成功率是否波动、上下文占用是否增加——这些问题在运行时像慢性病一样积累不主动观测不会自愈。关于技能的互联与组合长期看会逐渐形成“技能图谱”技能之间通过标准输入输出接口互相连接上层编排按业务目标自由组合。这一步走通后Agent 开发的范式就变了从写代码变成了组装技能。就像软件工程从写函数进化到框架调用一样开发者的重心会转移到“如何定义好接口”和“如何编排流程”上。这个方向能不能普及取决于技能标准是否足够统一。目前各家有各家的格式和协议短时间内还会比较乱。但大的趋势已经很明确让模型直接面对非结构化世界是低效且危险的工程中间必须有一层结构化的能力层来缓冲。Agent Skills 就是站在这个位置上的东西。最后分享一个我个人在实际调试中的体会不要试图把技能一遍写对这不现实。我写过的所有高质量技能几乎都经过了至少三轮迭代——第一轮跑通主流程第二轮打磨边界场景第三轮优化上下文消耗。三轮迭代里每一轮都要看日志、调描述、改测试用里。这个过程很磨人但只有走完技能才算真正能交付。另外一个小技巧每个技能上线前别急着接入主流程先开一个“影子模式”跑三天让它在真实流量下干活但不做关键决策看完行为和耗时数据再放量。这一步能帮你躲掉绝大多数翻车事件。
返回列表