easy-agent
Java 应用打造的 Agent 开发组件
项目简介
Easy Agent 是一个面向 Java 应用的智能体(Agent)开发组件,深度拥抱 Spring 生态,旨在让基于 Spring Boot 的应用快速暴露业务工具、接入大模型、提供 MCP 工具服务,并使用本地文档做基础 RAG 检索。开发者引入 Starter 后,可以通过配置开关启用注解式工具注册、MCP HTTP 接口、Skill 文件生成、RAG 检索和 OpenAI 兼容 LLM 客户端。
核心理念
- 零侵入:通过
@EasyTool注解自动发现和注册工具,无需修改业务代码结构 - 即插即用:引入 Starter 依赖即可自动装配,通过配置开关控制各模块
- 灵活组合:未配置 LLM 时也可以仅提供 MCP 工具调用能力
- 领域友好:Skill 生成器通过对话式引导,生成你的专属业务 Skill Markdown 文件
技术栈
| 类别 | 技术 | 版本 |
|---|---|---|
| 基础框架 | Spring Boot | 3.5+ |
| AI 框架 | Spring AI | 1.0+ |
| JDK | OpenJDK / Oracle JDK | 17+ |
| 向量存储 | 内存存储(当前默认)/ PGVector 占位实现 | - |
| PDF 解析 | Apache PDFBox | 3.0.5 |
| JSON | Jackson | Spring Boot 内置 |
| 构建工具 | Maven | 3.9+ |
支持的大模型
| Provider | 说明 | 接入方式 |
|---|---|---|
| DashScope(通义千问) | 阿里云通义千问系列模型 | OpenAI 兼容 API |
| DeepSeek | DeepSeek 系列模型 | OpenAI 兼容 API |
| Ollama | 本地私有化部署模型 | OpenAI 兼容 API |
| OpenAI | GPT 系列模型 | OpenAI API |
模块架构
easy-agent
├── easy-agent-core # 核心模块:注解、注册中心、执行器
├── easy-agent-rag # RAG 模块:PDF/Excel 加载、内存检索、多搜索策略
├── easy-agent-mcp # MCP 模块:HTTP JSON-RPC 工具服务
├── easy-agent-skill # Skill 模块:业务 Skill Markdown 文件生成服务
├── easy-agent-llm # LLM 模块:多模型适配、OpenAI 兼容客户端
├── easy-agent-spring-boot-starter # Starter:自动装配、配置元数据
功能详解
1. @EasyTool 注解式工具注册
在任意 Spring Bean 的方法上添加 @EasyTool 注解,该方法便会自动注册到 ToolRegistry,可以通过 ToolExecutor 执行,也可以通过 MCP 的 tools/list 和 tools/call 暴露给客户端调用。
@Service
public class OrderService {
@EasyTool(name = "queryOrder", description = "根据订单号查询订单详情")
public OrderResult queryOrder(
@ToolParam(name = "orderId", description = "订单号") String orderId) {
return orderRepository.findById(orderId);
}
@EasyTool(name = "cancelOrder", description = "取消指定订单", category = "order")
public CancelResult cancelOrder(
@ToolParam(name = "orderId", description = "订单号") String orderId,
@ToolParam(name = "reason", description = "取消原因", required = false) String reason) {
return orderService.cancel(orderId, reason);
}
}
核心组件:
| 组件 | 说明 |
|---|---|
@EasyTool |
方法级注解,声明工具名称、描述、分类、启用状态 |
@ToolParam |
参数级注解,声明参数名称、描述、是否必填 |
ToolRegistry |
工具注册中心,管理所有已注册的工具定义 |
ToolExecutor |
工具执行器,负责参数解析、反射调用、结果序列化 |
EasyToolBeanPostProcessor |
Bean 后置处理器,自动扫描并注册 @EasyTool 方法 |
SPI 接口:
ToolProvider:自定义工具提供者,可编程式注册工具ToolExecutionListener:工具执行监听器,支持 before/after/error 钩子
业务系统引入 Starter 后,只需要把 ToolProvider 声明为 Spring Bean,easy-agent 会自动收集并注册其返回的工具定义。priority() 数值越小越先注册;如果工具名称重复,按 ToolRegistry 的现有规则覆盖。
@Component
public class BusinessToolProvider implements ToolProvider {
@Override
public Collection<ToolDefinition> provide() {
return List.of(new ToolDefinition(
"queryUserPermission",
"查询当前用户权限",
"user",
"permissionService",
"queryCurrentUserPermission",
List.of(),
true
));
}
@Override
public int priority() {
return 0;
}
}
业务系统也可以声明 ToolExecutionListener Bean,用于记录日志、审计、监控埋点或统计工具调用情况。beforeExecution 在业务工具调用前触发,afterExecution 在调用成功后触发,onError 在调用失败时触发。
@Component
public class BusinessToolExecutionListener implements ToolExecutionListener {
@Override
public void beforeExecution(ToolInvocation invocation) {
log.info("准备执行工具:{}", invocation.toolName());
}
@Override
public void afterExecution(ToolInvocation invocation, ToolResult result) {
log.info("工具执行成功:{}", invocation.toolName());
}
@Override
public void onError(ToolInvocation invocation, Throwable error) {
log.warn("工具执行失败:{}", invocation.toolName(), error);
}
}
2. Skill 文件生成
Skill 模块当前提供的是业务 Skill Markdown 文件生成能力:通过 MCP 暴露 skill.list_tools 和 skill.generate 两个工具,帮助用户查看当前项目中的 @EasyTool 工具,并生成业务侧自己的 Skill 描述文件。
核心组件:
| 组件 | 说明 |
|---|---|
SkillGeneratorService |
读取已注册工具,生成业务 Skill Markdown 文件 |
SkillMcpAdapter |
将 Skill 生成能力暴露为 MCP 工具 |
create-skill.md |
内置元技能说明文档,引导客户端如何生成 Skill |
生成文件默认写入项目根目录下的 skill/{name}.md,可通过 easy-agent.skill.skill-output-path 调整根目录。同名文件已存在时,MCP 客户端会询问使用者选择生成副本或覆盖。
当前版本不包含 Skill 文件解析、运行时加载、注册中心或文件热更新能力。
3. RAG 检索增强生成
RAG 模块支持在启动时加载 classpath:knowledge/ 下的 PDF、Excel 文件,切分为 DocumentChunk 后放入检索存储,并提供 Embedding、Cosine、TF-IDF 三种搜索策略。检索结果会在 DocumentChunk.score 中携带相关性分数。
存储策略:
| 模式 | 当前行为 |
|---|---|
AUTO |
使用内存存储 |
IN_MEMORY |
使用内存存储 |
PGVECTOR |
会创建 PgVector 占位 Provider,但当前 add/search/delete 仍不可用 |
当前推荐使用
AUTO或IN_MEMORY。PgVector 配置和占位类已存在,但还不是完整可用的持久化向量库实现。
搜索策略:
AUTO会按 Embedding、Cosine、TF-IDF 顺序降级检索- Embedding 检索会在文档加入内存存储时生成文档向量,查询时只生成 query 向量
- Cosine 和 TF-IDF 不依赖外部服务,适合作为本地兜底策略
文档加载:
- 自动扫描
classpath:knowledge/下的 PDF 文件、Excel 文件 - PDF 支持按字符长度分块(可配置 chunk 大小和重叠)
- PDF 的
chunk-overlap必须小于chunk-size - Excel 按行生成文档块
- 启动时自动索引,无需手动操作
运行时维护:
- 支持运行时添加 PDF、Excel 文档到知识库
- 支持按
source删除文档块 - 支持按
documentId删除文档块 - 支持清空索引
- 支持重新扫描默认知识库目录并重建索引
easy-agent 只提供 Java API,不默认暴露上传接口。业务系统负责上传入口、权限控制、文件大小限制、用户或租户隔离。
@Service
public class KnowledgeService {
@Autowired
private RagService ragService;
public String answerQuestion(String question) {
String context = ragService.searchAndConcat(question, 5);
// 将检索结果作为上下文传给 LLM
return llmService.chat(List.of(
ChatMessage.system("基于以下知识回答问题:\n" + context),
ChatMessage.user(question)
));
}
}
4. MCP 协议支持
实现了轻量 MCP(Model Context Protocol)HTTP 服务端,未配置 LLM 时也可仅提供 MCP 能力,让 Claude Code 等 MCP 客户端直接调用 @EasyTool 注册的工具。
当前 MCP 模块是基础工具型服务端,默认协议版本为 2025-11-25,并兼容 2024-11-05。initialize 时客户端未传 protocolVersion 会默认使用 2025-11-25;传入 2025-11-25 或 2024-11-05 会按客户端版本返回;传入其他版本会返回 JSON-RPC INVALID_PARAMS。
协议实现:
| 方法 | 说明 |
|---|---|
initialize |
初始化握手,返回服务端能力和版本信息 |
tools/list |
列出所有可用工具 |
tools/call |
调用指定工具 |
resources/list |
资源列表(预留) |
prompts/list |
提示词列表(预留) |
ping |
心跳检测 |
传输方式:
- HTTP POST:基于 JSON-RPC 2.0 的 POST 请求
- HTTP GET:支持 URL 参数方式调用(用于调试)
MCP 客户端配置示例(Claude Code):
{
"mcpServers": {
"easy-agent": {
"url": "http://{your-project-address}/mcp"
}
}
}
连接命令(Claude Code):
add claude mcp http://{your-project-address}/mcp
5. 多模型适配(LLM)
基于 OpenAI 兼容 API 的统一 HTTP 客户端,一套代码适配多家大模型供应商。当前支持普通对话、简单流式对话、Tool Calls 解析,以及基于已注册 @EasyTool 的自动工具调用闭环。
| 组件 | 说明 |
|---|---|
LlmService |
底层大模型对话服务,支持普通对话、流式对话和手动传入工具定义 |
AgentLlmService |
Agent 编排服务,自动读取 ToolRegistry 中的工具、调用模型、执行工具并继续对话 |
简化配置(推荐):
easy-agent:
llm:
enabled: true
model: qwen-plus # 通过模型名自动识别 provider
api-key: sk-xxxxxxxx # 通用 API Key(优先使用)
注意:
provider可省略,系统会根据model名称自动推断:
- 包含
qwen或tongyi→ dashscope(通义千问)- 包含
deepseek→ deepseek- 包含
llama、mistral→ ollama- 包含
gpt、o1、o3→ openai- 其他 → 默认使用 dashscope
提示:顶层的
api-key和model会优先使用。如果需要自定义 baseUrl,请在对应的 provider 内部配置。
完整配置示例:
# 通义千问
easy-agent:
llm:
provider: dashscope
dash-scope:
api-key: sk-xxxxxxxx
model: qwen-max
# DeepSeek
easy-agent:
llm:
provider: deepseek
deep-seek:
api-key: sk-xxxxxxxx
model: deepseek-chat
# Ollama(本地部署)
easy-agent:
llm:
provider: ollama
ollama:
base-url: http://localhost:11434
model: llama3
# OpenAI
easy-agent:
llm:
provider: openai
open-ai:
api-key: sk-xxxxxxxx
model: gpt-4o
快速开始
1. 引入依赖
<dependency>
<groupId>io.github.songrongzhen</groupId>
<artifactId>easy-agent-spring-boot-starter</artifactId>
<version>0.1.6</version>
</dependency>
2. 添加配置
easy-agent:
# MCP 配置(可选)
mcp:
# 是否启用 MCP HTTP 工具服务
enabled: true
# MCP 初始化握手时返回的服务名称
server-name: easy-agent-mcp-server
# MCP 初始化握手时返回的服务版本
server-version: 0.1.6
# MCP 接口跨域配置,仅作用于 /mcp/** 路径(CORS 配置可以不写,默认开启本地跨域。)
cors:
# 是否启用 MCP CORS 过滤器
enabled: true
# 允许访问 MCP 接口的来源,支持 Spring 的 origin pattern
allowed-origin-patterns:
- http://localhost:*
- http://127.0.0.1:*
# 允许的请求头
allowed-headers:
- "*"
# 允许的 HTTP 方法
allowed-methods:
- GET
- POST
- OPTIONS
# 允许浏览器读取的响应头
exposed-headers:
- Content-Type
llm:
enabled: true
model: "qwen-plus"
api-key: {your api key}
# RAG 配置(可选)
rag:
# 是否启用 RAG 功能
enabled: true
# 向量存储类型:AUTO、IN_MEMORY、PGVECTOR
# AUTO 和 IN_MEMORY 使用内存存储;PGVECTOR 当前为占位 Provider,暂不可用于实际检索
storage-type: IN_MEMORY
search:
# 搜索策略:AUTO(Embedding -> Cosine -> TF-IDF 降级)、EMBEDDING、COSINE、TF_IDF
strategy: AUTO
embedding:
# 是否启用 Embedding 向量检索(最精准,但需要配置 Embedding 服务)
enabled: true
# Embedding 服务提供者配置项已预留;实际 EmbeddingModel 由 Spring 容器提供
provider: DASHSCOPE
# Embedding 模型名称
model: nomic-embed-text
cosine:
# 是否启用余弦相似度搜索(作为 Embedding 的降级方案)
enabled: true
tfIdf:
# 是否启用 TF-IDF 搜索(兜底方案,不需要外部服务)
enabled: true
pdf:
# 是否启用 PDF 文档加载
enabled: true
# PDF 文件所在目录(支持 classpath: 前缀)
resource-path: classpath:knowledge/
# PDF 文档块字符长度
chunk-size: 1000
# PDF 文档块重叠字符数,必须小于 chunk-size
chunk-overlap: 200
excel:
# 是否启用 Excel 文档加载
enabled: true
# Excel 文件所在目录(支持 classpath: 前缀)
resource-path: classpath:knowledge/
# 说明:pdf.enabled 和 excel.enabled 同时影响启动加载和运行时 addDocument 支持的文件类型
# Skill 配置(可选;不配置时默认启用,并在项目根目录下生成 /skill/)
skill:
# 是否启用业务 Skill Markdown 文件生成能力,默认 true
enabled: true
# 生成目录的根路径,默认 .;最终文件写入 ${skill-output-path}/skill/
skill-output-path: .
3. 定义工具
@Service
public class MyTools {
@EasyTool(name = "getCurrentTime", description = "获取当前时间")
public String getCurrentTime() {
return java.time.LocalDateTime.now().toString();
}
@EasyTool(name = "calculate", description = "执行数学计算")
public double calculate(
@ToolParam(name = "expression", description = "数学表达式") String expression,
@ToolParam(name = "precision", description = "精度", required = false) int precision) {
// 计算逻辑...
return result;
}
}
4. 放置知识库(可选)
将 Excel、PDF 文件放到 src/main/resources/knowledge/ 目录下,启动时自动索引。
5. 生成 Skill(可选)
启动服务后,连接 Claude Code,说"我想创建一个 skill",系统会引导你完成 Skill 定义并生成业务 Skill Markdown 文件到项目根目录的 skill/ 文件夹。
完整配置参考
server:
port: 8999
tomcat :
socket:
soLingerOn: false
easy-agent:
# MCP 配置
mcp:
# 是否启用 MCP HTTP 工具服务
enabled: true
# MCP 初始化握手时返回的服务名称
server-name: easy-agent-mcp-server
# MCP 初始化握手时返回的服务版本
server-version: 0.1.6
# MCP 接口跨域配置,仅作用于 /mcp/** 路径 (CORS 配置可以不写,默认开启本地跨域。)
cors:
# 是否启用 MCP CORS 过滤器
enabled: true
# 允许访问 MCP 接口的来源,支持 Spring 的 origin pattern
allowed-origin-patterns:
- http://localhost:*
- http://127.0.0.1:*
# 允许的请求头
allowed-headers:
- "*"
# 允许的 HTTP 方法
allowed-methods:
- GET
- POST
- OPTIONS
# 允许浏览器读取的响应头
exposed-headers:
- Content-Type
llm:
enabled: true
model: "qwen-plus"
api-key: ${your api key}
# RAG 配置(可选)
rag:
# 是否启用 RAG 功能
enabled: true
# 向量存储类型:AUTO、IN_MEMORY、PGVECTOR
# AUTO 和 IN_MEMORY 使用内存存储;PGVECTOR 当前为占位 Provider,暂不可用于实际检索
storage-type: IN_MEMORY
search:
# 搜索策略:AUTO(Embedding -> Cosine -> TF-IDF 降级)、EMBEDDING、COSINE、TF_IDF
strategy: AUTO
embedding:
# 是否启用 Embedding 向量检索(最精准,但需要配置 Embedding 服务)
enabled: true
# Embedding 服务提供者配置项已预留;实际 EmbeddingModel 由 Spring 容器提供
provider: DASHSCOPE
# Embedding 模型名称
model: nomic-embed-text
cosine:
# 是否启用余弦相似度搜索(作为 Embedding 的降级方案)
enabled: true
tfIdf:
# 是否启用 TF-IDF 搜索(兜底方案,不需要外部服务)
enabled: true
pdf:
# 是否启用 PDF 文档加载
enabled: true
# PDF 文件所在目录(支持 classpath: 前缀)
resource-path: classpath:knowledge/
# PDF 文档块字符长度
chunk-size: 1000
# PDF 文档块重叠字符数,必须小于 chunk-size
chunk-overlap: 200
excel:
# 是否启用 Excel 文档加载
enabled: true
# Excel 文件所在目录(支持 classpath: 前缀)
resource-path: classpath:knowledge/
# 说明:pdf.enabled 和 excel.enabled 同时影响启动加载和运行时 addDocument 支持的文件类型
# Skill 配置(可选;不配置时默认启用,并在项目根目录下生成 /skill/)
skill:
# 是否启用业务 Skill Markdown 文件生成能力,默认 true
enabled: true
# 生成目录的根路径,默认 .;最终文件写入 ${skill-output-path}/skill/
skill-output-path: .
# 日志配置
logging:
level:
io.github.songrongzhen: DEBUG
项目结构
easy-agent/
├── pom.xml # 父 POM:依赖管理、插件配置
├── docker-compose.yml # 开发环境示例
├── easy-agent-core/
│ └── src/main/java/.../core/
│ ├── annotation/
│ │ ├── EasyTool.java # 核心注解:标记方法为 LLM 工具
│ │ └── ToolParam.java # 参数注解:描述工具参数
│ ├── model/
│ │ ├── ToolDefinition.java # 工具定义(名称、描述、参数等)
│ │ ├── ParameterDefinition.java # 参数定义
│ │ ├── ToolInvocation.java # 工具调用请求
│ │ └── ToolResult.java # 工具调用结果
│ ├── registry/
│ │ └── ToolRegistry.java # 工具注册中心
│ ├── executor/
│ │ └── ToolExecutor.java # 工具执行器(反射调用)
│ ├── processor/
│ │ └── EasyToolBeanPostProcessor.java # Bean 后置处理器(自动注册)
│ ├── spi/
│ │ ├── ToolProvider.java # SPI:自定义工具提供者
│ │ └── ToolExecutionListener.java # SPI:工具执行监听器
│ └── exception/
│ ├── EasyAgentException.java # 基础异常
│ ├── ToolExecutionException.java # 工具执行异常
│ └── ToolNotFoundException.java # 工具未找到异常
├── easy-agent-rag/
│ └── src/main/java/.../rag/
│ ├── config/
│ │ └── EasyAgentRagProperties.java # RAG 配置属性
│ ├── store/
│ │ ├── VectorStoreProvider.java # 向量存储接口
│ │ ├── PgVectorStoreProvider.java # PGVector 占位实现
│ │ ├── InMemoryVectorStoreProvider.java # 内存实现
│ │ ├── VectorStoreProviderFactory.java # 存储工厂
│ │ └── DocumentChunk.java # 文档分块模型
│ ├── loader/
│ │ ├── DocumentLoader.java # 文档加载接口
│ │ ├── PdfDocumentLoader.java # PDF 文档加载与分块
│ │ └── ExcelDocumentLoader.java # Excel 文档加载与分块
│ ├── search/
│ │ ├── SearchStrategy.java # 搜索策略接口
│ │ ├── SearchStrategyFactory.java # 搜索策略工厂(自动选择)
│ │ ├── EmbeddingSearchStrategy.java # Embedding 向量检索
│ │ ├── CosineSimilaritySearchStrategy.java # 余弦相似度搜索
│ │ └── TfIdfSearchStrategy.java # TF-IDF 搜索
│ └── service/
│ └── RagService.java # RAG 服务:索引、检索
├── easy-agent-mcp/
│ └── src/main/java/.../mcp/
│ ├── config/
│ │ ├── EasyAgentMcpProperties.java # MCP 配置属性
│ │ └── McpCorsConfig.java # CORS 配置
│ ├── protocol/
│ │ └── McpProtocol.java # MCP 协议类型定义
│ ├── adapter/
│ │ ├── McpToolAdapter.java # @EasyTool → MCP Tool 适配
│ │ └── SkillMcpAdapter.java # Skill 生成工具 → MCP Tool 适配
│ ├── server/
│ │ └── EasyAgentMcpServer.java # MCP 服务端核心逻辑
│ └── controller/
│ └── McpController.java # HTTP 传输层端点
├── easy-agent-skill/
│ └── src/main/
│ ├── java/.../skill/
│ │ ├── config/
│ │ │ └── EasyAgentSkillProperties.java # Skill 配置属性
│ │ └── service/
│ │ └── SkillGeneratorService.java # Skill 生成服务
│ └── resources/
│ └── skills/
│ └── create-skill.md # 内置元技能:生成业务 Skill Markdown 文件
├── easy-agent-llm/
│ └── src/main/java/.../llm/
│ ├── config/
│ │ └── EasyAgentLlmProperties.java # LLM 配置属性
│ ├── service/
│ │ ├── LlmService.java # LLM 服务接口
│ │ ├── ChatMessage.java # 聊天消息模型
│ │ ├── ChatResponse.java # 聊天响应模型
│ │ ├── ToolCall.java # 工具调用模型
│ │ ├── ToolDescriptor.java # 工具描述模型
│ │ ├── ToolParameter.java # 工具参数模型
│ │ └── Usage.java # Token 用量模型
│ ├── client/
│ │ ├── OpenAiCompatibleApi.java # OpenAI 兼容 API 类型定义
│ │ └── OpenAiCompatibleClient.java # OpenAI 兼容 HTTP 客户端
│ └── provider/
│ ├── LlmServiceFactory.java # LLM 服务工厂
│ ├── OpenAiCompatibleLlmService.java # 通用 LLM 服务实现
│ └── NoOpLlmService.java # 空实现(MCP-Only 模式)
└── easy-agent-spring-boot-starter/
└── src/main/
├── java/.../autoconfigure/
│ ├── EasyAgentCoreAutoConfiguration.java # Core 自动配置
│ ├── EasyAgentRagAutoConfiguration.java # RAG 自动配置
│ ├── EasyAgentMcpAutoConfiguration.java # MCP 自动配置
│ ├── EasyAgentSkillAutoConfiguration.java # Skill 自动配置
│ └── EasyAgentLlmAutoConfiguration.java # LLM 自动配置
└── resources/
└── META-INF/
├── spring/
│ └── org.springframework.boot.autoconfigure.AutoConfiguration.imports
└── spring-configuration-metadata.json
使用示例
1. llm 模块
// 基本 LLM 对话能力
@GetMapping("chat-message")
public ChatResponse chatMessage(@RequestParam String query) {
ChatMessage userMessage = new ChatMessage(ChatMessage.Role.USER, query);
ChatMessage systemMessage = new ChatMessage(ChatMessage.Role.SYSTEM, query);
List<ChatMessage> chatMessage = List.of(systemMessage, userMessage);
ChatResponse chat = llmService.chat(chatMessage);
return chat;
}
// 带 @EasyTool 自动工具调用的 Agent 对话能力
@GetMapping("agent-message")
public ChatResponse agentMessage(@RequestParam String query) {
return agentLlmService.chatWithRegisteredTools(List.of(ChatMessage.user(query)));
}
// 简单流式对话
@GetMapping("/chat/stream")
public ResponseEntity<StreamingResponseBody> chatStream(@RequestParam String message) {
StreamingResponseBody stream = outputStream -> {
StringBuilder fullResponse = new StringBuilder();
Writer writer = new OutputStreamWriter(outputStream);
List<ChatMessage> messages = List.of(ChatMessage.user(message));
llmService.chatStream(messages, token -> {
if (token != null) {
fullResponse.append(token);
try {
writer.write(token);
writer.flush();
} catch (IOException e) {
throw new RuntimeException(e);
}
} else {
try {
writer.write("\n[DONE]");
writer.flush();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
});
};
return ResponseEntity.ok()
.contentType(MediaType.parseMediaType("text/event-stream;charset=UTF-8"))
.header("Cache-Control", "no-cache")
.header("X-Accel-Buffering", "no")
.body(stream);
}
2. mcp 模块
// 先准备两个工具
@Component
public class McpServiceTools {
@EasyTool(name = "hello", description = "向用户打招呼")
public String sayHello(String name) {
return "你好," + name + "!欢迎使用 easy-agent!";
}
@EasyTool(name = "add", description = "计算两个数字的和")
public int add(int a, int b) {
System.out.println("正在计算两个数字的和...");
return a + b;
}
}
/**
*将测试服务启动,安装 Claude code 后使用 add claude mcp http://localhost:8080/mcp 将服务端注册为 MCP 服务
*启动 claude 问我有哪些功能,此时会列出注册的工具
*/
3. rag 模块
// rag 增强搜索能力
@GetMapping("/chat-rag-message")
public ChatResponse chtatRagMessage(@RequestParam String query,
@RequestParam(defaultValue = "2") int topK) {
List<DocumentChunk> results = ragService.search(query, topK);
ChatMessage userMessage = new ChatMessage(ChatMessage.Role.USER, results.toString());
ChatMessage systemMessage = new ChatMessage(ChatMessage.Role.SYSTEM, "从内容中抽出问答对中的,A 的内容直接返回,不要加额外任何内容");
List<ChatMessage> chatMessage = List.of(systemMessage, userMessage);
ChatResponse chat = llmService.chat(chatMessage);
return chat;
}
运行时维护知识库:
@RestController
@RequestMapping("/knowledge")
public class KnowledgeController {
private final RagService ragService;
public KnowledgeController(RagService ragService) {
this.ragService = ragService;
}
@PostMapping("/upload")
public List<DocumentChunk> upload(@RequestParam MultipartFile file) throws IOException {
return ragService.addDocument(file.getOriginalFilename(), file.getInputStream());
}
@PostMapping("/{documentId}/upload")
public List<DocumentChunk> uploadWithDocumentId(@PathVariable String documentId,
@RequestParam MultipartFile file) throws IOException {
return ragService.addDocument(documentId, file.getOriginalFilename(), file.getInputStream());
}
@DeleteMapping("/source")
public void deleteBySource(@RequestParam String source) {
ragService.deleteBySource(source);
}
@DeleteMapping("/{documentId}")
public void deleteByDocumentId(@PathVariable String documentId) {
ragService.deleteByDocumentId(documentId);
}
@DeleteMapping
public void clearIndex() {
ragService.clearIndex();
}
@PostMapping("/rebuild")
public void rebuildIndex() {
ragService.rebuildIndex();
}
}
addDocument(filename, inputStream) 会自动生成 documentId,返回的 DocumentChunk.metadata 中包含该值。业务系统如果已有自己的文件 ID,建议调用 addDocument(documentId, filename, inputStream),后续可以直接用该 ID 删除或替换文档。
4. skill 模块
// (***前提 1)通过 @EasyTool 注解 定义了 向用户打招呼、计算两个数字的和接口
// (***前提 2)安装 Claude code 后使用 add claude mcp http://localhost:8080/mcp 将服务端注册为 MCP 服务
// 启动 claude 后询问有哪些功能,此时会列出注册的工具,
// 其中包含 skill.list_tools 和 skill.generate。
// 说“我想生成一个 skill”,根据提示输入后,会在项目根目录下的 skill/ 目录生成 Markdown 文件。
