Spring AI提供了一套简洁的机制,可以将Java方法暴露为AI模型可调用的工具。以下是完整的开发指南:
1. 环境准备
首先添加Spring AI依赖到你的项目中:
<!-- pom.xml -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-core</artifactId>
<version>0.8.1</version> <!-- 使用最新版本 -->
</dependency>
2. 基础工具开发
2.1 创建工具类
import org.springframework.ai.tool.Tool;
import org.springframework.ai.tool.P;
import org.springframework.stereotype.Component;
@Component
public class BusinessTools {
// 简单工具示例
@Tool(name = "calculate", description = "执行数学计算")
public double calculate(
@P(description = "第一个操作数") double a,
@P(description = "运算符(+,-,*,/)") String op,
@P(description = "第二个操作数") double b) {
return switch (op) {
case "+" -> a + b;
case "-" -> a - b;
case "*" -> a * b;
case "/" -> a / b;
default -> throw new IllegalArgumentException("不支持的运算符: " + op);
};
}
}
2.2 注册工具
import org.springframework.ai.tool.ToolCallbackProvider;
import org.springframework.ai.tool.method.MethodToolCallbackProvider;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**通过MethodToolCallbackProvider自动注册服务类中的工具方法*/
@Configuration
public class ToolConfiguration {
@Bean
public ToolCallbackProvider businessTools(BusinessTools tools) {
return MethodToolCallbackProvider.builder()
.toolObjects(tools) // 注册包含@Tool注解的bean
.build();
}
}
3. 复杂工具开发
3.1 使用DTO作为参数
// 定义DTO
public record OrderRequest(
String customerId,
List<String> productIds,
String shippingAddress) {}
// 在工具类中添加方法
@Tool(name = "createOrder", description = "创建新订单")
public OrderResult createOrder(
@P(description = "订单请求") OrderRequest request) {
// 实际业务逻辑
return orderService.create(request);
}
3.2 异步工具
@Tool(name = "generateReport", description = "生成业务报表")
public CompletableFuture<Report> generateReport(
@P(description = "报表类型") ReportType type,
@P(description = "日期范围") String dateRange) {
return CompletableFuture.supplyAsync(() -> {
// 长时间运行的报表生成逻辑
return reportService.generate(type, dateRange);
});
}
4. 工具调用控制
4.1 添加权限控制
@Tool(name = "deleteUser", description = "删除用户账户")
public String deleteUser(
@P(description = "用户名") String username) {
// 检查权限
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
if (!auth.getAuthorities().contains("ROLE_ADMIN")) {
throw new AccessDeniedException("无权执行此操作");
}
return userService.delete(username);
}
4.2 输入验证
@Tool(name = "reserveRoom", description = "预订会议室")
public ReservationResult reserveRoom(
@P(description = "会议室ID") @Min(1) int roomId,
@P(description = "开始时间(yyyy-MM-dd HH:mm)") @Future String startTime,
@P(description = "持续时间(分钟)") @Min(15) @Max(240) int duration) {
// 方法参数会自动验证
return reservationService.reserve(roomId, startTime, duration);
}
5. 集成AI模型
5.1 配置AI客户端
import org.springframework.ai.chat.ChatClient;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class AiConfig {
@Bean
public ChatClient chatClient(ToolCallbackProvider toolCallbackProvider) {
return new OpenAiChatClient.Builder()
.apiKey("your-api-key")
.toolCallbackProvider(toolCallbackProvider) // 注册工具
.build();
}
}
5.2 创建控制器
import org.springframework.ai.chat.ChatResponse;
import org.springframework.ai.chat.prompt.Prompt;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/api/ai")
public class AiController {
private final ChatClient chatClient;
public AiController(ChatClient chatClient) {
this.chatClient = chatClient;
}
@PostMapping("/chat")
public String chat(@RequestBody String userMessage) {
Prompt prompt = new Prompt(userMessage);
ChatResponse response = chatClient.call(prompt);
return response.getResult().getOutput().getContent();
}
}
6. 转换成微服务
6.1 添加启动类
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class McpServerApplication {
public static void main(String[] args) {
SpringApplication.run(McpServerApplication.class, args);
}
}
6.2 添加application.yml
spring.ai.mcp.server.name=my-ai-server
spring.ai.mcp.server.version=0.0.1
server.port=9090
最佳实践
- 命名规范:使用动词-名词组合(如
createOrder
、calculateSum
) - 参数描述:为每个参数提供清晰的自然语言描述
- 错误处理:定义明确的错误响应格式
- 性能考虑:长时间运行的操作实现为异步
- 文档化:为每个工具添加详细的JavaDoc注释
- 安全审计:记录所有工具调用日志
通过以上步骤,你可以有效地将Java方法暴露为AI可调用微服务,构建智能化的业务应用,也可提供给dify、bisheng等智能体调用。