Agent技能沉淀实战:让智能体从“聊天玩具”变成“干活工具”

发布时间:2026/10/14 9:02:26
Agent技能沉淀实战:让智能体从“聊天玩具”变成“干活工具”
过去两年我一直在做各类智能体项目从最初把大模型接进对话框就算完成到后来开始认真考虑一个很扎心的问题Agent上线后的表现能不能稳定复现今天想聊的agent-skills这个方向就是我在无数次上一版明明还好好的、这版怎么突然变笨了之后沉淀下来的一套解决思路。先说结论一个Agent如果只是靠每次对话临时想出答案它的水平上限和稳定性都不可控。而把那些高频、稳定、可复用的行为范式固化下来形成一个技能库才是让Agent从聊天玩具走向干活工具的关键一步。这篇文章会从技能的定义形态、构建流程、踩坑排查到进阶管理把我实际做过的方案完整拆开来讲适合正在做Agent应用开发、或者被Agent能力不可复现折磨过的朋友参考。1. 为什么Agent容易学了就忘技能沉淀是当前多数智能体方案的最大短板先还原一个我亲身经历过的场景。某公司内部做了一个客服问答Agent上线第一周效果惊艳业务流程问什么都能答上来。但到了第二周运营同学反馈同样的问题上午答得对下午就答偏了同一个问题换个用户问答案风格完全不一样。我接手排查时发现这个Agent根本没有技能的概念——它每一次回答都是靠大模型的上下文即时发挥历史对话一多早期约定的业务规则就被稀释掉了。这个现象背后有个很容易被忽视的底层原因。大模型的记忆和能力是绑在上下文里的上下文一变行为就跟着变。你告诉它报价要含税它记住了但聊了十轮之后它可能就把这条规则忘在角落里。这不是模型变笨了而是它没有一个稳定、独立于对话之外的执行逻辑。技能沉淀要解决的本质问题就是把行为范式从临时上下文里剥离出来变成Agent随时可以取用的固定资产。我当时做了个简单的对照实验更能说明问题。同一个Agent一个版本让它在对话中自由发挥另一个版本把核心业务动作固化成技能调用测试了200个真实问题对比维度纯对话方案技能化方案标准流程问题回答准确率72%94%连续多轮后的规则保持率明显下降稳定新增业务规则的成本每次都要重新说明改一个技能文件即可问题排查难度靠猜按技能逐项定位我不是说纯对话方案没有价值它胜在灵活。但当你的Agent要承担确定性交付任务时——比如查订单、算报价、走审批流程——灵活反而变成了缺陷。技能化方案的核心理念是把怎么干和干的时候用到的信息分开流程是固定的信息是流动的。从那时起我开始把Agent技能当作一等公民来设计而不是把一堆提示词散落在各个系统里。后面几章我会具体讲一个可落地的Agent技能体系到底长什么样、怎么一步步建起来。2. Agent技能的真实形态从会调用到会迁移的三种承载方式聊到Agent技能很多人第一反应是不就是给大模型写提示词吗。这个理解方向是对的但不完整。经过我自己的几次重构我把技能形态归纳成了三种各有各的适用场景也各有各的坑。2.1 声明式技能卡大模型能读懂的行为说明书第一种形态我习惯叫它技能卡本质上是一份结构化的自然语言文档。它描述清楚一个技能的触发条件、执行步骤、输入输出约束和注意事项Agent通过读取这份文档来学会这个技能。这种形态的优点是成本极低、迭代极快。业务人员就能写不需要懂代码。我在某模拟项目中做过一个退换货处理的技能卡里面就写清了几个环节先校验订单状态、再检查退换货时效、然后按商品类目走不同审批路径、最后生成处理结果。某次运营同学发现某个类目的时效规则写错了直接改文档当晚就生效完全不用发版。缺点也很明显因为所有逻辑都靠大模型理解在复杂分支场景下容易漏步骤或者加戏。我的经验是声明式技能卡适合流程稳定、分支不太多、且对执行准确性要求不是极端苛刻的场景比如标准客服话术、常见FAQ处理、基础数据查询。2.2 程序化技能确定性交给代码智能性交给模型第二种形态是程序化技能。技能不再是一段文字而是一段可执行的代码逻辑大模型只负责两件事判断该不该调用、填好必要的参数。剩下的计算、查询、落库全部走代码逻辑。这种方式我是在被提示词幻觉坑过之后才开始重用的。当时做一个订单状态查询技能纯靠大模型读订单数据再回答它偶尔会把已发货说成已签收因为它在做合理推测而不是精确读取。改成程序化技能后大模型只负责从用户消息里提取订单号并决定调用查出来的状态是代码直接读数据库拿到的回答部分再把查到的状态填进模板里。从模型自己看着办变成模型只做它擅长的意图识别和参数抽取确定性逻辑交给代码准确率从不超过85%直接拉到99%以上。代价是需要开发维护。而且大模型填参数偶尔会出幺蛾子比如把订单号填成用户ID所以程序化技能必须带参数校验层。2.3 混合型技能先读说明书再动真家伙第三种是我现在最常用的形态也是我理解的agent-skills的完全体。一个技能同时包含两部分一部分是给大模型读的技能卡说明在什么场景下用、参数怎么填、注意什么另一部分是给系统执行的代码函数。Agent先根据用户请求和技能卡判断该调用哪个技能然后从请求中抽取参数最后调用代码函数完成实际动作。以我做一个内部报销单创建技能为例。技能卡部分写明只有当用户提出报销相关需求时才触发需要提取金额、事由、票据编号三个参数且金额必须大于0、票据编号必须符合格式。代码函数部分则负责写数据库、校验重复提交、返回创建结果。两者配合起来既保留了大模型的语义理解能力又用代码保证了关键步骤不出错。为了方便对比我整理了一个表格我选型时会拿它做参考技能形态开发成本维护成本执行确定性典型适用场景声明式技能卡低低中话术问答、SOP引导、信息整理程序化技能高中高数据查询、订单操作、接口调用混合型技能中中高需要语义理解又要精确执行的任务选型建议很简单能用代码守住的关键节点绝不放给模型自由发挥需要模型理解语义的地方绝不硬写成死规则。这两句话我写在团队协作文档的首页每次设计新技能时都会对照一遍。3. 构建一个可复用技能库的完整落地流程理论讲再多不如跑通一个完整流程。这一章我按我实际搭建技能库的顺序把每一步的要点和容易踩的坑都摊开来讲。3.1 第一步盘点高频动作划出技能边界先不要急着写技能先做一件事——翻历史对话记录和业务工单把所有重复出现过的需求列出来。我当时的筛选标准有三个频率够高一周内出现超过10次、行为够稳定每次的解决流程基本一致、边界够清晰知道什么时候该用、什么时候不该用。这里有一个很容易犯的错把技能设计得过大。比如处理客户问题这种技能听起来什么都能干实际上Agent根本不知道该调用它还是不调用它调用之后也不知道该走到哪一步。我的建议是技能宁可粒度细一点不要贪大。一个技能只做一件完整的事比如查询订单状态是一个技能处理退换货申请是另一个技能两者可以有关联但不要揉在一起。边界模糊是后续意图识别失败的根源之一。筛选完之后我给每个候选技能做了一行描述格式是在什么情况下、做什么事、产出什么结果。比如在用户提供订单号时查询订单实时状态并返回物流节点信息。这一步看着简单但决定了后面的技能描述质量和召回效果。3.2 第二步定义技能标准模板统一字段规范技能不是越自由越好尤其当技能数量超过20个之后没有统一规范会乱成一锅粥。我把每个技能都定义成一张结构化的技能卡核心字段如下name: query_order_status description: 在用户提供订单号并询问订单状态时调用查询订单实时状态及物流信息 when_to_use: - 用户主动询问订单到哪里了 - 用户反馈长时间未收到货 - 用户咨询物流异常 when_not_to_use: - 用户询问退款进度应调用退款查询技能 input_params: order_id: type: string description: 订单编号通常以字母和数字组合 required: true execution_steps: - 校验order_id格式 - 调用订单查询接口 - 将返回结果映射为用户可读文案 output_format: 包含订单状态、最新物流节点、预计送达时间的自然语言文本 error_handling: - 订单不存在时提示用户核对订单号 - 接口超时时返回稍后重试的引导话术这个模板不是我一次性想出来的是经过三次返工才定成这样的。最开始没有when_not_to_use字段结果Agent经常把退款进度问题错误地调用到订单状态查询因为两者语义太接近了。加了这个字段之后误调用率明显下降。技能卡不只是告诉Agent什么时候该用更要明确告诉它什么时候不该用——边界是排除出来的。另外建议给每个技能配一个独立的版本号我习惯用语义化版本比如query_order_statusv1.3.2。这样每次改动都留痕后面排错会轻松很多。3.3 第三步编码实现技能逻辑预留参数校验层技能卡是给模型看的但要真正干活还需要代码层的实现。我一般把每个技能写成一个独立的Python模块内部包含三个阶段参数清洗与校验、核心逻辑执行、结果格式化。以查询订单状态技能为例核心代码结构大概是这样def query_order_status(order_id: str) - dict: # 阶段1参数校验 if not re.fullmatch(r[A-Za-z0-9]{12,20}, order_id): return {status: invalid_param, message: 订单号格式不正确请重新确认} # 阶段2业务逻辑 order_info order_service.query(order_id) if order_info is None: return {status: not_found, message: 查不到该订单请核对订单号} # 阶段3结果格式化 return { status: success, order_status: order_info.state, # 枚举值 tracking_node: order_info.latest_logistics, eta: order_info.estimated_delivery }几个要点说一下。第一不要在核心逻辑里掺杂大模型调用除非是混合型技能里确实需要二次理解。第二返回结构要统一都有status字段标记成功、失败或参数错误这样上层Agent才能根据状态决定下一步动作。第三所有可能出错的地方都要返回清晰的错误信息不能抛裸异常。你永远不知道模型会在什么场景下填出什么鬼参数好的校验层是技能库的护城河。3.4 第四步注册到技能索引让Agent知道你有什么技能写好了代码实现了但如果Agent不知道它的存在一切等于白做。这一步需要维护一个技能索引文件相当于整个Agent的技能目录。我实际用的索引结构很简单SKILL_REGISTRY [ { name: query_order_status, skill_card: path/to/query_order_status_card.md, handler: skills.order_status.query_order_status, enabled: True }, { name: process_return_refund, skill_card: path/to/return_refund_card.md, handler: skills.return_refund.process_return_refund, enabled: True } ]Agent每次收到用户请求时我会先做一步技能召回把技能索引里所有技能的描述、when_to_use、when_not_to_use塞进一个精简的候选列表让大模型从中选出最匹配的技能。技能一旦多了这一步不能省略。我曾经偷懒把所有技能卡全文都塞进上下文结果技能超过15个后大模型反而开始混淆不同技能的功能召回准确率直线下降。后来改成先做粗粒度召回再做细粒度执行即先用一段简短描述筛选出3到5个候选技能再把这几个候选的完整技能卡加载进上下文效果才稳定下来。3.5 第五步建立技能回归集每次改动都能验证技能库最怕的就是改A坏B。技能之间可能有隐含的关联和依赖一个技能的描述变了可能影响另一个技能的召回。比如我把query_order_status的when_to_use写得过于宽泛它就开始抢process_return_refund的活儿。解决办法就是建回归测试集。我维护了几百条典型的用户请求每一条都标注了期望调用的技能名称。每次任何技能卡、技能代码或召回策略有改动就全量跑一遍回归集看哪些请求被错误路由到了其他技能。这套东西不复杂但价值极高——它能拦住大部分改动引发的连锁问题。有个细节值得注意回归集里的用例要刻意包含边缘和混淆场景。比如我订单丢了怎么办——这既可能是查订单状态也可能是申请补发或理赔。这类边界用例能逼着你把技能边界定义得更清楚倒逼技能设计质量提升。我用这套方法把类似问题的误路由率从18%降到了4%以内。4. 实战中的坑技能冲突、上下文污染与识别失败的完整排查链路技能库搭起来只是开始运行过程中会遇到各种问题。这一章我挑三个最典型的坑每个都按我实际排查的链路来讲你可以直接拿这套方法来定位你自己的问题。4.1 高发问题技能描述太泛导致意图识别失败现象是这样某开发同学反馈用户问我这个订单还能不能退Agent没有调用退换货技能反而调用了订单状态查询技能回答完全答非所问。我一开始以为是模型能力问题后来逐个排查才发现是技能的when_not_to_use字段没写好。排查过程分三步。第一步复现问题把那条用户请求原样发给Agent观察召回阶段选中的技能候选。第二步查看命中候选的技能卡内容发现query_order_status的技能卡里when_to_use只写了用户询问订单状态、物流异常但缺少用户涉及售后动作时不应使用的排除说明。第三步定位根因大模型在做意图匹配时更倾向于选择它见过的、描述明确的技能而能不能退这个意图在两个技能的描述中都没有得到清晰的覆盖。修复方案很简单但也值得复用我给每个技能卡补充了完整的when_not_to_use字段并新增了一个明确的规则——只要用户请求中包含售后动作词退、换、赔、补发等一律不得调用订单状态查询技能。改完之后这类请求的召回准确率从79%直接回升到96%。你如果也遇到类似的识别失败建议按这个顺序排查先看召回阶段选了什么再看技能卡描述有没有覆盖该意图最后看是技能卡问题还是模型问题。不要一上来就怀疑模型大多数情况是技能边界描述不到位。4.2 隐蔽元凶上下文污染让Agent带着记忆执行技能第二个坑更隐蔽。某次上线一个新技能后老技能的正常率突然掉了。我排查了一整天最后发现是上下文污染。具体症状是用户先问了帮我查下订单A的状态Agent正确调用了查询技能并返回了结果。接着用户又问顺便把订单A退了Agent这次虽然调用了退换货技能但在执行退换货时把它从上一轮对话中看到的订单A状态带入了参数甚至把上一轮模型的回答文本也拼接到了当前回复里导致最终的退款处理逻辑错乱。根因是我的技能执行模块在调用代码函数时把全部对话历史也一起传了进去而大模型在抽取参数时会优先采信上下文里最近的、即便是用户早期消息中的信息。结果是参数抽取不再只认当前这条消息而是从上下文中自由找证据。修复链路如下。第一步把技能参数抽取的输入限制为当前用户消息明确的必填参数提醒不再传入全部历史对话。第二步在技能卡中增加一条强制性说明参数必须从用户当前这条消息中直接提取如果当前消息中不存在该参数立即向用户追问不得使用历史对话中的信息来填充。第三步在代码层加一道校验如果参数来源标记不是当前消息直接拒绝执行并让Agent向用户确认。这三个改动下去问题彻底消失。对比修复前后的数据参数误填率从11%降到了1%以下。这类问题最难的不是修而是意识到根因在上下文而非模型配置。4.3 边界重叠两个技能同时在抢同一个意图第三个坑发生在技能数量多了之后两个技能写的边界太重疊导致Agent每次要么随机挑一个要么先调用A再因为规则冲突回退到B用户看到的就是Agent变来变去。有一次我做了一个账单查询技能和一个消费明细查询技能。前者的定位是查询当前欠费金额和缴费状态后者是查询历史每一笔消费记录。乍一听边界很清楚但实际用户问题里我这个月花了多少钱这句话既可以被理解为账单查询也可以被理解为消费明细查询。两个技能的召回分数都很高Agent就随机选了结果今天答A明天答B用户完全摸不着头脑。排查链路第一步找规律发现随机选的场景都集中在金额汇总类的提问第二步看两个技能卡发现它们的when_to_use都写了用户询问消费、花费、账单第三步确认冲突把两条描述并排对比账单查询写了用于查询欠费、应缴费用和缴费状态消费明细查询写了用于查询每一笔消费记录、花费金额分布。我这个月花了多少钱刚好踩在两者中间。修复方法很经典给技能定义优先级。我在技能索引里增加了一个字段叫precedence数字越大优先级越高。同时把边界重新划清——涉及应缴、欠费、待支付的归账单技能涉及已消费、历史明细、月度汇总的归消费明细查询技能。我这个月花了多少钱划给后者前者在when_not_to_use中增加一条用户询问历史消费汇总时不要使用。之后我再跑回归集这一类问题的路由稳定率恢复到了99%。5. 进阶技能的组合编排、版本演进与质量评估解决了这些问题之后技能库才算真正能稳定服务业务。但这套体系的想象空间不止于此最后一个章节聊三个进阶方向都是我实践下来觉得回报最高的。5.1 组合编排把原子技能变成可嵌套的工作流单独的技能能解决单个任务但真实业务往往是多步骤的。比如用户申请退款这一个听起来简单的需求实际可能包含校验订单状态、确认是否在售后时效内、计算退款金额、创建退款单、通知财务。如果把这五个动作做成一个巨型技能维护起来会要命如果让Agent在会话里一步一步调用它可能中途跳步。我的做法是把技能分成原子技能和流程技能两层。原子技能不可再拆比如查订单状态计算退款金额创建退款单。流程技能则负责编排它读入一个目标意图按预设的步骤序列依次调用原子技能并把上一个技能的输出作为下一个技能的输入。name: process_refund_flow type: workflow steps: - skill: query_order_status input_map: order_id: $context.order_id output_key: order_status - skill: check_refund_eligibility input_map: order_status: $order_status.state order_id: $context.order_id - skill: calculate_refund_amount input_map: order_id: $context.order_id output_key: refund_amount - skill: create_refund_order input_map: order_id: $context.order_id amount: $refund_amount这套设计的好处是原子技能可以复用流程技能可以灵活组合。某天业务调整退款规则只需要改check_refund_eligibility这一个原子技能所有走这个流程的技能自动生效。组合编排让技能库从一堆工具变成了一套可灵活配置的流水线。5.2 版本演进让技能库越用越准确而不是越用越乱技能库不是写一次就完工的静态资产它需要像软件一样做版本管理。我目前的做法是每个技能独立版本整库定期做基线发布。技能独立版本的意义在于线上出了问题可以快速回滚到上一个可靠版本。比如某次我把某个技能的when_to_use改得太激进导致误召回率上升发现后一条命令就把该技能回滚到旧版本其他技能完全不受影响。基线发布则用于保证整套技能的兼容性每两周把所有技能冻结一个版本号组合流程跑一遍完整回归集全部通过后记录为新的基线。变更日志这一步容易被忽略但我吃过亏。某个技能卡在两周内被改了六次没人记录改了什么最后出了性能下降没有任何线索可查。后来我强制要求所有技能卡的改动必须追加一条Changelog每次发版自动生成变更摘要。排查效率提升了一个数量级。5.3 质量评估准确率之外还要看哪些指标最后说评估。很多人衡量Agent技能只盯最终回答对不对但我觉得至少要看四类指标才能看出技能库的真实健康度指标含义我的合理值参考召回准确率正确技能被选中的比例目标95%以上参数误填率技能执行时参数抽取错误的占比目标3%以下回退率Agent调用技能失败后转向兜底话术的占比目标5%以下端到端成功率用户问题最终被有效解决的占比目标85%以上光看端到端成功率是看不出问题在哪一环的。比如成功率掉到80%你得分清是技能没召回、参数填错、执行失败还是回复没答到点子上。所以我在技能执行链路里的每个环节都增加了日志埋点每次调用都记录召回候选、命中技能、参数JSON、执行异常、最终回复。排查问题时直接按调用ID把所有日志拽出来定位到具体环节。另外还有一句经验想分享技能质量评估一定要有分母意识。某个技能看起来成功率只有70%但如果它被调用的场景全是历史遗留的复杂特例那70%可能已经不错了。我在评估每个技能时都会把该技能的请求难度分布也记录在案避免一刀切地用统一标准误伤边缘高难度场景。做Agent技能沉淀这条路我踩过的坑比总结出来的方法论多得多。回头看agent-skills最核心的价值不在一套漂亮的架构而在于它逼着我把Agent从临场发挥的聊天对象变成了有章法的执行者。如果你正被Agent表现不稳定、能力不可复用这些问题困扰我建议你从最小闭环开始——挑一个最高频的业务动作按技能卡的标准写清楚边界用代码守住确定性再把它接进Agent里跑一周看看数据。等这个循环跑顺了你会发现Agent技能的沉淀和维护其实就是一套越用越顺手的基础设施。