AI应用(6)- 实战演练之langchain4j的使用

langchain4j是干嘛的?

它就是一个面向java生态的LLM应用开发框架,,他主要是为了让你能够快速接入模型,是一个开源社区维护的,他其中包括了提示词、上下文、多伦记忆、工具调用、RAG知识库、检索、结构化输出、流式输出等功能,让你写AI应用想写java业务代码一样,说白了就是封装了各种调用AI大模型的功能,让你方便开发,现在最新版本是1.10.0了,避免你用http到处去拼接请求。

截图是他们的官网,支持的大模型也是相当的多,但很多模型都兼容OPENAI的标准,为啥要兼容他?因为他是最早出来并且指定标准的,各大厂商为了方便开发中调用,基本都兼容了openAI的调用方式,比如国内的deepseek和阿里千问都支持这种调用。

langchain和langchain4j有什么关系

langchain是最早出来的东西,他主要是支持python语言和JavaScript语言,langchain4j是后面出来的,专门为java开发者设计的,然后langchain4j不是又出了和springboot集成吗,以及又出了springAI,说白了就是为了抢占市场,springboot正在做一系列努力,不然到时候大家都去用python了,没有人用java写代码了、

LlamaIndex主要是python为主,他和langchain又有区别,langchain属于比较全能,封装的接口功能很多,但LlamaIndex主要是偏向于RAG知识库,具体可以看下这篇文章,讲的很详细

https://blog.csdn.net/weixin_41046245/article/details/150060929

还有springAI上面也说了,就是为了springboot依赖者,快速去接入开发AI应用的

LangChain4j 代码示例

复制代码
//需要导入的依赖
<dependencies>
        <dependency>
            <groupId>dev.langchain4j</groupId>
            <artifactId>langchain4j</artifactId>
            <version>1.10.0</version>
        </dependency>

        <dependency>
            <groupId>dev.langchain4j</groupId>
            <artifactId>langchain4j-open-ai</artifactId>
            <version>1.10.0</version>
        </dependency>

        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter</artifactId>
            <version>5.11.4</version>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>dashscope-sdk-java</artifactId>
            <version>2.21.0</version>
        </dependency>
 
         <!-- ollama工具依赖 -->
        <dependency>
            <groupId>dev.langchain4j</groupId>
            <artifactId>langchain4j-ollama</artifactId>
            <version>1.10.0</version>
        </dependency>
        </dependencies>

LangChain4j 最简单的openAI模式调用

复制代码
//OpenAI模型调用
@Test
    void test01() {
        OpenAiChatModel model = OpenAiChatModel.builder()
                .apiKey("demo")
                .modelName("gpt-4o-mini")
                .build();

        String answer = model.chat("你好,你是谁?");
        System.out.println(answer);
    }

//deepseek模型调用
@Test
void test02(){
    OpenAiChatModel model = OpenAiChatModel.builder().baseUrl("https://api.deepseek.com")
    .apiKey(System.getenv("DEEPSEEK_API_KEY"))
    .modelName("deepseek-reasoner").build();
    String answer = model.chat("你好,你是谁?");
    System.out.println(answer);
}

//阿里千问模型调用
@Test
    void test03(){
        OpenAiChatModel model = OpenAiChatModel.builder()
        .baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1")
        .apiKey(System.getenv("ALI_API_KEY"))
        .modelName("qwen-plus").build();
        String answer = model.chat("你好,你是谁?");
        System.out.println(answer);
    }

//阿里千问模型调用,上面是阿里兼容openai的调用方法,这个是阿里原生的,在阿里云百炼平台有示例,不是 OpenAI 兼容模式
// - 优点:完全按阿里原生能力走(有些高级能力/参数在这里更完整)。
// - 缺点:代码与供应商绑定更强,不如 OpenAI-compatible 通用。
@Test
    void test04(){
         try {
            GenerationResult result = callWithMessage();
            System.out.println(result.getOutput().getChoices().get(0).getMessage().getContent());
            // 如需查看完整响应,请取消下列注释
            // System.out.println(JsonUtils.toJson(result));
        } catch (ApiException | NoApiKeyException | InputRequiredException e) {
            System.err.println("错误信息:"+e.getMessage());
            System.out.println("请参考文档:https://help.aliyun.com/zh/model-studio/developer-reference/error-code");
        }
    }

    public static GenerationResult callWithMessage() throws ApiException, NoApiKeyException, InputRequiredException {
        // 以下为北京地域url,若使用新加坡地域的模型,需将url替换为:https://dashscope-intl.aliyuncs.com/api/v1
        Generation gen = new Generation(Protocol.HTTP.getValue(), "https://dashscope.aliyuncs.com/api/v1");
        Message systemMsg = Message.builder()
                .role(Role.SYSTEM.getValue())
                .content("You are a helpful assistant.")
                .build();
        // userMsg 就是用户问题(User message)
        Message userMsg = Message.builder()
                .role(Role.USER.getValue())
                .content("65*889等于几")
                .build();
        GenerationParam param = GenerationParam.builder()
                // 若没有配置环境变量,请用阿里云百炼API Key将下行替换为:.apiKey("sk-xxx")
                // 各地域的API Key不同。获取API Key:https://help.aliyun.com/zh/model-studio/get-api-key
                // 建议:学习阶段可以先写死;实战建议改成 System.getenv("DASHSCOPE_API_KEY")。
                .apiKey(System.getenv("ALI_API_KEY"))
                .model("qwen-plus")
                .messages(Arrays.asList(systemMsg, userMsg))
                .resultFormat(GenerationParam.ResultFormat.MESSAGE)
                .build();
        return gen.call(param);
    }

本地大模型调用

上面都是接入的几个别人家的大模型,但很多实际应用场景里面是需要自己部署开源大模型的,市面上的开源大模型很多,ollama是一个部署大模型的工具,官网是https://ollama.com/download。可以下载这个功能,然后直接部署大模型到本地,

ollama里面已经写好了各种命令,可以帮助你直接安装各种模型,不过一般自己电脑配置不行,就只能安装deepseek-r1 1.5b...不过这个模型是真的拉。部署完以后,就可以直接访问自己部署的模型了,不在需要apikey了

复制代码
//Ollama(本地大模型服务)
   @Test
    void test05(){
        OllamaChatModel model = OllamaChatModel.builder()
        .baseUrl("http://localhost:11434")
        //.apiKey("sk-1639b23a1d3148cb8912dcddf78f0bdc")
        .modelName("deepseek-r1:1.5b").build();

        String answer = model.chat("65*889等于几");//算这个就花了十几分钟,1.5b的模型就只能部署了玩玩

        System.out.println(answer);
    }

文生图模型

上面几个都是文生文的模型,也可以文生图等等,可以去各大官网去看看,下面这个代码是阿里的文生图的模型调用

复制代码
    //阿里千问官方示例
    @Test
    void test06(){
        String prompt = "一个美女图片";
        Map<String, Object> parameters = new HashMap<>();
        parameters.put("prompt_extend", true);
        parameters.put("watermark", false);
        parameters.put("negative_prompt", " ");
        ImageSynthesisParam param =
                ImageSynthesisParam.builder()
                         .apiKey(System.getenv("ALI_API_KEY"))
                        // 当前仅qwen-image-plus、qwen-image模型支持异步接口
                        .model("qwen-image-plus")
                        .prompt(prompt)
                        .n(1)
                        .size("1664*928")
                        .parameters(parameters)
                        .build();

        ImageSynthesis imageSynthesis = new ImageSynthesis();
        ImageSynthesisResult result = null;
        try {
            System.out.println("---同步调用,请等待任务执行----");
            result = imageSynthesis.call(param);
        } catch (ApiException | NoApiKeyException e){
            throw new RuntimeException(e.getMessage());
        }
        System.out.println(JsonUtils.toJson(result));
    }

AiServices

在 LangChain4j 里,AiServices 可以理解成:把"调用大模型"封装成一个 Java 接口的实现(动态代理)。

主要是四个地方:

  • Prompt/消息自动装配:SystemMessage 设定助手规则,UserMessage 标记用户输入
  • 多轮记忆:MemoryId + chatMemoryProvider(...) 实现"会话隔离 + 记忆注入"
  • 结构化输出:返回 POJO(比如你的 LessonPlan),框架帮你做映射(失败会抛异常)
  • 流式输出:让模型的回答是一段段的,而不是直接返回所有结果
消息自动装配
复制代码
 interface QwenAssistant {
        // @SystemMessage:给模型的"系统提示词"(System Prompt),用于设定角色/风格/规则。
        // 这里固定为"严谨中文助手",让回答更稳定。
        @SystemMessage("你是一个严谨的中文助手。")
        // @UserMessage:标记这是用户输入。
        // 不加也能用,但加上后在多参数、多组件场景更清晰。
        String chat(@UserMessage String message);
    }
@Test
    void test07(){
        ChatModel model = OpenAiChatModel.builder()
                .baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1")
                .apiKey(System.getenv("ALI_API_KEY"))
                .modelName("qwen-plus")
                .build();

        // AiServices.builder(QwenAssistant.class) 会创建一个实现了 QwenAssistant 的代理对象。
        // 代理对象内部会把你的方法调用转换成一次(或多次)LLM 调用。
        QwenAssistant assistant = AiServices.builder(QwenAssistant.class)
                .chatModel(model)
                .build();

        System.out.println(assistant.chat("请你说一下以后AI的发展方向"));
    }
带记忆的对话

上面的示例都是不带记忆的,他不知道你是谁,下次对话就记不住了

复制代码
    // 带记忆的 Assistant:
    // - @MemoryId:用来区分"哪个用户/哪个会话"的对话历史。
    // - MessageWindowChatMemory:一个最简单的内存实现,只保留最近 N 条消息。
    //   (生产中你可以换成 Redis/DB 持久化,或者自己实现 MemoryStore)
    interface QwenAssistantWithMemory {
        @SystemMessage("你是一个严谨的中文助手。")
        String chat(@MemoryId String userId, @UserMessage String message);
    }

    // 示例 08:ChatMemory + MemoryId(多用户对话隔离)
    // 知识点:ChatMemory(对话记忆)、MessageWindowChatMemory(窗口记忆)、@MemoryId(多会话隔离)
    // 目标:让模型"记住上下文",并且不同 userId 之间互不串台。
    // 运行预期:
    // - u1 先说"我叫李雷",再问"我叫什么?"模型应回答"李雷"。
    // - u2 没有说过名字,模型不应该知道。
    // 你可以改动点:
    // - withMaxMessages(20) 改大/改小,观察记忆窗口对效果的影响。
    @Test
    void test08(){
        ChatModel model = OpenAiChatModel.builder()
                .baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1")
                .apiKey(System.getenv("ALI_API_KEY"))
                .modelName("qwen-plus")
                .build();

        // chatMemoryProvider:根据 MemoryId 动态创建/获取一个记忆对象。
        // 这里演示最简单的:每个 userId 都用一个"窗口记忆"。
        QwenAssistantWithMemory assistant = AiServices.builder(QwenAssistantWithMemory.class)
                .chatModel(model)
                .chatMemoryProvider(userId -> MessageWindowChatMemory.withMaxMessages(20))
                .build();

        System.out.println(assistant.chat("u1", "我叫李雷"));
        System.out.println(assistant.chat("u1", "我叫什么?"));
        System.out.println(assistant.chat("u2", "我叫什么?"));
    }
结构化输出
复制代码
static class LessonPlan {
        // 结构化输出示例:
        // LangChain4j 可以让模型把回答"映射"为一个 POJO。
        // 注意:
        // - 这依赖模型的"结构化输出/JSON 生成能力"。
        // - 如果模型没按结构返回,可能会解析失败(抛异常)。
        public String topic;
        public int days;
        public String[] tasks;
    }

  interface QwenStructuredAssistant {
        @SystemMessage("你是一个教学规划助手。请严格返回结构化结果。")
        LessonPlan plan(@UserMessage String request);
    }

	@Test
    void test09(){
        ChatModel model = OpenAiChatModel.builder()
                .baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1")
                 .apiKey(System.getenv("ALI_API_KEY"))
                .modelName("qwen-plus")
                .build();

        QwenStructuredAssistant assistant = AiServices.builder(QwenStructuredAssistant.class)
                .chatModel(model)
                .build();

        LessonPlan plan = assistant.plan("我想 7 天入门 LangChain4j,请给计划");
        System.out.println(JsonUtils.toJson(plan));
    }
流式输出

这里是TokenStream(边生成边回调),也属于import dev.langchain4j.service.TokenStream;下面的方法,他的效果就是TokenStream(边生成边回调),就类似你去请求豆包一样,他是一段话一段话的输出。

复制代码
	interface QwenStreamingAssistant {
        @SystemMessage("你是一个简洁的中文助手。")
        TokenStream chat(@UserMessage String message);
    }

	@Test
    void test10() {
        // Streaming 必须使用 StreamingChatModel(普通 ChatModel 不支持 token-by-token 输出)
        StreamingChatModel model = OpenAiStreamingChatModel.builder()
                .baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1")
                .apiKey(System.getenv("ALI_API_KEY"))
                .modelName("qwen-plus")
                .build();

        QwenStreamingAssistant assistant = AiServices.create(QwenStreamingAssistant.class, model);

        TokenStream stream = assistant.chat("用 3 句话解释 Java 的 GC,并给一个调优建议");
        CompletableFuture<Void> done = new CompletableFuture<>();

        // 每次收到一段增量输出都会回调(适合"打字机效果")
        stream.onPartialResponse(System.out::print)
                // 全部完成后回调(你也可以在这里拿到完整 ChatResponse)
                .onCompleteResponse(r -> done.complete(null))
                .onError(done::completeExceptionally)
                .start();

        // 等待流式完成,避免 JUnit 提前结束导致看不到输出
        done.orTimeout(60, TimeUnit.SECONDS).join();
        System.out.println();
    }

工具调用(Function/Tool Call)

Tool Call也可以叫Function Call,让大模型不只是"生成文字",而是能在回答过程中调用你提供的函数/工具,拿到"可验证的结果/外部数据",再把结果组织成最终回复。

你可以把它理解成:模型会"发起一次函数调用请求" → 你的程序执行真实逻辑 → 把执行结果回给模型 → 模型再输出最终答案。

通过调用工具,可以让大模型根据真实数据去回答,而不是胡编乱造,模型负责理解意图、拆解步骤、决定何时调用哪个工具。

复制代码
     // 知识点:@Tool(把 Java 方法暴露给模型)、AiServices.tools(...)、让模型"会用工具"而不是纯嘴算
    // 注意:
    // - 是否支持工具调用取决于模型/网关能力;如果服务端不支持会报 400/Unsupported。
    interface QwenToolAssistant {
        @SystemMessage("你是一个严谨的计算助手。需要计算时优先调用工具。")
        String ask(@UserMessage String question);
    }

    static class CalculatorTools {
        @Tool("计算两个整数的乘积")
        int multiply(int a, int b) {
            System.out.println("调用了工具");
            return a * b;
        }
    }

    @Test
    void test11(){
        ChatModel model = OpenAiChatModel.builder()
                .baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1")
                .apiKey(System.getenv("ALI_API_KEY"))
                .modelName("qwen-plus")
                .build();

        QwenToolAssistant assistant = AiServices.builder(QwenToolAssistant.class)
                .chatModel(model)
                .tools(new CalculatorTools())
                .build();

        System.out.println(assistant.ask("请调用工具计算 65*889,最后只输出结果"));
    }
相关推荐
美酒没故事°15 小时前
Open WebUI安装指南。搭建自己的自托管 AI 平台
人工智能·windows·ai
鸿乃江边鸟15 小时前
Nanobot 从onboard启动命令来看个人助理Agent的实现
人工智能·ai
本旺15 小时前
【Openclaw 】完美解决 Codex 认证失败
ai·codex·openclaw·小龙虾·gpt5.4
张張40816 小时前
(域格)环境搭建和编译
c语言·开发语言·python·ai
乐鑫科技 Espressif16 小时前
使用 MCP 服务器,把乐鑫文档接入 AI 工作流
人工智能·ai·esp32·乐鑫科技
语戚16 小时前
Stable Diffusion 入门:架构、空间与生成流程概览
人工智能·ai·stable diffusion·aigc·模型
俊哥V16 小时前
每日 AI 研究简报 · 2026-04-08
人工智能·ai
rrrjqy17 小时前
什么是RAG?
ai
Flittly17 小时前
【SpringAIAlibaba新手村系列】(15)MCP Client 调用本地服务
java·笔记·spring·ai·springboot
Flittly18 小时前
【SpringAIAlibaba新手村系列】(14)MCP 本地服务与工具集成
java·spring boot·笔记·spring·ai