# SpringAi项目 **Repository Path**: SmileCco/spring-ai-project ## Basic Information - **Project Name**: SpringAi项目 - **Description**: SpringAi项目,参考图灵航空,实现AI处理业务等基本操作,此为学习项目。 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 7 - **Forks**: 3 - **Created**: 2025-02-12 - **Last Updated**: 2025-11-24 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README ## 简介 架构图 ![架构图.png](mdImage/springAiModel.png) 环境准备 - Java 21 - Node.js 18+ - 获取API Key api-key 配置 在正式开始体验之前,需要申请到模型的 api-key。申请地址:https://help.aliyun.com/zh/dashscope/developer-reference/activate-dashscope-and-create-anapi-key --- ### 运行 - 前端 ```text 前端环境安装:https://note.youdao.com/s/AXcWXq3v cd app/chatgpt-demo 执⾏安装依赖命令: npm i 运⾏: npm run dev ``` - 后端 ```text 需要配置 application.yml的 ai: dashscope: api-key: ${AI_KEY} chat: options: model: ${MODEL_NAME} 启动spring工程即可:mvn spring-boot:run ``` --- ### 笔记 分析原始代码 1. OpenAiController 构造方法 - 描述:`OpenAiController` 构造方法用于初始化 `ChatClient`,并配置日志记录拦截器、聊天记忆顾问和问答顾问。 - 参数 - `chatClientBuilder` (ChatClient.Builder): 用于构建 `ChatClient` 的构建器。 - `loggingAdvisor` (LoggingAdvisor): 日志记录拦截器,用于记录用户对话日志。 - `chatMemory` (ChatMemory): 聊天记忆,用于存储和检索聊天历史。 - `vectorStore` (VectorStore): 向量存储(Rag),用于存储和检索嵌入向量。 ### 示例 ```java public OpenAiController(ChatClient.Builder chatClientBuilder, LoggingAdvisor loggingAdvisor, ChatMemory chatMemory, VectorStore vectorStore) { this.chatClient = chatClientBuilder // 日志记录拦截器 .defaultAdvisors(loggingAdvisor, new PromptChatMemoryAdvisor(chatMemory), new QuestionAnswerAdvisor(vectorStore, SearchRequest.defaults())) // RAG .defaultSystem(""" 你是“YunCco(云科)”航空公司的客户聊天⽀持代理。请以友好、乐于助⼈且愉快的⽅式来回复。 你正在通过在线聊天系统与客户互动。 在操作更改预定或取消预订的操作之前,您必须始终从用户处获取以下信息:预订号、客户姓名。 更改预定必须去要求用户提供新的日期、出发地和目的地。 在更改预定或退订预定操作之前,请获取改乘客的机票预定详细信息并提醒操作的规则。 得到用户确定之后才进行处理机票更改或者处理机票退订操作。 在询问用户之前,请检查消息历史记录以获取操作所需要的信息。 今天的时间是 {current_date}。 请讲中⽂。 """) .defaultFunctions("cancelBookingRequestFunction","getBookingRequestFunction","updateBookingRequestFunction") // RAG .build(); } ``` 2. generateStreamAsString 方法 - 描述:`generateStreamAsString` 方法用于生成一个包含用户输入消息的实时流响应。 - 参数:`message` (String): 用户输入的消息,这里设置默认值 "你好"。 - 返回值:`Flux`: 返回一个包含用户输入消息的实时流响应(sse输出,若为call()方法输出则直接返回值为String)。 ### 示例 ```java @CrossOrigin @GetMapping(value = "/ai/generateStreamAsString", produces = MediaType.TEXT_EVENT_STREAM_VALUE) public Flux generateStreamAsString(@RequestParam(value = "message", defaultValue = "你好") String message) { Flux content = chatClient.prompt() .user(message) .system(prompt -> prompt.param("current_date", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")))) .advisors(advisorSpec -> advisorSpec.param(AbstractChatMemoryAdvisor.CHAT_MEMORY_RETRIEVE_SIZE_KEY, 100)) .stream() .content() .concatWith(Flux.just("[complete]")); return content; } ``` 详细说明 1. @CrossOrigin: 允许跨域请求。 2. @GetMapping: 映射HTTP GET请求到/ai/generateStreamAsString路径,并指定返回的媒体类型为text/event-stream,适用于服务器发送事件(SSE) 3. @RequestParam: 从请求中获取message参数,默认为"你好"。 4. chatClient.prompt(): 创建一个新的聊天提示。 5. .user(message): 设置用户输入的消息。 6. .system(prompt -> prompt.param("current_date", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")))): 设置系统参数current_date为当前日期和时间。这里对应了构造方法的defaultSystem参数。 7. .advisors(advisorSpec -> advisorSpec.param(AbstractChatMemoryAdvisor.CHAT_MEMORY_RETRIEVE_SIZE_KEY, 100)): 配置内存存放历史记录条数为100。 8. .stream(): 启动流式处理。 9. .content(): 获取流内容。 10. .concatWith(Flux.just("[complete]")): 在流的末尾添加一个"[complete]"标记,作用为与前端约定输出complete标志者为结束。 ### 1.加⼊打印⽇志拦截器 配置日志拦截器 ```java /** * @description: 记录ai用户对话的日志拦截器,可用于数据分析等 * @author liaohao * @createDate 2025/2/11 15:38 **/ @Slf4j @Component public class LoggingAdvisor implements RequestResponseAdvisor { @Override public AdvisedRequest adviseRequest(AdvisedRequest request, Map context) { log.info("Request: {}", request); // log.info("Context: {}", context); return request; } } ``` 装配入Chat构造方法中即可使用 ### 2.对话记忆 - 配置类中加入Bean ```java /** * 注入chatMemory,用于记录对话 * * @return */ @Bean public ChatMemory chatMemory() { return new InMemoryChatMemory(); } ``` - 构造方法中装配 ```java .defaultAdvisors(new PromptChatMemoryAdvisor(chatMemory)) ``` ### 3.实现业务处理 以便理解,这里以实现一个简单的业务处理为例,实现一个简单的问答功能。 - 在配置类中加入业务代码Bean ```java /** * @Description: 处理退订的逻辑 * @createDate 2025/2/11 18:06 **/ @Bean @Description("处理机票退订")//描述-用户输入的指令 public Function cancelBookingRequestFunction() { //apply方法调用,处理用户输入的指令,调用退订功能 return cancelBookingRequest -> { try { flightBookingService.cancelBooking(cancelBookingRequest.bookingNumber(), cancelBookingRequest.customerName()); return "退订成功"; }catch (Exception e){ return "退订失败"; } }; } ``` - 构造方法设置defaultFunctions属性 ```java .defaultFunctions("cancelBookingRequestFunction") ``` ### 4.通过RAG(检索增强⽣成),外挂⼀个知识库 向量数据库:相似性检索,⼤数据领域(推荐、你喜欢的) ![Rag流程图解.png](mdImage/ragImage.png) > 步骤: > 1. 配置向量数据库 > 2. 写⼊数据(Embedding) > 3. 查询 存储嵌入向量 ```java @Bean public VectorStore vectorStore(EmbeddingModel embeddingModel) { return new SimpleVectorStore(embeddingModel); } ``` 将服务条款文档嵌入到向量存储中。 ```java @Bean public CommandLineRunner ingestTermOfServiceToVectorStore( EmbeddingModel embeddingModel, VectorStore vectorStore, @Value("classpath:rag/terms-of-service.txt") Resource termsOfServiceDocs) { return args -> { vectorStore.write( // 3.写⼊ new TokenTextSplitter().transform( // 2.转换 new TextReader(termsOfServiceDocs).read()) // 1.读取 ); }; } ``` > 详细说明: > 1. `vectorStore`方法: > - 创建并返回一个`SimpleVectorStore`实例。 > - 注入 EmbeddingModel 以生成向量。 > 2. `ingestTermOfServiceToVectorStore`方法: > - 读取服务条款文档。 > - 使用`TokenTextSplitter`将文档转换为嵌入向量。 > - 将嵌入向量写入`VectorStore`。 配置Chat构造方法 ```java .defaultAdvisors(new QuestionAnswerAdvisor(vectorStore, SearchRequest.defaults())) //RAG ```