PHP 8.0 可通过 HTTP 流式请求调用 Mistral API 实现实时输出,需启用 chunked 解析、适配 SSE 或 JSON Lines 格式,并配合前端 EventSource 或流读取实现“打字机”效果。

PHP 8.0 本身不能直接运行 Mistral 模型(它是基于 PyTorch 的本地大模型),但可以通过调用 Mistral 提供的 API 接口(如 Ollama、OpenRouter、Together AI 或自部署的 vLLM/Llama.cpp API)实现流式输出。关键在于:PHP 发起 HTTP 请求时启用 chunked 响应解析,逐段读取 SSE(Server-Sent Events)或换行分隔的 JSON 流。
确认 Mistral 服务支持流式接口
不是所有 Mistral 接口都默认开启流式。需确保后端服务满足以下条件:
- 使用 Ollama:调用
/api/chat时传"stream": true - 使用 vLLM:调用
/v1/chat/completions同样需设"stream": true - 使用 OpenRouter:Header 中添加
HTTP-Header: "HTTP_ACCEPT": "text/event-stream",且请求体含"stream": true - 响应 Content-Type 应为
text/event-stream或application/json(流式 JSON Lines)
PHP 8.0 使用 cURL 实现流式读取
禁用 cURL 缓冲、设置低超时、逐行解析响应流。示例代码片段(对接 Ollama):
将小说章节转换为电影分镜剧本。用户上传txt/md/docx文本,AI分析场景、角色、情绪、镜头语言,输出专业分镜脚本。适用于用户提及“分镜”“storyboard”“小说转分镜”“影视改编”“镜头脚本”或需要将小说改编为分镜的场景。
$url = 'http://localhost:11434/api/chat';
$data = json_encode([
'model' => 'mistral',
'messages' => [['role' => 'user', 'content' => '你好']],
'stream' => true
]);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, false); // 关键:不缓存响应体
curl_setopt($ch, CURLOPT_HEADER, false);
curl_setopt($ch, CURLOPT_WRITEFUNCTION, function($ch, $data) {
// 过滤空行和 event/comment 字段,提取 data: 后的 JSON
if (str_starts_with($data, "data: ")) {
$json = trim(substr($data, 6));
if (!empty($json) && $json !== '[DONE]') {
$chunk = json_decode($json, true);
if (isset($chunk['message']['content'])) {
echo $chunk['message']['content']; // 实时输出文本
ob_flush();
flush();
}
}
}
return strlen($data);
});
curl_exec($ch);
curl_close($ch);
处理常见流式格式差异
不同服务返回格式略有不同,PHP 需灵活适配:
立即学习“PHP免费学习笔记(深入)”;
-
SSE 格式(Ollama / OpenRouter):每行以
data: {...}开头,可能夹杂event: message或注释: - JSON Lines 格式(vLLM 默认):每行一个完整 JSON 对象,无前缀,需按换行切分
- 建议统一用
fgets()或stream_get_line()替代大块curl_exec,避免内存堆积 - 务必检查
json_last_error(),跳过非法 JSON 行(如心跳、空行、[DONE])
前端配合实现“打字机”效果
PHP 流式输出只是后端一环。要让浏览器实时显示,需配合前端:
- PHP 输出时保持
Content-Type: text/plain; charset=utf-8或text/event-stream - 禁用 PHP 输出缓冲:
ob_end_flush(); ob_implicit_flush(true); - 前端用
fetch().then(res => res.body.getReader())或EventSource接收流 - 避免使用
file_get_contents()或简单echo—— 它们会等全部响应结束才输出


















