NestJS + LangChain 集成指南:从库封装到手动构建

NestJS + LangChain 集成指南:从库封装到手动构建

📌 前言

在 NestJS 中集成 LangChain,主要有两种主流方式:

  1. 库封装方式 :使用第三方库 nestjs-langchain,通过 LangChainModuleLangChainService 快速集成。
  2. 手动构建方式 :在 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),想切换到库封装方式,只需要:

  1. 安装 nestjs-langchain
  2. AppModule 中注册 LangChainModule
  3. AiService 中的 @Inject(ConfigService) 和 LangChain 初始化代码删除。
  4. 构造函数改为注入 LangChainService
  5. 调用 this.langChainService.run(question) 替代 this.chain.invoke({ query })

反之,如果你从库封装切换回手动构建,只需将上述步骤逆序执行即可。


🧠 总结

库封装方式是"买整机",手动构建是"自己组装电脑"。

整机(库封装)开箱即用,适合绝大多数场景;自己组装(手动构建)虽然费点功夫,但每个零件的规格都由你说了算。

作为学习路径,我建议:

  1. 入门阶段:先用库封装方式跑通完整流程,建立信心。
  2. 进阶阶段:切换到手动构建,深入理解 LangChain 的核心概念(Prompt、Model、Chain、Parser)。
  3. 实战阶段:根据项目实际需求,在两种方式之间灵活选择甚至混合使用。

你的 AiService 手动构建代码非常标准,已经完美掌握了第二种方式。如果需要让 AI 调用外部工具,随时可以考虑引入 nestjs-langchain@Tool() 装饰器来解放双手!🚀

相关推荐
草莓熊Lotso2 小时前
【Linux网络加餐】手动部署:SSH 与 Web 服务实战 + 底层原理全解析
linux·运维·网络·人工智能·python·langchain·ssh
65岁退休Coder19 小时前
LangChain v1.3.4 笔记 - 08 MCP & 相关概念
后端·python·langchain
可遇_不可求20 小时前
合集:LangChain智能体开发(四)langchain-elasticsearch
elasticsearch·langchain
前端 贾公子1 天前
第08章:中间件(8)
langchain
睡觉时不困4421 天前
15.LangChain 1.0+ 第三篇:LangSmith——给 AI 应用装上监控台.发布清单
langchain
gis分享者1 天前
LangChain 和 LlamaIndex 有什么区别?各自适合什么场景?
人工智能·ai·langchain·场景·区别·llamaindex
北斗落凡尘2 天前
LangGraph 入门实战(12)--使用MCP
后端·python·langchain
赵广陆2 天前
企业实战:Web服务端搭建
前端·langchain·langgraph
赵广陆2 天前
RAG企业实战:SSE快速入门
pycharm·langchain·langgraph