最近好几个朋友跑来问我同一个问题:为什么用同一个基础模型,别人家的Agent像个靠谱的执行助理,自家的Agent像个只会接话的聊天机器人?说实话,模型能力的差距真有那么大吗?不一定。大多数差距出在“能力的组织方式”上。一个Agent能不能真正落地干活,关键就看它有没有一套像样的技能体系——也就是agent-skills这个词背后真正指的东西:把可复用的能力沉淀成技能包,让Agent在需要时按需加载、照着执行、自主校验。
这篇文章我想系统聊聊Agent技能体系的构建思路,包括Skill的物理结构、运行时原理、完整实战案例,以及我在多次项目里踩过的坑。不管你是刚接触Agent开发,还是已经在做企业内部智能体,看完应该都能直接上手搭建自己的技能库。
1. 从“工具函数”到“技能包”:Agent能力复用的质变
很多人对Agent能力的理解还停留在“给模型挂一堆工具函数”,觉得只要把API封装成function call,Agent就会自动变强。早期我也是这么干的,但接的Agent越多越发现,工具函数这套东西在真正复杂的工作流面前,远远不够。
1.1 传统Tool调用的四个硬伤
先说说纯工具函数的模式长什么样。最常见的是OpenAI Function Calling那种用法:给模型一个JSON Schema,告诉它“有个函数叫search_products,参数是keyword和page”,模型自己决定要不要调、参数填什么。这种方式解决单点操作没问题,但一旦任务链条变长,问题就暴露了。
第一,工具的“使用说明书”和“业务规则”放不进结构化的Schema里。比如一个“数据脱敏”工具,Schema里只能写参数是file_path和level,但什么字段需要脱敏、脱敏到什么程度、哪些特殊情况不能动,这些规则塞不进去。结果就是模型真的把不该脱敏的手机号也给脱了。
第二,工具多了之后上下文被撑爆。接30个工具,光描述就几十KB,全塞进系统提示词里,模型对每个工具的注意力都被稀释了,经常出现“工具明明在那里却不调用”的怪事。我们在一次客服智能体项目里接过20多个业务工具,实测工具的触发准确率比接10个工具时掉了快两成。
第三,能力没法跨项目复用。字符级工具函数是跟具体API绑定的,换一个项目,参数结构变了、鉴权方式变了、甚至业务口径都不一样,代码基本要重写。沉淀不下来,等于每次从零开始。
第四,流程知识无处安放。一个复杂的业务流程往往有步骤顺序、有分支条件、有兜底策略,工具函数只能表达“能做什么”,表达不了“应该怎么做”。模型需要在一堆工具里自己组合出流程,出错概率极高。
1.2 Skill带来的三个本质变化
Skill(技能包)恰恰是针对上面这些痛点设计的。我理解的Skill,不是工具的换皮,而是把“某类任务的做法”整体打包成一个模块,里面既有让模型理解任务上下文的说明文档,也有实际可执行的脚本,还有配套的参考案例和校验规则。它与传统Tool相比核心差异有三点。
第一个本质变化是:从“暴露能力”变成“暴露职责边界”。传统工具描述的是“我能干什么”,Skill描述的是“我负责解决什么、不负责什么”。别小看这个变化,模型做路由决策时的逻辑完全不同——它看到的是一个“岗位说明书”,而不是一个“接口清单”。我们做客服机器人时,把“退货处理”做成一个Skill,里面明确写了“仅处理符合7天无理由条件的订单”,模型就极少再越权处理那些不能退的定制商品。
第二个本质变化是:流程被固化成规范文档,而不是靠模型现场临场发挥。Skill的指令部分是自然语言写的SOP,模型加载技能后相当于先读了一遍操作手册再开工。哪怕换个弱一点的模型,只要照着SOP走,输出质量也差不到哪去。这个特性让我第一次觉得“能力是可以被管理和传承的”。
第三个本质变化是:按需加载,不再一股脑塞进上下文。Agent系统里挂一个技能索引(通常只有几KB),模型根据用户请求决定要不要加载某个技能,加载后才把完整的SKILL.md和相关资源注入上下文。这样即使整个技能库有上百个技能,单次对话的上下文压力也不会增加,模型还能保持高专注度。
1.3 什么场景该上Skill体系
不是所有项目都要一上来就搞技能库。我的判断标准很简单:任务如果满足“有反复出现的套路”和“多步骤且规则复杂”这两个条件,就值得做成Skill。比如周报生成、简历初筛、数据质量分析、合同合规检查、客服话术引导,这些都是典型的Skill候选。
如果只是单一函数调用,比如查个天气、算个汇率,用传统Tool就够了,没必要套Skill的壳。Skill体系的维护成本是真实存在的,用对了是杠杆,用错了是负担。
| 对比维度 | 传统Tool函数 | Skill技能包 |
|---|---|---|
| 表达内容 | 结构化参数签名 | 自然语言SOP+代码+资源案例 |
| 上下文占用 | 常驻,工具多时膨胀 | 按需注入,轻量索引 |
| 流程知识 | 模型临场组合 | 文档固化,流程稳定 |
| 可复用性 | 与API强绑定 | 跨项目几乎零成本迁移 |
| 维护门槛 | 低 | 中高,需持续评估优化 |
2. 拆解一个Skill的物理结构:目录、元数据、指令与资源
想用好Skill,先要理解一个Skill包里到底放了什么。很多自己做技能的同学,把SKILL.md写得跟教学大纲似的,结果模型加载后根本抓不住重点。这一节我就把Skill的物理结构掰开揉碎讲清楚。
2.1 推荐的目录布局与命名规范
一个标准的Skill通常是一个独立目录,我推荐下面的布局,这也是目前业界比较通行的做法:
data-profiler-skill/ ├── SKILL.md # 技能包的核心入口:元数据+触发描述+执行指令 ├── scripts/ # 可执行脚本(Python、Shell、Node均可) │ ├── profile_csv.py │ └── validate_output.py ├── resources/ # 模型可能需要查阅的参考知识 │ ├── abnormal_patterns.md │ └── column_types.csv └── reference/ # 输出示例、评测基准 ├── output_examples.md └── test_cases.jsonl命名这块我的经验是:目录名用动词开头的snake_case,比如csv_data_profiler、weekly_report_generator、contract_compliance_checker。为什么不用名词?因为模型在做技能路由时,动词开头的名字本身就带有动作指向性,语义匹配的准确率会高一些。这算是个小细节,但实测对我们的技能命中率有两到三个点的提升。
还有一个小技巧:把SKILL.md固定放在目录根节点,各模块可以放在子目录。Agent加载技能时第一个读的必然是SKILL.md,其他资源则在指令里被引用到才加载。这样设计,既能保持技能包的完整性,又不会一次性把上下文撑爆。
2.2 SKILL.md的核心字段与编写要点
SKILL.md是技能包的心脏,一般分为两部分:YAML格式的元数据区,和Markdown格式的指令区。YAML头部我一般只保留四个最关键的字段:
--- name: csv_data_profiler description: | 当用户提供CSV文件并希望了解数据质量、缺失值、重复值、类型异常、异常值时使用。 典型请求:"帮我看下这个表""这份数据脏不脏""分析下上传的csv有没有问题"。 不适用于:Excel宏操作、数据库查询、非表格类数据的分析。 ---写description是门手艺活,最重要的是说清楚触发条件而不是堆功能描述。很多新手喜欢写“该技能可以对CSV进行全面的质量分析和统计报告生成,包括缺失率、唯一值、类型分布、异常检测等”,听起来很专业,但模型看到这段话根本不知道用户说什么时该触发它。我后来改成“当用户提供CSV文件并希望了解数据质量时使用”,效果立竿见影。描述里尽量给出具体的用户话术样例和负面样例(什么情况不要用),这样模型的路由判断会准得多。
指令区是告诉模型“拿到这个技能之后,具体按什么步骤干活”的。我一般分成执行步骤、参数说明、边界约束、校验要求四块。执行步骤用有序列表,每一步写清楚“做什么+产出什么”。边界约束必须写:什么情况该停止、什么情况该如实承认失败。校验要求写上“输出前要跑什么验证脚本”,这能把很多幻觉问题掐死在源头。
2.3 资源文件为什么可能是“杀手锏”
SKILL.md之外的resources目录,是很多人容易忽略的地方,但在我眼里它往往才是技能的“杀手锏”。模型本身有大量通识知识,缺的是“你这个业务场景里的具体规则和案例”。资源文件就是用来补这一块的。
举个例子,我们做过一个“合同条款合规检查”的Skill。SKILL.md里只写了大致的检查流程,真正让技能好用的是resources目录里那份abnormal_patterns.md——里面整理了公司过往三年法务实际标记过的问题条款,每条都附了正反面例子。模型加载这个技能时,先看SKILL.md,再看这份案例库,检查的准确率比只给规则描述高出很多。这其实就是把RAG的思想融入技能包里。
资源文件最大的坑是堆量不结构化。一开始同事往里塞了一堆几百页的PDF,模型加载完直接“知识过载”,输出质量反而下降。我后来的原则是:资源文件宁可少而精,每个资源在SKILL.md指令里必须被显式点名引用。没被引用的资源,模型根本不会主动去看,等于白放。
| 字段 | 核心作用 | 常见错误 |
|---|---|---|
| name | 全局唯一标识,路由用 | 用中文或带空格 |
| description | 触发路由判断 | 写成功能介绍而非触发条件 |
| instructions | 告诉模型怎么做 | 规则含糊、步骤无序 |
| resources | 补充业务流程知识 | 塞大文件不结构化 |
| validation | 输出质量兜底 | 缺失或流于形式 |
3. 运行时原理:Skill Manager如何发现、加载与执行技能
结构定义好了,接下来要解决的是Agent怎么知道该用哪个技能、怎么加载、怎么执行。这部分我管它叫“运行时机制”,也就是Skill Manager干的事。理解这层原理,你写的Skill才有机会被正确调用。
3.1 技能发现与匹配的三种策略及实测对比
技能发现,本质上是一个“从用户请求到技能条目”的匹配过程。目前业界有三条主流路线,我可以分享下实测感受。
第一种是LLM路由。把技能清单(只包含name和description,不含完整指令)写到系统提示词里,让模型根据用户请求直接选择技能。优点是灵活,能理解复杂语义;缺点是技能数量多的时候,模型会“选择困难”,还容易受上下文污染影响。我们在17个技能以内实测还不错,超过25个之后命中率就明显波动。
第二种是Embedding检索。把每个技能的description向量化建索引,用户请求来了做向量相似度匹配,取Top-K。优点是可扩展,几千个技能也不怕;缺点是对description写作质量要求极高,写不好召回就全是噪声,而且不带业务语义,有些请求意思相近但字面不同会被漏掉。
第三种是关键词/规则匹配。用正则或者标签体系做粗筛。优点是稳定可控、可解释;缺点显而易见,覆盖不全。像“帮我看看这表脏不脏”这种表述,关键词匹配几乎不可能命中“数据质量分析”这个技能。
我现在的做法是混合策略:先走一层轻量级标签/规则做粗筛,把明显不相关的技能过滤掉;再用Embedding做Top-10精排;最后把这10个候选的name和description交给LLM做final decision。多走这一层不会多花多少token,但技能挑选的体验稳定太多了。
3.2 上下文注入与技能执行循环
技能被选中之后,Manager要做的事是把Skill的各个部分按需注入到对话上下文中。这一步有个重要的顺序问题:最先注入的是SKILL.md的instructions,不是resources。先让模型知道执行步骤,再按需读取资源,顺序反了模型会被大量背景信息干扰,抓不住主干。
整个执行循环我一般这样设计:
- 用户请求到达,Manager进入路由阶段。
- 匹配选中的技能,加载SKILL.md元数据与指令区。
- 将指令区和当前对话的上下文拼装,交给模型生成第一步动作。
- 模型按指令调用scripts里的脚本,传入参数。
- 收到脚本输出后,模型根据输出结果继续推进流程,直到完成所有步骤。
- 完成自校验(校验脚本或自检规则),通过后输出最终结果,不通过则回到第4步重试最多两次。
这个循环里我踩过最大的一次坑是第4步和第5步之间缺少“状态记录”。第一次做技能时,脚本输出直接返回给模型就完事了,结果任务一复杂,模型记不住前面哪一步跑过、哪些列已经处理了,后面全部乱套。后来我在指令里强制要求:每跑一步,模型先把结果摘要写到一个progress_note里,并基于它决定下一步。等于给模型加了个“便签本”,效果立竿见影。
3.3 错误处理与降级策略:让Agent学会“认怂”
技能再好也架不住意外。文件损坏、权限不足、脚本崩溃、外部API超时……这些每个都是真实会遇到的。我的原则是:让Agent学会认怂,比学会硬撑更重要。
所以每个Skill的指令末尾我都会固定写一段“失败处理”规则,比如:脚本报错时先检查参数再重试一次;仍失败则明确告知用户“无法完成,原因是XXX”,同时给出可行的替代建议;严禁编造不存在的处理结果。这三句话救了我很多次。没有这段兜底指令,模型在脚本失败时会强行脑补一个看起来合理的输出,这在数据类任务里简直灾难。
降级策略也要在系统层面做。如果一个技能连着两次校验不过,Manager自动降级成“不带技能处理的普通对话模式”,并记录日志供后续排查。这能避免技能故障时整个Agent卡死,至少还能跟用户正常沟通。
| 失败类型 | 处理方式 | 补救动作 |
|---|---|---|
| 脚本运行报错 | 检查参数后重试一次 | 记录错误堆栈到日志 |
| 输出校验不通过 | 将问题反馈给模型修一次 | 第二次失败给兜底模板 |
| 资源文件缺失 | 跳过该资源继续 | 告知用户部分能力不可用 |
| 用户请求与技能不匹配 | 终止执行 | 回到普通对话流程 |
4. 从零手写“数据体检”Skill:完整实战
光讲概念不够,我直接用一个真实做过的“CSV数据质量体检”技能来演示完整构建过程。这个技能我们内部叫csv_data_profiler,专门处理“帮我看下这个表脏不脏”“分析下这份csv有没有问题”这类高频画质差需求,自己写一遍就能完全Get技能包的精髓。
4.1 需求定义与目录搭建
先想清楚问题边界:这个技能要取代人工重复的“看表”动作,输入一个CSV文件,输出一份数据质量报告,包含总体评分、缺失值分析、重复行检测、类型一致性检查和清洗建议。不需要它做复杂的可视化或机器学习建模。
决定要做之后,先建目录。我用的是上面推荐的标准布局,直接贴一下:
cd skills mkdir -p csv_data_profiler/scripts mkdir -p csv_data_profiler/resources mkdir -p csv_data_profiler/reference目录建好,先写脚本,再写SKILL.md,这样指令里引用的文件都是真实存在的,不会写架空。
4.2 SKILL.md完整示例:为什么每一步都这么写
SKILL.md是整个技能的核心,我逐步解释设计意图。
--- name: csv_data_profiler description: | 当用户提供CSV文件并希望了解数据质量、缺失值、重复值、类型异常、异常值时使用。 典型请求:"帮我看下这个表""这份数据脏不脏""分析下上传的csv有没有问题""这个文件能直接入库吗"。 不适用于:Excel宏操作、数据库查询、非表格类数据的分析、可视化图表制作。 --- ## 执行步骤 1. 使用 `python scripts/profile_csv.py <file_path>` 分析CSV文件,读取返回的 quality_report.json。 2. 依据报告中各项指标逐条分析: - 缺失率超过30%的列,必须给出具体建议(删除列、填充方案、保留但标注); - 类型不一致的列(如数字列混入字符串),说明可能的原因与处理方案; - 重复行占比超过0.1%时,建议去重方案。 3. 生成Markdown格式的数据质量报告,结构必须包含:总体评分、分项问题清单、清洗建议三大部分。 4. 每完成一步,将当前进展记录到progress_note,再决定下一步。 ## 边界约束 - 只分析CSV文件,其他格式(xlsx、json、parquet)不处理,明确告知用户当前能力范围。 - 遇到编码报错时,先尝试用 `utf-8-sig` 编码重跑一次。 - 脚本连续两次报错,停止执行并如实说明,严禁编造统计数字或处理结果。这份SKILL.md的设计有一个关键点:“执行步骤”和“边界约束”分开写,不给模型发挥空间,也给它留好退路。步骤1先调脚本而不是让模型自己“分析”,把最容易出错的部分交给确定性代码处理,模型只做解读和呈现,这是技能包效果稳定的核心原因。
4.3 配套脚本与验证逻辑:让“确定性”回归代码
配套的profile_csv.py是整个技能的“确定性引擎”。我写得比较轻量,但能覆盖主流场景:
import argparse import csv import json from collections import Counter from pathlib import Path def detect_type(values): non_null = [v for v in values if v != ""] if not non_null: return "empty" if all(is_int(v) for v in non_null): return "integer" if all(is_float(v) for v in non_null): return "float" classes = {detect_single(v) for v in non_null} return "mixed:" + "/".join(sorted(classes)) def detect_single(v): if v.strip().lstrip("-").isdigit(): return "integer" try: float(v) return "float" except ValueError: return "string" def profile_csv(file_path): import io # 先尝试utf-8,失败则utf-8-sig for enc in ["utf-8", "utf-8-sig"]: try: with open(file_path, encoding=enc) as f: reader = csv.DictReader(f) rows = list(reader) break except UnicodeDecodeError: continue else: return {"error": "encoding_error"} if not rows: return {"error": "empty_file"} summary = { "row_count": len(rows), "col_count": len(reader.fieldnames), "columns": {} } for col in reader.fieldnames: values = [r.get(col, "") for r in rows] missing = sum(1 for v in values if v.strip() == "") summary["columns"][col] = { "missing_count": missing, "missing_rate": round(missing / len(rows), 4), "type": detect_type(values), "unique_count": len(set(values)) } raw = [(tuple(r.values()), r) for r in rows] dup_count = len(rows) - len({tuple(r.values()) for r in rows}) summary["duplicate_rows"] = dup_count return summary if __name__ == "__main__": parser = argparse.ArgumentParser() parser.add_argument("file_path") args = parser.parse_args() result = profile_csv(args.file_path) print(json.dumps(result, ensure_ascii=False, indent=2))脚本还配了一个validate_output.py,作用是对模型生成的报告做最小化校验:报告里有“总体评分”关键词、有“清洗建议”段落、引用的数字与quality_report里的统计一致。校验不通过时返回错误码,Manager根据错误码决定要不要让模型修改重试。把校验逻辑写进代码而非依赖模型的自觉,这一步让整个技能的可靠性上了大台阶。
4.4 接入Manager后的真实调用效果
技能接进Manager后,一次完整调用流程是这样的:
用户发来一句“帮我看看这个csv有没有问题,能直接入库不”。Manager先做路由,把用户请求跟csv_data_profiler的description做匹配,判定触发该技能,随后把SKILL.md指令区注入上下文。模型执行步骤1,调用profile_csv.py读取文件生成quality_report.json,接着模型分析报告、生成质量体检报告。整个过程下来,同一个文件跑了十几次,输出结构基本稳定,不再出现之前纯prompt方案那种“第一次说缺失率30%,第二次说8%”的飘忽情况。
这个案例给我的最大启发是:技能的稳定性,主要靠脚本和校验机制兜底,而不是靠模型自觉。SKILL.md里写得再清楚,模型也可能在细节上跑偏,而脚本输出的确定性数字能帮它把叙述钉死在地面上。
5. 技能质量的评估视角与常见翻车现场
技能写好了不等于能上线。我见过太多团队把Skill堆了一文件夹,结果Agent能力没提升,反而多了各种奇怪行为。所以这节我想聊聊怎么科学评估一个技能好不好用、以及我在真实项目里踩过的几个典型雷。
5.1 一套实用评估指标
评估一个技能不能只看“单个请求跑通了没”。我建议每个技能建立几个基础指标:
| 指标 | 衡量什么 | 推荐测试方法 |
|---|---|---|
| 触发召回率 | 该用技能的时候是否用上了 | 准备50条典型用户请求,人工标注是否触发 |
| 误触发率 | 不该用的时候是否瞎用 | 准备50条无关请求,统计误触发比例 |
| 任务成功率 | 技能执行后输出质量 | 30条真实任务,人工看结果正确率 |
| 稳定性 | 同输入多次运行输出一致性 | 同一任务跑5次,对比结构差异 |
| 平均修复轮次 | 校验失败到成功需要的重试次数 | 统计日志里的retry数字 |
这些指标里,最容易被忽视的是“误触发率”。很多人只看召回率,结果技能被训练得像个“老好人”,什么请求都往上凑,反而干扰了正常对话。我们一度为了提升召回率把description写得太宽,结果用户问“有没有负面新闻”这种跟数据体检毫无关系的问题,Agent都会把csv_data_profiler拉进来,整个对话体验崩了。后来在description里加了硬性的“不适用场景”列表,误触发率才压下来。
5.2 我实际遇到的三类翻车案例
第一类翻车是“教条式执行”。有一次我们给技能指令写死了“必须给出5条清洗建议”,模型面对一个其实很干净的CSV,硬是编了5条建议,其中两条明显多余甚至有害。这就是典型的“规则过拟合”。现在的做法是:给建议数量用一个区间描述——“不少于2条,如无必要不超过5条”,把判断空间还给模型。
第二类翻车是“技能冲突”。当库里同时存在data_profiler和eda_analyzer时,模型经常拿不准同一份数据该用哪个。我后来在每个技能的description里都加入“如果另一个技能更适合请优先推荐对方”这种协作提示,并为边界场景专门做了一些标注为重复的测试用例做路由调优,情况缓解很多。
第三类翻车是“资源过载”。前面提过同事塞了几百页PDF进resources,模型处理每条请求都先吞吐一遍大文档,速度慢不说,报告里还开始出现跟本任务无关的知识点。拆成精简版+详细版两个资源文件后,模型只会在少数情况下加载详细版,速度和准确率都恢复正常。
5.3 上线前必须过一遍的检查清单
基于这些翻车经验,我总结了技能上线前的硬性检查项,每一条都是真金白银换来的:
- description写的是触发条件和负面场景,而不是功能介绍。
- 指令里的每一步都有明确产出物,且能被下游消费。
- 涉及代码执行的步骤,至少预留一次“参数修正重试”的容错。
- 输出必须有可执行的校验环节(脚本校验或结构化自检)。
- 资源文件只保留被显式引用的内容,且每个不超过模型可承受的体量。
- 做过至少一轮“同一技能在不同风格请求下”的稳定性测试。
- 确认技能之间没有明显职责重叠,或已写好协作边界。
这套检查清单我建议贴在团队wiki里,每次新增或修改技能都过一遍。它没法保证技能一定优秀,但能把绝大部分低级故障挡在门外。
6. 团队级Skill仓库的维护心得
当个人项目变成团队项目,技能就不只是一个技术产物了,它更像一个“知识资产库”,需要建立稳定可持续的管理规范。最后这节分享一些团队层面的实操心得。
6.1 命名、目录与协作规范
多人协作时的命名混乱问题,比想象中严重得多。有人用中文名,有人用大写驼峰,还有人把技能名起得充满创意(比如smart_helper_v2_final),结果路由阶段直接懵圈。我们团队后来定了硬性规范:技能名一律snake_case动词开头,置于skills/<业务域>/<技能名>/SKILL.md的层级下。业务域从主目录名体现,比如skills/customer_support/refund_handler、skills/data_analytics/csv_profiler。这样定位技能时路径本身就是信息。
协作上每个技能目录下要求有一个CHANGELOG.md,任何改动要追加记录:改了什么描述、为什么改、改了之后路由准确率变化多少。这看起来像是额外负担,但真到排查“为什么技能突然失准”的时候,这份日志就是救命的。我们有两次技能掉性能,全靠CHANGELOG定位到是同事调宽了description导致的误触发。
6.2 评审、灰度与版本回滚
技能是会“越改越坏”的。一个技能一开始可能很好用,但因为某次顺手改了description里的几个词,整个路由就崩了。因此我们给技能的改动引入了类似软件工程的发布流程:
- 新技能或大改动先提交PR,附上路由准确率旧版vs新版的对比数据。
- 合并前在预发环境跑一批准备好的回归测试用例(50条典型请求+30条负样本)。
- 灰度阶段用“版本开关”控制,线上只让10%流量走新技能,比对成功率之后再全量放行。
- 每个版本需要能一键回滚,我们在技能目录里放了VERSION文件,Manager启动时按版本号加载。
这套流程说起来不复杂,但真坚持下来了,技能质量的曲线就是持续向上的。很多团队的问题不是没人写技能,而是写完就没人敢动,怕改坏,最后技能库成了一潭死水。
6.3 权限边界与安全策略:技能能力强了更要有缰绳
技能包一旦能执行脚本,就不再是“调个API”那么简单了。它可能读文件、写文件、访问内部系统。因此权限设计必须从一开始就考虑。我们内部的做法是:所有技能脚本默认在受限沙箱里运行,只能访问被授权的目录和网络白名单域名;SKILL.md里必须写明“本技能可访问的资源范围”,Manager在实际调用前做一次权限断言,超出范围直接拒绝执行。可能有人觉得这是过度设计,但等到真出现“Agent把脱敏前的用户明细写到公共目录”这种事故时,这些约束就是低成本的保命符。
安全这块还要注意:不要在图里的技能描述或指令里放敏感的业务密钥或内部URL,技能包会upstream flows到模型上下文,等于把秘密直接暴露给模型了。凡是涉及敏感信息的调用都改成环境变量注入,技能包里只保留变量占位符。
技能库的管理本质上跟代码库的管理一个道理:命名规范、评审流程、灰度发布、权限控制,一个都不能少。把技能当作一等公民来对待,你的Agent才能持续变强,而不是三天两头出幺蛾子。
上次做内部智能体项目,我把项目组的一半精力从调prompt挪到了整理技能库上。一开始同事觉得有点过度,等到上线后效果稳得超出预期,大家才明白:Agent能力的上限,很大程度取决于你能把多少隐性知识固化成可加载、可评估、可迭代的技能包。这跟写代码要先想清楚接口是一个道理。先别急着追新模型,静下心梳理一下你手里这些反复做的事,它们每一条都可能是你下一个Skill的起点。