diff --git a/黄永兴学习笔记/3.30黄永兴-软件功能总结.docx b/黄永兴学习笔记/3.30黄永兴-软件功能总结.docx new file mode 100644 index 0000000..c6d3ba9 Binary files /dev/null and b/黄永兴学习笔记/3.30黄永兴-软件功能总结.docx differ diff --git a/黄永兴学习笔记/3.30黄永兴.docx b/黄永兴学习笔记/3.30黄永兴.docx new file mode 100644 index 0000000..2ce79f3 Binary files /dev/null and b/黄永兴学习笔记/3.30黄永兴.docx differ diff --git a/黄永兴学习笔记/StudySpringAI/.idea/.gitignore b/黄永兴学习笔记/StudySpringAI/.idea/.gitignore new file mode 100644 index 0000000..b6b1ecf --- /dev/null +++ b/黄永兴学习笔记/StudySpringAI/.idea/.gitignore @@ -0,0 +1,10 @@ +# 默认忽略的文件 +/shelf/ +/workspace.xml +# 已忽略包含查询文件的默认文件夹 +/queries/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml +# 基于编辑器的 HTTP 客户端请求 +/httpRequests/ diff --git a/黄永兴学习笔记/StudySpringAI/.idea/MarsCodeWorkspaceAppSettings.xml b/黄永兴学习笔记/StudySpringAI/.idea/MarsCodeWorkspaceAppSettings.xml new file mode 100644 index 0000000..12c0aa4 --- /dev/null +++ b/黄永兴学习笔记/StudySpringAI/.idea/MarsCodeWorkspaceAppSettings.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/黄永兴学习笔记/StudySpringAI/.idea/compiler.xml b/黄永兴学习笔记/StudySpringAI/.idea/compiler.xml new file mode 100644 index 0000000..14e84ae --- /dev/null +++ b/黄永兴学习笔记/StudySpringAI/.idea/compiler.xml @@ -0,0 +1,20 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/黄永兴学习笔记/StudySpringAI/.idea/encodings.xml b/黄永兴学习笔记/StudySpringAI/.idea/encodings.xml new file mode 100644 index 0000000..f822134 --- /dev/null +++ b/黄永兴学习笔记/StudySpringAI/.idea/encodings.xml @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/黄永兴学习笔记/StudySpringAI/.idea/jarRepositories.xml b/黄永兴学习笔记/StudySpringAI/.idea/jarRepositories.xml new file mode 100644 index 0000000..cd9845b --- /dev/null +++ b/黄永兴学习笔记/StudySpringAI/.idea/jarRepositories.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/黄永兴学习笔记/StudySpringAI/.idea/misc.xml b/黄永兴学习笔记/StudySpringAI/.idea/misc.xml new file mode 100644 index 0000000..75a1ef4 --- /dev/null +++ b/黄永兴学习笔记/StudySpringAI/.idea/misc.xml @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/黄永兴学习笔记/StudySpringAI/.idea/modules.xml b/黄永兴学习笔记/StudySpringAI/.idea/modules.xml new file mode 100644 index 0000000..36f3002 --- /dev/null +++ b/黄永兴学习笔记/StudySpringAI/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/黄永兴学习笔记/StudySpringAI/.idea/vcs.xml b/黄永兴学习笔记/StudySpringAI/.idea/vcs.xml new file mode 100644 index 0000000..94a25f7 --- /dev/null +++ b/黄永兴学习笔记/StudySpringAI/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/黄永兴学习笔记/StudySpringAI/SpringAIEmbedding/.gitignore b/黄永兴学习笔记/StudySpringAI/SpringAIEmbedding/.gitignore new file mode 100644 index 0000000..667aaef --- /dev/null +++ b/黄永兴学习笔记/StudySpringAI/SpringAIEmbedding/.gitignore @@ -0,0 +1,33 @@ +HELP.md +target/ +.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ diff --git a/黄永兴学习笔记/StudySpringAI/SpringAIEmbedding/.mvn/wrapper/maven-wrapper.properties b/黄永兴学习笔记/StudySpringAI/SpringAIEmbedding/.mvn/wrapper/maven-wrapper.properties new file mode 100644 index 0000000..c595b00 --- /dev/null +++ b/黄永兴学习笔记/StudySpringAI/SpringAIEmbedding/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1,3 @@ +wrapperVersion=3.3.4 +distributionType=only-script +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.14/apache-maven-3.9.14-bin.zip diff --git a/黄永兴学习笔记/StudySpringAI/SpringAIEmbedding/pom.xml b/黄永兴学习笔记/StudySpringAI/SpringAIEmbedding/pom.xml new file mode 100644 index 0000000..8ca984d --- /dev/null +++ b/黄永兴学习笔记/StudySpringAI/SpringAIEmbedding/pom.xml @@ -0,0 +1,100 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 3.5.13 + + + com.example + SpringAIEmbedding + 0.0.1-SNAPSHOT + SpringAIEmbedding + SpringAIEmbedding + + + + + + + + + + + + + + + 17 + 1.1.3 + + + + + + org.springframework.ai + spring-ai-bom + 1.0.0-SNAPSHOT + pom + import + + + + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.ai + spring-ai-starter-model-zhipuai + + + + + org.springframework.ai + spring-ai-client-chat + 1.0.0 + + + + + + + + + spring-milestones + Spring Milestones + https://repo.spring.io/milestone + + false + + + + + spring-snapshots + Spring Snapshots + https://repo.spring.io/snapshot + + false + + + true + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/黄永兴学习笔记/StudySpringAI/SpringAIEmbedding/src/main/java/com/example/springaiembedding/SpringAiEmbeddingApplication.java b/黄永兴学习笔记/StudySpringAI/SpringAIEmbedding/src/main/java/com/example/springaiembedding/SpringAiEmbeddingApplication.java new file mode 100644 index 0000000..8b2eadb --- /dev/null +++ b/黄永兴学习笔记/StudySpringAI/SpringAIEmbedding/src/main/java/com/example/springaiembedding/SpringAiEmbeddingApplication.java @@ -0,0 +1,13 @@ +package com.example.springaiembedding; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class SpringAiEmbeddingApplication { + + public static void main(String[] args) { + SpringApplication.run(SpringAiEmbeddingApplication.class, args); + } + +} diff --git a/黄永兴学习笔记/StudySpringAI/SpringAIEmbedding/src/main/java/com/example/springaiembedding/controller/EmbeddingController.java b/黄永兴学习笔记/StudySpringAI/SpringAIEmbedding/src/main/java/com/example/springaiembedding/controller/EmbeddingController.java new file mode 100644 index 0000000..e21032d --- /dev/null +++ b/黄永兴学习笔记/StudySpringAI/SpringAIEmbedding/src/main/java/com/example/springaiembedding/controller/EmbeddingController.java @@ -0,0 +1,54 @@ +package com.example.springaiembedding.controller; + +import com.example.springaiembedding.service.TextSimilarityService; +import jakarta.annotation.Resource; +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.ai.embedding.EmbeddingModel; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +import java.util.Arrays; +import java.util.Map; + +@RestController +@RequestMapping("/ai") +public class EmbeddingController { + + @Autowired + private EmbeddingModel embeddingModel; + + //对用户传入的文本进行向量化处理,测试embedding模型 + + @RequestMapping("/embedding") + public Map embedding( + @RequestParam(value = "message",defaultValue = "给我讲个笑话") String message + ){ + + // 对用户传入的文本进行向量化处理 + float[] embedding = embeddingModel.embed(message); + + return Map.of("message",message, + "vector",embedding); + } + + + @Resource + private TextSimilarityService textSimilarityService; + + /** + * 查找相似文本接口 + * @param message 查询文本 + * @return 相似文本+相似度 + */ + @GetMapping("/similarity") + public Map findSimilarText(@RequestParam String message) { + // 查询Top3相似文本 + return textSimilarityService.findSimilarTexts(message, 3); + } + + +} diff --git a/黄永兴学习笔记/StudySpringAI/SpringAIEmbedding/src/main/java/com/example/springaiembedding/controller/RagController.java b/黄永兴学习笔记/StudySpringAI/SpringAIEmbedding/src/main/java/com/example/springaiembedding/controller/RagController.java new file mode 100644 index 0000000..bdcc487 --- /dev/null +++ b/黄永兴学习笔记/StudySpringAI/SpringAIEmbedding/src/main/java/com/example/springaiembedding/controller/RagController.java @@ -0,0 +1,22 @@ +package com.example.springaiembedding.controller; + +import com.example.springaiembedding.service.RagService; +import jakarta.annotation.Resource; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + + +@RestController +@RequestMapping("/ai/rag") +public class RagController { + @Resource + private RagService ragService; + + // 问答接口 + @GetMapping("/query") + public String query(@RequestParam String question) { + return ragService.generateAnswer(question); + } +} \ No newline at end of file diff --git a/黄永兴学习笔记/StudySpringAI/SpringAIEmbedding/src/main/java/com/example/springaiembedding/service/RagService.java b/黄永兴学习笔记/StudySpringAI/SpringAIEmbedding/src/main/java/com/example/springaiembedding/service/RagService.java new file mode 100644 index 0000000..1dcbab8 --- /dev/null +++ b/黄永兴学习笔记/StudySpringAI/SpringAIEmbedding/src/main/java/com/example/springaiembedding/service/RagService.java @@ -0,0 +1,87 @@ +package com.example.springaiembedding.service; + +import com.example.springaiembedding.tool.DocumentLoader; +import jakarta.annotation.PostConstruct; +import jakarta.annotation.Resource; +import org.springframework.ai.chat.client.ChatClient; +import org.springframework.ai.chat.model.ChatModel; +import org.springframework.ai.embedding.EmbeddingModel; +import org.springframework.ai.embedding.EmbeddingResponse; +import org.springframework.stereotype.Service; + +import java.io.IOException; +import java.util.*; +import java.util.stream.Collectors; + +@Service +public class RagService { + @Resource + private EmbeddingModel embeddingModel; + @Resource + private ChatModel chatModel; + + // 内存存储:知识库片段 → 对应向量 + private Map knowledgeVectors = new HashMap<>(); + + // 项目启动时自动加载并向量化知识库 + @PostConstruct + public void initKnowledgeBase() throws IOException { + // 1. 加载并拆分文档 + List chunks = DocumentLoader.loadAndSplit("knowledge.txt"); + // 2. 批量向量化(一次请求生成所有片段向量) + EmbeddingResponse embeddingResponse = embeddingModel.embedForResponse(chunks); + // 3. 存储片段与向量的映射 + for (int i = 0; i < chunks.size(); i++) { + knowledgeVectors.put(chunks.get(i), embeddingResponse.getResults().get(i).getOutput()); + } + } + + // 检索与用户问题最相似的 Top N 片段 + private List retrieveSimilarChunks(String query, int topN) { + // 1. 用户问题向量化 + float[] queryVector = embeddingModel.embed(query); + // 2. 计算与所有知识库片段的相似度 + Map similarityMap = new HashMap<>(); + //Entry是什么?Map.Entry entry 是一个 Map.Entry 对象,用于遍历 Map 中的键值对。 + for (Map.Entry entry : knowledgeVectors.entrySet()) { + similarityMap.put(entry.getKey(), CosineSimilarityCalculator.calculate(queryVector, entry.getValue())); + } + // 3. 按相似度降序排序,取 Top N + return similarityMap.entrySet().stream() + .sorted(Collections.reverseOrder(Map.Entry.comparingByValue())) + .limit(topN) + .map(Map.Entry::getKey) + .collect(Collectors.toList()); + } + + // 生成最终回答 + public String generateAnswer(String query) { + // 1. 检索相似片段(取 Top 2) + List similarChunks = retrieveSimilarChunks(query, 2); + // 2. 拼接 Prompt(约束模型基于知识库回答) + StringBuilder prompt = new StringBuilder(); + prompt.append("请基于以下知识库内容回答用户问题,禁止编造信息:\n"); + for (String chunk : similarChunks) { + prompt.append("- ").append(chunk).append("\n"); + } + prompt.append("\n用户问题:").append(query); + // 3. 调用 Chat 模型生成回答 + ChatClient chatClient = ChatClient.builder(chatModel).build(); + return chatClient.prompt().user(prompt.toString()).call().content(); + } + + public class CosineSimilarityCalculator { + // 计算两个 float[] 向量的余弦相似度 + public static double calculate(float[] vectorA, float[] vectorB) { + double dotProduct = 0.0; + double normA = 0.0; + double normB = 0.0; + for (int i = 0; i < vectorA.length; i++) { + dotProduct += vectorA[i] * vectorB[i]; + normA += Math.pow(vectorA[i], 2); + normB += Math.pow(vectorB[i], 2); + } + return dotProduct / (Math.sqrt(normA) * Math.sqrt(normB)); + } + } +} \ No newline at end of file diff --git a/黄永兴学习笔记/StudySpringAI/SpringAIEmbedding/src/main/java/com/example/springaiembedding/service/TextSimilarityService.java b/黄永兴学习笔记/StudySpringAI/SpringAIEmbedding/src/main/java/com/example/springaiembedding/service/TextSimilarityService.java new file mode 100644 index 0000000..819acd7 --- /dev/null +++ b/黄永兴学习笔记/StudySpringAI/SpringAIEmbedding/src/main/java/com/example/springaiembedding/service/TextSimilarityService.java @@ -0,0 +1,93 @@ +package com.example.springaiembedding.service; + +import org.springframework.ai.embedding.EmbeddingModel; +import org.springframework.ai.embedding.EmbeddingResponse; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.*; +import java.util.stream.Collectors; + +@Service +public class TextSimilarityService { + + @Autowired + private EmbeddingModel embeddingModel; + + // 模拟本地文本库(可替换为数据库/向量库) + private final List TEXT_LIBRARY = Arrays.asList( + "我爱Java编程", + "SpringBoot是最流行的后端框架", + "人工智能改变世界", + "大模型应用开发", + "我喜欢学习编程", + "向量数据库用于存储Embedding", + "SpringAI简化大模型开发" + ); + + /** + * 查找最相似的文本 + * @param queryText 查询文本 + * @param topN 返回前N条结果 + * @return 相似文本+相似度 + */ + + public Map findSimilarTexts(String queryText, int topN) { + // 1. 将查询文本转为向量 + //float[] queryVector = embeddingModel.embed(queryText); + EmbeddingResponse queryEmbedding = embeddingModel.embedForResponse(List.of(queryText)); + float[] queryVector = queryEmbedding.getResults().get(0).getOutput(); + + // 2. 将文本库所有文本转为向量 + // 2. 将文本库所有文本转为向量 + Map textVectorMap = new HashMap<>(); + for (String text : TEXT_LIBRARY) { + float[] textVector = embeddingModel.embed(text); + //put是将文本和向量存储到Map中 + textVectorMap.put(text, textVector); + } + + // 3. 计算相似度并排序 + Map similarityMap = new HashMap<>(); + for (Map.Entry entry : textVectorMap.entrySet()) { + double similarity = CosineSimilarityCalculator.calculate(queryVector, entry.getValue()); + similarityMap.put(entry.getKey(), similarity); + } + + // 4. 按相似度降序排序,取TopN + return similarityMap.entrySet().stream() + .sorted(Collections.reverseOrder(Map.Entry.comparingByValue())) + .limit(topN) + .collect(Collectors.toMap( + Map.Entry::getKey, + Map.Entry::getValue, + (oldValue, newValue) -> oldValue, + LinkedHashMap::new + )); + } + + /** + * 余弦相似度工具类(计算文本向量相似度) + */ + public class CosineSimilarityCalculator { + + /** + * 计算两个向量的余弦相似度 + * @param vectorA 向量A + * @param vectorB 向量B + * @return 相似度 0~1,值越大越相似 + */ + public static double calculate(float[] vectorA, float[] vectorB) { + double dotProduct = 0.0; + double normA = 0.0; + double normB = 0.0; + + for (int i = 0; i < vectorA.length; i++) { + dotProduct += vectorA[i] * vectorB[i]; + normA += Math.pow(vectorA[i], 2); + normB += Math.pow(vectorB[i], 2); + } + return dotProduct / (Math.sqrt(normA) * Math.sqrt(normB)); + } +} +} \ No newline at end of file diff --git a/黄永兴学习笔记/StudySpringAI/SpringAIEmbedding/src/main/java/com/example/springaiembedding/tool/DocumentLoader.java b/黄永兴学习笔记/StudySpringAI/SpringAIEmbedding/src/main/java/com/example/springaiembedding/tool/DocumentLoader.java new file mode 100644 index 0000000..784bbeb --- /dev/null +++ b/黄永兴学习笔记/StudySpringAI/SpringAIEmbedding/src/main/java/com/example/springaiembedding/tool/DocumentLoader.java @@ -0,0 +1,28 @@ +package com.example.springaiembedding.tool; + +import org.springframework.core.io.ClassPathResource; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + + +// 文档加载工具类 +public class DocumentLoader { + // 加载并拆分知识库文档 + public static List loadAndSplit(String resourcePath) throws IOException { + ClassPathResource resource = new ClassPathResource(resourcePath); // 从类路径加载资源 + BufferedReader reader = new BufferedReader(new InputStreamReader(resource.getInputStream())); // 按行读取 + String content = reader.lines().collect(Collectors.joining("\n")); // 读取文件内容,将所有行连接起来一个字符串 + + // 按 "---" 拆分片段,过滤空内容 + List chunks = new ArrayList<>(); + for (String chunk : content.split("---")) { + String trimmed = chunk.trim(); + if (!trimmed.isEmpty()) chunks.add(trimmed); + } + return chunks; + } +} \ No newline at end of file diff --git a/黄永兴学习笔记/StudySpringAI/SpringAIEmbedding/src/main/resources/application.properties b/黄永兴学习笔记/StudySpringAI/SpringAIEmbedding/src/main/resources/application.properties new file mode 100644 index 0000000..2d4fc1e --- /dev/null +++ b/黄永兴学习笔记/StudySpringAI/SpringAIEmbedding/src/main/resources/application.properties @@ -0,0 +1,21 @@ +spring.application.name=SpringAIEmbedding + +server.port=8080 + +## ????AI ???? +# Embedding ?? +spring.ai.zhipuai.api-key=c721340a438942d0942148b48a22e50e.5VCKagzmQdyHpwyc +spring.ai.zhipuai.base-url=https://open.bigmodel.cn/api/paas + +# Embedding ?? +spring.ai.zhipuai.embedding-model=embedding-2 +# Chat ?? +spring.ai.zhipuai.chat.options.model=GLM-4.7-Flash + +# ?????? +logging.pattern.console=%-5level %logger - %msg%n + + + + + diff --git a/黄永兴学习笔记/StudySpringAI/SpringAIEmbedding/src/main/resources/knowledge.txt b/黄永兴学习笔记/StudySpringAI/SpringAIEmbedding/src/main/resources/knowledge.txt new file mode 100644 index 0000000..88cf6fb --- /dev/null +++ b/黄永兴学习笔记/StudySpringAI/SpringAIEmbedding/src/main/resources/knowledge.txt @@ -0,0 +1,8 @@ +--- +Spring AI 是一个用于简化大模型应用开发的框架,支持智谱AI、OpenAI 等多种大模型厂商。 +--- +智谱AI Embedding 模型可将文本转换为向量,用于语义检索、相似匹配等场景。 +--- +RAG(检索增强生成)通过检索本地知识库内容,辅助大模型生成更准确的回答,避免幻觉。 +--- +Spring AI 提供 EmbeddingModel 和 ChatModel 接口,让开发者快速接入大模型能力。 \ No newline at end of file diff --git a/黄永兴学习笔记/StudySpringAI/SpringAIEmbedding/src/test/java/com/example/springaiembedding/SpringAiEmbeddingApplicationTests.java b/黄永兴学习笔记/StudySpringAI/SpringAIEmbedding/src/test/java/com/example/springaiembedding/SpringAiEmbeddingApplicationTests.java new file mode 100644 index 0000000..b79cd15 --- /dev/null +++ b/黄永兴学习笔记/StudySpringAI/SpringAIEmbedding/src/test/java/com/example/springaiembedding/SpringAiEmbeddingApplicationTests.java @@ -0,0 +1,13 @@ +package com.example.springaiembedding; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class SpringAiEmbeddingApplicationTests { + + @Test + void contextLoads() { + } + +} diff --git a/黄永兴学习笔记/StudySpringAI/SpringAIQuickStart/.gitignore b/黄永兴学习笔记/StudySpringAI/SpringAIQuickStart/.gitignore new file mode 100644 index 0000000..667aaef --- /dev/null +++ b/黄永兴学习笔记/StudySpringAI/SpringAIQuickStart/.gitignore @@ -0,0 +1,33 @@ +HELP.md +target/ +.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ diff --git a/黄永兴学习笔记/StudySpringAI/SpringAIQuickStart/.mvn/wrapper/maven-wrapper.properties b/黄永兴学习笔记/StudySpringAI/SpringAIQuickStart/.mvn/wrapper/maven-wrapper.properties new file mode 100644 index 0000000..c595b00 --- /dev/null +++ b/黄永兴学习笔记/StudySpringAI/SpringAIQuickStart/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1,3 @@ +wrapperVersion=3.3.4 +distributionType=only-script +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.9.14/apache-maven-3.9.14-bin.zip diff --git a/黄永兴学习笔记/StudySpringAI/SpringAIQuickStart/pom.xml b/黄永兴学习笔记/StudySpringAI/SpringAIQuickStart/pom.xml new file mode 100644 index 0000000..f9ec54f --- /dev/null +++ b/黄永兴学习笔记/StudySpringAI/SpringAIQuickStart/pom.xml @@ -0,0 +1,104 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 3.5.13 + + + com.example + SpringAIQuickStart + 0.0.1-SNAPSHOT + SpringAIQuickStart + SpringAIQuickStart + + + + + + + + + + + + + + + 17 + + + + + + org.springframework.ai + spring-ai-bom + 1.0.0-SNAPSHOT + pom + import + + + + + + + org.springframework.boot + spring-boot-starter + + + + org.springframework.boot + spring-boot-starter-web + + + + + org.springframework.ai + spring-ai-starter-model-deepseek + + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + + + spring-milestones + Spring Milestones + https://repo.spring.io/milestone + + false + + + + + spring-snapshots + Spring Snapshots + https://repo.spring.io/snapshot + + false + + + true + + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + diff --git a/黄永兴学习笔记/StudySpringAI/SpringAIQuickStart/src/main/java/com/example/springaiquickstart/SpringAiQuickStartApplication.java b/黄永兴学习笔记/StudySpringAI/SpringAIQuickStart/src/main/java/com/example/springaiquickstart/SpringAiQuickStartApplication.java new file mode 100644 index 0000000..42f5322 --- /dev/null +++ b/黄永兴学习笔记/StudySpringAI/SpringAIQuickStart/src/main/java/com/example/springaiquickstart/SpringAiQuickStartApplication.java @@ -0,0 +1,13 @@ +package com.example.springaiquickstart; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class SpringAiQuickStartApplication { + + public static void main(String[] args) { + SpringApplication.run(SpringAiQuickStartApplication.class, args); + } + +} diff --git a/黄永兴学习笔记/StudySpringAI/SpringAIQuickStart/src/main/java/com/example/springaiquickstart/controller/ChatController.java b/黄永兴学习笔记/StudySpringAI/SpringAIQuickStart/src/main/java/com/example/springaiquickstart/controller/ChatController.java new file mode 100644 index 0000000..a755f92 --- /dev/null +++ b/黄永兴学习笔记/StudySpringAI/SpringAIQuickStart/src/main/java/com/example/springaiquickstart/controller/ChatController.java @@ -0,0 +1,127 @@ +package com.example.springaiquickstart.controller; + + +import jakarta.servlet.http.HttpServlet; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.ai.chat.messages.AssistantMessage; +import org.springframework.ai.chat.messages.Message; +import org.springframework.ai.chat.messages.SystemMessage; +import org.springframework.ai.chat.messages.UserMessage; +import org.springframework.ai.chat.model.ChatResponse; +import org.springframework.ai.chat.model.Generation; +import org.springframework.ai.chat.prompt.ChatOptions; +import org.springframework.ai.chat.prompt.Prompt; +import org.springframework.ai.deepseek.DeepSeekChatModel; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpRequest; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; +import reactor.core.publisher.Flux; + +import java.util.Arrays; +import java.util.List; + +@RestController +@RequestMapping("/ai") +public class ChatController { + + @Autowired + private DeepSeekChatModel chatModel; + + // 与模型直接对话,返回字符串响应 + @GetMapping("/generate") + public String generate(@RequestParam(value = "message",defaultValue = "你好,你是谁?") String message) { + System.out.println("message: " + message); + + // 与模型直接对话,调用chatModel的call方法生成响应 + String response = chatModel.call(message); + + System.out.println("response: " + response); + + return response; + } + + // 与模型对话,流式返回内容 + @GetMapping("/generateStream1") + public Flux generateStream1(@RequestParam(value = "message",defaultValue = "你好,你是谁?") String message) { + System.out.println("message: " + message); + + // 与模型对话,流式返回内容 + Prompt prompt = new Prompt(message); + Flux stream = chatModel.stream(prompt); + + System.out.println("stream: " + stream); + + return stream; + } + + // 与模型对话,流式返回内容,转换为字符串流 + // 解决中文乱码问题 + // 用lambda表达式简化 + @GetMapping("/generateStream2") + public Flux generateStream2( + @RequestParam(value = "message",defaultValue = "你好,你是谁?") String message, + HttpServletResponse response + ) { + //设置字符编码为UTF-8,解决中文乱码问题 + response.setCharacterEncoding("UTF-8"); + System.out.println("message: " + message); + + // 与模型对话,流式返回内容 + Prompt prompt = new Prompt(message); + Flux stream = chatModel.stream(prompt); + + // 转换为字符串流,用lambda表达式简化 + Flux result = stream.map(ChatResponse -> + ChatResponse.getResult().getOutput().getText() + ); + // 转换为字符串流,用方法引用简化 +// Flux result = stream.map(ChatResponse::getResult) +// .map(Generation::getOutput) +// .map(AssistantMessage::getText); + + + System.out.println("result: " + result); + + return result; + } + + //运行时设置模型参数 + @GetMapping("/runtimeOptions") + public Flux runtimeOptions( + @RequestParam(value = "message",defaultValue = "你好,你是谁?") String message, + @RequestParam(value = "temperature",required = false) Double temp, + HttpServletResponse response + ) { + //设置字符编码为UTF-8,解决中文乱码问题 + response.setCharacterEncoding("UTF-8"); + // 构建系统提示 + SystemMessage systemMessage = new SystemMessage("你是一个资深Java开发工程师,回答要简洁专业"); + // 构建用户消息 + UserMessage userMessage = new UserMessage(message); + // 构建历史消息(多轮对话时加入) + List messages = Arrays.asList(systemMessage, userMessage); + + // 封装成 Prompt,还可以设置模型参数 + Prompt prompt = new Prompt(messages, + ChatOptions.builder() + .temperature(temp) + .maxTokens(1000) + .build() + ); + + // 流式调用 + Flux stream = chatModel.stream(prompt); + // 转换为字符串流,用lambda表达式简化 + Flux result = stream.map(ChatResponse -> + ChatResponse.getResult().getOutput().getText() + ); + + System.out.println("result: " + result); + return result; + } + + +} diff --git a/黄永兴学习笔记/StudySpringAI/SpringAIQuickStart/src/main/resources/application.properties b/黄永兴学习笔记/StudySpringAI/SpringAIQuickStart/src/main/resources/application.properties new file mode 100644 index 0000000..04b888c --- /dev/null +++ b/黄永兴学习笔记/StudySpringAI/SpringAIQuickStart/src/main/resources/application.properties @@ -0,0 +1,13 @@ +spring.application.name=SpringAIQuickStart + +server.port=8080 + +#?? Deepseek ???????url????????? +spring.ai.deepseek.base-url=https://api.deepseek.com +spring.ai.deepseek.api-key=sk-ccbfe09f433148129cd98df6150653e8 +spring.ai.deepseek.chat.options.model=deepseek-chat + +#??0-2???0????????2??????? +spring.ai.deepseek.chat.options.temperature=0.8 + + diff --git a/黄永兴学习笔记/StudySpringAI/SpringAIQuickStart/src/main/resources/static/index.html b/黄永兴学习笔记/StudySpringAI/SpringAIQuickStart/src/main/resources/static/index.html new file mode 100644 index 0000000..b15dd6d --- /dev/null +++ b/黄永兴学习笔记/StudySpringAI/SpringAIQuickStart/src/main/resources/static/index.html @@ -0,0 +1,224 @@ + + + + + + Spring AI 聊天助手 + + + + + + + + + + + + Spring AI 聊天助手 + + + + + 在线 + + + + + + + + + + + + AI 助手 + 基于 DeepSeek 模型 + + + + + + + + + + + + AI 助手 + 你好!我是基于 DeepSeek 模型的 AI 助手,有什么可以帮助你的吗? + + + + + + + + + + + 发送 + + + + + + + + + 功能说明 + + + + 支持自然语言对话 + + + + 基于 DeepSeek 大语言模型 + + + + 实时响应生成 + + + + 简洁美观的用户界面 + + + + + + + + + + + \ No newline at end of file diff --git a/黄永兴学习笔记/StudySpringAI/SpringAIQuickStart/src/test/java/com/example/springaiquickstart/SpringAiQuickStartApplicationTests.java b/黄永兴学习笔记/StudySpringAI/SpringAIQuickStart/src/test/java/com/example/springaiquickstart/SpringAiQuickStartApplicationTests.java new file mode 100644 index 0000000..85ad504 --- /dev/null +++ b/黄永兴学习笔记/StudySpringAI/SpringAIQuickStart/src/test/java/com/example/springaiquickstart/SpringAiQuickStartApplicationTests.java @@ -0,0 +1,13 @@ +package com.example.springaiquickstart; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class SpringAiQuickStartApplicationTests { + + @Test + void contextLoads() { + } + +} diff --git a/黄永兴学习笔记/StudySpringAI/StudySpringAI.iml b/黄永兴学习笔记/StudySpringAI/StudySpringAI.iml new file mode 100644 index 0000000..9a5cfce --- /dev/null +++ b/黄永兴学习笔记/StudySpringAI/StudySpringAI.iml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file
基于 DeepSeek 模型
AI 助手
你好!我是基于 DeepSeek 模型的 AI 助手,有什么可以帮助你的吗?