首页/新闻资讯/正文详情

从零搭建agent-skills技能体系:让大模型从“能聊”到“能干”的关键实战

发布时间:2026/9/25 23:09:37 来源:云帆数科 栏目:资讯中心
从零搭建agent-skills技能体系:让大模型从“能聊”到“能干”的关键实战
最近半年身边做 Agent 的朋友几乎都会碰到同一个词agent-skills。不管是做大模型应用层、写工作流还是做企业内部的知识库助手只要想让模型真正“干成事”最终都会绕回这套能力把不可控的对话能力拆成可控的、可复用的技能。我自己的体会是Agent 项目从 Demo 到生产最大的分水岭不是模型选型而是技能体系搭没搭起来。没有 skills 的时候你只能靠一段超级长的系统提示词去硬撑功能一多就乱模型一换就崩有了 skills 之后每一个动作都有明确的输入输出可测试、可回滚、可扩展。这篇文章就围绕 agent-skills 这个主题把我从零搭建技能体系的核心思路、代码实现和实际踩坑记录完整拆一遍。如果你准备在项目里引入技能机制或者正在做 Agent 的工程化改造这篇应该能帮你省掉不少弯路。1. 先搞明白 agent-skills 在解决什么问题1.1 从“能聊天”到“能干活”中间差了一整套技能闭环大语言模型一开始给用户的印象是“能聊天”后来大家都发现聊天只是表象真正的价值是让模型帮你执行任务。但执行任务和生成文本是两回事。你让模型写一段营销文案它可以直接生成质量高低另说你让模型帮你在数据库里跑一张报表在代码仓库里提交一次变更或者把一份 PDF 按指定字段结构化抽取出来它就抓瞎了因为模型本身没有操作外部系统的能力。agent-skills 解决的就是这个断层。它的本质是把“模型能不能做”这个问题拆成“模型有没有对应技能”的问题。技能是一种封装单元它定义了某个任务的触发条件、输入参数、执行逻辑、输出格式和失败处理方式。模型负责判断“什么时候该用哪个技能”而真正落地执行的是宿主程序里的代码逻辑。这样模型始终做它最擅长的事——规划与理解而确定性操作交给代码完成两者各司其职。我还记得最早试着用纯 Prompt 做工具调用时的痛苦。当时为了给一个智能客服接上订单查询和退款功能把几十段 if-else 描述全部塞进系统提示词结果模型经常选错工具参数也传得七零八落。后来换成 skills 机制把每个技能描述压缩成两三行配合结构化参数约束选型和参数准确率一下子就上去了。原因很简单规范化的技能描述远比几大段口语化说明更容易让模型稳定理解。1.2 我理解的技能边界工具、提示词、工作流和经验沉淀的统一体很多人第一次接触 agent-skills 会觉得它就是把 API 包装一下起个名字告诉模型怎么调用。但真正做过之后就会发现技能这个词比“工具”要宽得多。工具通常只对应一个可执行函数而技能可以包含提示词策略、多步骤流程、前置条件、后置校验甚至可以有内部状态。举个例子一个“数据清洗”技能它不只是调用一个清洗函数还可能需要先判断列的缺失率再决定是删除行还是填默认值最后输出一份清洗报告。这套逻辑里既有模型步骤识别字段、判断清洗策略也有确定性步骤pandas 处理、统计它们是绑在一起的。这其实就是 agent-skills 里很关键的设计思想不确定的部分尽量收敛确定的部分尽量代码化。技能也承载了经验沉淀。你在某类任务上不断调优最后发现“每次提取采购单的时候必须让模型先拆分成行项目再逐行提取出错率最低”这个经验如果写死在业务代码里换个场景就浪费了但封装成技能后它变成了 Agent 可以随时调用的资产。这也是我理解里 agent-skills 的真正价值它不是单一接口而是“能稳定完成某类任务的最小能力包”。2. 从零设计一套 agent-skills 技能体系2.1 技能的三个核心定义名称、描述、参数结构设计 skill 的第一步不是写代码而是定规范。我自己的习惯是每个技能必须包含四件事名称name、描述description、参数定义parameters和执行函数execute。名称要短描述要准参数要严。这三点非常影响模型的表现。先看名称。名称是模型识别技能的唯一标识不能用一串无意义的 UUID也不能太长。比如执行销售订单查询的技能我建议叫query_sales_order而不是销售订单查询功能实现。英文小写加下划线的风格在大多数模型的工具选择中表现更稳定这是语义清晰和 token 消耗之间的平衡点。再看描述。描述的作用是让模型判断“当前用户意图该不该用这个技能”。所以描述里不能只写一句话功能说明最好包含使用时机、适用对象、典型场景。比如“当用户想查询历史订单、核对订单金额或追踪发货状态时使用”。我实测过把描述写成有条件的完整句比写成“查询订单”四个字工具命中准确率高不少。参数定义建议直接用 JSON Schema。这个应该是目前各种 Agent 框架的通行做法但很多人只是套模板不理解为什么。其实关键在于模型需要从用户原话中抽取出结构化的参数而 JSON Schema 能清晰定义字段名、类型、必填项、枚举值和描述模型抽参数时的幻觉率会显著下降。比如一个下单技能的items字段如果只定义成数组模型会随意构造内容如果定义成对象数组并提供每个子字段的类型和示例结果会规范很多。2.2 技能编排从单点技能到多技能协作当技能数量一多就会引出编排问题。一个真实任务很少只靠一个技能完成。比如“帮我整理一下这个月所有项目组发过的周报提取出风险项并汇总成邮件”这里面可能涉及文件解析技能、文本提取技能、风险识别技能、邮件起草技能和发送技能。模型需要决定调用的顺序、依赖关系以及中间结果的传递。我在项目里的做法是引入两层结构底层是原子技能上层是编排策略。原子技能只做一件事比如extract_file_text、parse_csv这种容易测试、容易复用。编排策略则写在 Agent 的执行循环里模型根据用户目标逐步决定下一步调用哪个技能并把上一个技能的输出作为下一个技能的输入。这里最怕的是把编排逻辑写死成流程那就退化成传统的工作流引擎失去了 Agent 的动态规划能力。当然全交给模型动态编排也有风险。我的解法是给关键路径加上技能间依赖声明比如某个技能执行前必须检查前置技能是否完成否则直接返回错误。这样既保住了灵活性又给了系统可管理的边界。对于金融、医疗这类强合规场景甚至可以把依赖关系做成强校验不满足条件模型就不能跳过。2.3 技能评估与回归没有度量就不要提上线技能体系上线前一定要做评估这是很多团队忽略的点。如果只是“试了几个例子感觉不错”就上线后面用户一多问题会炸得很突然。我建议每个技能都建一个测试集至少二十条代表性的输入里面覆盖普通情况、边界情况和错误输入。评估指标分两层单技能层和端到端层。单技能层看意图识别准确率、参数提取正确率和执行成功率。比如测试集中有“查一下昨天华南区的订单”模型是否选到了query_sales_order参数region华南区、date昨天是否被正确转换。端到端层则是看完整任务完成率任务最终给出用户可用的结果而不是仅仅调用对了技能、失败在下一步。有了评估集你在每次调整技能描述、改参数结构或者换模型的时候都能跑一遍回归。我见过很多“模型一升级线上 Agent 就抽风”的案例原因就是没有回归机制。其实做一套简单的自动化评估脚本并不复杂但能省下大量的线上事故排查时间。我在后面第 3 部分会给出一个最小实现复制过去就能跑。3. 把 agent-skills 落到代码里的完整实操3.1 一个最小的技能管理器BaseSkill 与注册表先动手写一个最简的技能基类和注册机制。我会用 Python 写因为现在做 Agent 生态实验用它最顺手。你如果熟悉 TypeScript思路完全一样只是签名写法不同。# skill_base.py from typing import Any, Callable, Dict, Optional class BaseSkill: 所有技能的基类定义模型侧看到的技能描述和执行入口。 name: str description: str parameters: Dict[str, Any] {} def execute(self, **kwargs) - Any: raise NotImplementedError def to_schema(self) - dict: return { type: function, function: { name: self.name, description: self.description, parameters: self.parameters, }, } class SkillRegistry: 技能注册表统一管理所有可被 Agent 调用的技能。 def __init__(self): self._skills: Dict[str, BaseSkill] {} def register(self, skill: BaseSkill): self._skills[skill.name] skill def get(self, name: str) - Optional[BaseSkill]: return self._skills.get(name) def list_schemas(self) - list: return [skill.to_schema() for skill in self._skills.values()] def execute(self, name: str, arguments: dict) - Any: skill self.get(name) if skill is None: raise ValueError(fskill not found: {name}) return skill.execute(**arguments)这段代码核心就是BaseSkill和SkillRegistry。BaseSkill让每个技能都统一暴露name、description、parameters和execute这是模型层和代码层解耦的关键。SkillRegistry则负责把所有技能汇总起来向模型提供 schema 列表同时在实际执行时根据模型选择的 skill 名分发到对应函数。这里有一个容易忽略的点to_schema()要生成贴近 OpenAI function calling 协议的格式因为这是目前最通用的模型接口。即使你用的是其他模型大部分也支持兼容格式。如果后续切换框架只需要把to_schema()的输出稍微转换一下不用改各个技能的内部实现。3.2 一个可以直接复用的技能示例周报风险提取为了演示完整链路我写一个真实业务场景里很常见的技能从周报文本中提取风险项。这个技能不是简单调用一个大模型接口而是要经历“文本切分、模型抽取、结构化输出”三个步骤应该在 execute 内部完成。# skill_weekly_risk.py import json from typing import Any from skill_base import BaseSkill class WeeklyRiskExtractSkill(BaseSkill): name extract_weekly_risks description ( 从项目周报或项目状态描述中提取风险项。 当用户提到风险、阻塞、延期、依赖问题时使用。 ) parameters { type: object, properties: { content: { type: string, description: 周报原文内容尽量完整传入。 } }, required: [content] } def execute(self, content: str, **kwargs) - Any: # 实际项目中这里可以调用模型也可以走规则 模型混合解析。 # 下面是一个简化的示例实现。 prompt ( f从下面的周报中提取风险项输出 JSON 数组 f每个元素包含 risk 和 level 字段\n{content} ) # 假设已封装好 call_model 函数 raw call_model(prompt) try: return json.loads(raw) except json.JSONDecodeError: return {error: 模型输出不是合法 JSON, raw: raw}实际做的时候execute 里可不止一个模型调用。我的习惯是先判断文本长度超过 token 上限就按段落切分分块提取后再合并去重结果还需要做一次 schema 校验字段缺失就重试一次。这个技能的难点在于“风险”这种概念对模型来说比较模糊所以描述里一定要给例子比如“延期风险”“人力缺口”“外部依赖阻塞”都算。这个示例其实点出了 agent-skills 的一个核心理念技能内部可以很复杂但对外接口必须简单。模型只需要传入一个content字段剩下的切分、解析、校验都在技能内部完成这样模型侧的认知负担很低调用稳定性自然更高。3.3 把技能挂到 Agent 上的两种常见姿势技能定义好之后怎么让模型“看到”技能并调用现在最主流的有两种姿势function calling 风格和 ReAct 文本风格。我这里分别说一下我的实现差异和选型理由。第一种是 function calling。你先把所有技能的 schema 列表传给模型模型在推理时如果决定调用某个技能会返回一个结构化对象里面包含name和arguments字符串。你的代码解析这个对象从注册表取出对应技能执行再把结果返回模型生成最终回答。这种方式优点是稳定、字段清晰适合大多数业务场景。我的代码里SkillRegistry.list_schemas()就是为这个姿势准备的。第二种是 ReAct 模式。模型不返回结构化工具调用而是在回答内容里输出一段标记比如“Action: extract_weekly_risks\nAction Input: {...}”你再用正则或解析器从文本里提取。这种方式兼容老旧模型但对模型输出格式要求很高容易因为一个换行符出问题。除非你的模型不支持 function calling否则我建议优先用第一种。我自己的经验是如果是企业内部老模型可以两种都保留先解析 function calling失败时回退到 ReAct。但回退逻辑要有频率限制否则线上会看到大量解析失败告警。大部分情况下用支持 function calling 的模型加一个健壮的执行层就够了别给自己找额外维护负担。4. agent-skills 实战中的常见问题与排查4.1 技能调用失败的三个高频原因我在上线初期遇到的第一个问题就是模型偶尔调用一个不存在的技能名。原因通常是技能注册表在构建时漏掉了某个技能但模型侧 schema 列表来自旧缓存也可能是因为技能描述写得太接近模型混淆了名字。排查第一步永远是去日志里查实际返回的name是什么别光看用户反馈。第二个高频问题是参数乱传。模型把日期传成字符串“昨天”或者把用户随口一句“大概几个”当成数量参数传进来。解决办法不是让模型变聪明而是在参数 Schema 里增加格式约束和示例。比如日期字段写成format: YYYY-MM-DD数量字段用minimum、maximum去限制。如果模型总把自然语言时间翻译错还可以在技能内部做一个时间表达式解析把“昨天”“上个月”先解析成具体日期再进业务逻辑。第三个高频问题是执行超时。技能内部调外部 API结果 API 慢了或者报错Agent 就卡住了。我的做法是给每个技能加统一超时时间默认十秒超时后返回一个明确错误码并告诉模型“可以尝试换一种表述或请用户稍后再试”。这样模型能主动向用户解释而不是一直沉默。某次线上故障就是因为第三方接口返回了 502我改成超时兜底加上重试一次策略后用户体感好了很多。4.2 技能互相干扰与上下文污染怎么处理当技能数量超过二十个你会开始遇到一个诡异的现象单独测每个技能都正常但全部挂上 Agent 后模型频繁选错技能。本质是技能 schema 太多模型注意力被稀释了。我试过把描述写得越来越详细结果更差后来改成精简描述并把相似技能合并成一个入口反而准确率回升。上下文污染是另一个坑。模型调用第一个技能后返回了一段很长的原始结果然后模型会把这堆内容全部写进后续的上下文里导致第二轮技能决策时被无关内容带偏。我的解决办法是控制技能结果的截断长度输出超过一定大小时不要原样回传而是先做摘要。比如文件解析结果几千行先转成“共 152 行包含 6 个章节”模型就已经能做下一步判断不需要看完整内容。上下文污染还来自历史对话。用户问过的东西比如一次订单查询的完整订单明细其实在决策下一轮技能时可能并不需要。所以我建议在构造给模型的上下文时把上一轮技能调用的中间结果单独放一个字段而不是混在对话历史里。如果框架不支持至少要做消息裁剪保证最近几轮正常更早的细节做摘要。4.3 如何做好技能白名单与权限边界agent-skills 直接面对的是底层操作如果权限控制没跟上风险是很大的。尤其当技能可以读文件、发邮件、改数据库的时候模型一旦被诱导就可能做出越权操作。这里我坚持的原则是模型只能看到当前用户有权限的技能列表后台每个技能都绑定一个权限标签。具体实现上注册表不只保存技能对象还要保存需要的权限码。构造给模型的 schema 列表之前先根据当前用户的权限过滤一遍。比如普通员工能看到query_own_salary但不能看到update_salary_level。即使模型因为 prompt injection 想调用越权技能它在 schema 列表里根本看不到也就无从调用。执行层还需要做二次校验。用户上下文里传递一个user_id和role技能执行前由装饰器或中间件检查user_id是否匹配资源 owner。比如查询订单技能如果订单 owner 不是当前用户直接返回无权限。这个校验不能依赖模型必须在代码层强制。这个是我认为 agent-skills 体系里最容易忽略、但绝对不能省的一环。5. 普通开发者上手 agent-skills 的三个建议5.1 别一上来就做技能市场先做三个技能跑通闭环很多人看到 agent-skills 就想着做一个平台、做一个技能市场让大家都来上传技能。我在早期也踩过这个坑最后发现真正的瓶颈不是生态而是你自己能不能把少数几个技能做到高可用。正确的打开方式是先挑三个高频业务场景把它们做成技能跑通“用户提问 - 调用技能 - 返回结果”完整链路。这三个技能最好覆盖不同的类型一个偏信息查询比如查订单或查文档一个偏内容生成比如写周报摘要一个偏操作类比如创建工单。这样你能检验技能体系对三类任务的适配度。我当时用订单查询、客户情绪分析、工单创建三个技能做验证很快就把注册表、参数校验、权限拦截这些基础设施打磨了一遍。跑通闭环还有一个作用是让你能观察真实用户的用法。你会惊讶地发现用户提问方式跟测试集差很远。比如测试集里写“帮我查一下单号 123”真实用户会说“我昨天买的东西发货了没”模型需要先推测查询对象和范围。所以技能描述要留有余地不要只匹配关键字。5.2 技能迭代不能靠拍脑袋要跟着测试集走技能不是写一次就结束的。每次模型升级、业务规则调整都可能让某个技能表现变差。我建议把技能测试集当成最小产品资产来维护每个技能变更都必须跑一遍回归通过以后再合并上线。这不是流程繁琐而是对自己的保护。测试集用例也要持续补充。每次线上出现一次模型选错技能或者参数解析失败的案例就把案例脱敏后加入测试集然后修复描述或参数定义。这样你的测试集会越来越接近真实分布。大概跑两三个月后每次改动权限都会非常有底气因为你清楚哪些用例会导致 dangerously 的行为哪些可以安全放松。如果团队多人协作还可以给技能加版本号。技能对象里包含version字段变更时递增。执行日志里记下版本出问题就能快速定位是哪个版本的技能行为发生了变化。这个字段虽然小但在线上排查时能省很多时间。5.3 我后来最常用的一条技能设计心法最后分享一个我在多次调整后总结出来的设计心法技能描述第一句写“这个技能在什么情况下用”第二句写“这个技能不能做什么”。大多数人的描述只写了能做什么忘了写边界模型就会在模棱两可的意图上强行调用错误技能。加上“不能做什么”之后错误的调用会明显减少。比如一个“生成周报摘要”的技能描述可以是“当用户要求整理周报重点时使用。如果用户要求的是翻译周报或修改周报内容不要使用本技能。”我在几个项目里都验证过这种正反两面描述比单纯强调正面能力更稳。它本质上是在给模型提供排除条件帮助模型更快收敛到正确意图。整个 agent-skills 的搭建过程其实并不神秘核心就是把不确定性收拢进技能边界把确定性的操作交给代码和权限体系。你只要有耐心打磨第一个技能后面的事情就会越来越顺。等你把技能库积累到几十个的时候Agent 的能力边界和价值会远远超过当初那一段超级提示词的极限。

相关推荐

武汉 Q5L 维修去哪?按高发故障逐个看处理能力
武汉 Q5L 维修去哪?按高发故障逐个看处理能力

判断武汉哪家店修 Q5L 专业,不用听门店怎么宣传,把 Q5L 最容易出问题的几个系统摆出来,看它对每个故障怎么诊断、怎么修、有没有同车型工单,能力高低一目了然。Q5L 搭载三代 EA888 发动机和 DL382 七速湿式双离合,空调… · 2026/9/25 23:09:37

Atlas 300V 24G上从零部署YOLO:推理加速卡的完整实战指南
Atlas 300V 24G上从零部署YOLO:推理加速卡的完整实战指南

先回答一个很多人搜索时最先问的问题:Atlas 300V 24G到底是不是“运算加速卡”?准确讲,它是一张AI推理加速卡,属于昇腾架构的推理产品线,不是传统意义上的GPU图形卡,也不是用来做大模型训练的卡。它存在的意… · 2026/9/25 23:09:37

Dify+Ollama+DeepSeek-r1 私有化部署实战:从架构选型到避坑指南
Dify+Ollama+DeepSeek-r1 私有化部署实战:从架构选型到避坑指南

简介:一套面向企业IT运维与技术人员的DifyOllamaDeepSeek-r1私有化部署资源包,聚焦数据安全与个性化服务场景,解决在隔离网络环境中搭建完整AI数据处理链路的需求。资源共36个文件,涵盖PDF部署手册、Docker离线安装包(… · 2026/9/25 23:09:04

Linux死机排查实战:分层定位、SysRq救援与kdump崩溃分析
Linux死机排查实战:分层定位、SysRq救援与kdump崩溃分析

简介:这是一份面向Linux运维工程师与系统管理员的故障排查参考资料,聚焦系统死机或崩溃后如何有效采集与分析现场信息,帮助判断问题源于硬件故障还是应用程序缺陷。资源以doc文档形式交付,压缩包内共1个文件,体积约47K… · 2026/9/25 23:46:05

Linux死机别急着重启:SysRq与kdump现场取证指南
Linux死机别急着重启:SysRq与kdump现场取证指南

简介:这是一份面向Linux运维工程师与系统管理员的故障排查参考资料,聚焦系统死机或崩溃后如何有效采集与分析现场信息,帮助判断问题源于硬件故障还是应用程序缺陷。资源以doc文档形式交付,压缩包内共1个文件,体积约47K… · 2026/9/25 23:45:52

Linux死机处理全指南:从分类、取证到恢复的实战流程
Linux死机处理全指南:从分类、取证到恢复的实战流程

简介:这是一份面向Linux运维工程师与系统管理员的故障排查参考资料,聚焦系统死机或崩溃后如何有效采集与分析现场信息,帮助判断问题源于硬件故障还是应用程序缺陷。文档围绕Core dump、Diskdump、Netdump三种机制展开,分别覆盖应用… · 2026/9/25 23:45:52

Windows 下 Dify 部署实战:30 分钟跑通 Docker Compose 与 WSL2 环境
Windows 下 Dify 部署实战:30 分钟跑通 Docker Compose 与 WSL2 环境

简介:这份资源是面向Windows平台开发者的Dify Hackathon环境部署文档,适合具备Git、Docker与Python基础、准备参与Dify Hackathon或搭建本地大模型应用开发环境的技术爱好者。内容围绕前置环境准备、代码克隆、环境变量配置、docker-compose服务启动、数… · 2026/9/25 23:45:39

1700万K12题库MySQL导入与LaTeX公式渲染实战指南
1700万K12题库MySQL导入与LaTeX公式渲染实战指南

简介:这份资源面向在线K12教育从业者与题库系统开发者,聚焦数学、物理、化学等学科试题在数据库中的存储与公式显示难题。包内以MySQL数据库文件为核心,配合说明文档完整呈现试题结构、LaTeX公式录入与前端渲染方案,并提供可直接参… · 2026/9/25 23:45:39

R语言高光谱数据分析全流程:从数据读取到分类可视化
R语言高光谱数据分析全流程:从数据读取到分类可视化

简介:一份面向R语言用户的开源高光谱数据分析资源,围绕hsdar包提供从数据导入、预处理到特征提取、分类建模及可视化的完整流程。内容涵盖ENVI、HDF、GeoTIFF等多种格式支持,以及平滑、大气校正、主成分分析、支持向量机、随机森林等常用方法… · 2026/9/25 23:45:33

数值优化(Numerical Optimization)学习系列-03-共轭梯度方法(Conjugate Gradient)
数值优化(Numerical Optimization)学习系列-03-共轭梯度方法(Conjugate Gradient)

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:31

创维E900V22D刷机全攻略:S905L3SB芯片兼容性解析与救砖实战
创维E900V22D刷机全攻略:S905L3SB芯片兼容性解析与救砖实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:31

MQTT协议原理与Broker服务器搭建实战:从Mosquitto到EMQX
MQTT协议原理与Broker服务器搭建实战:从Mosquitto到EMQX

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:37

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码