LangChain4j 续集
本文介绍了LangChain4j框架在模型参数配置、多模态视觉理解、流式输出、记忆缓存和提示词工程等方面的应用开发。主要内容包括:1) 通过OpenAI协议标准配置模型参数,实现日志、监控、重试和超时机制;2) 多模态开发实现图像理解和文生图功能;3) 流式输出响应式编程实现;4) 记忆缓存管理对话上下文;5) 提示词工程限定AI助手能力范围。开发过程涵盖模块创建、POM依赖配置、YML参数设置、
五、LangChain4j之模型参数配置
5.1 开发步骤基础工程Base
5.1.1 建module
langchain4j-05model-parameters
5.1.2 改pom
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--langchain4j-open-ai 基础-->
<!--所有调用均基于 OpenAI 协议标准,实现一致的接口设计与规范LangChain4j 提供与许多 LLM 提供商的集成
从最简单的开始方式是从 OpenAI 集成开始https://docs.langchain4j.dev/get-started -->
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-open-ai</artifactId>
</dependency>
<!--langchain4j 高阶-->
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j</artifactId>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!--hutool-->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.22</version>
</dependency>
<!--test-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
5.1.3 写yml
server.port=9005
spring.application.name=langchain4j-05model-parameters
5.1.4 主启动
5.1.5 业务类
@Configuration
public class LLMConfig
{
@Bean(name = "qwen")
public ChatModel chatModelQwen()
{
return OpenAiChatModel.builder()
.apiKey(System.getenv("aliQwen-api"))
.modelName("qwen-plus")
.baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1")
.build();
}
}
@RestController
@Slf4j
public class ModelParameterController
{
@Resource
private ChatModel chatModelQwen;
// http://localhost:9003/chatconfig/config
@GetMapping(value = "/modelparam/config")
public String config(@RequestParam(value = "prompt", defaultValue = "你是谁") String prompt)
{
String result = chatModelQwen.chat(prompt);
System.out.println("通过langchain4j调用模型返回结果:"+result);
return result;
}
}
5.2 日志配置
只有日志级别调整为debug级别,同时配置以上 langchain 日志输出开关才有效
@Configuration
public class LLMConfig
{
@Bean(name = "qwen")
public ChatModel chatModelQwen()
{
return OpenAiChatModel.builder()
.apiKey(System.getenv("aliQwen-api"))
.modelName("qwen-plus")
.baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1")
.logRequests(true) // 日志界别设置为debug才有效
.logResponses(true)// 日志界别设置为debug才有效
.build();
}
}
配置类
server.port=9005
spring.application.name=langchain4j-05model-parameters
# 只有日志级别调整为debug级别,同时配置以上 langchain 日志输出开关才有效
logging.level.dev.langchain4j = DEBUG
测试:

5.3 监控 (Observability)
配置类
@Configuration
public class LLMConfig
{
@Bean(name = "qwen")
public ChatModel chatModelQwen()
{
return OpenAiChatModel.builder()
.apiKey(System.getenv("aliQwen-api"))
.modelName("qwen-plus")
.baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1")
.logRequests(true) // 日志界别设置为debug才有效
.logResponses(true)// 日志界别设置为debug才有效
.listeners(List.of(new TestChatModelListener())) //监听器
.build();
}
}
@Slf4j
public class TestChatModelListener 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);
}
}
5.4 重试机制 (Retry Configuration)
@Configuration
public class LLMConfig
{
@Bean(name = "qwen")
public ChatModel chatModelQwen()
{
return OpenAiChatModel.builder()
.apiKey(System.getenv("aliQwen-api"))
.modelName("qwen-plus")
.baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1")
.logRequests(true) // 日志界别设置为debug才有效
.logResponses(true)// 日志界别设置为debug才有效
.listeners(List.of(new TestChatModelListener())) //监听器
.maxRetries(2)// 重试机制共计2次
.build();
}
}
5.5 超时时间 timeout
@Configuration
public class LLMConfig
{
@Bean(name = "qwen")
public ChatModel chatModelQwen()
{
return OpenAiChatModel.builder()
.apiKey(System.getenv("aliQwen-api"))
.modelName("qwen-plus")
.baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1")
.logRequests(true) // 日志界别设置为debug才有效
.logResponses(true)// 日志界别设置为debug才有效
.listeners(List.of(new TestChatModelListener())) //监听器
.maxRetries(2)// 重试机制
.timeout(Duration.ofSeconds(3))
.build();
}
}
六、LangChain4j之多模态视觉理解
6.1 LangChain4j进行图像理解
模型选择

6.2 案例开发1
6.2.1 建module
langchain4j-06chat-image
6.2.2 改pom
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--langchain4j-open-ai 基础-->
<!--所有调用均基于 OpenAI 协议标准,实现一致的接口设计与规范LangChain4j 提供与许多 LLM 提供商的集成
从最简单的开始方式是从 OpenAI 集成开始https://docs.langchain4j.dev/get-started -->
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-open-ai</artifactId>
</dependency>
<!--langchain4j 高阶-->
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j</artifactId>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!--hutool-->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.22</version>
</dependency>
<!--test-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
6.2.3 写yml
server.port=9006
spring.application.name=langchain4j-06chat-image
6.2.4 主启动
6.2.5 业务类
①. resources目录下放入mi.jpg图片

② LLMConfig配置
@Configuration
public class LLMConfig
{
@Bean
public ChatModel ImageModel() {
return OpenAiChatModel.builder()
.apiKey(System.getenv("aliQwen-api"))
//qwen-vl-max 是一个多模态大模型,支持图片和文本的结合输入,适用于视觉-语言任务。
.modelName("qwen-vl-max")
.baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1")
.build();
}
}
③.
a.图片转码:通过Base64编码将图片转化为字符串
b. 提示词指定:结合ImageContent和TextContent一起发送到模型进行处理。
c. API调用:使用OpenAiChatModel来构建请求,并通过chat()方法调用模型。请求内容包括文本提示和图片,模型会根据输入返回分析结果。
d. 解析与输出:从ChatResponse中获取AI大模型的回复,打印出处理后的结果。
@Value("classpath:static.images/鼠.jpg")
private Resource resource;
// http://localhost:9006/image/call@GetMapping("/image/call")
public String readImageProcessor() throws IOException {
byte[] imageByte = resource.getContentAsByteArray();
String base64String = Base64.getEncoder().encodeToString(imageByte);
UserMessage userMessage = UserMessage.from(
TextContent.from("分析一下图片"),
ImageContent.from(base64String, "image/jpg")
);
ChatResponse chatResponse = chatModel.chat(userMessage);
String text = chatResponse.aiMessage().text();
System.out.println(text);
return text;
}
6.3 切换通义万相-文生图模型 wanx2.1-t2i-turbo 它支持通过一句话生成图像

6.3.1 修改父工程POM文件
<!--langchain4j-community 引入阿里云百炼平台依赖管理清单-->
<langchain4j-community.version>1.0.1-beta6</langchain4j-community.version>
6.3.2 改POM
<!--DashScope (Qwen)接入阿里云百炼平台
https://docs.langchain4j.dev/integrations/language-models/dashscope
-->
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-community-dashscope-spring-boot-starter</artifactId>
</dependency>
6.3.3 写YML
server.port=9006
spring.application.name=langchain4j-06chat-image
6.3.4 主启动
6.3.5 业务类
/**
* @Description: 测试通义万象来实现图片生成,
* 官网说明:https://help.aliyun.com/zh/model-studio/text-to-image
*/
@Bean
public WanxImageModel wanxImageModel()
{
return WanxImageModel.builder()
.apiKey(System.getenv("aliQwen-api"))
.modelName("wanx2.1-t2i-turbo") //图片生成 https://help.aliyun.com/zh/model-studio/text-to-image
.build();
}
@RestController
@Slf4j
public class WanxImageModelController
{
@Autowired
private WanxImageModel wanxImageModel;
// http://localhost:9006/image/create2
@GetMapping(value = "/image/create2")
public String createImageContent2() throws IOException
{
System.out.println(wanxImageModel);
Response<Image> imageResponse = wanxImageModel.generate("美女");
System.out.println(imageResponse.content().url());
return imageResponse.content().url().toString();
}
@GetMapping(value = "/image/create3")
public String createImageContent3() throws IOException
{
String prompt = "近景镜头,18岁的中国女孩,古代服饰,圆脸,正面看着镜头," +
"民族优雅的服装,商业摄影,室外,电影级光照,半身特写,精致的淡妆,锐利的边缘。";
ImageSynthesisParam param =
ImageSynthesisParam.builder()
.apiKey(System.getenv("aliQwen-api"))
.model(ImageSynthesis.Models.WANX_V1)
.prompt(prompt)
.style("<watercolor>")
.n(1)
.size("1024*1024")
.build();
ImageSynthesis 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);
}
}
七、LangChain4j之流式输出
7.1 前置知识点
Springboot3响应式编程
7.2 案例开发
7.2.1 建Module
langchain4j-07chat-stream
7.2.2
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--langchain4j-open-ai + langchain4j + langchain4j-reactor-->
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-open-ai</artifactId>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j</artifactId>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-reactor</artifactId>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!--hutool-->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.22</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
7.2.3 写YML
server.port=9007
spring.application.name=langchain4j-07chat-stream
# 设置响应的字符编码,避免流式返回输出乱码
server.servlet.encoding.charset=utf-8
server.servlet.encoding.enabled=true
server.servlet.encoding.force=true
7.2.4 主启动
7.2.5 业务类
① ChatAssistant接口
② 注意ChatModel的改变
③ Config 配置
@Configuration
public class LLMConfig
{
@Bean(name = "qwen")
public ChatModel chatModelQwen()
{
return OpenAiChatModel.builder()
.apiKey(System.getenv("aliQwen-api"))
.modelName("qwen-plus")
.baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1")
.build();
}
@Bean
public StreamingChatModel streamingChatModel(){
return OpenAiStreamingChatModel.builder()
.apiKey(System.getenv("aliQwen-api"))
.modelName("qwen-plus")
.baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1")
.build();
}
@Bean
public ChatAssistant chatAssistant(StreamingChatModel streamingChatModel){
return AiServices.create(ChatAssistant.class, streamingChatModel);
}
}
④ Controller
@RestController
@Slf4j
public class StreamingChatModelController
{
@Resource //直接使用 low-level LLM API
private StreamingChatModel streamingChatLanguageModel;
@Resource //自己封装接口使用 high-level LLM API
private ChatAssistant chatAssistant;
// http://localhost:9007/chatstream/chat?prompt=天津有什么好吃的
@GetMapping(value = "/chatstream/chat")
public Flux<String> chat(@RequestParam("prompt") String prompt)
{
return Flux.create(stringFluxSink -> {
streamingChatLanguageModel.chat(prompt, new StreamingChatResponseHandler()
{
@Override
public void onPartialResponse(String s)
{
stringFluxSink.next(s);
}
@Override
public void onCompleteResponse(ChatResponse completeResponse)
{
stringFluxSink.complete();
}
@Override
public void onError(Throwable throwable)
{
stringFluxSink.error(throwable);
}
});
});
}
@GetMapping(value = "/chatstream/chat2")
public void chat2(@RequestParam(value = "prompt", defaultValue = "北京有什么好吃") String prompt)
{
System.out.println("---come in chat2");
streamingChatLanguageModel.chat(prompt, new StreamingChatResponseHandler()
{
@Override
public void onPartialResponse(String partialResponse)
{
System.out.println(partialResponse);
}
@Override
public void onCompleteResponse(ChatResponse completeResponse)
{
System.out.println("---response over: "+completeResponse);
}
@Override
public void onError(Throwable throwable)
{
throwable.printStackTrace();
}
});
}
@GetMapping(value = "/chatstream/chat3")
public Flux<String> chat3(@RequestParam(value = "prompt", defaultValue = "南京有什么好吃") String prompt)
{
System.out.println("---come in chat3");
return chatAssistant.chatFlux(prompt);
}
}
八、LangChain4j之记忆缓存
8.1 介绍
是什么?
记忆缓存是聊天系统中的一个重要组件,用于存储和管理对话的上下文信息。它的主要作用是让AI助手能够”记住”之前的对话内容,从而提供连贯和个性化的回复。
Eviction policy:

8.2 案例开发
8.2.1 建module
langchain4j-08chat-memory
8.2.2 改POM
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--langchain4j-open-ai + langchain4j + langchain4j-reactor-->
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-open-ai</artifactId>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j</artifactId>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-reactor</artifactId>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!--hutool-->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.22</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
8.2.3 写YML
server.port=9008
spring.application.name=langchain4j-08chat-memory
# 设置响应的字符编码
server.servlet.encoding.charset=utf-8
server.servlet.encoding.enabled=true
server.servlet.encoding.force=true
8.2.4 主启动
8.2.5 业务类
① 新建接口
public interface ChatMemoryAssistant
{
/**
* 聊天带记忆缓存功能
*
* @param userId 用户 ID
* @param prompt 消息
* @return {@link String }
*/
String chatWithChatMemory(@MemoryId Long userId, @UserMessage String prompt);
}
② Config 配置 更换模型

@Configuration
public class LLMConfig
{
@Bean
public ChatModel chatModel()
{
return OpenAiChatModel.builder()
.apiKey(System.getenv("aliQwen-api"))
.modelName("qwen-long")
.baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1")
.build();
}
@Bean(name = "chat")
public ChatAssistant chatAssistant(ChatModel chatModel)
{
return AiServices.create(ChatAssistant.class, chatModel);
}
@Bean(name = "chatMessageWindowChatMemory")
public ChatMemoryAssistant chatMessageWindowChatMemory(ChatModel chatModel)
{
return AiServices.builder(ChatMemoryAssistant.class)
.chatModel(chatModel)
// 注意每个memoryId对应创建一个ChatMemory
.chatMemoryProvider(memoryId -> MessageWindowChatMemory.withMaxMessages(100))
.build();
}
@Bean(name = "chatTokenWindowChatMemory")
public ChatMemoryAssistant chatTokenWindowChatMemory(ChatModel chatModel)
{
// TokenCountEstimator默认的token分词器,需要结合Tokenizer计算ChatMessage的token数量
TokenCountEstimator openAiTokenizer = new OpenAiTokenCountEstimator("gpt-4");
return AiServices.builder(ChatMemoryAssistant.class)
.chatModel(chatModel)
.chatMemoryProvider(memoryId -> TokenWindowChatMemory.withMaxTokens(1000,openAiTokenizer))
.build();
}
}
③ Controller
@RestController
@Slf4j
public class ChatMemoryController
{
@Resource(name = "chat")
private ChatAssistant chatAssistant;
@Resource(name = "chatMessageWindowChatMemory")
private ChatMemoryAssistant chatMessageWindowChatMemory;
@Resource(name = "chatTokenWindowChatMemory")
private ChatMemoryAssistant chatTokenWindowChatMemory;
@GetMapping(value = "/chatmemory/test1")
public String chat()
{
String answer01 = chatAssistant.chat("你好,我的名字叫张三");
System.out.println("answer01返回结果:"+answer01);
String answer02 = chatAssistant.chat("我的名字是什么");
System.out.println("answer02返回结果:"+answer02);
return "success : "+ DateUtil.now()+"<br> \n\n answer01: "+answer01+"<br> \n\n answer02: "+answer02;
}
@GetMapping(value = "/chatmemory/test2")
public String chatMessageWindowChatMemory()
{
chatMessageWindowChatMemory.chatWithChatMemory(1L, "你好!我的名字是Java.");
String answer01 = chatMessageWindowChatMemory.chatWithChatMemory(1L, "我的名字是什么");
System.out.println("answer01返回结果:"+answer01);
chatMessageWindowChatMemory.chatWithChatMemory(3L, "你好!我的名字是C++");
String answer02 = chatMessageWindowChatMemory.chatWithChatMemory(3L, "我的名字是什么");
System.out.println("answer02返回结果:"+answer02);
return "chatMessageWindowChatMemory success : "
+ DateUtil.now()+"<br> \n\n answer01: "+answer01+"<br> \n\n answer02: "+answer02;
}
@GetMapping(value = "/chatmemory/test3")
public String chatTokenWindowChatMemory()
{
chatTokenWindowChatMemory.chatWithChatMemory(1L, "你好!我的名字是mysql");
String answer01 = chatTokenWindowChatMemory.chatWithChatMemory(1L, "我的名字是什么");
System.out.println("answer01返回结果:"+answer01);
chatTokenWindowChatMemory.chatWithChatMemory(3L, "你好!我的名字是oracle");
String answer02 = chatTokenWindowChatMemory.chatWithChatMemory(3L, "我的名字是什么");
System.out.println("answer02返回结果:"+answer02);
return "chatTokenWindowChatMemory success : "
+ DateUtil.now()+"<br> \n\n answer01: "+answer01+"<br> \n\n answer02: "+answer02;
}
}
九、LangChain4j之提示词工程
9.1 能干吗
打造专业的限定能力范围和作用边界的AI助手
9.2 案例开发
9.2.1 设计要求:
使用SystemMessage明确定义助手的角色和能力范围,将其限定在法律咨询领域。在LangChain4j中,我们主要利用SystemMessage来实现这一点,SystemMessage具有高优先级,能有效地指导模型的整体行为
利用提示词模板(@UserMessage, @V)精确控制输入和期望的输出格式,确保问题被正确理解和回答
9.2.2 建module
langchain4j-09chat-prompt
9.2.3 改pom
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--langchain4j-open-ai + langchain4j + langchain4j-reactor-->
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-open-ai</artifactId>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j</artifactId>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-reactor</artifactId>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!--hutool-->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.22</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
9.2.4 写YML
server.port=9009
spring.application.name=langchain4j-09chat-prompt
# 设置响应的字符编码
server.servlet.encoding.charset=utf-8
server.servlet.encoding.enabled=true
server.servlet.encoding.force=true
9.2.5 主启动
9.2.6 业务类
① 第一组
@SystemMessage+@ UserMessage+ @ V
public interface LawAssistant
{
//案例1
@SystemMessage("你是一位专业的中国法律顾问,只回答与中国法律相关的问题。" +
"输出限制:对于其他领域的问题禁止回答,直接返回'抱歉,我只能回答中国法律相关的问题。'")
@UserMessage("请回答以下法律问题:{{question}},字数控制在{{length}}以内")
String chat(@V("question") String question, @V("length") int length);
}
配置类:
@Configuration
public class LLMConfig
{
@Bean
public ChatModel chatModel()
{
return OpenAiChatModel.builder()
.apiKey(System.getenv("aliQwen-api"))
.modelName("qwen-long")
.baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1")
.build();
}
@Bean
public LawAssistant lawAssistant(ChatModel chatModel) {
return AiServices.create(LawAssistant.class, chatModel);
}
}
controller
@RestController
@Slf4j
public class ChatPromptController
{
@Resource
private LawAssistant lawAssistant;
// http://localhost:9009/chatprompt/test1
@GetMapping(value = "/chatprompt/test1")
public String test1()
{
String chat = lawAssistant.chat("什么是知识产权?",2000);
System.out.println(chat);
String chat2 = lawAssistant.chat("什么是java?",2000);
System.out.println(chat2);
String chat3 = lawAssistant.chat("介绍下西瓜和芒果",2000);
System.out.println(chat3);
String chat4 = lawAssistant.chat("飞机发动机原理",2000);
System.out.println(chat4);
return "success : "+ DateUtil.now()+"<br> \n\n chat: "+chat+"<br> \n\n chat2: "+chat2;
}
}
② 第二组
新建带着@StructuredPrompt的业务实体类
@Data
@StructuredPrompt("根据中国{{legal}}法律,解答以下问题:{{question}}")
public class LawPrompt
{
private String legal;
private String question;
}
接口类
public interface LawAssistant
{
//案例1
@SystemMessage("你是一位专业的中国法律顾问,只回答与中国法律相关的问题。" +
"输出限制:对于其他领域的问题禁止回答,直接返回'抱歉,我只能回答中国法律相关的问题。'")
@UserMessage("请回答以下法律问题:{{question}},字数控制在{{length}}以内")
String chat(@V("question") String question, @V("length") int length);
//案例2
@SystemMessage("你是一位专业的中国法律顾问,只回答与中国法律相关的问题。" +
"输出限制:对于其他领域的问题禁止回答,直接返回'抱歉,我只能回答中国法律相关的问题。'")
String chat(LawPrompt lawPrompt);
}
Controller
@GetMapping(value = "/chatprompt/test2")
public String test2()
{
LawPrompt prompt = new LawPrompt();
prompt.setLegal("知识产权");
prompt.setQuestion("TRIPS协议?");
String chat = lawAssistant.chat(prompt);
System.out.println(chat);
return "success : "+ DateUtil.now()+"<br> \n\n chat: "+chat;
}
③ 第三组
直接Controller
/**
* @Description: 单个参数可以使用{{it}》”占位符或者”{{参数名}”,如果为其他字符,系统不能自动识别会报错。
* @Auther: zzyybs@126.com
*/
@GetMapping(value = "/chatprompt/test3")
public String test3()
{
// 默认 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()+"<br> \n\n chat: "+chatResponse.aiMessage().text();
}
十、LangChain4j之持久化
10.1 设计要求
将客户和大模型的对话问答保存进Redis进行持久化记忆留存
10.2 建module
langchain4j-10chat-persistence
10.3 改POM
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--langchain4j-open-ai + langchain4j + langchain4j-reactor-->
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-open-ai</artifactId>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j</artifactId>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-reactor</artifactId>
</dependency>
<!--spring-boot-starter-data-redis
https://docs.langchain4j.dev/tutorials/chat-memory#persistence
-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!--hutool-->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.8.22</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
10.4 写YML
server.port=9010
spring.application.name=langchain4j-10chat-persistence
server.servlet.encoding.charset=utf-8
server.servlet.encoding.enabled=true
server.servlet.encoding.force=true
spring.data.redis.host=localhost
spring.data.redis.port=6379
spring.data.redis.database=0
spring.data.redis.connect-timeout=3s
spring.data.redis.timeout=2s
10.5 主启动
10.6 业务类
① 新建高阶接口ChatPersistenceAssistant
public interface ChatPersistenceAssistant
{
/**
* 聊天
* @param userId 用户 ID
* @param message 消息
* @return {@link String }
*/
String chat(@MemoryId Long userId, @UserMessage String message);
}
② Redis 配置类
@Configuration
@Slf4j
public class RedisConfig
{
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactor)
{
RedisTemplate<String,Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactor);
//设置key序列化方式string
redisTemplate.setKeySerializer(new StringRedisSerializer());
//设置value的序列化方式json,使用GenericJackson2JsonRedisSerializer替换默认序列化
redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
}
③ 自定义客户化ChatMemoryStore接口类
@Component
public class RedisChatMemoryStore implements ChatMemoryStore
{
public static final String CHAT_MEMORY_PREFIX = "CHAT_MEMORY:";
@Resource
private RedisTemplate<String,String> redisTemplate;
@Override
public List<ChatMessage> getMessages(Object memoryId)
{
String retValue = redisTemplate.opsForValue().get(CHAT_MEMORY_PREFIX + memoryId);
return ChatMessageDeserializer.messagesFromJson(retValue);
}
@Override
public void updateMessages(Object memoryId, List<ChatMessage> messages)
{
redisTemplate.opsForValue().set(CHAT_MEMORY_PREFIX + memoryId, ChatMessageSerializer.messagesToJson(messages));
}
@Override
public void deleteMessages(Object memoryId)
{
redisTemplate.delete(CHAT_MEMORY_PREFIX + memoryId);
}
}
④、 LLMConfig配置类
@Bean
public ChatPersistenceAssistant chatMemoryAssistant(ChatModel chatModel)
{
ChatMemoryProvider chatMemoryProvider = memoryId -> MessageWindowChatMemory.builder()
.id(memoryId)
.maxMessages(1000)
.chatMemoryStore(redisChatMemoryStore)
.build();
return AiServices.builder(ChatPersistenceAssistant.class)
.chatModel(chatModel)
.chatMemoryProvider(chatMemoryProvider)
.build();
}
更多推荐


所有评论(0)