You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过NestJS的SSE将LangChain流式响应转发至前端?

解决方案

你的问题在于直接使用@Res()手动写入响应,没有遵循NestJS SSE的规范。NestJS的@Sse()装饰器要求方法返回Server-Sent Event格式的数据流,而非直接操作响应对象。以下是修正后的实现方案:

核心修改点

  • 移除@Res()注入,让NestJS自动处理SSE响应
  • 返回符合SSE规范的数据流(支持Observable或异步迭代器)
  • 在LangChain的回调中按SSE格式发送每个token

实现代码(Observable方式)

import { Observable, Subject } from 'rxjs';
import { Sse, ServerSentEvent } from '@nestjs/common';
import { CreateChatRequestDto } from './dto/create-chat-request.dto';

@Sse('sse')
createChat(
  @Body() createChatRequestDto: CreateChatRequestDto,
): Observable<ServerSentEvent<string>> {
  const subject = new Subject<ServerSentEvent<string>>();

  (async () => {
    try {
      const { chain, sanitizedQuestion, histories } = await this.chatService.createChat(createChatRequestDto);

      await chain.call(
        {
          question: sanitizedQuestion,
          chat_history: histories || [],
        },
        [
          {
            handleLLMNewToken(token: string) {
              // 按SSE规范发送数据,每个消息以data字段包裹
              subject.next({ data: token });
            },
            handleLLMEnd() {
              // 流结束时完成Subject
              subject.complete();
            },
            handleLLMError(error: Error) {
              // 错误时发送错误信息并结束
              subject.error(error);
            },
          },
        ],
      );
    } catch (error) {
      subject.error(error);
    }
  })();

  return subject.asObservable();
}

实现代码(异步迭代器方式)

如果你更倾向于使用异步迭代器(更贴合Node.js流式风格),可以这样写:

import { Sse, ServerSentEvent } from '@nestjs/common';
import { CreateChatRequestDto } from './dto/create-chat-request.dto';

@Sse('sse')
async *createChat(
  @Body() createChatRequestDto: CreateChatRequestDto,
): AsyncGenerator<ServerSentEvent<string>> {
  const { chain, sanitizedQuestion, histories } = await this.chatService.createChat(createChatRequestDto);

  // 创建一个Promise用于等待流式完成
  await new Promise((resolve, reject) => {
    chain.call(
      {
        question: sanitizedQuestion,
        chat_history: histories || [],
      },
      [
        {
          handleLLMNewToken: (token: string) => {
            // 通过yield发送每个SSE消息
            yield { data: token };
          },
          handleLLMEnd: () => {
            resolve(null);
          },
          handleLLMError: (error: Error) => {
            reject(error);
          },
        },
      ],
    );
  });
}

关键说明

  1. SSE格式要求:每个消息必须以data: [内容]\n\n格式发送,NestJS的ServerSentEvent会自动帮你处理这个格式转换。
  2. 流的生命周期:必须在流式结束(handleLLMEnd)或出错(handleLLMError)时结束数据流,避免前端连接一直挂起。
  3. HTTP方法注意:SSE通常使用GET请求(因为是客户端主动拉取流),如果你坚持用POST,需要确保前端请求时设置正确的Accept: text/event-stream头。

内容的提问来源于stack exchange,提问作者정주호

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 08:43:27