LangChain 整合 SpringBoot
下述代碼均使用 阿里云百煉平臺 提供的模型。
創建項目,引入依賴
- 通過
IDEA
創建SpringBoot
項目,并引入Spring Web
依賴,SpringBoot
推薦使用 3.x 版本。
- 引入 LangChain4j 和 WebFlux 依賴
<!--阿里云 DashScope API(通義大模型)的 Spring Boot Starter 依賴-->
<dependency><groupId>dev.langchain4j</groupId><artifactId>langchain4j-community-dashscope-spring-boot-starter</artifactId><version>1.0.0-beta2</version>
</dependency>
<!--LangChain4j 的核心庫-->
<dependency><groupId>dev.langchain4j</groupId><artifactId>langchain4j</artifactId><version>1.0.0-beta2</version>
</dependency>
<!--Spring WebFlux 依賴-->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
案例一 — 普通對話
該示例為整體返回,即等待模型回復完成后,一起進行返回。
- 配置 yaml
langchain4j:community:dashscope:chat-model:api-key: 個人 api-keymodel-name: qwen-max
- 創建
ChatController
,并編寫相關接口
@RestController
@RequestMapping("/chat")
public class ChatController {@Autowiredprivate ChatLanguageModel chatLanguageModel;@RequestMapping("/test1")public String test1(@RequestParam(defaultValue = "你好") String message) {String response = chatLanguageModel.chat(message);return response;}
}
- 測試接口響應
瀏覽器中訪問:http://localhost:8080/chat/test1?message=你好,你是誰
,如果有響應類似下述內容,則說明成功。
案例二 — 流式對話
上述示例用戶體驗并不好,本示例采用流式返回
- 配置 yaml
langchain4j:community:dashscope:streaming-chat-model:model-name: qwen-maxapi-key: 個人 api-key
- 編寫相關接口
@Autowired
private StreamingChatLanguageModel streamingChatLanguageModel;// 指定 produces,否則會出現亂碼情況
@RequestMapping(value = "/test2", produces = "text/stream;charset=UTF-8")
public Flux<String> test2(@RequestParam(defaultValue = "你好") String message) {Flux<String> flux = Flux.create(sink -> {streamingChatLanguageModel.chat(message, new StreamingChatResponseHandler() {@Overridepublic void onPartialResponse(String partialResponse) {sink.next(partialResponse);}@Overridepublic void onCompleteResponse(ChatResponse completeResponse) {sink.complete();}@Overridepublic void onError(Throwable error) {sink.error(error);}});});return flux;
}
- 測試接口響應
瀏覽器中訪問:http://localhost:8080/chat/test2?message=你好,你是誰
,如果有響應類似下述內容,則說明成功。
本案例與案例一的區別為輸出方式不同,一種是整體輸出,一種是流式輸出。
案例三 — 圖片生成
百煉平臺提供500張圖片的免費額度用于學習。
本案例采用同步的方式獲取圖片,也可以按照官方文檔采用異步方式進行圖片獲取。
- 配置yaml
gen-img:api-key: 個人 api-keymodel-name: wanx2.1-t2i-turbo
- 配置
WanxImageModel
,編寫相關接口
@Configuration
public class AIConfig {@Value("${gen-img.api-key}")private String genImgApiKey;@Value("${gen-img.model-name}")private String genImgModelName;@Bean/*** 圖片繪制模型*/public WanxImageModel wanxImageModel() {return WanxImageModel.builder().apiKey(genImgApiKey).modelName(genImgModelName).build();}
}
@Autowired
private WanxImageModel wanxImageModel;@RequestMapping("/test3")
public String test3(@RequestParam(defaultValue = "午后的公園") String message) {Response<Image> generate = wanxImageModel.generate(message);// 具體返回結構可查看官方定義,這里只獲取圖片的 urlreturn generate.content().url().toString();
}
- 測試接口響應
在瀏覽器中輸入:http://localhost:8080/chat/test3?message=雨后的公園
下圖中返回數據為生成圖片的 url,使用瀏覽器訪問該 url,可以在瀏覽器中下載生成后的圖片。
生成的圖片如下:
案例四 — 記憶對話
- 配置
AiService
相關對象
// 定義聊天助手接口
public interface MyAssistant {String chat(String message);TokenStream stream(String message);
}@Bean
public MyAssistant assistant(ChatLanguageModel qwenChatModel, StreamingChatLanguageModel qwenStreamingChatModel) {MyAssistant assistant = AiServices.builder(MyAssistant.class).chatLanguageModel(qwenChatModel).streamingChatLanguageModel(qwenStreamingChatModel).chatMemory(MessageWindowChatMemory.withMaxMessages(20))// 自定義對話存儲方式
// .chatMemoryProvider(memoryId -> MessageWindowChatMemory
// .builder()
// .chatMemoryStore(new ChatMemoryStore() {
// @Override
// public List<ChatMessage> getMessages(Object memoryId) {
// return null;
// }
//
// @Override
// public void updateMessages(Object memoryId, List<ChatMessage> messages) {
//
// }
//
// @Override
// public void deleteMessages(Object memoryId) {
//
// }
// }
// ).build()).build();return assistant;
}
- 編寫接口,采用流式返回
@Autowired
private AIConfig.MyAssistant assistant;@RequestMapping(value = "/test4", produces = "text/stream;charset=UTF-8")
public Flux<String> test4(@RequestParam(defaultValue = "你好") String message) {TokenStream stream = assistant.stream(message);return Flux.create(sink -> {stream.onPartialResponse(sink::next).onCompleteResponse(c -> sink.complete()).onError(sink::error).start();});
}
- 測試接口響應
-
直接進行詢問
-
通過接口給模型寫入記憶
-
根據寫入記憶,進行對話
-
上述聊天信息默認存儲在內存中,程序重啟后會丟失記憶,可以重寫被注釋掉的內容,將信息存儲到 mysql、redis等存儲容器中。
案例五 — 記憶對話,數據隔離
上述案例中,所有的問答都是混合到一起的,即 A 對模型輸入的信息,B 也可以讀取到,本案例將通過 memoryId
對記憶數據進行隔離。
- 配置
AiService
相關對象
public interface MyAssistantIsolate {String chat(@MemoryId String memoryId, @UserMessage String message);TokenStream stream(@MemoryId String memoryId, @UserMessage String message);
}@Bean
public MyAssistantIsolate myAssistantMemory(ChatLanguageModel qwenChatModel, StreamingChatLanguageModel qwenStreamingChatModel) {ChatMemoryProvider chatMemoryProvider = memoryId -> MessageWindowChatMemory.builder().id(memoryId).maxMessages(20)// 自定義對話存儲方式
// .chatMemoryStore(new ChatMemoryStore() {
// @Override
// public List<ChatMessage> getMessages(Object memoryId) {
// return null;
// }
//
// @Override
// public void updateMessages(Object memoryId, List<ChatMessage> messages) {
//
// }
//
// @Override
// public void deleteMessages(Object memoryId) {
//
// }
// }).build();MyAssistantIsolate assistant = AiServices.builder(MyAssistantIsolate.class).chatLanguageModel(qwenChatModel).streamingChatLanguageModel(qwenStreamingChatModel).chatMemoryProvider(chatMemoryProvider).build();return assistant;
}
- 編寫接口
@Autowired
private AIConfig.MyAssistantIsolate myAssistantIsolate;@RequestMapping(value = "/test5", produces = "text/stream;charset=UTF-8")
// 通過不同的 memoryId 對記憶進行分割,memoryId 可以使用 userId 或 uuid
public Flux<String> test5(String memoryId, String message) {TokenStream stream = myAssistantIsolate.stream(memoryId, message);return Flux.create(sink -> {stream.onPartialResponse(sink::next).onCompleteResponse(c -> sink.complete()).onError(sink::error).start();});
}
- 測試接口響應
- 給 memoryId = 1,設置記憶信息
- 通過 memoryId = 1,查詢記憶信息
- 通過 memoryId = 2,查詢記憶信息
- 給 memoryId = 1,設置記憶信息
上述內容為 LangChain4j
整合 SpringBoot
的基本示例。