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,最后只输出结果"));
    }
相关推荐
冰糖猕猴桃3 小时前
【AI】把“大杂烩抽取”拆成多步推理:一个从单提示到多阶段管线的实践案例
大数据·人工智能·ai·提示词·多步推理
PPIO派欧云3 小时前
PPIO上线GLM-OCR:0.9B参数SOTA性能,支持一键部署
人工智能·ai·大模型·ocr·智谱
金融RPA机器人丨实在智能4 小时前
2026动态规划新风向:实在智能Agent如何以自适应逻辑重构企业效率?
算法·ai·重构·动态规划
哥布林学者4 小时前
吴恩达深度学习课程:深度学习入门笔记全集目录
深度学习·ai
带刺的坐椅6 小时前
用 10 行 Java8 代码,开发一个自己的 ClaudeCodeCLI?你信吗?
java·ai·llm·agent·solon·mcp·claudecode·skills
程序设计实验室7 小时前
Windows + AMD 显卡,终于能用 PyTorch 炼丹了
ai
CoderJia程序员甲7 小时前
GitHub 热榜项目 - 日榜(2026-02-05)
ai·开源·大模型·github·ai教程
GJGCY7 小时前
2026主流智能体平台技术路线差异,各大平台稳定性与集成能力对比
人工智能·经验分享·ai·智能体
acai_polo8 小时前
如何在国内合规、稳定地使用GPT/Claude/Gemini API?中转服务全解析
人工智能·gpt·ai·语言模型·ai作画
阿杰学AI8 小时前
AI核心知识86——大语言模型之 Superalignment(简洁且通俗易懂版)
人工智能·深度学习·ai·语言模型·超级对齐·superalignment·#ai安全