6. LangChain4j + 流式输出详细说明

6. LangChain4j + 流式输出详细说明

@[toc]

流式输出(StreamingOutput)的概念

是一种逐步返回大模型生成结果的技术,生成一点返回一点,允许服务器将响应内容,分批次实时传输给客户端,而不是等待全部内容生成完毕后再一次性返回。这种机制能显著提升用户体验,尤其适用于大模型响应较慢的场景(如生成长文本或复杂推理结果)。

简单的理解就是:服务器接受到一点大模型的信息,就生成发送一点给前端。

LangChain4j + 流式输出实操

  1. 创建对应的 moudle 模块项目

  2. pom.xml 编写相关依赖:最基本的流式输出 langchain4j-open-ai + langchain4j + langchain4j-reactor 这三件必须存在,这里我们不指定版本,而是通过继承的 pom.xml 当中获取。

xml 复制代码
<!--langchain4j-open-ai + langchain4j + langchain4j-reactor-->
<!--  低阶 langchain4j-->
<dependency>
    <groupId>dev.langchain4j</groupId>
    <artifactId>langchain4j-open-ai</artifactId>
</dependency>
<!--  高阶 langchain4j-->
<dependency>
    <groupId>dev.langchain4j</groupId>
    <artifactId>langchain4j</artifactId>
</dependency>
<!-- 流式输出 -->
<dependency>
    <groupId>dev.langchain4j</groupId>
    <artifactId>langchain4j-reactor</artifactId>
</dependency>
xml 复制代码
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>com.rainbowsea</groupId>
        <artifactId>langchain4j-studys</artifactId>
        <version>1.0-SNAPSHOT</version>
    </parent>

    <groupId>com.rainbowsea.langchain4j07chatstream</groupId>
    <artifactId>langchain4j-05chat-stream</artifactId>
    <packaging>jar</packaging>

    <name>langchain4j-05chat-stream</name>
    <url>http://maven.apache.org</url>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--langchain4j-open-ai + langchain4j + langchain4j-reactor-->
        <dependency>
            <groupId>dev.langchain4j</groupId>
            <artifactId>langchain4j-open-ai</artifactId>
        </dependency>
        <dependency>
            <groupId>dev.langchain4j</groupId>
            <artifactId>langchain4j</artifactId>
        </dependency>
        <dependency>
            <groupId>dev.langchain4j</groupId>
            <artifactId>langchain4j-reactor</artifactId>
        </dependency>
        <!--lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <!--hutool-->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.22</version>
        </dependency>


        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>3.8.1</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>
  1. 配置 applcation.yaml / properties 配置文件,其中指明我们的输出响应的编码格式,因为如果不指定的话,存在返回的中文,就是乱码了。
properties 复制代码
server.port=9005
spring.application.name=langchain4j-05chat-stream 
# 设置响应的字符编码,避免流式返回输出乱码
server.servlet.encoding.charset=utf-8
server.servlet.encoding.enabled=true
server.servlet.encoding.force=true
  1. 编写 ChatAssistan 接口,操作交流大模型
java 复制代码
package com.rainbowsea.langchain4j07chatstream.service;

import reactor.core.publisher.Flux;

/**
 * @Date 2025-05-30 16:19
 * @Description: TODO
 */
public interface ChatAssistant
{
    /**
     * 普通输出,不是流式的
     * @param prompt
     * @return
     */
    String chat(String prompt);

    /**
     * 流式输出,是流式的
     * 注意:流式输出返回的要为 Flux<T> 类型的数据类型
     * @param prompt
     * @return
     */
    Flux<String> chatFlux(String prompt);
}
  1. 编写大模型三件套(大模型 key,大模型 name,大模型 url) 三件套配置类
java 复制代码
package com.rainbowsea.langchain4j07chatstream.config;

import com.rainbowsea.langchain4j07chatstream.service.ChatAssistant;
import dev.langchain4j.model.chat.ChatModel;
import dev.langchain4j.model.chat.StreamingChatModel;
import dev.langchain4j.model.openai.OpenAiChatModel;
import dev.langchain4j.model.openai.OpenAiStreamingChatModel;
import dev.langchain4j.service.AiServices;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.time.Duration;
import java.util.List;

/**
 * @Description: 知识出处,https://docs.langchain4j.dev/tutorials/response-streaming
 */
@Configuration
public class LLMConfig
{


    /**
     * @Description: 流式对话接口 StreamingChatModel
     * @Auther: zzyybs@126.com
     */
    @Bean
    public StreamingChatModel streamingChatModel(){
        return OpenAiStreamingChatModel.builder()
                .apiKey(System.getenv("aliQwen-api"))
                .modelName("qwen-plus")
                .baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1")
                .build();
    }

    @Bean
    public ChatAssistant chatAssistant(StreamingChatModel streamingChatModel){
        return AiServices.create(ChatAssistant.class, streamingChatModel);
    }


    

    /**
    * @Description: 普通对话接口 ChatModel
    * @Auther: zzyybs@126.com
    */
    @Bean(name = "qwen")
    public ChatModel chatModelQwen()
    {
        return OpenAiChatModel.builder()
                .apiKey(System.getenv("aliQwen_api"))  // 配置为你自己的环境变量当中的值
                .modelName("qwen-plus")
                .baseUrl("https://dashscope.aliyuncs.com/compatible-mode/v1")
                .build();
    }



}
  1. 编写流式调用的 cutroller
  • 流式输出的编写的 cutroller 有三种方式:
    • 第一种方式:Flux.create() 方法(该返回会返回一个 Flux 流式类)返回流式输出,但是 Flux.create() 方法的 StreamingChatLanguageModel 当中的 chat(prompt, new StreamingChatResponseHandler() ) 方法的StreamingChatResponseHandler() 是个接口, 我们需要实现该接口的三个方法。
    • 第二种方式:直接重写使用StreamingChatLanguageModel 接口类,直接调用 streamingChatLanguageModel.chat(prompt, new StreamingChatResponseHandler() 方法,没有返回值。不会返回一个 Flux 流式类
    • 第三种方式:就是使用自己定义的 ChatAssistant 操作大模型的接口类,让就返回一个 Flux 流式类。推荐使用第三种方式,简单,灵活,方便实现

第一种方式: Flux.create() 方法(该返回会返回一个 Flux 流式类)返回流式输出,但是 Flux.create() 方法的 StreamingChatLanguageModel 当中的 chat(prompt, new StreamingChatResponseHandler() ) 方法的

java 复制代码
Flux.create(emitter -> {
            streamingChatLanguageModel.chat(prompt, new StreamingChatResponseHandler()
            {
                @Override
                public void onPartialResponse(String partialResponse)
                {
                    emitter.next(partialResponse);
                }

                @Override
                public void onCompleteResponse(ChatResponse completeResponse)
                {
                    emitter.complete();
                }

                @Override
                public void onError(Throwable throwable)
                {
                    emitter.error(throwable);
                }
            });
        });

返回的是一个 Flux 流式类

java 复制代码
import com.rainbowsea.langchain4j07chatstream.service.ChatAssistant;
import dev.langchain4j.model.chat.StreamingChatModel;
import dev.langchain4j.model.chat.response.ChatResponse;
import dev.langchain4j.model.chat.response.StreamingChatResponseHandler;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;

/**
 * @Description: 知识出处,https://docs.langchain4j.dev/tutorials/response-streaming
 */
@RestController
@Slf4j
public class StreamingChatModelController
{
    @Resource //直接使用 low-level LLM API
    private StreamingChatModel streamingChatLanguageModel;


    // http://localhost:9005/chatstream/chat?prompt=天津有什么好吃的
    @GetMapping(value = "/chatstream/chat")
    public Flux<String> chat(@RequestParam("prompt") String prompt)
    {
        System.out.println("---come in chat");

        return Flux.create(emitter -> {
            streamingChatLanguageModel.chat(prompt, new StreamingChatResponseHandler()
            {
                @Override
                public void onPartialResponse(String partialResponse)
                {
                    emitter.next(partialResponse);
                }

                @Override
                public void onCompleteResponse(ChatResponse completeResponse)
                {
                    emitter.complete();
                }

                @Override
                public void onError(Throwable throwable)
                {
                    emitter.error(throwable);
                }
            });
        });
    }

}

运行测试:

第二种方式:直接重写使用StreamingChatLanguageModel 接口类,直接调用 streamingChatLanguageModel.chat(prompt, new StreamingChatResponseHandler() 方法,没有返回值。不会返回一个 Flux 流式类

java 复制代码
import com.rainbowsea.langchain4j07chatstream.service.ChatAssistant;
import dev.langchain4j.model.chat.StreamingChatModel;
import dev.langchain4j.model.chat.response.ChatResponse;
import dev.langchain4j.model.chat.response.StreamingChatResponseHandler;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;

/**
 * @Description: 知识出处,https://docs.langchain4j.dev/tutorials/response-streaming
 */
@RestController
@Slf4j
public class StreamingChatModelController
{
    @Resource //直接使用 low-level LLM API
    private StreamingChatModel streamingChatLanguageModel;


    @GetMapping(value = "/chatstream/chat2")
    public void chat2(@RequestParam(value = "prompt", defaultValue = "北京有什么好吃") String prompt)
    {
        System.out.println("---come in chat2");
        streamingChatLanguageModel.chat(prompt, new StreamingChatResponseHandler()
        {
            @Override
            public void onPartialResponse(String partialResponse)
            {
                System.out.println(partialResponse);
            }

            @Override
            public void onCompleteResponse(ChatResponse completeResponse)
            {
                System.out.println("---response over: "+completeResponse);
            }

            @Override
            public void onError(Throwable throwable)
            {
                throwable.printStackTrace();
            }
        });
    }

}

运行测试:

因为没有返回值,只是在控制台当中打印出来。

第三种方式:就是使用自己定义的 ChatAssistant 操作大模型的接口类,让就返回一个 Flux 流式类。

java 复制代码
import com.rainbowsea.langchain4j07chatstream.service.ChatAssistant;
import dev.langchain4j.model.chat.StreamingChatModel;
import dev.langchain4j.model.chat.response.ChatResponse;
import dev.langchain4j.model.chat.response.StreamingChatResponseHandler;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import reactor.core.publisher.Flux;

/**
 * @Description: 知识出处,https://docs.langchain4j.dev/tutorials/response-streaming
 */
@RestController
@Slf4j
public class StreamingChatModelController
{

    @Resource //自己封装接口使用 high-level LLM API
    private ChatAssistant chatAssistant;


    @GetMapping(value = "/chatstream/chat3")
    public Flux<String> chat3(@RequestParam(value = "prompt", defaultValue = "南京有什么好吃") String prompt)
    {
        System.out.println("---come in chat3");

        return chatAssistant.chatFlux(prompt);
    }

}

运行测试:

最后:

"在这个最后的篇章中,我要表达我对每一位读者的感激之情。你们的关注和回复是我创作的动力源泉,我从你们身上吸取了无尽的灵感与勇气。我会将你们的鼓励留在心底,继续在其他的领域奋斗。感谢你们,我们总会在某个时刻再次相遇。"

相关推荐
大强同学26 分钟前
对比 VS Code:Zed 编辑器编码体验全面解析
人工智能·windows·编辑器·ai编程
熊猫钓鱼>_>26 分钟前
从“流程固化“到“意图驱动“:大模型调智能体调Skill架构深度解析
ai·架构·大模型·llm·agent·skill·openclaw
前进的李工1 小时前
LangChain使用AI工具赋能:解锁大语言模型无限潜力
开发语言·人工智能·语言模型·langchain·大模型
小村儿2 小时前
连载04-最重要的Skill---一起吃透 Claude Code,告别 AI coding 迷茫
前端·后端·ai编程
北冥有羽Victoria3 小时前
OpenCLI 操作网页 从0到1完整实操指南
vscode·爬虫·python·github·api·ai编程·opencli
杨艺韬3 小时前
为什么需要理解 LangChain
langchain·agent
坤岭4 小时前
大模型“入侵”广告推荐
人工智能·langchain·推荐算法
Thomas.Sir4 小时前
GitHub Copilot从入门到精通【从基础补全到智能代理,解锁AI编程全技能】
github·copilot·ai编程
加瓦点灯4 小时前
Vibe Coding 最佳实践:人控架构,AI执行
ai编程
Baihai_IDP4 小时前
微软多模态推理模型 Phi-4-reasoning-vision 训练经验分享
人工智能·面试·llm