前端转AI第一章--接入langchain
·
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
依赖说明:
| 依赖 | 作用 |
|---|---|
| langchain | LangChain 主库 |
| @langchain/core | LangChain 核心能力 |
| @langchain/openai | ChatOpenAI 模型 |
| @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_KEY | API 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 | 模型地址 |
| apiKey | API 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)
};
}
}
更多推荐

所有评论(0)