NestJS 接入 LangChain 实战:invoke、stream、batch 三种调用方式详解(完整代码)

在使用 LangChain + NestJS 构建 AI 应用时,我们通常会使用三种模型调用方式:

  • invoke:一次完整返回
  • stream:流式返回(推荐)
  • batch:批量调用

本文将从 LangChain 接入 NestJS 开始,完整讲解三种调用方式,并提供完整代码示例。


一、NestJS 接入 LangChain

在使用 LangChain 调用大模型之前,需要先在 NestJS 项目中完成 LangChain 接入。


1 安装依赖

pnpm install langchain @langchain/openai @langchain/core @nestjs/config

依赖说明:

依赖作用
langchainLangChain 主库
@langchain/coreLangChain 核心能力
@langchain/openaiChatOpenAI 模型
@nestjs/config读取 .env 配置

2 配置环境变量

在项目根目录创建 .env:

CHAT_BASE_URL=https://api.deepseek.com
CHAT_MODE_NAME=deepseek-chat
CHAT_API_KEY=your-api-key

参数说明:

参数说明
CHAT_BASE_URL模型服务地址
CHAT_MODE_NAME模型名称
CHAT_API_KEYAPI Key

⚠️ 注意:

不要把 .env 提交到仓库。

建议 .gitignore:

.env

3 NestJS 加载 .env

修改 app.module.ts:

import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { ChatModule } from './chat/chat.module';

@Module({
  imports: [
    ConfigModule.forRoot({
      isGlobal: true,
    }),
    ChatModule,
  ],
})
export class AppModule {}

作用:

  • 启动时读取 .env
  • 在代码中可以直接使用
process.env.CHAT_API_KEY

4 初始化 LangChain 模型

创建 ChatService:

import { Injectable } from '@nestjs/common';
import { ChatOpenAI } from '@langchain/openai';

@Injectable()
export class ChatService {

  private model = new ChatOpenAI({
    configuration: {
      baseURL: process.env.CHAT_BASE_URL,
    },
    apiKey: process.env.CHAT_API_KEY,
    model: process.env.CHAT_MODE_NAME,
    temperature: 0.7,
    maxTokens: 2048,
    timeout: 60000,
    maxRetries: 3
  });

}

配置说明:

参数说明
baseURL模型地址
apiKeyAPI Key
model模型名称
temperature输出随机度
maxTokens最大输出
timeout超时时间

二、invoke 调用

1 invoke 介绍

invoke 是 LangChain 最基础的调用方式。

特点:

  • 一次请求
  • 返回完整回答
  • 实现最简单

2 Service 实现

async invoke(text: string) {
  const result = await this.model.invoke(text);
  return result.content;
}

返回类型:

AIMessage

通常只需要:

result.content

3 Controller 实现

@Get(':text')
invoke(@Param('text') text: string) {
  return this.chatService.invoke(text);
}

4 请求示例

curl "http://localhost:3000/chat/你好"

返回:

"你好!有什么可以帮你?"

三、stream 流式调用

1 什么是 stream

stream 是 流式生成模式。

模型会:

逐 token 返回

用户可以实时看到输出。


2 Service 实现

async stream(text: string) {
  return this.model.stream(text);
}

返回类型:

AsyncIterable<AIMessageChunk>

3 Controller 实现

@Get('stream/:text')
async stream(@Param('text') text: string, @Res() res: Response) {

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

  const stream = await this.chatService.stream(text);

  for await (const chunk of stream) {

    if (!chunk.content) continue;

    res.write(
      `data: ${JSON.stringify({ content: chunk.content })}\n\n`
    );

  }

  res.end();
}

4 请求示例

GET /chat/stream/你好

返回:

data: {"content":"你好"}
data: {"content":"!"}
data: {"content":"有什么"}

5 前端读取

const response = await fetch('/chat/stream/你好');

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

while (true) {

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

  const chunk = decoder.decode(value);
  console.log(chunk);

}

四、batch 批量调用

1 batch 介绍

batch 用于 批量处理多个输入。

例如:

["你好","你是谁","介绍LangChain"]

2 Service 实现

async batch(texts: string) {

  const inputs = texts.split(',');

  const result = await this.model.batch(inputs);

  return {
    inputs,
    outputs: result.map(message => message.content)
  };

}

3 Controller 实现

@Get('batch/:texts')
batch(@Param('texts') texts: string) {
  return this.chatService.batch(texts);
}

4 请求示例

curl "http://localhost:3000/chat/batch/你好,你是谁"

返回:

{
  "inputs": [
    "你好",
    "你是谁"
  ],
  "outputs": [
    "你好!有什么可以帮你?",
    "我是 AI 助手"
  ]
}

五、三种调用方式对比

调用方式是否流式适合场景
invoke❌简单接口
stream✅AI聊天
batch❌批量任务

推荐:

聊天应用 → stream
简单接口 → invoke
批量任务 → batch

六、完整代码演示

chat.controller.ts

import { Controller, Get, Param, Res } from '@nestjs/common';
import { ChatService } from './chat.service';
import { Response } from 'express';

@Controller('chat')
export class ChatController {

  constructor(private readonly chatService: ChatService) {}

  @Get(':text')
  invoke(@Param('text') text: string) {
    return this.chatService.invoke(text);
  }

  @Get('stream/:text')
  async stream(@Param('text') text: string, @Res() res: Response) {

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

    const stream = await this.chatService.stream(text);

    for await (const chunk of stream) {

      if (!chunk.content) continue;

      res.write(`data: ${JSON.stringify({ content: chunk.content })}\n\n`);

    }

    res.end();
  }

  @Get('batch/:texts')
  batch(@Param('texts') texts: string) {
    return this.chatService.batch(texts);
  }

}

chat.service.ts

import { Injectable } from '@nestjs/common';
import { ChatOpenAI } from '@langchain/openai';

@Injectable()
export class ChatService {

  private model = new ChatOpenAI({
    configuration: {
      baseURL: process.env.CHAT_BASE_URL
    },
    apiKey: process.env.CHAT_API_KEY,
    model: process.env.CHAT_MODE_NAME,
    temperature: 0.7,
    maxTokens: 2048,
    timeout: 60000,
    maxRetries: 3
  });

  async invoke(text: string) {
    const result = await this.model.invoke(text);
    return result.content;
  }

  async stream(text: string) {
    return this.model.stream(text);
  }

  async batch(texts: string) {

    const inputs = texts.split(',');

    const result = await this.model.batch(inputs);

    return {
      inputs,
      outputs: result.map(message => message.content)
    };

  }

}

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐