王炸!Spring AI+Tools 一分鐘實現(xiàn)CRUD智能助手
環(huán)境:SpringBoot3.4.2
1. 簡介
Tools賦予大語言模型與外部工具或API交互能力,使其能動態(tài)調(diào)用函數(shù)執(zhí)行復(fù)雜任務(wù)。其核心作用包括:
- 突破模型文本生成局限,實現(xiàn)查詢天氣、調(diào)用數(shù)據(jù)庫等實時操作
 - 構(gòu)建多步驟智能體,支持旅行規(guī)劃、電商下單等跨工具協(xié)同場景
 - 與企業(yè)系統(tǒng)深度集成,自動調(diào)用CRM、ERP等業(yè)務(wù)接口處理客戶訂單、庫存查詢等需求,推動AI從對話助手向業(yè)務(wù)執(zhí)行者躍遷。
 
關(guān)于Tools更多的內(nèi)容,請查看下面這篇文章:
太強了!Spring AI調(diào)用本地函數(shù),實時獲取最新數(shù)據(jù)
本文將基于Spring AI+Tools 實現(xiàn)會議預(yù)約模塊的全鏈路CRUD操作。如下是一個查詢所有會議的小示例:

接下來,我們將實現(xiàn)上面的查詢功能及其它操作(新增,刪除等)。
2. 實戰(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: xxxooo2.1 基本增刪改查
實體對象
@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 = "會議時間")
  private LocalDateTime startTime ;
  @ToolParam(description = "會議大概持續(xù)時間,單位分鐘")
  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)前時間:{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)前的時間,如果不這樣做最終得到的時間是錯誤的。
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ì)
圖片
查詢所有會議
圖片
刪除會議
            
                
                    
                        
圖片















 
 
 





 
 
 
 