commit 0d15e2078071161dcd70c864a6d3fe21f30a5eb2 Author: userpu <565599455@qq.com> Date: Wed Dec 17 19:47:14 2025 +0800 Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5ff6309 --- /dev/null +++ b/.gitignore @@ -0,0 +1,38 @@ +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### IntelliJ IDEA ### +.idea/modules.xml +.idea/jarRepositories.xml +.idea/compiler.xml +.idea/libraries/ +*.iws +*.iml +*.ipr + +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store \ No newline at end of file diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..7d05e99 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,10 @@ +# 默认忽略的文件 +/shelf/ +/workspace.xml +# 基于编辑器的 HTTP 客户端请求 +/httpRequests/ +# 依赖于环境的 Maven 主目录路径 +/mavenHomeManager.xml +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/dataSources.xml b/.idea/dataSources.xml new file mode 100644 index 0000000..3508924 --- /dev/null +++ b/.idea/dataSources.xml @@ -0,0 +1,17 @@ + + + + + mysql.8 + true + com.mysql.cj.jdbc.Driver + jdbc:mysql://localhost:3306/langchain4j + + + + + + $ProjectFileDir$ + + + \ No newline at end of file diff --git a/.idea/encodings.xml b/.idea/encodings.xml new file mode 100644 index 0000000..eb5644e --- /dev/null +++ b/.idea/encodings.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..82dbec8 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,14 @@ + + + + + + + + + + \ No newline at end of file diff --git a/langchain4j-ai-helloworld/pom.xml b/langchain4j-ai-helloworld/pom.xml new file mode 100644 index 0000000..82ee066 --- /dev/null +++ b/langchain4j-ai-helloworld/pom.xml @@ -0,0 +1,46 @@ + + + 4.0.0 + + com.iwe3 + langchain4j-ai-java + 1.0-SNAPSHOT + + + langchain4j-ai-helloworld + jar + + 17 + 17 + UTF-8 + + + + + org.springframework.boot + spring-boot-starter-web + + + dev.langchain4j + langchain4j-open-ai + + + dev.langchain4j + langchain4j + + + org.projectlombok + lombok + true + + + + org.springframework.boot + spring-boot-starter-test + test + + + + \ No newline at end of file diff --git a/langchain4j-ai-helloworld/src/main/java/com/iwe3/langchain4j/HelloworldApplication.java b/langchain4j-ai-helloworld/src/main/java/com/iwe3/langchain4j/HelloworldApplication.java new file mode 100644 index 0000000..2d2fb57 --- /dev/null +++ b/langchain4j-ai-helloworld/src/main/java/com/iwe3/langchain4j/HelloworldApplication.java @@ -0,0 +1,12 @@ +package com.iwe3.langchain4j; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class HelloworldApplication { + + public static void main(String[] args) { + SpringApplication.run(HelloworldApplication.class,args); + } +} diff --git a/langchain4j-ai-helloworld/src/main/java/com/iwe3/langchain4j/config/LLMConfig.java b/langchain4j-ai-helloworld/src/main/java/com/iwe3/langchain4j/config/LLMConfig.java new file mode 100644 index 0000000..f2fcc21 --- /dev/null +++ b/langchain4j-ai-helloworld/src/main/java/com/iwe3/langchain4j/config/LLMConfig.java @@ -0,0 +1,19 @@ +package com.iwe3.langchain4j.config; + +import dev.langchain4j.model.chat.ChatModel; +import dev.langchain4j.model.openai.OpenAiChatModel; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class LLMConfig { + @Bean + public ChatModel chatModelQwen(){ + return OpenAiChatModel.builder() + .apiKey(System.getenv("DASH_SCOPE_API_KEY")) + .modelName("qwen-plus") + .baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1") + .build(); + } + +} diff --git a/langchain4j-ai-helloworld/src/main/java/com/iwe3/langchain4j/controller/LangChain4JController.java b/langchain4j-ai-helloworld/src/main/java/com/iwe3/langchain4j/controller/LangChain4JController.java new file mode 100644 index 0000000..c1259a6 --- /dev/null +++ b/langchain4j-ai-helloworld/src/main/java/com/iwe3/langchain4j/controller/LangChain4JController.java @@ -0,0 +1,26 @@ +package com.iwe3.langchain4j.controller; + +import dev.langchain4j.model.chat.ChatModel; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@Slf4j +public class LangChain4JController +{ + // http://localhost:9001/langchain4j/hello?question=如何学习LangChain4J + + @Resource + private ChatModel chatModel; + + @GetMapping(value = "/langchain4j/hello") + public String hello(@RequestParam(value = "question",defaultValue = "你是谁") String question) + { + var result = chatModel.chat(question); + System.out.println("通过langchain4j调用模型返回结果:\n"+result); + return result; + } +} \ No newline at end of file diff --git a/langchain4j-ai-helloworld/src/main/resources/application.yml b/langchain4j-ai-helloworld/src/main/resources/application.yml new file mode 100644 index 0000000..08e8cce --- /dev/null +++ b/langchain4j-ai-helloworld/src/main/resources/application.yml @@ -0,0 +1,5 @@ +server: + port: 9001 +spring: + application: + name: langchain4j-ai-helloworld \ No newline at end of file diff --git a/langchain4j-ai-image/pom.xml b/langchain4j-ai-image/pom.xml new file mode 100644 index 0000000..87f72fe --- /dev/null +++ b/langchain4j-ai-image/pom.xml @@ -0,0 +1,49 @@ + + + 4.0.0 + + com.iwe3 + langchain4j-ai-java + 1.0-SNAPSHOT + + + langchain4j-ai-image + + + 17 + 17 + UTF-8 + + + + + dev.langchain4j + langchain4j-community-dashscope-spring-boot-starter + + + org.projectlombok + lombok + true + + + org.springframework.boot + spring-boot-starter-web + + + + dev.langchain4j + langchain4j-open-ai-spring-boot-starter + 1.9.1-beta17 + + + + dev.langchain4j + langchain4j-spring-boot-starter + 1.9.1-beta17 + + + \ No newline at end of file diff --git a/langchain4j-ai-image/src/main/java/com/iwe3/langchain4j/ImageApplication.java b/langchain4j-ai-image/src/main/java/com/iwe3/langchain4j/ImageApplication.java new file mode 100644 index 0000000..7aa5cb4 --- /dev/null +++ b/langchain4j-ai-image/src/main/java/com/iwe3/langchain4j/ImageApplication.java @@ -0,0 +1,13 @@ +package com.iwe3.langchain4j; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class ImageApplication { + + public static void main(String[] args) { + SpringApplication.run(ImageApplication.class,args); + } + +} diff --git a/langchain4j-ai-image/src/main/java/com/iwe3/langchain4j/config/LLMConfig.java b/langchain4j-ai-image/src/main/java/com/iwe3/langchain4j/config/LLMConfig.java new file mode 100644 index 0000000..0de0cdf --- /dev/null +++ b/langchain4j-ai-image/src/main/java/com/iwe3/langchain4j/config/LLMConfig.java @@ -0,0 +1,34 @@ +package com.iwe3.langchain4j.config; + +import dev.langchain4j.community.model.dashscope.WanxImageModel; +import dev.langchain4j.model.chat.ChatModel; +import dev.langchain4j.model.openai.OpenAiChatModel; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class LLMConfig +{ + @Bean + public ChatModel ImageModel() { + return OpenAiChatModel.builder() + .apiKey(System.getenv("DASH_SCOPE_API_KEY")) + //qwen-vl-max 是一个多模态大模型,支持图片和文本的结合输入,适用于视觉-语言任务。 + .modelName("qwen-vl-max") + .baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1") + .build(); + } + + /** + * @Description: 测试通义万象来实现图片生成, + * 知识出处,https://help.aliyun.com/zh/model-studio/text-to-image + */ + @Bean + public WanxImageModel wanxImageModel() + { + return WanxImageModel.builder() + .apiKey(System.getenv("DASH_SCOPE_API_KEY")) + .modelName("wanx2.1-t2i-turbo") //图片生成 https://help.aliyun.com/zh/model-studio/text-to-image + .build(); + } +} diff --git a/langchain4j-ai-image/src/main/java/com/iwe3/langchain4j/controller/ImageModelController.java b/langchain4j-ai-image/src/main/java/com/iwe3/langchain4j/controller/ImageModelController.java new file mode 100644 index 0000000..cbd8c03 --- /dev/null +++ b/langchain4j-ai-image/src/main/java/com/iwe3/langchain4j/controller/ImageModelController.java @@ -0,0 +1,62 @@ +package com.iwe3.langchain4j.controller; + +import dev.langchain4j.data.message.ImageContent; +import dev.langchain4j.data.message.TextContent; +import dev.langchain4j.data.message.UserMessage; +import dev.langchain4j.model.chat.ChatModel; +import dev.langchain4j.model.chat.response.ChatResponse; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.core.io.Resource; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.io.IOException; +import java.util.Base64; + +@RestController +@Slf4j +public class ImageModelController +{ + @Autowired + private ChatModel ImageModel; + + @Value("classpath:static/imgs/1.png") + private Resource resource;//import org.springframework.core.io.Resource; + + /** + * @Description: + * 通过Base64编码将图片转化为字符串 + * 结合ImageContent和TextContent形成UserMessage一起发送到模型进行处理。 + * + *测试地址:http://localhost:9005/lc4j/image/call + */ + @GetMapping(value = "/lc4j/image/call") + public String readImageContent() throws IOException + { + String result = null; + + //第一步,图片转码:通过Base64编码将图片转化为字符串 + byte[] byteArray = resource.getContentAsByteArray(); + String base64Data = Base64.getEncoder().encodeToString(byteArray); + + //第二步,提示词指定:结合ImageContent和TextContent一起发送到模型进行处理。 + UserMessage userMessage = UserMessage.from( + TextContent.from("她是谁?"), + ImageContent.from(base64Data, "image/jpg") + ); + //第三步,API调用:使用OpenAiChatModel来构建请求,并通过chat()方法调用模型。 + //请求内容包括文本提示和图片,模型会根据输入返回分析结果。 + ChatResponse chatResponse = ImageModel.chat(userMessage); + + //第四步,解析与输出:从ChatResponse中获取AI大模型的回复,打印出处理后的结果。 + result = chatResponse.aiMessage().text(); + + //后台打印 + System.out.println(result); + + //返回前台 + return result; + } +} diff --git a/langchain4j-ai-image/src/main/java/com/iwe3/langchain4j/controller/WanxImageModelController.java b/langchain4j-ai-image/src/main/java/com/iwe3/langchain4j/controller/WanxImageModelController.java new file mode 100644 index 0000000..03512cc --- /dev/null +++ b/langchain4j-ai-image/src/main/java/com/iwe3/langchain4j/controller/WanxImageModelController.java @@ -0,0 +1,71 @@ +package com.iwe3.langchain4j.controller; + +import com.alibaba.dashscope.aigc.imagesynthesis.ImageSynthesis; +import com.alibaba.dashscope.aigc.imagesynthesis.ImageSynthesisParam; +import com.alibaba.dashscope.aigc.imagesynthesis.ImageSynthesisResult; +import com.alibaba.dashscope.exception.ApiException; +import com.alibaba.dashscope.exception.NoApiKeyException; +import com.alibaba.dashscope.utils.JsonUtils; +import dev.langchain4j.community.model.dashscope.WanxImageModel; +import dev.langchain4j.data.image.Image; +import dev.langchain4j.model.output.Response; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.io.IOException; + + +@RestController +@Slf4j +public class WanxImageModelController +{ + @Autowired + private WanxImageModel wanxImageModel; + + // http://localhost:9005/lc4j/image/create + @GetMapping(value = "/lc4j/image/create") + public String createImageContent() throws IOException + { + System.out.println(wanxImageModel); + var imageResponse = wanxImageModel.generate("美女"); + System.out.println(imageResponse.content().url()); + return imageResponse.content().url().toString(); + + } + + // http://localhost:9005/lc4j/image/create2 + @GetMapping(value = "/lc4j/image/create2") + public String createImageContent2() throws IOException + { + + var prompt = "近景镜头,18岁的中国女孩,古代服饰,圆脸,正面看着镜头," + + "民族优雅的服装,商业摄影,室外,电影级光照,半身特写,精致的淡妆,锐利的边缘。"; + var param = + ImageSynthesisParam.builder() + .apiKey(System.getenv("DASH_SCOPE_API_KEY")) + .model(ImageSynthesis.Models.WANX_V1) + .prompt(prompt) + .style("") + .n(1) + .size("1024*1024") + .build(); + + var imageSynthesis = new ImageSynthesis(); + ImageSynthesisResult result = null; + + try { + System.out.println("---sync call, please wait a moment----"); + + result = imageSynthesis.call(param); + } catch (ApiException | NoApiKeyException e){ + throw new RuntimeException(e.getMessage()); + } + + + System.out.println(JsonUtils.toJson(result)); + + return JsonUtils.toJson(result); + } +} diff --git a/langchain4j-ai-image/src/main/resources/application.yml b/langchain4j-ai-image/src/main/resources/application.yml new file mode 100644 index 0000000..fe4ccc6 --- /dev/null +++ b/langchain4j-ai-image/src/main/resources/application.yml @@ -0,0 +1,5 @@ +server: + port: 9005 +spring: + application: + name: langchain4j-ai-image \ No newline at end of file diff --git a/langchain4j-ai-image/src/main/resources/static/imgs/1.png b/langchain4j-ai-image/src/main/resources/static/imgs/1.png new file mode 100644 index 0000000..d3472d7 Binary files /dev/null and b/langchain4j-ai-image/src/main/resources/static/imgs/1.png differ diff --git a/langchain4j-ai-image/src/main/resources/static/imgs/2.png b/langchain4j-ai-image/src/main/resources/static/imgs/2.png new file mode 100644 index 0000000..7598a5b Binary files /dev/null and b/langchain4j-ai-image/src/main/resources/static/imgs/2.png differ diff --git a/langchain4j-ai-low-high-api/pom.xml b/langchain4j-ai-low-high-api/pom.xml new file mode 100644 index 0000000..9d79456 --- /dev/null +++ b/langchain4j-ai-low-high-api/pom.xml @@ -0,0 +1,42 @@ + + + 4.0.0 + + com.iwe3 + langchain4j-ai-java + 1.0-SNAPSHOT + + + langchain4j-ai-low-high-api + + + 17 + 17 + UTF-8 + + + + org.projectlombok + lombok + true + + + org.springframework.boot + spring-boot-starter-web + + + + dev.langchain4j + langchain4j-open-ai-spring-boot-starter + 1.9.1-beta17 + + + + dev.langchain4j + langchain4j-spring-boot-starter + 1.9.1-beta17 + + + \ No newline at end of file diff --git a/langchain4j-ai-low-high-api/src/main/java/com/iwe3/langchain4j/LowHighApplication.java b/langchain4j-ai-low-high-api/src/main/java/com/iwe3/langchain4j/LowHighApplication.java new file mode 100644 index 0000000..3ab76b3 --- /dev/null +++ b/langchain4j-ai-low-high-api/src/main/java/com/iwe3/langchain4j/LowHighApplication.java @@ -0,0 +1,12 @@ +package com.iwe3.langchain4j; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class LowHighApplication { + + public static void main(String[] args) { + SpringApplication.run(LowHighApplication.class,args); + } +} diff --git a/langchain4j-ai-low-high-api/src/main/java/com/iwe3/langchain4j/config/LLMConfig.java b/langchain4j-ai-low-high-api/src/main/java/com/iwe3/langchain4j/config/LLMConfig.java new file mode 100644 index 0000000..b9e868b --- /dev/null +++ b/langchain4j-ai-low-high-api/src/main/java/com/iwe3/langchain4j/config/LLMConfig.java @@ -0,0 +1,37 @@ +package com.iwe3.langchain4j.config; + +import dev.langchain4j.model.chat.ChatModel; +import dev.langchain4j.model.openai.OpenAiChatModel; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class LLMConfig { + + @Bean(name = "qwen") + public ChatModel chatModelQwen(){ + /*大模型3件套:apikey ,model-name,base-url */ + return OpenAiChatModel.builder() + .apiKey(System.getenv("DASH_SCOPE_API_KEY")) + .modelName("qwen-plus") + .baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1") + .build(); + } + + /** + * @Description: + * 知识出处,https://api-docs.deepseek.com/zh-cn/ + */ + @Bean(name = "deepseek") + public ChatModel chatModelDeepSeek() + { + return + OpenAiChatModel.builder() + .apiKey(System.getenv("DEEP_SEEK_API_KEY")) + .modelName("deepseek-chat") + //.modelName("deepseek-reasoner") + .baseUrl("https://api.deepseek.com/v1") + .build(); + } + +} diff --git a/langchain4j-ai-low-high-api/src/main/java/com/iwe3/langchain4j/controller/HighLevelController.java b/langchain4j-ai-low-high-api/src/main/java/com/iwe3/langchain4j/controller/HighLevelController.java new file mode 100644 index 0000000..482815f --- /dev/null +++ b/langchain4j-ai-low-high-api/src/main/java/com/iwe3/langchain4j/controller/HighLevelController.java @@ -0,0 +1,21 @@ +package com.iwe3.langchain4j.controller; + +import com.iwe3.langchain4j.service.ChatAssistant; +import jakarta.annotation.Resource; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class HighLevelController { + + @Resource + private ChatAssistant chatAssistant; + + // http://localhost:9003/lc4j/boot/declarative?prompt=我是谁 + @GetMapping(value = "/lc4j/boot/declarative") + public String declarative(@RequestParam(value = "prompt", defaultValue = "你是谁") String prompt) + { + return chatAssistant.chat(prompt); + } +} diff --git a/langchain4j-ai-low-high-api/src/main/java/com/iwe3/langchain4j/controller/LowLevelController.java b/langchain4j-ai-low-high-api/src/main/java/com/iwe3/langchain4j/controller/LowLevelController.java new file mode 100644 index 0000000..3176975 --- /dev/null +++ b/langchain4j-ai-low-high-api/src/main/java/com/iwe3/langchain4j/controller/LowLevelController.java @@ -0,0 +1,41 @@ +package com.iwe3.langchain4j.controller; + +import dev.langchain4j.data.message.UserMessage; +import dev.langchain4j.model.chat.ChatModel; +import dev.langchain4j.model.chat.response.ChatResponse; +import dev.langchain4j.model.output.TokenUsage; +import jakarta.annotation.Resource; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +@RestController +public class LowLevelController { + + @Resource(name = "qwen") + private ChatModel chatModel; + + // http://localhost:9003/lc4j/lowapi/api01?prompt=我是谁 + @GetMapping(value = "/lc4j/lowapi/api01") + public String api01(@RequestParam(value = "prompt", defaultValue = "你是谁") String prompt) + { + return chatModel.chat(prompt); + } + + // http://localhost:9003/lc4j/lowapi/api02?prompt=我是谁 + @GetMapping(value = "/lc4j/lowapi/api02") + public String api02(@RequestParam(value = "prompt", defaultValue = "你是谁") String prompt) + { + ChatResponse chatResponse = chatModel.chat(UserMessage.from(prompt)); + + String result = chatResponse.aiMessage().text(); + System.out.println("通过调用大模型返回结果:"+result); + + // Token 用量计算的底层api + TokenUsage tokenUsage = chatResponse.tokenUsage(); + System.out.println("本次调用消耗的token:"+tokenUsage); + result = result +"\t\n"+tokenUsage; + + return result; + } +} diff --git a/langchain4j-ai-low-high-api/src/main/java/com/iwe3/langchain4j/service/ChatAssistant.java b/langchain4j-ai-low-high-api/src/main/java/com/iwe3/langchain4j/service/ChatAssistant.java new file mode 100644 index 0000000..5fdd791 --- /dev/null +++ b/langchain4j-ai-low-high-api/src/main/java/com/iwe3/langchain4j/service/ChatAssistant.java @@ -0,0 +1,14 @@ +package com.iwe3.langchain4j.service; + +import dev.langchain4j.service.spring.AiService; +import dev.langchain4j.service.spring.AiServiceWiringMode; + +/** + * 知识出处: + * https://docs.langchain4j.dev/tutorials/spring-boot-integration/#spring-boot-starter-for-declarative-ai-services + */ +@AiService(wiringMode = AiServiceWiringMode.EXPLICIT +,chatModel = "qwen") +public interface ChatAssistant { + String chat(String prompt); +} diff --git a/langchain4j-ai-low-high-api/src/main/resources/application.yml b/langchain4j-ai-low-high-api/src/main/resources/application.yml new file mode 100644 index 0000000..1eae114 --- /dev/null +++ b/langchain4j-ai-low-high-api/src/main/resources/application.yml @@ -0,0 +1,5 @@ +server: + port: 9003 +spring: + application: + name: langchain4j-ai-low-level \ No newline at end of file diff --git a/langchain4j-ai-memory/pom.xml b/langchain4j-ai-memory/pom.xml new file mode 100644 index 0000000..4fa026a --- /dev/null +++ b/langchain4j-ai-memory/pom.xml @@ -0,0 +1,52 @@ + + + 4.0.0 + + com.iwe3 + langchain4j-ai-java + 1.0-SNAPSHOT + + + langchain4j-ai-memory + + + 17 + 17 + UTF-8 + + + + + dev.langchain4j + langchain4j-reactor + 1.9.1-beta17 + + + org.projectlombok + lombok + true + + + org.springframework.boot + spring-boot-starter-web + + + + dev.langchain4j + langchain4j-open-ai-spring-boot-starter + 1.9.1-beta17 + + + + dev.langchain4j + langchain4j-spring-boot-starter + 1.9.1-beta17 + + + org.springframework.boot + spring-boot-starter-test + + + \ No newline at end of file diff --git a/langchain4j-ai-memory/src/main/java/com/iwe3/langchain4j/MemoryApplication.java b/langchain4j-ai-memory/src/main/java/com/iwe3/langchain4j/MemoryApplication.java new file mode 100644 index 0000000..775a0a8 --- /dev/null +++ b/langchain4j-ai-memory/src/main/java/com/iwe3/langchain4j/MemoryApplication.java @@ -0,0 +1,12 @@ +package com.iwe3.langchain4j; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class MemoryApplication { + + public static void main(String[] args) { + SpringApplication.run(MemoryApplication.class,args); + } +} diff --git a/langchain4j-ai-memory/src/main/java/com/iwe3/langchain4j/config/LLMConfig.java b/langchain4j-ai-memory/src/main/java/com/iwe3/langchain4j/config/LLMConfig.java new file mode 100644 index 0000000..c1f56fc --- /dev/null +++ b/langchain4j-ai-memory/src/main/java/com/iwe3/langchain4j/config/LLMConfig.java @@ -0,0 +1,23 @@ +package com.iwe3.langchain4j.config; + +import dev.langchain4j.model.chat.ChatModel; +import dev.langchain4j.model.openai.OpenAiChatModel; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class LLMConfig { + + /** + * @Description: 普通对话接口 ChatModel + */ + @Bean(name = "qwen") + public ChatModel chatModelQwen() + { + return OpenAiChatModel.builder() + .apiKey(System.getenv("DASH_SCOPE_API_KEY")) + .modelName("qwen-plus") + .baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1") + .build(); + } +} diff --git a/langchain4j-ai-memory/src/main/java/com/iwe3/langchain4j/config/MemoryChatAssistantConfig.java b/langchain4j-ai-memory/src/main/java/com/iwe3/langchain4j/config/MemoryChatAssistantConfig.java new file mode 100644 index 0000000..c82f520 --- /dev/null +++ b/langchain4j-ai-memory/src/main/java/com/iwe3/langchain4j/config/MemoryChatAssistantConfig.java @@ -0,0 +1,19 @@ +package com.iwe3.langchain4j.config; + +import dev.langchain4j.memory.ChatMemory; +import dev.langchain4j.memory.chat.MessageWindowChatMemory; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class MemoryChatAssistantConfig { + + + + //@Bean -> 向IOC容器中注入 chatMemory 的实例 + @Bean + ChatMemory windowChatMemory() { + // 设置聊天记忆记录的message数量 + return MessageWindowChatMemory.withMaxMessages(10); + } +} diff --git a/langchain4j-ai-memory/src/main/java/com/iwe3/langchain4j/config/SeparateChatAssistantConfig.java b/langchain4j-ai-memory/src/main/java/com/iwe3/langchain4j/config/SeparateChatAssistantConfig.java new file mode 100644 index 0000000..91a05e9 --- /dev/null +++ b/langchain4j-ai-memory/src/main/java/com/iwe3/langchain4j/config/SeparateChatAssistantConfig.java @@ -0,0 +1,26 @@ +package com.iwe3.langchain4j.config; + +import dev.langchain4j.memory.chat.ChatMemoryProvider; +import dev.langchain4j.memory.chat.MessageWindowChatMemory; +import dev.langchain4j.store.memory.chat.InMemoryChatMemoryStore; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class SeparateChatAssistantConfig { + + /** + * 聊天记忆提供器 + * 配置:采用memoryId来完成隔离 + * @return + */ + @Bean + ChatMemoryProvider chatMemoryProvider() { + return memoryId -> MessageWindowChatMemory.builder() + .id(memoryId) + .maxMessages(10).chatMemoryStore(new InMemoryChatMemoryStore()) + .build(); + //如果未来想自定义 -> 则自己写一个类实现 ChatMemoryStore + } + +} diff --git a/langchain4j-ai-memory/src/main/java/com/iwe3/langchain4j/service/ChatAssistant.java b/langchain4j-ai-memory/src/main/java/com/iwe3/langchain4j/service/ChatAssistant.java new file mode 100644 index 0000000..72d4d45 --- /dev/null +++ b/langchain4j-ai-memory/src/main/java/com/iwe3/langchain4j/service/ChatAssistant.java @@ -0,0 +1,20 @@ +package com.iwe3.langchain4j.service; + +import dev.langchain4j.service.spring.AiService; +import dev.langchain4j.service.spring.AiServiceWiringMode; + +/** + * 知识出处: + * https://docs.langchain4j.dev/tutorials/spring-boot-integration/#spring-boot-starter-for-declarative-ai-services + * chatMemory = "chatMemory" 则表示:使用ChatMemory来完成聊天记忆 + */ +@AiService(wiringMode = AiServiceWiringMode.EXPLICIT +,chatModel = "qwen",chatMemory = "windowChatMemory") +public interface ChatAssistant { + /** + * 普通聊天 + * @param prompt + * @return + */ + String chat(String prompt); +} diff --git a/langchain4j-ai-memory/src/main/java/com/iwe3/langchain4j/service/SeparateChatAssistant.java b/langchain4j-ai-memory/src/main/java/com/iwe3/langchain4j/service/SeparateChatAssistant.java new file mode 100644 index 0000000..ff4222d --- /dev/null +++ b/langchain4j-ai-memory/src/main/java/com/iwe3/langchain4j/service/SeparateChatAssistant.java @@ -0,0 +1,22 @@ +package com.iwe3.langchain4j.service; + +import dev.langchain4j.service.MemoryId; +import dev.langchain4j.service.UserMessage; +import dev.langchain4j.service.spring.AiService; +import dev.langchain4j.service.spring.AiServiceWiringMode; + +@AiService( + wiringMode = AiServiceWiringMode.EXPLICIT, + chatModel = "qwen", + chatMemoryProvider = "chatMemoryProvider" +) +public interface SeparateChatAssistant { + + /** + * 分离聊天记录 + * @param memoryId 聊天id + * @param userMessage 用户消息 + * @return + */ + String chat(@MemoryId int memoryId, @UserMessage String userMessage); +} diff --git a/langchain4j-ai-memory/src/main/resources/application.yml b/langchain4j-ai-memory/src/main/resources/application.yml new file mode 100644 index 0000000..a71688f --- /dev/null +++ b/langchain4j-ai-memory/src/main/resources/application.yml @@ -0,0 +1,10 @@ +server: + port: 9007 + servlet: + encoding: + charset: utf-8 + enabled: true + force: true # 设置响应的字符编码,避免流式返回输出乱码 +spring: + application: + name: langchain4j-ai-memory \ No newline at end of file diff --git a/langchain4j-ai-memory/src/test/java/com/iwe3/langchain4j/MemoryApplicationTest.java b/langchain4j-ai-memory/src/test/java/com/iwe3/langchain4j/MemoryApplicationTest.java new file mode 100644 index 0000000..56417c4 --- /dev/null +++ b/langchain4j-ai-memory/src/test/java/com/iwe3/langchain4j/MemoryApplicationTest.java @@ -0,0 +1,51 @@ +package com.iwe3.langchain4j; + +import com.iwe3.langchain4j.service.ChatAssistant; +import dev.langchain4j.data.message.UserMessage; +import dev.langchain4j.model.chat.ChatModel; +import jakarta.annotation.Resource; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class MemoryApplicationTest { + + @Resource(name="qwen") + private ChatModel chatModel; + + @Test + public void testLowerLevel(){ + + // 第一轮对话 + var um01 = UserMessage.userMessage("我是蒲哥"); + var res01 = chatModel.chat(um01); + var am01 = res01.aiMessage(); + // 输出大语言模型的回复 + System.out.println(am01.text()); + + // 第二轮对话 + var um02 = UserMessage.userMessage("你知道我是谁吗"); + //将第一轮对话记录,也一起发给 LLM + var res02 = chatModel.chat(um02); + + var am02 = res02.aiMessage(); + // 输出大语言模型的回复 + System.out.println(am02.text()); + } + + + + @Autowired + private ChatAssistant chatAssistant; + @Test + public void testHighLevel(){ + var res = chatAssistant.chat("我是蒲哥"); + System.out.println("res = " + res); + res = chatAssistant.chat("我是谁?"); + System.out.println("res = " + res); + } + + + +} \ No newline at end of file diff --git a/langchain4j-ai-memory/src/test/java/com/iwe3/langchain4j/SeparateChatTest.java b/langchain4j-ai-memory/src/test/java/com/iwe3/langchain4j/SeparateChatTest.java new file mode 100644 index 0000000..497b126 --- /dev/null +++ b/langchain4j-ai-memory/src/test/java/com/iwe3/langchain4j/SeparateChatTest.java @@ -0,0 +1,30 @@ +package com.iwe3.langchain4j; + +import com.iwe3.langchain4j.service.SeparateChatAssistant; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +public class SeparateChatTest { + + @Autowired + private SeparateChatAssistant separateChatAssistant; + + @Test + public void testSeparateChatMemory() { + // 用户1的对话 + var res = separateChatAssistant.chat(1, "我是蒲哥"); + System.out.println(res); + res = separateChatAssistant.chat(1, "你知道我是谁吗"); + System.out.println(res); + + // 用户2的对话 + var res02 = separateChatAssistant.chat(2, "我是小明"); + System.out.println(res02); + res02 = separateChatAssistant.chat(2, "我叫什么名字"); + System.out.println(res02); + } + + +} diff --git a/langchain4j-ai-model-params/pom.xml b/langchain4j-ai-model-params/pom.xml new file mode 100644 index 0000000..b308542 --- /dev/null +++ b/langchain4j-ai-model-params/pom.xml @@ -0,0 +1,51 @@ + + + 4.0.0 + + com.iwe3 + langchain4j-ai-java + 1.0-SNAPSHOT + + + langchain4j-ai-model-params + + + 17 + 17 + UTF-8 + + + + ch.qos.logback + logback-classic + + + cn.hutool + hutool-all + 5.8.39 + + + org.projectlombok + lombok + true + + + org.springframework.boot + spring-boot-starter-web + + + + dev.langchain4j + langchain4j-open-ai-spring-boot-starter + 1.9.1-beta17 + + + + dev.langchain4j + langchain4j-spring-boot-starter + 1.9.1-beta17 + + + \ No newline at end of file diff --git a/langchain4j-ai-model-params/src/main/java/com/iwe3/langchain4j/ModelParamsApplication.java b/langchain4j-ai-model-params/src/main/java/com/iwe3/langchain4j/ModelParamsApplication.java new file mode 100644 index 0000000..002fdb0 --- /dev/null +++ b/langchain4j-ai-model-params/src/main/java/com/iwe3/langchain4j/ModelParamsApplication.java @@ -0,0 +1,12 @@ +package com.iwe3.langchain4j; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class ModelParamsApplication { + + public static void main(String[] args) { + SpringApplication.run(ModelParamsApplication.class,args); + } +} diff --git a/langchain4j-ai-model-params/src/main/java/com/iwe3/langchain4j/config/LLMConfig.java b/langchain4j-ai-model-params/src/main/java/com/iwe3/langchain4j/config/LLMConfig.java new file mode 100644 index 0000000..7093646 --- /dev/null +++ b/langchain4j-ai-model-params/src/main/java/com/iwe3/langchain4j/config/LLMConfig.java @@ -0,0 +1,45 @@ +package com.iwe3.langchain4j.config; + +import com.iwe3.langchain4j.listener.UserpuChatModelListener; +import dev.langchain4j.model.chat.ChatModel; +import dev.langchain4j.model.openai.OpenAiChatModel; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import java.time.Duration; +import java.util.List; + +@Configuration +public class LLMConfig { + + @Bean(name = "qwen") + public ChatModel chatModelQwen(){ + /*模型3件套:apikey - modelName - baseUrl */ + return OpenAiChatModel.builder() + .apiKey(System.getenv("DASH_SCOPE_API_KEY")) + .modelName("qwen-plus") + .baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1") + .logRequests(true) + .logResponses(true) + .listeners(List.of(new UserpuChatModelListener())) + .maxRetries(3) + .timeout(Duration.ofSeconds(5)) + .build(); + } + + /** + * @Description: + * 知识出处,https://api-docs.deepseek.com/zh-cn/ + */ + @Bean(name = "deepseek") + public ChatModel chatModelDeepSeek(){ + return + OpenAiChatModel.builder() + .apiKey(System.getenv("DEEP_SEEK_API_KEY")) + .modelName("deepseek-chat") + //.modelName("deepseek-reasoner") + .baseUrl("https://api.deepseek.com/v1") + .build(); + } + +} diff --git a/langchain4j-ai-model-params/src/main/java/com/iwe3/langchain4j/controller/ModelParameterController.java b/langchain4j-ai-model-params/src/main/java/com/iwe3/langchain4j/controller/ModelParameterController.java new file mode 100644 index 0000000..8bd455d --- /dev/null +++ b/langchain4j-ai-model-params/src/main/java/com/iwe3/langchain4j/controller/ModelParameterController.java @@ -0,0 +1,27 @@ +package com.iwe3.langchain4j.controller; + +import dev.langchain4j.model.chat.ChatModel; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@Slf4j +public class ModelParameterController +{ + @Resource(name = "qwen") + private ChatModel chatModelQwen; + + // http://localhost:9004/lc4j/modelparam/config?prompt=我是谁 + @GetMapping(value = "/lc4j/modelparam/config") + public String config(@RequestParam(value = "prompt", defaultValue = "你是谁") String prompt) + { + var result = chatModelQwen.chat(prompt); + + System.out.println("通过langchain4j调用模型返回结果:"+result); + + return result; + } +} \ No newline at end of file diff --git a/langchain4j-ai-model-params/src/main/java/com/iwe3/langchain4j/listener/UserpuChatModelListener.java b/langchain4j-ai-model-params/src/main/java/com/iwe3/langchain4j/listener/UserpuChatModelListener.java new file mode 100644 index 0000000..0e5d24a --- /dev/null +++ b/langchain4j-ai-model-params/src/main/java/com/iwe3/langchain4j/listener/UserpuChatModelListener.java @@ -0,0 +1,36 @@ +package com.iwe3.langchain4j.listener; + +import cn.hutool.core.util.IdUtil; +import dev.langchain4j.model.chat.listener.ChatModelErrorContext; +import dev.langchain4j.model.chat.listener.ChatModelListener; +import dev.langchain4j.model.chat.listener.ChatModelRequestContext; +import dev.langchain4j.model.chat.listener.ChatModelResponseContext; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class UserpuChatModelListener implements ChatModelListener +{ + @Override + public void onRequest(ChatModelRequestContext requestContext) + { + + // onRequest配置的k:v键值对,在onResponse阶段可以获得,上下文传递参数好用 + String uuidValue = IdUtil.simpleUUID(); + requestContext.attributes().put("TraceID",uuidValue); + log.info("请求参数requestContext:{}", requestContext+"\t"+uuidValue); + } + + @Override + public void onResponse(ChatModelResponseContext responseContext) + { + Object object = responseContext.attributes().get("TraceID"); + + log.info("返回结果responseContext:{}", object); + } + + @Override + public void onError(ChatModelErrorContext errorContext) + { + log.error("请求异常ChatModelErrorContext:{}", errorContext); + } +} diff --git a/langchain4j-ai-model-params/src/main/resources/application.yml b/langchain4j-ai-model-params/src/main/resources/application.yml new file mode 100644 index 0000000..6783374 --- /dev/null +++ b/langchain4j-ai-model-params/src/main/resources/application.yml @@ -0,0 +1,9 @@ +server: + port: 9004 +spring: + application: + name: langchain4j-ai-model-params +logging: + level: + dev: + langchain4j: debug \ No newline at end of file diff --git a/langchain4j-ai-mongodb/pom.xml b/langchain4j-ai-mongodb/pom.xml new file mode 100644 index 0000000..84b3f6f --- /dev/null +++ b/langchain4j-ai-mongodb/pom.xml @@ -0,0 +1,57 @@ + + + 4.0.0 + + com.iwe3 + langchain4j-ai-java + 1.0-SNAPSHOT + + + langchain4j-ai-mongodb + + + 17 + 17 + UTF-8 + + + + + + org.springframework.boot + spring-boot-starter-data-mongodb + + + dev.langchain4j + langchain4j-reactor + 1.9.1-beta17 + + + org.projectlombok + lombok + true + + + org.springframework.boot + spring-boot-starter-web + + + + dev.langchain4j + langchain4j-open-ai-spring-boot-starter + 1.9.1-beta17 + + + + dev.langchain4j + langchain4j-spring-boot-starter + 1.9.1-beta17 + + + org.springframework.boot + spring-boot-starter-test + + + \ No newline at end of file diff --git a/langchain4j-ai-mongodb/src/main/java/com/iwe3/langchain4j/MongoDBApplication.java b/langchain4j-ai-mongodb/src/main/java/com/iwe3/langchain4j/MongoDBApplication.java new file mode 100644 index 0000000..a08b38f --- /dev/null +++ b/langchain4j-ai-mongodb/src/main/java/com/iwe3/langchain4j/MongoDBApplication.java @@ -0,0 +1,12 @@ +package com.iwe3.langchain4j; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class MongoDBApplication { + + public static void main(String[] args) { + SpringApplication.run(MongoDBApplication.class,args); + } +} diff --git a/langchain4j-ai-mongodb/src/main/java/com/iwe3/langchain4j/config/LLMConfig.java b/langchain4j-ai-mongodb/src/main/java/com/iwe3/langchain4j/config/LLMConfig.java new file mode 100644 index 0000000..c1f56fc --- /dev/null +++ b/langchain4j-ai-mongodb/src/main/java/com/iwe3/langchain4j/config/LLMConfig.java @@ -0,0 +1,23 @@ +package com.iwe3.langchain4j.config; + +import dev.langchain4j.model.chat.ChatModel; +import dev.langchain4j.model.openai.OpenAiChatModel; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class LLMConfig { + + /** + * @Description: 普通对话接口 ChatModel + */ + @Bean(name = "qwen") + public ChatModel chatModelQwen() + { + return OpenAiChatModel.builder() + .apiKey(System.getenv("DASH_SCOPE_API_KEY")) + .modelName("qwen-plus") + .baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1") + .build(); + } +} diff --git a/langchain4j-ai-mongodb/src/main/java/com/iwe3/langchain4j/config/MongoChatMemoryStore.java b/langchain4j-ai-mongodb/src/main/java/com/iwe3/langchain4j/config/MongoChatMemoryStore.java new file mode 100644 index 0000000..82e569f --- /dev/null +++ b/langchain4j-ai-mongodb/src/main/java/com/iwe3/langchain4j/config/MongoChatMemoryStore.java @@ -0,0 +1,51 @@ +package com.iwe3.langchain4j.config; + +import com.iwe3.langchain4j.entity.ChatMessages; +import dev.langchain4j.data.message.ChatMessage; +import dev.langchain4j.data.message.ChatMessageDeserializer; +import dev.langchain4j.data.message.ChatMessageSerializer; +import dev.langchain4j.store.memory.chat.ChatMemoryStore; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.data.mongodb.core.query.Criteria; +import org.springframework.data.mongodb.core.query.Query; +import org.springframework.data.mongodb.core.query.Update; +import org.springframework.stereotype.Component; + +import java.util.LinkedList; +import java.util.List; + +@Component +public class MongoChatMemoryStore implements ChatMemoryStore { + + @Autowired + private MongoTemplate mongoTemplate; + + @Override + public List getMessages(Object memoryId) { + Criteria criteria = Criteria.where("memoryId").is(memoryId); + Query query = new Query(criteria); + ChatMessages chatMessages = mongoTemplate.findOne(query, ChatMessages.class); + if (chatMessages == null) return new LinkedList<>(); + return ChatMessageDeserializer.messagesFromJson(chatMessages.getContent()); + } + + @Override + public void updateMessages(Object memoryId, List messages) { + Criteria criteria = Criteria.where("memoryId").is(memoryId); + Query query = new Query(criteria); + + Update update = new Update(); + update.set("content", ChatMessageSerializer.messagesToJson(messages)); + + // 根据query条件能查询出文档,则修改文档;否则新增文档 + mongoTemplate.upsert(query, update, ChatMessages.class); + } + + @Override + public void deleteMessages(Object memoryId) { + Criteria criteria = Criteria.where("memoryId").is(memoryId); + Query query = new Query(criteria); + mongoTemplate.remove(query, ChatMessages.class); + } +} \ No newline at end of file diff --git a/langchain4j-ai-mongodb/src/main/java/com/iwe3/langchain4j/config/SeparateChatAssistantConfig.java b/langchain4j-ai-mongodb/src/main/java/com/iwe3/langchain4j/config/SeparateChatAssistantConfig.java new file mode 100644 index 0000000..ae04333 --- /dev/null +++ b/langchain4j-ai-mongodb/src/main/java/com/iwe3/langchain4j/config/SeparateChatAssistantConfig.java @@ -0,0 +1,29 @@ +package com.iwe3.langchain4j.config; + +import dev.langchain4j.memory.chat.ChatMemoryProvider; +import dev.langchain4j.memory.chat.MessageWindowChatMemory; +import dev.langchain4j.store.memory.chat.InMemoryChatMemoryStore; +import jakarta.annotation.Resource; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class SeparateChatAssistantConfig { + + @Resource + private MongoChatMemoryStore mongoChatMemoryStore; + + /** + * 指定使用-> mongoChatMemoryStore 来存储 + * @return + */ + @Bean + ChatMemoryProvider chatMemoryProvider() { + return memoryId -> MessageWindowChatMemory.builder() + .id(memoryId) + .maxMessages(10). + chatMemoryStore(mongoChatMemoryStore) + .build(); + } +} \ No newline at end of file diff --git a/langchain4j-ai-mongodb/src/main/java/com/iwe3/langchain4j/entity/ChatMessages.java b/langchain4j-ai-mongodb/src/main/java/com/iwe3/langchain4j/entity/ChatMessages.java new file mode 100644 index 0000000..e2c4933 --- /dev/null +++ b/langchain4j-ai-mongodb/src/main/java/com/iwe3/langchain4j/entity/ChatMessages.java @@ -0,0 +1,24 @@ +package com.iwe3.langchain4j.entity; + + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.bson.types.ObjectId; +import org.springframework.data.annotation.Id; +import org.springframework.data.mongodb.core.mapping.Document; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Document("chat_messages") +public class ChatMessages { + + //唯一标识,映射到 MongoDB 文档的 _id 字段 + @Id + private ObjectId messageId; //利用数据库生成ID就用ObjectId + + private String memoryId; //隔离聊天记录的ID + + private String content; //存储当前聊天记录列表的json字符串 +} \ No newline at end of file diff --git a/langchain4j-ai-mongodb/src/main/java/com/iwe3/langchain4j/service/SeparateChatAssistant.java b/langchain4j-ai-mongodb/src/main/java/com/iwe3/langchain4j/service/SeparateChatAssistant.java new file mode 100644 index 0000000..ff4222d --- /dev/null +++ b/langchain4j-ai-mongodb/src/main/java/com/iwe3/langchain4j/service/SeparateChatAssistant.java @@ -0,0 +1,22 @@ +package com.iwe3.langchain4j.service; + +import dev.langchain4j.service.MemoryId; +import dev.langchain4j.service.UserMessage; +import dev.langchain4j.service.spring.AiService; +import dev.langchain4j.service.spring.AiServiceWiringMode; + +@AiService( + wiringMode = AiServiceWiringMode.EXPLICIT, + chatModel = "qwen", + chatMemoryProvider = "chatMemoryProvider" +) +public interface SeparateChatAssistant { + + /** + * 分离聊天记录 + * @param memoryId 聊天id + * @param userMessage 用户消息 + * @return + */ + String chat(@MemoryId int memoryId, @UserMessage String userMessage); +} diff --git a/langchain4j-ai-mongodb/src/main/resources/application.yml b/langchain4j-ai-mongodb/src/main/resources/application.yml new file mode 100644 index 0000000..14bdbfe --- /dev/null +++ b/langchain4j-ai-mongodb/src/main/resources/application.yml @@ -0,0 +1,13 @@ +server: + port: 9008 + servlet: + encoding: + charset: utf-8 + enabled: true + force: true # 设置响应的字符编码,避免流式返回输出乱码 +spring: + application: + name: langchain4j-ai-mongodb + data: + mongodb: + uri: mongodb://localhost:27017/chat_memory_db # MongoDB连接配置,数据库 chat_memory_db 会自动创建 \ No newline at end of file diff --git a/langchain4j-ai-mongodb/src/test/java/com/iwe3/langchain4j/MongoCrudTest.java b/langchain4j-ai-mongodb/src/test/java/com/iwe3/langchain4j/MongoCrudTest.java new file mode 100644 index 0000000..4610747 --- /dev/null +++ b/langchain4j-ai-mongodb/src/test/java/com/iwe3/langchain4j/MongoCrudTest.java @@ -0,0 +1,57 @@ +package com.iwe3.langchain4j; + +import com.iwe3.langchain4j.entity.ChatMessages; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.data.mongodb.core.query.Criteria; +import org.springframework.data.mongodb.core.query.Query; +import org.springframework.data.mongodb.core.query.Update; + +@SpringBootTest +public class MongoCrudTest { + + @Autowired + private MongoTemplate mongoTemplate; + + @Test + public void delete(){ + var criteria = Criteria.where("_id").is("69420db67db051baab1b4873"); + var query = new Query(criteria); + mongoTemplate.remove(query,ChatMessages.class); + } + + @Test + public void update(){ + //id不存在,则会自动变成:新增 + var criteria = Criteria.where("_id").is("69420db67db051baab1b4873"); + var query = new Query(criteria); + //创建一个修改对象 + var update = new Update(); + update.set("content","奥特之母"); + //将查询条件, 修改的内容,文档的信息 -> mongodb + mongoTemplate.upsert(query,update,ChatMessages.class); + } + + + @Test + public void insert(){ +// mongoTemplate.insert(new ChatMessages(1L,"迪迦")); //程序员自己管理ID就用Long + + //利用数据库生成ID就用ObjectId + var msg = new ChatMessages(); + msg.setContent("贝利亚"); + mongoTemplate.insert(msg); + } + + @Test + public void findById(){ + var msg = mongoTemplate. + findById("69420db67db051baab1b4873", + ChatMessages.class); + System.out.println(msg); + } + + +} diff --git a/langchain4j-ai-mongodb/src/test/java/com/iwe3/langchain4j/MongoDBApplicationTest.java b/langchain4j-ai-mongodb/src/test/java/com/iwe3/langchain4j/MongoDBApplicationTest.java new file mode 100644 index 0000000..47fe13c --- /dev/null +++ b/langchain4j-ai-mongodb/src/test/java/com/iwe3/langchain4j/MongoDBApplicationTest.java @@ -0,0 +1,30 @@ +package com.iwe3.langchain4j; + +import com.iwe3.langchain4j.service.SeparateChatAssistant; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; + + +@SpringBootTest +class MongoDBApplicationTest { + + @Autowired + private SeparateChatAssistant separateChatAssistant; + + @Test + public void testSeparateChatMemory() { + // 用户1的对话 + var res = separateChatAssistant.chat(1, "我是蒲哥"); + System.out.println(res); + res = separateChatAssistant.chat(1, "你知道我是谁吗"); + System.out.println(res); + + // 用户2的对话 + var res02 = separateChatAssistant.chat(2, "我是小明"); + System.out.println(res02); + res02 = separateChatAssistant.chat(2, "我叫什么名字"); + System.out.println(res02); + } + +} \ No newline at end of file diff --git a/langchain4j-ai-multimode/pom.xml b/langchain4j-ai-multimode/pom.xml new file mode 100644 index 0000000..c8307f1 --- /dev/null +++ b/langchain4j-ai-multimode/pom.xml @@ -0,0 +1,46 @@ + + + 4.0.0 + + com.iwe3 + langchain4j-ai-java + 1.0-SNAPSHOT + + + langchain4j-ai-multimode + + + 17 + 17 + UTF-8 + + + + + org.springframework.boot + spring-boot-starter-web + + + dev.langchain4j + langchain4j-open-ai + + + dev.langchain4j + langchain4j + + + org.projectlombok + lombok + true + + + + org.springframework.boot + spring-boot-starter-test + test + + + + \ No newline at end of file diff --git a/langchain4j-ai-multimode/src/main/java/com/iwe3/langchain4j/MultiModelApplication.java b/langchain4j-ai-multimode/src/main/java/com/iwe3/langchain4j/MultiModelApplication.java new file mode 100644 index 0000000..d39438e --- /dev/null +++ b/langchain4j-ai-multimode/src/main/java/com/iwe3/langchain4j/MultiModelApplication.java @@ -0,0 +1,11 @@ +package com.iwe3.langchain4j; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class MultiModelApplication { + public static void main(String[] args) { + SpringApplication.run(MultiModelApplication.class); + } +} diff --git a/langchain4j-ai-multimode/src/main/java/com/iwe3/langchain4j/config/LLMConfig.java b/langchain4j-ai-multimode/src/main/java/com/iwe3/langchain4j/config/LLMConfig.java new file mode 100644 index 0000000..458fcac --- /dev/null +++ b/langchain4j-ai-multimode/src/main/java/com/iwe3/langchain4j/config/LLMConfig.java @@ -0,0 +1,37 @@ +package com.iwe3.langchain4j.config; + +import dev.langchain4j.model.chat.ChatModel; +import dev.langchain4j.model.openai.OpenAiChatModel; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class LLMConfig { + + @Bean(name = "qwen") + public ChatModel chatModelQwen() + { + return OpenAiChatModel.builder() + .apiKey(System.getenv("DASH_SCOPE_API_KEY")) + .modelName("qwen-plus") + .baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1") + .build(); + } + + /** + * @Description: + * 知识出处,https://api-docs.deepseek.com/zh-cn/ + */ + @Bean(name = "deepseek") + public ChatModel chatModelDeepSeek() + { + return + OpenAiChatModel.builder() + .apiKey(System.getenv("DEEP_SEEK_API_KEY")) + .modelName("deepseek-chat") + //.modelName("deepseek-reasoner") + .baseUrl("https://api.deepseek.com/v1") + .build(); + } + +} diff --git a/langchain4j-ai-multimode/src/main/java/com/iwe3/langchain4j/controller/MultiModelController.java b/langchain4j-ai-multimode/src/main/java/com/iwe3/langchain4j/controller/MultiModelController.java new file mode 100644 index 0000000..b3cf0fe --- /dev/null +++ b/langchain4j-ai-multimode/src/main/java/com/iwe3/langchain4j/controller/MultiModelController.java @@ -0,0 +1,35 @@ +package com.iwe3.langchain4j.controller; + +import dev.langchain4j.model.chat.ChatModel; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@Slf4j +public class MultiModelController +{ + @Resource(name = "qwen") + private ChatModel chatModelQwen; + + @Resource(name = "deepseek") + private ChatModel chatModelDeepSeek; + + // http://localhost:9002/multimodel/qwen?prompt=如何学习LangChain4J + @GetMapping(value = "/multimodel/qwen") + public String qwenCall(@RequestParam(value = "prompt", defaultValue = "你是谁") String prompt) { + var result = chatModelQwen.chat(prompt); + System.out.println("通过langchain4j调用模型返回结果:\n"+result); + return result; + } + + // http://localhost:9002/multimodel/deepseek?prompt=如何学习LangChain4J + @GetMapping(value = "/multimodel/deepseek") + public String deepseekCall(@RequestParam(value = "prompt", defaultValue = "你是谁") String prompt){ + var result = chatModelDeepSeek.chat(prompt); + System.out.println("通过langchain4j调用模型返回结果:\n"+result); + return result; + } +} diff --git a/langchain4j-ai-multimode/src/main/resources/application.yml b/langchain4j-ai-multimode/src/main/resources/application.yml new file mode 100644 index 0000000..f9865bd --- /dev/null +++ b/langchain4j-ai-multimode/src/main/resources/application.yml @@ -0,0 +1,5 @@ +server: + port: 9002 +spring: + application: + name: langchain4j-ai-multimode \ No newline at end of file diff --git a/langchain4j-ai-pinecone/pom.xml b/langchain4j-ai-pinecone/pom.xml new file mode 100644 index 0000000..eb8ceb0 --- /dev/null +++ b/langchain4j-ai-pinecone/pom.xml @@ -0,0 +1,67 @@ + + + 4.0.0 + + com.iwe3 + langchain4j-ai-java + 1.0-SNAPSHOT + + + langchain4j-ai-pinecone + + + 17 + 17 + UTF-8 + + + + + dev.langchain4j + langchain4j-pinecone + + + + dev.langchain4j + langchain4j-community-dashscope-spring-boot-starter + + + + dev.langchain4j + langchain4j-easy-rag + + + + dev.langchain4j + langchain4j-document-parser-apache-pdfbox + + + org.springframework.boot + spring-boot-starter-test + + + org.projectlombok + lombok + true + + + org.springframework.boot + spring-boot-starter-web + + + + dev.langchain4j + langchain4j-open-ai-spring-boot-starter + 1.9.1-beta17 + + + + dev.langchain4j + langchain4j-spring-boot-starter + 1.9.1-beta17 + + + + \ No newline at end of file diff --git a/langchain4j-ai-pinecone/src/main/java/com/iwe3/langchain4j/PineConeApplication.java b/langchain4j-ai-pinecone/src/main/java/com/iwe3/langchain4j/PineConeApplication.java new file mode 100644 index 0000000..9a085a6 --- /dev/null +++ b/langchain4j-ai-pinecone/src/main/java/com/iwe3/langchain4j/PineConeApplication.java @@ -0,0 +1,12 @@ +package com.iwe3.langchain4j; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class PineConeApplication { + + public static void main(String[] args) { + SpringApplication.run(PineConeApplication.class,args); + } +} diff --git a/langchain4j-ai-pinecone/src/main/java/com/iwe3/langchain4j/config/EmbeddingStoreConfig.java b/langchain4j-ai-pinecone/src/main/java/com/iwe3/langchain4j/config/EmbeddingStoreConfig.java new file mode 100644 index 0000000..b7f3275 --- /dev/null +++ b/langchain4j-ai-pinecone/src/main/java/com/iwe3/langchain4j/config/EmbeddingStoreConfig.java @@ -0,0 +1,32 @@ +package com.iwe3.langchain4j.config; + +import dev.langchain4j.data.segment.TextSegment; +import dev.langchain4j.model.embedding.EmbeddingModel; +import dev.langchain4j.store.embedding.EmbeddingStore; +import dev.langchain4j.store.embedding.pinecone.PineconeEmbeddingStore; +import dev.langchain4j.store.embedding.pinecone.PineconeServerlessIndexConfig; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class EmbeddingStoreConfig { + + @Autowired + private EmbeddingModel embeddingModel; + + @Bean + public EmbeddingStore embeddingStore() { + // 创建向量存储 + return PineconeEmbeddingStore.builder() + .apiKey(System.getenv("PINECONE_API_KEY")) + .index("xiaoai-index") // 如果指定的索引不存在,将创建一个新的索引 + .nameSpace("xiaoai-namespace") // 如果指定的名称空间不存在,将创建一个新的名称空间 + .createIndex(PineconeServerlessIndexConfig.builder() + .cloud("AWS") // 指定索引部署在 AWS 云服务上。 + .region("us-east-1") // 指定索引所在的 AWS 区域为 us-east-1。 + .dimension(embeddingModel.dimension()) // 指定索引的向量维度,该维度与 embeddingModel 生成的向量维度相同。 + .build()) + .build(); + } +} \ No newline at end of file diff --git a/langchain4j-ai-pinecone/src/main/java/com/iwe3/langchain4j/config/LLMConfig.java b/langchain4j-ai-pinecone/src/main/java/com/iwe3/langchain4j/config/LLMConfig.java new file mode 100644 index 0000000..c1f56fc --- /dev/null +++ b/langchain4j-ai-pinecone/src/main/java/com/iwe3/langchain4j/config/LLMConfig.java @@ -0,0 +1,23 @@ +package com.iwe3.langchain4j.config; + +import dev.langchain4j.model.chat.ChatModel; +import dev.langchain4j.model.openai.OpenAiChatModel; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class LLMConfig { + + /** + * @Description: 普通对话接口 ChatModel + */ + @Bean(name = "qwen") + public ChatModel chatModelQwen() + { + return OpenAiChatModel.builder() + .apiKey(System.getenv("DASH_SCOPE_API_KEY")) + .modelName("qwen-plus") + .baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1") + .build(); + } +} diff --git a/langchain4j-ai-pinecone/src/main/resources/application.yml b/langchain4j-ai-pinecone/src/main/resources/application.yml new file mode 100644 index 0000000..2e075fd --- /dev/null +++ b/langchain4j-ai-pinecone/src/main/resources/application.yml @@ -0,0 +1,11 @@ +server: + port: 9011 +spring: + application: + name: langchain4j-ai-pinecone +langchain4j: + community: + dashscope: + embedding-model: + model-name: text-embedding-v3 + api-key: ${DASH_SCOPE_API_KEY} \ No newline at end of file diff --git a/langchain4j-ai-pinecone/src/test/java/com/iwe3/langchain4j/PineConeApplicationTest.java b/langchain4j-ai-pinecone/src/test/java/com/iwe3/langchain4j/PineConeApplicationTest.java new file mode 100644 index 0000000..926d47b --- /dev/null +++ b/langchain4j-ai-pinecone/src/test/java/com/iwe3/langchain4j/PineConeApplicationTest.java @@ -0,0 +1,79 @@ +package com.iwe3.langchain4j; + +import dev.langchain4j.data.segment.TextSegment; +import dev.langchain4j.model.embedding.EmbeddingModel; +import dev.langchain4j.store.embedding.EmbeddingMatch; +import dev.langchain4j.store.embedding.EmbeddingSearchRequest; +import dev.langchain4j.store.embedding.EmbeddingSearchResult; +import dev.langchain4j.store.embedding.EmbeddingStore; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class PineConeApplicationTest { + + @Autowired + private EmbeddingModel embeddingModel; + @Autowired + private EmbeddingStore embeddingStore; + + + /** + * Pinecone - 相似度匹配 + */ + @Test + public void embeddingSearch() { + // 提问,并将问题转成向量数据 + var queryEmbedding = embeddingModel.embed("你最喜欢的运动是什么?").content(); + + // 创建搜索请求对象 + var searchRequest = EmbeddingSearchRequest.builder() + .queryEmbedding(queryEmbedding) + .maxResults(1) // 匹配最相似的一条记录 + .minScore(0.8) + .build(); + + // 根据搜索请求 searchRequest 在向量存储中进行相似度搜索 + EmbeddingSearchResult searchResult = embeddingStore.search(searchRequest); + + // searchResult.matches(): 获取搜索结果中的匹配项列表。 + // .get(0): 从匹配项列表中获取第一个匹配项 + EmbeddingMatch embeddingMatch = searchResult.matches().get(0); + + // 获取匹配项的相似度得分 + System.out.println(embeddingMatch.score()); // 输出:0.8144288515898701 + + // 返回文本结果 + System.out.println(embeddingMatch.embedded().text()); + } + + + + /** + * 将文本转换成向量,然后存储到 pinecone 中 + * + * 参考: + * https://docs.langchain4j.dev/tutorials/embedding-stores + */ + @Test + public void testPineconeEmbedded() { + // 将文本转换成向量 + var seg1 = TextSegment.from("我喜欢羽毛球"); + var em1 = embeddingModel.embed(seg1).content(); + embeddingStore.add(em1, seg1);// 存入向量数据库 + + var seg2 = TextSegment.from("今天天气很好"); + var em2 = embeddingModel.embed(seg2).content(); + embeddingStore.add(em2, seg2);// 存入向量数据库 + } + + + @Test + public void testEmbeddingModel() { + var embed = embeddingModel.embed("你好"); + + System.out.println("向量维度:" + embed.content().vector().length); + System.out.println("向量输出:" + embed.toString()); + } +} \ No newline at end of file diff --git a/langchain4j-ai-prompt/pom.xml b/langchain4j-ai-prompt/pom.xml new file mode 100644 index 0000000..e07df07 --- /dev/null +++ b/langchain4j-ai-prompt/pom.xml @@ -0,0 +1,48 @@ + + + 4.0.0 + + com.iwe3 + langchain4j-ai-java + 1.0-SNAPSHOT + + + langchain4j-ai-prompt + + + 17 + 17 + UTF-8 + + + + + org.springframework.boot + spring-boot-starter-test + + + org.projectlombok + lombok + true + + + org.springframework.boot + spring-boot-starter-web + + + + dev.langchain4j + langchain4j-open-ai-spring-boot-starter + 1.9.1-beta17 + + + + dev.langchain4j + langchain4j-spring-boot-starter + 1.9.1-beta17 + + + + \ No newline at end of file diff --git a/langchain4j-ai-prompt/src/main/java/com/iwe3/langchain4j/PromptApplication.java b/langchain4j-ai-prompt/src/main/java/com/iwe3/langchain4j/PromptApplication.java new file mode 100644 index 0000000..e118cb9 --- /dev/null +++ b/langchain4j-ai-prompt/src/main/java/com/iwe3/langchain4j/PromptApplication.java @@ -0,0 +1,12 @@ +package com.iwe3.langchain4j; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class PromptApplication { + + public static void main(String[] args) { + SpringApplication.run(PromptApplication.class,args); + } +} diff --git a/langchain4j-ai-prompt/src/main/java/com/iwe3/langchain4j/config/LLMConfig.java b/langchain4j-ai-prompt/src/main/java/com/iwe3/langchain4j/config/LLMConfig.java new file mode 100644 index 0000000..c1f56fc --- /dev/null +++ b/langchain4j-ai-prompt/src/main/java/com/iwe3/langchain4j/config/LLMConfig.java @@ -0,0 +1,23 @@ +package com.iwe3.langchain4j.config; + +import dev.langchain4j.model.chat.ChatModel; +import dev.langchain4j.model.openai.OpenAiChatModel; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class LLMConfig { + + /** + * @Description: 普通对话接口 ChatModel + */ + @Bean(name = "qwen") + public ChatModel chatModelQwen() + { + return OpenAiChatModel.builder() + .apiKey(System.getenv("DASH_SCOPE_API_KEY")) + .modelName("qwen-plus") + .baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1") + .build(); + } +} diff --git a/langchain4j-ai-prompt/src/main/java/com/iwe3/langchain4j/controller/ChatPromptController.java b/langchain4j-ai-prompt/src/main/java/com/iwe3/langchain4j/controller/ChatPromptController.java new file mode 100644 index 0000000..13c49bb --- /dev/null +++ b/langchain4j-ai-prompt/src/main/java/com/iwe3/langchain4j/controller/ChatPromptController.java @@ -0,0 +1,104 @@ +package com.iwe3.langchain4j.controller; + +import com.iwe3.langchain4j.entity.LawPrompt; +import com.iwe3.langchain4j.service.LawExplainAssistant; +import dev.langchain4j.data.message.UserMessage; +import dev.langchain4j.model.chat.ChatModel; +import dev.langchain4j.model.chat.response.ChatResponse; +import dev.langchain4j.model.input.Prompt; +import dev.langchain4j.model.input.PromptTemplate; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.assertj.core.util.DateUtil; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.Map; + +@RestController +@Slf4j +public class ChatPromptController { + + @Resource + private LawExplainAssistant lawExplainAssistant; + /** + * http://localhost:9008/lc4j/chatprompt/test2 + * TRIPS协议(与贸易有关的知识产权协议): + * 世界贸易组织(WTO)成员间的一个重要协议, + * 它规定了最低标准的知识产权保护要求,并适用于所有WTO成员。 + * @return + */ + @GetMapping(value = "/lc4j/chatprompt/test2") + public String test2() + { + var prompt = new LawPrompt(); + prompt.setLegal("知识产权"); + prompt.setQuestion("TRIPS协议?"); + + var chat = lawExplainAssistant.chat(prompt); + System.out.println(chat); + + return "success : "+ DateUtil.now()+"
\n\n chat: "+chat; + } + + + /** + * 高阶API调用 + * http://localhost:9008/lc4j/chatprompt/test1 + * @return + */ + @GetMapping(value = "/lc4j/chatprompt/test1") + public String test1() + { + String chat = lawExplainAssistant.chat("什么是知识产权?",2000); + System.out.println(chat); + + String chat2 = lawExplainAssistant.chat("什么是java?",2000); + System.out.println(chat2); + + return "success : "+ DateUtil.now()+"
\n\n chat: "+chat+"
\n\n chat2: "+chat2; + } + + + + + + + @Resource(name = "qwen") + private ChatModel chatModel; + + /** + * 低阶API调用 + * http://localhost:9008/lc4j/chatprompt/test + * @return + */ + @GetMapping(value = "/lc4j/chatprompt/test") + public String test(){ + // 看看源码,默认 PromptTemplate 构造使用 it 属性作为默认占位符 + + /*String role = "外科医生"; + String question = "牙疼";*/ + + String role = "财务会计"; + String question = "人民币大写"; + + //1 构造PromptTemplate模板 + PromptTemplate template = PromptTemplate.from("你是一个{{it}}助手,{{question}}怎么办"); + //2 由PromptTemplate生成Prompt + Prompt prompt = template.apply(Map.of("it",role,"question",question)); + //3 Prompt提示词变成UserMessage + UserMessage userMessage = prompt.toUserMessage(); + //4 调用大模型 + ChatResponse chatResponse = chatModel.chat(userMessage); + + //4.1 后台打印 + System.out.println(chatResponse.aiMessage().text()); + //4.2 前台返回 + return "success : "+ DateUtil.now()+"
\n\n chat: "+chatResponse.aiMessage().text(); + } + + + + +} diff --git a/langchain4j-ai-prompt/src/main/java/com/iwe3/langchain4j/entity/LawPrompt.java b/langchain4j-ai-prompt/src/main/java/com/iwe3/langchain4j/entity/LawPrompt.java new file mode 100644 index 0000000..e649f52 --- /dev/null +++ b/langchain4j-ai-prompt/src/main/java/com/iwe3/langchain4j/entity/LawPrompt.java @@ -0,0 +1,12 @@ +package com.iwe3.langchain4j.entity; + +import dev.langchain4j.model.input.structured.StructuredPrompt; +import lombok.Data; + +@Data +@StructuredPrompt("根据中国{{legal}}法律,解答以下问题:{{question}}") +public class LawPrompt +{ + private String legal;//法律 + private String question;//问题 +} diff --git a/langchain4j-ai-prompt/src/main/java/com/iwe3/langchain4j/service/LawExplainAssistant.java b/langchain4j-ai-prompt/src/main/java/com/iwe3/langchain4j/service/LawExplainAssistant.java new file mode 100644 index 0000000..051ce74 --- /dev/null +++ b/langchain4j-ai-prompt/src/main/java/com/iwe3/langchain4j/service/LawExplainAssistant.java @@ -0,0 +1,38 @@ +package com.iwe3.langchain4j.service; + +import com.iwe3.langchain4j.entity.LawPrompt; +import dev.langchain4j.service.SystemMessage; +import dev.langchain4j.service.UserMessage; +import dev.langchain4j.service.V; +import dev.langchain4j.service.spring.AiService; + +/** + * 一个法律解释助手 + */ +@AiService(chatModel = "qwen") +public interface LawExplainAssistant { + + //案例3 当提示词过多,也可以将从外部资源加载 + @SystemMessage(fromResource = "prompt-template.txt") + String chat(LawPrompt lawPrompt); + + //案例2 新建带着@StructuredPrompt的业务实体类,比如LawPrompt +// @SystemMessage("你是一位专业的中国法律顾问,只回答与中国法律相关的问题。" + +// "输出限制:对于其他领域的问题禁止回答,直接返回'抱歉,我只能回答中国法律相关的问题。'") +// String chat(LawPrompt lawPrompt); + + + // @SystemMessage : 定AI-LLM 的角色,任务,风格,格式 + // @UserMessage : 用户提示词 + // @V : 超过1个以上参数,需要起别名 + //案例1 @SystemMessage + @UserMessage + @V + @SystemMessage("你是一位专业的中国法律顾问,只回答与中国法律相关的问题。" + + "输出限制:对于其他领域的问题禁止回答,直接返回'抱歉,我只能回答中国法律相关的问题。'") + + @UserMessage("请回答以下法律问题:{{question}},字数控制在{{length}}以内") + String chat(@V("question") String question, @V("length") int length); + + + + +} diff --git a/langchain4j-ai-prompt/src/main/resources/application.yml b/langchain4j-ai-prompt/src/main/resources/application.yml new file mode 100644 index 0000000..6ae92a4 --- /dev/null +++ b/langchain4j-ai-prompt/src/main/resources/application.yml @@ -0,0 +1,5 @@ +server: + port: 9008 +spring: + application: + name: langchain4j-ai-prompt \ No newline at end of file diff --git a/langchain4j-ai-prompt/src/main/resources/prompt-template.txt b/langchain4j-ai-prompt/src/main/resources/prompt-template.txt new file mode 100644 index 0000000..0895918 --- /dev/null +++ b/langchain4j-ai-prompt/src/main/resources/prompt-template.txt @@ -0,0 +1,2 @@ +你是一位专业的中国法律顾问,只回答与中国法律相关的问题。 +输出限制:对于其他领域的问题禁止回答,直接返回'抱歉,我只能回答中国法律相关的问题。 \ No newline at end of file diff --git a/langchain4j-ai-rag/pom.xml b/langchain4j-ai-rag/pom.xml new file mode 100644 index 0000000..08379e0 --- /dev/null +++ b/langchain4j-ai-rag/pom.xml @@ -0,0 +1,58 @@ + + + 4.0.0 + + com.iwe3 + langchain4j-ai-java + 1.0-SNAPSHOT + + + langchain4j-ai-rag + + + 17 + 17 + UTF-8 + + + + + + dev.langchain4j + langchain4j-easy-rag + + + + dev.langchain4j + langchain4j-document-parser-apache-pdfbox + + + org.springframework.boot + spring-boot-starter-test + + + org.projectlombok + lombok + true + + + org.springframework.boot + spring-boot-starter-web + + + + dev.langchain4j + langchain4j-open-ai-spring-boot-starter + 1.9.1-beta17 + + + + dev.langchain4j + langchain4j-spring-boot-starter + 1.9.1-beta17 + + + + \ No newline at end of file diff --git a/langchain4j-ai-rag/src/main/java/com/iwe3/langchain4j/RagApplication.java b/langchain4j-ai-rag/src/main/java/com/iwe3/langchain4j/RagApplication.java new file mode 100644 index 0000000..fff9dfa --- /dev/null +++ b/langchain4j-ai-rag/src/main/java/com/iwe3/langchain4j/RagApplication.java @@ -0,0 +1,12 @@ +package com.iwe3.langchain4j; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class RagApplication { + + public static void main(String[] args) { + SpringApplication.run(RagApplication.class,args); + } +} diff --git a/langchain4j-ai-rag/src/main/java/com/iwe3/langchain4j/config/LLMConfig.java b/langchain4j-ai-rag/src/main/java/com/iwe3/langchain4j/config/LLMConfig.java new file mode 100644 index 0000000..c1f56fc --- /dev/null +++ b/langchain4j-ai-rag/src/main/java/com/iwe3/langchain4j/config/LLMConfig.java @@ -0,0 +1,23 @@ +package com.iwe3.langchain4j.config; + +import dev.langchain4j.model.chat.ChatModel; +import dev.langchain4j.model.openai.OpenAiChatModel; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class LLMConfig { + + /** + * @Description: 普通对话接口 ChatModel + */ + @Bean(name = "qwen") + public ChatModel chatModelQwen() + { + return OpenAiChatModel.builder() + .apiKey(System.getenv("DASH_SCOPE_API_KEY")) + .modelName("qwen-plus") + .baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1") + .build(); + } +} diff --git a/langchain4j-ai-rag/src/main/resources/application.yml b/langchain4j-ai-rag/src/main/resources/application.yml new file mode 100644 index 0000000..e299359 --- /dev/null +++ b/langchain4j-ai-rag/src/main/resources/application.yml @@ -0,0 +1,5 @@ +server: + port: 9010 +spring: + application: + name: langchain4j-ai-rag \ No newline at end of file diff --git a/langchain4j-ai-rag/src/main/resources/files/test.txt b/langchain4j-ai-rag/src/main/resources/files/test.txt new file mode 100644 index 0000000..4b6d1bd --- /dev/null +++ b/langchain4j-ai-rag/src/main/resources/files/test.txt @@ -0,0 +1 @@ +电子科技大学,简称“成电”(UESTC) [12],位于四川成都,是中华人民共和国教育部直属全国重点大学 [127],国家首批“211工程”“985工程”重点建设大学,首批国家“双一流”建设高校; [188]入选111计划 [140]、101计划 [141]、强基计划 [137]、珠峰计划 [138]、英才计划 [120]、卓越工程师教育培养计划 [139]、国家建设高水平大学公派研究生项目 [136];是一所以电子信息科学技术为核心,以工为主,理工渗透,理、工、管、文、医协调发展的多科性研究型大学,被誉为“中国民族电子工业摇篮”和“中国电子类院校排头兵”。 \ No newline at end of file diff --git a/langchain4j-ai-rag/src/main/resources/files/电子科大.md b/langchain4j-ai-rag/src/main/resources/files/电子科大.md new file mode 100644 index 0000000..8582793 --- /dev/null +++ b/langchain4j-ai-rag/src/main/resources/files/电子科大.md @@ -0,0 +1,21 @@ +电子科技大学(University of Electronic Science and Technology of China,简称 **UESTC** 或 **“成电”**)是中国电子信息领域顶尖的高等学府,也是国家“985工程”“211工程”和首批“双一流”A类建设高校。以下是其核心简介: + +------ + +### 📍 基本信息 + +- **所在地**:四川省成都市(主校区为清水河校区,另有沙河、九里堤校区) +- **创办时间**:1956年 +- **主管部门**:中华人民共和国教育部 +- **校训**:求实求真,大气大为 + +------ + +### 🏛️ 历史沿革 + +- 由周恩来总理亲自部署,整合: + - 交通大学(现上海交大、西安交大) + - 南京工学院(现东南大学) + - 华南工学院(现华南理工大学) 的**电讯工程专业**,组建 **成都电讯工程学院**。 +- 1988年更名为 **电子科技大学**。 +- 1960年即被列为全国重点高校,1961年成为“国防七子”之一。 \ No newline at end of file diff --git a/langchain4j-ai-rag/src/main/resources/files/电子科大.pdf b/langchain4j-ai-rag/src/main/resources/files/电子科大.pdf new file mode 100644 index 0000000..158db7f Binary files /dev/null and b/langchain4j-ai-rag/src/main/resources/files/电子科大.pdf differ diff --git a/langchain4j-ai-rag/src/test/java/com/iwe3/langchain4j/RagApplicationTest.java b/langchain4j-ai-rag/src/test/java/com/iwe3/langchain4j/RagApplicationTest.java new file mode 100644 index 0000000..edd53df --- /dev/null +++ b/langchain4j-ai-rag/src/test/java/com/iwe3/langchain4j/RagApplicationTest.java @@ -0,0 +1,83 @@ +package com.iwe3.langchain4j; + +import ai.djl.huggingface.tokenizers.HuggingFaceTokenizer; +import dev.langchain4j.data.document.Document; +import dev.langchain4j.data.document.loader.FileSystemDocumentLoader; +import dev.langchain4j.data.document.parser.apache.pdfbox.ApachePdfBoxDocumentParser; +import dev.langchain4j.data.document.splitter.DocumentByParagraphSplitter; +import dev.langchain4j.data.message.UserMessage; +import dev.langchain4j.data.segment.TextSegment; +import dev.langchain4j.model.chat.ChatModel; +import dev.langchain4j.model.chat.response.ChatResponse; +import dev.langchain4j.model.output.TokenUsage; +import dev.langchain4j.store.embedding.EmbeddingStoreIngestor; +import dev.langchain4j.store.embedding.inmemory.InMemoryEmbeddingStore; +import jakarta.annotation.Resource; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class RagApplicationTest { + + @Resource + private ChatModel chatModel; + + + @Test + public void testCountToken(){ + var res = chatModel.chat(UserMessage.from("你好,这是一段文字!")); + var result = res.aiMessage().text(); + System.out.println("通过调用大模型返回结果:" + result); + /*Token用量计算底层API*/ + var tu = res.tokenUsage(); + System.out.println("本地调用销毁的TOKEN:" + tu); + } + + + /** + * 加载文档并存入向量数据库 + */ + @Test + public void testReadDocumentAndStore() { + // 使用FileSystemDocumentLoader读取指定目录下的知识库文档 + // 并使用默认的文档解析器TextDocumentParser对文档进行解析 + var document = FileSystemDocumentLoader.loadDocument("D:/files/电子科大.md"); + + // 为了简单起见,我们暂时使用基于内存的向量存储 + InMemoryEmbeddingStore db = new InMemoryEmbeddingStore<>(); + + // /ingest + // /1、分割文档,默认使用递归分割器,将文档分割为多个文本片段,每个片段包含不超过 300个token,并且有 30个token的重叠部分保证连贯性 + // /2、文本向量化:使用一个LangChain4j内置的轻量化向量模型对每个文本片段进行向量化 + // /3、将原始文本和向量存储到向量数据库中(InMemoryEmbeddingStore) + EmbeddingStoreIngestor.ingest(document, db); + + // 查看向量数据库内容 + System.out.println(db); + } + + + + /** + * 解析PDF + */ + @Test + public void testParsePDF() { + var document = FileSystemDocumentLoader.loadDocument( + "D:/files/电子科大.pdf", + new ApachePdfBoxDocumentParser() + ); + System.out.println(document); + } + + @Test + public void testReadDocument() { + // 使用FileSystemDocumentLoader读取指定目录下的知识库文档 + // 并使用默认的文档解析器TextDocumentParser对文档进行解析 + var document = FileSystemDocumentLoader + .loadDocument("D:/files/test.txt"); + System.out.println(document.metadata()); + System.out.println(document.text()); + } + +} \ No newline at end of file diff --git a/langchain4j-ai-stream/pom.xml b/langchain4j-ai-stream/pom.xml new file mode 100644 index 0000000..e1c2fdf --- /dev/null +++ b/langchain4j-ai-stream/pom.xml @@ -0,0 +1,57 @@ + + + 4.0.0 + + com.iwe3 + langchain4j-ai-java + 1.0-SNAPSHOT + + + langchain4j-ai-stream + + + 17 + 17 + UTF-8 + + + + + org.springframework.boot + spring-boot-starter-test + + + + org.springframework.boot + spring-boot-starter-data-mongodb + + + dev.langchain4j + langchain4j-reactor + 1.9.1-beta17 + + + org.projectlombok + lombok + true + + + org.springframework.boot + spring-boot-starter-web + + + + dev.langchain4j + langchain4j-open-ai-spring-boot-starter + 1.9.1-beta17 + + + + dev.langchain4j + langchain4j-spring-boot-starter + 1.9.1-beta17 + + + \ No newline at end of file diff --git a/langchain4j-ai-stream/src/main/java/com/iweb/langchain4j/StreamApplication.java b/langchain4j-ai-stream/src/main/java/com/iweb/langchain4j/StreamApplication.java new file mode 100644 index 0000000..2a4fbca --- /dev/null +++ b/langchain4j-ai-stream/src/main/java/com/iweb/langchain4j/StreamApplication.java @@ -0,0 +1,13 @@ +package com.iweb.langchain4j; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +public class StreamApplication { + + public static void main(String[] args) { + SpringApplication.run(StreamApplication.class,args); + } + +} diff --git a/langchain4j-ai-stream/src/main/java/com/iweb/langchain4j/config/LLMConfig.java b/langchain4j-ai-stream/src/main/java/com/iweb/langchain4j/config/LLMConfig.java new file mode 100644 index 0000000..136ce27 --- /dev/null +++ b/langchain4j-ai-stream/src/main/java/com/iweb/langchain4j/config/LLMConfig.java @@ -0,0 +1,36 @@ +package com.iweb.langchain4j.config; + +import dev.langchain4j.model.chat.ChatModel; +import dev.langchain4j.model.chat.StreamingChatModel; +import dev.langchain4j.model.openai.OpenAiChatModel; +import dev.langchain4j.model.openai.OpenAiStreamingChatModel; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class LLMConfig { + + /** + * @Description: 普通对话接口 ChatModel + */ + @Bean(name = "qwen") + public ChatModel chatModelQwen() + { + return OpenAiChatModel.builder() + .apiKey(System.getenv("DASH_SCOPE_API_KEY")) + .modelName("qwen-plus") + .baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1") + .build(); + } + /** + * @Description: 流式对话接口 StreamingChatModel + */ + @Bean + public StreamingChatModel streamingChatModel(){ + return OpenAiStreamingChatModel.builder() + .apiKey(System.getenv("DASH_SCOPE_API_KEY")) + .modelName("qwen-plus") + .baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1") + .build(); + } +} diff --git a/langchain4j-ai-stream/src/main/java/com/iweb/langchain4j/controller/StreamController.java b/langchain4j-ai-stream/src/main/java/com/iweb/langchain4j/controller/StreamController.java new file mode 100644 index 0000000..230597a --- /dev/null +++ b/langchain4j-ai-stream/src/main/java/com/iweb/langchain4j/controller/StreamController.java @@ -0,0 +1,57 @@ +package com.iweb.langchain4j.controller; + +import com.iweb.langchain4j.service.ChatAssistant; +import dev.langchain4j.model.chat.StreamingChatModel; +import dev.langchain4j.model.chat.response.ChatResponse; +import dev.langchain4j.model.chat.response.StreamingChatResponseHandler; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; +import reactor.core.publisher.Flux; + +@RestController +@Slf4j +public class StreamController { + + @Resource //直接使用 low-level LLM API + private StreamingChatModel chatModelQwen; + @Resource //自己封装接口使用 high-level LLM API + private ChatAssistant chatAssistant; + + // http://localhost:9006/lc4j/chatstream/chat2?prompt=我是谁? + @GetMapping(value = "/lc4j/chatstream/chat2") + public Flux chat3(@RequestParam(value = "prompt", defaultValue = "你是谁?") String prompt) { + return chatAssistant.chatFlux(prompt); + } + + + // http://localhost:9006/lc4j/chatstream/chat?prompt=我是谁? + @GetMapping(value = "/lc4j/chatstream/chat") + public Flux chat(@RequestParam("prompt") String prompt) { + + return Flux.create(emitter -> { + chatModelQwen.chat(prompt, new StreamingChatResponseHandler() + { + @Override + public void onPartialResponse(String partialResponse) + { + emitter.next(partialResponse); + } + + @Override + public void onCompleteResponse(ChatResponse completeResponse) + { + emitter.complete(); + } + + @Override + public void onError(Throwable throwable) + { + emitter.error(throwable); + } + }); + }); + } +} diff --git a/langchain4j-ai-stream/src/main/java/com/iweb/langchain4j/service/ChatAssistant.java b/langchain4j-ai-stream/src/main/java/com/iweb/langchain4j/service/ChatAssistant.java new file mode 100644 index 0000000..c565f83 --- /dev/null +++ b/langchain4j-ai-stream/src/main/java/com/iweb/langchain4j/service/ChatAssistant.java @@ -0,0 +1,27 @@ +package com.iweb.langchain4j.service; + +import dev.langchain4j.service.spring.AiService; +import dev.langchain4j.service.spring.AiServiceWiringMode; +import reactor.core.publisher.Flux; + +/** + * 知识出处: + * https://docs.langchain4j.dev/tutorials/spring-boot-integration/#spring-boot-starter-for-declarative-ai-services + */ +@AiService(wiringMode = AiServiceWiringMode.EXPLICIT +,streamingChatModel = "streamingChatModel") +public interface ChatAssistant { + /** + * 普通聊天 + * @param prompt + * @return + */ + String chat(String prompt); + + /** + * 流式聊天 + * @param prompt + * @return + */ + Flux chatFlux(String prompt); +} diff --git a/langchain4j-ai-stream/src/main/resources/application.yml b/langchain4j-ai-stream/src/main/resources/application.yml new file mode 100644 index 0000000..755ec5c --- /dev/null +++ b/langchain4j-ai-stream/src/main/resources/application.yml @@ -0,0 +1,10 @@ +server: + port: 9006 + servlet: + encoding: + charset: utf-8 + enabled: true + force: true # 设置响应的字符编码,避免流式返回输出乱码 +spring: + application: + name: langchain4j-ai-stream \ No newline at end of file diff --git a/langchain4j-ai-tools/pom.xml b/langchain4j-ai-tools/pom.xml new file mode 100644 index 0000000..82bd328 --- /dev/null +++ b/langchain4j-ai-tools/pom.xml @@ -0,0 +1,46 @@ + + + 4.0.0 + + com.iwe3 + langchain4j-ai-java + 1.0-SNAPSHOT + + + langchain4j-ai-tools + + + 17 + 17 + UTF-8 + + + + org.springframework.boot + spring-boot-starter-test + + + org.projectlombok + lombok + true + + + org.springframework.boot + spring-boot-starter-web + + + + dev.langchain4j + langchain4j-open-ai-spring-boot-starter + 1.9.1-beta17 + + + + dev.langchain4j + langchain4j-spring-boot-starter + 1.9.1-beta17 + + + \ No newline at end of file diff --git a/langchain4j-ai-tools/src/main/java/com/iwe3/langchain4j/ToolsApplication.java b/langchain4j-ai-tools/src/main/java/com/iwe3/langchain4j/ToolsApplication.java new file mode 100644 index 0000000..5277618 --- /dev/null +++ b/langchain4j-ai-tools/src/main/java/com/iwe3/langchain4j/ToolsApplication.java @@ -0,0 +1,22 @@ +package com.iwe3.langchain4j; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.Bean; +import org.springframework.web.client.RestTemplate; + +@SpringBootApplication +public class ToolsApplication { + /** + * 创建RestTemplate的实例 + * @return + */ + @Bean + public RestTemplate restTemplate(){ + return new RestTemplate(); + } + + public static void main(String[] args) { + SpringApplication.run(ToolsApplication.class,args); + } +} diff --git a/langchain4j-ai-tools/src/main/java/com/iwe3/langchain4j/config/LLMConfig.java b/langchain4j-ai-tools/src/main/java/com/iwe3/langchain4j/config/LLMConfig.java new file mode 100644 index 0000000..61029b8 --- /dev/null +++ b/langchain4j-ai-tools/src/main/java/com/iwe3/langchain4j/config/LLMConfig.java @@ -0,0 +1,20 @@ +package com.iwe3.langchain4j.config; + +import dev.langchain4j.model.chat.ChatModel; +import dev.langchain4j.model.openai.OpenAiChatModel; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class LLMConfig { + + @Bean(name = "qwen") + public ChatModel chatModelQwen(){ + /*大模型3件套:apikey ,model-name,base-url */ + return OpenAiChatModel.builder() + .apiKey(System.getenv("DASH_SCOPE_API_KEY")) + .modelName("qwen-plus") + .baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1") + .build(); + } +} diff --git a/langchain4j-ai-tools/src/main/java/com/iwe3/langchain4j/config/SeparateChatAssistantConfig.java b/langchain4j-ai-tools/src/main/java/com/iwe3/langchain4j/config/SeparateChatAssistantConfig.java new file mode 100644 index 0000000..583f089 --- /dev/null +++ b/langchain4j-ai-tools/src/main/java/com/iwe3/langchain4j/config/SeparateChatAssistantConfig.java @@ -0,0 +1,25 @@ +package com.iwe3.langchain4j.config; + +import dev.langchain4j.memory.chat.ChatMemoryProvider; +import dev.langchain4j.memory.chat.MessageWindowChatMemory; +import dev.langchain4j.store.memory.chat.InMemoryChatMemoryStore; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class SeparateChatAssistantConfig { + + /** + * 聊天记忆提供器 + * 配置:采用memoryId来完成隔离 + * @return + */ + @Bean + ChatMemoryProvider chatMemoryProvider() { + return memoryId -> MessageWindowChatMemory.builder() + .id(memoryId) + .maxMessages(10).chatMemoryStore(new InMemoryChatMemoryStore()) + .build(); + //如果未来想自定义 -> 则自己写一个类实现 ChatMemoryStore + } +} diff --git a/langchain4j-ai-tools/src/main/java/com/iwe3/langchain4j/service/ChatAssistant.java b/langchain4j-ai-tools/src/main/java/com/iwe3/langchain4j/service/ChatAssistant.java new file mode 100644 index 0000000..d5922d4 --- /dev/null +++ b/langchain4j-ai-tools/src/main/java/com/iwe3/langchain4j/service/ChatAssistant.java @@ -0,0 +1,32 @@ +package com.iwe3.langchain4j.service; + +import dev.langchain4j.service.MemoryId; +import dev.langchain4j.service.UserMessage; +import dev.langchain4j.service.V; +import dev.langchain4j.service.spring.AiService; +import dev.langchain4j.service.spring.AiServiceWiringMode; + +/** + * 知识出处: + * https://docs.langchain4j.dev/tutorials/spring-boot-integration/#spring-boot-starter-for-declarative-ai-services + */ +@AiService(wiringMode = AiServiceWiringMode.EXPLICIT + ,chatModel = "qwen", + tools = {"weatherTools"}, + chatMemoryProvider = "chatMemoryProvider") +public interface ChatAssistant { + /** + * 聊天 + * @param memoryId + * @param userMessage + * @return + */ + @UserMessage("请用粤语回答问题,并且添加一些表情符号。 {{msg}}") + String chat(@MemoryId int memoryId, @V("msg") String userMessage); + /** + * 普通聊天 + * @param prompt + * @return + */ + String chat(String prompt); +} diff --git a/langchain4j-ai-tools/src/main/java/com/iwe3/langchain4j/tools/WeatherTools.java b/langchain4j-ai-tools/src/main/java/com/iwe3/langchain4j/tools/WeatherTools.java new file mode 100644 index 0000000..cb29a14 --- /dev/null +++ b/langchain4j-ai-tools/src/main/java/com/iwe3/langchain4j/tools/WeatherTools.java @@ -0,0 +1,27 @@ +package com.iwe3.langchain4j.tools; + +import dev.langchain4j.agent.tool.P; +import dev.langchain4j.agent.tool.Tool; +import dev.langchain4j.agent.tool.ToolMemoryId; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestTemplate; + +@Component +public class WeatherTools { + + @Resource + private RestTemplate restTemplate; + + //name 是工具描述 value是工具补充信息 + @Tool(name = "查询天气",value = "根据城市编码调用高德开发平台,返回对应城市的天气情况") + public String queryWeather(@ToolMemoryId int memoryId, + @P(value = "城市编码",required = true) String citycode){ + System.out.println("查询天气情况---> 开始 ---> memoryId=" + memoryId); + //高德地图:查询天气 + //https://lbs.amap.com/api/webservice/guide/api-advanced/weatherinfo + var key = "cf6cb4245c630692d2f13c1cd1ad1632"; + var url = "https://restapi.amap.com/v3/weather/weatherInfo?key="+key+"&city="+citycode+"&extensions=all"; + return restTemplate.getForObject(url, String.class); + } +} diff --git a/langchain4j-ai-tools/src/main/resources/application.yml b/langchain4j-ai-tools/src/main/resources/application.yml new file mode 100644 index 0000000..82250cf --- /dev/null +++ b/langchain4j-ai-tools/src/main/resources/application.yml @@ -0,0 +1,5 @@ +server: + port: 9009 +spring: + application: + name: langchain4j-ai-tools diff --git a/langchain4j-ai-tools/src/test/java/com/iwe3/langchain4j/ToolsApplicationTest.java b/langchain4j-ai-tools/src/test/java/com/iwe3/langchain4j/ToolsApplicationTest.java new file mode 100644 index 0000000..b79c56e --- /dev/null +++ b/langchain4j-ai-tools/src/test/java/com/iwe3/langchain4j/ToolsApplicationTest.java @@ -0,0 +1,26 @@ +package com.iwe3.langchain4j; + +import com.iwe3.langchain4j.service.ChatAssistant; +import jakarta.annotation.Resource; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class ToolsApplicationTest { + + @Resource + private ChatAssistant chatAssistant; + + @Test + public void getWeatherByMemoryId(){ + var res = chatAssistant.chat(1,"成都今天天气如何?城市编码:510100"); + System.out.println("res = " + res); + } + + @Test + public void getWeather(){ + var res = chatAssistant.chat("成都今天天气如何?城市编码:510100"); + System.out.println("res = " + res); + } + +} \ No newline at end of file diff --git a/langchain4j-ai-xiaoai-agent/pom.xml b/langchain4j-ai-xiaoai-agent/pom.xml new file mode 100644 index 0000000..482270a --- /dev/null +++ b/langchain4j-ai-xiaoai-agent/pom.xml @@ -0,0 +1,96 @@ + + + 4.0.0 + + com.iwe3 + langchain4j-ai-java + 1.0-SNAPSHOT + + + langchain4j-ai-xiaoai-agent + + + 17 + 17 + UTF-8 + 4.3.0 + + + + + dev.langchain4j + langchain4j-community-dashscope-spring-boot-starter + + + + dev.langchain4j + langchain4j-pinecone + + + + + dev.langchain4j + langchain4j-easy-rag + + + + + com.alibaba + druid-spring-boot-3-starter + 1.2.27 + + + com.mysql + mysql-connector-j + runtime + + + org.mybatis.spring.boot + mybatis-spring-boot-starter + 3.0.5 + + + org.springframework.boot + spring-boot-starter-test + + + + org.springframework.boot + spring-boot-starter-data-mongodb + + + dev.langchain4j + langchain4j-reactor + 1.9.1-beta17 + + + org.projectlombok + lombok + true + + + org.springframework.boot + spring-boot-starter-web + + + + dev.langchain4j + langchain4j-open-ai-spring-boot-starter + 1.9.1-beta17 + + + + dev.langchain4j + langchain4j-spring-boot-starter + 1.9.1-beta17 + + + + com.github.xiaoymin + knife4j-openapi3-jakarta-spring-boot-starter + ${knife4j.version} + + + \ No newline at end of file diff --git a/langchain4j-ai-xiaoai-agent/src/main/java/com/iwe3/langchain4j/XiaoAIAgentApplication.java b/langchain4j-ai-xiaoai-agent/src/main/java/com/iwe3/langchain4j/XiaoAIAgentApplication.java new file mode 100644 index 0000000..81ea110 --- /dev/null +++ b/langchain4j-ai-xiaoai-agent/src/main/java/com/iwe3/langchain4j/XiaoAIAgentApplication.java @@ -0,0 +1,13 @@ +package com.iwe3.langchain4j; + +import org.mybatis.spring.annotation.MapperScan; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@MapperScan("com.iwe3.langchain4j.mapper") +@SpringBootApplication +public class XiaoAIAgentApplication { + public static void main(String[] args) { + SpringApplication.run(XiaoAIAgentApplication.class,args); + } +} diff --git a/langchain4j-ai-xiaoai-agent/src/main/java/com/iwe3/langchain4j/config/EmbeddingStoreConfig.java b/langchain4j-ai-xiaoai-agent/src/main/java/com/iwe3/langchain4j/config/EmbeddingStoreConfig.java new file mode 100644 index 0000000..b7f3275 --- /dev/null +++ b/langchain4j-ai-xiaoai-agent/src/main/java/com/iwe3/langchain4j/config/EmbeddingStoreConfig.java @@ -0,0 +1,32 @@ +package com.iwe3.langchain4j.config; + +import dev.langchain4j.data.segment.TextSegment; +import dev.langchain4j.model.embedding.EmbeddingModel; +import dev.langchain4j.store.embedding.EmbeddingStore; +import dev.langchain4j.store.embedding.pinecone.PineconeEmbeddingStore; +import dev.langchain4j.store.embedding.pinecone.PineconeServerlessIndexConfig; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class EmbeddingStoreConfig { + + @Autowired + private EmbeddingModel embeddingModel; + + @Bean + public EmbeddingStore embeddingStore() { + // 创建向量存储 + return PineconeEmbeddingStore.builder() + .apiKey(System.getenv("PINECONE_API_KEY")) + .index("xiaoai-index") // 如果指定的索引不存在,将创建一个新的索引 + .nameSpace("xiaoai-namespace") // 如果指定的名称空间不存在,将创建一个新的名称空间 + .createIndex(PineconeServerlessIndexConfig.builder() + .cloud("AWS") // 指定索引部署在 AWS 云服务上。 + .region("us-east-1") // 指定索引所在的 AWS 区域为 us-east-1。 + .dimension(embeddingModel.dimension()) // 指定索引的向量维度,该维度与 embeddingModel 生成的向量维度相同。 + .build()) + .build(); + } +} \ No newline at end of file diff --git a/langchain4j-ai-xiaoai-agent/src/main/java/com/iwe3/langchain4j/config/LLMConfig.java b/langchain4j-ai-xiaoai-agent/src/main/java/com/iwe3/langchain4j/config/LLMConfig.java new file mode 100644 index 0000000..506c9ea --- /dev/null +++ b/langchain4j-ai-xiaoai-agent/src/main/java/com/iwe3/langchain4j/config/LLMConfig.java @@ -0,0 +1,23 @@ +package com.iwe3.langchain4j.config; + +import dev.langchain4j.model.chat.StreamingChatModel; +import dev.langchain4j.model.openai.OpenAiStreamingChatModel; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + + +@Configuration +public class LLMConfig { + + /** + * @Description: 流式对话接口 StreamingChatModel + */ + @Bean + public StreamingChatModel streamingChatModel(){ + return OpenAiStreamingChatModel.builder() + .apiKey(System.getenv("DASH_SCOPE_API_KEY")) + .modelName("qwen-plus") + .baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1") + .build(); + } +} diff --git a/langchain4j-ai-xiaoai-agent/src/main/java/com/iwe3/langchain4j/config/MongoChatMemoryStore.java b/langchain4j-ai-xiaoai-agent/src/main/java/com/iwe3/langchain4j/config/MongoChatMemoryStore.java new file mode 100644 index 0000000..aa26fa4 --- /dev/null +++ b/langchain4j-ai-xiaoai-agent/src/main/java/com/iwe3/langchain4j/config/MongoChatMemoryStore.java @@ -0,0 +1,65 @@ +package com.iwe3.langchain4j.config; + +import com.iwe3.langchain4j.entity.ChatMessages; +import dev.langchain4j.data.message.ChatMessage; +import dev.langchain4j.data.message.ChatMessageDeserializer; +import dev.langchain4j.data.message.ChatMessageSerializer; +import dev.langchain4j.store.memory.chat.ChatMemoryStore; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.data.mongodb.core.query.Criteria; +import org.springframework.data.mongodb.core.query.Query; +import org.springframework.data.mongodb.core.query.Update; +import org.springframework.stereotype.Component; + +import java.util.LinkedList; +import java.util.List; + +@Component +public class MongoChatMemoryStore implements ChatMemoryStore { + + @Autowired + private MongoTemplate mongoTemplate; + + /** + * 根据聊天ID查询所有消息 + * @param memoryId + * @return + */ + @Override + public List getMessages(Object memoryId) { + Criteria criteria = Criteria.where("memoryId").is(memoryId); + Query query = new Query(criteria); + ChatMessages chatMessages = mongoTemplate.findOne(query, ChatMessages.class); + if (chatMessages == null) return new LinkedList<>(); + return ChatMessageDeserializer.messagesFromJson(chatMessages.getContent()); + } + + /** + * 根据聊天id修改聊天消息 + * @param memoryId + * @param messages + */ + @Override + public void updateMessages(Object memoryId, List messages) { + Criteria criteria = Criteria.where("memoryId").is(memoryId); + Query query = new Query(criteria); + + Update update = new Update(); + update.set("content", ChatMessageSerializer.messagesToJson(messages)); + + // 根据query条件能查询出文档,则修改文档;否则新增文档 + mongoTemplate.upsert(query, update, ChatMessages.class); + } + + /** + * 根据聊天ID删除聊天消息 + * @param memoryId + */ + @Override + public void deleteMessages(Object memoryId) { + Criteria criteria = Criteria.where("memoryId").is(memoryId); + Query query = new Query(criteria); + mongoTemplate.remove(query, ChatMessages.class); + } +} \ No newline at end of file diff --git a/langchain4j-ai-xiaoai-agent/src/main/java/com/iwe3/langchain4j/config/SeparateChatAssistantConfig.java b/langchain4j-ai-xiaoai-agent/src/main/java/com/iwe3/langchain4j/config/SeparateChatAssistantConfig.java new file mode 100644 index 0000000..a6b277b --- /dev/null +++ b/langchain4j-ai-xiaoai-agent/src/main/java/com/iwe3/langchain4j/config/SeparateChatAssistantConfig.java @@ -0,0 +1,27 @@ +package com.iwe3.langchain4j.config; + +import dev.langchain4j.memory.chat.ChatMemoryProvider; +import dev.langchain4j.memory.chat.MessageWindowChatMemory; +import jakarta.annotation.Resource; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class SeparateChatAssistantConfig { + + @Resource + private MongoChatMemoryStore mongoChatMemoryStore; + + /** + * 指定使用-> mongoChatMemoryStore 来存储 + * @return + */ + @Bean + ChatMemoryProvider chatMemoryProvider() { + return memoryId -> MessageWindowChatMemory.builder() + .id(memoryId) + .maxMessages(30). + chatMemoryStore(mongoChatMemoryStore) + .build(); + } +} \ No newline at end of file diff --git a/langchain4j-ai-xiaoai-agent/src/main/java/com/iwe3/langchain4j/config/XiaoAiAgentConfig.java b/langchain4j-ai-xiaoai-agent/src/main/java/com/iwe3/langchain4j/config/XiaoAiAgentConfig.java new file mode 100644 index 0000000..4e9bfd4 --- /dev/null +++ b/langchain4j-ai-xiaoai-agent/src/main/java/com/iwe3/langchain4j/config/XiaoAiAgentConfig.java @@ -0,0 +1,63 @@ +package com.iwe3.langchain4j.config; + +import dev.langchain4j.data.document.loader.FileSystemDocumentLoader; +import dev.langchain4j.data.document.parser.TextDocumentParser; +import dev.langchain4j.data.segment.TextSegment; +import dev.langchain4j.model.embedding.EmbeddingModel; +import dev.langchain4j.rag.content.retriever.ContentRetriever; +import dev.langchain4j.rag.content.retriever.EmbeddingStoreContentRetriever; +import dev.langchain4j.store.embedding.EmbeddingStore; +import dev.langchain4j.store.embedding.EmbeddingStoreIngestor; +import dev.langchain4j.store.embedding.inmemory.InMemoryEmbeddingStore; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +import java.nio.file.FileSystems; + +@Configuration +public class XiaoAiAgentConfig { + + @Autowired + private EmbeddingStore embeddingStore; + + @Autowired + private EmbeddingModel embeddingModel; + + @Bean + ContentRetriever contentRetrieverInPinecone() { + // 创建一个 EmbeddingStoreContentRetriever 对象,用于从嵌入存储中检索内容 + return EmbeddingStoreContentRetriever + .builder() + // 设置用于生成嵌入向量的嵌入模型 + .embeddingModel(embeddingModel) + // 指定要使用的嵌入存储 + .embeddingStore(embeddingStore) + // 设置最大检索结果数量,这里表示最多返回 1 条匹配结果 + .maxResults(1) + // 设置最小得分阈值,只有得分大于等于 0.8 的结果才会被返回 + .minScore(0.8) + // 构建最终的 EmbeddingStoreContentRetriever 实例 + .build(); + } + /** + * 配置RAG检索增强 文档库 + * @return + */ + @Bean + ContentRetriever contentRetrieverInMemory() { + // 使用FileSystemDocumentLoader读取指定目录下的知识库文档 + var pathMatcher = FileSystems.getDefault() + .getPathMatcher("glob:*\\.md"); + var documents = FileSystemDocumentLoader + .loadDocuments("D:/documents", pathMatcher, new TextDocumentParser()); + + // 使用内存向量存储 + InMemoryEmbeddingStore db = new InMemoryEmbeddingStore<>(); + // 使用默认的文档分割器 + EmbeddingStoreIngestor.ingest(documents, db); + // 从嵌入存储(EmbeddingStore)里检索和查询内容相关的信息 + return EmbeddingStoreContentRetriever.from(db); + } + +} diff --git a/langchain4j-ai-xiaoai-agent/src/main/java/com/iwe3/langchain4j/controller/XiaoAIController.java b/langchain4j-ai-xiaoai-agent/src/main/java/com/iwe3/langchain4j/controller/XiaoAIController.java new file mode 100644 index 0000000..f3a76b3 --- /dev/null +++ b/langchain4j-ai-xiaoai-agent/src/main/java/com/iwe3/langchain4j/controller/XiaoAIController.java @@ -0,0 +1,26 @@ +package com.iwe3.langchain4j.controller; + +import com.iwe3.langchain4j.record.ChatRecord; +import com.iwe3.langchain4j.service.XiaoAIChatAssistant; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; +import reactor.core.publisher.Flux; + +@Tag(name="小艾") +@RestController +@RequestMapping("/xiaoai") +public class XiaoAIController { + + @Resource + private XiaoAIChatAssistant xiaoAIChatAssistant; + + @Operation(summary = "对话") + @PostMapping("/chat") + public Flux chat(@RequestBody ChatRecord record){ + return xiaoAIChatAssistant.chat(record.memoryId(),record.message()); + } +} diff --git a/langchain4j-ai-xiaoai-agent/src/main/java/com/iwe3/langchain4j/entity/AppointmentEntity.java b/langchain4j-ai-xiaoai-agent/src/main/java/com/iwe3/langchain4j/entity/AppointmentEntity.java new file mode 100644 index 0000000..b1e4a5c --- /dev/null +++ b/langchain4j-ai-xiaoai-agent/src/main/java/com/iwe3/langchain4j/entity/AppointmentEntity.java @@ -0,0 +1,14 @@ +package com.iwe3.langchain4j.entity; + +import lombok.Data; + +@Data +public class AppointmentEntity { + private Long id; + private String username; + private String idCard; + private String department; + private String date; + private String time; + private String doctorName; +} \ No newline at end of file diff --git a/langchain4j-ai-xiaoai-agent/src/main/java/com/iwe3/langchain4j/entity/ChatMessages.java b/langchain4j-ai-xiaoai-agent/src/main/java/com/iwe3/langchain4j/entity/ChatMessages.java new file mode 100644 index 0000000..e2c4933 --- /dev/null +++ b/langchain4j-ai-xiaoai-agent/src/main/java/com/iwe3/langchain4j/entity/ChatMessages.java @@ -0,0 +1,24 @@ +package com.iwe3.langchain4j.entity; + + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.bson.types.ObjectId; +import org.springframework.data.annotation.Id; +import org.springframework.data.mongodb.core.mapping.Document; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Document("chat_messages") +public class ChatMessages { + + //唯一标识,映射到 MongoDB 文档的 _id 字段 + @Id + private ObjectId messageId; //利用数据库生成ID就用ObjectId + + private String memoryId; //隔离聊天记录的ID + + private String content; //存储当前聊天记录列表的json字符串 +} \ No newline at end of file diff --git a/langchain4j-ai-xiaoai-agent/src/main/java/com/iwe3/langchain4j/mapper/AppointmentMapper.java b/langchain4j-ai-xiaoai-agent/src/main/java/com/iwe3/langchain4j/mapper/AppointmentMapper.java new file mode 100644 index 0000000..743f1a6 --- /dev/null +++ b/langchain4j-ai-xiaoai-agent/src/main/java/com/iwe3/langchain4j/mapper/AppointmentMapper.java @@ -0,0 +1,25 @@ +package com.iwe3.langchain4j.mapper; + +import com.iwe3.langchain4j.entity.AppointmentEntity; +import com.iwe3.langchain4j.record.AppointmentRecord; +import org.apache.ibatis.annotations.Delete; +import org.apache.ibatis.annotations.Insert; +import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +@Mapper +public interface AppointmentMapper { + + @Insert(""" + insert into appointment(username,id_card,department,date,time,doctor_name) + values (#{r.userName},#{r.idcard},#{r.department},#{r.date},#{r.time},#{r.doctorName}) + """) + void saveAppointmentEntity(@Param("r") AppointmentRecord record); + + @Delete(""" + delete from appointment where id = #{id} + """) + void removeById(@Param("id") long id); + + AppointmentEntity getOne(@Param("r") AppointmentRecord record); +} diff --git a/langchain4j-ai-xiaoai-agent/src/main/java/com/iwe3/langchain4j/record/AppointmentRecord.java b/langchain4j-ai-xiaoai-agent/src/main/java/com/iwe3/langchain4j/record/AppointmentRecord.java new file mode 100644 index 0000000..1ca38fc --- /dev/null +++ b/langchain4j-ai-xiaoai-agent/src/main/java/com/iwe3/langchain4j/record/AppointmentRecord.java @@ -0,0 +1,18 @@ +package com.iwe3.langchain4j.record; + +/** + * 编写挂号记录类 + * @param userName + * @param idcard + * @param department + * @param date + * @param time + * @param doctorName + */ +public record AppointmentRecord(String userName, + String idcard, + String department, + String date, + String time, + String doctorName) { +} diff --git a/langchain4j-ai-xiaoai-agent/src/main/java/com/iwe3/langchain4j/record/ChatRecord.java b/langchain4j-ai-xiaoai-agent/src/main/java/com/iwe3/langchain4j/record/ChatRecord.java new file mode 100644 index 0000000..79efdd9 --- /dev/null +++ b/langchain4j-ai-xiaoai-agent/src/main/java/com/iwe3/langchain4j/record/ChatRecord.java @@ -0,0 +1,9 @@ +package com.iwe3.langchain4j.record; + +/** + * 对话对象 + * @param memoryId + * @param message + */ +public record ChatRecord(Long memoryId,String message) { +} diff --git a/langchain4j-ai-xiaoai-agent/src/main/java/com/iwe3/langchain4j/service/IAppointmentService.java b/langchain4j-ai-xiaoai-agent/src/main/java/com/iwe3/langchain4j/service/IAppointmentService.java new file mode 100644 index 0000000..cd646cc --- /dev/null +++ b/langchain4j-ai-xiaoai-agent/src/main/java/com/iwe3/langchain4j/service/IAppointmentService.java @@ -0,0 +1,10 @@ +package com.iwe3.langchain4j.service; + +import com.iwe3.langchain4j.entity.AppointmentEntity; +import com.iwe3.langchain4j.record.AppointmentRecord; + +public interface IAppointmentService { + void saveAppointmentEntity(AppointmentRecord record); + void removeById(long id); + AppointmentEntity getOne(AppointmentRecord record); +} diff --git a/langchain4j-ai-xiaoai-agent/src/main/java/com/iwe3/langchain4j/service/XiaoAIChatAssistant.java b/langchain4j-ai-xiaoai-agent/src/main/java/com/iwe3/langchain4j/service/XiaoAIChatAssistant.java new file mode 100644 index 0000000..ad17527 --- /dev/null +++ b/langchain4j-ai-xiaoai-agent/src/main/java/com/iwe3/langchain4j/service/XiaoAIChatAssistant.java @@ -0,0 +1,21 @@ +package com.iwe3.langchain4j.service; + +import dev.langchain4j.service.MemoryId; +import dev.langchain4j.service.SystemMessage; +import dev.langchain4j.service.UserMessage; +import dev.langchain4j.service.spring.AiService; +import dev.langchain4j.service.spring.AiServiceWiringMode; +import reactor.core.publisher.Flux; + +//chatMemoryProvider = "chatMemoryProvider" 指定->MongoDB +//contentRetriever = "contentRetrieverInPinecone" 指定->Pinecone 向量存储版 +@AiService(wiringMode = AiServiceWiringMode.EXPLICIT + ,streamingChatModel = "streamingChatModel", + chatMemoryProvider = "chatMemoryProvider", + tools = {"appointmentTools"}, + contentRetriever = "contentRetrieverInPinecone") +public interface XiaoAIChatAssistant { + + @SystemMessage(fromResource = "xiaoai-prompt.txt") + Flux chat(@MemoryId Long memoryId, @UserMessage String userMessage); +} diff --git a/langchain4j-ai-xiaoai-agent/src/main/java/com/iwe3/langchain4j/service/impl/AppointmentServiceImpl.java b/langchain4j-ai-xiaoai-agent/src/main/java/com/iwe3/langchain4j/service/impl/AppointmentServiceImpl.java new file mode 100644 index 0000000..b3cd7e9 --- /dev/null +++ b/langchain4j-ai-xiaoai-agent/src/main/java/com/iwe3/langchain4j/service/impl/AppointmentServiceImpl.java @@ -0,0 +1,34 @@ +package com.iwe3.langchain4j.service.impl; + +import com.iwe3.langchain4j.entity.AppointmentEntity; +import com.iwe3.langchain4j.mapper.AppointmentMapper; +import com.iwe3.langchain4j.record.AppointmentRecord; +import com.iwe3.langchain4j.service.IAppointmentService; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +@Service +public class AppointmentServiceImpl implements IAppointmentService { + + private final AppointmentMapper appointmentMapper; + public AppointmentServiceImpl(AppointmentMapper appointmentMapper) { + this.appointmentMapper = appointmentMapper; + } + + @Transactional + @Override + public void saveAppointmentEntity(AppointmentRecord record) { + appointmentMapper.saveAppointmentEntity(record); + } + + @Transactional + @Override + public void removeById(long id) { + appointmentMapper.removeById(id); + } + + @Override + public AppointmentEntity getOne(AppointmentRecord record) { + return appointmentMapper.getOne(record); + } +} diff --git a/langchain4j-ai-xiaoai-agent/src/main/java/com/iwe3/langchain4j/tools/AppointmentTools.java b/langchain4j-ai-xiaoai-agent/src/main/java/com/iwe3/langchain4j/tools/AppointmentTools.java new file mode 100644 index 0000000..53f5579 --- /dev/null +++ b/langchain4j-ai-xiaoai-agent/src/main/java/com/iwe3/langchain4j/tools/AppointmentTools.java @@ -0,0 +1,62 @@ +package com.iwe3.langchain4j.tools; + +import com.iwe3.langchain4j.record.AppointmentRecord; +import com.iwe3.langchain4j.service.IAppointmentService; +import dev.langchain4j.agent.tool.P; +import dev.langchain4j.agent.tool.Tool; +import org.springframework.stereotype.Component; + +@Component +public class AppointmentTools { + + private final IAppointmentService appointmentServiceImpl; + public AppointmentTools(IAppointmentService appointmentServiceImpl) { + this.appointmentServiceImpl = appointmentServiceImpl; + } + //修改此处的提示词 + @Tool(name = "预约挂号", value = "根据参数,先执行工具方法queryDepartment查询是否可预约,并直接给用户回答是否可预约,并让用户确认所有预约信息,用户确认后再进行预约。如果用户没有提供具体的医生姓名,请从向量存储中找到一位医生。") + public String scheduleAppointment(AppointmentRecord record) { + // 查找数据库中是否包含对应的预约记录 + var appointment = appointmentServiceImpl.getOne(record); + if (appointment == null) { + appointmentServiceImpl.saveAppointmentEntity(record); + return "预约成功,并返回预约详情"; + } + + return "您在相同的科室和时间已有预约"; + } + + @Tool(name = "取消预约挂号", value = "根据参数,查询预约是否存在,如果存在则删除预约记录并返回取消预约成功,否则返回取消预约失败") + public String cancelAppointment(AppointmentRecord record) { + var appointment = appointmentServiceImpl.getOne(record); + + if (appointment != null) { + appointmentServiceImpl.removeById(appointment.getId()); + return "取消预约成功"; + } + // 取消失败 + return "您没有预约记录,请核对预约科室和时间"; + } + + @Tool(name = "查询是否有号源", value = "根据科室名称,日期,时间和医生查询是否有号源,并返回给用户") + public boolean queryDepartment( + @P(value = "科室名称") String name, + @P(value = "日期") String date, + @P(value = "时间,可选值:上午、下午") String time, + @P(value = "医生名称", required = false) String doctorName + ) { + + System.out.println("查询是否有号源"); + System.out.println("科室名称: " + name); + System.out.println("日期: " + date); + System.out.println("时间: " + time); + System.out.println("医生名称: " + doctorName); + + // TODO 维护医生的排班信息: + // 如果没有指定医生名字,则根据其他条件查询是否有可以预约的医生(有返回true,否则返回false); + // + // 如果指定了医生名字,则判断医生是否有排班(没有排版返回false) + // 如果有排班,则判断医生排班时间段是否已约满(约满返回false,有空闲时间返回true) + return true; + } +} diff --git a/langchain4j-ai-xiaoai-agent/src/main/resources/application.yml b/langchain4j-ai-xiaoai-agent/src/main/resources/application.yml new file mode 100644 index 0000000..8aad13b --- /dev/null +++ b/langchain4j-ai-xiaoai-agent/src/main/resources/application.yml @@ -0,0 +1,31 @@ +server: + port: 8080 + servlet: + encoding: + charset: utf-8 + enabled: true + force: true # 设置响应的字符编码,避免流式返回输出乱码 +spring: + application: + name: langchain4j-ai-xiaoai-agent + data: + mongodb: + uri: mongodb://localhost:27017/xiao_ai_db # MongoDB连接配置,数据库 xiao_ai_db 会自动创建 + datasource: + driver-class-name: + type: com.alibaba.druid.pool.DruidDataSource + url: jdbc:mysql://localhost:3306/langchain4j?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true + username: root + password: 123456 +#配置Mybatis +mybatis: + mapper-locations: classpath:mapper/*.xml + type-aliases-package: com.iwe3.langchain4j.entity + configuration: + map-underscore-to-camel-case: true +langchain4j: + community: + dashscope: + embedding-model: + model-name: text-embedding-v3 + api-key: ${DASH_SCOPE_API_KEY} \ No newline at end of file diff --git a/langchain4j-ai-xiaoai-agent/src/main/resources/documents/医院信息.md b/langchain4j-ai-xiaoai-agent/src/main/resources/documents/医院信息.md new file mode 100644 index 0000000..8652454 --- /dev/null +++ b/langchain4j-ai-xiaoai-agent/src/main/resources/documents/医院信息.md @@ -0,0 +1,35 @@ +**医院名称:** + 四川大学华西医院 + +**医院地址:** + (国重院区)四川省成都市武侯区国学巷37号,邮编:610041 + (温江院区)四川省成都市温江区万春东路566号,邮编:611135 + +**门诊开放时间:** + 工作日:8:00 - 17:30 + 急诊:24小时开放 + +**服务热线:** + (国重院区)028-85422114 + (温江院区)028-87606666 + +**医院简介:** + 四川大学华西医院是中国西部疑难危急重症诊疗的国家级中心,集医疗、教学、科研、预防、保健、康复为一体,是国家三级甲等综合医院、国家临床医学研究中心、国家药物临床试验机构。作为中国现代医学教育的重要发源地之一,华西医院拥有全国领先的学科群,尤其在麻醉学、放射学、胸外科、泌尿外科、消化内科、老年医学等领域具有突出优势。连续多年在全国三级公立医院绩效考核中位居前列,综合实力稳居全国第一方阵,享有“北有协和,南有华西”的盛誉。 + +**国重院区乘车路线:** + +1. 16、21、26、28、34、45、58、61、77、99路到“华西坝”站 +2. 地铁1号线或18号线到“华西坝”站,B出口步行约3分钟 +3. 机场专线2号线至“省体育馆”站,换乘地铁1号线1站即达 + +**温江院区乘车路线:** + +1. 温江W13、W22、W26、W31路到“华西医院温江院区”站 +2. 地铁17号线到“明光站”,C出口换乘接驳公交或步行约15分钟 +3. 自驾可经成都绕城高速“文家场”出口或成温邛高速“金马”出口抵达 + +**国重院区预约号取号地点:** + 国重院区门诊楼一层大厅自助取号机或人工挂号窗口取号 + +**温江院区预约号取号地点:** + 温江院区门诊楼一层大厅自助取号机或挂号收费窗口取号 \ No newline at end of file diff --git a/langchain4j-ai-xiaoai-agent/src/main/resources/documents/口腔科.md b/langchain4j-ai-xiaoai-agent/src/main/resources/documents/口腔科.md new file mode 100644 index 0000000..41c8885 --- /dev/null +++ b/langchain4j-ai-xiaoai-agent/src/main/resources/documents/口腔科.md @@ -0,0 +1,85 @@ +# 四川大学华西医院口腔科详细介绍 + +四川大学华西医院口腔科源于1907年成立的**华西协合大学牙学院**——中国现代口腔医学的发源地,也是亚洲最早建立的高等口腔医学教育机构。历经百余年发展,华西口腔已成长为集医疗、教学、科研于一体的国家级口腔医学中心,被誉为“中国口腔医学的摇篮”。 + +作为四川大学华西医院的重要组成部分,口腔科依托**国家口腔疾病临床医学研究中心**、**口腔医学国家重点实验室**和**国家“双一流”建设学科**,始终站在中国口腔医学发展的前沿。科室秉承“选英才、育精英、创精品”的理念,在口腔疑难重症诊治、多学科协作及技术创新方面具有全国引领地位。 + +## 历史沿革 + +- **1907年**:加拿大传教士林则博士(Dr. Ashley W. Lindsay)在成都创办华西协合大学牙学院,开创中国高等口腔医学教育先河。 +- **1950年代**:在全国院系调整中,华西口腔成为新中国口腔医学人才培养的核心基地。 +- **1980年代至今**:持续引领口腔种植、颌面外科、牙体牙髓病、牙周病等领域的临床与科研创新,多项技术填补国内空白。 +- **2000年后**:随着四川大学华西医院综合实力提升,口腔科进一步整合资源,强化与全身疾病管理的联动,形成“大口腔、大健康”服务模式。 + +## 科室现状 + +目前,华西医院口腔科设有以下专业组: + +- 口腔颌面外科学 +- 牙体牙髓病学 +- 牙周病学 +- 口腔修复学 +- 口腔正畸学 +- 口腔种植学 +- 儿童口腔病学 +- 口腔黏膜病学 +- 无痛舒适化治疗中心 +- 口腔激光诊疗中心 + +科室配备**80余台国际先进口腔综合治疗台**、**20张住院病床**,拥有医护人员**130余人**,其中医生**70名**(含教授/主任医师15人、副教授/副主任医师20人)、护理及技术人员**60余名**。现有**博士生导师10人**、**硕士生导师15人**,形成结构合理、梯队完善的人才体系。 + +## 学术影响与行业地位 + +- 华西口腔连续多年在复旦版《中国医院专科声誉排行榜》中位列**全国第一**。 +- 多位专家担任国家级学会主委/副主委: + - **周学东教授**:曾任中华口腔医学会会长,中国工程院院士候选人,龋病防治权威。 + - **石冰教授**:中华口腔医学会唇腭裂专委会前任主委,国际知名唇腭裂整形专家。 + - **胡静教授**:中华口腔医学会口腔颌面外科专委会主委,擅长复杂颌面畸形与肿瘤整复。 + - **王杭教授**:中华口腔医学会镇静镇痛专委会常委,国内舒适化牙科治疗先行者。 + +科室每年承担**国家自然科学基金重点项目、科技部重点研发计划**等国家级课题20余项,发表SCI论文300+篇,牵头制定多项**国家口腔诊疗规范与指南**。 + +## 特色优势 + +- **多学科协作(MDT)**:作为大型综合医院口腔科,可高效联动内分泌科、心血管科、血液科等,为合并全身疾病的患者(如糖尿病、高血压、凝血障碍)提供安全、个体化的口腔治疗。 +- **舒适化诊疗**:2005年率先成立西南地区首个“无痛牙科中心”,开展笑气镇静、静脉镇静、全麻下儿童牙病治疗等技术。 +- **数字化精准口腔**:全面应用CBCT、口内扫描、3D打印、动态导航种植等数字技术,实现精准诊断与微创治疗。 + +------ + +## 科室地址 + +- **国重院区**:成都市武侯区国学巷37号,四川大学华西医院门诊楼**8层** +- **温江院区**:成都市温江区万春东路566号,门诊楼**3层** + +------ + +## 专家团队 + +### 胡静 + +**口腔颌面外科主任 主任医师 教授 博士生导师** + +**擅长**:口腔颌面部肿瘤、复杂颌骨畸形、创伤修复、正颌外科 + **简介**: + 胡静,教授、主任医师,博士生导师。现任中华口腔医学会口腔颌面外科专业委员会主任委员。从事口腔颌面外科临床工作30余年,在颌面部肿瘤根治与功能重建、先天性颌面畸形矫正等领域具有极高造诣。主持国家自然科学基金重点项目5项,获国家科技进步二等奖1项。带领团队完成西南地区首例“全脸移植”术前评估与规划。 + +------ + +### 王杭 + +**口腔科副主任 主任医师 教授** + +**擅长**:无痛牙科治疗、牙科恐惧症干预、复杂牙体牙髓病、老年口腔综合治疗 + **简介**: + 王杭,主任医师,教授。中华口腔医学会镇静镇痛专业委员会常委,四川省口腔医学会舒适化诊疗学组组长。2006年创建华西“舒适牙科中心”,是国内最早系统开展笑气/静脉镇静下牙科治疗的专家之一。主编《舒适化口腔诊疗技术规范》,培训全国基层医师超千人。 + +------ + +### 石冰 + +**唇腭裂中心主任 主任医师 教授 博士生导师** + +**擅长**:唇腭裂序列治疗、颌骨发育畸形矫正、语音康复 + **简介**: + 石冰,教授,博士生导师,国际唇腭裂基金会(ICPF)顾问。曾任中华口腔医学会唇腭裂专委会主任委员。创立“华西唇腭裂序列治疗模式”,累计完成唇腭裂手术超万例,技术辐射“一带一路”多个国家。获“全国优秀科技工作者”称号。 \ No newline at end of file diff --git a/langchain4j-ai-xiaoai-agent/src/main/resources/documents/神经内科.md b/langchain4j-ai-xiaoai-agent/src/main/resources/documents/神经内科.md new file mode 100644 index 0000000..5866660 --- /dev/null +++ b/langchain4j-ai-xiaoai-agent/src/main/resources/documents/神经内科.md @@ -0,0 +1,32 @@ +### 四川大学华西医院神经内科详细介绍 + +四川大学华西医院神经内科成立于1914年,历经百年发展,已成为国内乃至国际上享有盛誉的专业科室之一。作为中国西部地区最早成立的神经病学专业科室,华西医院神经内科不仅是全国首批神经病学硕士、博士学位授予点及博士后工作站,也是国家级重点学科,在处理复杂疑难杂症方面处于领先地位。 + +#### 科室设置与服务 + +- **专业组**:临床神经生理、脑电图与癫痫、痴呆与认知障碍、脑血管病、帕金森及运动障碍、神经病理、神经肌肉病、感染与脑脊液细胞学、神经免疫、神经遗传和睡眠等11个专业组。 +- **特色门诊**:开设有神经肌肉病门诊、肌张力障碍和肉毒毒素治疗门诊、帕金森病和老年痴呆门诊、癫痫门诊、脑血管病门诊、运动神经元病、重症肌无力门诊、多发性硬化门诊和头痛门诊等9个特色门诊,为患者提供高水平的医疗服务。 + +#### 医疗实力 + +- **床位数**:拥有超过100张床位,每年门急诊接诊量超过20万人次,住院患者超过2000人次。 +- **实验室设施**:配备了先进的肌电图与脑诱发电位、神经病理、脑电图、经颅超声多普勒、神经生化和免疫、分子生物学实验室,为临床诊断提供了强有力的支持。 + +#### 科研与教学 + +- **科研成就**:近五年来承担了超过50项科研课题,包括多项国家级重点项目,累计科研经费超过5000万元,并获得了包括国家科技进步奖在内的多个重要奖项。 +- **教学任务**:承担四川大学华西临床医学院本科生、研究生、进修医师的教学工作,是四川省住院医师规范化培训基地。每年举办多个国家级继续教育学习班,如神经系统疾病高级进展学习班、经颅多普勒超声学习班等,为全国输送大量神经内科专科人才。 + +#### 专家团队 + +- **现有医生**:共有60余名医生,其中包括教授12人、副教授18人、主治医生20人、住院医生10人,其中博士生导师8人,硕士生导师10人。 + +- 知名专家: + + - **李为民**:主任医师,教授,博士研究生导师。擅长脑血管病及神经系统危重疾病的诊治,在国内外发表学术论文150余篇。 +- **王莉**:现任神经内科主任,教授,博士研究生导师。专注于运动神经元病、周围神经病、肌肉病等神经系统的各种疑难杂症的研究与治疗,发表了超过300篇学术论文,并著书20余本。 + +#### 地址与联系方式 + +- **地址**:成都市武侯区国学巷37号,四川大学华西医院门诊楼6层。 +- **电话**:028-85422114(总机) \ No newline at end of file diff --git a/langchain4j-ai-xiaoai-agent/src/main/resources/documents/科室信息.md b/langchain4j-ai-xiaoai-agent/src/main/resources/documents/科室信息.md new file mode 100644 index 0000000..9588950 --- /dev/null +++ b/langchain4j-ai-xiaoai-agent/src/main/resources/documents/科室信息.md @@ -0,0 +1,13 @@ +### 四川大学华西医院科室详细介绍 + +#### 1、内科学系 + +心内科、呼吸与危重症医学科、消化内科、肾内科、血液内科、风湿免疫科、感染性疾病中心、全科医学科(普通内科)、肿瘤中心(含肿瘤内科、放疗科)、老年医学科、内分泌代谢科、重症医学科(ICU/MICU)、儿科、神经内科、心理卫生中心、皮肤性病科、变态反应(过敏)科、急诊科、中医科、康复医学科、临床营养科、罕见病诊治中心。 + +#### 2、外科学系 + +普外科(含胃肠外科、结直肠外科、胰腺外科、甲状腺外科等亚专业)、骨科、心脏大血管外科、胸外科、泌尿外科、神经外科、血管外科、整形外科/烧伤科、乳腺疾病中心、肝脏外科/肝移植中心、麻醉科、手术室。 + +#### 3、其他科室 + +妇产科(含妇科、产科、生殖医学中心)、眼科、耳鼻咽喉头颈外科、口腔科(依托华西口腔医学院,全国顶尖)、超声医学科、病理科、检验科、放射科(医学影像中心)、放射治疗科(肿瘤放疗中心)、核医学科、输血科、药剂科、病案管理科、国际医疗部、健康管理中心(体检中心)、临床药理研究中心、转化医学中心、护理部、医务部、医院感染管理部。 \ No newline at end of file diff --git a/langchain4j-ai-xiaoai-agent/src/main/resources/mapper/AppointmentMapper.xml b/langchain4j-ai-xiaoai-agent/src/main/resources/mapper/AppointmentMapper.xml new file mode 100644 index 0000000..b6a678e --- /dev/null +++ b/langchain4j-ai-xiaoai-agent/src/main/resources/mapper/AppointmentMapper.xml @@ -0,0 +1,35 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/langchain4j-ai-xiaoai-agent/src/main/resources/xiaoai-prompt.txt b/langchain4j-ai-xiaoai-agent/src/main/resources/xiaoai-prompt.txt new file mode 100644 index 0000000..c2e1cd7 --- /dev/null +++ b/langchain4j-ai-xiaoai-agent/src/main/resources/xiaoai-prompt.txt @@ -0,0 +1,18 @@ +你的名字是“小艾”,你是一家名为“四川大学华西医院”的智能客服。 +你是一个训练有素的医疗顾问和医疗伴诊助手。 +你态度友好、礼貌且言辞简洁。 +1、请仅在用户发起第一次会话时,和用户打个招呼,并介绍你是谁。 +2、作为一个训练有素的医疗顾问: +请基于当前临床实践和研究,针对患者提出的特定健康问题,提供详细、准确且实用的医疗建议。请同时考虑可能的病 +因、诊断流程、治疗方案以及预防措施,并给出在不同情境下的应对策略。对于药物治疗,请特别指明适用的药品名 +称、剂量和疗程。如果需要进一步的检查或就医,也请明确指示。 +3、作为医疗伴诊助手,你可以回答用户就医流程中的相关问题,主要包含以下功能: +AI分导诊:根据患者的病情和就医需求,智能推荐最合适的科室。 +AI挂号助手:实现智能查询是否有挂号号源服务;实现智能预约挂号服务;实现智能取消挂号服务。 +4、你必须遵守的规则如下: +在获取挂号预约详情或取消挂号预约之前,你必须确保自己知晓用户的姓名(必选)、身份证号(必选)、预约科室 +(必选)、预约日期(必选,格式举例:2025-12-12)、预约时间(必选,格式:上午 或 下午)、预约医生(可 +选)。 +当被问到其他领域的咨询时,要表示歉意并说明你无法在这方面提供帮助。 +5、请在回答的结果中适当包含一些轻松可爱的图标和表情。 +6、今天是 {{current_date}} \ No newline at end of file diff --git a/langchain4j-ai-xiaoai-agent/src/test/java/com/iwe3/langchain4j/RagUploadTest.java b/langchain4j-ai-xiaoai-agent/src/test/java/com/iwe3/langchain4j/RagUploadTest.java new file mode 100644 index 0000000..74c4644 --- /dev/null +++ b/langchain4j-ai-xiaoai-agent/src/test/java/com/iwe3/langchain4j/RagUploadTest.java @@ -0,0 +1,40 @@ +package com.iwe3.langchain4j; + +import dev.langchain4j.data.document.loader.FileSystemDocumentLoader; +import dev.langchain4j.data.document.parser.TextDocumentParser; +import dev.langchain4j.model.embedding.EmbeddingModel; +import dev.langchain4j.store.embedding.EmbeddingStore; +import dev.langchain4j.store.embedding.EmbeddingStoreIngestor; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; + +import java.nio.file.FileSystems; + +@SpringBootTest +public class RagUploadTest { + + @Autowired + private EmbeddingStore embeddingStore; + + @Autowired + private EmbeddingModel embeddingModel; + + @Test + public void testUploadKnowledgeLibrary() { + // 使用FileSystemDocumentLoader读取指定目录下的知识库文档 + var pathMatcher = FileSystems.getDefault() + .getPathMatcher("glob:*\\.md"); + var documents = FileSystemDocumentLoader + .loadDocuments("D:/documents", pathMatcher, + new TextDocumentParser()); + + // 文本向量化并存入向量数据库:将每个片段进行向量化,得到一个嵌入向量 + EmbeddingStoreIngestor + .builder() + .embeddingStore(embeddingStore) + .embeddingModel(embeddingModel) + .build() + .ingest(documents); + } +} diff --git a/langchain4j-ai-xiaoai-agent/src/test/java/com/iwe3/langchain4j/XiaoAIAgentApplicationTest.java b/langchain4j-ai-xiaoai-agent/src/test/java/com/iwe3/langchain4j/XiaoAIAgentApplicationTest.java new file mode 100644 index 0000000..4630987 --- /dev/null +++ b/langchain4j-ai-xiaoai-agent/src/test/java/com/iwe3/langchain4j/XiaoAIAgentApplicationTest.java @@ -0,0 +1,42 @@ +package com.iwe3.langchain4j; + +import com.iwe3.langchain4j.record.AppointmentRecord; +import com.iwe3.langchain4j.service.IAppointmentService; +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class XiaoAIAgentApplicationTest { + + @Autowired + private IAppointmentService appointmentServiceImpl; + + + @Test + void saveAppointmentEntity() { + var record = new AppointmentRecord("贝利亚", + "123456789012345678", + "内科", + "2025-12-12","上午08.30","李娜"); + appointmentServiceImpl.saveAppointmentEntity(record); + } + + @Test + void removeById() { + appointmentServiceImpl.removeById(1L); + } + + @Test + void getOne() { + var record = new AppointmentRecord("贝利亚", + "123456789012345678", + "内科", + "2025-12-12","上午08.30","李娜"); + var entity = appointmentServiceImpl.getOne(record); + System.out.println("entity = " + entity); + } + + + +} \ No newline at end of file diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..d21fb38 --- /dev/null +++ b/pom.xml @@ -0,0 +1,90 @@ + + + 4.0.0 + + com.iwe3 + langchain4j-ai-java + 1.0-SNAPSHOT + pom + + + + langchain4j-ai-helloworld + langchain4j-ai-multimode + langchain4j-ai-low-high-api + langchain4j-ai-model-params + langchain4j-ai-image + langchain4j-ai-stream + langchain4j-ai-memory + langchain4j-ai-mongodb + langchain4j-ai-prompt + langchain4j-ai-xiaoai-agent + langchain4j-ai-tools + langchain4j-ai-rag + langchain4j-ai-pinecone + + + + 17 + 17 + UTF-8 + + 3.5.0 + + 1.0.0 + + 1.0.0-M6.1 + + 1.9.1 + + 1.0.1-beta6 + + + + + + org.springframework.boot + spring-boot-dependencies + ${spring-boot.version} + pom + import + + + + org.springframework.ai + spring-ai-bom + ${spring-ai.version} + pom + import + + + + com.alibaba.cloud.ai + spring-ai-alibaba-starter + ${spring-ai-alibaba.version} + + + + dev.langchain4j + langchain4j-bom + ${langchain4j.version} + pom + import + + + + dev.langchain4j + langchain4j-community-bom + ${langchain4j-community.version} + pom + import + + + + \ No newline at end of file