NestJS + LangChain 集成指南:从库封装到手动构建
📌 前言
在 NestJS 中集成 LangChain,主要有两种主流方式:
- 库封装方式 :使用第三方库
nestjs-langchain,通过LangChainModule和LangChainService快速集成。 - 手动构建方式 :在 Service 中直接使用
@langchain/openai等核心包,手动组装 Chain。
两种方式各有优劣,本文将从最简单的"开箱即用"方案讲起,逐步过渡到更灵活、更可控的手动构建方案,帮助你根据项目需求做出合适的选择。
🚀 第一阶段:库封装方式(开箱即用)
1.1 安装依赖
bash
npm install nestjs-langchain langchain @langchain/openai
1.2 注册 LangChain 模块
在 AppModule 中通过 LangChainModule.register() 进行全局配置:
typescript
// app.module.ts
import { Module } from '@nestjs/common';
import { LangChainModule } from 'nestjs-langchain';
import { AiModule } from './ai/ai.module';
@Module({
imports: [
LangChainModule.register({
model: {
model: 'openai:gpt-3.5-turbo', // 指定模型
apiKey: process.env.OPENAI_API_KEY,
},
systemPrompt: 'You are a helpful assistant.',
}),
AiModule,
],
})
export class AppModule {}
1.3 在 Service 中注入使用
在任何 Service 中,都可以通过构造函数注入 LangChainService:
typescript
// ai.service.ts
import { Injectable } from '@nestjs/common';
import { LangChainService } from 'nestjs-langchain';
@Injectable()
export class AiService {
constructor(private readonly langChainService: LangChainService) {}
async askQuestion(question: string) {
// 直接调用 LangChainService 的 run 方法
return await this.langChainService.run(question);
}
}
1.4 创建 AI 工具(高级特性)
nestjs-langchain 最强大的功能之一:通过 @Tool() 装饰器将任意 Service 方法暴露为 AI 可调用的工具。
typescript
// math.service.ts
import { Injectable } from '@nestjs/common';
import { Tool, ToolParam } from 'nestjs-langchain';
@Injectable()
export class MathService {
@Tool({
description: '将两个数字相加。当用户需要进行加法计算时使用此工具。',
})
add(
@ToolParam({ name: 'a', description: '第一个加数', type: 'number' })
a: number,
@ToolParam({ name: 'b', description: '第二个加数', type: 'number' })
b: number,
): number {
return a + b;
}
}
注册工具时,只需将 MathModule 传入 tools 数组:
typescript
@Module({
imports: [
LangChainModule.register({
model: { model: 'openai:gpt-3.5-turbo', apiKey: process.env.OPENAI_API_KEY },
systemPrompt: '你是一个智能助手,可以使用工具来帮助用户。',
tools: [MathModule], // 注册 MathModule 中的所有 @Tool() 方法
}),
MathModule,
],
})
export class AppModule {}
1.5 库封装方式的优缺点
| 优点 | 缺点 |
|---|---|
| ✅ 开箱即用,配置简单,代码量少 | ❌ 受限于库提供的 API,灵活性较低 |
✅ 工具注册方便 ,@Tool() 装饰器非常优雅 |
❌ 对 LangChain 最新特性的支持可能有滞后 |
| ✅ 依赖注入体系完整,与 NestJS 深度集成 | ❌ 引入额外依赖,增加项目体积 |
🔧 第二阶段:手动构建方式(完全掌控)
当你的业务场景需要高度定制 (如自定义 Prompt 模板、多模型切换、复杂 Chain 编排)时,手动构建是更好的选择。这种方式直接使用 @langchain/openai 等核心包,在 Service 中自行组装 Chain。
2.1 安装依赖
bash
npm install @langchain/openai @langchain/core
2.2 创建 AI 模块
使用 NestJS CLI 生成模块、控制器和服务:
bash
nest g module ai
nest g controller ai
nest g service ai
2.3 手动构建 Chain(核心代码)
这是最关键的部分------在 AiService 的构造函数中手动初始化 LangChain 链。
typescript
// ai.service.ts
import { Injectable, Inject } from '@nestjs/common';
import { ChatOpenAI } from '@langchain/openai';
import { PromptTemplate } from '@langchain/core/prompts';
import { StringOutputParser } from '@langchain/core/output_parsers';
import type { Runnable } from '@langchain/core/runnables';
import { ConfigService } from '@nestjs/config';
@Injectable()
export class AiService {
// 链式调用对象
private readonly chain: Runnable;
constructor(@Inject(ConfigService) configService: ConfigService) {
// 1. 定义 Prompt 模板
const prompt = PromptTemplate.fromTemplate(
`请回答以下问题: \n\n{query}`
);
// 2. 初始化 ChatOpenAI 模型(从 ConfigService 读取配置)
const model = new ChatOpenAI({
temperature: 0.7,
modelName: configService.get('MODEL_NAME'),
apiKey: configService.get('OPENAI_API_KEY'),
configuration: {
baseURL: configService.get('OPENAI_BASE_URL'),
},
});
// 3. 组装 Chain(使用 .pipe() 方法串联)
this.chain = prompt.pipe(model).pipe(new StringOutputParser());
}
// 4. 暴露运行方法给 Controller 调用
async runChain(query: string): Promise<string> {
return this.chain.invoke({ query });
}
}
2.4 注册模块
typescript
// ai.module.ts
import { Module } from '@nestjs/common';
import { AiService } from './ai.service';
import { AiController } from './ai.controller';
@Module({
controllers: [AiController],
providers: [AiService],
})
export class AiModule {}
2.5 编写 Controller
typescript
// ai.controller.ts
import { Controller, Get, Query } from '@nestjs/common';
import { AiService } from './ai.service';
@Controller('ai')
export class AiController {
constructor(private readonly aiService: AiService) {}
@Get('chat')
async chat(@Query('query') query: string) {
const answer = await this.aiService.runChain(query);
return {
answer,
};
}
}
2.6 配置环境变量
在 .env 文件中添加必要的配置:
env
OPENAI_API_KEY=your-api-key-here
OPENAI_BASE_URL=https://api.openai.com/v1
MODEL_NAME=gpt-3.5-turbo
2.7 关键代码逐行解析
| 代码段 | 作用说明 |
|---|---|
PromptTemplate.fromTemplate() |
定义 Prompt 模板,使用 {query} 占位符 |
new ChatOpenAI({...}) |
初始化 OpenAI 模型实例,从 ConfigService 读取配置 |
prompt.pipe(model).pipe(new StringOutputParser()) |
使用 .pipe() 方法串联:模板 → 模型 → 输出解析器 |
this.chain.invoke({ query }) |
执行链式调用,传入 query 替换模板中的占位符 |
ConfigService |
NestJS 内置配置服务,从 .env 文件读取环境变量 |
2.8 手动构建方式的优缺点
| 优点 | 缺点 |
|---|---|
| ✅ 完全可控,可自由定制每个环节 | ❌ 需要手动管理 LangChain 依赖和版本 |
| ✅ 无额外依赖,只使用 LangChain 核心包 | ❌ 代码量相对较多,需要自己维护 Chain 构建逻辑 |
| ✅ 紧跟 LangChain 最新特性,不受第三方库限制 | ❌ 工具(Tool)注册需要自己实现 Agent 逻辑 |
| ✅ 易于测试,可以 Mock 具体的方法 |
📊 两种方式对比总结
| 对比维度 | 库封装方式 (nestjs-langchain) |
手动构建方式 |
|---|---|---|
| 配置复杂度 | 简单,集中在 AppModule 中 |
中等,需要自行初始化 Model 和 Chain |
| 灵活性 | 受限于库 API | 完全灵活,可以深度定制 |
| 工具注册 | ✅ @Tool() 装饰器,极其方便 |
❌ 需要手动实现 Agent 逻辑 |
| 学习曲线 | 平缓,开箱即用 | 较陡,需要理解 LangChain 核心概念 |
| 依赖管理 | 多一层 nestjs-langchain 依赖 |
只依赖 @langchain/* 核心包 |
| 适用场景 | 快速原型、标准问答、工具调用 | 复杂 Prompt 工程、多模型切换、定制 Chain |
🎯 实战建议:怎么选?
选择「库封装方式」,如果:
- 你刚开始接触 NestJS + LangChain,希望快速上手。
- 你需要让 AI 调用外部工具(如查天气、算数、查数据库),
@Tool()装饰器能大幅提升开发效率。 - 你的业务场景比较标准,不需要深度定制 Prompt 或 Chain。
选择「手动构建方式」,如果:
- 你需要精细控制 Prompt 模板(如动态拼接、条件分支)。
- 你需要使用 LangChain 最新发布的实验性特性,而
nestjs-langchain尚未支持。 - 你想保持项目依赖树尽量简洁,避免引入不必要的第三方库。
- 你希望在未来的迭代中,随时可以替换模型的底层实现。
🔄 从手动构建迁移到库封装(或反之)
如果你当前是手动构建方式(如本文的 AiService),想切换到库封装方式,只需要:
- 安装
nestjs-langchain。 - 在
AppModule中注册LangChainModule。 - 将
AiService中的@Inject(ConfigService)和 LangChain 初始化代码删除。 - 构造函数改为注入
LangChainService。 - 调用
this.langChainService.run(question)替代this.chain.invoke({ query })。
反之,如果你从库封装切换回手动构建,只需将上述步骤逆序执行即可。
🧠 总结
库封装方式是"买整机",手动构建是"自己组装电脑"。
整机(库封装)开箱即用,适合绝大多数场景;自己组装(手动构建)虽然费点功夫,但每个零件的规格都由你说了算。
作为学习路径,我建议:
- 入门阶段:先用库封装方式跑通完整流程,建立信心。
- 进阶阶段:切换到手动构建,深入理解 LangChain 的核心概念(Prompt、Model、Chain、Parser)。
- 实战阶段:根据项目实际需求,在两种方式之间灵活选择甚至混合使用。
你的 AiService 手动构建代码非常标准,已经完美掌握了第二种方式。如果需要让 AI 调用外部工具,随时可以考虑引入 nestjs-langchain 的 @Tool() 装饰器来解放双手!🚀