背景

最近再折腾GPT的时候, 遇到流式的响应,总是感觉有点怪怪的,但是又很好,解析了一下,发现竟然是标准化更广的一种协议。

Server-Sent Events

data: {"id":"id-1720428652482","object":"chat.completion.chunk","created":1720428652,"model":"gemma-7b-it","choices":[{"delta":{"content":"。"}}]}

data: [DONE]

openai 返回的流式数据特征非常清晰。

每一行都是 data: 开头,后面是 json 数据,最后一行是 data: [DONE] 表示结束。content type 是 text/event-stream

这个标准就很HTTP,简单高效,实际上,每行的文本也能自定义。如下代码。

spring webflux

@GetMapping(path = "/stream-flux", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<String> streamFlux() {
    return Flux.interval(Duration.ofSeconds(1))
      .map(sequence -> "Flux - " + LocalTime.now().toString());
}

NDJSON

但是实际上我最早期接触的是 NDJSON, 也就是 Newline Delimited JSON, 也就是每一行都是一个 json 对象,如下代码。

NDJSON 更在乎的是结构化的 json 本体,所以其他内容都不会有。但是该规范要晚一点,2013年才有了1.0版。

虽然暂时还是没有看到大型项目中使用过,但是未来可期。两种规范我都是比较支持的。未来的科技领域上 stream 响应一定会越来越多。

spring webflux

@GetMapping(value = "interval", produces = MediaType.APPLICATION_NDJSON_VALUE)
public Flux<TimeModel> interval() {
    DateFormatter dateFormatter = new DateFormatter();
    return Flux.interval(Duration.ofSeconds(1))
            .map(i -> Instant.now())
            .map(ins -> new TimeModel(ins.toEpochMilli(), dateFormatter.print(Date.from(ins), Locale.CHINA)))
            .log();
}

Ref: