导读
本章深入介绍Skill技能系统,这是AgentScope框架中用于标准化能力定义、组合和管理的核心组件。
在企业级AI应用中,我们经常面临以下挑战:
- 如何复用已有的AI能力,避免重复开发?
- 如何标准化不同团队开发的Agent能力?
- 如何实现技能的版本管理和依赖管理?
- 如何构建可组合、可扩展的AI能力体系?
本章将通过深入的技术讲解,帮助你掌握:
- 技能的DSL(Domain-Specific Language)设计
- 技能加载器的实现机制
- 技能依赖图的解析和执行
- 技能版本冲突的解决策略
- 分布式技能仓库的设计
1. Skill系统架构设计(What - 是什么)
什么是Skill?
Skill(技能)是AgentScope中对Agent能力的标准化封装单元,类似于软件工程中的"组件"或"模块"。
Skill的定位:
软件工程类比:
├─ 函数/方法 → 基本能力单元
├─ 类/模块 → 能力的封装
├─ 库/框架 → 能力的集合
└─ Skill → Agent能力的标准化封装
Skill的核心价值:
┌─────────────────────────────────┐
│ 标准化 (Standardization) │
│ → 统一的定义格式和接口 │
└─────────────────────────────────┘
↓
┌─────────────────────────────────┐
│ 可复用 (Reusability) │
│ → 一次定义,多处使用 │
└─────────────────────────────────┘
↓
┌─────────────────────────────────┐
│ 可组合 (Composability) │
│ → 技能可以相互依赖和调用 │
└─────────────────────────────────┘
↓
┌─────────────────────────────────┐
│ 可管理 (Manageability) │
│ → 版本控制、依赖管理、发布 │
└─────────────────────────────────┘
↓
┌─────────────────────────────────┐
│ 可共享 (Shareability) │
│ → 通过技能市场共享和交易 │
└─────────────────────────────────┘
Skill系统的整体架构
┌────────────────────────────────────────────────────────────┐
│ Skill系统架构 │
└────────────────────────────────────────────────────────────┘
┌──────────────┐
│ 技能定义层 │
│ (Definition) │ ← Markdown DSL / Java Code
└──────┬───────┘
↓
┌──────────────┐
│ 技能加载层 │
│ (Loader) │ ← Parser + Validator + Resolver
└──────┬───────┘
↓
┌──────────────┐
│ 技能存储层 │
│ (Storage) │ ← Local File / Remote Repository / Database
└──────┬───────┘
↓
┌──────────────┐
│ 技能执行层 │
│ (Executor) │ ← Agent Integration + Dependency Resolution
└──────┬───────┘
↓
┌──────────────┐
│ 技能管理层 │
│ (Management) │ ← Version Control + Marketplace + Analytics
└──────────────┘
Skill的完整组成
一个完整的Skill包含以下要素:
/**
* Skill的数据模型
*/
@Data
@Builder
public class AgentSkill {
// ========== 基础元信息 ==========
private String id; // 唯一标识
private String name; // 技能名称
private String displayName; // 显示名称
private String description; // 简短描述
private String detailedDescription; // 详细描述
private String version; // 版本号(语义化版本)
private String author; // 作者
private String organization; // 组织
private LocalDateTime createdAt; // 创建时间
private LocalDateTime updatedAt; // 更新时间
private List<String> tags; // 标签
private List<String> keywords; // 关键词
private String category; // 分类
// ========== 技能定义 ==========
private String objective; // 技能目标
private String usageMethod; // 使用方法
private Map<String, Object> inputSpec; // 输入规范
private Map<String, Object> outputSpec; // 输出规范
private List<SkillExample> examples; // 使用示例
private List<String> bestPractices; // 最佳实践
private List<String> limitations; // 使用限制
// ========== 依赖管理 ==========
private List<SkillDependency> dependencies; // 依赖的其他技能
private List<SkillDependency> conflicts; // 冲突的技能
private Map<String, String> requires; // 环境要求
// ========== 执行配置 ==========
private SkillExecutionConfig executionConfig; // 执行配置
private Map<String, Object> parameters; // 可配置参数
private SkillPerformanceMetrics metrics; // 性能指标
// ========== 质量保证 ==========
private List<SkillTestCase> testCases; // 测试用例
private SkillQualityScore qualityScore; // 质量评分
private List<SkillReview> reviews; // 用户评价
// ========== 许可和计费 ==========
private String license; // 许可证
private SkillPricing pricing; // 定价信息
private boolean isPublic; // 是否公开
// ========== 扩展字段 ==========
private Map<String, Object> metadata; // 自定义元数据
}
Skill定义语言(Skill DSL)
AgentScope使用Markdown + YAML Front Matter作为技能定义语言,这是一种既人类可读又机器可解析的格式。
完整的Skill定义示例
---
# ========== 基础信息 ==========
id: skill-analytics-001
name: advanced_data_analytics
displayName: 高级数据分析
version: 2.1.0
author: DataScience Team
organization: AgentScope Inc.
createdAt: 2024-01-15T10:00:00Z
updatedAt: 2024-12-20T15:30:00Z
# ========== 分类和标签 ==========
category: analytics
tags:
- data-analysis
- statistics
- visualization
- business-intelligence
keywords:
- 数据分析
- 统计分析
- 趋势预测
- 异常检测
- 相关性分析
# ========== 技能描述 ==========
description: >
高级数据分析技能,支持统计分析、趋势预测、异常检测、
相关性分析等多种分析方法。适用于销售数据、用户行为、
业务指标等各类数据的深度分析。
detailedDescription: |
本技能提供企业级的数据分析能力,包括:
**核心功能**:
- 描述性统计分析(均值、中位数、方差、分位数等)
- 时间序列分析(趋势、季节性、周期性检测)
- 异常值检测(基于统计方法和机器学习)
- 相关性分析(Pearson、Spearman相关系数)
- 聚类分析(K-means、DBSCAN等)
- 回归分析(线性回归、逻辑回归)
**技术特点**:
- 支持大规模数据处理(百万级记录)
- 自动数据预处理和清洗
- 智能化的分析方法选择
- 可视化结果输出
- 业务洞察自动生成
# ========== 依赖管理 ==========
dependencies:
- skill: statistical_summary
version: ">=2.0.0"
required: true
reason: 提供基础统计计算能力
- skill: data_visualization
version: "^1.5.0"
required: true
reason: 生成图表和可视化
- skill: data_preprocessing
version: "~1.3.0"
required: false
reason: 高级数据清洗(可选)
conflicts:
- skill: legacy_analytics
reason: 功能重叠,可能导致执行冲突
requires:
runtime: java
minVersion: "17"
memory: "512MB"
libraries:
- name: apache-commons-math
version: "3.6.1"
- name: jfreechart
version: "1.5.3"
# ========== 执行配置 ==========
executionConfig:
timeout: 300000 # 5分钟
retries: 3
parallelizable: true
cacheable: true
cacheExpiration: 3600 # 1小时
parameters:
confidenceLevel:
type: float
default: 0.95
min: 0.8
max: 0.99
description: 置信水平
outlierThreshold:
type: float
default: 3.0
min: 1.0
max: 5.0
description: 异常值检测的标准差倍数
visualizationEnabled:
type: boolean
default: true
description: 是否生成可视化图表
# ========== 性能指标 ==========
metrics:
avgExecutionTime: 2500 # ms
successRate: 0.987
usageCount: 15234
satisfactionScore: 4.7 # /5.0
# ========== 质量保证 ==========
qualityScore:
overall: 4.8
accuracy: 4.9
performance: 4.6
documentation: 4.9
usability: 4.7
# ========== 许可和定价 ==========
license: Apache-2.0
pricing:
model: freemium
free:
maxCalls: 1000
maxDataSize: "10MB"
premium:
pricePerCall: 0.01 # USD
pricePerMonth: 49.99 # USD
features:
- unlimited_calls
- advanced_algorithms
- priority_support
isPublic: true
---
# 高级数据分析技能
## 📋 技能目标
本技能旨在为Agent提供**企业级的数据分析能力**,能够从原始数据中提取有价值的洞察,支持业务决策。
**适用场景**:
- 销售数据分析和预测
- 用户行为分析
- 业务指标监控
- 市场趋势分析
- 运营效率评估
## 🔧 使用方法
### 基本流程
1. **数据准备**
- 提供CSV、JSON或Excel格式的数据
- 指定要分析的列和分析类型
- 可选:配置分析参数
2. **执行分析**
- 技能自动选择合适的分析方法
- 执行数据预处理和清洗
- 应用统计模型和算法
3. **结果输出**
- 生成统计摘要
- 输出可视化图表
- 提供业务洞察和建议
### 高级用法
- **自定义分析流程**:通过参数配置选择特定的分析方法
- **批量分析**:同时分析多个数据集
- **增量分析**:基于历史分析结果进行增量更新
- **API集成**:通过RESTful API调用分析服务
## 📥 输入规范
```json
{
"data": {
"type": "object",
"required": true,
"description": "待分析的数据",
"properties": {
"format": {
"type": "string",
"enum": ["csv", "json", "excel", "parquet"],
"default": "json"
},
"content": {
"type": "string",
"description": "数据内容或文件路径"
},
"columns": {
"type": "array",
"items": {"type": "string"},
"description": "要分析的列名"
}
}
},
"analysisType": {
"type": "array",
"items": {
"type": "string",
"enum": [
"statistical", // 统计分析
"trend", // 趋势分析
"anomaly", // 异常检测
"correlation", // 相关性分析
"clustering", // 聚类分析
"regression", // 回归分析
"forecasting" // 预测分析
]
},
"default": ["statistical", "trend"]
},
"options": {
"type": "object",
"description": "可选配置",
"properties": {
"confidenceLevel": {"type": "number", "default": 0.95},
"outlierThreshold": {"type": "number", "default": 3.0},
"visualizationEnabled": {"type": "boolean", "default": true},
"groupBy": {"type": "string", "description": "分组字段"},
"timeSeries": {
"type": "object",
"properties": {
"dateColumn": {"type": "string"},
"frequency": {"type": "string", "enum": ["daily", "weekly", "monthly"]}
}
}
}
}
}
📤 输出规范
{
"status": {
"type": "string",
"enum": ["success", "partial_success", "failure"],
"description": "执行状态"
},
"summary": {
"type": "object",
"description": "统计摘要",
"properties": {
"recordCount": {"type": "integer"},
"columnCount": {"type": "integer"},
"missingValues": {"type": "object"},
"dataTypes": {"type": "object"}
}
},
"analyses": {
"type": "array",
"items": {
"type": "object",
"properties": {
"type": {"type": "string"},
"results": {"type": "object"},
"confidence": {"type": "number"},
"interpretation": {"type": "string"}
}
}
},
"visualizations": {
"type": "array",
"items": {
"type": "object",
"properties": {
"type": {"type": "string", "enum": ["line", "bar", "scatter", "heatmap"]},
"title": {"type": "string"},
"data": {"type": "object"},
"imageUrl": {"type": "string"}
}
}
},
"insights": {
"type": "array",
"items": {
"type": "object",
"properties": {
"category": {"type": "string", "enum": ["trend", "anomaly", "pattern", "correlation"]},
"severity": {"type": "string", "enum": ["high", "medium", "low"]},
"description": {"type": "string"},
"evidence": {"type": "array", "items": {"type": "string"}}
}
}
},
"recommendations": {
"type": "array",
"items": {
"type": "object",
"properties": {
"priority": {"type": "string", "enum": ["critical", "high", "medium", "low"]},
"action": {"type": "string"},
"rationale": {"type": "string"},
"expectedImpact": {"type": "string"}
}
}
},
"metadata": {
"type": "object",
"properties": {
"executionTime": {"type": "integer", "description": "执行时间(毫秒)"},
"skillVersion": {"type": "string"},
"timestamp": {"type": "string", "format": "date-time"}
}
}
}
📚 使用示例
示例1:销售数据多维度分析
业务背景: 某电商公司需要分析过去12个月的销售数据,识别销售趋势、异常订单、地区差异等。
输入:
{
"data": {
"format": "csv",
"content": "sales_data_2024.csv",
"columns": ["date", "amount", "region", "category", "quantity"]
},
"analysisType": ["statistical", "trend", "anomaly", "correlation"],
"options": {
"groupBy": "region",
"timeSeries": {
"dateColumn": "date",
"frequency": "monthly"
},
"visualizationEnabled": true
}
}
执行步骤:
- 加载12个月的销售数据(约50万条记录)
- 执行数据清洗:处理缺失值、异常值
- 按地区分组进行统计分析
- 时间序列分析:识别月度趋势和季节性
- 异常检测:标记异常订单和异常波动
- 相关性分析:分析销售额与其他因素的关系
- 生成可视化图表:折线图、柱状图、热力图
- 提取业务洞察和建议
输出:
{
"status": "success",
"summary": {
"recordCount": 487235,
"columnCount": 5,
"dateRange": "2024-01-01 to 2024-12-31",
"totalRevenue": 15847892.50
},
"analyses": [
{
"type": "statistical",
"results": {
"byRegion": {
"North": {"mean": 325.50, "median": 298.00, "std": 127.30},
"South": {"mean": 412.80, "median": 389.00, "std": 156.20},
"East": {"mean": 378.90, "median": 345.00, "std": 142.10},
"West": {"mean": 295.60, "median": 275.00, "std": 98.70}
}
},
"confidence": 0.95,
"interpretation": "南部地区平均订单金额最高,西部地区最低但波动性也最小"
},
{
"type": "trend",
"results": {
"overallTrend": "increasing",
"growthRate": 0.187,
"seasonality": {
"pattern": "quarterly",
"peaks": ["Q2", "Q4"],
"troughs": ["Q1", "Q3"]
}
},
"confidence": 0.89,
"interpretation": "整体销售呈上升趋势,年增长率18.7%,Q2和Q4是销售旺季"
},
{
"type": "anomaly",
"results": {
"anomalyCount": 247,
"anomalyRate": 0.0005,
"topAnomalies": [
{"date": "2024-03-15", "amount": 8950.00, "zscore": 4.2},
{"date": "2024-07-22", "amount": 9200.00, "zscore": 4.5},
{"date": "2024-11-11", "amount": 12500.00, "zscore": 5.8}
]
},
"confidence": 0.92,
"interpretation": "检测到247个异常订单,主要集中在促销活动期间"
}
],
"insights": [
{
"category": "trend",
"severity": "high",
"description": "销售额呈现稳定增长趋势,预计明年可达1850万",
"evidence": ["月度增长率平均1.5%", "Q4增长加速至2.1%", "客单价稳步提升"]
},
{
"category": "pattern",
"severity": "medium",
"description": "明显的季节性模式,Q2和Q4是销售高峰",
"evidence": ["Q2平均增长35%", "Q4增长42%", "与节假日高度相关"]
},
{
"category": "correlation",
"severity": "high",
"description": "南部地区销售额与营销投入呈强正相关",
"evidence": ["相关系数0.87", "每增加1万营销投入,销售额平均增加15万"]
}
],
"recommendations": [
{
"priority": "critical",
"action": "加大Q2和Q4的库存备货,提前1个月准备",
"rationale": "历史数据显示这两个季度需求激增,库存不足风险高",
"expectedImpact": "预计可减少缺货率50%,增加销售额8-12%"
},
{
"priority": "high",
"action": "针对南部地区加大营销投入,ROI最高",
"rationale": "南部地区对营销活动响应度最高,客单价也最高",
"expectedImpact": "预计ROI提升15-20%"
},
{
"priority": "medium",
"action": "分析西部地区低销售原因,制定改进方案",
"rationale": "西部地区销售额明显低于其他地区",
"expectedImpact": "挖掘市场潜力,预计增长空间30%以上"
}
],
"metadata": {
"executionTime": 2347,
"skillVersion": "2.1.0",
"timestamp": "2024-12-30T10:30:00Z"
}
}
业务价值:
- 发现销售增长机会:预测明年可达1850万
- 优化库存管理:提前备货减少缺货
- 精准营销投放:聚焦高ROI地区
- 市场潜力挖掘:改进低表现地区
示例2:用户行为深度分析
业务背景: SaaS公司需要分析用户的使用行为,识别流失风险、提升活跃度、优化产品功能。
输入:
{
"data": {
"format": "json",
"content": "user_behavior_logs.json",
"columns": ["user_id", "timestamp", "action", "duration", "feature", "device"]
},
"analysisType": ["statistical", "clustering", "correlation"],
"options": {
"confidenceLevel": 0.95,
"groupBy": "feature"
}
}
分析维度:
-
用户活跃度分析
- 日活(DAU)、周活(WAU)、月活(MAU)
- 留存率分析:次日、7日、30日留存
- 活跃时段分布
-
用户分层
- 基于RFM模型的用户价值分层
- K-means聚类识别用户群体
- 高价值用户特征分析
-
功能使用分析
- 各功能的使用频率和时长
- 功能间的跳转路径
- 冷门功能识别
-
流失风险预测
- 流失用户特征提取
- 流失预警指标
- 挽回策略建议
输出洞察:
{
"insights": [
{
"category": "pattern",
"severity": "high",
"description": "用户在使用'高级功能A'后,留存率提升35%",
"evidence": [
"使用过该功能的用户7日留存率达78%,未使用仅43%",
"该功能的用户NPS评分高出平均值22分"
]
},
{
"category": "anomaly",
"severity": "critical",
"description": "识别出15%的用户存在流失风险",
"evidence": [
"连续7天未登录",
"最近30天使用时长下降60%",
"未参与任何营销活动"
]
}
],
"recommendations": [
{
"priority": "critical",
"action": "针对流失风险用户推送个性化内容和优惠",
"rationale": "及时挽回可减少50%的流失",
"expectedImpact": "预计挽回3000+用户,价值约15万月费"
},
{
"priority": "high",
"action": "在新用户引导中重点突出'高级功能A'",
"rationale": "提升该功能的渗透率可显著提升留存",
"expectedImpact": "预计整体留存率提升10-15%"
}
]
}
示例3:实时业务监控仪表盘
场景:运营团队需要实时监控关键业务指标,快速发现异常并响应。
持续分析配置:
{
"mode": "streaming",
"dataSource": {
"type": "kafka",
"topic": "business_metrics",
"pollInterval": 60000 // 1分钟
},
"analysisType": ["statistical", "anomaly", "trend"],
"options": {
"alertThreshold": {
"orderVolume": {"min": 100, "max": 5000},
"averageOrderValue": {"min": 50, "max": 1000},
"conversionRate": {"min": 0.02}
},
"alertChannels": ["email", "slack", "sms"]
}
}
实时告警示例:
{
"alert": {
"level": "critical",
"metric": "conversionRate",
"currentValue": 0.0125,
"expectedValue": 0.035,
"deviation": -64.3,
"detectedAt": "2024-12-30T14:25:00Z",
"possibleCauses": [
"支付系统响应缓慢",
"商品详情页加载失败",
"营销活动配置错误"
],
"suggestedActions": [
"立即检查支付网关状态",
"回滚最近的前端部署",
"暂停当前营销活动"
]
}
}
⚠️ 使用限制
-
数据规模限制
- 免费版:最大10MB数据,1000次/月
- 高级版:最大1GB数据,无限次调用
- 企业版:无限制
-
性能考虑
- 大数据集(>100万行)建议使用采样分析
- 复杂分析(聚类、回归)可能需要5-10分钟
- 实时分析模式延迟<5秒
-
数据质量要求
- 至少70%的数据完整性
- 数值列不应包含过多异常值
- 时间序列数据需要连续性
-
兼容性
- 需要Java 17+
- 建议内存:>=512MB
- 推荐CPU:>=2核心
✅ 最佳实践
数据准备
// ✓ 好的做法
public void prepareData() {
// 1. 数据清洗
data.removeNullValues();
data.handleMissingValues(strategy = "median");
// 2. 数据验证
validator.checkDataQuality(data);
if (validator.getCompleteness() < 0.7) {
throw new DataQualityException("数据完整性不足");
}
// 3. 数据转换
data.normalizeNumericColumns();
data.encodeCategoricalColumns();
}
// ✗ 不好的做法
public void prepareData() {
// 直接使用原始数据,可能包含大量噪声和异常值
analyzeDirectly(rawData);
}
分析方法选择
// ✓ 根据数据特征选择合适的方法
public AnalysisType selectAnalysisMethod(Dataset data) {
if (data.isTimeSeries()) {
return AnalysisType.TREND_ANALYSIS;
} else if (data.hasCategoricalTarget()) {
return AnalysisType.CLASSIFICATION;
} else if (data.hasContinuousTarget()) {
return AnalysisType.REGRESSION;
} else {
return AnalysisType.STATISTICAL_SUMMARY;
}
}
// ✗ 盲目使用所有分析方法
public void analyze(Dataset data) {
// 浪费计算资源,结果可能无意义
runAll Analysis(data);
}
结果解释
// ✓ 提供业务相关的洞察
public Insight generateInsight(AnalysisResult result) {
return Insight.builder()
.description("销售额Q4增长42%,主要由促销活动驱动")
.evidence(List.of(
"促销期间日均订单量增加3倍",
"客单价提升25%",
"新客户占比达35%"
))
.recommendation("建议在Q1继续推出类似促销活动")
.expectedImpact("预计可增加销售额15-20%")
.build();
}
// ✗ 仅输出统计数字
public String generateInsight(AnalysisResult result) {
return "Mean: 425.5, Std: 127.3";
}
性能优化
// ✓ 大数据集使用采样
public void analyzeL argeDataset(Dataset data) {
if (data.size() > 1_000_000) {
Dataset sample = data.randomSample(100_000);
AnalysisResult result = analyze(sample);
result.addNote("基于10万样本的分析结果");
return result;
}
return analyze(data);
}
// ✓ 启用缓存
@Cacheable(key = "#dataHash", expiration = "1h")
public AnalysisResult analyze(String dataHash, Dataset data) {
return performAnalysis(data);
}
Skill定义的关键要素解析
1. YAML Front Matter(元数据)
---
# 这部分是机器可解析的结构化数据
id: skill-analytics-001 # 全局唯一ID
name: advanced_data_analytics # 技能名称(programmatic)
displayName: 高级数据分析 # 显示名称(human-readable)
version: 2.1.0 # 语义化版本
...
---
设计考虑:
- 使用YAML格式便于人类阅读和编辑
- 结构化数据便于程序解析和验证
- 版本号遵循SemVer规范(Major.Minor.Patch)
2. Markdown Body(文档)
# 技能标题
## 各个章节...
设计考虑:
- Markdown格式便于编写和渲染
- 支持代码高亮、表格、链接等丰富格式
- 可以生成HTML文档供用户浏览
3. 依赖管理
dependencies:
- skill: statistical_summary
version: ">=2.0.0" # 语义化版本约束
required: true
reason: 提供基础统计计算能力
版本约束语法:
"1.0.0"- 精确匹配">=1.0.0"- 大于等于"^1.5.0"- 兼容版本(1.5.x,但不包括2.x)"~1.3.0"- 近似版本(1.3.x)"1.0.0 - 2.0.0"- 范围
(How - 如何实现)
Skill加载器的完整实现
/**
* Skill加载器:负责从各种来源加载Skill定义
*/
public class SkillLoader {
private static final Logger logger = LoggerFactory.getLogger(SkillLoader.class);
private static final SkillValidator validator = new SkillValidator();
private static final DependencyResolver dependencyResolver = new DependencyResolver();
private static final Map<String, AgentSkill> skillCache = new ConcurrentHashMap<>();
/**
* 从Mark down文件加载Skill(主要方式)
*/
public static AgentSkill loadFromMarkdown(String markdownContent)
throws SkillLoadException {
try {
// 1. 解析YAML Front Matter
SkillMetadata metadata = parseYamlFrontMatter(markdownContent);
// 2. 解析Markdown Body
SkillDocumentation doc = parseMarkdownBody(markdownContent);
// 3. 构建AgentSkill对象
AgentSkill skill = AgentSkill.builder()
.id(metadata.getId())
.name(metadata.getName())
.displayName(metadata.getDisplayName())
.description(metadata.getDescription())
.detailedDescription(metadata.getDetailedDescription())
.version(metadata.getVersion())
.author(metadata.getAuthor())
.organization(metadata.getOrganization())
.createdAt(metadata.getCreatedAt())
.updatedAt(metadata.getUpdatedAt())
.tags(metadata.getTags())
.keywords(metadata.getKeywords())
.category(metadata.getCategory())
.objective(doc.getObjective())
.usageMethod(doc.getUsageMethod())
.inputSpec(doc.getInputSpec())
.outputSpec(doc.getOutputSpec())
.examples(doc.getExamples())
.bestPractices(doc.getBestPractices())
.limitations(doc.getLimitations())
.dependencies(metadata.getDependencies())
.conflicts(metadata.getConflicts())
.requires(metadata.getRequires())
.executionConfig(metadata.getExecutionConfig())
.parameters(metadata.getParameters())
.metrics(metadata.getMetrics())
.testCases(doc.getTestCases())
.qualityScore(metadata.getQualityScore())
.reviews(metadata.getReviews())
.license(metadata.getLicense())
.pricing(metadata.getPricing())
.isPublic(metadata.isPublic())
.metadata(metadata.getCustomMetadata())
.build();
// 4. 验证Skill定义
ValidationResult validationResult = validator.validate(skill);
if (!validationResult.isValid()) {
throw new SkillValidationException(
"Skill验证失败: " + validationResult.getErrors()
);
}
// 5. 解析依赖
DependencyResolutionResult depResult = dependencyResolver.resolve(skill);
if (!depResult.isResolved()) {
logger.warn("依赖解析失败: {}", depResult.getUnresolvedDependencies());
}
// 6. 缓存Skill
skillCache.put(skill.getId(), skill);
logger.info("✓ 成功加载技能: {} v{}", skill.getName(), skill.getVersion());
return skill;
} catch (Exception e) {
logger.error("加载技能失败", e);
throw new SkillLoadException("无法加载技能: " + e.getMessage(), e);
}
}
/**
* 从本地文件加载
*/
public static AgentSkill loadFromFile(Path skillFile) throws SkillLoadException {
try {
String content = Files.readString(skillFile, StandardCharsets.UTF_8);
return loadFromMarkdown(content);
} catch (IOException e) {
throw new SkillLoadException("读取文件失败: " + skillFile, e);
}
}
/**
* 从远程URL加载
*/
public static AgentSkill loadFromURL(String url) throws SkillLoadException {
try {
// 检查缓存
String cacheKey = "url:" + url;
if (skillCache.containsKey(cacheKey)) {
logger.debug("从缓存加载: {}", url);
return skillCache.get(cacheKey);
}
// 下载内容
HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(url))
.timeout(Duration.ofSeconds(30))
.build();
HttpResponse<String> response = client.send(
request,
HttpResponse.BodyHandlers.ofString()
);
if (response.statusCode() != 200) {
throw new SkillLoadException(
"HTTP错误: " + response.statusCode()
);
}
AgentSkill skill = loadFromMarkdown(response.body());
skillCache.put(cacheKey, skill);
return skill;
} catch (Exception e) {
throw new SkillLoadException("从 URL 加载失败: " + url, e);
}
}
/**
* 从Java代码定义加载
*/
public static AgentSkill loadFromClass(Class<? extends SkillDefinition> skillClass)
throws SkillLoadException {
try {
SkillDefinition skillDef = skillClass.getDeclaredConstructor().newInstance();
AgentSkill skill = skillDef.define();
// 验证
ValidationResult validationResult = validator.validate(skill);
if (!validationResult.isValid()) {
throw new SkillValidationException(
"Skill验证失败: " + validationResult.getErrors()
);
}
skillCache.put(skill.getId(), skill);
return skill;
} catch (Exception e) {
throw new SkillLoadException("从类加载失败: " + skillClass.getName(), e);
}
}
/**
* 批量加载技能
*/
public static List<AgentSkill> loadFromDirectory(Path directory)
throws SkillLoadException {
List<AgentSkill> skills = new ArrayList<>();
try (Stream<Path> paths = Files.walk(directory)) {
List<Path> skillFiles = paths
.filter(Files::isRegularFile)
.filter(p -> p.toString().endsWith(".md"))
.collect(Collectors.toList());
logger.info("发现 {} 个技能文件", skillFiles.size());
for (Path skillFile : skillFiles) {
try {
AgentSkill skill = loadFromFile(skillFile);
skills.add(skill);
} catch (SkillLoadException e) {
logger.error("加载失败: {}", skillFile, e);
// 继续加载其他技能
}
}
} catch (IOException e) {
throw new SkillLoadException("遍历目录失败: " + directory, e);
}
logger.info("✓ 成功加载 {} 个技能", skills.size());
return skills;
}
/**
* 清理缓存
*/
public static void clearCache() {
skillCache.clear();
logger.info("技能缓存已清理");
}
/**
* 获取缓存的技能
*/
public static Optional<AgentSkill> getCached(String skillId) {
return Optional.ofNullable(skillCache.get(skillId));
}
// ========== 私有辅助方法 ==========
private static SkillMetadata parseYamlFrontMatter(String content) {
// 提取YAML Front Matter
Pattern pattern = Pattern.compile("^---\\s*\\n(.*?)\\n---\\s*\\n",
Pattern.DOTALL);
Matcher matcher = pattern.matcher(content);
if (!matcher.find()) {
throw new IllegalArgumentException("未找到YAML Front Matter");
}
String yamlContent = matcher.group(1);
// 解析YAML
Yaml yaml = new Yaml();
Map<String, Object> yamlData = yaml.load(yamlContent);
// 转换为SkillMetadata
return SkillMetadata.fromMap(yamlData);
}
private static SkillDocumentation parseMarkdownBody(String content) {
// 移除YAML Front Matter
String markdownBody = content.replaceFirst(
"^---\\s*\\n.*?\\n---\\s*\\n",
""
);
// 解析Markdown结构
CommonMarkParser parser = CommonMarkParser.builder().build();
Node document = parser.parse(markdownBody);
// 提取各个章节
SkillDocumentation.Builder docBuilder = SkillDocumentation.builder();
document.accept(new AbstractVisitor() {
private String currentSection = null;
private StringBuilder sectionContent = new StringBuilder();
@Override
public void visit(Heading heading) {
// 处理上一个章节
if (currentSection != null) {
processSection(currentSection, sectionContent.toString(), docBuilder);
}
// 开始新章节
currentSection = ((Text)heading.getFirstChild()).getLiteral();
sectionContent = new StringBuilder();
super.visit(heading);
}
@Override
public void visit(Text text) {
if (currentSection != null) {
sectionContent.append(text.getLiteral());
}
super.visit(text);
}
});
return docBuilder.build();
}
private static void processSection(String section, String content,
SkillDocumentation.Builder builder) {
switch (section.trim()) {
case "技能目标":
case "📋 技能目标":
builder.objective(content.trim());
break;
case "使用方法":
case "🔧 使用方法":
builder.usageMethod(content.trim());
break;
case "输入规范":
case "📥 输入规范":
builder.inputSpec(parseJsonSchema(content));
break;
case "输出规范":
case "📤 输出规范":
builder.outputSpec(parseJsonSchema(content));
break;
case "使用示例":
case "📚 使用示例":
builder.examples(parseExamples(content));
break;
case "最佳实践":
case "✅ 最佳实践":
builder.bestPractices(parseBestPractices(content));
break;
case "使用限制":
case "⚠️ 使用限制":
builder.limitations(parseLimitations(content));
break;
}
}
private static Map<String, Object> parseJsonSchema(String content) {
// 提取JSON代码块
Pattern pattern = Pattern.compile("```json\\s*\\n(.*?)\\n```",
Pattern.DOTALL);
Matcher matcher = pattern.matcher(content);
if (matcher.find()) {
String jsonContent = matcher.group(1);
ObjectMapper mapper = new ObjectMapper();
try {
return mapper.readValue(jsonContent,
new TypeReference<Map<String, Object>>() {});
} catch (JsonProcessingException e) {
logger.error("解析JSON Schema失败", e);
return Collections.emptyMap();
}
}
return Collections.emptyMap();
}
private static List<SkillExample> parseExamples(String content) {
// TODO: 实现示例解析逻辑
return Collections.emptyList();
}
private static List<String> parseBestPractices(String content) {
// TODO: 实现最佳实践解析逻辑
return Collections.emptyList();
}
private static List<String> parseLimitations(String content) {
// TODO: 实现限制解析逻辑
return Collections.emptyList();
}
}
Skill验证器
/**
* Skill验证器:验证Skill定义的完整性和正确性
*/
public class SkillValidator {
private static final Logger logger = LoggerFactory.getLogger(SkillValidator.class);
/**
* 验证Skill
*/
public ValidationResult validate(AgentSkill skill) {
List<ValidationError> errors = new ArrayList<>();
List<ValidationWarning> warnings = new ArrayList<>();
// 1. 验证基础信息
validateBasicInfo(skill, errors);
// 2. 验证版本号
validateVersion(skill, errors);
// 3. 验证依赖
validateDependencies(skill, errors, warnings);
// 4. 验证输入/输出Schema
validateSchemas(skill, errors);
// 5. 验证示例
validateExamples(skill, warnings);
// 6. 验证执行配置
validateExecutionConfig(skill, warnings);
return ValidationResult.builder()
.valid(errors.isEmpty())
.errors(errors)
.warnings(warnings)
.build();
}
private void validateBasicInfo(AgentSkill skill, List<ValidationError> errors) {
// 必填字段
if (StringUtils.isBlank(skill.getId())) {
errors.add(new ValidationError("id", "技能ID不能为空"));
}
if (StringUtils.isBlank(skill.getName())) {
errors.add(new ValidationError("name", "技能名称不能为空"));
} else {
// 验证命名规范:小写字母、数字、下划线
if (!skill.getName().matches("^[a-z0-9_]+$")) {
errors.add(new ValidationError("name",
"技能名称应仅包含小写字母、数字和下划线"));
}
}
if (StringUtils.isBlank(skill.getDescription())) {
errors.add(new ValidationError("description", "技能描述不能为空"));
}
// 检查描述长度
if (skill.getDescription() != null && skill.getDescription().length() > 200) {
errors.add(new ValidationError("description",
"简短描述应少于200字符"));
}
}
private void validateVersion(AgentSkill skill, List<ValidationError> errors) {
if (StringUtils.isBlank(skill.getVersion())) {
errors.add(new ValidationError("version", "版本号不能为空"));
return;
}
// 验证语义化版本号格式:Major.Minor.Patch
if (!skill.getVersion().matches("^\\d+\\.\\d+\\.\\d+(-[a-zA-Z0-9.]+)?$")) {
errors.add(new ValidationError("version",
"版本号应遵循SemVer格式(如: 1.0.0, 2.1.0-beta)"));
}
}
private void validateDependencies(AgentSkill skill,
List<ValidationError> errors,
List<ValidationWarning> warnings) {
if (skill.getDependencies() == null || skill.getDependencies().isEmpty()) {
return;
}
for (SkillDependency dep : skill.getDependencies()) {
// 验证依赖名称
if (StringUtils.isBlank(dep.getSkillName())) {
errors.add(new ValidationError("dependencies",
"依赖技能名称不能为空"));
}
// 验证版本约束
if (StringUtils.isBlank(dep.getVersionConstraint())) {
warnings.add(new ValidationWarning("dependencies",
"建议指定依赖的版本约束: " + dep.getSkillName()));
}
// 验证版本约束语法
if (!isValidVersionConstraint(dep.getVersionConstraint())) {
errors.add(new ValidationError("dependencies",
"无效的版本约束: " + dep.getVersionConstraint()));
}
}
// 检查循环依赖
if (hasCircularDependency(skill)) {
errors.add(new ValidationError("dependencies",
"检测到循环依赖"));
}
}
private void validateSchemas(AgentSkill skill, List<ValidationError> errors) {
// 验证输入Schema
if (skill.getInputSpec() != null) {
try {
validateJsonSchema(skill.getInputSpec());
} catch (Exception e) {
errors.add(new ValidationError("inputSpec",
"输入Schema格式错误: " + e.getMessage()));
}
}
// 验证输出Schema
if (skill.getOutputSpec() != null) {
try {
validateJsonSchema(skill.getOutputSpec());
} catch (Exception e) {
errors.add(new ValidationError("outputSpec",
"输出Schema格式错误: " + e.getMessage()));
}
}
}
private void validateExamples(AgentSkill skill, List<ValidationWarning> warnings) {
if (skill.getExamples() == null || skill.getExamples().isEmpty()) {
warnings.add(new ValidationWarning("examples",
"建议提供至少一个使用示例"));
}
}
private void validateExecutionConfig(AgentSkill skill,
List<ValidationWarning> warnings) {
SkillExecutionConfig config = skill.getExecutionConfig();
if (config == null) {
return;
}
// 检查超时设置
if (config.getTimeout() <= 0) {
warnings.add(new ValidationWarning("executionConfig.timeout",
"超时时间应大于0"));
}
if (config.getTimeout() > 600000) { // 10分钟
warnings.add(new ValidationWarning("executionConfig.timeout",
"超时时间过长,可能影响用户体验"));
}
// 检查重试次数
if (config.getRetries() > 5) {
warnings.add(new ValidationWarning("executionConfig.retries",
"重试次数过多,建议不超过5次"));
}
}
private boolean isValidVersionConstraint(String constraint) {
if (StringUtils.isBlank(constraint)) {
return false;
}
// 支持的格式:>=1.0.0, ^1.5.0, ~1.3.0, 1.0.0 - 2.0.0
String[] patterns = {
"^\\d+\\.\\d+\\.\\d+$", // 1.0.0
"^[><=!]+\\d+\\.\\d+\\.\\d+$", // >=1.0.0, <=2.0.0
"^\\^\\d+\\.\\d+\\.\\d+$", // ^1.5.0
"^~\\d+\\.\\d+\\.\\d+$", // ~1.3.0
"^\\d+\\.\\d+\\.\\d+ - \\d+\\.\\d+\\.\\d+$" // 1.0.0 - 2.0.0
};
for (String pattern : patterns) {
if (constraint.matches(pattern)) {
return true;
}
}
return false;
}
private boolean hasCircularDependency(AgentSkill skill) {
// TODO: 实现循环依赖检测
return false;
}
private void validateJsonSchema(Map<String, Object> schema) {
// TODO: 使用JSON Schema验证器
}
}
/**
* 验证结果
*/
@Data
@Builder
public class ValidationResult {
private boolean valid;
private List<ValidationError> errors;
private List<ValidationWarning> warnings;
public String getErrorSummary() {
if (valid) {
return "验证通过";
}
StringBuilder sb = new StringBuilder("验证失败:\n");
for (ValidationError error : errors) {
sb.append(" - ").append(error.getField())
.append(": ").append(error.getMessage())
.append("\n");
}
return sb.toString();
}
}
@Data
@AllArgsConstructor
public class ValidationError {
private String field;
private String message;
}
@Data
@AllArgsConstructor
public class ValidationWarning {
private String field;
private String message;
}
依赖解析器
/**
* 依赖解析器:解析技能的依赖关系
*/
public class DependencyResolver {
private static final Logger logger = LoggerFactory.getLogger(DependencyResolver.class);
private final SkillRepository repository;
public DependencyResolver() {
this.repository = null; // 默认使用全局仓库
}
public DependencyResolver(SkillRepository repository) {
this.repository = repository;
}
/**
* 解析技能的所有依赖
*/
public DependencyResolutionResult resolve(AgentSkill skill) {
Map<String, AgentSkill> resolvedDeps = new HashMap<>();
List<String> unresolvedDeps = new ArrayList<>();
List<String> conflicts = new ArrayList<>();
if (skill.getDependencies() == null || skill.getDependencies().isEmpty()) {
return DependencyResolutionResult.builder()
.resolved(true)
.dependencies(Collections.emptyMap())
.unresolvedDependencies(Collections.emptyList())
.conflicts(Collections.emptyList())
.build();
}
// 构建依赖图
DependencyGraph graph = buildDependencyGraph(skill);
// 拓扑排序
List<String> sortedDeps = graph.topologicalSort();
// 逐个解析
for (String depName : sortedDeps) {
SkillDependency dep = findDependency(skill, depName);
if (dep == null) continue;
try {
AgentSkill resolvedSkill = resolveSingleDependency(dep);
if (resolvedSkill != null) {
resolvedDeps.put(depName, resolvedSkill);
} else {
unresolvedDeps.add(depName);
}
} catch (DependencyConflictException e) {
conflicts.add(e.getMessage());
}
}
boolean resolved = unresolvedDeps.isEmpty() && conflicts.isEmpty();
return DependencyResolutionResult.builder()
.resolved(resolved)
.dependencies(resolvedDeps)
.unresolvedDependencies(unresolvedDeps)
.conflicts(conflicts)
.build();
}
private AgentSkill resolveSingleDependency(SkillDependency dep)
throws DependencyConflictException {
// 1. 尝试从缓存加载
Optional<AgentSkill> cached = SkillLoader.getCached(dep.getSkillName());
if (cached.isPresent()) {
AgentSkill skill = cached.get();
if (matchesVersionConstraint(skill.getVersion(), dep.getVersionConstraint())) {
logger.debug("从缓存解析: {} v{}", skill.getName(), skill.getVersion());
return skill;
}
}
// 2. 从仓库加载
if (repository != null) {
List<AgentSkill> candidates = repository.searchSkills(dep.getSkillName());
for (AgentSkill candidate : candidates) {
if (matchesVersionConstraint(candidate.getVersion(),
dep.getVersionConstraint())) {
logger.info("从仓库解析: {} v{}",
candidate.getName(), candidate.getVersion());
return candidate;
}
}
}
// 3. 尝试下载最新版本
if (repository != null) {
try {
AgentSkill skill = repository.downloadSkill(
dep.getSkillName(),
"latest"
);
if (skill != null && matchesVersionConstraint(
skill.getVersion(), dep.getVersionConstraint())) {
logger.info("下载并解析: {} v{}",
skill.getName(), skill.getVersion());
return skill;
}
} catch (Exception e) {
logger.error("下载依赖失败: {}", dep.getSkillName(), e);
}
}
logger.warn("无法解析依赖: {} {}",
dep.getSkillName(), dep.getVersionConstraint());
return null;
}
private boolean matchesVersionConstraint(String version, String constraint) {
if (StringUtils.isBlank(constraint)) {
return true; // 无约束
}
SemVer actualVersion = SemVer.parse(version);
if (constraint.startsWith(">=")) {
SemVer minVersion = SemVer.parse(constraint.substring(2));
return actualVersion.compareTo(minVersion) >= 0;
}
else if (constraint.startsWith(">")) {
SemVer minVersion = SemVer.parse(constraint.substring(1));
return actualVersion.compareTo(minVersion) > 0;
}
else if (constraint.startsWith("<=")) {
SemVer maxVersion = SemVer.parse(constraint.substring(2));
return actualVersion.compareTo(maxVersion) <= 0;
}
else if (constraint.startsWith("<")) {
SemVer maxVersion = SemVer.parse(constraint.substring(1));
return actualVersion.compareTo(maxVersion) < 0;
}
else if (constraint.startsWith("^")) {
// 兼容版本:^1.5.0 匹配 1.5.x 但不包括 2.x
SemVer baseVersion = SemVer.parse(constraint.substring(1));
return actualVersion.getMajor() == baseVersion.getMajor() &&
actualVersion.compareTo(baseVersion) >= 0;
}
else if (constraint.startsWith("~")) {
// 近似版本:~1.3.0 匹配 1.3.x
SemVer baseVersion = SemVer.parse(constraint.substring(1));
return actualVersion.getMajor() == baseVersion.getMajor() &&
actualVersion.getMinor() == baseVersion.getMinor() &&
actualVersion.compareTo(baseVersion) >= 0;
}
else if (constraint.contains(" - ")) {
// 范围:1.0.0 - 2.0.0
String[] parts = constraint.split(" - ");
SemVer minVersion = SemVer.parse(parts[0].trim());
SemVer maxVersion = SemVer.parse(parts[1].trim());
return actualVersion.compareTo(minVersion) >= 0 &&
actualVersion.compareTo(maxVersion) <= 0;
}
else {
// 精确匹配
SemVer requiredVersion = SemVer.parse(constraint);
return actualVersion.equals(requiredVersion);
}
}
private DependencyGraph buildDependencyGraph(AgentSkill skill) {
DependencyGraph graph = new DependencyGraph();
buildGraphRecursive(skill, graph, new HashSet<>());
return graph;
}
private void buildGraphRecursive(AgentSkill skill,
DependencyGraph graph,
Set<String> visited) {
if (visited.contains(skill.getName())) {
return; // 避免循环
}
visited.add(skill.getName());
if (skill.getDependencies() == null) {
return;
}
for (SkillDependency dep : skill.getDependencies()) {
graph.addEdge(skill.getName(), dep.getSkillName());
// 递归构建依赖的依赖
Optional<AgentSkill> depSkill = SkillLoader.getCached(dep.getSkillName());
if (depSkill.isPresent()) {
buildGraphRecursive(depSkill.get(), graph, visited);
}
}
}
private SkillDependency findDependency(AgentSkill skill, String depName) {
if (skill.getDependencies() == null) {
return null;
}
return skill.getDependencies().stream()
.filter(d -> d.getSkillName().equals(depName))
.findFirst()
.orElse(null);
}
}
/**
* 依赖图
*/
class DependencyGraph {
private final Map<String, List<String>> adjacencyList = new HashMap<>();
public void addEdge(String from, String to) {
adjacencyList.computeIfAbsent(from, k -> new ArrayList<>()).add(to);
}
public List<String> topologicalSort() {
Map<String, Integer> inDegree = new HashMap<>();
List<String> result = new ArrayList<>();
// 计算入度
for (String node : adjacencyList.keySet()) {
inDegree.putIfAbsent(node, 0);
for (String neighbor : adjacencyList.get(node)) {
inDegree.put(neighbor, inDegree.getOrDefault(neighbor, 0) + 1);
}
}
// 找到所有入度为0的节点
Queue<String> queue = new LinkedList<>();
for (Map.Entry<String, Integer> entry : inDegree.entrySet()) {
if (entry.getValue() == 0) {
queue.offer(entry.getKey());
}
}
// BFS
while (!queue.isEmpty()) {
String node = queue.poll();
result.add(node);
if (adjacencyList.containsKey(node)) {
for (String neighbor : adjacencyList.get(node)) {
inDegree.put(neighbor, inDegree.get(neighbor) - 1);
if (inDegree.get(neighbor) == 0) {
queue.offer(neighbor);
}
}
}
}
return result;
}
}
/**
* 语义化版本号
*/
@Data
@AllArgsConstructor
class SemVer implements Comparable<SemVer> {
private int major;
private int minor;
private int patch;
private String preRelease; // 可选,如 "beta", "alpha.1"
public static SemVer parse(String version) {
String[] parts = version.split("-", 2);
String[] numbers = parts[0].split("\\.");
int major = Integer.parseInt(numbers[0]);
int minor = numbers.length > 1 ? Integer.parseInt(numbers[1]) : 0;
int patch = numbers.length > 2 ? Integer.parseInt(numbers[2]) : 0;
String preRelease = parts.length > 1 ? parts[1] : null;
return new SemVer(major, minor, patch, preRelease);
}
@Override
public int compareTo(SemVer other) {
if (this.major != other.major) {
return Integer.compare(this.major, other.major);
}
if (this.minor != other.minor) {
return Integer.compare(this.minor, other.minor);
}
if (this.patch != other.patch) {
return Integer.compare(this.patch, other.patch);
}
// 比较预发布版本
if (this.preRelease == null && other.preRelease == null) {
return 0;
}
if (this.preRelease == null) {
return 1; // 正式版本 > 预发布版本
}
if (other.preRelease == null) {
return -1;
}
return this.preRelease.compareTo(other.preRelease);
}
@Override
public String toString() {
String version = major + "." + minor + "." + patch;
if (preRelease != null) {
version += "-" + preRelease;
}
return version;
}
}
/**
* 依赖解析结果
*/
@Data
@Builder
class DependencyResolutionResult {
private boolean resolved;
private Map<String, AgentSkill> dependencies;
private List<String> unresolvedDependencies;
private List<String> conflicts;
}
class DependencyConflictException extends Exception {
public DependencyConflictException(String message) {
super(message);
}
}
class SkillLoadException extends Exception {
public SkillLoadException(String message) {
super(message);
}
public SkillLoadException(String message, Throwable cause) {
super(message, cause);
}
}
class SkillValidationException extends SkillLoadException {
public SkillValidationException(String message) {
super(message);
}
}
在Agent中使用Skill - 基础示例
public class SkillUsageDemo {
public static void main(String[] args) throws Exception {
Model model = DashScopeModel.builder()
.modelName("qwen-turbo")
.apiKey(System.getenv("DASHSCOPE_API_KEY"))
.build();
// 1. 加载技能
System.out.println("=== 加载技能 ===\n");
AgentSkill analysisSkill = SkillLoader.loadFromFile(
Paths.get("skills/data_analysis.md")
);
AgentSkill visualizationSkill = SkillLoader.loadFromFile(
Paths.get("skills/data_visualization.md")
);
// 2. 创建Agent并注入技能
System.out.println("=== 创建支持技能的Agent ===\n");
ReActAgent agent = ReActAgent.builder()
.name("DataAnalystAgent")
.model(model)
.skills(List.of(analysisSkill, visualizationSkill))
.systemPrompt(buildSystemPrompt(List.of(analysisSkill, visualizationSkill)))
.build();
// 3. 使用Agent
System.out.println("=== Agent执行任务 ===\n");
Msg response = agent.call(Msg.builder()
.textContent("""
这是我们公司过去6个月的销售数据:
[数据内容...]
请使用技能进行分析和可视化。
""")
.build()).block();
System.out.println("分析结果:\n" + response.getTextContent());
}
private static String buildSystemPrompt(List<AgentSkill> skills) {
StringBuilder prompt = new StringBuilder();
prompt.append("你是一个数据分析助手,拥有以下技能:\n\n");
for (AgentSkill skill : skills) {
prompt.append("【技能:").append(skill.getName()).append("】\n");
prompt.append("描述:").append(skill.getDescription()).append("\n");
prompt.append("使用方法:\n").append(skill.getUsageMethod()).append("\n\n");
}
prompt.append("请在回答用户问题时合理使用这些技能。");
return prompt.toString();
}
}
本章总结
Skill技能系统是AgentScope框架中的核心能力中台,提供了:
核心特性
- ✓ 标准化定义:Markdown + YAML Front Matter格式
- ✓ 复用性:一次定义,多处使用
- ✓ 组合性:技能可以相互依赖和调用
- ✓ 版本管理:语义化版本号和依赖解析
- ✓ 共享性:通过技能市场共享和交易
关键组件
- SkillLoader:从多种来源加载技能(文件、URL、类)
- SkillValidator:验证技能定义的完整性和正确性
- DependencyResolver:解析和管理技能依赖
- SkillRepository:技能库管理,支持本地和远程
- SkillOrchestrator:编排和执行多个技能
使用场景
- 企业AI能力中台
- 多Agent协作系统
- 领域专业知识封装
- 技能市场和生态