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);
    }

}

运行测试:

最后:

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

相关推荐
RainbowSea11 小时前
6. LangChain4j + 多模态视觉理解详细说明
langchain·llm·ai编程
爱可生开源社区12 小时前
2025 年 8 月《大模型 SQL 能力排行榜》发布
sql·llm
fundroid12 小时前
Warp:定义 AI 时代的终端体验
agent·ai编程·warp
用户40993225021212 小时前
Pydantic模型验证测试:你的API数据真的安全吗?
后端·ai编程·trae
玲小珑13 小时前
LangChain.js 完全开发手册(五)Runnable 接口与任务编排系统
前端·langchain·ai编程
Jooolin14 小时前
9.3 阅兵上的网络空间部队都做些什么国防工作?
安全·ai编程
CoderJia程序员甲16 小时前
GitHub 热榜项目 - 日榜(2025-09-02)
ai·llm·github·开源项目·github热榜
AI Echoes1 天前
LangGraph 重要注意事项和常见问题
人工智能·python·langchain·agent
AI大模型1 天前
给AI装上一个'超级大脑':信息检索如何改变RAG系统的游戏规则
程序员·llm·agent