You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PHP调用OpenAI GPT-3 API如何实现流式响应实时逐节点输出

问题根因

原代码无法实现流式输出,核心有3个问题:

  • 开启了CURLOPT_RETURNTRANSFER配置,cURL会把所有响应内容暂存到内存,等请求完全结束后才会一次性返回结果,不会边接收边处理
  • 没有配置cURL的写入回调函数,无法在接收到每一块响应数据时立刻做处理输出
  • PHP默认开启了输出缓冲,即使打印内容,Web服务器/PHP也会等内容攒到一定大小或者请求结束才发给浏览器,不会实时推送到前端
实现方案

按以下逻辑调整代码即可实现逐段实时输出:

  1. 关闭CURLOPT_RETURNTRANSFER,通过写入回调逐块处理响应,不要等curl_exec返回完整结果
  2. 配置CURLOPT_WRITEFUNCTION回调,每接收到一块OpenAI返回的SSE格式数据,立刻解析内容、推送给客户端
  3. 临时关闭PHP的输出缓冲,每次输出内容后手动执行刷缓冲操作,确保内容实时发送到前端
  4. Web访问场景下提前设置SSE相关响应头,关闭Web服务器的代理缓冲

调整后的可运行代码如下:

// 关闭PHP输出缓冲,开启强制刷出
ob_end_clean();
ob_implicit_flush(true);
// Web场景下设置SSE响应头,关闭各级缓冲
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
header('Connection: keep-alive');
header('X-Accel-Buffering: no'); // 适配Nginx反向代理场景,关闭Nginx缓冲

function str_starts_with_compatible($haystack, $needle) {
    return substr($haystack, 0, strlen($needle)) === $needle;
}

function openAI(){
    $OPENAI_API_KEY="API_KEY_GOES_HERE";
    $user_id="1";
    $prompt="tell me what you can do for me.";
    $temperature=0.5;
    $max_tokens=300;

    $data = array(
        'model'=>'text-davinci-002',
        'prompt'=>$prompt,
        'temperature'=>$temperature,
        'max_tokens'=>$max_tokens,
        'top_p'=>1.0,
        'stream'=>true,
        'frequency_penalty'=>0.0,
        'presence_penalty'=>0.0,
        'user' => $user_id
    );

    $post_json= json_encode($data);
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, 'https://api.openai.com/v1/completions');
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, false);
    curl_setopt($ch, CURLOPT_POST, 1);
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $post_json);
    curl_setopt($ch, CURLOPT_TIMEOUT, 0); // 取消超时限制,避免长流中断

    $headers = array();
    $headers[] = 'Content-Type: application/json';
    $headers[] = "Authorization: Bearer $OPENAI_API_KEY";
    $headers[] = 'Accept: text/event-stream';
    curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);

    // 配置写入回调,每收到一块数据触发一次
    curl_setopt($ch, CURLOPT_WRITEFUNCTION, function($ch, $chunk){
        $lines = explode("\n", $chunk);
        foreach ($lines as $line) {
            $line = trim($line);
            if (empty($line)) continue;
            // 处理SSE格式的data行
            if (str_starts_with_compatible($line, 'data: ')) {
                $dataStr = substr($line, 6);
                // 收到结束标识终止请求
                if ($dataStr === '[DONE]') {
                    return 0;
                }
                $data = json_decode($dataStr, true);
                if (isset($data['choices'][0]['text'])) {
                    echo $data['choices'][0]['text'];
                    // 刷出所有层级的缓冲
                    if (ob_get_level() > 0) {
                        ob_flush();
                    }
                    flush();
                }
            }
        }
        return strlen($chunk);
    });

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

openAI();
注意事项
  • 上述兼容函数str_starts_with_compatible适配PHP 8以下版本,PHP 8及以上版本可以直接使用内置str_starts_with函数替换
  • CLI命令行模式下运行不需要设置SSE相关HTTP头,仅关闭输出缓冲即可正常逐段输出
  • 在Laravel、ThinkPHP等Web框架中使用时,需要提前关闭框架自带的响应缓冲机制,否则框架会在请求逻辑全部执行完成后才统一返回内容,流式输出会失效
  • 写入回调中不要执行数据库写入、第三方接口调用等耗时操作,否则会导致流式响应卡顿中断

内容的提问来源于stack exchange,提问作者Logical Nonsense

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 19:18:22