LangChain4J 跟 SpringAi 差不多, 都提供了提示词工程、对话记忆、结构化输出、RAG、MCP 等功能
接入LangChain4J
依赖
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j</artifactId>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-open-ai-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-reactor</artifactId>
</dependency>
低层次接口
提供了 Basics(大模型、提示词模板、对话记忆等) 和 RAG(向量模型、向量数据库、文本载入分割工具) 两种低层次接口
@GetMapping("/chat01")
public String chat01() {
return chatModel.chat("你好,你是谁?");
}
@GetMapping("/stream01")
public Flux<String> stream01(HttpServletResponse response) {
response.setCharacterEncoding("UTF-8");
return Flux.create(sink -> {
streamingChatModel.chat("你好,我是谁?", new StreamingChatResponseHandler() {
@Override
public void onPartialResponse(String partialResponse) {
sink.next(partialResponse);
}
@Override
public void onCompleteResponse(ChatResponse completeResponse) {
sink.complete();
}
@Override
public void onError(Throwable error) {
sink.error(error);
}
});
});
}
/**
* 对话记忆,基于手动保存
*/
@GetMapping("/memory01")
public String memory01(@RequestParam("message") String message, HttpServletResponse response) {
response.setCharacterEncoding("UTF-8");
List<ChatMessage> messages = List.of(
new SystemMessage("""
# 角色
你是一个美食推荐博主
# 推荐前提问
1.询问喜好
2.询问忌口
"""),
new UserMessage("给我推荐今晚该吃什么"),
new AiMessage("请问你有什么喜欢吃的菜系和有什么不喜欢吃或忌口的吗?"),
new UserMessage("我不喜欢吃香菜、芹菜"),
new AiMessage("了解,我推荐你今晚吃一道家常菜,西红柿炒鸡蛋"),
new UserMessage(message)
);
return chatModel.chat(messages).aiMessage().text();
}
/**
* 对话记忆,基于MessageWindowChatMemory
*/
@GetMapping("/memory02")
public String memory02(@RequestParam("message") String message, HttpServletResponse response) {
response.setCharacterEncoding("UTF-8");
MessageWindowChatMemory memory = MessageWindowChatMemory.withMaxMessages(10);
memory.add(
new SystemMessage("""
# 角色
你是一个美食推荐博主
# 推荐前提问
1.询问喜好
2.询问忌口
"""),
new UserMessage("给我推荐今晚该吃什么"),
new AiMessage("请问你有什么喜欢吃的菜系和有什么不喜欢吃或忌口的吗?"),
new UserMessage("我不喜欢吃香菜、芹菜"),
new AiMessage("了解,我推荐你今晚吃一道家常菜,西红柿炒鸡蛋"),
new UserMessage(message)
);
return chatModel.chat(memory.messages()).aiMessage().text();
}
/**
* 结构化输出
*/
@GetMapping("/structure")
public String structure(@RequestParam("language") String language, HttpServletResponse response) {
response.setCharacterEncoding("UTF-8");
// 构造Json结构
ResponseFormat format = ResponseFormat.builder().type(ResponseFormatType.JSON).jsonSchema(
JsonSchema.builder().name("Book").rootElement(
JsonObjectSchema.builder()
.addStringProperty("name", "书名")
.addStringProperty("author", "作者")
.addStringProperty("publisher", "出版社")
.addNumberProperty("price", "价格,以分为单位,人民币")
.build()
).build()
).build();
ChatRequest request = ChatRequest.builder().responseFormat(format).messages(
UserMessage.from("给我推荐几本%s路线学习的书,输出格式为Json".formatted(language))
).build();
return chatModel.chat(request).aiMessage().text();
}
/**
* 工具使用
*/
@GetMapping("tools")
public String tools(@RequestParam("city") String city, HttpServletResponse response) {
response.setCharacterEncoding("UTF-8");
// 构造工具清单
List<ToolSpecification> tools = ToolSpecifications.toolSpecificationsFrom(TemperatureTools.class);
// 让ai生成调用工具的指令
List<ChatMessage> messages = new ArrayList<>();
UserMessage message = UserMessage.from("查询中国%s今天的天气".formatted(city));
messages.add(message);
ChatRequest request = ChatRequest.builder().messages(message).toolSpecifications(tools).toolChoice(ToolChoice.AUTO).build();
AiMessage aiMessage = chatModel.chat(request).aiMessage();
messages.add(aiMessage);
// 调用工具并获取工具返回信息
List<ToolExecutionRequest> toolExecutionRequests = aiMessage.toolExecutionRequests();
toolExecutionRequests.forEach(toolExecutionRequest -> {
DefaultToolExecutor executor = new DefaultToolExecutor(new TemperatureTools(), toolExecutionRequest);
String result = executor.execute(toolExecutionRequest, UUID.randomUUID().toString());
ToolExecutionResultMessage toolMessage = ToolExecutionResultMessage.from(toolExecutionRequest, result);
messages.add(toolMessage);
});
// 把用户信息和工具返回结果一起交给ai生成最终回复
ChatRequest finalRequest = ChatRequest.builder().messages(messages).toolSpecifications(tools).build();
return chatModel.chat(finalRequest).aiMessage().text();
}
高层次接口
AI Services(和 Spring Data JPA 类似, 只需显式定义接口, 可以自定义加入 Menory、Tools、RAG 等)
Controller
@GetMapping("/chat01")
public String chat01() {
return aiService.chat("你好,你是谁?");
}
@GetMapping("/stream01")
public Flux<String> stream01(HttpServletResponse response) {
response.setCharacterEncoding("UTF-8");
return aiService.stream("你好,我是谁?");
}
@GetMapping("/prompt")
public Flux<String> prompt(HttpServletResponse response) {
response.setCharacterEncoding("UTF-8");
return aiService.prompt("推荐一道美食");
}
Service
@AiService
public interface LangChainAiService {
String chat(String msg);
Flux<String> stream(String msg);
@SystemMessage("你是我的美食推荐bot,推荐前询问我的喜好、忌口")
Flux<String> prompt(String msg);
@UserMessage("请推荐一本{{language}}入门书")
Book structure(@V("language") String language);
}
@AiService
public interface MemoryAiService {
Flux<String> stream(@MemoryId String memoryId, @UserMessage String msg);
}
提示词模板、结构化输出
@GetMapping("/structure")
public Book structure(HttpServletResponse response) {
response.setCharacterEncoding("UTF-8");
return aiService.structure("Java");
}
对话记忆
@GetMapping("/memory")
public Flux<String> memory(@RequestParam("memory-id") String memoryId, @RequestParam("msg") String msg, HttpServletResponse response) {
response.setCharacterEncoding("UTF-8");
MemoryAiService service = AiServices.builder(MemoryAiService.class)
.streamingChatModel(stream).chatMemoryProvider(id ->
MessageWindowChatMemory.withMaxMessages(10)
).build();
return service.stream(memoryId, msg);
}
@GetMapping("/memory")
public Flux<String> memory(@RequestParam("memory-id") String memoryId, @RequestParam("msg") String msg, HttpServletResponse response) {
response.setCharacterEncoding("UTF-8");
MemoryAiService service = AiServices.builder(MemoryAiService.class)
.streamingChatModel(stream).chatMemoryProvider(id ->
MessageWindowChatMemor
.builder()
.id(memoryId)
.chatMemoryStore(custom)
.build()
).build();
return service.stream(memoryId, msg);
}
工具调用
/**
* 工具调用
*/
@GetMapping("/tools")
public String tools(@RequestParam("city") String city, HttpServletResponse response){
response.setCharacterEncoding("UTF-8");
LangChainAiService service = AiServices
.builder(LangChainAiService.class)
.tools(new TemperatureTools())
.chatModel(model)
.build();
return service.chat("中国%s今天天气怎么样?".formatted(city));
}