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

}

运行测试:

最后:

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

相关推荐
mwq301233 小时前
Cursor Tab 共享无限车
llm
AI大模型3 小时前
RAG不会过时,但你需要这10个上下文处理技巧丨Context Engineering
程序员·llm·agent
thginWalker3 小时前
《LangChain 实战课》学习笔记
langchain
AI大模型4 小时前
万人收藏的提示词工程指导白皮书(附中文版)!Google官方出品,看完整个人都通透了
程序员·llm·agent
三点水7694 小时前
Langchain提示词模版
langchain
三点水7694 小时前
创建自己的第一个LangChainAI
langchain
酷柚易汛智推官5 小时前
AI编程不是低代码的“终结者”,而是进化的“催化剂”
低代码·ai编程·酷柚易汛
Baihai_IDP5 小时前
剖析大模型产生幻觉的三大根源
人工智能·面试·llm
EdisonZhou6 小时前
MAF快速入门(3)聊天记录持久化到数据库
llm·aigc·agent·.net core
在未来等你15 小时前
AI Agent设计模式 Day 19:Feedback-Loop模式:反馈循环与自我优化
设计模式·llm·react·ai agent·plan-and-execute