NestJS + LangChain SSE 流式输出 + 前端实时渲染打字机效果

整体流程

  1. 后端:NestJS 开启 SSE 接口 → 调用 LangChain 流式 LLM → 逐块推送到前端
  2. 前端:监听 SSE 流 → 实时拼接文字 → 实现打字机效果

一、后端实现(NestJS + LangChain + SSE)

1. 安装依赖

bash 复制代码
# Nest 核心
npm install @nestjs/common @nestjs/core @nestjs/platform-express

# LangChain
npm install langchain @langchain/openai

2. 后端 SSE 流式接口(核心代码)

src/ai/ai.controller.ts

typescript 复制代码
import { Controller, Post, Body, Sse } from '@nestjs/common';
import { Observable } from 'rxjs';
import { ChatOpenAI } from '@langchain/openai';
import { HumanMessage } from '@langchain/core/messages';

@Controller('ai')
export class AiController {
  // SSE 流式输出 AI 回答
  @Post('stream')
  @Sse('sse') // 声明这是 SSE 接口
  async streamChat(@Body() body: { message: string }) {
    const { message } = body;

    // 1. 初始化流式 LLM
    const llm = new ChatOpenAI({
      model: 'gpt-3.5-turbo',
      apiKey: '你的 OPENAI_API_KEY',
      configuration: {
      	baseURL: '你的 OPENAI_BASE_URL',
      },
    });

    // 2. from 接收流式迭代器 → map 包装成 SSE 格式
    const stream = await llm.stream([new HumanMessage(message)]);
    return from(stream).pipe(
      map((chunk) => ({
        data: chunk.content,
      }))
    );
  }
}

二、前端实现

  • 使用浏览器原生 EventSourcefetch + ReadableStream 接收 SSE,从而实现实时拼接内容 → 打字机效果
javascript 复制代码
async function chat(message) {
  const res = await fetch('http://localhost:3000/ai/stream', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ message }),
  });

  const reader = res.body.getReader();
  const decoder = new TextDecoder();
  let text = '';

  while (true) {
    const { done, value } = await reader.read();
    if (done) break;

		// 解析 SSE 流
    for (const line of decoder.decode(value).split('\n')) {
      if (!line.startsWith('data:')) continue;
      const data = line.replace('data:', '').trim();
      text += data;
      document.getElementById('result').innerText = text; // 打字机效果
    }
  }
}

三、补充:原生 EventSource

EventSource 只支持 GET,不能 POST。无需 fetch、无需解析流、无需 TextDecoder,因为 EventSource 本身就是 SSE 专用对象,最简洁。

html 复制代码
<script>
const res = document.getElementById('result');
let text = '';
// 创建 SSE 连接
const es = new EventSource('http://localhost:3000/ai/stream?message=你好');
// 接收流式消息
es.onmessage = e => {
  text += e.data;
  res.innerText = text;
};
// 结束
es.onend = () => es.close();;
// 错误
es.onerror = es.close;
</script>

四、总结

  • 后端:NestJS @Sse + LangChain stream() + RxJS Observable 推流
  • 前端:fetch 读取流 → 解析 SSE → 实时渲染打字机效果
相关推荐
runnerdancer12 分钟前
Agent如何加载执行Skill的脚本
前端·agent
yingyima33 分钟前
VS Code 正则替换技巧:从凌晨3点的服务器报警开始
前端
默_笙40 分钟前
🛬 我让 AI 帮我写了一个打飞机游戏,结果 Canvas 把我整不会了
前端·javascript
梯度不陡40 分钟前
AI 到底能不能从零写软件?ProgramBench 和 RepoZero 给出了两种答案
前端·javascript·面试
冬奇Lab1 小时前
每日一个开源项目(第137篇):Penpot - 真正开源的设计协作工具,SVG 原生格式消灭设计-开发鸿沟
前端·开源·设计
nuIl1 小时前
实现一个 Coding Agent(7):Skills
前端·agent·cursor
nuIl1 小时前
实现一个 Coding Agent(8):会话持久化与多会话
前端·agent·cursor
jt君424262 小时前
React Native JSI 深入剖析 — 第 5 部分中文技术整理:用 HostObject 把 C++ 类暴露给 JavaScript
前端·react native
胡萝卜术2 小时前
滑动窗口最大值:从暴力到单调队列,层层优化全解析
前端·javascript·面试
fluffyox2 小时前
Notion 的公式栏里,藏着一台虚拟机——逆向 + 用 600 行 JS 复刻它的编译器与栈式 VM
前端