LangChain4j(2):整合SpringBoot
1 新建Springboot项目
1.1 引入依赖
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.4.3</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>org.example</groupId>
<artifactId>langchain4jSpringbootpro</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>jar</packaging>
<name>langchain4jSpringbootpro</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<langchain4j.version>1.0.0-beta1</langchain4j.version>
</properties>
<dependencies>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-community-dashscope-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-community-bom</artifactId>
<version>${langchain4j.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
2 配置项
查看加载的依赖中的langchain4j-community-dashscope-spring-boot-starter的Autoconfig文件。
可以看到使用时需要的配置条件,需要配置apikey。
在源文件中可以查看配置模型:
新建配置application.properties
server.port=8080
langchain4j.community.dashscope.chat-model.api-key = 你的apikey
langchain4j.community.dashscope.chat-model.model-name = qwen-plus
2.3 代码实现
package org.example.controller;
import dev.langchain4j.community.model.dashscope.QwenChatModel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/ai")
public class AiController {
@Autowired
QwenChatModel qwenChatModel;
@RequestMapping("/chat")
public String test(@RequestParam(defaultValue = "你是谁") String message){
String chat = qwenChatModel.chat(message);
return chat;
}
}
2.4 访问结果
启动后,访问链接http://localhost:8080/ai/chat。
2 接入DeepSeek
接入DeepSeek只需要修改配置文件即可,如下:
langchain4j.community.dashscope.chat-model.api-key = 你的key
langchain4j.community.dashscope.chat-model.model-name = deepseek-r1
启动后,访问链接http://localhost:8080/ai/chat。
3 接入Ollama
安装Ollama,下载想要的大模型。
引用依赖:
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-ollama-spring-boot-starter</artifactId>
<version>${langchain4j.version}</version>
</dependency>
加入配置文件:
langchain4j.ollama.chat-model.base-url = http://localhost:11434
langchain4j.ollama.chat-model.model-name = deepseek-r1:1.5b
代码如下:
package org.example.controller;
import dev.langchain4j.community.model.dashscope.QwenChatModel;
import dev.langchain4j.model.chat.ChatLanguageModel;
import dev.langchain4j.model.ollama.OllamaChatModel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/ai")
public class AiController {
@Autowired
ChatLanguageModel chatLanguageModel;
@RequestMapping("/ollamachat")
public String ollamachatfuc(@RequestParam(defaultValue = "你是谁") String message){
String ollamachat = chatLanguageModel.chat(message);
return ollamachat;
}
}
结果如下:
4 流式输出
之前的依赖不变,但是因为langchain4j不是spring家族,所以我们在wen应用中需要引入webflux。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
通过Flux进行流式响应
@RequestMapping(value = "/streamchat",produces = "text/stream;charset=UTF-8")
public Flux<String> streamchatfuc(@RequestParam(defaultValue="你是谁") String message){
Flux<String> flux = Flux.create(fluxSink -> {
streamingChatModel.chat(message, new StreamingChatResponseHandler() {
@Override
public void onPartialResponse(String partialResponse) {
fluxSink.next(partialResponse);
}
@Override
public void onCompleteResponse(ChatResponse completeResponse) {
fluxSink.complete();
}
@Override
public void onError(Throwable error) {
fluxSink.error(error);
}
});
});
return flux;
}
加入配置文件:
langchain4j.community.dashscope.streaming-chat-model.api-key = sk-4d1748fba8994a2e94cb0fbaf3d34f23
langchain4j.community.dashscope.chat-model.model-name = deepseek-r1
启动后访问链接:http://localhost:8080/ai/streamchat,会发现答复是按照流式输出的。
5 记忆对话
5.1 ChatMemory
大模型并不会把我们每次的对话存在服务端,所以他记不住我们说的话,如下代码:
@Test
public void test_bad(){
ChatLanguageModel model = OpenAiChatModel
.builder()
.apiKey("demo")
.modelName("gpt-4o-mini")
.build();
System.out.println(model.chat("你好,我是徐庶老师"));
System.out.println("----");
System.out.println(model.chat("我叫什么"));
}
运行结果如下:
所以每次对话都需要将之前的对话记录,都发给大模型,这样才能知道我们之前说了什么:
@Test
public void test03(){
ChatLanguageModel model = OpenAiChatModel
.builder()
.apiKey("demo")
.modelName("gpt-4o-mini")
.build();
UserMessage userMessage1 = UserMessage.userMessage("你好,我是徐庶");
ChatResponse response1 = model.chat(userMessage1);
AiMessage aiMessage1 = response1.aiMessage();//大模型的第一次响应
System.out.println(aiMessage1.text());
System.out.println("----");
// 下面一行代码是重点
ChatResponse response2 = model.chat(userMessage1,aiMessage1, UserMessage.userMessage("我叫什么?"));
AiMessage aiMessage2 = response2.aiMessage();
// 大模型的第二次响应
System.out.println(aiMessage2.text());
System.out.println(model.chat("你好,我是徐庶老师"));
System.out.println("----");
System.out.println(model.chat("我叫什么"));
}
返回结果如下:
但是如果要我们每次把之前的记录自己去维护,未免太麻烦,所以提供了ChatMemory但是他这个ChatMemory没有SpringAi好用、易用、十分麻烦!所以说谁在跟我说Langchain4i比SpringAi好我跟谁急!
package org.example.config;
import dev.langchain4j.memory.ChatMemory;
import dev.langchain4j.memory.chat.MessageWindowChatMemory;
import dev.langchain4j.model.chat.ChatLanguageModel;
import dev.langchain4j.model.chat.StreamingChatLanguageModel;
import dev.langchain4j.service.AiServices;
import dev.langchain4j.service.TokenStream;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class Aiconfig {
public interface Assistant{
String chat(String message);
// 流式响应
TokenStream stream(String message);
}
@Bean
public Assistant assistant(ChatLanguageModel qwenchatModel, StreamingChatLanguageModel qwenstreamingchatModel) {
//设置最大记录对话数
ChatMemory chatMemory = MessageWindowChatMemory.withMaxMessages(10);
Assistant assistant = AiServices
.builder(Assistant.class)
.chatLanguageModel(qwenchatModel)
.streamingChatLanguageModel(qwenstreamingchatModel)
.chatMemory(chatMemory)
.build();
return assistant;
}
}
原理:
- 通过AiService创建的代理对象(Aiservices.builder(XushuChatModel.class))调用chat方法(XushuChatModel.chat)
- 代理对象会去ChatMemory中获取之前的对话记录(获取记忆)
- 将获取到的对话记录合并到当前对话中(此时大模型根据之前的聊天记录肯定就拥有了“记忆”)
- 将当前的对话内容存入ChatMemory(保存记忆)
代码如下:
package org.example.controller;
import dev.langchain4j.service.TokenStream;
import jakarta.servlet.http.HttpServletResponse;
import org.example.config.Aiconfig;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;
import java.time.LocalDate;
@RestController
@RequestMapping("/ai_other")
public class OtherAiController {
@Autowired
Aiconfig.Assistant assistant;
//告诉模型我叫诸葛懿
@RequestMapping(value = "/memory_chat")
public String memorychat(@RequestParam(defaultValue = "我叫诸葛懿") String message) {
return assistant.chat(message);
}
//流式响应
@RequestMapping(value = "/memory_stream_chat",produces ="text/stream;charset=UTF-8")
public Flux<String> memoryStreamChat(@RequestParam(defaultValue="我是谁") String message, HttpServletResponse response) {
TokenStream stream = assistant.stream(message);
return Flux.create(sink -> {
stream.onPartialResponse(s -> sink.next(s))
.onCompleteResponse(c -> sink.complete())
.onError(sink::error)
.start();
});
}
}
先访问http://localhost:8080/ai_other/memory_chat告诉模型你的名字,后访问http://localhost:8080/ai_other/memory_stream_chat看结果,结果如下:
5.2 记忆分离
现在我们再来想另一种情况:如果不同的用户或者不同的对话肯定不能用同一个记忆,要不然对话肯定会混淆此时就需要进行区分:
可以通过memoryld进行区分
5.3 持久对话