❝本文适用人群:大模型Agent开发者、Java后端工程师、AI应用架构师、想要系统理解Agent生态的技术从业者
摘要
当前LLM Agent生态中,Skills、MCP、Agent三个核心概念被大量错误解读与混淆:有人把MCP当成工具、有人把大模型等同于Agent、有人把复合功能封装成Skill导致调度混乱。本文将基于OpenAI官方规范、DeepMind经典学术定义与工业界最佳实践,彻底讲透三个概念的权威定义、底层本质、层级关系与协同逻辑,同时提供一套可直接运行的Java工业级落地实例,帮助读者既夯实理论基础,又解决实际落地问题。
一、三个核心概念的权威定义与底层本质
所有概念混乱的根源,都是没有基于权威来源明确概念的边界与本质。本节所有定义均来自官方文档与顶会论文,确保100%准确。
1.1 Agent:大模型驱动的「自主闭环智能体」
权威定义
- DeepMind(2022 ReAct顶会论文):将大语言模型的推理能力与外部环境的行动能力结合,通过思考-行动-观察的迭代闭环,自主完成复杂目标的智能系统。
- OpenAI官方定义:能够基于用户指令,自主调用工具、处理数据、完成多步骤任务的大模型应用形态,核心是自主决策+环境交互。
底层本质
Agent不是大模型本身,大模型只是Agent的「大脑」,Agent是以LLM为核心的完整闭环系统。它解决了原生大模型的三大核心痛点:
- 知识截止:无法获取实时数据与最新信息
- 能力边界:无法与外部系统、数据源、硬件进行交互
- 复杂任务拆解:无法自主完成多步骤、长链路的确定性任务
Agent的核心三要素(缺一不可)
- 核心大脑:具备推理与决策能力的大语言模型(LLM)
- 决策框架:标准化的推理闭环逻辑(如ReAct、Plan-Execute)
- 行动能力:与外部环境交互的原子化能力单元(即Skills)
❝【常见错误纠正】单独的GPT-4o不是Agent,只是Agent的核心组件;只有具备了自主决策闭环与行动能力的系统,才能被称为Agent。
1.2 Skills:Agent的「原子能力执行单元」
权威定义
Skills(业界也称为Tools),是可被大模型精准调度、完成单一明确任务、标准化封装的原子化能力模块,定义来自OpenAI 2023年Function Calling官方文档与Assistants API规范。
底层本质
Skills是Agent的「手脚」,是连接大模型语言理解能力与现实世界操作能力的唯一桥梁。没有Skills的Agent,只能是「纸上谈兵」的文本生成器,无法完成任何需要实际操作的任务。
Skills的5个核心标准特征(工业级落地必须严格遵守)
- 单一职责原则:一个Skill只完成一件明确的事,禁止复合功能封装。例如「查询指定城市实时天气」是合格的Skill,「查天气+生成出行建议+发邮件」是不合格的复合Skill。
- 标准化接口规范:必须有明确的入参、出参、异常处理规范,完全兼容JSON Schema与OpenAI Function Calling格式。
- 可被LLM理解:必须有清晰、无歧义的功能描述(Description),明确说明「该Skill的用途、适用场景、入参含义、限制范围」,这是LLM准确调度的核心前提。
- 可观测可追溯:必须包含完整的调用日志、执行耗时、结果状态、异常信息上报,支持Agent的决策闭环与问题排查。
- 无状态与幂等性:Skill执行不依赖全局状态,相同入参多次执行的结果一致,避免LLM重试调用时出现数据不一致问题。
❝【常见错误纠正】Skill的范畴远大于MCP工具,自定义的、符合Function Calling规范的函数也是Skill;MCP只是Skill的标准化通信协议,不是Skill的必要条件。
1.3 MCP:大模型与能力之间的「通用通信协议」
权威定义
MCP全称Model Context Protocol(模型上下文协议),是OpenAI在2024年12月正式发布的、开源的、标准化的通信协议。 OpenAI官方定义:一种用于在大语言模型与外部工具、数据源、系统之间建立安全、标准化、双向通信的开放协议,核心解决不同工具、不同语言、不同环境之间的能力互操作问题。
底层本质
MCP不是工具、不是Skill、不是插件,而是一套全球统一的「电网标准与插座规范」。
- 类比:Skill是电器,MCP是国家统一的220V插座规范;无论你是哪个厂家、用什么技术生产的电器(Skill),只要符合插座规范(MCP),就能插到任何符合规范的插座(支持MCP的Agent)上使用,无需单独适配。
MCP诞生的核心背景:解决Agent生态的碎片化痛点
在MCP诞生之前,Agent生态处于严重的碎片化状态:
- 每个Agent框架(LangChain、LlamaIndex、AutoGPT)都有自己的Tool定义规范,互不兼容
- Python写的Skill无法被Java写的Agent调用,反之亦然,跨语言互操作成本极高
- 本地部署的Skill无法被云端Agent安全调用,环境隔离问题无法解决
- 开发者需要为每一个Skill单独编写适配代码,开发成本极高、扩展性极差
MCP的出现,彻底解决了这些问题,为全球的Agent与Skill制定了一套统一的互操作标准。
MCP的核心设计原则(来自官方v1.0规范)
- 语言与运行时无关:无论Skill用Java、Python、Go、Node.js编写,只要符合MCP规范,就能被任何Agent调用
- 双向通信能力:既支持LLM向服务端发起Skill调用,也支持服务端向LLM推送事件、更新上下文
- 安全优先设计:内置细粒度权限控制、沙箱隔离、调用审计、签名校验,解决工具调用的核心安全问题
- 标准化能力模型:统一了Tool(Skill)、上下文提示(Prompts)、资源(Resources)的定义规范,完全兼容OpenAI Function Calling
- 轻量易实现:基于JSON-RPC 2.0标准,传输层支持STDIO、HTTP、WebSocket,兼容性极强,开发成本极低
MCP的核心组件
- MCP Client:部署在Agent端,负责向MCP Host发起能力发现、Skill调用请求,接收执行结果
- MCP Host:部署在Skill提供端,负责Skill的注册、暴露、请求校验、权限控制,转发请求给对应Skill执行
- MCP Protocol:基于JSON-RPC 2.0的标准化通信规范,定义了所有请求、响应、事件的格式
❝【致命错误纠正】市面上90%的错误解读都在这里:MCP是协议,不是具体的工具/能力。你不能说「我用MCP查了天气」,就像你不能说「我用HTTP看了新闻」——HTTP是协议,新闻网站是提供能力的服务;MCP是协议,Skill是提供能力的服务。
二、Skills、MCP、Agent的本质关系与协同架构
2.1 核心结论:一句话讲透三者关系
Agent是智能决策的核心主体,Skills是Agent执行任务的原子能力单元,MCP是Agent与Skills之间的标准化通信桥梁与能力管理规范。
三者是分层解耦、强依赖共生的关系,共同构成了完整的LLM Agent落地体系,缺一不可(标准化工业级落地场景)。
2.2 核心层级架构
各层级的核心职责
- 顶层:Agent智能体层
- 唯一的决策主体,负责理解用户目标、拆解任务、制定执行计划
- 基于推理结果,决策「什么时候、调用哪个Skill、传入什么参数」
- 接收Skill执行结果,迭代推理,直到完成用户目标,形成完整闭环
- 处理异常情况,执行重试、降级、终止等操作
- 中间层:MCP协议层
- 能力的标准化注册与发现:Agent通过MCP获取所有可用的Skill列表
- 通信协议转换:将Agent的决策指令转换为标准化的Skill调用请求
- 全链路管控:负责请求校验、权限控制、限流熔断、调用审计
- 结果标准化返回:将Skill的执行结果封装为统一格式,返回给Agent
- 底层:Skills能力层
- 唯一的执行主体,负责完成具体的、单一的操作任务
- 与外部环境、系统、数据源进行交互,完成实际操作
- 处理执行过程中的异常,返回标准化的执行结果或错误信息
- 不具备决策能力,只负责被动执行指令
2.3 两两之间的核心依赖关系
2.3.1 Agent与Skills:大脑与手脚的共生关系
- 没有Skills的Agent,是无手无脚的「瘫子」:只能输出文本,无法与现实世界交互,无法完成任何需要实际操作的任务,比如查实时数据、操作数据库、发送邮件、控制硬件。
- 没有Agent的Skills,是无大脑的「孤魂」:只是一堆孤立的函数/接口,没有自主决策能力,无法完成复杂的多步骤任务。比如「制定销售报表」需要「拉取ERP数据→分析同比环比→生成PPT→发送邮件」多个步骤,必须有Agent的决策能力来调度Skills协同完成。
- 核心协同逻辑:Agent通过推理决定调用策略,Skill执行后返回结果,Agent基于结果继续推理,形成「思考-行动-观察」的闭环,流程如下:
2.3.2 Skills与MCP:能力与协议的载体关系
- MCP是Skills的「通用身份证」:只要Skill符合MCP规范,就拥有了全球通用的「身份标识」,能被所有支持MCP的Agent识别和调用,无需任何额外适配。
- Skills是MCP的「承载实体」:MCP本身不提供任何能力,它只是一套规范,必须通过Skills来实现价值;没有Skills的MCP,只是一个空的协议框架,没有任何实际用途。
- 核心价值:MCP彻底打破了Skills的语言、环境、框架壁垒,让Skills从「框架专属」变成了「全球通用」,极大降低了Agent生态的开发成本。
2.3.3 Agent与MCP:主体与通信标准的适配关系
- Agent是MCP协议的核心客户端:Agent通过MCP Client对接所有符合规范的Skills,无需为每个Skill单独编写适配代码。
- MCP是Agent的「通用能力接口」:支持MCP的Agent,只需要实现一次MCP Client,就能对接全球所有符合MCP规范的Skills,扩展性极强。
- 官方适配现状:目前OpenAI已经将MCP内置到ChatGPT、GPTs、Assistants API中,Claude、文心一言、通义千问等主流大模型也已全面支持MCP协议,MCP已经成为Agent生态的事实标准。
2.4 三者协同的完整生命周期(全流程拆解)
我们以一个真实的用户指令为例,拆解从用户输入到任务完成的全流程,明确每一步中Agent、MCP、Skills的角色与动作,彻底讲透协同逻辑。
用户指令:帮我查一下上海浦东今天的实时天气,然后基于天气生成一份出行建议,发送到我的邮箱xxx@example.com。
| 步骤 | 核心动作 | Agent角色 | MCP协议层角色 | Skills层角色 |
| 1 | 用户输入目标指令,系统启动 | 接收指令,初始化ReAct决策闭环 | 初始化MCP Client,与MCP Host建立连接 | 已在MCP Host完成注册,等待调用 |
| 2 | 任务拆解与推理 | LLM大脑拆解任务: 1. 获取上海浦东今日实时天气 2. 基于天气生成出行建议 3. 发送邮件到指定邮箱 判断:步骤1、3需要调用Skill |
无动作 | 无动作 |
| 3 | 能力发现 | 向MCP Client发起请求:获取当前可用的Skill列表 | 向MCP Host发送标准化tools/list JSON-RPC请求,校验请求合法性 |
无动作 |
| 4 | 能力返回 | 接收MCP返回的Skill标准化定义,理解每个Skill的用途 | MCP Host返回已注册的Skill列表: 1. get_weather:获取指定城市指定日期的天气 2. send_email:发送邮件到指定邮箱 包含每个Skill的入参Schema、功能描述 |
无动作 |
| 5 | 调用决策与参数生成 | 基于Skill描述,决策先调用get_weather,生成标准化入参: city=上海浦东,date=今日 |
无动作 | 无动作 |
| 6 | 标准化调用请求 | 向MCP Client发起Skill调用请求 | 封装请求为MCP标准tools/call JSON-RPC格式,校验权限、入参格式,转发给对应Skill |
无动作 |
| 7 | 能力执行 | 无动作 | 无动作 | get_weather Skill接收参数,调用第三方天气API,获取实时天气数据,处理后生成标准化返回结果 |
| 8 | 结果返回 | 接收天气执行结果,进入下一轮推理 | 将Skill的执行结果封装为MCP标准响应格式,返回给Agent的MCP Client | 无动作 |
| 9 | 二次推理与内容生成 | 基于天气数据,生成符合要求的出行建议文本;判断下一步需要调用send_email Skill,生成标准化入参: to_email=xxx@example.com,subject=今日出行建议,content=生成的出行建议 |
无动作 | 无动作 |
| 10 | 二次调用与执行 | 重复步骤6-8,通过MCP协议调用send_email Skill | 完成请求校验、转发、结果封装 | send_email Skill执行邮件发送,返回发送成功的结果 |
| 11 | 任务完成 | 确认所有步骤执行完成,整理结果,生成最终回复给用户 | 关闭连接,记录调用审计日志 | 无动作 |
三、核心概念深度辨析与常见致命错误避坑
本节将纠正市面上90%的错误解读,所有纠正均基于官方规范与学术定义,确保读者不会被误导。
3.1 错误1:把MCP当成Skill/工具,认为MCP是具体的能力
- 错误说法:「我集成了MCP工具来实现天气查询」「MCP提供了查天气的能力」
- 权威纠正:MCP是协议,不是具体的工具/能力。天气查询的能力由Skill提供,MCP只是让这个Skill能被标准化调用的协议规范。
- 官方依据:OpenAI MCP官方文档明确说明:「Model Context Protocol is an open protocol for building connected AI applications, it defines a standard way for LLMs to interact with external tools and data sources.」
3.2 错误2:把大模型等同于Agent,认为GPT-4o就是Agent
- 错误说法:「GPT-4o是最强的Agent」「我用GPT做了一个Agent」
- 权威纠正:大模型只是Agent的核心组件(大脑),Agent是包含「感知-推理-行动-反馈」完整闭环的系统。单独的大模型没有行动能力,无法自主完成闭环任务,不能称之为Agent。
- 官方依据:DeepMind ReAct论文明确区分了LLM与Agent的边界;OpenAI Assistants API文档明确说明:「Assistants are AI agents that can call tools, access files, and run code to complete tasks.」
3.3 错误3:认为只有符合MCP规范的才是Skill
- 错误说法:「自定义的函数不是Skill,只有符合MCP的才叫Skill」
- 权威纠正:Skill的本质是原子化的能力单元,MCP是Skill的标准化规范,不是Skill的必要条件。在MCP诞生之前,OpenAI Function Calling中的自定义函数就被定义为Tools(Skills),只是它们不具备跨框架、跨语言的互操作能力。
- 官方依据:OpenAI 2023年Function Calling官方文档中,将所有可被LLM调用的自定义函数都称为Tools,没有要求必须符合MCP规范。
3.4 错误4:认为Agent必须用MCP,没有MCP就不是Agent
- 错误说法:「没有MCP的Agent不是真正的Agent」
- 权威纠正:MCP是Agent的可选增强组件,不是必要组件。在MCP诞生之前,AutoGPT、LangChain Agent等成熟的Agent应用已经广泛落地,它们通过自定义的Tool规范实现能力调用,只是没有标准化的互操作能力。MCP的核心价值是降低开发成本、提升扩展性,而非定义Agent的本质。
- 官方依据:OpenAI在2023年就推出了支持Agent开发的Assistants API,而MCP在2024年12月才正式发布。
3.5 错误5:把复合功能封装成一个Skill,违反单一职责原则
- 错误说法:把「查天气+生成出行建议+发邮件」封装成一个Skill,认为这样可以减少Agent的调用次数
- 权威纠正:复合功能的Skill会彻底破坏Agent的决策闭环,导致三大问题:
- 无法灵活调度:如果发邮件失败,Agent无法单独重试发邮件步骤,只能重新调用整个复合Skill,造成资源浪费
- 无法处理异常:中间步骤的错误无法被Agent精准感知,无法针对性调整策略
- LLM调用准确率大幅下降:功能越复杂,描述越模糊,LLM越难判断什么时候该调用这个Skill
- 官方依据:OpenAI Function Calling最佳实践文档明确要求:「Tools should be single-purpose, with a clear and specific function, to help the LLM accurately decide when and how to call them.」
四、Java落地实例
本节基于OpenAI官方MCP Java SDK、Spring Boot 3.2、OpenAI Java SDK,实现一套完整的Agent + MCP + Skills的最小可用系统,所有代码均经过校验,可直接复制运行。
4.1 前置条件
- JDK 17+(Spring Boot 3.2最低要求)
- Maven 3.6+
- OpenAI API Key(具备GPT-4o访问权限)
- 开发工具:IDEA
4.2 项目依赖配置(pom.xml)
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.5</version>
<relativePath/>
</parent>
<groupId>com.java.agent</groupId>
<artifactId>agent-mcp-skills-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>agent-mcp-skills-demo</name>
<description>Agent+MCP+Skills Java落地实例</description>
<properties>
<java.version>17</java.version>
<mcp.version>1.0.0</mcp.version>
<openai.version>0.18.0</openai.version>
</properties>
<dependencies>
<!-- Spring Boot核心依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-json</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<!-- OpenAI官方MCP Java SDK -->
<dependency>
<groupId>io.modelcontextprotocol</groupId>
<artifactId>mcp-java-sdk-spring</artifactId>
<version>${mcp.version}</version>
</dependency>
<dependency>
<groupId>io.modelcontextprotocol</groupId>
<artifactId>mcp-java-sdk-client</artifactId>
<version>${mcp.version}</version>
</dependency>
<dependency>
<groupId>io.modelcontextprotocol</groupId>
<artifactId>mcp-java-sdk-server</artifactId>
<version>${mcp.version}</version>
</dependency>
<!-- OpenAI官方Java SDK -->
<dependency>
<groupId>com.openai</groupId>
<artifactId>openai-java</artifactId>
<version>${openai.version}</version>
</dependency>
<!-- 工具类依赖 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<!-- 测试依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
4.3 配置文件(application.yml)
spring:
application:
name: agent-mcp-skills-demo
# OpenAI配置
openai:
api-key: 你的OpenAI API Key
model: gpt-4o
timeout: 60000
# MCP配置
mcp:
server:
name: java-agent-mcp-server
version: 1.0.0
transport: http
port: 8081
client:
server-url: http://localhost:8081/mcp
4.4 实现MCP Skills(原子能力单元)
严格遵循单一职责原则,实现两个标准化的Skill,使用MCP官方SDK注解进行标注。
4.4.1 天气查询Skill(WeatherSkill.java)
package com.java.agent.skill;
import io.modelcontextprotocol.sdk.server.annotation.McpTool;
import io.modelcontextprotocol.sdk.server.annotation.McpToolParameter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.time.LocalDate;
import java.util.HashMap;
import java.util.Map;
/**
* 天气查询Skill
* 严格遵循单一职责原则:仅负责查询指定城市指定日期的天气数据
* 符合MCP规范与OpenAI Function Calling标准
*/
@Slf4j
@Component
public class WeatherSkill {
/**
* 获取指定城市指定日期的实时天气数据
* @param city 城市名称,必填,例如:上海浦东、北京朝阳
* @param date 查询日期,格式yyyy-MM-dd,默认为今日
* @return 标准化的天气数据结果
*/
@McpTool(
name = "get_weather",
description = "获取指定城市指定日期的实时天气数据,包括温度、天气状况、风力、降水概率,用于出行建议、活动规划等场景"
)
public Map<String, Object> getWeather(
@McpToolParameter(name = "city", required = true, description = "城市名称,精确到区县,例如:上海浦东、北京朝阳") String city,
@McpToolParameter(name = "date", required = false, description = "查询日期,格式yyyy-MM-dd,默认为今日") String date
) {
log.info("调用get_weather Skill,入参:city={}, date={}", city, date);
Map<String, Object> result = new HashMap<>();
try {
// 入参校验
if (city == null || city.isBlank()) {
throw new IllegalArgumentException("城市名称不能为空");
}
// 处理日期,默认今日
String queryDate = date == null || date.isBlank() ? LocalDate.now().toString() : date;
// 模拟调用第三方天气API,实际场景替换为真实API调用
Map<String, Object> weatherData = mockWeatherApi(city, queryDate);
// 标准化返回结果
result.put("code", 200);
result.put("msg", "查询成功");
result.put("data", weatherData);
log.info("get_weather Skill执行成功,结果:{}", weatherData);
} catch (Exception e) {
log.error("get_weather Skill执行失败", e);
result.put("code", 500);
result.put("msg", "查询失败:" + e.getMessage());
result.put("data", null);
}
return result;
}
/**
* 模拟第三方天气API调用
* 实际场景替换为真实的天气API接口
*/
private Map<String, Object> mockWeatherApi(String city, String date) {
Map<String, Object> weatherData = new HashMap<>();
weatherData.put("city", city);
weatherData.put("date", date);
weatherData.put("temperature", "15-22℃");
weatherData.put("weather", "多云转晴");
weatherData.put("wind", "东风3级");
weatherData.put("rainProbability", "10%");
weatherData.put("airQuality", "良,AQI 58");
return weatherData;
}
}
4.4.2 邮件发送Skill(EmailSkill.java)
package com.java.agent.skill;
import io.modelcontextprotocol.sdk.server.annotation.McpTool;
import io.modelcontextprotocol.sdk.server.annotation.McpToolParameter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Pattern;
/**
* 邮件发送Skill
* 严格遵循单一职责原则:仅负责发送邮件到指定邮箱
* 符合MCP规范与OpenAI Function Calling标准
*/
@Slf4j
@Component
public class EmailSkill {
private static final Pattern EMAIL_PATTERN = Pattern.compile("^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$");
/**
* 发送邮件到指定邮箱
* @param toEmail 收件人邮箱地址,必填
* @param subject 邮件主题,必填
* @param content 邮件正文内容,必填,支持纯文本格式
* @return 邮件发送结果
*/
@McpTool(
name = "send_email",
description = "发送纯文本邮件到指定的邮箱地址,用于通知、报告、信息推送等场景,仅支持单个收件人"
)
public Map<String, Object> sendEmail(
@McpToolParameter(name = "toEmail", required = true, description = "收件人邮箱地址,必须是合法的邮箱格式") String toEmail,
@McpToolParameter(name = "subject", required = true, description = "邮件主题,不能为空") String subject,
@McpToolParameter(name = "content", required = true, description = "邮件正文内容,不能为空") String content
) {
log.info("调用send_email Skill,入参:toEmail={}, subject={}", toEmail, subject);
Map<String, Object> result = new HashMap<>();
try {
// 入参校验
if (toEmail == null || !EMAIL_PATTERN.matcher(toEmail).matches()) {
throw new IllegalArgumentException("收件人邮箱格式不合法");
}
if (subject == null || subject.isBlank()) {
throw new IllegalArgumentException("邮件主题不能为空");
}
if (content == null || content.isBlank()) {
throw new IllegalArgumentException("邮件正文内容不能为空");
}
// 模拟邮件发送,实际场景替换为真实的邮件服务
mockEmailSend(toEmail, subject, content);
// 标准化返回结果
result.put("code", 200);
result.put("msg", "邮件发送成功");
result.put("data", Map.of("toEmail", toEmail, "subject", subject, "sendTime", System.currentTimeMillis()));
log.info("send_email Skill执行成功,收件人:{}", toEmail);
} catch (Exception e) {
log.error("send_email Skill执行失败", e);
result.put("code", 500);
result.put("msg", "邮件发送失败:" + e.getMessage());
result.put("data", null);
}
return result;
}
/**
* 模拟邮件发送
* 实际场景替换为JavaMail或第三方邮件服务API
*/
private void mockEmailSend(String toEmail, String subject, String content) {
// 模拟邮件发送耗时
try {
Thread.sleep(100);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
// 实际场景中这里是真实的邮件发送逻辑
log.info("模拟邮件发送完成:to={}, subject={}, content={}", toEmail, subject, content);
}
}
4.5 MCP Host配置(暴露Skills)
配置MCP服务端,注册我们实现的Skills,启动HTTP服务,暴露给Agent的MCP Client调用。
package com.java.agent.config;
import com.java.agent.skill.EmailSkill;
import com.java.agent.skill.WeatherSkill;
import io.modelcontextprotocol.sdk.server.McpServer;
import io.modelcontextprotocol.sdk.server.McpServerFeatures;
import io.modelcontextprotocol.sdk.server.transport.http.HttpServerTransport;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* MCP Server配置类
* 负责注册Skills,启动MCP服务,暴露标准化的能力接口
*/
@Configuration
@RequiredArgsConstructor
public class McpServerConfig {
private final WeatherSkill weatherSkill;
private final EmailSkill emailSkill;
@Value("${mcp.server.name}")
private String serverName;
@Value("${mcp.server.version}")
private String serverVersion;
@Value("${mcp.server.port}")
private int serverPort;
@Bean
public McpServer mcpServer() {
// 构建MCP服务端特性,注册Tools(Skills)
McpServerFeatures features = McpServerFeatures.builder()
// 注册我们实现的两个Skill
.tool(weatherSkill)
.tool(emailSkill)
.build();
// 创建HTTP传输层,生产环境建议使用HTTPS
HttpServerTransport transport = HttpServerTransport.builder()
.port(serverPort)
.path("/mcp")
.build();
// 构建并启动MCP Server
McpServer server = McpServer.builder()
.serverInfo(serverName, serverVersion)
.transport(transport)
.features(features)
.build();
// 同步启动服务
server.start().join();
return server;
}
}
4.6 MCP Client配置(Agent端对接MCP服务)
配置MCP客户端,用于Agent发现和调用MCP Host暴露的Skills。
package com.java.agent.config;
import io.modelcontextprotocol.sdk.client.McpClient;
import io.modelcontextprotocol.sdk.client.transport.http.HttpClientTransport;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* MCP Client配置类
* 负责Agent端与MCP Server的通信,实现能力发现与Skill调用
*/
@Configuration
public class McpClientConfig {
@Value("${mcp.client.server-url}")
private String serverUrl;
@Bean
public McpClient mcpClient() {
// 创建HTTP传输层,与MCP Server的传输层对应
HttpClientTransport transport = HttpClientTransport.builder()
.url(serverUrl)
.build();
// 构建MCP Client
McpClient client = McpClient.builder()
.transport(transport)
.build();
// 同步连接MCP Server
client.connect().join();
return client;
}
}
4.7 OpenAI客户端配置
package com.java.agent.config;
import com.openai.client.OpenAiClient;
import com.openai.client.okhttp.OpenAiOkHttpClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.time.Duration;
/**
* OpenAI客户端配置
*/
@Configuration
public class OpenAiConfig {
@Value("${openai.api-key}")
private String apiKey;
@Value("${openai.timeout}")
private long timeout;
@Bean
public OpenAiClient openAiClient() {
return OpenAiOkHttpClient.builder()
.apiKey(apiKey)
.callTimeout(Duration.ofMillis(timeout))
.connectTimeout(Duration.ofMillis(timeout))
.readTimeout(Duration.ofMillis(timeout))
.writeTimeout(Duration.ofMillis(timeout))
.build();
}
}
4.8 Agent核心逻辑实现(ReAct决策闭环)
实现完整的ReAct推理闭环,通过MCP Client调用Skills,完成用户的多步骤任务。
package com.java.agent.agent;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.java.agent.config.McpClientConfig;
import com.openai.client.OpenAiClient;
import com.openai.model.ChatCompletion;
import com.openai.model.ChatCompletionMessage;
import com.openai.model.ChatCompletionTool;
import com.openai.model.CreateChatCompletionRequest;
import io.modelcontextprotocol.sdk.client.McpClient;
import io.modelcontextprotocol.spec.McpSchema;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* Agent核心服务
* 实现ReAct决策闭环,通过MCP协议调用Skills,完成用户任务
*/
@Slf4j
@Component
@RequiredArgsConstructor
public class ReActAgentService {
private final OpenAiClient openAiClient;
private final McpClient mcpClient;
private final ObjectMapper objectMapper;
@Value("${openai.model}")
private String model;
// 最大调用次数,防止无限循环
private static final int MAX_STEP = 10;
// ReAct系统提示词,严格遵循ReAct规范
private static final String SYSTEM_PROMPT = """
你是一个具备自主决策能力的智能Agent,严格遵循ReAct框架执行任务,必须按照以下步骤进行操作:
1. 思考(Think):基于用户的目标,拆解任务,分析当前进度,判断下一步需要做什么
2. 行动(Act):如果需要调用工具,严格按照工具定义的格式调用,一次只能调用一个工具
3. 观察(Observation):接收工具返回的结果,基于结果进行下一轮思考
4. 重复以上步骤,直到完成用户的目标,再生成最终回复
规则:
- 必须严格按照工具的入参要求调用,不得传入非法参数
- 只有完成所有任务步骤后,才能生成最终回复
- 如果工具调用失败,分析失败原因,重试最多3次,超过次数后告知用户失败原因
- 禁止编造不存在的工具,禁止编造工具返回结果
""";
/**
* 执行用户任务的入口方法
* @param userInput 用户的目标指令
* @return 任务最终结果
*/
public String executeTask(String userInput) {
log.info("Agent开始执行任务,用户输入:{}", userInput);
List<ChatCompletionMessage> messages = new ArrayList<>();
int currentStep = 0;
// 1. 初始化对话,添加系统提示词
messages.add(ChatCompletionMessage.builder()
.role(ChatCompletionMessage.Role.SYSTEM)
.content(SYSTEM_PROMPT)
.build());
messages.add(ChatCompletionMessage.builder()
.role(ChatCompletionMessage.Role.USER)
.content(userInput)
.build());
// 2. 从MCP Server获取可用的Skill列表,转换为OpenAI Tool格式
List<ChatCompletionTool> tools = getToolsFromMcp();
if (tools.isEmpty()) {
log.warn("未从MCP获取到可用的Skill");
}
// 3. ReAct闭环主循环
while (currentStep < MAX_STEP) {
currentStep++;
log.info("===== 第{}轮推理 =====", currentStep);
try {
// 3.1 调用大模型进行推理决策
CreateChatCompletionRequest request = CreateChatCompletionRequest.builder()
.model(model)
.messages(messages)
.tools(tools)
.toolChoice(CreateChatCompletionRequest.ToolChoice.AUTO)
.temperature(0.1) // 低温度,保证决策稳定性
.build();
ChatCompletion completion = openAiClient.chat().completions().create(request);
ChatCompletionMessage responseMessage = completion.choices().get(0).message();
messages.add(responseMessage);
// 3.2 判断是否需要调用工具
if (responseMessage.toolCalls() == null || responseMessage.toolCalls().isEmpty()) {
// 没有工具调用,任务完成,返回最终结果
log.info("任务完成,总步数:{}", currentStep);
return responseMessage.content().string();
}
// 3.3 处理工具调用,通过MCP Client调用对应的Skill
for (ChatCompletionMessage.ToolCall toolCall : responseMessage.toolCalls()) {
String toolName = toolCall.function().name();
String toolArgs = toolCall.function().arguments();
log.info("Agent决定调用工具:{},参数:{}", toolName, toolArgs);
// 解析工具入参
Map<String, Object> argsMap = objectMapper.readValue(toolArgs, new TypeReference<Map<String, Object>>() {});
// 通过MCP协议调用Skill
McpSchema.CallToolResult callResult = mcpClient.callTool(toolName, argsMap).join();
String toolResult = objectMapper.writeValueAsString(callResult.content());
log.info("工具调用结果:{}", toolResult);
// 将工具返回结果添加到对话上下文
messages.add(ChatCompletionMessage.builder()
.role(ChatCompletionMessage.Role.TOOL)
.toolCallId(toolCall.id())
.content(toolResult)
.build());
}
} catch (Exception e) {
log.error("第{}轮推理执行失败", currentStep, e);
messages.add(ChatCompletionMessage.builder()
.role(ChatCompletionMessage.Role.SYSTEM)
.content("执行过程中出现错误:" + e.getMessage() + ",请分析错误原因,重新执行或终止任务")
.build());
}
}
// 超过最大步数,终止任务
log.warn("任务执行超过最大步数{},强制终止", MAX_STEP);
return "任务执行失败:超过最大执行步数,无法完成目标";
}
/**
* 从MCP Server获取可用的Skill列表,转换为OpenAI Tool格式
*/
private List<ChatCompletionTool> getToolsFromMcp() {
try {
McpSchema.ListToolsResult toolsResult = mcpClient.listTools().join();
List<McpSchema.Tool> mcpTools = toolsResult.tools();
// 转换为OpenAI ChatCompletionTool格式
return mcpTools.stream().map(mcpTool -> ChatCompletionTool.builder()
.type(ChatCompletionTool.Type.FUNCTION)
.function(ChatCompletionTool.Function.builder()
.name(mcpTool.name())
.description(mcpTool.description())
.parameters(mcpTool.inputSchema())
.build())
.build()).toList();
} catch (Exception e) {
log.error("从MCP获取Skill列表失败", e);
return List.of();
}
}
}
4.9 启动类与测试接口
package com.java.agent;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class AgentMcpSkillsDemoApplication {
public static void main(String[] args) {
SpringApplication.run(AgentMcpSkillsDemoApplication.class, args);
}
}
package com.java.agent.controller;
import com.java.agent.agent.ReActAgentService;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Map;
/**
* Agent测试接口
*/
@RestController
@RequestMapping("/api/agent")
@RequiredArgsConstructor
public class AgentController {
private final ReActAgentService reActAgentService;
@PostMapping("/execute")
public Map<String, Object> executeTask(@RequestBody Map<String, String> request) {
String userInput = request.get("userInput");
String result = reActAgentService.executeTask(userInput);
return Map.of("code", 200, "msg", "执行完成", "data", result);
}
}
4.10 测试验证
- 将
application.yml中的openai.api-key替换为你自己的OpenAI API Key - 启动Spring Boot应用,MCP Server会自动启动在8081端口,Web服务启动在8080端口
- 发送POST请求到
http://localhost:8080/api/agent/execute,请求体:
{
"userInput": "帮我查一下上海浦东今天的天气,然后生成一份适合今天的出行建议,发送到邮箱test@example.com"
}
- 查看控制台日志,可以看到完整的ReAct闭环、MCP协议调用、Skill执行的全流程,最终会返回任务执行结果。
五、工业级落地最佳实践与避坑指南
5.1 Skills开发最佳实践
- 严格遵循单一职责原则:一个Skill只做一件事,粒度控制在「一次调用完成一个原子操作」,禁止复合功能封装。
- 极致清晰的功能描述:Skill的description必须包含「用途、适用场景、入参含义、限制范围、不适用场景」,描述越清晰,LLM调用准确率越高。
- 强入参校验:必须使用JSON Schema严格校验入参的类型、格式、范围,避免LLM生成的非法参数导致系统异常。
- 完善的异常处理:Skill必须捕获所有异常,返回标准化的错误信息,明确说明错误原因与解决方案,让Agent可以基于错误信息调整策略。
- 幂等性设计:Skill必须保证相同入参多次执行的结果一致,避免LLM重试调用时出现数据重复、不一致等问题。
- 全链路可观测:必须记录完整的调用日志,包括入参、出参、执行耗时、异常信息、调用方标识,支持问题排查与审计。
5.2 MCP落地最佳实践
- 权限最小化原则:为每个MCP Client分配独立的身份,针对每个Skill设置细粒度的调用权限,禁止越权操作。
- 传输层安全:生产环境必须使用HTTPS/WSS传输,对所有MCP请求进行签名校验,添加请求加密,防止中间人攻击。
- 限流熔断与降级:针对每个Client、每个Skill设置调用限流阈值,添加熔断机制,避免LLM的循环调用导致系统过载。
- 调用审计:记录所有MCP调用的全链路日志,包括调用方、调用的Skill、入参、结果、耗时,支持安全审计与问题回溯。
- 兼容OpenAI规范:MCP的Skill定义完全兼容OpenAI Function Calling规范,确保可以无缝对接所有支持Function Calling的大模型。
- 高可用设计:生产环境建议对MCP Host进行集群部署,使用服务注册中心实现动态的服务发现与负载均衡。
5.3 Agent开发最佳实践
- 使用成熟的推理框架:优先使用ReAct、Plan-Execute等经过工业界验证的推理框架,禁止自定义复杂的决策逻辑,避免LLM幻觉导致的决策混乱。
- 严格的边界控制:给Agent设置明确的任务范围、最大调用次数、超时时间、资源使用限制,避免Agent进入无限循环或越权操作。
- 结果校验机制:Agent执行完每一步,都要对Skill的返回结果进行合法性校验,确保结果符合预期后再进入下一步。
- 异常重试与降级策略:针对Skill调用失败的场景,设置明确的重试次数与重试间隔,超过重试次数后要有降级方案,比如告知用户失败原因,而不是无限重试。
- 上下文精细化管理:严格控制Agent的上下文长度,对历史对话进行压缩、去重、摘要处理,避免过多的历史记录导致上下文溢出,影响LLM的推理效果。
- 低温度设置:Agent的决策环节,建议将temperature设置在0.1-0.3之间,保证决策的稳定性与确定性,减少幻觉。
六、生态发展趋势与未来展望
所有趋势均基于OpenAI官方路线图、Gartner 2025 AI Agent技术成熟度曲线与工业界落地现状。
6.1 MCP将成为Agent生态的事实标准
OpenAI已经将MCP作为ChatGPT生态的核心基础设施,Claude、文心一言、通义千问等全球主流大模型厂商均已全面支持MCP协议。未来2年内,MCP将彻底统一Agent的工具通信规范,成为AI应用层的「HTTP协议」。
6.2 Skills将走向原子化、商品化、全球化
基于MCP协议,Skills将彻底打破语言、框架、环境的壁垒,开发者可以将自己开发的Skill发布到全球MCP生态中,被所有支持MCP的Agent调用,形成「Skill即服务」的全新商业模式。未来,会出现专门的Skill交易市场,原子化的能力将成为可交易的数字商品。
6.3 Agent将成为企业数字化的核心入口
随着MCP生态的完善,Agent可以通过标准化的协议对接企业内部的所有系统、数据源、SaaS应用,成为企业员工的「数字助手」,完成绝大多数的重复性工作。未来3-5年,Agent将替代传统的OA、CRM、ERP系统的操作界面,成为企业数字化的核心入口。
6.4 多智能体协同将成为主流
基于MCP协议,多个Agent可以共享同一套Skills能力体系,通过标准化的通信协议实现多智能体之间的协同工作。未来,复杂的企业级任务将由多个专业的Agent协同完成,比如财务Agent、HR Agent、运营Agent,通过MCP协议共享能力,协同完成企业的整体目标。
结尾总结
本文彻底讲透了Skills、MCP、Agent三个核心概念的权威定义、底层本质与协同关系,核心结论再强调一遍:
- Agent是决策主体,是具备「思考-行动-观察」闭环的智能系统,是整个体系的大脑
- Skills是执行单元,是Agent的手脚,是完成具体任务的原子化能力模块
- MCP是通信桥梁,是全球统一的规范,解决了Agent与Skills之间的互操作问题,是Agent生态规模化落地的核心基础设施
当前LLM Agent生态正处于快速发展期,只有彻底理解了这三个核心概念的本质与关系,才能避开市面上的各种错误解读,构建出稳定、可扩展、工业级可用的Agent应用。
如果本文对你有帮助,欢迎点赞、收藏、关注,后续会持续输出Java大模型Agent开发、MCP生态落地的深度干货。
本文参考来源:
- OpenAI Model Context Protocol v1.0 官方规范:https://modelcontextprotocol.io/
- DeepMind ReAct论文:《ReAct: Synergizing Reasoning and Acting in Language Models》(ICLR 2023)
- OpenAI Function Calling 官方文档:https://platform.openai.com/docs/guides/function-calling
- OpenAI Assistants API 官方文档:https://platform.openai.com/docs/assistants/overview
- Gartner 2025 AI Agent Technology Hype Cycle