chat - 两种 http 流式输入输出
2026年9月7日 上午8:33:02
http 流式输出(主要是指文本流式输出),需要使用响应式接口和支持流输出的 mime 声明。常见的有两种文本流式输出:
1、输出 sse(Server Sent Event)
输出的格式:以 sse 消息块为单位,以"空行"为识别间隔。
示例代码:
import org.noear.solon.annotation.Mapping;
import org.noear.solon.annotation.Produces;
import org.noear.solon.ai.chat.event.ChatEvent;
import org.noear.solon.ai.chat.event.ChatEventType;
import org.noear.solon.core.util.MimeType;
import org.noear.solon.web.sse.SseEvent;
import reactor.core.publisher.Flux;
import java.io.IOException;
@Produces(MimeType.TEXT_EVENT_STREAM_UTF8_VALUE)
@Mapping("case1")
public Flux<SseEvent> case1(String prompt) throws IOException {
return chatModel.prompt(prompt)
.stream()
.filter(e -> e.is(ChatEventType.TEXT_DELTA) && e.hasText())
.map(ChatEvent::getText)
.map(text -> new SseEvent().data(text));
}
输出效果如下(sse 消息块有多个属性,data 为必选,其它为可选)
data:xxx
data:yyy
2、输出 ndjson(Newline-Delimited JSON)
输出的格式:以 json 消息块为单位,以"换行符"为识别间隔。
import org.noear.solon.ai.chat.event.ChatEvent;
import org.noear.solon.annotation.Mapping;
import org.noear.solon.annotation.Produces;
import org.noear.solon.core.util.MimeType;
import reactor.core.publisher.Flux;
import java.io.IOException;
@Produces(MimeType.APPLICATION_X_NDJSON_UTF8_VALUE)
@Mapping("case2")
public Flux<ChatEvent> case2(String prompt) throws IOException {
return chatModel.prompt(prompt)
.stream();
}
输出效果如下(内容可能非常复杂,不建议直接输出 ChatEvent)
{"type":"TEXT_DELTA","text":"xxx", ......}
{"type":"TEXT_DELTA","text":"yyy", ......}
3、获取
上面讲的是作为 server 以流式输出。solon-net-httputils 则提供了,作为客户端接收流式获取(或接收)的能力:
- 使用 HttpUtils 获取文本行流(比如 ndjson)
Flux<String> publisher = HttpUtils.http("http://localhost:8080/stream")
.execAsLineStream("GET");
- 使用 HttpUtils 获取 ServerSentEvnet (简称:sse)文本流
Flux<ServerSentEvent> publisher = HttpUtils.http("http://localhost:8080/sse")
.execAsSseStream("GET");