
在 AI Agent 工程中,Skill(技能)指的是一个可被按需加载、可复用、带明确输入输出和操作步骤的能力单元。它通常由一份说明文档、若干脚本和可选资源组成,Agent 在需要时加载对应 Skill,而不是把所有知识一次性塞进系统提示词。
理解 Skill 最直接的方式是对比它与其他几个常被混淆的概念:
概念 | 本质 | 谁执行 | 典型问题 |
|---|---|---|---|
Prompt | 一段指令文本 | 模型 | 越写越长,互相干扰 |
Tool / Function | 一个可调用接口 | 程序或模型 | 只描述“能做什么”,不描述“怎么做对” |
Plugin | 打包的扩展 | 宿主平台 | 平台绑定强,粒度粗 |
Skill | 操作知识与脚本的封装 | 模型 + 脚本 | 需要良好的触发描述与边界 |
一句话概括:Tool 是能力,Skill 是手艺。 Tool 告诉 Agent“这里有把锤子”,Skill 告诉 Agent“钉这种钉子时,先定位、再预钻、最后敲入,注意别敲裂”。
一个工程化的 Skill 通常是一个目录,而不是一个文件:
skills/
invoice-reconcile/
SKILL.md # 元信息 + 操作说明
scripts/
reconcile.py # 确定性逻辑放脚本
references/
field-map.md # 按需读取的参考文档
assets/
template.xlsx # 模板类资源这个结构的关键在于分层:SKILL.md 是入口,始终轻量;脚本承担确定性计算;references 和 assets 只在需要时读取。这与“把全部内容写进一个巨型提示词”是两种完全不同的工程思路。
Skill 最重要的设计思想是渐进式披露(progressive disclosure):模型先只看到技能的名称和一句话描述,判断相关后才加载完整说明,执行到具体步骤时才读取参考文档或调用脚本。
这样做有三个直接收益:
从工程角度看,渐进式披露本质是把上下文当成稀缺资源来管理,这与微服务拆分、按需加载模块是同一种思路。
先看入口文件。SKILL.md 通常包含元信息与操作步骤:
---
name: invoice-reconcile
description: 对账发票与订单,输出差异清单。当用户需要对账、核对发票金额或排查差异时使用。
---
# 发票对账
## 步骤
1. 读取 `references/field-map.md`,确认字段映射。
2. 运行 `scripts/reconcile.py --invoice <发票文件> --order <订单文件>`。
3. 按脚本输出的差异类型解释结果,不要自行猜测金额。
## 约束
- 金额以脚本计算为准,模型不得手算。
- 差异超过 5% 时,提示人工复核。注意几个细节:description 写的是触发条件而不是功能罗列;步骤里明确“谁来做”;约束里明确“模型不许做什么”。这三条决定了 Skill 是否可靠。
配套脚本承担确定性逻辑:
# scripts/reconcile.py
import argparse, json
def reconcile(invoice, order):
diffs = []
for k, inv in invoice.items():
if k not in order:
diffs.append({"id": k, "type": "missing_in_order"})
elif inv != order[k]:
diffs.append({"id": k, "type": "amount_mismatch",
"invoice": inv, "order": order[k]})
return diffs
if __name__ == "__main__":
p = argparse.ArgumentParser()
p.add_argument("--invoice", required=True)
p.add_argument("--order", required=True)
args = p.parse_args()
print(json.dumps(reconcile({"A1": 100}, {"A1": 90}), ensure_ascii=False))脚本很短,但它承担了 Skill 里最容易被模型做错的部分:数值比较。凡是确定性、可验证、易出错的计算,都应该放进脚本而不是交给模型。
再看一个极简的加载器,体现“先看描述、后加载正文”的机制:
import re, pathlib
def index_skills(root="skills"):
skills = []
for md in pathlib.Path(root).glob("*/SKILL.md"):
text = md.read_text(encoding="utf-8")
meta = dict(re.findall(r"^(\w+):\s*(.+)$", text.split("---")[1], re.M))
skills.append({"path": md, "name": meta["name"], "desc": meta["description"]})
return skills
def load(skill):
return skill["path"].read_text(encoding="utf-8")index_skills 只返回元信息,供模型判断相关性;真正需要时才调用 load。这二十行代码就是渐进式披露的最小实现。
第一,描述写触发场景。 “用于对账”比“一个对账工具”更容易被正确激活。描述是路由,不是广告。
第二,步骤写清执行者。 哪一步由模型判断、哪一步由脚本执行,必须明确。模糊的步骤会导致模型自由发挥。
第三,约束要写“不许做什么”。 否定式约束往往比正向说明更有效,尤其是涉及金额、删除、外发等高风险动作时。
第四,确定性逻辑下沉脚本。 计算、解析、格式转换、批量操作,都应脚本化并加测试。模型负责编排与解释,脚本负责精确执行。
第五,单一职责。 一个 Skill 解决一类任务。出现“顺便也处理一下”的时候,就应该拆分。
第六,资源按需引用。 参考文档、模板、示例数据放在 references 与 assets 中,用路径引用,而不是内联进 SKILL.md。
反模式一:把 Skill 写成百科全书。 正文几千行,加载即爆上下文。正确做法是入口精简、细节外置。
反模式二:描述含糊。 “处理数据”这类描述会导致误触发或漏触发,最终用户觉得“这个 Agent 不稳定”。
反模式三:让模型做精确计算。 金额、税率、日期差、去重计数交给脚本,模型只解释结果。
反模式四:脚本无测试、无参数校验。 Skill 的脚本同样是生产代码,需要单元测试和失败路径处理。
反模式五:缺少退出条件。 没有“做不了时怎么办”的说明,模型会硬编结果。应在 Skill 中写明何时停止并请求人工介入。
反模式六:Skill 之间职责重叠。 两个 Skill 都能处理同一类请求时,路由会随机化,行为难以复现。
建议关注四个指标:
此外,建议为每个 Skill 维护一组回归用例:几条典型输入、期望输出和期望行为。Skill 迭代时跑一遍,能避免“改一个技能、坏三个场景”。
Skill 的本质,是把散落在提示词里的经验,沉淀为可复用、可测试、可演进的能力单元。它的工程要点可以浓缩为四句:入口轻、描述准、逻辑沉脚本、边界写清楚。
少量代码足以搭出一个可用的 Skill 体系,但真正决定质量的是纪律:渐进式披露控制上下文,脚本承担确定性,约束划清责任,回归用例保障演进。Skill 做得好,Agent 显得“懂行”;做得不好,只是一堆更长的提示词。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。