
代理型AIAgent跑起来容易跑得稳却很难。最近我把项目里沉淀出来的技能体系整理成了开源组件“agent-skills”不少同行问这东西到底怎么设计、怎么落地。这篇就把我在实际项目中踩过的坑、总结出的经验一次性讲透。先给个定义agent-skills 是一套面向智能体Agent的技能封装与编排方案核心解决三件事——让大模型知道“有哪些能力可用”、让大模型“正确调用这些能力”、让技能“可持续迭代不失控”。不管你是刚接触Agent开发的新手还是已经被工具调用搞得焦头烂额的老手这套思路都能直接拿过去用。我会从设计思路、封装方法、编排策略、评估体系四个维度展开最后附上我实际排查过的经典问题全文偏实战代码示例以Python伪码为主但思想与语言无关。1. 技能体系Agent从“会聊天”到“会干活”的关键一跃1.1 大模型缺的不是智商而是一套“职业手册”很多团队做Agent的第一版就是给大模型配一堆函数让它自己决定调哪个。跑demo没问题一上生产就崩模型根本不知道什么时候该调哪个函数参数填得乱七八糟调用失败后不知道怎么办最要命的是——功能越加越多模型的选择越迷茫。打个比方这就像让一个刚毕业的新人直接上手项目管理你告诉他“遇到问题就解决问题”这等于没说。他需要的是岗位说明书、操作流程、应急预案。Agent也一样模型本身是通用的推理引擎但“在什么场景下用什么工具、怎么用、用完了怎么收尾”这属于专业知识范畴必须通过技能体系这套“职业手册”灌输给模型。agent-skills 的设计初衷就是把“工具函数”升级为“技能单元”。一个技能单元不只是函数签名它至少包含组成部分作用类比技能描述告诉模型“何时用、为何用”岗位职责说明参数Schema定义入参格式与校验规则工作流程表执行逻辑实际动手干活的代码业务动作后置处理结果修正、记忆更新、异常兜底复盘机制元信息版本号、作者、依赖关系、权限标签档案标签有了这套结构模型看到的不再是一个个孤零零的函数而是一个个有上下文、有边界、有行为规范的能力单元。这个转变是质变的。1.2 函数调用与技能体系“能跑”和“跑得稳”的分界线OpenAI 刚出 Function Calling 那阵子大家都觉得Agent的最后一公里通了。但实践下来发现Function Calling 只是“传输通道”它解决的是结构化参数传递的问题而 Agent 的稳定性隐患恰恰不在这条通道里而在通道两端输入端模型怎么从对话上下文里提取出调用意图提错怎么办输出端函数返回值怎么反馈给模型出错怎么处理多步依赖怎么管理agent-skills 把“函数”包了一层“业务皮肤”我在项目里见过无数团队明明用着最先进的模型却因为技能设计得跟裸函数一样效果还不如人家精心封装过的老模型。差距就在这个“皮肤”上。这套体系的落地还能额外带来一个好处技能可以脱离主进程独立调试。函数调用时代调试一个函数必须跑完整条Agent链路技能体系里每个技能都能被单独加载、测试、压测问题定位效率提升好几个量级。2. 技能的定义与封装把能力变成“标准件”2.1 技能描述写好“说明书”里最关键的一百个字技能描述是整个体系中性价比最高的部分也是绝大多数团队最容易忽视的部分。我见过太多技能描述写成这样获取天气信息这跟没写一样模型根本不知道什么时候用。合格的描述至少要包含四个要素说人话使用场景什么类型的请求应该走这个技能给出正反例。能力边界这个技能不能干什么避免模型拿它硬套。输入要求参数缺失时怎么办需要什么前置条件。输出说明返回结构长什么样模型该怎么理解结果。我给团队定的描述模板是这样的示例以天气技能为参考/weather/get 当用户询问当前天气、温度、降水概率、空气质量等气象相关信息时使用本技能。 本技能不支持未来15天以上的预报需转 /weather/forecast、历史天气回溯需转 /weather/history、穿衣建议需转 /lifestyle/dressing。 输入要求必需参数为经度longitude、纬度latitude可选参数为语言lang默认zh。 输出与说明返回实时气象数据包含温度、体感温度、湿度、风向风力、PM2.5等字段。这段描述里我给模型划了两条边界线一个是横向的——这个技能管什么、不管什么、别的技能管什么另一个是纵向的——输入必须满足什么、输出怎么理解。模型有了边界感之后误调用率能降一半以上。这里有个实操心得写完描述后拿10条典型用户问题过一遍模型看它是否准确选中目标技能。这个动作不要偷懒每次改动描述都要回归测试因为模型对措辞极其敏感改几个字可能效果天翻地覆。2.2 参数Schema校验不是“防呆”而是“缓冲层”JSON Schema 本身不复杂但很多团队直接把参数校验放在执行函数的入口处Pass 就执行Fail 就报错——这是错误示范。因为Agent和普通程序不一样普通程序的调用方也是程序参数格式约定好了不会乱传而Agent的调用方是大模型它在生成参数时本质是在“猜”猜错是常态猜对才是运气。正确的做法是把校验做成缓冲层而不是铁闸门。我在 agent-skills 里封装了一个参数处理管线def skill_call_handler(skill_name: str, llm_params: dict) - dict: 技能调用统一入口 1. 参数格式校验类型、必填、枚举 2. 参数缺失补偿从对话上下文中引渡 3. 参数纠偏时区、单位、别名映射 4. 调用真实技能逻辑 5. 结果后处理状态码归一化、内容摘要化 schema skills_registry.get(skill_name).schema normalized schema.normalize(llm_params) # 纠偏层 validated schema.validate(normalized) # 校验层 if not validated.ok: return need_human_guidance(validated.reasons) # 引导模型补充 result execute_skill(skill_name, normalized) return compress(result, max_tokens512) # 压缩后回填上下文注意第五步的结果压缩这步我后面专门讲但先记住大模型的上下文窗口是稀缺资源技能返回的大段JSON绝不能原样塞回去必须做摘要。参数纠偏层我单独说一句它可以实现很多“看似不起眼实则救老命”的能力。比如模型传了“北京”而不是经纬度纠偏层可以内置一个地理编码器自动转换比如用户说“明天”模型可能传日期也可能传“明天”这个词纠偏层要能统一消化。这层做得越好模型就越“聪明”——因为很多所谓“模型理解力不足”其实是工程侧没给它不犯错的机会。2.3 技能注册与热更新给Agent装个“App Store”技能体系规范了以后自然要建设技能注册中心。我推荐大家用声明式注册不要用硬编码注册。所谓声明式就是每个技能一个目录目录里包含SKILL.md描述、schema.json参数定义、code.py实现、meta.yaml元信息。注册中心扫描目录自动生成技能清单挂载到模型上下文中。这样做的好处有两个热更新不重启代理新增技能、修改描述只需刷新技能清单无需重新部署整个Agent服务。技能可编排多人协作不打架一个技能一个目录Git分支管理天然隔离merge即发布。我实际项目中就靠这套目录结构让三个后端同学并行开发不同技能互不阻塞。技能系统的核心价值之一就是把Agent的能力扩展从“改代码”变成“加目录”。注册时需要关注meta.yaml中的一个字段dependency。技能不是孤立的比如“订酒店”技能可能依赖“城市编码解析”技能的能力。这个依赖关系要在注册时声明清楚执行引擎才能构建依赖图避免运行时才发现“这个技能内部还要调另一个技能”的尴尬。3. 技能的编排与执行让Agent学会“打组合拳”3.1 两种编排路径引擎驱动与模型自主技能调用不是单发单收真实任务往往是多步骤的。比如“帮我在上海订一间明天入住的行政房型酒店”拆开看至少需要城市解析技能、酒店搜索技能、房型筛选技能、预订下单技能。这串流程怎么编排我总结下来有两种路径路径一显式工作流确定性优先你在代码里定义好技能的执行顺序和流转条件模型只负责在每个节点提供必要的参数输入。适合流程固定、容错率低的场景比如风控审核、订单支付。路径二模型自主决策灵活性优先把技能清单全量提供给模型由模型自行决定调用顺序与组合方式。适合诉求多变、流程不固定的场景比如内容创作辅助、个人助理类任务。agent-skills 体系两种都支持但我会明确建团队时立一条规矩凡是预期中高频出现的路径一律先固化为显式工作流模型自主决策只服务长尾、非确定性的路径。原因很简单——确定性流程用模型决策等于拿大炮打蚊子既慢又容易飘不确定性流程用硬编码等于用尺子量河流根本覆盖不了。举个例子我团队里做“竞品分析报告”这个Agent早期让模型全自主编排跑是能跑但生成一份报告平均要调20多次模型且每份报告的结构千奇百怪。后来我把“网页抓取—信息抽取—聚合归并—结构化输出—质量校验”这条主链路固化成工作流模型只负责在每个环节做内容优化。结果生成本降60%报告结构稳定性大幅提升而长尾的“临时新增分析维度”这需求依然留给模型玩自主编排。3.2 失败处理与重试最怕的不是失败是“失败的失败”技能调用一定会失败参数错误、接口超时、权限不足、数据为空……失败不可怕可怕的是模型拿到失败结果后不知所措或者更糟——自己脑补一个成功结果。我在技能后置处理里强制要求一个动作失败归一化。所有技能抛出的异常统一转换为标准错误结构{ error_code: SKILL_TIMEOUT, error_message: 上游服务响应超时(6000ms)已自动重试1次, recoverable: true, suggest_action: 稍后重试或改用其他数据源技能 }suggest_action这个字段特别重要。模型遇到错误后如果提示里直接写了“建议怎么做”它照做的概率远高于让它自己思考。这就是“失败的失败”的解法——给模型一条退路而不是把它逼到墙角让它在幻觉边缘试探。重试策略上我实践下来的经验是分三层参数级重试若校验失败说明模型参数生成有问题不重试执行直接返回需要模型补充信息。服务级重试若技能内部依赖的上游接口超时或5xx自动重试1~2次用指数退避间隔200ms起步。路径级重试若本次技能调用链路整体失败触发降级策略换备用技能源或收束为用户可理解的话术。这里有个心态要放平Agent产品不可能做到每次调用都成功但通过失败归一化分级重试可以把“一次失败”的破坏半径控制在局部不演变成整条任务的崩塌这就够了。3.3 上下文瘦身与技能记忆别让Agent“越聊越傻”技能执行返回的结果如何处理直接关系到Agent的长期稳定性。我验过一个残酷的规律Agent对话轮次超过15轮后模型的有效注意力质量显著下降。这不是模型不行是上下文里塞了太多过期信息、原始返回、中间推理过程。所以我对技能返回有一条铁律回填上下文前必须压缩。压缩不是截断而是摘要化重构。比如一个搜索技能返回了20条结果原样塞回去是1万token轻则浪费重则干扰模型判断。我会让技能引擎自动提取返回主体事实、与当前任务相关的实体关系、可作为后续依据的交待压缩后500token就够用了。技能记忆是另一层设计。所谓记忆不是给Agent装个“硬盘”而是让技能执行的结果能被同一会话内的后续步骤引用。举例用户问“跟前天聊的那份合同相比这份有什么变化”前天那份合同的摘要如果没有留存这个需求根本无法完成。我在 agent-skills 里内置了一个轻量记忆槽memory_slot { contract_A_summary: 甲方乙方/标的金额/交付节点, extracted_at: 2025-05-18T10:30:00, source_skill: contract/parser }后续任何技能查询记忆槽时都会先检查时间戳是否陈旧超时比如超过24小时就直接失效避免脏数据干扰。这套机制落地后Agent在跨轮次任务里的延续性显著改善用户明显感觉“它记得我说过什么”。4. 技能的评估与迭代没有度量就没有改进4.1 单技能评估指标别只盯着“调用成功率”很多团队上线技能后只统计一个指标调用成功率。这个数字好看但其实参考价值有限——因为技能可能压根没被正确触发或者触发了但该技能本来就不该出场而成功率统计不出来这些。我实践的技能评估指标分四维维度指标说明触发准确率应调此技能时是否调用了它召回率视角低了说明描述不清触发纯净率调用了它时是否真的该调它精确率视角低了说明边界模糊参数合理率入参在业务规则下是否合理纠偏层到位后此指标应大于九成结果有用率返回结果是否解决用户问题最硬核需要人工标注或LLM Judge这四维凑齐一个技能的健康度才看得清。“触发准确率低”和“参数合理率低”的解决方向完全不同前者改技能描述后者改Schema设计与纠偏层。4.2 回归测试集给技能招“刺头”技能的迭代压力比普通代码大因为模型的输出不固定一个昨天还正常的技能今天可能因为模型版本更新就失灵了。所以我强烈建议给每个技能配一个“刺头集”也就是回归测试集。刺头集的正样本是典型应触发场景负样本是“看似相关实则不该触发”的干扰场景边界样本是模棱两可的模糊场景特殊样本是参数缺失、错类型、错单位等异常输入。每轮技能变更后跑一遍刺头集触发准确率、参数合理率、结果有用率这三个指标任意一个下降本次变更不允许合并。我团队里现在有超过200条刺头用例每次技能描述改一个字我都要过一遍全套。看着麻烦但这才是工程化真正咬合力所在。没有回归保护的Agent项目活跃代码里埋着的时间炸弹比谁都多。4.3 灰度发布与回滚给“模型技能”这对耦合体系上安全带Agent项目有个隐蔽风险技能升级的影响面不可控。普通微服务升级影响的是接口行为Agent技能升级影响的是“模型的决策行为”后者更难预判。所以不能一把梭全量上线我给 agent-skills 配了“技能编排层灰度”策略。操作上很简单技能目录里加灰度配置——按流量比例、按用户特征比如企业客户优先、按场景类型比如只灰度询价场景不下单场景分发。新技能版本跑在小流量监控48小时观察上面说的四维评估指标和平均响应时间、上下文增量全绿才能放量。回滚也要轻量化。技能系统里每个版本都保留不可变快照线上配置文件里一个rollback指令就能切回上一版本。快速、安全、可追溯这是在多次被“模型技能”的组合拳打趴下之后总结出的保命设计。5. 常见问题与排查技巧实录那些文档里不写的东西5.1 模型陷入技能调用死循环现象Agent反复调用同一个技能或者A调完B、B调完又去调A像原地转圈。我用过的排查路径按性价比排序第一查技能返回内容是否明确标示“这是最终答案/这是中间结果”。模型分不清自己是拿到结果了还是要继续干是死循环的第一诱因。解决结果压缩阶段强制给每个技能返回加一个result_kind字段final或intermediate模型决策路径会清晰很多。第二查技能描述里是否写了“调用本技能后请根据结果输出最终回答”。这句话看似多余但很多模型真的会因为缺少这句指引而继续找别的技能来凑数。第三查模型温度参数。超过0.7之后决策随机性激增循环概率也随之上升把决策类任务的温度降到0.3以下立竿见影。5.2 参数幻觉模型编造了用户没给的信息用户只说“帮我订明天的酒店”模型调用订房技能时把入住人姓名填成了“张三”。这类参数幻觉在涉及客户敏感信息的场景里极其危险。我的排查结论幻觉大多不是模型坏是Schema设计里给了幻觉发生的土壤。如果Schema把必填字段标得过多模型被逼着填就会编造。解法区分必填与可选字段必填字段必须真实地从上下文或用户输入中提取。提取不到时进入缺失补偿流程返回模型“查无此信息请向用户询问”。咱宁让流程慢一步不要让幻觉降维打击信任度。在字段描述里显式声明“禁止推测该字段”或“该字段现实来源为XXX系统”给模型戴上紧箍咒。文本生成与结构化数据操作是两个物种用文本生成的惯性去填结构化字段幻觉几乎是必然的Schema 设计要站在反幻觉的第一线。5.3 技能冲突两个技能争着回答同一个问题业务一大技能不免重叠。比如“帮我写一封邮件”会命中“邮件撰写技能”也可能命中“万能文本生成技能”。模型选谁全看命。这类冲突的排查和根治说到底是技能边界的颗粒度设计与冲突仲裁机制。我在 agent-skills 里给每个技能加了priority字段模型在技能排序阶段先按优先级过滤再在剩余候选中做上下文匹配。另外描述中“不支持什么”的负例描述是降低冲突率的一大利器别舍不得写、别怕写多写清楚边界比多让模型思考几秒更重要。排查冲突问题时我推荐把候选技能清单直接打印到日志里看模型在每一步看到了哪些选项、排除了哪些、依据是什么。透明化是排查技能冲突的唯一出路黑盒优化只会让你在“修好A坏了B”的泥潭里越陷越深。写在最后的一些话我这些年做Agent落地最深的感受是大模型是很好用的推理引擎但引擎再猛车的底盘、方向盘、仪表盘也得有人设计。agent-skills 这套技能体系解决的就是底盘问题——让模型有章可循、有据可依、有路可退。从工程的视角看我一直坚持一个观点Agent的产品体验上限由模型决定但稳定性下限由工程决定。技能体系的设计就是把稳定性下限拉高一点点、再拉高一点点。给模型边界感、给调用以缓冲、给失败以预案、给迭代以准绳这些看起来不是什么颠覆性技术但正是这些“不太酷”的功夫决定了一个Agent从demo到产品之间那十万八千里的距离。如果这篇文章能给正在Build Agent的你一些思路上的锚点那这功夫就没白费。技能体系这条路我已经替你踩过不少坑你可以放心往前走。