多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

TypeScript工程化实战:从零搭建NestJS与LangChain驱动的AI应用

TypeScript工程化实战:从零搭建NestJS与LangChain驱动的AI应用 1. 从“Hello, World”到“Hello, AI”为什么你的第一个TypeScript项目应该从这里开始如果你刚接触TypeScript或者已经用它写过一些简单的脚本现在想用它来构建一个真正能跑起来的、有点“智能”的应用那么恭喜你这个起点选对了。很多人学TypeScript止步于配置tsconfig.json或者跟着教程写几个接口和类然后就不知道下一步该做什么了。这就像学开车只学会了打火和挂挡却从来没上过路。今天我们不谈那些枯燥的语法细节直接上手一个实战目标搭建一个能调用AI能力的TypeScript工程。为什么是AI因为它足够“性感”能立刻让你看到代码的产出价值而不是停留在控制台打印“Hello, World”。我们将以NestJS作为后端框架LangChain.js作为AI应用层构建一个结构清晰、配置可维护的现代Node.js项目。这不仅仅是初始化一个项目更是理解一个现代TypeScript工程如何组织、如何配置、如何为后续的复杂功能比如服务间通讯、复杂的构建流程打下坚实基础。你会发现一个合理的工程初始化能帮你避开未来80%的配置坑。比如如何处理TypeScript 7.0中即将废弃的baseUrl选项如何让VSCode完美支持你的项目包括VueTypeScript的格式化如何配置Vite使其能正确解析TypeScript装饰器这些看似琐碎的问题恰恰是项目能否顺畅跑起来的关键。我们这就开始手把手带你走通从零到一的完整链路。2. 工程基石项目初始化与核心依赖选型在动手敲代码之前我们需要先搭好舞台。这个阶段的目标是创建一个干净、标准、可扩展的项目骨架。很多教程会直接让你npm init -y然后装一堆包但我们得先想清楚为什么这么选。2.1 创建项目与包管理器的选择首先创建一个新的项目目录并初始化。我个人强烈推荐使用pnpm作为包管理器它比npm和yarn更快采用硬链接节省磁盘空间并且能严格处理依赖关系避免“幽灵依赖”问题。如果你的环境还没有pnpm可以先用npm安装npm install -g pnpm。mkdir my-ai-project cd my-ai-project pnpm init执行pnpm init后会生成一个package.json文件。我们立刻对它进行一些关键修改{ name: my-ai-project, version: 0.1.0, description: A TypeScript project for AI application with NestJS LangChain, private: true, type: module, scripts: { build: nest build, start: nest start, start:dev: nest start --watch, start:debug: nest start --debug --watch, start:prod: node dist/main, lint: eslint \{src,test,libs}/**/*.ts\, lint:fix: eslint \{src,test,libs}/**/*.ts\ --fix, format: prettier --write \src/**/*.ts\ \test/**/*.ts\, test: jest, test:watch: jest --watch, test:cov: jest --coverage }, engines: { node: 18.0.0 } }关键点解析private: true防止误发布到公共npm仓库。type: module声明使用ES模块规范。这是现代Node.js项目的趋势能更好地支持顶级await等特性并与前端生态如Vite对齐。NestJS从v10开始也原生支持ESM。scripts预先定义好从开发到构建、测试、代码规范的完整工作流脚本。使用Nest CLI的命令能保证一致性。engines锁定Node.js版本确保团队环境一致。AI相关的库如LangChain通常对较新的Node版本有更好支持。2.2 核心框架与库的安装接下来安装项目的核心依赖。我们将采用分层安装的方式让你清楚每个包的作用。# 1. 安装NestJS核心及相关CLI工具 pnpm add nestjs/common nestjs/core nestjs/platform-express reflect-metadata rxjs pnpm add -D nestjs/cli nestjs/schematics nestjs/testing # 2. 安装TypeScript及Node.js类型定义 pnpm add -D typescript types/node ts-node tsconfig-paths # 3. 安装LangChain.js核心 (以OpenAI为例) pnpm add langchain langchain/openai # 4. 安装开发工具链代码规范、格式化、测试 pnpm add -D eslint eslint-config-prettier eslint-plugin-prettier prettier pnpm add -D jest types/jest ts-jest pnpm add -D husky lint-staged为什么是这些库NestJS不是一个简单的HTTP库而是一个开箱即用、架构清晰的渐进式Node.js框架。它采用依赖注入、模块化设计非常适合构建中大型、可维护的后端应用。用它来承载AI能力调用能让业务逻辑和AI调用逻辑解耦得更好。LangChain.js它是构建AI应用的事实标准库。它抽象了与不同AI模型OpenAI、Anthropic等的交互提供了链Chains、代理Agents、记忆Memory等高级抽象让你能专注于应用逻辑而不是底层的API调用细节。直接安装langchain/openai这个集成包比只安装核心包更方便。ESLint Prettier保证代码风格一致性的“黄金搭档”。ESLint负责检查代码质量问题Prettier负责自动格式化。分开配置它们然后让Prettier作为ESLint的规则来运行可以避免冲突。Husky lint-staged在Git提交前自动运行代码检查和格式化确保进入仓库的代码都是干净的。这是保障团队协作代码质量的利器。注意安装reflect-metadata是必须的因为NestJS和TypeScript装饰器依赖它来存储和读取元数据。rxjs是NestJS内部处理异步流如拦截器、守卫时使用的库。3. 配置的艺术从TypeScript到代码规范配置文件的堆叠常常让人头疼但每份文件都有其明确的职责。理解它们之间的关系比死记硬背配置项更重要。3.1 TypeScript配置 (tsconfig.json)这是TypeScript项目的核心。我们不用Nest CLI生成的默认配置而是手动创建一个更清晰、适应现代ESM模块的配置。在项目根目录创建tsconfig.json{ compilerOptions: { module: NodeNext, moduleResolution: NodeNext, target: ES2022, lib: [ES2023], outDir: ./dist, rootDir: ./src, strict: true, esModuleInterop: true, skipLibCheck: true, forceConsistentCasingInFileNames: true, declaration: true, removeComments: true, emitDecoratorMetadata: true, experimentalDecorators: true, allowSyntheticDefaultImports: true, sourceMap: true, incremental: true, resolveJsonModule: true }, include: [src/**/*], exclude: [node_modules, dist, test, **/*.spec.ts] }关键配置深度解读module: NodeNext与moduleResolution: NodeNext这是面向未来的配置。它告诉TypeScript使用Node.js最新的ES模块解析策略。当你在package.json中设置了type: module后这组配置能确保.ts文件被编译为.mjs或与ESM兼容的.js文件并且导入语句import能正确工作。这是替代旧版baseUrl和paths方案的重要一步。关于“baseUrl”弃用你可能会在旧项目或网上看到baseUrl和paths用于配置路径别名。在TypeScript 7.0中baseUrl将被弃用。新的最佳实践是使用moduleResolution: NodeNext或Bundler并结合打包器如Vite、Webpack或运行时加载器如tsconfig-paths来处理路径映射。在我们的NestJS项目中使用tsconfig-paths配合ts-node在开发时就能很好地工作无需依赖即将废弃的baseUrl。target: ES2022和lib: [ES2023]将编译目标设定为较新的ECMAScript版本可以获得更优的运行时性能和更简洁的编译输出。lib包含了类型定义设置成比target更新的版本通常没问题能让你使用最新的语言特性类型。emitDecoratorMetadata: true必须为true。这是NestJS装饰器如Injectable(),Controller()能够正常工作的基石编译器会为装饰器生成额外的元数据信息。incremental: true启用增量编译。TypeScript会缓存上一次编译的信息下次编译时只重新编译改变的文件极大提升大型项目的编译速度。3.2 ESLint配置 (.eslintrc.js)ESLint的配置我们采用JavaScript文件因为它更灵活。创建.eslintrc.jsmodule.exports { parser: typescript-eslint/parser, parserOptions: { project: tsconfig.json, tsconfigRootDir: __dirname, sourceType: module, }, plugins: [typescript-eslint/eslint-plugin], extends: [ plugin:typescript-eslint/recommended, plugin:prettier/recommended, // 必须放在最后用Prettier的规则覆盖代码格式规则 ], root: true, env: { node: true, jest: true, }, ignorePatterns: [.eslintrc.js, dist], rules: { typescript-eslint/interface-name-prefix: off, typescript-eslint/explicit-function-return-type: off, typescript-eslint/explicit-module-boundary-types: off, typescript-eslint/no-explicit-any: warn, // 将any警告而非报错开发初期更友好 typescript-eslint/no-unused-vars: [error, { argsIgnorePattern: ^_ }], // 忽略以下划线开头的未使用参数 }, };配置逻辑我们使用typescript-eslint插件来解析TS代码。extends中plugin:prettier/recommended这个扩展项做了三件事1. 启用eslint-plugin-prettier2. 设置prettier/prettier规则为error3. 关闭所有与Prettier冲突的ESLint规则。这样当你运行eslint --fix时它会自动调用Prettier进行格式化。3.3 Prettier配置 (.prettierrc)Prettier的配置很简单一个JSON文件定义你喜欢的代码风格即可。创建.prettierrc{ singleQuote: true, trailingComma: es5, printWidth: 100, tabWidth: 2, semi: true, bracketSpacing: true, arrowParens: always }3.4 Git提交钩子配置利用Husky和lint-staged我们可以实现提交前的自动检查。首先初始化Huskynpx husky init pnpm pkg set scripts.preparehusky install然后编辑自动生成的.husky/pre-commit文件#!/usr/bin/env sh . $(dirname -- $0)/_/husky.sh npx lint-staged接着在package.json中配置lint-staged{ ... // 其他配置 lint-staged: { src/**/*.ts: [ eslint --fix, prettier --write ] } }这样每次你执行git commit时Husky会触发lint-staged后者只对你本次提交所更改的src目录下的TypeScript文件运行ESLint修复和Prettier格式化。这是一个非常高效的代码质量守护流程。4. 构建项目骨架NestJS模块与第一个AI服务配置完成后我们开始构建真正的代码。NestJS采用模块化架构我们将创建一个核心模块来管理AI功能。4.1 生成项目结构使用Nest CLI可以快速生成标准结构。如果你全局安装了nestjs/cli可以直接使用nest命令。但我们更推荐使用项目内安装的CLI通过pnpm脚本来调用保证环境一致。# 使用项目内的nest命令生成应用骨架 pnpm exec nest new . --skip-git --package-manager pnpm # 如果提示是否覆盖文件选择否N因为我们已手动创建了部分配置。 # 或者更安全的方式是手动创建src目录和核心文件。我们选择手动创建以加深理解。创建以下目录和文件src/ ├── app.module.ts ├── main.ts ├── ai/ │ ├── ai.module.ts │ ├── ai.service.ts │ ├── ai.controller.ts │ └── dto/ │ └── ask-ai.dto.ts4.2 实现AI服务层 (ai.service.ts)服务层是业务逻辑的核心。在这里我们将集成LangChain来调用OpenAI。首先你需要一个OpenAI的API密钥。可以去OpenAI官网注册获取。切记永远不要将API密钥硬编码在代码中或提交到版本库。我们在项目根目录创建.env文件并把它加入.gitignoreOPENAI_API_KEYsk-your-actual-api-key-here OPENAI_BASE_URLhttps://api.openai.com/v1 # 如果你使用代理或特定端点可以修改此项然后安装管理环境变量的库pnpm add nestjs/config现在实现AiService// src/ai/ai.service.ts import { Injectable, Logger } from nestjs/common; import { ConfigService } from nestjs/config; import { ChatOpenAI } from langchain/openai; import { StringOutputParser } from langchain/core/output_parsers; import { PromptTemplate } from langchain/core/prompts; Injectable() export class AiService { private readonly logger new Logger(AiService.name); private chatModel: ChatOpenAI; constructor(private configService: ConfigService) { // 安全地从环境变量获取配置 const apiKey this.configService.getstring(OPENAI_API_KEY); const baseURL this.configService.getstring(OPENAI_BASE_URL); if (!apiKey) { this.logger.warn(OPENAI_API_KEY is not set in environment variables.); // 在生产环境中这里应该抛出错误或采用更优雅的降级策略 } this.chatModel new ChatOpenAI({ openAIApiKey: apiKey, configuration: { baseURL: baseURL, }, modelName: gpt-3.5-turbo, // 可根据需要切换模型如 gpt-4 temperature: 0.7, // 控制创造性0-1之间越高越随机 maxTokens: 500, // 限制响应长度 verbose: true, // 开发时开启可以看到LangChain的详细调用日志 }); } /** * 一个简单的问答方法 * param question 用户的问题 * returns AI的回复 */ async askSimpleQuestion(question: string): Promisestring { try { const outputParser new StringOutputParser(); // 使用PromptTemplate来构造更结构化的提示词 const prompt PromptTemplate.fromTemplate(你是一个乐于助人的助手。请用中文回答以下问题。 问题{question} 回答); // 创建链prompt - model - outputParser const chain prompt.pipe(this.chatModel).pipe(outputParser); const response await chain.invoke({ question }); return response; } catch (error) { this.logger.error(Failed to get AI response: ${error.message}, error.stack); throw new Error(AI service temporarily unavailable: ${error.message}); } } /** * 一个更复杂的示例使用系统消息和对话历史简化版 * param messages 消息数组包含角色和内容 */ async chatWithHistory(messages: Array{ role: user | assistant | system; content: string }) { // LangChain的ChatOpenAI可以直接接受消息格式 // 这里展示另一种方式实际可根据LangChain的AIMessage, HumanMessage等封装 // 为简化示例我们直接调用底层API风格 const response await this.chatModel.invoke(messages); return response.content; } }代码要点与避坑指南依赖注入通过Injectable()装饰器AiService成为一个可注入的提供者。ConfigService由nestjs/config模块提供用于安全读取环境变量。初始化时机在构造函数中初始化ChatOpenAI客户端。确保在服务实例化时配置就已就绪。如果API_KEY为空在生产环境应抛出错误阻止应用启动。错误处理用try...catch包裹AI调用。网络波动、API限额、模型错误都可能抛出异常。记录详细的错误日志至关重要同时向客户端返回友好的错误信息避免泄露内部细节。Prompt工程这里使用了PromptTemplate。将用户问题嵌入到固定的提示模板中能获得更稳定、符合预期的回答。这是AI应用开发中的关键技巧。链Chainprompt.pipe(model).pipe(outputParser)是LangChain的核心抽象。它清晰地定义了数据处理流程输入经过提示词模板格式化送入模型最后解析输出。这种组合方式非常灵活。4.3 创建数据传输对象与控制器接下来定义API接口的数据结构和控制器。// src/ai/dto/ask-ai.dto.ts import { IsString, MaxLength, MinLength } from class-validator; export class AskAiDto { IsString() MinLength(1, { message: 问题不能为空 }) MaxLength(1000, { message: 问题过长 }) question: string; }我们使用class-validator进行输入验证。安装它pnpm add class-validator class-transformer。然后实现控制器// src/ai/ai.controller.ts import { Body, Controller, HttpCode, HttpStatus, Post } from nestjs/common; import { AiService } from ./ai.service; import { AskAiDto } from ./dto/ask-ai.dto; Controller(ai) export class AiController { constructor(private readonly aiService: AiService) {} Post(ask) HttpCode(HttpStatus.OK) async askQuestion(Body() askAiDto: AskAiDto) { const answer await this.aiService.askSimpleQuestion(askAiDto.question); return { success: true, data: { answer }, message: Success, }; } }4.4 组装AI模块与主模块将服务、控制器等组装成模块。// src/ai/ai.module.ts import { Module } from nestjs/common; import { AiService } from ./ai.service; import { AiController } from ./ai.controller; import { ConfigModule } from nestjs/config; Module({ imports: [ConfigModule], // 导入ConfigModule以在AiService中注入ConfigService controllers: [AiController], providers: [AiService], exports: [AiService], // 如果其他模块也需要使用AiService则导出它 }) export class AiModule {}最后在主应用模块中导入AiModule。// src/app.module.ts import { Module } from nestjs/common; import { ConfigModule } from nestjs/config; import { AiModule } from ./ai/ai.module; Module({ imports: [ ConfigModule.forRoot({ isGlobal: true, // 使ConfigService全局可用无需在每个模块中重复导入 envFilePath: .env, // 指定环境变量文件路径 }), AiModule, ], }) export class AppModule {}// src/main.ts import { NestFactory } from nestjs/core; import { AppModule } from ./app.module; import { ValidationPipe } from nestjs/common; async function bootstrap() { const app await NestFactory.create(AppModule); // 全局启用验证管道自动校验使用class-validator装饰器的DTO app.useGlobalPipes(new ValidationPipe({ whitelist: true, // 自动剥离DTO中未定义的属性 forbidNonWhitelisted: true, // 如果请求包含未定义的属性则抛出错误 transform: true, // 自动将请求负载转换为DTO类的实例 })); await app.listen(process.env.PORT ?? 3000); console.log(Application is running on: ${await app.getUrl()}); } bootstrap();5. 开发、调试与构建让项目跑起来至此一个具备基础AI调用能力的后端服务就搭建完成了。现在让我们启动它并测试。5.1 运行与测试首先确保你的.env文件已配置好OPENAI_API_KEY。开发模式运行监听文件变化热重载pnpm start:devNest CLI会启动开发服务器。你应该看到控制台输出应用运行的URL通常是http://localhost:3000。测试API接口使用你喜欢的API测试工具如Postman、cURL或VSCode的REST Client插件。请求POST http://localhost:3000/ai/askBody (JSON){ question: 用TypeScript写一个简单的Hello World函数 }预期响应{ success: true, data: { answer: 当然这是一个简单的TypeScript Hello World函数示例\n\ntypescript\nfunction sayHello(name: string): string {\n return Hello, ${name}!;\n}\n\nconst greeting sayHello(\World\);\nconsole.log(greeting); // 输出: Hello, World!\n\n\n这个函数接收一个字符串参数name并返回一个拼接好的问候语。 }, message: Success }5.2 VSCode开发体验优化为了让开发更顺畅我们需要配置VSCode。1. 工作区推荐扩展 (.vscode/extensions.json):{ recommendations: [ dbaeumer.vscode-eslint, esbenp.prettier-vscode, ms-vscode.vscode-typescript-next, firsttris.vscode-jest-runner ] }2. 工作区设置 (.vscode/settings.json):{ editor.formatOnSave: true, editor.codeActionsOnSave: { source.fixAll.eslint: explicit }, editor.defaultFormatter: esbenp.prettier-vscode, typescript.preferences.importModuleSpecifier: relative, typescript.updateImportsOnFileMove.enabled: always, [typescript]: { editor.defaultFormatter: esbenp.prettier-vscode }, files.exclude: { **/node_modules: true, **/dist: true } }这个设置实现了保存时自动格式化由Prettier执行并自动修复ESLint错误。确保你的VSCode已安装ESLint和Prettier扩展。3. 调试配置 (.vscode/launch.json):{ version: 0.2.0, configurations: [ { type: node, request: launch, name: Debug NestJS, runtimeExecutable: pnpm, runtimeArgs: [run, start:debug], console: integratedTerminal, restart: true, autoAttachChildProcesses: true, skipFiles: [node_internals/**] }, { type: node, request: launch, name: Jest Current File, program: ${workspaceFolder}/node_modules/.bin/jest, args: [${relativeFile}], console: integratedTerminal, internalConsoleOptions: neverOpen } ] }这样你就可以在VSCode中直接打断点调试NestJS应用或单个Jest测试文件了。5.3 生产构建与部署开发完成后需要构建出用于生产环境的代码。构建pnpm build这个命令会调用nest build它本质上运行tscTypeScript编译器根据tsconfig.json的配置将src目录下的TypeScript代码编译成JavaScript输出到dist目录。检查构建产物dist目录的结构会镜像src目录但都是.js、.js.map源码映射用于调试和.d.ts类型声明文件。生产环境运行# 首先确保安装了生产依赖通常CI/CD流程中会做 pnpm install --prod # 然后运行 pnpm start:prodstart:prod脚本执行node dist/main直接运行编译后的入口文件。关于环境变量生产环境中OPENAI_API_KEY等敏感信息不应通过.env文件管理而应使用云平台提供的环境变量配置、密钥管理服务如AWS Secrets Manager, Azure Key Vault或Docker secrets。nestjs/config模块默认会读取系统环境变量所以只需确保在运行环境中设置好即可。6. 进阶配置与常见问题排查项目跑起来只是第一步在实际开发中你会遇到各种问题。这里分享几个进阶配置和踩坑点。6.1 路径别名配置替代baseUrl虽然我们使用了moduleResolution: NodeNext但有时为了代码简洁我们仍然希望使用像/这样的路径别名。这需要打包器或加载器的支持。对于开发阶段使用ts-node修改tsconfig.json添加paths注意baseUrl已被标记为弃用但某些工具仍需要它我们可以用.代替。{ compilerOptions: { // ... 其他配置保持不变 baseUrl: ., // 当前目录作为基础路径 paths: { /*: [src/*], ai/*: [src/ai/*] } } }确保tsconfig-paths已安装并在运行命令时注册。Nest CLI的start:dev默认支持。如果你手动用ts-node运行需要ts-node -r tsconfig-paths/register src/main.ts。对于构建阶段TypeScript编译器(tsc)不会在输出的JS文件中转换路径别名。你需要一个打包工具来处理。如果你使用Vite或Webpack构建前端它们有相应的插件。对于纯Node.js后端一个常见的方案是使用tsc-alias这个工具。安装pnpm add -D tsc-alias修改package.json中的构建脚本{ scripts: { build: nest build tsc-alias -p tsconfig.json, // ... 其他脚本 } }这样在tsc编译后tsc-alias会将输出JS文件中的路径别名如/替换为正确的相对路径。6.2 处理Vite构建与TypeScript装饰器如果你的项目是前后端一体例如使用NestJS 某个前端框架并且使用Vite作为构建工具你可能会遇到Vite无法解析TypeScript装饰器语法的问题。这是因为Vite默认使用ESBuild进行TS转译而ESBuild不进行类型检查也不转换装饰器。解决方案使用插件安装vite-plugin-checker和vitejs/plugin-react如果是React或相应的Vue插件它们可以集成TypeScript类型检查。但对于装饰器可能需要额外配置。更彻底的方案将后端NestJS和前端分开成两个独立的项目分别构建。后端用tsc或nest build前端用Vite。这是更清晰、更常见的微服务或前后端分离架构。如果必须混合可以尝试使用swc插件如vitejs/plugin-react-swc并配置其支持装饰器但这通常比较棘手不推荐初学者尝试。6.3 依赖项版本冲突与幽灵依赖这是使用Monorepo或复杂项目时的高频问题。pnpm的严格模式能很大程度上避免“幽灵依赖”即代码中引用了未在package.json中声明的包。如果你遇到Cannot find module错误请检查是否在正确的dependencies或devDependencies中声明了该包。运行pnpm install --force可以重新构建依赖树。查看node_modules/.pnpm目录了解实际的依赖链接情况。对于NestJS和LangChain关注其主要依赖如nestjs/core,langchain的版本兼容性。通常遵循官方文档的安装指令是最安全的。6.4 API调用失败与错误处理增强我们的AiService中已经有了基本的try-catch。但在生产环境中你需要更健壮的处理重试机制网络波动或API限流可能导致临时失败。可以使用retry库实现指数退避重试。速率限制OpenAI API有每分钟/每天的调用限制。需要在应用层实现简单的队列或使用令牌桶算法进行限流避免超出限额。降级策略当AI服务完全不可用时是否有备选方案例如返回一个缓存的通用答案或者引导用户使用其他功能。结构化错误响应定义统一的错误响应格式并在全局异常过滤器NestJS的ExceptionFilter中捕获和处理所有未处理的异常返回给客户端友好的信息同时记录详细的服务器日志。7. 从工程化到产品化下一步可以做什么至此你已经拥有了一个结构完整、配置现代、具备基础AI调用能力的TypeScript后端工程。但这只是一个起点。基于这个骨架你可以向多个方向深化1. 功能深化复杂AI链利用LangChain的SequentialChain,RouterChain等构建多步骤的AI工作流。例如先让AI总结一篇长文再根据总结回答问题。记忆与上下文集成ConversationSummaryMemory或BufferMemory让AI能记住对话历史实现真正的多轮对话。工具调用与代理让AI能够使用外部工具如查询数据库、调用天气API。LangChain的Agent和Tool概念就是为此设计的。向量数据库与检索结合langchain/community中的向量存储集成如Chroma, Pinecone实现基于私有知识的智能问答RAG。2. 工程化加固完整的测试为AiService编写单元测试Jest模拟ChatOpenAI的调用为AiController编写端到端测试Supertest。API文档集成Swagger使用nestjs/swagger模块自动生成交互式API文档。日志与监控接入更专业的日志系统如Winston ELK Stack并添加应用性能监控APM。容器化编写Dockerfile和docker-compose.yml将应用及其依赖如Redis用于缓存会话容器化实现一键部署。CI/CD流水线在GitHub Actions或GitLab CI中配置自动化流程实现代码检查、测试、构建和部署。3. 架构扩展微服务拆分如果AI功能变得庞大复杂可以考虑将其拆分为独立的微服务通过gRPC或消息队列如RabbitMQ与主应用通信。NestJS对微服务有很好的支持。前端集成构建一个简单的前端如用Vite React/Vue通过这个后端API与AI交互形成一个完整的全栈应用。这个初始化的工程就像一副坚实的骨架。你现在要做的就是根据产品的需求为其增添血肉和灵魂。每一次新的配置、每一个新的模块都是对这个骨架的一次锤炼和扩展。当你熟悉了这套配置和架构后你会发现启动任何新的TypeScript全栈或后端项目都变得有章可循效率倍增。
返回列表