问题:人工智能对话模型如何实现流式接口响应(一行一行打印出来)?
环境:php + nginx
答:
流式响应就是在请求接口时实时地一行一行传输给前端,第一反应是使用echo进行循环打印,所以即写了一段小代码测试,发现是一下子返回,无法实现一行一行的效果。
为什么呢?
查询资料了解到,在后台将数据返回给前端时,需要经过缓冲区,缓存区是为了优化请求过程而使用的方法,具体就是先将小数据缓存累计起来再一次性传输。
那么在请求的过程中经过了哪些缓冲区buffer呢?
1、php语言本身有一个output_buffering配置,就是默认的缓冲区,默认值是4096,也即是会累计4k的数据再进行传输;

(php.ini)
2、nginx和php之间有一个通用网关接口程序,叫cgi,是来链接nginx和php的桥梁,本身也有缓冲区的配置

fastcgi_connect_timeout 300;
fastcgi_send_timeout 300;
fastcgi_read_timeout 300;
fastcgi_buffer_size 4k;  //用多大的缓冲区来读取响应的第一部分,也即是http的响应头
fastcgi_buffers 4 4k; //开启4个4k大小的缓冲区
fastcgi_busy_buffers_size 4k; //达到多大就先将数据传输
fastcgi_temp_file_write_size 256k;
fastcgi_intercept_errors on;

3、nginx本身的配置,包括

 gzip off;

话不多少,贴代码
前端:

async function getRes() {

  const res = await fetch(url, {
    method:'POST',
    mode: 'cors', // no-cors, *cors, same-origin
    headers: {
        'Content-Type': 'application/json',
        "Authorization":"Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJ4IiwiYXVkIjoieCIsImlhdCI6MTcxODY4ODE3NiwibmJmIjoxNzE4Njg4MTc2LCJleHAiOjE3MjEyODAxNzYsImV4dGVuZCI6eyJpZCI6MSwibmFtZSI6InBhZ2UiLCJlbWFpbCI6bnVsbCwicm9sZSI6WzFdLCJzdGF0dXMiOjF9fQ.t5yn5k2o-bgXQZoqwBp7I2BAr5EesK5S4XyMMg2Q3mg"
    },
    body:JSON.stringify({
          "message": "介绍优乐公司",
    }),
 });
  const reader = res.body.getReader();
  const decoder = new TextDecoder();
  while(1) {
    // 读取数据流的第一块数据,done表示数据流是否完成,value表示当前的数
    const {done, value} = await reader.read();
    if (done) break;
    const text = decoder.decode(value);
    // 打印第一块的文本内容
    console.log(text, done);
  }
}

后端:

     //如何将数据写到响应中
        $fuc = function ($curl, $data) use (&$res, $user, $current) {

            $filters = explode("\n", $data);


            foreach($filters as $filter) {
                //拼接字符串
                $reply =  json_decode(
                    substr($filter, 5),
                    true
                );


                if($reply != null) {

                    if($reply["choices"][0]["finish_reason"] == "stop") {
                        $rebuild = ["text" => "DONE","message_id" => ""];
                        echo json_encode($rebuild, JSON_UNESCAPED_UNICODE);
                        echo str_pad('', 8192);

                    } else {
                        $rebuild = ["text" => $reply["choices"][0]["delta"]["content"],"message_id" => ""];
                    }


                    if(!empty($reply["choices"][0]['delta'])
                    && $reply["choices"][0]["delta"]["content"] != ""
                    ) {
                     
                        echo json_encode($rebuild, JSON_UNESCAPED_UNICODE);
                        echo str_pad('', 8192);
                      
                    }


                    if($reply["choices"][0]["finish_reason"] == "stop") { //结束

                        break;

                    } else {

                        $res .= $reply["choices"][0]["delta"]["content"];
                    }

                }


            }

            return strlen($data);
        };
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, DeepSeekHelper::$base_url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
        curl_setopt($ch, CURLOPT_HTTPHEADER, [
          'Content-Type: application/json; charset=utf-8',
          'Accept: application/json',
          "Authorization: Bearer ".DeepSeekHelper::$apiKey
        ]);

        curl_setopt($ch, CURLOPT_WRITEFUNCTION, $fuc);

        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($postData));
        curl_setopt($ch, CURLOPT_TIMEOUT, 60);

        // dd(json_encode($postData));

        curl_exec($ch);
        curl_close($ch);

sengerlion
55 声望401 粉丝

了解自己到细胞粒度。