☰
构建Agent技能库:从Prompt膨胀到结构化能力的完整指南
2026/10/14 9:54:22 网站建设 项目流程

做Agent开发这一年多,我最大的感触是:模型的推理能力决定了Agent的上限,但真正拉低下限的,往往是那些脏活累活——格式解析、数据清洗、工具调用、领域规范。以前我习惯把这些逻辑硬编码进Prompt,结果Prompt越积越厚,一个Agent从几百token膨胀到几千token,改一处就牵一发动全身。后来接触了Skills(技能库)这套思路,才算是把乱麻理清了。

现在市面上讲Agent的文章很多,但大多在讲ReAct循环、讲记忆机制、讲工具调用框架,很少有文章认真聊一个事:Agent到底靠什么把任务干利索?我的答案是技能。这篇东西不是什么教科书,就是把我自己搭建Agent技能库的全过程、设计思路、踩过的坑,一次性讲清楚。如果你正在做Agent落地,或者正在被Prompt膨胀、任务拆解不细、调用结果不稳定折磨,这篇文章应该能帮你省下好几周的试错时间。

1. Agent Skills是什么,为什么必须聊它

1.1 从Prompt膨胀说起的痛

先聊个真实场景。我之前做某跨平台系统的自动化助手,需要让Agent实现“从文档里提取信息,做校验,按固定模板输出”这么一条链路。刚开始我老老实实把所有规则写进系统提示词里:字段格式是什么、哪些字段必填、超出范围怎么处理、输出要JSON还是表格……第一次写完大概800token,还能撑住。后来越加越多,规则之间有重叠、有冲突,最终涨到2000多token,模型调用成本上去了,效果反而变差——因为它被大量相互纠缠的规则干扰,开始自作聪明地“理解”规则而不是“执行”规则。

当时我一度以为是大模型能力不够,后来复盘才发现,问题出在组织方式上。把技能当Prompt写,等价于让一个人一边读操作手册一边干活,手册还越来越厚;把技能封装成独立的、可被按需加载的模块,等价于工具箱里的扳手和螺丝刀——要用的时候取出来,用完放回去。

这个认知转变,就是我决定深入搞Agent技能库的起点。所谓Skills,本质上就是一套结构化的能力封装方案:用固定的目录、固定的描述格式、固定的范例,把Agent完成某类任务所需的知识、步骤、约束和代码模板打包起来。模型在任务过程中按需加载,而不是从头到尾背负全部。

1.2 技能库能解决什么问题

技能库解决的不是“模型怎么思考”的问题,而是“模型怎么知道该怎么干活”的问题。

举个例子:你让Agent帮你格式化一份CSV,它知道CSV是什么,但它不一定知道你所在团队对CSV的字段命名规范、日期格式要求、空值处理策略。这些都是你踩过坑总结出来的“组织知识”。如果没有技能库,这些知识只能塞进Prompt,或者靠每次对话现讲。有了技能库,这些知识被沉淀成一个独立的技能,Agent遇到CSV处理任务时自动触发,里面既有规则描述,又有正反范例,它照着做就行。

从架构上看,技能库提供了几个实实在在的好处:第一,Prompt瘦身,系统提示词只保留身份、目标和底线约束,领域细节全部外置;第二,能力可复用,同一套技能可以同时供给不同的Agent使用,不用每个Agent重新写一遍规则;第三,可测试,技能是独立的,可以单独验证,不需要把整个Agent跑起来才能知道规则对不对;第四,可演进,技能版本化管理,改坏了能回滚,不像改Prompt那样改完就没了。

1.3 我的核心设计思路

我当时给自己定了几条原则,后来证明都很关键。

首先是单一职责。一个技能只解决一类问题,不要做一个“啥都管”的超级技能。看起来省事,实际调试和复用都会很痛苦。

其次是描述大于内容。技能里真正给模型看的不只是步骤说明,更重要的是“什么时候该用这个技能”的描述。模型靠描述做路由,描述模糊,它就不知道该在什么时候触发。

最后是范例驱动。模型从范例里学到的格式偏好,远超你写十句“注意保持输出格式统一”。每个技能我都坚持放一段“输入示例 + 输出示例”,效果立竿见影。

这几条原则,贯穿了我后面搭建整个技能库的全部过程。

2. 技能库的整体设计:目录、结构、命名

2.1 技能库目录规划

技能库的物理组织我参考了主流做法,按“领域/技能”两层来铺:第一层是领域,比如“数据处理”“文本分析”“API对接”;第二层是具体技能,比如“CSV清洗”“JSON校验”“Restful接口调用”等。每个技能都是一个独立目录,目录里包含一个说明文件(SKILL.md),外加若干资源文件。

这是我的技能库目录结构:

skills/ ├── data_processing/ │ ├── csv_cleaner/ │ │ ├── SKILL.md │ │ ├── examples/ │ │ │ ├── input_sample.csv │ │ │ └── output_sample.csv │ │ └── scripts/ │ │ └── clean_csv.py │ ├── json_validator/ │ │ ├── SKILL.md │ │ └── examples/ │ └── text_formatter/ │ ├── SKILL.md │ └── rules.txt ├── api_integration/ │ ├── rest_client/ │ │ ├── SKILL.md │ │ └── scripts/ │ │ └── client_template.py │ └── webhook_sender/ │ ├── SKILL.md │ └── schemas/ └── ...

这个目录有几个好处:一是路径即命名空间,模型能通过路径快速理解技能归属;二是技能自带脚本和资源,不需要把代码嵌在说明文档里,代码更新只动对应文件;三是可以按目录批量加载,比如这个Agent只做数据处理,那就只挂载data_processing目录,避免无关技能干扰路由判断。

2.2 SKILL.md里面到底写什么

技能目录的灵魂是SKILL.md。开始我以为随便写点说明就行,后来反复调整才找到合适的结构。我现在固定用四段式:元信息、触发条件、执行步骤、示例。

元信息放在最前面,用键值对的方式写,方便模型快速识别。主要包含技能名称、所属领域、依赖文件路径、版本号。元信息不用太长,但版本号一定要有,否则后面技能迭代时你根本不知道模型加载的是哪个草稿。

触发条件这一段是整个文档里最重要的。我会用“当…时”句式写,把能触发这个技能的场景尽量枚举全。比如CSV清洗技能的触发条件:“当用户要求处理CSV文件、表格数据、导出数据清洗结果时;当输入数据包含重复行、空字段、格式不一致问题时;当用户明确提到需要规范日期格式或数字精度时。”

执行步骤就是给模型看的分步指南,但别写成散文。我一般用有序列表,每一步写明输入是什么、用什么方法做、结果输出到哪里。如果这一步涉及脚本调用,就写明“调用scripts/clean_csv.py,传参为待处理文件路径”。这里要特别注意:执行步骤里的措辞要尽量确定,不要出现“适当”“尽量”“大概”这类模糊词,模型对模糊指令的执行结果会非常随机。

2.3 技能描述与命名:决定成败的细节

技能命名要像变量名一样讲究。最开始我贪图好记,给技能起名叫“helper”“utils”,结果模型面对一个模糊任务时根本无法判断该不该调用它。后来改成“csv_cleaner”“json_validator”这种动宾结构,触发准确率立刻上了一个档次。命名规则我总结为三要素:对象+动作+场景。比如“yaml_to_json_converter”比“converter”好;“webhook_notification_sender”比“notify”好。

技能描述和命名一样关键。有些技能库的SKILL.md里有一栏叫“description”,我在早期没当回事,随手写了个“用于处理数据”,结果模型什么任务都往这个技能上套,输出自然一塌糊涂。后来我把description当成路由条件来写,明确了“只处理用户明确提供文件路径或文件内容的场景,不主动推断用户未提供的文件”。

经验说透一点:模型选择技能,本质上是“文本匹配”——你的描述和当前任务文本越相似,它越容易触发。所以描述里应该使用任务中可能出现的原词、同义词和常见说法。这跟搜索引擎写关键词是一个道理。

3. 实操全流程:从零搭建一套Agent技能库

3.1 第0步:先想清楚技能边界

动手写任何SKILL.md之前,先想清楚这个技能的输入、输出、边界和失败条件。这一步偷懒,后面改到死。

我一般用一张表来辅助设计:

设计项说明示例(csv_cleaner)
技能目标一句话说清楚干什么将混乱的CSV数据清洗为结构化标准格式
输入条件调用它需要哪些前置条件输入为CSV文件路径或文件的文本内容,且编码为UTF-8
输出格式结果长什么样标准化后的CSV文件,字段顺序固定,日期格式为YYYY-MM-DD
边界哪些情况下不能用这个技能不处理Excel二进制文件;不做语义去重
失败条件什么情况下要停下并报告文件无法解析、列数不一致、超时未返回结果

这张表其实就是给SKILL.md打草稿。你把它填完,文档结构已经出来了70%。

3.2 实操示例:从零写一个“CSV清洗”技能

拿上面这个csv_cleaner为例,我一步步给你看我是怎么配置的。

第一步,创建目录结构:

mkdir -p skills/data_processing/csv_cleaner/{examples,scripts} cd skills/data_processing/csv_cleaner

第二步,写SKILL.md。下面这个版本是我多次迭代后沉淀的最终框架,供参考:

--- name: csv_cleaner domain: data_processing version: 1.2.0 dependencies: - scripts/clean_csv.py --- ## 触发条件 - 当用户要求处理CSV文件、表格数据、导出数据清洗结果时; - 当输入数据包含重复行、空字段、格式不一致、日期格式混乱等问题时; - 当用户明确提到需要“规范化”“清洗”“整理”CSV数据时。 ## 输入 - 必要输入:CSV文件路径,或直接粘贴的CSV文本内容。 - 可选输入:目标字段顺序、日期格式、空值处理策略。未提供时使用默认策略。 ## 执行步骤 1. 读取CSV内容。如果是文件路径,先检查路径存在性以及扩展名为.csv,再读取;如果是文本内容,直接解析。 2. 执行字段标准化: - 去除字段首尾空格; - 统一日期格式为YYYY-MM-DD; - 数值字段统一保留两位小数。 3. 执行行级去重:所有字段完全一致的行只保留第一行。 4. 空值处理:指定字段为空时填入NULL字符串,其余字段为空时删除该行。 5. 按目标字段顺序重新排序列,未指定的字段追加到末尾。 6. 输出清洗后的CSV内容或文件路径。 ## 示例 输入示例: ```csv name,date,amount "Alice ","2024/3/1",100 Bob,2024-03-01,100

输出示例:

name,date,amount Alice,2024-03-01,100.00 Bob,2024-03-01,100.00

失败处理

  • 文件路径不存在:报错并提示用户检查路径;
  • 解析后列数不一致:报错并返回错误行上下文;
  • 输入为空:不执行清洗,直接提示用户补充输入。
第三步,写scripts/clean_csv.py。这个脚本不需要太复杂,但一定要能直接跑通,模型调用时你不想让它面对一个跑就报错的脚本。我当时写了个两百行左右的Python脚本,覆盖了上面的标准化逻辑,并且用命令行参数接收输入输出路径。写完用三份不同格式的CSV测试过才放进目录。 第四步,准备examples。很多教程不重视examples,我强烈建议你重视。模型看两遍范例,比自己读十行规则学得快。我给csv_cleaner准备了两个范例:一个是“正常输入+输出”,另一个是“带问题输入+已修复输出”。后者价值更高,因为它天然给模型展示了“技能要怎么修正问题”。 ### 3.3 如何设计“越界”时的兜底行为 技能设计里最容易被忽略的是“什么时候不能干”。我在早期完全不写边界和失败处理,结果模型在CSV文件路径给错、文件本身编码不对、字段数对不上这些场景下,会继续硬着头皮输出一个“看起来差不多”的结果。这对用户来说非常危险,因为你不知道它哪一步是瞎编的。 后来我要求每个技能必须写失败处理,并且明确写一句“遇到无法处理的情况必须停止并报告,不得猜测输出”。这一条加上之后,Agent的行为可靠度高了一大截。说实话,这是我在这个项目里最值的一条经验。 ### 4. Agent调用技能的三种方式与路由逻辑 ### 4.1 方式一:技能说明注入式 最简单的方式,把所有SKILL.md的内容塞进系统提示词。早期我图省事就这么干,直接拼接,结果Prompt长度飙到5000token,调用延迟肉眼可见地上升。这种方法适合技能库很小(3~5个技能)或者初版验证时用,优点是一切都在上下文里,模型不会漏调用;缺点是不可扩展、成本高、相互干扰明显。 ### 4.2 方式二:按需加载式 稍微成熟一点的做法,是在系统提示词里只放“技能清单”和“技能名+一句话摘要”,模型判断需要某个技能时,再通过工具调用获取完整的SKILL.md内容。好处是大部分任务只需要加载一两个技能,上下文占用大幅下降。缺点是多了一次内部调用的延迟,而且在摘要写得不准确时,模型可能压根不会去加载。 这种方式适合技能库规模在十到几十个的场景。比如我的Agent核心系统提示词里,技能清单是这样组织的: ```text 可用技能: - csv_cleaner:用于CSV数据清洗、格式化、去重,处理表格数据; - json_validator:用于JSON结构校验、字段类型检查、Schema比对; - rest_client:用于调用RESTful接口,携带认证信息并解析响应; - yaml_to_json_converter:用于将YAML格式转换为JSON,支持文件输入;

模型看到“用户给了一个CSV文件”时,会匹配“csv_cleaner”摘要,然后主动调用技能读取指令。实测下来触发准确率比全量注入高不少。

4.3 方式三:路由模型/规则前置式

如果你有多个Agent或者技能库规模很大,建议在模型前面加一层路由。路由可以用一个小模型,也可以是一套规则引擎,预先判断当前任务属于哪个领域、需要哪几个技能,再决定把哪些技能挂进上下文。这样做的好处是主模型完全不需要“想”该用什么技能,任务更稳;缺点是架构复杂,你需要单独维护路由逻辑。

我现在的项目用的是“规则前置+按需加载”混合:简单任务直接由规则定位技能,复杂任务允许模型自主选择。混合方案实测下来,相比纯规则或纯模型,任务成功率分别提升了大概18%和12%。当然这个数字跟具体任务集有关,但趋势有普适性:纯规则太脆,纯模型太飘,中间地带最舒服。

4.4 技能路由的优先级与冲突仲裁

多个技能都“看起来适用”的时候,必须有仲裁机制。我的实现方式是在技能清单里给每个技能加优先级字段,规则级路由命中时按优先级排序,模型自主路由时要求它必须从高优先级开始尝试,失败才能降级。

优先级怎么定?一个经验:具体技能高于通用技能。比如“json_validator”优先级一定高于“data_processor”,因为前者能给出精确的校验结果,后者只会模糊地“处理数据”。这跟现实中去找专科医生而不是全科医生是一个道理。我在实践中发现,模型面对多个候选技能时,如果描述都模糊,它会选名字看起来最顺眼的那个,加入优先级字段之后乱选的情况少了很多。

5. 常见问题与排查技巧实录

5.1 问题一:技能被当成模型能力乱用

这是我踩过的第一个大坑。技能库里有个“text_formatter”技能,本意是处理文本对齐、Markdown表格规范化之类的任务,描述写成了“用于文本格式化”。结果模型在用户说“帮我改写这段文字”的时候也触发了它,输出的东西文风诡异,完全偏离用户预期。

排查思路:翻开日志,看模型决策时的输入和技能描述。一看就明白了,是“文本格式化”和“改写文本”在语义上太接近,模型无法区分“格式”和“内容”的差别。修复方式就是改描述,明确加上“只调整排版和结构,不改写文字内容,不改变措辞和语气”。改动很小,效果立竿见影。

经验总结下来:技能描述必须写清“做什么”,更重要的是写清“不做什么”。负向描述是路由准确率的最大功臣。

5.2 问题二:依赖冲突与版本隔离

技能库规模变大以后,两个技能可能依赖同一个库的不同版本。比如csv_cleaner用了A库的2.x,另一个rest_client用了A库的1.x。早期我把所有依赖装在同一个虚拟环境里,结果运行csv_cleaner时报错,排查了半天发现是rest_client启动时把A库降级了。

解决方案有两种:一是给每个技能建独立的虚拟环境,脚本里写好requirements.txt,并在SKILL.md里注明启动前需要先激活哪个环境;二是统一升级所有技能到同一套依赖版本。前者隔离度好,但占用磁盘空间;后者维护成本低,但要处理兼容性问题。

我最终选了折中:共享一个基础环境,但把有冲突的技能用子进程方式调用,子进程内部使用独立环境。你如果技能不多,建议直接用统一版本方案,省心。

5.3 问题三:多个技能共同调用时,谁先谁后

有些任务需要串多个技能。比如“清洗CSV再生成JSON”,理想路径是先走csv_cleaner再走json_converter,但如果模型先调用了converter,输入还是乱糟糟的CSV,输出自然是垃圾。

解决这个问题,我试过把“串联关系”写进父级技能的描述里。比如在csv_cleaner的执行步骤末尾加了一句:“如果后续需要将清洗结果转换为其他格式,请先通过json_converter等转换技能完成格式转换后再交付。”同时在json_converter的触发条件里写了“当输入并非标准JSON或包含未清洗字段时,先调用csv_cleaner等预处理技能”。

两端互相锚定之后,顺序乱掉的情况大幅减少。本质上,这就是给技能之间织了一张“调用网”,不能只靠模型自己悟。

5.4 问题四:技能库太大,加载性能受损

技能库到几十个后,即使按需加载也发现系统提示词太长,因为技能清单本身就要占不少token。优化办法是用“两级摘要”,第一级只列领域列表,模型判断领域后,第二级才返回该领域下的技能清单和摘要。这样模型每次需要对比的技能数量从几十个降到几个,路由准确率和响应速度都有提升。

另外一个优化点是技能文档本身。SKILL.md我控制在60行以内,超过60行说明职责太宽,需要拆。拆的时候先从“执行步骤”里找可独立的部分,而不是无脑拆分描述。这样拆出来的技能边界才清晰。

6. 一些经验,以及这个方向还能怎么延伸

做Agent技能库这件事,真正的产出物其实不是一个目录、几个文档和脚本,而是一整套“把经验结构化”的思考方式。以前我眼里只有“模型能力”和“Prompt技巧”,现在我会下意识地想:这个知识能不能沉淀成一个技能?它是稳定的还是临时的?它需要几个输入、什么输出、什么条件下失效?这套追问下来,很多模糊需求会自动变清晰。

最后分享一个小技巧:给技能库写测试用例。很多人觉得技能是给模型看的,没法测,其实可以测。我把每个技能配了一组输入输出对,每次改动技能后跑一遍,看模型在固定输入下的输出跟预期差多远。坚持一段时间后,技能库的稳定性有了质的提升。你可以在自己的项目里试试,先从三五个核心技能配起,后续再扩。

这个方向往后走,还可以做技能共享仓库、技能自动生成、技能组合编排这些事。不过那些都是后话了——先把基础打牢,让一个Agent先把一件小事干利索,比什么都重要。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询