背景:Spring AI Alibaba 开源项目基于 Spring AI 构建,是阿里云通义系列模型及服务在 Java AI 应用开发领域的最佳实践,提供高层次的 AI API 抽象与云原生基础设施集成方案,帮助开发者快速构建 AI 应用。Spring AI Alibaba官方文档:https://java2ai.com/docs/1.0.0-M5.1/overview/?spm=4347728f.7a696532.0.0.55ca6e97w8zCXV<properties> <java.version>17</java.version> <vaadin.version>24.4.7</vaadin.version> <maven-deploy-plugin.version>3.1.1</maven-deploy-plugin.version> <spring-ai-alibaba.version>1.0.0-M6.1</spring-ai-alibaba.version></properties>
jdk版本不低于17,spring-ai-alibaba的版本为1.0.0-M6.1,基于Spring Boot 3.x开发。<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-webflux</artifactId></dependency>
@Configuration@Slf4jpublic class AssistantConfig { /** * 航班助理 * * @param modelBuilder * @param vectorStore * @param chatMemory */ @Bean public ChatClient getChatClient(ChatClient.Builder modelBuilder, VectorStore vectorStore, ChatMemory chatMemory) { log.info("航班助理配置CustomerSupportAssistant().."); ChatClient chatClient = modelBuilder .defaultSystem(""" 您是“Flight-Booking”航空公司的客户聊天支持代理,请以友好、乐于助人且愉快的方式来回复. 您正在通过在线聊天系统与客户互动. 您能够支持已有机票的预订详情查询、机票日期改签、机票预订取消等操作,其余功能将在后续版本中添加,如果用户问的问题不支持请告知详情. 在提供有关机票预订详情查询、机票日期改签、机票预订取消等操作之前,您必须始终从用户处获取以下信息:预订号、客户姓名. 在为用户查询信息后,每个字段的内容都需要分行展示,分行显示内容时注意保持样式一致,需要使用-分行显示,其他格式不符合. 在询问用户之前,请检查消息历史记录以获取预订号、客户姓名等信息,尽量避免重复询问给用户造成困扰. 在更改预订之前,您必须确保条款允许这样做. 如果更改需要收费,您必须在继续之前征得用户同意. 使用提供的功能获取预订详细信息、更改预订和取消预订. 如果需要,您可以调用相应函数辅助完成. 请讲中文. 今天的日期是 {current_date}. """) .defaultAdvisors( // 会话记忆 new PromptChatMemoryAdvisor(chatMemory),
// 存储,基于RAG new QuestionAnswerAdvisor(vectorStore, SearchRequest.builder().topK(4).similarityThresholdAll().build()),
// logger 日志打印 new SimpleLoggerAdvisor() ) .defaultFunctions( "getBookingDetails", "changeBooking", "cancelBooking" ) .build(); return chatClient; }
@Bean CommandLineRunner ingestTermOfServiceToVectorStore(EmbeddingModel embeddingModel, VectorStore vectorStore, @Value("classpath:rag/terms-of-service.txt") Resource termsOfServiceDocs) { log.info("向量数据存储.."); return args -> { // Ingest the document into the vector store vectorStore.write(new TokenTextSplitter().transform(new TextReader(termsOfServiceDocs).read()));
vectorStore.similaritySearch("Cancelling Bookings").forEach(doc -> { log.info("Similar Document: {}", doc.getText()); }); }; }
@Bean public VectorStore vectorStore(EmbeddingModel embeddingModel) { log.info("vectorStore初始化.."); return SimpleVectorStore.builder(embeddingModel).build(); }
@Bean public ChatMemory chatMemory() { log.info("chatMemory().."); return new InMemoryChatMemory(); }
@Bean @ConditionalOnMissingBean public RestClient.Builder restClientBuilder() { log.info("restClientBuilder().."); return RestClient.builder(); }}
这个配置在chatClient使用前配置系统角色,基于RAG的模式投喂给大模型机票助手应该具备哪些规则,ChatMemory使其具备聊天记忆功能,Function Calling支持函数调用.@RequestMapping(path = "/chat", produces = MediaType.TEXT_EVENT_STREAM_VALUE)public Flux<String> chat(String chatId, String userMessage) { return assistantService.chat(chatId, userMessage);}这段基于流式回答,chatId标志一次对话,该演示项目为对接数据库,所有数据均为临时,可以基于业务需求,建表存储会话和消息记录。 /** * 用户对话 * * @param chatId * @param userMessageContent * @return */ public Flux<String> chat(String chatId, String userMessageContent) { log.info("用户对话ID: {}", chatId); return this.chatClient.prompt() .system(s -> s.param("current_date", LocalDate.now().toString())) .user(userMessageContent) .advisors(a -> a.param(CHAT_MEMORY_CONVERSATION_ID_KEY, chatId).param(CHAT_MEMORY_RETRIEVE_SIZE_KEY, 100)) .stream() .content(); }注意点:current_date当做参数传递,细心的小伙伴注意到AssistantConfig的提示词中含有该参数,大家可以根据需求自行传递,如控制用户权限。@Bean@Description("获取机票预定详细信息")public Function<BookingDetailsRequest, BookingDetails> getBookingDetails() { log.info("获取机票预定详细信息1..");return request -> { log.info("获取机票预定详细信息2..");try {return flightBookingService.getBookingDetails(request.bookingNumber(), request.name()); } catch (Exception e) { logger.warn("Booking details: {}", NestedExceptionUtils.getMostSpecificCause(e).getMessage());return new BookingDetails(request.bookingNumber(), request.name(), null, null, null, null, null); } };}public record BookingDetailsRequest(String bookingNumber, String name) {}以"获取机票信息"函数为例,其他函数同理;其BookingTools类添加了注解Configuration,意味着项目启动就会初始化,如果侧重于业务,@Service注解同样也可以实现!其中请求体record是jdk17具备的,简化了实体类的创建,参数bookingNumber即为预约号,name即为用户名。大家可以利用MCP功能,基于@Tool等注解改写代码,实现功能。至此,使用Spring AI Alibaba搭建智能机票助手已实现。但应用到实际需求时,大模型处理用户提供的时间[时分秒]总是出错,欢迎大家提供解决方案!
立即咨询 JOTO
JOTO 提供覆盖企业智能体规划与搭建、AI 平台私有化部署、RAG 知识工程、AI 安全治理、FDE 驻场共创及持续运营优化的全周期 AI 落地服务,帮助企业把验证中的 AI 能力转化为安全、可控、可持续迭代的生产力。 联系 JOTO 获取 AI 落地咨询