最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

基于SpringBoot和Dify實(shí)現(xiàn)流式響應(yīng)輸出

 更新時(shí)間:2025年03月18日 11:06:35   作者:ZKM??!  
這篇文章主要為大家詳細(xì)介紹了如何基于SpringBoot和Dify實(shí)現(xiàn)流式響應(yīng)輸出效果,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以參考一下

在使用 Dify(假設(shè)為某種生成式 AI 模型或服務(wù))結(jié)合 Spring Boot 和 WebClient 實(shí)現(xiàn)流式輸出時(shí),我們需要確保技術(shù)棧的版本兼容性,并理解流式輸出的核心概念。以下是詳細(xì)講解:

1. 技術(shù)棧版本要求

Spring Boot 版本要求

最低推薦版本:2.7.x 或 3.x

如果需要支持 HTTP/2 或更高級別的異步處理能力,建議使用 Spring Boot 3.x。

Spring Boot 3.x 基于 Spring Framework 6.x 和 Java 17+,提供了更好的反應(yīng)式編程支持。

JDK 版本要求

最低推薦版本:Java 11

Spring Boot 2.7.x 支持 Java 8 及以上,但推薦使用 Java 11 或更高版本。

如果使用 Spring Boot 3.x,則必須使用 Java 17 或更高版本,因?yàn)?Spring Boot 3.x 已經(jīng)停止支持 Java 11 以下的版本。

2. 核心概念:流式輸出

流式輸出(Streaming Output)是指服務(wù)器以分塊的方式逐步將數(shù)據(jù)發(fā)送到客戶端,而不是一次性返回完整的結(jié)果。這種方式特別適合處理大文件傳輸、實(shí)時(shí)數(shù)據(jù)流或生成式模型的逐詞輸出。

在 Spring Boot 中,可以通過以下方式實(shí)現(xiàn)流式輸出:

  • 使用 ResponseEntity<Flux<?>> 或 ResponseBodyEmitter(適用于同步場景)。
  • 使用 WebClient 的反應(yīng)式編程模型來處理流式請求和響應(yīng)。

3. 實(shí)現(xiàn)步驟

3.1 添加依賴

確保在 pom.xml 中添加以下依賴項(xiàng):

 <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-webflux</artifactId>
 </dependency>

spring-boot-starter-webflux 提供了反應(yīng)式 Web 編程的支持。

3.2 配置 WebClient

創(chuàng)建一個(gè) WebClient 實(shí)例,主要用于設(shè)置跨域資源共享(CORS, Cross-Origin Resource Sharing)。它的作用是解決前端和后端在不同域名或端口下通信時(shí)的跨域問題。

@Configuration
public class WebConfig implements WebMvcConfigurer {

    static final List<String> ORIGIN_LIST = Arrays.asList(
            // 本地
            "http://localhost:8080",
            "http://127.0.0.1:8080",
            "http://localhost:8888",
            "http://127.0.0.1:8888",
            "http://localhost:8803",
            "http://127.0.0.1:8803"
    );

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        // 配置全局跨域規(guī)則
        registry.addMapping("/**") // 允許所有路徑的請求
                .allowedOrigins(ORIGIN_LIST.toArray(new String[0])) // 允許的源
                .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS") // 允許的HTTP方法
                .allowedHeaders("Content-Type", "Authorization") // 允許的請求頭
                .allowCredentials(true); // 是否允許發(fā)送Cookie等憑證信息
    }
}

3.3 實(shí)現(xiàn)流式輸出控制器

@Slf4j
@RestController
@RequestMapping("/api")
@RequiredArgsConstructor
public class DifyController {
    

    @Value("${portal.chatMessages}")
    private String chatMessages;
    
    private final DifyService difyService;
    
    @GetMapping(value = "/chatMessagesStreaming", produces = "text/event-stream")
    public Flux<StreamResponse> chatMessagesStreaming(HttpServletRequest request,
                                                  @RequestParam(value = "query", required = true) String query,
                                                  @RequestParam(value = "userName", required = true) String userName,
                                                  @RequestParam(value = "conversationId", required = false) String conversationId) throws Exception {
   
	   return difyService.streamingMessage(query, conversationId, userName).doOnNext(response -> {
	        log.info("流式結(jié)果:" + response.toString());
	        //workflow_finished節(jié)點(diǎn)可以獲取完整答案,進(jìn)行你的邏輯處理
	        if (response.getEvent().equals("workflow_finished")) {
	            log.info("進(jìn)入workflow_finished階段");
	            String answer = response.getData().getOutputs().getAnswer();//完整答案
	        }
	         //message_end結(jié)束節(jié)點(diǎn),進(jìn)行你的邏輯處理
	        if (response.getEvent().equals("message_end")) {
	            log.info("進(jìn)入message_end");
	        }
	
	    });
}

3.4 實(shí)現(xiàn)流式輸出服務(wù)層

java
@Slf4j
@Service
@RequiredArgsConstructor
public class DifyService {

	@Value("${dify.url}")
    private String url;

    @Value("${dify.key}")
    private String apiKey;
	/**
     * 流式調(diào)用dify.
     *
     * @param query 查詢文本
     * @param conversationId id
     * @param userName  用戶名
     * @return Flux 響應(yīng)流
     */
    public Flux<StreamResponse> streamingMessage(String query, String conversationId, String userName) {
        //1.設(shè)置請求體
        DifyRequestBody body = new DifyRequestBody();
        body.setInputs(new HashMap<>());
        body.setQuery(query);
        body.setResponseMode("streaming");
        body.setConversationId("");
        body.setUser(userName);
        if (StringUtils.isNotEmpty(conversationId)) {
            body.setConversationId(conversationId);
        }
        //如果存在自定義入?yún)⒖梢约拥饺缦翸ap中
        //Map<String, Object> commoninputs = new HashMap<>();
        //commoninputs.put("search_type", searchType);
        //body.setInputs(commoninputs);

        //2.使用webclient發(fā)送post請求
        return webClient.post()
                .uri(url)
                .headers(httpHeaders -> {
                    httpHeaders.setContentType(MediaType.APPLICATION_JSON);
                    httpHeaders.setBearerAuth(apiKey);
                })
                .bodyValue(JSON.toJSONString(body))
                .retrieve()
                .bodyToFlux(StreamResponse.class);//實(shí)體轉(zhuǎn)換
                .filter(this::shouldInclude) // 過濾掉不需要的數(shù)據(jù)【根據(jù)需求增加】
                //.map(this::convertToCustomResponseAsync) // 異步轉(zhuǎn)換【如果返回格式自定義則通過異步轉(zhuǎn)換實(shí)現(xiàn)】
                .onErrorResume(throwable -> {
                	log.info("異常輸出:"+throwable.getMessage())
                })
                //.concatWith(Mono.just(createCustomFinalMessage())); // 添加自定義的最終消息【根據(jù)需求增加】
    }

    private boolean shouldInclude(StreamResponse streamResponse) {
        // 示例:只要message節(jié)點(diǎn)的數(shù)據(jù)和message_end節(jié)點(diǎn)的數(shù)據(jù)
        if (streamResponse.getEvent().equals("message")
                || streamResponse.getEvent().equals("message_end")) {
            return true;
        }
        return false;
    }

3.4 實(shí)現(xiàn)流式輸出數(shù)據(jù)訪問層

和dify返回流式輸出格式一致

@Data
public class StreamResponse implements Serializable {

    /**
     * 不同模式下的事件類型.
     */
    private String event;

    /**
     * agent_thought id.
     */
    private String id;

    /**
     * 任務(wù)ID.
     */
    private String task_id;

    /**
     * 消息唯一ID.
     */
    private String message_id;

    /**
     * LLM 返回文本塊內(nèi)容.
     */
    private String answer;

    /**
     * 創(chuàng)建時(shí)間戳.
     */
    private Long created_at;

    /**
     * 會(huì)話 ID.
     */
    private String conversation_id;
    
    private StreamResponseData data;
}

@Data
public class StreamResponseData implements Serializable {
    private String id;
    private String workflow_id;
    private String status;
    private Long created_at;
    private Long finished_at;
    private OutputsData outputs;
}

@Data
public class OutputsData implements Serializable {
    private String answer;
}

4. 關(guān)鍵點(diǎn)說明

1.MediaType.TEXT_EVENT_STREAM_VALUE

表示使用 Server-Sent Events (SSE) 協(xié)議進(jìn)行流式傳輸。

客戶端可以通過瀏覽器或支持 SSE 的工具(如 Postman)接收流式數(shù)據(jù)。

2.Flux

Flux 是 Reactor 庫中的核心類型,表示一個(gè)可以包含零個(gè)或多個(gè)元素的異步序列。

在這里,F(xiàn)lux 表示從 Dify 接收到的逐詞或逐句生成的文本流。

3.WebClient 的反應(yīng)式特性

WebClient 是 Spring 提供的反應(yīng)式 HTTP 客戶端,能夠高效處理流式數(shù)據(jù)。

它不會(huì)阻塞線程,而是通過事件驅(qū)動(dòng)的方式逐步處理數(shù)據(jù)

總結(jié)

通過上述步驟,我們可以使用 Spring Boot 和 WebClient 實(shí)現(xiàn)流式輸出功能。關(guān)鍵在于利用反應(yīng)式編程模型(Reactor 的 Flux 和 WebClient),以及正確配置流式傳輸協(xié)議(如 SSE)。根據(jù)需求選擇合適的 Spring Boot 和 JDK 版本,可以確保項(xiàng)目的性能和穩(wěn)定性。

到此這篇關(guān)于基于SpringBoot和Dify實(shí)現(xiàn)流式響應(yīng)輸出的文章就介紹到這了,更多相關(guān)SpringBoot Dify流式響應(yīng)輸出內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 解決idea?中?SpringBoot?點(diǎn)擊運(yùn)行沒反應(yīng)按鈕成灰色的問題

    解決idea?中?SpringBoot?點(diǎn)擊運(yùn)行沒反應(yīng)按鈕成灰色的問題

    在使用 Spring Boot 開發(fā)項(xiàng)目時(shí),可能會(huì)遇到一個(gè)問題:點(diǎn)擊運(yùn)行按鈕后,控制臺沒有任何輸出,項(xiàng)目界面也沒有顯示,這種情況可能是由多種原因?qū)е碌?,本文將介紹一些常見的解決方法,需要的朋友可以參考下
    2023-08-08
  • Java 將PPT幻燈片轉(zhuǎn)為HTML文件的實(shí)現(xiàn)思路

    Java 將PPT幻燈片轉(zhuǎn)為HTML文件的實(shí)現(xiàn)思路

    本文以Java程序代碼為例展示如何通過格式轉(zhuǎn)換的方式將PPT幻燈片文檔轉(zhuǎn)為HTML文件,本文通過實(shí)例代碼圖文相結(jié)合給大家分享實(shí)現(xiàn)思路,需要的朋友參考下吧
    2021-06-06
  • Java 隨機(jī)取字符串的工具類

    Java 隨機(jī)取字符串的工具類

    隨機(jī)數(shù)在實(shí)際中使用很廣泛,比如要隨即生成一個(gè)固定長度的字符串、數(shù)字?;蛘唠S即生成一個(gè)不定長度的數(shù)字、或者進(jìn)行一個(gè)模擬的隨機(jī)選擇等等。Java提供了最基本的工具,可以幫助開發(fā)者來實(shí)現(xiàn)這一切
    2014-01-01
  • java取出list中某幾個(gè)屬性組成一個(gè)新集合的幾種方式

    java取出list中某幾個(gè)屬性組成一個(gè)新集合的幾種方式

    在Java開發(fā)中經(jīng)常需要對List中的對象進(jìn)行一些操作,例如對某個(gè)字段進(jìn)行過濾、排序等,這篇文章主要給大家介紹了關(guān)于java取出list中某幾個(gè)屬性組成一個(gè)新集合的幾種方式,需要的朋友可以參考下
    2024-03-03
  • Java面向?qū)ο笾蓡T隱藏與屬性封裝操作示例

    Java面向?qū)ο笾蓡T隱藏與屬性封裝操作示例

    這篇文章主要介紹了Java面向?qū)ο笾蓡T隱藏與屬性封裝操作,結(jié)合實(shí)例形式分析了Java面向?qū)ο蟪绦蛟O(shè)計(jì)中成員的隱藏及屬性封裝相關(guān)實(shí)現(xiàn)與使用操作技巧,需要的朋友可以參考下
    2018-06-06
  • Java設(shè)計(jì)模式之橋模式(Bridge模式)介紹

    Java設(shè)計(jì)模式之橋模式(Bridge模式)介紹

    這篇文章主要介紹了Java設(shè)計(jì)模式之橋模式(Bridge模式)介紹,本文講解了為什么使用橋模式、如何實(shí)現(xiàn)橋模式、Bridge模式在EJB中的應(yīng)用等內(nèi)容,需要的朋友可以參考下
    2015-03-03
  • SpringBoot中application.properties、application.yaml、application.yml區(qū)別

    SpringBoot中application.properties、application.yaml、applicati

    本文主要介紹了SpringBoot中application.properties、application.yaml、application.yml區(qū)別,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2024-04-04
  • Java中ArrayList 和 HashMap 自動(dòng)擴(kuò)容機(jī)制詳解

    Java中ArrayList 和 HashMap 自動(dòng)擴(kuò)容機(jī)制詳解

    本文深入分析了Java集合框架中ArrayList和HashMap的自動(dòng)擴(kuò)容機(jī)制,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2026-03-03
  • Java?深入學(xué)習(xí)static關(guān)鍵字和靜態(tài)屬性及方法

    Java?深入學(xué)習(xí)static關(guān)鍵字和靜態(tài)屬性及方法

    這篇文章主要介紹了Java?深入學(xué)習(xí)static關(guān)鍵字和靜態(tài)屬性及方法,文章通過圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下
    2022-09-09
  • 關(guān)于fastjson的常見API詳解

    關(guān)于fastjson的常見API詳解

    這篇文章主要介紹了關(guān)于fastjson的常見API詳解,Fastjson是一個(gè)Java庫,可用于將Java對象轉(zhuǎn)換為其JSON表示,它還可用于將JSON字符串轉(zhuǎn)換為等效的Java對象,Fastjson可以處理任意Java對象,包括您沒有源代碼的預(yù)先存在的對象,需要的朋友可以參考下
    2023-07-07

最新評論

临夏市| 南投市| 塘沽区| 磐安县| 双柏县| 连江县| 高唐县| 梧州市| 吉木萨尔县| 榕江县| 桐庐县| 上林县| 尚义县| 大名县| 洛阳市| 上犹县| 双桥区| 中山市| 漳州市| 揭阳市| 垣曲县| 城步| 淳化县| 阿克陶县| 灵丘县| 临夏县| 乌海市| 岑巩县| 辽中县| 谢通门县| 惠东县| 永城市| 大余县| 两当县| 闵行区| 上犹县| 普格县| 边坝县| 调兵山市| 肥城市| 巢湖市|