基于 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)

相关推荐
奔跑吧邓邓子4 小时前
DeepSeek 赋能智能零售,解锁动态定价新范式
人工智能·动态定价·智能零售·deepseek
bin915311 小时前
DeepSeek 助力 Vue3 开发:打造丝滑的日历(Calendar),日历_天气预报日历示例(CalendarView01_18)
前端·javascript·vue.js·ecmascript·deepseek
橙某人1 天前
🤝和Ollama贴贴!解锁本地大模型的「私人订制」狂欢🎉
前端·deepseek
奔跑吧邓邓子1 天前
DeepSeek 赋能金融衍生品:定价与风险管理的智能革命
人工智能·金融衍生品·deepseek·金融市场·定价与风险管理
hresh1 天前
通辽宇宙知识库:从洗澡灵感到AI协作开发的全流程实践
aigc·ai编程·deepseek
道可云2 天前
道可云人工智能每日资讯|北京农业人工智能与机器人研究院揭牌
人工智能·机器人·ar·deepseek
webmote332 天前
DeepSeek私域数据训练之封装Anything LLM的API 【net 9】
.net·api·deepseek
小虚竹2 天前
1.6万字测评:deepseek-r1-0528横向对比 gemini-2.5-pro-0506和claude4
claude·gemini·deepseek
程序员海军2 天前
从懵懂到落地:记录我们第一次成功将大模型“塞”进业务的曲折历程
前端·后端·deepseek