大模型的流式输出
{
"seq":0, // 结果序号,取值:0, 1, 2, ...
"status":0, // 结果状态,取值:0, 1, 2, 3
"text":"今天深圳市天气阴,气温在26°C到33°C之间,空气质量优," // 应答文本
}
大模型的响应基本都是流式(会分多次)返回的,每次返回一段结果,客户端需要将这些结果段拼接起来才能得到完整的结果。每个json结果段中有一些字段来标记结果的状态,其中的主要字段:
字段 | 说明 |
---|---|
seq | 结果序号,从0开始,取值:0, 1, … |
status | 结果状态,取值:0(开始),1(继续),2(结束),3(就一个结果) |
text | 回复语的片段,需要拼接起来得到完成回复语 |
{
"seq":0,
"status":0, // 开始状态
"text":"今天深圳市天气"
}
{
"seq":1,
"status":1, // 继续状态
"text":"天气预计为"
}
...
{
"seq":9,
"status":2, // 结束状态
"text":"!"
}
上面是一个完整的响应结果示例,从开始、进行中到结束,当然也可能就一个状态为3的结果。
语音播报的逻辑
其实播报分为两个步骤,首先是将文本合成为对应的音频数据,再将合成的音频数据播放出来。其中合成一般也会获取到相应的状态:
{
"dte": "pcm",
"dtf": "audio/L16;rate=16000",
"dts": 1
}
音频合成状态字段,举例说明:常规合成dts顺序: 0 1 1 1 ... 2,短文本合成dts顺序: 3
字段 | 说明 |
---|---|
dts | 音频块合成进度信息:0(合成开始),1(合成中间块,可出现多次),2(合成结束),3(独立合成,合成短文本时出现) |
由于大模型的响应是流式的,如果响应结束拿到完整的结果再进行合成播报会有很高的响应延迟。为了解决延迟问题可以采用边收到结果边合成边播报的并行处理方式。参考流程如下:

整体流程分三支来表述:
大模型响应的处理流程:大模型以持续分段的结果响应用户的一次输入,拿到某一分段数据后需要先判断是否这次响应已经接收完成。其中接收完成判断逻辑是已存接收数据列表不为空并且已存最后一条数据的状态为结束且序号等于已存数据的长度。如果判断接收完成则不进行后续处理,否则将分段数据按照其序号字段加入到接收结果队列中,然后判断是否正在响应处理中,是的话不进行后续处理,否则(初始或打断状态)获取下一个需要合成播报的文本数据,如果获取到的文本数据为空则标记当前状态为打断态,否则标记为启动态并且送往合成播报流程。其中获取下一个需要合成播报的文本数据的流程单独表述。
语音合成状态处理流程:在发起语音合成播报之后语音合成的状态会持续的接收到,如果接收到的合成状态为完成(dts字段是2或者3)判断是否是这次响应的最后一段,如果是的话表示这次响应全部完成清空状态和数据,否则发起获取下一段合成的文本流程。
获取下一段合成播报文本流程:接收完成判断剩余待合成播放的长度是否小于设定的最小长度,小于的话直接返回剩余全文(合成播报这次响应的剩余部分),否则查找剩余部分限制长度后的分隔符,如果找到则截取这部分返回,否则将剩余全文本返回。其中查找分隔符是为了保障一次播报听上去更加完整。接收没有完成也判断待合成播放的长度是否小于设定的最小长度,小于的话返回空不进行后续的合成播报,否则查找剩余部分限制长度后的分隔符,如果找到则截取这部分返回,否则返回空。其中接收未完成流程中返回空时需要等待下一段结果再判断发起合成播报。