Spring AI 学习之路 流式响应与非流式响应

在构建智能对话系统时,响应的处理方式对于系统的性能和用户体验至关重要。Spring AI 作为一个现代化的框架,支持两种常见的响应处理方式:流式响应(Streaming Response)和非流式响应(Non-streaming Response)。这两种模式各有其优势和适用场景,理解它们的差异能够帮助我们根据实际需求选择最佳的实现方式。

本文将深入探讨 Spring AI 中流式响应和非流式响应的概念、工作原理、使用场景,以及如何在 Spring AI 中实现它们。

什么是流式响应(Streaming Response)?

流式响应是一种逐步返回数据的方式,而不是等待所有数据完全生成后才返回。流式响应通常用于数据量较大、生成过程较长的场景,能够提高系统的实时性,避免长时间的阻塞。

在流式响应中,系统会将数据分批次传输给客户端,每一批数据都可以在生成后立即发送,而不需要等待整个响应完成。这种方式特别适用于实时交互、动态生成内容和大规模数据传输的场景。

流式响应的优势

低延迟:流式响应允许系统在数据生成的过程中就开始将部分数据返回给客户端,显著降低了响应时间。
节省内存:流式处理避免了一次性加载所有数据到内存中,因此可以处理大量数据。
增强交互性:在对话系统中,流式响应能够使得用户在等待回应时就能看到部分内容,从而提升交互体验。

流式响应的适用场景

实时对话系统:当用户与聊天机器人交互时,流式响应可以在用户输入后立即反馈部分结果,逐步完成任务或提供答案。
大数据传输:例如在生成大型报告或数据文件时,流式响应允许系统在数据生成过程中逐步返回文件的一部分。
视频流或音频流:流媒体应用可以通过流式响应来实时传输视频或音频内容。

什么是非流式响应(Non-streaming Response)?

非流式响应是一种传统的响应处理方式,系统会等待所有数据完全准备好后,再将数据一起返回给客户端。在对话系统中,非流式响应通常意味着系统会在处理完全部信息后一次性返回给用户。

非流式响应的优势

简单易实现:相比流式响应,非流式响应的实现更加简单,适用于大多数不需要实时响应的应用场景。
减少并发问题:流式响应可能面临并发数据处理的问题,而非流式响应通常会等待数据完整生成后再发送,因此不会在数据流过程中发生竞争条件。
适用于小数据量:对于一次性可以获取并返回的少量数据,非流式响应更加高效。

非流式响应的适用场景

普通问答系统:用户输入问题后,系统一次性给出完整的回答。
事务处理:当业务逻辑需要完成一些计算或处理后,才能给出完整结果时,非流式响应更为合适。
静态内容交付:例如返回一个完整的网页或文档,非流式响应能更方便地处理。

Spring AI 中的流式响应与非流式响应实现

1. 非流式响应实现

在 Spring AI 中实现非流式响应非常简单。假设我们使用 ChatClient 进行对话处理,它将等待处理完毕后一次性返回响应。

    // ali
    private final ChatModel chatModel;
/**
     * 非流式问答
     *
     * @param prompt 用户提问
     * @return String
     */
    @GetMapping("chat")
    public String chat(@RequestParam String prompt) {
        return this.chatModel.call(prompt);
    }

在这个例子中,ChatClient 负责发送消息并等待生成的完整响应返回。当用户发送消息时,sendMessage 方法会处理整个对话过程并一次性返回结果。

2. 流式响应实现(使用 ChatClient)

对于流式响应,我们可以使用 ChatClient 的流式接口,使系统能够逐步向客户端返回响应数据。这非常适合需要实时反馈的多轮对话系统。

    private final ChatModel chatModel;

/**
     * 流式问答
     *
     * @param prompt 用户提问
     * @return Flux<ServerSentEvent < String>> 流式响应
     */
    @GetMapping(value = "chat/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<ServerSentEvent<String>> chatStream(@RequestParam String prompt) {
        return ChatClient.create(chatModel).prompt()
                // 输入多条消息,可以将历史记录传入
                .messages(new SystemMessage("你是一个Java智能助手,请帮助用户解决Java相关问题"),
                        new UserMessage(prompt))
                // 流式返回
                .stream()
                // 构造SSE(ServerSendEvent)格式返回结果
                .chatResponse().map(chatResponse -> ServerSentEvent.builder(toJson(chatResponse))
                        .event("message")
                        .build());
    }
    
    /**
     * 将流式回答结果转json字符串
     *
     * @param chatResponse 流式回答结果
     * @return String json字符串
     */
    @SneakyThrows
    public String toJson(ChatResponse chatResponse) {
        return objectMapper.writeValueAsString(chatResponse);
    }
posted @ 2025-03-04 10:01  brother_four  阅读(1288)  评论(0)    收藏  举报