基于 Ollama 的大模型流式响应实践

🚀 基于 Ollama 的大模型流式响应实践总结

本文记录了在本地使用 Ollama 调用大模型(如 DeepSeek)时,如何通过 Node.js 实现流式响应,并通过前端进行实时显示的实践过程与问题解决方案。 页面如下:


🧠 项目背景

我们基于 Ollama 部署本地大语言模型(如 deepseek-r1:7b),前端通过 AJAX 请求向后端发送 prompt,后端调用 Ollama 的 /api/chat 接口,采用 流式返回(stream: true) 的方式,实现模型逐词输出,提升用户体验。


🛠️ 技术栈

  • 后端:Node.js (CommonJS)
  • 模型接口:Ollama 本地 API
  • 前端:原生 JS / 任意框架(如 React)
  • 请求库:node-fetch(需注意 ESM 兼容性)
  • 数据传输协议:SSE(Server-Sent Events)

🧩 常见问题与解决

❌ 报错:require() of ES Module not supported

bash 复制代码
Error [ERR_REQUIRE_ESM]: require() of ES Module ... not supported.

原因node-fetch@3+ 是 ESM 模块,不再支持 CommonJS 的 require()

解决方案

  • 使用动态导入:const fetch = (await import('node-fetch')).default
  • 或使用 node-fetch@2(仍支持 CommonJS)

❌ 报错:response.body.getReader is not a function

该错误说明当前返回的 response.body 不是一个 ReadableStream。

排查方向

  • 确保模型接口启用了 "stream": true
  • 确保使用的是支持 ReadableStream 的 fetch(如 node-fetch@3 且为 ESM,或用原生 fetch with node >=18

✅ 后端处理方式(SSE 流式传输)

js 复制代码
app.post('/chat', async (req, res) => {
  const { prompt } = req.body;

  const response = await fetch('http://localhost:11434/api/chat', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({
      model: 'deepseek-r1:7b',
      messages: [{ role: 'user', content: prompt }],
      stream: true,
    }),
  });

  res.setHeader('Content-Type', 'text/event-stream');
  res.setHeader('Cache-Control', 'no-cache');
  res.setHeader('Connection', 'keep-alive');

  const reader = response.body.getReader();
  const decoder = new TextDecoder();

  while (true) {
    const { value, done } = await reader.read();
    if (done) {
      res.write('data: [DONE]\n\n');
      break;
    }

    const chunk = decoder.decode(value, { stream: true });
    const lines = chunk.split('\n').filter(Boolean);
    for (const line of lines) {
      try {
        const json = JSON.parse(line);
        res.write(`data: ${json.message?.content || ''}\n\n`);
      } catch (err) {
        continue;
      }
    }
  }
});

✅ 前端接收方式(SSE)

js 复制代码
const eventSource = new EventSource('/chat');

eventSource.onmessage = function (event) {
  console.log('Received:', event.data);
  if (event.data === '[DONE]') {
    eventSource.close();
  } else {
    // 追加 event.data 到聊天窗口
  }
};

🔍 模型返回示例

json 复制代码
{
  "model": "deepseek-r1:7b",
  "message": {
    "role": "assistant",
    "content": "Hello"
  },
  "done": false
}

返回为逐块数据,直到:

json 复制代码
{
  "done": true,
  "done_reason": "stop"
}

✅ 模型可用性测试(curl)

bash 复制代码
curl http://localhost:11434/api/chat \
  -X POST \
  -H "Content-Type: application/json" \
  -d '{
    "model": "deepseek-r1:7b",
    "messages": [{"role": "user", "content": "Hello"}],
    "stream": true
  }'

如出现:

json 复制代码
{"error":"model \"llama3\" not found, try pulling it first"}

请使用正确的模型名,如 deepseek-r1:7b


🎯 总结

  • 使用 Ollama 本地部署大模型是开发 LLM 应用的高效方式。
  • 使用 stream: true 可大幅提升响应体验。
  • 后端使用 SSE 向前端推送数据是简单高效的方式。
  • 需注意 CommonJS 与 ESM 模块的兼容问题。

以实际的代码为准,欢迎交流探讨


🧑‍💻 作者:byteLee

📅 时间:2025 年

📁 项目地址:(https://gitee.com/yadalihongye/local-ds-chat)

相关推荐
AC赳赳老秦7 小时前
DeepSeek 私有化部署避坑指南:敏感数据本地化处理与合规性检测详解
大数据·开发语言·数据库·人工智能·自动化·php·deepseek
AC赳赳老秦20 小时前
Unity游戏开发实战指南:核心逻辑与场景构建详解
开发语言·spring boot·爬虫·搜索引擎·全文检索·lucene·deepseek
且去填词21 小时前
DeepSeek-R1 实战:数据分析
人工智能·python·mysql·语言模型·deepseek·structured data
且去填词1 天前
DeepSeek API 深度解析:从流式输出、Function Calling 到构建拥有“手脚”的 AI 应用
人工智能·python·语言模型·llm·agent·deepseek
AC赳赳老秦2 天前
Shell 脚本批量生成:DeepSeek 辅助编写服务器运维自动化指令
运维·服务器·前端·vue.js·数据分析·自动化·deepseek
AC赳赳老秦2 天前
量化交易脚本开发:DeepSeek生成技术指标计算与信号触发代码
数据库·elasticsearch·信息可视化·流程图·数据库架构·memcached·deepseek
AC赳赳老秦2 天前
Python 爬虫进阶:DeepSeek 优化反爬策略与动态数据解析逻辑
开发语言·hadoop·spring boot·爬虫·python·postgresql·deepseek
Java后端的Ai之路2 天前
【大模型技术栈】-Qwen与DeepSeek如何构建智能大脑?
大模型·qwen·deepseek
AC赳赳老秦3 天前
Go语言微服务文档自动化生成:基于DeepSeek的智能解析实践
大数据·开发语言·人工智能·微服务·golang·自动化·deepseek
AC赳赳老秦4 天前
前端可视化组件开发:DeepSeek辅助Vue/React图表组件编写实战
前端·vue.js·人工智能·react.js·信息可视化·数据分析·deepseek