Agent 应用做深之后,很快会遇到一个问题:模型本身会推理,但业务能力很难维护。
以数据分析为例,一个 Agent 可能需要理解财务口径、识别 A/B 实验指标、生成 SQL(Structured Query Language,结构化查询语言)、选择 Hive 或 Doris 查询引擎、执行脚本、解释结果,还要在指标异常时继续做归因分析。把这些内容全部塞进系统提示词,短期能跑,长期会变得很难维护:上下文越来越长,Token 消耗越来越大,不同业务知识互相干扰,某个流程改动也容易影响整个 Agent。
Agent Skills 的思路是把这些能力拆成独立的“技能包”。每个技能包都是一个目录,里面放技能说明、业务知识、操作步骤、脚本和资源文件。Agent 平时只知道有哪些技能以及它们适合处理什么任务,真正需要执行时,才加载对应技能的详细内容。
这让 Agent 能力从“一个巨大的提示词”变成“可组合的能力目录”。
Agent Skills 解决什么问题
Agent Skills 可以理解为一种面向 AI Agent 的能力封装规范。一个 Skill 不是单条 Prompt,也不是一个简单函数,而是一组完成特定任务所需的材料:
skill = 使用说明 + 领域知识 + 执行流程 + 脚本工具 + 资源文件
它适合封装这类任务:
| 任务类型 | 典型例子 | 为什么适合做成 Skill |
|---|---|---|
| 有固定流程 | 自然语言查数、报表生成、代码审查 | 步骤稳定,可以沉淀为说明文档 |
| 依赖业务知识 | 财务口径、实验指标、运营规则 | 业务信息可放在资源文件中单独维护 |
| 需要调用脚本 | SQL 执行、文件解析、数据加工 | 确定性逻辑交给代码处理更可靠 |
| 可被多个 Agent 复用 | 不同业务线都要查数、归因、下钻 | 能力只维护一份,各 Agent 动态加载 |
传统做法通常有两种:一种是把所有知识写进系统提示词,另一种是为每个场景单独做一个 Agent。前者容易造成上下文膨胀,后者会产生大量重复能力。Agent Skills 则把“领域能力”单独抽出来,让不同 Agent 按需引用。
flowchart LR
U[用户问题] --> A[通用 Agent]
A --> D{判断任务类型}
D -->|查数| S1[自然语言查数 Skill]
D -->|归因| S2[指标归因 Skill]
D -->|下钻| S3[OLAP 下钻 Skill]
S1 --> R[返回分析结果]
S2 --> R
S3 --> R
Agent Skills、MCP、A2A 的边界
Agent Skills 经常会和 MCP、A2A 一起讨论,但三者解决的问题不同。
- Agent Skills 定义“能力”
- MCP 提供“工具”
- A2A 负责“协作”
MCP(Model Context Protocol,模型上下文协议)更像统一工具接入层。数据库、搜索、文件系统、业务 API(应用程序编程接口)等外部能力,可以通过 MCP 暴露给模型调用。
A2A(Agent-to-Agent,智能体间协作协议)关注多个 Agent 如何沟通、分工和交付结果。复杂任务可能需要数据分析 Agent、代码 Agent、审核 Agent 共同完成,A2A 处理的是它们之间的协作关系。
Agent Skills 不直接解决工具接入,也不主要解决多 Agent 通信,它解决的是“某类任务怎么做”的问题。
| 能力 | Agent Skills | MCP | A2A |
|---|---|---|---|
| 核心定位 | 封装任务能力 | 标准化工具调用 | 多 Agent 协作 |
| 关注点 | 流程、知识、脚本、资源 | 外部系统、工具接口 | 通信、分工、状态同步 |
| 典型内容 | SKILL.md、docs、scripts | 数据库查询、文件读写、搜索接口 | 任务分派、结果汇总 |
| 解决的问题 | 让 Agent 学会某类任务 | 让 Agent 能使用外部工具 | 让多个 Agent 一起工作 |
| 数据分析例子 | “如何做自然语言查数” | “如何连接 Hive/Doris” | “查数 Agent 与报告 Agent 协作” |
用一个数据分析任务串起来看会更清楚:
sequenceDiagram
participant User as 用户
participant Agent as 数据分析 Agent
participant Skill as 自然语言查数 Skill
participant MCP as MCP 工具层
participant DB as Hive/Doris
User->>Agent: 查询某个业务指标
Agent->>Skill: 加载查数流程和领域知识
Skill-->>Agent: 返回元数据、SQL 规范、执行步骤
Agent->>MCP: 调用数据库查询工具
MCP->>DB: 执行 SQL
DB-->>MCP: 返回结果
MCP-->>Agent: 返回结构化数据
Agent-->>User: 输出查询结果和解释
核心机制:渐进式披露
Agent Skills 最关键的设计是渐进式披露。Agent 不需要一开始就把某个技能目录里的所有文件读进上下文,只需要先看到技能的名称和描述。当用户任务命中某个技能时,Agent 再读取该技能的详细说明、资源文件和脚本。
这类似一本说明书的组织方式:
技能列表:告诉 Agent 有哪些能力
└── SKILL.md 摘要:告诉 Agent 什么时候使用这个技能
└── 详细步骤:真正执行时再读取
├── docs:领域知识、规范、案例
├── resources:配置、模板、元数据
└── scripts:可执行脚本
这种机制带来两个直接收益。
一个收益是节省上下文。假设系统中有 100 个技能,每个技能都有详细文档、示例和脚本,如果全部塞进 Prompt,模型上下文很快就会被占满。渐进式披露只把技能摘要放进上下文,详细内容按需读取,Token 成本会低很多。
另一个收益是减少干扰。财务查数、实验分析、指标归因、报表生成可能都有自己的规则。如果所有规则同时出现在上下文里,模型可能混用口径。按需加载可以让当前任务只接触相关知识。
flowchart TD
A[Agent 启动] --> B[读取技能 name 和 description]
B --> C[用户提出任务]
C --> D{是否匹配某个 Skill}
D -->|否| E[按通用能力处理]
D -->|是| F[读取对应 SKILL.md]
F --> G[按需读取 docs/resources]
G --> H[必要时执行 scripts]
H --> I[返回结果]
为什么 Skill 里需要 scripts
LLM(Large Language Model,大语言模型)擅长理解语义、规划步骤和生成解释,但并不适合承担所有计算任务。很多确定性工作交给代码更合适。
例如,对一个列表排序,让模型逐个比较并生成结果,不如直接调用排序算法。执行 SQL、解析文件、计算环比、生成图表、读取节假日配置,也都更适合用脚本完成。
Agent Skills 允许把这些确定性逻辑放进 scripts 目录。Agent 需要时调用脚本,而不是把脚本内容和所有输入数据都塞进上下文。
| 工作 | 适合交给 LLM | 适合交给代码 |
|---|---|---|
| 理解用户意图 | 是 | 否 |
| 选择分析路径 | 是 | 部分适合 |
| 生成 SQL 草稿 | 是 | 部分适合 |
| 执行 SQL | 否 | 是 |
| 计算同比、环比、贡献度 | 否 | 是 |
| 判断异常原因 | 是 | 需要结合代码结果 |
| 生成自然语言解释 | 是 | 否 |
这种分工能让 Agent 更稳定:模型负责“判断做什么”,脚本负责“把明确的事做准”。
Skill 的目录结构
一个 Skill 本质上是一个文件夹。最重要的文件是 SKILL.md,它告诉 Agent 这个技能是什么、什么时候用、怎么执行。
一个用于自然语言查数的技能目录可以这样组织:
skills/
└── natural_language_query/
├── SKILL.md
├── docs/
│ ├── sql-style.md
│ ├── finance-metrics.md
│ └── ab-experiment-metrics.md
├── resources/
│ ├── datasets.yaml
│ └── metric-map.yaml
└── scripts/
├── hive.py
├── doris.py
└── validate_sql.py
SKILL.md 需要在开头写 YAML 格式的元信息。两个字段最重要:
| 字段 | 作用 | 写法建议 |
|---|---|---|
name | 技能名称 | 使用小写字母、数字、下划线,便于系统识别 |
description | 技能描述 | 写清适用场景,让 Agent 能判断什么时候加载 |
一个简单示例:
---
name: natural_language_query
description: 将用户的自然语言问题转换为 SQL,并基于业务元数据选择 Hive 或 Doris 查询。适用于财务查数、A/B 实验指标查询、订单和用户相关数据查询。
---
# 自然语言查数
## 使用目标
把用户问题转成可执行 SQL,查询结果后给出简洁解释。
## 执行流程
1. 识别用户要查询的业务主题,例如财务、A/B 实验、订单、用户。
2. 读取 `resources/datasets.yaml`,确认可用数据集。
3. 读取对应领域文档,获取指标口径、字段含义和过滤条件。
4. 根据 `docs/sql-style.md` 生成符合规范的 SQL。
5. 调用 `scripts/validate_sql.py` 校验 SQL。
6. 根据数据源选择执行脚本:
- Hive 查询调用 `scripts/hive.py`
- Doris 查询调用 `scripts/doris.py`
7. 基于查询结果回答用户,并说明关键口径。
description 不能写得太泛。如果只写“用于数据分析”,Agent 很难判断是否该加载这个技能。更好的写法是把场景边界说清楚,例如“适用于财务查数、A/B 实验指标查询、订单和用户相关数据查询”。
实战场景一:自然语言查数
大数据团队里常见一类需求:业务同学用自然语言问问题,系统自动理解指标口径,生成 SQL,查询 Hive 或 Doris,再返回结果。
如果为财务查数、A/B 实验查数、订单查数分别做独立 Agent,会产生大量重复逻辑。它们的共同流程其实很接近:
flowchart TD
A[用户自然语言问题] --> B[识别业务主题和指标]
B --> C[加载领域知识和元数据]
C --> D[确认数据集、字段、口径]
D --> E[生成 SQL]
E --> F[校验 SQL]
F --> G{选择查询引擎}
G -->|Hive| H[调用 hive.py]
G -->|Doris| I[调用 doris.py]
H --> J[获得查询结果]
I --> J
J --> K[解释结果和口径]
因此,可以把“自然语言查数”抽成一个通用 Skill。不同业务场景只维护自己的领域知识,不再重复开发查数流程。
目录可以进一步拆成这样:
natural_language_query/
├── SKILL.md
├── docs/
│ ├── common-sql-rules.md
│ ├── finance-domain.md
│ └── experiment-domain.md
├── resources/
│ ├── finance-datasets.yaml
│ ├── experiment-datasets.yaml
│ └── metric-dictionary.yaml
└── scripts/
├── hive.py
├── doris.py
└── sql_lint.py
财务 Agent 需要查数时加载同一个 Skill,但读取财务相关元数据;实验分析 Agent 也加载同一个 Skill,但读取实验指标和实验分组规则。能力复用的关键点不是“做更多 Agent”,而是把重复流程沉淀为一个标准技能。
| 角色 | 需要维护的内容 | 不需要重复维护的内容 |
|---|---|---|
| 财务分析场景 | 财务指标口径、财务数据集、过滤规则 | 自然语言转 SQL 流程、SQL 校验、查询脚本 |
| A/B 实验场景 | 实验指标、实验分组、显著性相关口径 | 查数流程、执行入口、结果解释模板 |
| 订单分析场景 | 订单字段、订单状态、城市维度 | 引擎选择、SQL 规范、脚本调用方式 |
这种拆法能降低治理成本。业务口径变化时,更新对应领域文档或元数据即可;查询脚本升级时,所有使用该 Skill 的 Agent 都能复用新的执行能力。
实战场景二:指标归因分析
自然语言查数解决的是“查一个数”。指标归因分析要更进一步:当核心指标下降时,系统需要判断哪些关联指标变化最大,是否存在节假日因素,是否需要做 OLAP(Online Analytical Processing,联机分析处理)下钻。
归因分析适合拆成多个 Skill 串联:
flowchart LR
A[用户要求分析指标变化] --> B[核心指标分析 Skill]
B --> C{指标是否异常}
C -->|否| D[输出指标状态]
C -->|是| E[关联指标分析]
E --> F[节假日影响判断]
F --> G{是否需要下钻}
G -->|否| H[输出可能原因]
G -->|是| I[OLAP 下钻 Skill]
I --> H
核心指标分析 Skill 可以封装这样的流程:
---
name: core_metric_diagnosis
description: 分析核心业务指标及其关联指标的周环比变化,识别主要影响因子和可能异常原因。适用于指标下降分析、业务波动归因、核心指标根因排查。
---
# 核心业务指标归因分析
## 分析目标
分析核心指标的周环比变化,并在指标下降时继续检查关联指标、节假日因素和细分维度贡献。
## 分析流程
### 1. 获取核心指标周环比数据
调用脚本:
```bash
python scripts/query_metric.py core_metric --json
返回数据应包含:
- 今日日期
- 上周同期日期
- 今日指标值
- 上周同期指标值
- 周环比变化率
2. 判断是否需要深入分析
如果核心指标下降,继续查询关联指标:
python scripts/query_metric.py metric_2 --json
python scripts/query_metric.py metric_3 --json
python scripts/query_metric.py metric_4 --json
python scripts/query_metric.py metric_5 --json
需要比较各指标变化率,识别变化最明显的指标,并结合指标关系判断可能影响路径。
3. 检查节假日因素
如需判断日期影响,调用:
python scripts/holiday.py
根据返回的工作日、周末、节假日信息,判断波动是否可能由日期结构变化引起。
4. 必要时进入 OLAP 下钻
如果某个关联指标变化明显,调用 olap_drilldown 技能,从城市、渠道、车型、用户类型等维度分析贡献度。
输出结构
结果需要包含:
- 核心指标状态:当前值、上周同期值、周环比变化。
- 关联指标变化:各指标变化率和影响排序。
- 可能原因:基于数据变化、指标关系和日期因素给出解释。
- 下钻结论:如触发 OLAP 下钻,需要给出关键维度贡献。
归因分析的重点不只是“把脚本跑完”,而是把业务经验结构化。比如哪些指标互相影响,什么变化幅度算异常,哪些日期需要特殊处理,哪些维度值得优先下钻,这些都应该写进 Skill 的文档或资源文件。
一个可维护的指标归因 Skill 可以包含:
```text
core_metric_diagnosis/
├── SKILL.md
├── docs/
│ ├── metric-relationship.md
│ ├── diagnosis-rules.md
│ └── output-template.md
├── resources/
│ ├── metric-tree.yaml
│ └── threshold.yaml
└── scripts/
├── query_metric.py
├── holiday.py
└── contribution.py
其中 metric-tree.yaml 描述指标之间的关系,threshold.yaml 描述异常阈值,contribution.py 用于计算不同维度的贡献度。模型根据 Skill 的说明决定分析路径,脚本负责拿数据和算结果。
Skill 设计的关键点
描述要能触发正确技能
description 是 Agent 判断是否加载 Skill 的重要依据。描述过短会导致召回不足,描述过宽会导致误触发。
不推荐:
description: 用于数据分析。
更合理:
description: 分析核心业务指标及其关联指标的周环比变化,识别主要影响因子和异常原因。适用于指标下降分析、业务波动归因、核心指标根因排查。
好的描述通常包含三类信息:
| 信息 | 例子 |
|---|---|
| 能做什么 | 分析核心指标周环比变化 |
| 适合什么场景 | 指标下降、业务波动、根因排查 |
| 不适合什么场景 | 不直接处理实时告警推送、不生成 BI 看板 |
业务知识决定能力上限
Agent Skills 降低的是“把业务经验注入模型”的工程复杂度,但不会自动产生高质量业务知识。指标口径不清、字段解释过时、分析规则混乱,Agent 的输出也会不稳定。
数据分析类 Skill 至少要维护三类知识:
| 知识类型 | 内容 |
|---|---|
| 元数据 | 表名、字段、分区、数据源、刷新频率 |
| 指标口径 | 指标定义、过滤条件、统计周期、单位 |
| 分析规则 | 异常阈值、指标关系、下钻维度、节假日处理方式 |
这些内容最好不要全部写在 SKILL.md 里。SKILL.md 负责描述流程,详细知识放到 docs 和 resources,这样更容易维护和版本化。
脚本要受控执行
scripts 能扩展 Agent 的能力边界,也会带来安全风险。一个来自外部的 Skill 如果包含脚本,理论上可能读取文件、访问网络、执行危险命令或泄露数据。
落地时需要给脚本执行加上约束:
| 风险 | 控制方式 |
|---|---|
| 任意命令执行 | 使用沙箱或容器隔离 |
| 越权访问数据 | 按 Skill 配置最小权限 |
| 访问外部网络 | 默认禁止,必要时配置白名单 |
| 读取敏感文件 | 限制可访问目录 |
| SQL 注入或误删数据 | 只读账号、SQL 校验、禁止 DDL/DML |
| 结果不可追踪 | 记录脚本版本、输入参数和执行日志 |
对于数据分析 Agent,查询脚本建议默认只读,且所有 SQL 经过校验。能用参数化调用就不要拼接任意字符串,能限制数据源范围就不要给全库权限。
Agent Skills 适合和不适合的场景
Agent Skills 不是所有 Agent 问题的答案。它最适合流程清晰、知识可沉淀、工具可封装的任务。
| 场景 | 是否适合 | 原因 |
|---|---|---|
| 自然语言查数 | 适合 | 流程稳定,依赖元数据和 SQL 规范 |
| 指标归因分析 | 适合 | 可拆成指标查询、关联分析、节假日判断、下钻 |
| 报告生成 | 适合 | 模板、口径、图表生成逻辑可复用 |
| 代码规范检查 | 适合 | 规则文档和检查脚本可封装 |
| 开放式创意写作 | 不太适合 | 流程不稳定,难以沉淀为确定技能 |
| 强实时控制 | 不太适合 | 更依赖低延迟系统和确定性服务 |
| 高风险自动操作 | 谨慎使用 | 需要权限控制、审核和回滚机制 |
判断一个任务是否适合做成 Skill,可以看三个问题:
- 是否有稳定流程?
- 是否有可维护的领域知识?
- 是否存在适合脚本处理的确定性步骤?
三个答案都偏向“是”,就值得抽象成 Skill。
从单体 Agent 到能力生态
Agent 应用早期常见做法是不断增强一个“全能 Agent”:加系统提示词、加工具、加规则、加案例。规模变大后,这种单体形态会越来越难维护。任何一次提示词修改都可能影响多个业务流程,能力复用也不清晰。
Agent Skills 更像给 Agent 增加一个能力包管理机制。不同技能以目录形式独立存在,Agent 根据任务动态加载。业务知识、脚本工具和执行流程可以分别维护,多个 Agent 也可以复用同一套能力。
flowchart TD
A[Agent Runtime] --> B[Skill Registry]
B --> C[自然语言查数 Skill]
B --> D[指标归因 Skill]
B --> E[OLAP 下钻 Skill]
B --> F[报告生成 Skill]
C --> C1[领域文档]
C --> C2[元数据资源]
C --> C3[查询脚本]
D --> D1[指标关系]
D --> D2[诊断规则]
D --> D3[归因脚本]
真正有价值的不是创建很多技能目录,而是建立一套可治理的能力体系:命名规范、描述规范、权限模型、版本管理、评估集、执行日志都要配套。否则 Skill 数量一多,又会变成新的混乱来源。
Agent Skills 的核心价值在于把 AI Agent 的能力从“写在 Prompt 里的隐性经验”变成“可发现、可组合、可复用、可治理的工程资产”。在数据分析场景里,它尤其适合承载自然语言查数、指标归因、OLAP 下钻、报告生成这类流程性强、业务知识密集、又需要脚本配合的任务。