Java大模型开发入门 (5/15):开发利器 – 初识Java最流行的LLM框架LangChain4j

前言

在上一篇文章中,我们成功地将大模型能力封装成了一个标准的Spring Boot服务。我们有了Controller、Service,通过依赖注入管理着OpenAIClient。这是一个巨大的进步,我们的AI应用已经具备了企业级开发的雏形。

但是,当我们想实现更复杂的功能时,挑战也随之而来:

  • 多轮对话:如何让AI记住我们之前的谈话内容?我们需要手动管理一个List<ChatMessage>,并在每次请求时都把它传来传去,这非常繁琐且容易出错。
  • 结构化输出:如何确保AI返回的是一个我们可以直接转换为Java对象的JSON,而不是一段随心所欲的文本?
  • 连接外部知识:如何让AI回答关于我们自己公司产品文档的问题?
  • 调用工具:如何让AI在回答问题时,能去调用一个外部API(比如查询实时天气)?

只靠我们目前使用的官方SDK,要实现这些功能,需要编写大量复杂的“胶水代码”。幸运的是,社区已经为我们准备好了一个功能极其强大的“瑞士军刀”——LangChain4j

今天,我们将正式引入这个Java领域最流行的LLM应用开发框架,看看它是如何将我们从繁杂的底层逻辑中解放出来的。

第一步:什么是LangChain4j?它解决了什么问题?

我们可以用一个简单的类比来理解:

如果说官方SDK(如openai-java-client)是为我们提供了一台性能强劲的汽车引擎,那么LangChain4j就是为我们提供了整车的底盘、变速箱、方向盘和智能驾驶系统

它不是要替代SDK,而是构建于SDK之上,让我们能更轻松地“驾驶”AI,构建完整的、复杂的应用。

LangChain4j的核心思想是 “链(Chain)” ,也就是将与大模型交互的多个步骤串联起来,形成一个自动化的工作流。它将复杂的AI应用抽象为几个核心组件:

  • 语言模型 (Language Models):对不同AI服务商(如OpenAI, DeepSeek, Google Gemini)的统一接口。
  • 提示模板 (Prompt Templates):创建可复用、可动态填充的提示词。
  • 记忆 (Memory):为对话提供短期或长期的记忆能力。
  • 输出解析器 (Output Parsers):将模型的文本输出强制转换为结构化的Java对象。
  • 检索器 (Retrievers)文档 (Documents):用于实现RAG(检索增强生成),让AI能连接外部知识库。

今天,我们先从它最神奇、最简单的功能之一AiServices入手,直观感受它的威力。

第二步:在Spring Boot中集成LangChain4j

LangChain4j与Spring Boot的集成非常成熟,我们只需要引入它的spring-boot-starter

  1. 修改pom.xml
    pom.xml中,添加LangChain4j的Spring Boot Starter依赖。注意:你可以移除上一章添加的openai-java-client依赖,因为langchain4j-open-ai-spring-boot-starter已经包含了它。

    <dependency>
        <groupId>dev.langchain4j</groupId>
        <artifactId>langchain4j-open-ai-spring-boot-starter</artifactId>
        <version>0.32.0</version> <!-- 使用最新的稳定版本 -->
    </dependency>
    
  2. 修改 application.properties
    LangChain4j的配置项遵循着清晰的命名空间。我们将之前的配置修改为LangChain4j的格式:

    # 服务器端口号
    server.port=8080
    
    # LangChain4j Configuration for DeepSeek
    langchain4j.open-ai.chat-model.api-key=${DEEPSEEK_API_KEY:}
    langchain4j.open-ai.chat-model.base-url=https://api.deepseek.com/v1/
    langchain4j.open-ai.chat-model.model-name=deepseek-chat
    langchain4j.open-ai.chat-model.temperature=0.7
    langchain4j.open-ai.chat-model.max-tokens=1024
    

    仅仅这样配置,LangChain4j的Starter就会自动为我们创建一个配置好的ChatLanguageModel Bean。我们已经不需要自己写AiClientConfig了!

第三步:代码重构 – 见证AiServices的魔力

现在,我们将重构上一章的ChatService,让你看看代码可以被简化到什么程度。LangChain4j提供了一个名为AiServices的工厂,它可以将一个Java接口,自动转换成一个可以与AI交互的实现类

  1. 创建一个AI助手接口
    service包下,创建一个新的接口Assistant.java

    package com.example.aidemoapp.service;
    
    public interface Assistant {
        String chat(String userMessage);
    }
    

    这是一个普通的Java接口,只有一个chat方法。

  2. 修改配置类
    删除上一章的AiClientConfig.java。新建一个AiServiceConfig.java

    package com.example.aidemoapp.config;
    
    import com.example.aidemoapp.service.Assistant;
    import dev.langchain4j.memory.chat.ChatMemoryProvider;
    import dev.langchain4j.memory.chat.MessageWindowChatMemory;
    import dev.langchain4j.model.chat.ChatLanguageModel;
    import dev.langchain4j.service.AiServices;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    @Configuration
    public class AiServiceConfig {
        
        // 将LangChain4j自动配置好的ChatLanguageModel注入进来
        @Bean
        public Assistant assistant(ChatLanguageModel chatLanguageModel) {
            // AiServices会为Assistant接口创建一个代理实现
            return AiServices.builder(Assistant.class)
                    .chatLanguageModel(chatLanguage-model)
                    .build();
        }
    }
    
  3. 重构ChatService
    现在我们的ChatService变得异常简单:

    package com.example.aidemoapp.service;
    
    import lombok.RequiredArgsConstructor;
    import org.springframework.stereotype.Service;
    
    @Service
    @RequiredArgsConstructor
    public class ChatService {
    
        // 直接注入我们定义的Assistant接口
        private final Assistant assistant;
    
        public String getChatResponse(String userPrompt) {
            // 直接调用接口方法,就像调用一个普通的Java方法一样
            return assistant.chat(userPrompt);
        }
    }
    

    ChatController完全不需要任何改动!

第四步:对比与思考

我们来对比一下前后的变化:

  • 之前 (纯SDK):我们需要在ChatService中手动构建ChatCompletionCreateParams对象,然后调用client.chat().completions().create(),再从复杂的响应对象中解析出结果。
  • 现在 (用LangChain4j):我们只定义了一个接口Assistant,然后就像调用一个本地方法一样调用assistant.chat()。所有的API请求构建和响应解析都被LangChain4j在幕后优雅地处理了。

这到底发生了什么?

AiServices.create()是一个神奇的工厂。当你调用assistant.chat("你好")时,LangChain4j的代理实现会自动:

  1. 创建一个ChatMessage,角色是user,内容是"你好"
  2. 构建一个完整的API请求。
  3. 调用我们配置好的ChatLanguageModel(也就是DeepSeek模型)。
  4. 等待响应,并自动解析出内容。
  5. 将内容作为String返回。

这就是框架的力量:它让你能够用业务逻辑的语言(assistant.chat(...))来编程,而不是用技术实现的语言。

总结

今天我们只是揭开了LangChain4j神秘面纱的一角,但其强大的生产力已经可见一斑。通过AiServices,我们以一种前所未有的优雅方式重构了我们的AI服务。

我们不再需要自己去管理和创建OpenAIClient,也不再需要手动拼装请求参数。LangChain4j的Spring Boot Starter和AiServices工厂为我们处理了这一切。

但这仅仅是开始。LangChain4j真正的威力在于它那些可组合的模块。如何让我们的Assistant拥有记忆?如何让它返回一个Java对象而不是String


下一篇预告:
Java大模型开发入门 (6/15):对话的灵魂 – 深入理解LangChain4j中的模型、提示和解析器》—— 我们将深入LangChain4j的核心,学习如何通过提示模板(Prompt Templates)和输出解析器(Output Parsers)来驯服AI,让它按照我们的意愿进行思考和输出!

© 版权声明

相关文章

暂无评论

暂无评论...