Laravel项目中AWS Lambda实现OpenAI流式响应失败求助
Laravel部署AWS Lambda后OpenAI流式响应失效的排查与修复
问题背景
在Laravel项目中尝试用AWS Lambda实现OpenAI流式响应,本地运行正常,但部署到Lambda后失效。已配置Lambda函数URL的CORS头部,问题仍存在。相关代码及配置如下:
适配AWS环境的代码
return response()->stream(function () use ($prompt) { if (ob_get_level() > 0) { ob_end_flush(); } header('Lambda-Runtime-Function-Response-Mode: streaming'); header('Transfer-Encoding: chunked'); $stream = OpenAI::chat()->createStreamed([ 'model' => 'gpt-3.5-turbo', 'messages' => $prompt['messages'], 'presence_penalty' => 0.6, 'frequency_penalty' => 0 ]); foreach ($stream as $response) { if (isset($response['choices'][0]['delta']['content'])) { $message = $response['choices'][0]['delta']['content']; $messageFix = str_replace(["\n", "\r", "\r\n"], "<br/>", $message); echo dechex(strlen($messageFix)) . "\n"; echo $messageFix . "\n"; if (ob_get_level() > 0) { ob_flush(); flush(); } usleep(5000); } if (connection_aborted()) { break; } } echo "0\n\n"; if (ob_get_level() > 0) { ob_flush(); flush(); } }, 200, [ 'Cache-Control' => 'no-cache', 'X-Accel-Buffering' => 'no', 'Content-Type' => 'text/event-stream', ]);
本地运行正常的旧代码
return response()->stream(function () use ($prompt) { $stream = OpenAI::chat()->createStreamed([ 'model' => 'gpt-3.5-turbo', 'messages' => $prompt['messages'], 'presence_penalty' => 0.6, 'frequency_penalty' => 0 ]); $output = ""; $responsedText = ""; foreach ($stream as $response){ if (isset($response['choices'][0]['delta']['content'])){ $message = $response['choices'][0]['delta']['content']; $messageFix = str_replace(["\n", "\r", "\r\n"], "<br/>", $message); $output .= $messageFix; $responsedText .= $message; $string_length = Str::length($messageFix); $needChars = 6000-$string_length; $random_text = Str::random($needChars); echo PHP_EOL; echo 'data: ' . $messageFix.'/**'.$random_text."\n\n"; ob_flush(); flush(); usleep(5000); } if (connection_aborted()) { break; } } echo 'data: [DONE]'; echo "\n\n"; ob_flush(); flush(); usleep(50000); }, 200, [ 'Cache-Control' => 'no-cache', 'X-Accel-Buffering' => 'no', 'Content-Type' => 'text/event-stream', ]);
CORS配置
- 暴露头部:content-type, connection, cache-control
- 允许头部:content-type, connection, cache-control, x-custom-header
解决方案
1. 调整Lambda流式响应头部设置方式
不要在stream回调中手动调用header()添加Lambda-Runtime-Function-Response-Mode,Laravel的response()->stream()会统一处理响应头部,手动添加可能被覆盖或不生效。直接将该头部移到响应的头部数组中。
2. 移除手动设置的Transfer-Encoding头部
Lambda流式响应会自动处理分块编码,手动设置Transfer-Encoding: chunked会导致格式冲突,直接移除即可。
3. 修正分块输出的换行符规范
HTTP分块编码要求用\r\n(CRLF)作为分隔符,原代码中的换行符不符合规范,会导致Lambda无法正确识别分块。
4. 保持SSE格式输出(匹配前端解析逻辑)
本地代码输出的是SSE格式(data: ...\n\n),适配Lambda的代码改成了直接分块输出内容,前端无法解析。需要保持SSE格式的输出,同时适配Lambda的流式要求。
修改后的代码示例
return response()->stream(function () use ($prompt) { // 彻底关闭所有输出缓冲 while (ob_get_level() > 0) { ob_end_flush(); } $stream = OpenAI::chat()->createStreamed([ 'model' => 'gpt-3.5-turbo', 'messages' => $prompt['messages'], 'presence_penalty' => 0.6, 'frequency_penalty' => 0 ]); foreach ($stream as $response) { if (isset($response['choices'][0]['delta']['content'])) { $message = $response['choices'][0]['delta']['content']; $messageFix = str_replace(["\n", "\r", "\r\n"], "<br/>", $message); // 构造符合SSE规范的输出内容 $sseData = "data: {$messageFix}\n\n"; // 按照Lambda流式要求输出分块:十六进制长度 + CRLF + 内容 + CRLF echo dechex(strlen($sseData)) . "\r\n"; echo $sseData . "\r\n"; ob_flush(); flush(); usleep(5000); } if (connection_aborted()) { break; } } // 输出结束分块,标志流式响应完成 echo "0\r\n\r\n"; ob_flush(); flush(); }, 200, [ 'Cache-Control' => 'no-cache', 'X-Accel-Buffering' => 'no', 'Content-Type' => 'text/event-stream', 'Lambda-Runtime-Function-Response-Mode' => 'streaming' ]);
额外排查点
- Lambda网络权限:确认Lambda函数的执行角色有访问OpenAI API的权限,若部署在私有子网需配置NAT网关确保互联网访问。
- CORS配置验证:检查Lambda函数URL的CORS设置是否允许
text/event-stream类型的请求,同时确认暴露的头部包含Content-Type和Cache-Control。 - OpenAI客户端适配:验证OpenAI SDK在Lambda环境下能正确处理流式响应,必要时调整客户端超时时间或代理配置。
内容的提问来源于stack exchange,提问作者Thomas Chirwa
相关产品推荐
相关产品推荐

