汉字魔法师
118.67M · 2026-02-04
在人工智能快速发展的今天,Agent智能体技术正在改变我们构建应用的方式。Agent Skills工作流作为连接智能体与具体能力的桥梁,为开发者提供了一种灵活、可扩展的架构模式。本文将从基础概念出发,结合实际案例,带你深入了解Agent Skills的设计与实现。
Agent(智能体):具有自主决策能力的实体,能够理解任务、规划行动并执行操作。
Skill(技能):Agent可以调用的具体能力单元,如文件读取、数据查询、文本分析等。
Agent Skills工作流:Agent通过识别任务需求,动态选择并调用合适的Skill,最终完成用户目标的过程。
Agent Skills架构包含四个核心层次:
这种分层设计确保了系统的可扩展性和可维护性。
package com.example.agent;
import com.example.skills.Skill;
import com.example.skills.SkillResult;
import java.util.Map;
/**
* Agent智能体接口
* 定义Agent的基本行为和能力
* @version 1.0.0
*/
public interface Agent {
/**
* 获取Agent名称
*/
String getName();
/**
* 获取Agent描述
*/
String getDescription();
/**
* 执行任务
*
* @param task 任务内容
* @param context 执行上下文
* @return 执行结果
*/
AgentResult execute(String task, AgentContext context);
/**
* 注册技能
*
* @param skill 技能实例
*/
void registerSkill(Skill skill);
/**
* 获取已注册的所有技能
*/
java.util.Collection<Skill> getSkills();
/**
* Agent执行结果
*/
class AgentResult {
private final boolean success;
private final String message;
private final Object data;
private final long executionTime;
public AgentResult(boolean success, String message, Object data, long executionTime) {
this.success = success;
this.message = message;
this.data = data;
this.executionTime = executionTime;
}
public static AgentResult success(String message, Object data) {
return new AgentResult(true, message, data, 0);
}
public static AgentResult success(String message, Object data, long executionTime) {
return new AgentResult(true, message, data, executionTime);
}
public static AgentResult failure(String message) {
return new AgentResult(false, message, null, 0);
}
public boolean isSuccess() {
return success;
}
public String getMessage() {
return message;
}
public Object getData() {
return data;
}
public long getExecutionTime() {
return executionTime;
}
@Override
public String toString() {
return "AgentResult{" +
"success=" + success +
", message='" + message + ''' +
", data=" + data +
", executionTime=" + executionTime + "ms" +
'}';
}
}
}
Agent接口定义了智能体的基本行为,其中最关键的是execute方法,它接收任务和上下文,返回执行结果。
package com.example.skills;
import java.util.Map;
/**
* Skill技能接口
* 定义Agent可以执行的具体技能
* @version 1.0.0
*/
public interface Skill {
/**
* 获取技能名称
*/
String getName();
/**
* 获取技能描述
*/
String getDescription();
/**
* 获取技能版本
*/
default String getVersion() {
return "1.0.0";
}
/**
* 判断技能是否可以执行该任务
*
* @param task 任务内容
* @return 是否可以执行
*/
boolean canExecute(String task);
/**
* 执行技能
*
* @param task 任务内容
* @param parameters 参数
* @return 执行结果
*/
SkillResult execute(String task, Map<String, Object> parameters);
/**
* 获取技能的超时时间(毫秒)
* 默认30秒
*/
default long getTimeout() {
return 30000;
}
/**
* 技能执行前的验证
*
* @param task 任务内容
* @param parameters 参数
* @return 验证是否通过
*/
default boolean validate(String task, Map<String, Object> parameters) {
return task != null && !task.trim().isEmpty();
}
/**
* 技能执行后的清理
*/
default void cleanup() {
// 默认不需要清理
}
}
Skill接口采用策略模式,每个技能实现独立的功能,并通过canExecute方法声明自己能处理哪些任务。
完整的技能调用流程包括10个步骤:
每个步骤都有其特定的职责,确保任务能够安全、高效地执行。
package com.example.skills.impl;
import com.example.skills.Skill;
import com.example.skills.SkillResult;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* 文件读取技能
* 用于读取本地文件内容
* @version 1.0.0
*/
public class FileReadSkill implements Skill {
private static final Logger logger = LoggerFactory.getLogger(FileReadSkill.class);
@Override
public String getName() {
return "FileReadSkill";
}
@Override
public String getDescription() {
return "读取本地文件内容,支持文本文件、配置文件等";
}
@Override
public boolean canExecute(String task) {
if (task == null) {
return false;
}
String lowerTask = task.toLowerCase();
return lowerTask.contains("文件") &&
(lowerTask.contains("读取") || lowerTask.contains("打开") || lowerTask.contains("查看"));
}
@Override
public boolean validate(String task, Map<String, Object> parameters) {
if (!Skill.super.validate(task, parameters)) {
return false;
}
// 检查文件路径参数
Object filePath = parameters.get("filePath");
if (filePath == null) {
logger.warn("filePath parameter is missing");
return false;
}
Path path = Paths.get(filePath.toString());
if (!Files.exists(path)) {
logger.warn("File does not exist: {}", filePath);
return false;
}
if (!Files.isReadable(path)) {
logger.warn("File is not readable: {}", filePath);
return false;
}
return true;
}
@Override
public SkillResult execute(String task, Map<String, Object> parameters) {
long startTime = System.currentTimeMillis();
try {
String filePath = parameters.get("filePath").toString();
logger.info("Reading file: {}", filePath);
Path path = Paths.get(filePath);
// 读取文件内容
String content = new String(Files.readAllBytes(path), StandardCharsets.UTF_8);
// 获取文件信息
long fileSize = Files.size(path);
String fileName = path.getFileName().toString();
// 构建元数据
Map<String, Object> metadata = new java.util.HashMap<>();
metadata.put("filePath", filePath);
metadata.put("fileName", fileName);
metadata.put("fileSize", fileSize);
metadata.put("lines", content.split("n").length);
long executionTime = System.currentTimeMillis() - startTime;
logger.info("File read successfully: {} ({} bytes)", fileName, fileSize);
return SkillResult.success(
"文件读取成功: " + fileName,
content,
executionTime,
metadata
);
} catch (IOException e) {
logger.error("Error reading file", e);
return SkillResult.failure("文件读取失败: " + e.getMessage(), e.getMessage());
}
}
@Override
public long getTimeout() {
return 10000; // 10秒超时
}
/**
* 读取文件行
*/
public List<String> readLines(String filePath) throws IOException {
Path path = Paths.get(filePath);
return Files.readAllLines(path, StandardCharsets.UTF_8);
}
/**
* 检查文件是否存在
*/
public boolean exists(String filePath) {
return Files.exists(Paths.get(filePath));
}
/**
* 获取文件大小
*/
public long getFileSize(String filePath) throws IOException {
return Files.size(Paths.get(filePath));
}
}
public class DataQuerySkill implements Skill {
private final Map<String, List<Map<String, Object>>> database;
public DataQuerySkill() {
this.database = new ConcurrentHashMap<>();
initializeSampleData();
}
@Override
public boolean canExecute(String task) {
String lowerTask = task.toLowerCase();
return lowerTask.contains("查询") ||
lowerTask.contains("数据");
}
@Override
public SkillResult execute(String task, Map<String, Object> parameters) {
String tableName = parameters.get("tableName").toString();
String condition = parameters.get("condition").toString();
List<Map<String, Object>> results = performQuery(
tableName, condition, 100
);
return SkillResult.success(
"查询成功,找到" + results.size() + "条记录",
results
);
}
}
public class TextAnalysisSkill implements Skill {
@Override
public SkillResult execute(String task, Map<String, Object> parameters) {
String text = parameters.get("text").toString();
String operation = parameters.get("operation").toString();
switch (operation) {
case "stats":
return analyzeStats(text);
case "keywords":
return extractKeywords(text);
case "sentiment":
return analyzeSentiment(text);
default:
return fullAnalysis(text);
}
}
}
Agent与Skills之间的交互遵循明确的时序关系:
AgentContext在执行过程中传递和存储数据:
package com.example.agent;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* Agent执行上下文
* 用于在Agent执行过程中传递和存储数据
* @version 1.0.0
*/
public class AgentContext {
private final String requestId;
private final Map<String, Object> attributes;
private final Map<String, Object> sessionData;
private final long createdAt;
public AgentContext(String requestId) {
this.requestId = requestId;
this.attributes = new ConcurrentHashMap<>();
this.sessionData = new ConcurrentHashMap<>();
this.createdAt = System.currentTimeMillis();
}
/**
* 获取请求ID
*/
public String getRequestId() {
return requestId;
}
/**
* 设置属性
*/
public void setAttribute(String key, Object value) {
attributes.put(key, value);
}
/**
* 批量设置属性
*/
public void setAttributes(Map<String, Object> attributes) {
if (attributes != null) {
this.attributes.putAll(attributes);
}
}
/**
* 获取属性
*/
public Object getAttribute(String key) {
return attributes.get(key);
}
/**
* 获取属性(带类型转换)
*/
@SuppressWarnings("unchecked")
public <T> T getAttribute(String key, Class<T> type) {
Object value = attributes.get(key);
if (value != null && type.isInstance(value)) {
return (T) value;
}
return null;
}
/**
* 移除属性
*/
public Object removeAttribute(String key) {
return attributes.remove(key);
}
/**
* 设置会话数据
*/
public void setSessionData(String key, Object value) {
sessionData.put(key, value);
}
/**
* 获取会话数据
*/
public Object getSessionData(String key) {
return sessionData.get(key);
}
/**
* 获取所有属性
*/
public Map<String, Object> getAllAttributes() {
return new HashMap<>(attributes);
}
/**
* 清空属性
*/
public void clear() {
attributes.clear();
}
/**
* 获取上下文创建时间
*/
public long getCreatedAt() {
return createdAt;
}
/**
* 获取上下文存活时间(毫秒)
*/
public long getAge() {
return System.currentTimeMillis() - createdAt;
}
/**
* 创建新的上下文
*/
public static AgentContext create() {
return create(generateRequestId());
}
/**
* 创建带请求ID的上下文
*/
public static AgentContext create(String requestId) {
return new AgentContext(requestId);
}
/**
* 生成请求ID
*/
private static String generateRequestId() {
return "req-" + System.currentTimeMillis() + "-" + Thread.currentThread().getId();
}
@Override
public String toString() {
return "AgentContext{" +
"requestId='" + requestId + ''' +
", attributes=" + attributes.size() +
", sessionData=" + sessionData.size() +
", age=" + getAge() + "ms" +
'}';
}
}
上下文分为临时属性和会话数据,临时属性在单次请求中有效,会话数据可以跨请求共享。
在复杂系统中,多个Agent协同工作可以完成更复杂的任务:
public class MessageBus {
private final Map<String, List<Agent>> subscribers;
public void publish(String topic, Message message) {
List<Agent> agents = subscribers.get(topic);
for (Agent agent : agents) {
executor.submit(() ->
agent.execute(message.getContent(), message.getContext())
);
}
}
}
我们以一个智能数据分析系统为例,展示Agent Skills的实际应用:
系统包含以下关键组件:
package com.example.demo;
import com.example.agent.Agent;
import com.example.agent.AgentContext;
import com.example.agent.BaseAgent;
import com.example.skills.SkillResult;
import com.example.skills.impl.DataQuerySkill;
import com.example.skills.impl.FileReadSkill;
import com.example.skills.impl.TextAnalysisSkill;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.HashMap;
import java.util.Map;
/**
* 数据分析Agent
* 专门处理数据分析相关任务
* @version 1.0.0
*/
public class DataAnalysisAgent extends BaseAgent {
private static final Logger logger = LoggerFactory.getLogger(DataAnalysisAgent.class);
public DataAnalysisAgent() {
super("DataAnalysisAgent", "数据分析智能体,提供数据查询、分析和可视化能力");
// 注册技能
registerSkill(new DataQuerySkill());
registerSkill(new TextAnalysisSkill());
registerSkill(new FileReadSkill());
}
/**
* 执行数据分析任务
*/
public Agent.AgentResult analyzeData(String query, AgentContext context) {
logger.info("[DataAnalysisAgent] Starting data analysis: {}", query);
// 设置分析参数
Map<String, Object> parameters = new HashMap<>();
parameters.put("tableName", "users");
parameters.put("condition", query);
parameters.put("limit", 100);
context.setAttributes(parameters);
return execute("查询用户数据: " + query, context);
}
/**
* 生成数据分析报告
*/
public Agent.AgentResult generateReport(String filePath, AgentContext context) {
logger.info("[DataAnalysisAgent] Generating report from file: {}", filePath);
Map<String, Object> parameters = new HashMap<>();
parameters.put("filePath", filePath);
context.setAttributes(parameters);
AgentResult fileResult = execute("读取数据文件", context);
if (fileResult.isSuccess()) {
String content = fileResult.getData().toString();
// 分析文本内容
Map<String, Object> analysisParams = new HashMap<>();
analysisParams.put("text", content);
analysisParams.put("operation", "analyze");
context.setAttributes(analysisParams);
return execute("分析文本内容", context);
}
return fileResult;
}
@Override
protected void preprocess(String task, AgentContext context) {
super.preprocess(task, context);
context.setAttribute("agentType", "data-analysis");
context.setAttribute("timestamp", System.currentTimeMillis());
}
@Override
protected void postprocess(String task, SkillResult result, AgentContext context) {
super.postprocess(task, result, context);
// 记录分析结果
if (result.isSuccess()) {
context.setSessionData("lastAnalysis", result.getData());
context.setSessionData("lastAnalysisTime", System.currentTimeMillis());
}
}
}
public class Demo {
public static void main(String[] args) {
// 创建Agent
DataAnalysisAgent agent = new DataAnalysisAgent();
// 执行查询
AgentContext context = AgentContext.create();
AgentResult result = agent.analyzeData("技术部", context);
if (result.isSuccess()) {
System.out.println("查询结果: " + result.getData());
}
}
}
生产环境需要考虑高可用、可扩展和监控:
关键设计要点:
public class BaseAgent {
protected ExecutorService executorService;
protected SkillResult executeSkill(Skill skill, String task,
Map<String, Object> parameters) {
Future<SkillResult> future = executorService.submit(
() -> skill.execute(task, parameters)
);
return future.get(skill.getTimeout(), TimeUnit.MILLISECONDS);
}
}
完善的错误处理机制:
try {
SkillResult result = executeSkill(skill, task, parameters);
if (result.isSuccess()) {
return AgentResult.success(result.getMessage(), result.getData());
} else {
// 记录错误日志
logger.error("Skill execution failed: {}", result.getError());
// 尝试备用技能
return executeFallbackSkill(task, context);
}
} catch (TimeoutException e) {
return AgentResult.failure("执行超时");
} catch (Exception e) {
return AgentResult.failure("执行异常: " + e.getMessage());
}
@DisplayName("TextAnalysisSkill测试")
class TextAnalysisSkillTest {
@Test
@DisplayName("测试情感分析")
void testSentimentAnalysis() {
TextAnalysisSkill skill = new TextAnalysisSkill();
Map<String, Object> parameters = new HashMap<>();
parameters.put("text", "今天心情非常好!");
parameters.put("operation", "sentiment");
SkillResult result = skill.execute("情感分析", parameters);
assertTrue(result.isSuccess());
assertNotNull(result.getData());
}
}
测试Agent与Skills的协作:
@Test
@DisplayName("测试Agent完整流程")
void testAgentWorkflow() {
DataAnalysisAgent agent = new DataAnalysisAgent();
AgentContext context = AgentContext.create();
AgentResult result = agent.analyzeData("技术部", context);
assertTrue(result.isSuccess());
assertNotNull(result.getData());
}
Agent Skills工作流为我们提供了一种优雅的架构模式,将AI智能体与传统软件开发有机结合。
未来,随着AI技术的发展,Agent Skills将在更多领域发挥重要作用。