芥末
发布于 2026-01-22 / 0 阅读
0
0

Agent Skills 在数据分析 Agent 中的工程化实践

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 SkillsMCPA2A
核心定位封装任务能力标准化工具调用多 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 技能,从城市、渠道、车型、用户类型等维度分析贡献度。

输出结构

结果需要包含:

  1. 核心指标状态:当前值、上周同期值、周环比变化。
  2. 关联指标变化:各指标变化率和影响排序。
  3. 可能原因:基于数据变化、指标关系和日期因素给出解释。
  4. 下钻结论:如触发 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 负责描述流程,详细知识放到 docsresources,这样更容易维护和版本化。

脚本要受控执行

scripts 能扩展 Agent 的能力边界,也会带来安全风险。一个来自外部的 Skill 如果包含脚本,理论上可能读取文件、访问网络、执行危险命令或泄露数据。

落地时需要给脚本执行加上约束:

风险控制方式
任意命令执行使用沙箱或容器隔离
越权访问数据按 Skill 配置最小权限
访问外部网络默认禁止,必要时配置白名单
读取敏感文件限制可访问目录
SQL 注入或误删数据只读账号、SQL 校验、禁止 DDL/DML
结果不可追踪记录脚本版本、输入参数和执行日志

对于数据分析 Agent,查询脚本建议默认只读,且所有 SQL 经过校验。能用参数化调用就不要拼接任意字符串,能限制数据源范围就不要给全库权限。

Agent Skills 适合和不适合的场景

Agent Skills 不是所有 Agent 问题的答案。它最适合流程清晰、知识可沉淀、工具可封装的任务。

场景是否适合原因
自然语言查数适合流程稳定,依赖元数据和 SQL 规范
指标归因分析适合可拆成指标查询、关联分析、节假日判断、下钻
报告生成适合模板、口径、图表生成逻辑可复用
代码规范检查适合规则文档和检查脚本可封装
开放式创意写作不太适合流程不稳定,难以沉淀为确定技能
强实时控制不太适合更依赖低延迟系统和确定性服务
高风险自动操作谨慎使用需要权限控制、审核和回滚机制

判断一个任务是否适合做成 Skill,可以看三个问题:

  1. 是否有稳定流程?
  2. 是否有可维护的领域知识?
  3. 是否存在适合脚本处理的确定性步骤?

三个答案都偏向“是”,就值得抽象成 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 下钻、报告生成这类流程性强、业务知识密集、又需要脚本配合的任务。


评论