NestJS集成LangChain两条路:封装库躺平 vs 手动硬撸

文章目录

      • 前言
      • [1 方案一:库封装,开箱直接躺平](#1 方案一:库封装,开箱直接躺平)
        • [1.1 先装依赖](#1.1 先装依赖)
        • [1.2 注册模块](#1.2 注册模块)
        • [1.3 服务里注入使用](#1.3 服务里注入使用)
        • [1.4 高阶玩法:工具调用一键搞定](#1.4 高阶玩法:工具调用一键搞定)
        • [1.5 优缺点唠一唠](#1.5 优缺点唠一唠)
      • [2 方案二:手动构建,一切自己说了算](#2 方案二:手动构建,一切自己说了算)
        • [2.1 装核心依赖](#2.1 装核心依赖)
        • [2.2 先建个AI模块](#2.2 先建个AI模块)
        • [2.3 核心操作:自己拼一条Chain](#2.3 核心操作:自己拼一条Chain)
        • [2.4 模块注册](#2.4 模块注册)
        • [2.5 写个接口](#2.5 写个接口)
        • [2.6 环境变量配好](#2.6 环境变量配好)
        • [2.7 每行代码干啥的,掰碎了说](#2.7 每行代码干啥的,掰碎了说)
        • [2.8 手动玩法的好坏处](#2.8 手动玩法的好坏处)
      • [3 两种方式横向对比](#3 两种方式横向对比)
      • [4 实战到底选哪个?听我一句劝](#4 实战到底选哪个?听我一句劝)
        • [4.1 选封装库,如果你](#4.1 选封装库,如果你)
        • [4.2 选手动构建,如果你](#4.2 选手动构建,如果你)
      • [5 想换阵营怎么办?](#5 想换阵营怎么办?)


P.S. 无意间发现了一个巨牛的人工智能教程,非常通俗易懂,对AI感兴趣的朋友强烈推荐去看看, 传送门https://blog.csdn.net/H1727548

前言

不知道你们刚开始把LangChain往NestJS里塞的时候,是不是都犯过选择困难症。

要么搜个第三方库一键装上,图个省事;要么硬着头皮自己手写每一步,图个踏实。

说白了就跟买电脑一个道理,有人买整机插电就用,有人买散件蹲直播间挨个比价自己装。

今天就把这两条路都给你们捋明白,看完你就知道自己该走哪条道。

1 方案一:库封装,开箱直接躺平

1.1 先装依赖

就一行npm命令的事,跟点外卖似的,你只管下单,剩下的交给npm帮你拉包。

装不上也别慌,多半是网络的锅,切个国内镜像再试,都是老演员了。

bash 复制代码
npm install nestjs-langchain langchain @langchain/openai
1.2 注册模块

在AppModule里注册一下,全局配置一次,项目里到处都能用。

就跟小区录门禁人脸似的,录一回,整个小区的门你都能刷脸进。

配置项也简单,指定用啥模型,填一下API Key,再写个系统提示词,齐活。

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的构造函数里注入LangChainService。

跟你平时注入数据库服务没啥区别,NestJS那套依赖注入该咋用咋用。

调用更简单,一个run方法传问题进去,直接拿结果。

新手第一次跑通的时候,多半都得感叹一句:原来AI集成这么简单?

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) {
    return await this.langChainService.run(question);
  }
}
1.4 高阶玩法:工具调用一键搞定

这库最香的地方,就是这个@Tool()装饰器。

你想让AI调用啥方法,就在方法头上贴个装饰器,写清楚干啥用的。

就跟公司给员工挂工牌似的,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;
  }
}

注册也省事,直接把模块丢进tools数组里,里面所有带装饰器的方法自动就被AI识别了。

typescript 复制代码
@Module({
  imports: [
    LangChainModule.register({
      model: { model: 'openai:gpt-3.5-turbo', apiKey: process.env.OPENAI_API_KEY },
      systemPrompt: '你是一个智能助手,可以使用工具来帮助用户。',
      tools: [MathModule],
    }),
    MathModule,
  ],
})
export class AppModule {}
1.5 优缺点唠一唠

好处不用多说,省事是真省事。配置集中,代码量少,跟NestJS依赖注入体系适配得特别顺。

缺点也明摆着:人家封装好啥你用啥,想搞点花活容易受限制。就跟买品牌整机似的,你想换个显卡超个频,人家壳子都给你焊死了。

而且LangChain官方更得快,第三方库跟进总得慢半拍,追新党可能会难受。

2 方案二:手动构建,一切自己说了算

要是你觉得封装库不够造,想怎么玩就怎么玩,那手动构建绝对适合你。

说白了就是不用中间商,直接跟LangChain核心包打交道。

2.1 装核心依赖

不用装第三方封装库了,就装官方的核心包。

依赖树干干净净,就像你清空了购物车,只留刚需品。

bash 复制代码
npm install @langchain/openai @langchain/core
2.2 先建个AI模块

用Nest CLI一行命令生成模块、控制器、服务。

老Nest玩家了,这步操作估计闭着眼都能敲。

bash 复制代码
nest g module ai
nest g controller ai
nest g service ai
2.3 核心操作:自己拼一条Chain

重点来了,在Service里自己把整条链路拼出来。

就跟拼奶茶似的,茶底选啥,糖度多少,加不加珍珠,全你自己定。

第一步先整个Prompt模板,留个占位符等着传问题。

第二步初始化模型,配置从ConfigService里读。别把密钥硬写代码里,不然上线就得被安全部门约谈。

第三步用pipe串起来,模板→模型→输出解析器,一条流水线就搭好了。

最后整个invoke方法对外暴露,完事。

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) {
        const prompt = PromptTemplate.fromTemplate(
            `请回答以下问题: \n\n{query}`
        );

        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'),
            },
        });

        this.chain = prompt.pipe(model).pipe(new StringOutputParser());
    }

    async runChain(query: string): Promise<string> {
        return this.chain.invoke({ query });
    }
}
2.4 模块注册

正常把服务和控制器注册进模块里就行。

没啥花里胡哨的,标准Nest模块写法。

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,写个GET接口,传query参数就能调用。

前端调一下,就能拿到AI的回答,前后端联调都省事儿。

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文件里把密钥、地址、模型名都写上。

别把密钥提交到Git!别把密钥提交到Git!别把密钥提交到Git!

重要的话说三遍,踩过坑的都懂。

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就是出题的卷子,提前把格式印好,到时候填问题就行。

ChatOpenAI就是阅卷老师,负责看题给答案。

pipe方法就是流水线传送带,把上一步的结果传给下一步。

invoke就是按下启动键,整条流水线跑起来。

ConfigService就是后勤,专门管各种配置参数,不用你到处写死。

2.8 手动玩法的好坏处

好处就是自由,极致的自由。Prompt想怎么改怎么改,多模型切换随便搞,复杂Chain随便编排。

官方更啥新特性,你当天就能用上,不用等第三方适配。依赖也干净,没有中间商赚差价。

缺点就是啥都得自己来,代码量肯定多一点。尤其是工具调用,得自己写Agent逻辑,不像封装库一个装饰器就搞定。

新手刚上手可能有点懵,得先搞懂LangChain那几个核心概念。

3 两种方式横向对比

配置复杂度:封装库简单,都集中在模块里;手动构建中等,得自己初始化。

灵活性:封装库受限于API;手动构建完全灵活,可以深度定制。

工具注册:封装库一个装饰器完事;手动构建得自己实现Agent逻辑。

学习曲线:封装库平缓,开箱即用;手动构建较陡,得懂核心概念。

依赖管理:封装库多一层第三方依赖;手动构建只依赖官方核心包。

4 实战到底选哪个?听我一句劝

别纠结,看菜下饭,看需求选方案。

4.1 选封装库,如果你

刚接触这俩玩意,想先跑通流程找找感觉。

需要AI调用各种工具,不想自己写Agent写到头秃。

业务场景不复杂,不用搞啥花里胡哨的定制。

4.2 选手动构建,如果你

对Prompt要求特别高,要动态拼接、搞条件分支各种操作。

喜欢追新,LangChain出啥新特性都想第一时间玩上。

有代码洁癖,不想项目里多一堆没必要的依赖。

以后说不定要换模型底层,想留好扩展空间。

5 想换阵营怎么办?

很简单,双向奔赴都不难,没什么技术壁垒。

从手动转封装:装库,注册模块,删掉自己写的初始化代码,换成注入服务,改调用方法就行。

从封装转手动:反过来操作一遍,把库的东西删掉,自己写初始化逻辑。

说白了就是换个写法,核心逻辑还是那套东西。

最后总结一句:封装库是买整机,插电就用,适合大多数场景;手动构建是自己装机,麻烦点,但每一块配件都合你心意。

学习可以先从封装库入门跑通流程,熟了再转手动摸透原理。真到项目里,甚至可以混着用,哪块适合用哪种就用哪种。

能解决问题的写法,就是最好的写法。

P.S. 无意间发现了一个巨牛的人工智能教程,非常通俗易懂,对AI感兴趣的朋友强烈推荐去看看,传送门https://blog.csdn.net/H1727548

相关推荐
知识分享小能手9 小时前
深度学习学习教程,从入门到精通,自编码器 — 完整知识点与代码案例(14)
人工智能·深度学习·学习
来让爷抱一个9 小时前
2026 纹理一致性实战:贴图不许花脸,百智云精灵图把材质契约写进素材包
人工智能·机器学习·材质·贴图
零依赖极客9 小时前
Day 8·1 自注意力机制:Q·K^T/softmax/V的在线计算
c语言·arm开发·人工智能·llama
幻影123!10 小时前
AlphaZero 五子棋实战(五):评估工具 —— 学会在错误的地方掉头
人工智能·机器学习·强化学习·alpha zero
jbk331110 小时前
PixiuCut「视频批量分割」支持智能镜头分割、按时长、按数量分割,可定义最小时长避免无效片段等多可选参数可设置
人工智能·音视频·剪辑软件·剪映自动化软件
诺伦10 小时前
RiseClaw玄策:GEO优化工程实战,从零搭建生成式引擎优化体系
人工智能·chatgpt
星禾元亨10 小时前
企业 AI 落地 5 步路线图:诊断、企业知识库与 GEO 获客的工程化实施步骤
大数据·人工智能·自动化·创业创新
苏打水com10 小时前
内容合规红线:大模型生成内容,哪些能做哪些会犯法?
人工智能·安全·大模型
南京兴帝文化传媒有限公司10 小时前
本地生活服务商户GEO优化技术实践:AI大模型收录机制与地图POI权重算法拆解
大数据·人工智能·算法·生活·geo优化实操·csdn运营技巧·ai内容收录