如何在Laravel中中断OpenAI流式响应并避免Token浪费?
流式响应中途停止功能实现方案
前端JS实现
核心是利用浏览器原生的AbortController中断流式请求,搭配停止按钮触发中断操作:
// 全局存储中断控制器实例 let abortController; // 发起流式聊天请求 async function startChatStream() { abortController = new AbortController(); const signal = abortController.signal; try { const response = await fetch('/api/chat-stream', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').content }, body: JSON.stringify({ prompt: document.getElementById('user-prompt').value }), signal: signal }); const reader = response.body.getReader(); const decoder = new TextDecoder('utf-8'); const chatContent = document.getElementById('chat-content'); while (true) { const { done, value } = await reader.read(); if (done) break; // 追加流式返回的内容到聊天框 chatContent.textContent += decoder.decode(value); } } catch (error) { // 忽略主动中断的错误 if (error.name !== 'AbortError') { console.error('请求异常:', error); } } } // 绑定停止按钮事件 document.getElementById('stop-response-btn').addEventListener('click', () => { if (abortController) { abortController.abort(); abortController = null; // 更新UI状态 document.getElementById('status-indicator').textContent = '已停止响应'; } });
后端Laravel实现
需要检测客户端连接状态,一旦断开就终止OpenAI流式API调用,避免资源浪费:
use Illuminate\Http\Request; use OpenAI\Client; Route::post('/api/chat-stream', function (Request $request, Client $openai) { $prompt = $request->input('prompt'); return response()->stream(function () use ($openai, $prompt) { // 调用OpenAI流式接口 $stream = $openai->chat()->createStreamed([ 'model' => 'gpt-3.5-turbo', 'messages' => [['role' => 'user', 'content' => $prompt]], ]); foreach ($stream as $chunk) { // 检查客户端是否断开连接 if (connection_aborted()) { break; } $content = $chunk->choices[0]->delta->content ?? ''; echo $content; // 强制刷新缓冲区,确保内容实时返回前端 ob_flush(); flush(); } }, 200, [ 'Content-Type' => 'text/plain; charset=utf-8', 'Transfer-Encoding' => 'chunked', ]); });
关键注意事项
- 前端必须通过
AbortController中断请求,这是目前浏览器支持的标准中断Fetch请求的方式 - 后端通过
connection_aborted()函数检测客户端连接状态,一旦返回true立即终止循环和API调用 - 后端每次输出内容后必须调用
ob_flush()和flush(),避免内容被服务器缓冲区缓存,确保流式传输的实时性
内容的提问来源于stack exchange,提问作者Imtiaze
相关产品推荐
相关产品推荐

