王炸!Spring AI+Tools 一分鐘實(shí)現(xiàn)CRUD智能助手
環(huán)境:SpringBoot3.4.2
1. 簡介
Tools賦予大語言模型與外部工具或API交互能力,使其能動態(tài)調(diào)用函數(shù)執(zhí)行復(fù)雜任務(wù)。其核心作用包括:
- 突破模型文本生成局限,實(shí)現(xiàn)查詢天氣、調(diào)用數(shù)據(jù)庫等實(shí)時(shí)操作
- 構(gòu)建多步驟智能體,支持旅行規(guī)劃、電商下單等跨工具協(xié)同場景
- 與企業(yè)系統(tǒng)深度集成,自動調(diào)用CRM、ERP等業(yè)務(wù)接口處理客戶訂單、庫存查詢等需求,推動AI從對話助手向業(yè)務(wù)執(zhí)行者躍遷。
關(guān)于Tools更多的內(nèi)容,請查看下面這篇文章:
太強(qiáng)了!Spring AI調(diào)用本地函數(shù),實(shí)時(shí)獲取最新數(shù)據(jù)
本文將基于Spring AI+Tools 實(shí)現(xiàn)會議預(yù)約模塊的全鏈路CRUD操作。如下是一個查詢所有會議的小示例:
接下來,我們將實(shí)現(xiàn)上面的查詢功能及其它操作(新增,刪除等)。
2. 實(shí)戰(zhàn)案例
首先,準(zhǔn)備環(huán)境,引入如下依賴及配置
<dependency>
<groupId>com.alibaba.cloud.ai</groupId>
<artifactId>spring-ai-alibaba-starter</artifactId>
<version>1.0.0-M6.1</version>
</dependency>
配置文件application.yml
spring:
ai:
dashscope:
api-key: sk-xxxooo
base-url: https://dashscope.aliyuncs.com/compatible-mode/v1
chat:
options:
model: qwen-turbo
---
# 數(shù)據(jù)庫相關(guān)配置
spring:
datasource:
driverClassName: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/ds
username: root
password: xxxooo
2.1 基本增刪改查
實(shí)體對象
@Entity
@Table(name = "t_meeting")
public class Meeting {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id ;
private String title ;
private String description ;
private LocalDateTime startTime ;
private Integer duration ;
@Enumerated(EnumType.STRING)
private Urgency urgency ;
private String creator ;
@OneToMany(mappedBy = "meeting", fetch = FetchType.EAGER, cascade = CascadeType.ALL)
private Set<Participant> participants = new HashSet<>() ;
}
@Entity
@Table(name = "t_participant")
public class Participant {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@ManyToOne(optional = false)
@JoinColumn(name = "mid")
@JsonIgnore
private Meeting meeting ;
}
Repository定義
public interface MeetingRepository extends JpaRepository<Meeting, Long> {
}
Service增刪改查操作
@Service
public class MeetingService {
private final MeetingRepository meetingRepository ;
public MeetingService(MeetingRepository meetingRepository) {
this.meetingRepository = meetingRepository;
}
@Transactional
public Meeting createMeeting(Meeting meeting) {
return meetingRepository.save(meeting);
}
public Meeting getMeetingById(Long id) {
return meetingRepository.findById(id).orElseThrow(() -> new ResourceNotFoundException("會議不存在"));
}
@Transactional
public void deleteMeeting(Long id) {
meetingRepository.deleteById(id);
}
@Transactional(readOnly = true)
public List<Meeting> getAllMeetings() {
return meetingRepository.findAll();
}
}
2.2 Tools定義
首先,我們定義一個VO對象,用來接收解析后的用戶輸入內(nèi)容。
public class MeetingVO {
@ToolParam(description = "會議主題,也可以是會議標(biāo)題")
private String title ;
@ToolParam(description = "會議描述,備注信息")
private String description ;
@ToolParam(description = "會議時(shí)間")
private LocalDateTime startTime ;
@ToolParam(description = "會議大概持續(xù)時(shí)間,單位分鐘")
private Integer duration ;
@ToolParam(description = "會議緊急程度,分為3個等級: LOW(低), MEDIUM(一般), HIGH(高)")
@Enumerated(EnumType.STRING)
private Urgency urgency ;
@ToolParam(description = "預(yù)約會議人")
private String creator ;
@ToolParam(description = "會議參與者,用逗號','分割")
private Set<String> participants = new HashSet<>() ;
// getters, setters
}
@ToolParam描述了每一個屬性的作用。接下來,是具體工具定義:
@Component
public class MeetingTools {
private final MeetingService meetingService ;
public MeetingTools(MeetingService meetingService) {
this.meetingService = meetingService;
}
@Tool(description = "添加預(yù)約會議")
public R<Meeting> addMeeting(MeetingVO meetingVO) {
Meeting meeting = new Meeting() ;
BeanUtils.copyProperties(meetingVO, meeting) ;
Set<Participant> participants = meetingVO.getParticipants()
.stream()
.map(p -> new Participant(p, meeting))
.collect(Collectors.toSet()) ;
meeting.setParticipants(participants) ;
this.meetingService.createMeeting(meeting) ;
return R.success(meeting) ;
}
@Tool(description = "刪除預(yù)約會議")
public R<String> deleteMeeting(@ToolParam(description = "會議編號") Long id) {
this.meetingService.deleteMeeting(id) ;
return R.success("刪除會議【" + id + "】成功") ;
}
@Tool(description = "查詢指定編號的會議")
public R<Meeting> queryMeeting(@ToolParam(description = "會議編號") Long id) {
return R.success(this.meetingService.getMeetingById(id)) ;
}
@Tool(description = "查詢所有會議")
public R<List<Meeting>> queryMeetings() {
return R.success(this.meetingService.getAllMeetings()) ;
}
}
2.3 配置ChatClient
@Configuration
public class ChatConfig {
@Bean
ChatClient meetingChat(ChatClient.Builder chatClientBuilder) {
String systemMessage = """
當(dāng)前時(shí)間:{date}。輸出結(jié)果使用HTML table表格展示。需要自適應(yīng)頁面大小(寬度),字體大小為12px。除HTML相關(guān)的內(nèi)容,不要有任何其它內(nèi)容。
""" ;
ChatClient chatClient = chatClientBuilder
.defaultSystem(systemMessage)
.build();
return chatClient ;
}
}
該配置中我們配置了系統(tǒng)文本內(nèi)容,告知了當(dāng)前的時(shí)間,如果不這樣做最終得到的時(shí)間是錯誤的。
2.4 測試
@RestController
@RequestMapping("/meeting/chat")
public class MeetingChatController {
private final MeetingTools meetingTools ;
private final ChatClient chatClient ;
public MeetingChatController(ChatClient chatClient) {
this.meetingTools = meetingTools ;
this.chatClient = chatClient ;
}
@GetMapping
public ResponseEntity<?> chat(String message) {
Prompt prompt = new Prompt(message) ;
String content = this.chatClient
.prompt(prompt)
// 設(shè)置系統(tǒng)文本中的占位符參數(shù)
.system(p -> p.param("date", new Date()))
.tools(meetingTools)
.call()
.content() ;
return ResponseEntity.ok(content) ;
}
}
創(chuàng)建會議
圖片
查詢指定會議詳細(xì)
圖片
查詢所有會議
圖片
刪除會議
圖片