当使用 php 库 guzzle 在读取大模型的 stream 数据时,总是发生读取 n 个字节有可能同时读出 n 条 EventSource 消息的问题导致数据看起来是乱序的。
下面是核心方法,该方法是使用百度千帆 AppBuilder 的 OpenAPI 时遇到 stream 流式对话问题的一种解决方案
$answer = $buffer = '';
while (!$body->eof()) {
// 读取 128byte 数据
$buffer .= $body->read(128);
// 这里使用 while 是因为读取 n 个字节有可能同时读出 n 条 EventSource 消息
while (($pos = strpos($buffer, "\n\n")) !== false) {
$eventMsg = substr($buffer, 0, $pos); // 一条 event 消息
// echo Utils::formatMsg("event: {$eventMsg}");
$buffer = substr($buffer, $pos + 2); // 剩余部分
// 解析事件消息
if (empty($eventMsg)) continue;
$jsonString = str_replace('data: ', '', $eventMsg);
$data = json_decode($jsonString, true);
if (json_last_error() == JSON_ERROR_NONE) {
if (empty($data['answer'])) continue;
$content = $data['answer'];
$answer .= $content;
if (is_callable($callback)) $callback($content);
} else {
// 记录错误信息
// echo Utils::formatMsg("error: {$eventMsg}");
if (is_callable($callbackErr)) $callbackErr($eventMsg); // 带有 data: 开头的原始数据
}
}
}
return $answer;
以上大模型流式对话就算搞定了,参考文章:记一次chatgpt接入_guzzle接收stream event-CSDN博客