ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Egg.js 4.0 企业级框架革新:DDD+TypeScript 驱动 AI 原生落地实践

Egg.js 4.0 企业级框架革新:DDD+TypeScript 驱动 AI 原生落地实践 1. 为什么 Egg.js 4.0 值得后端团队重新评估Egg.js 4.0 是阿里开源的企业级 Node.js 框架在 2025 年的一次大版本重构核心变化可以概括成三件事全 TypeScript 重写、DDD 模块化架构原生支持、AI 能力MCP / Agent内置。它适合谁适合正在用 Egg.js 2.x/3.x 维护中大型单体、又想把架构往领域驱动方向迁移的 Node.js 后端团队也适合准备做 AI Agent 服务端、但不想从零搭一套通信协议和编排层的团队。我所在的团队维护着一套 3.x 的订单系统二十多个 controller 挤在一个目录里路由靠router.js手写类型提示基本靠注释。改一个字段要全局搜新人上手两周还在问「这个 service 在哪注册的」。Egg.js 4.0 的 tegg 模板把这些问题拆成了三块装饰器声明路由和依赖注入、modules 目录做领域隔离、MCP 装饰器直接暴露 AI 工具。下面按「搭骨架 → 配 TS → 接 AI → 验证 → 排障」的顺序走一遍命令和配置都能直接复制。2. TaoToken 前置给 AI 能力准备一个可调用的模型入口Egg.js 4.0 的 Agent 和 MCP 工具最终要落到一个能对话的模型上。企业内网环境里直接调外部模型接口往往卡在鉴权和网络策略上所以我会先用 TaoToken 把模型调用这一层固定下来再让框架去接。TaoToken 是一个兼容 OpenAI 接口规范的模型调用平台官网在 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 入口是 https://taotoken.net/api 。它的作用是给你一个统一的 base_url 和 key框架侧只认这两个值换模型不用改业务代码。操作路径很直接进控制台 https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_contentconsoleutm_campaignrewrite 创建 API Key然后在 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite 里复制出来。想先确认模型通不通用模型对话页 https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_contentmodelsutm_campaignrewrite 发一条测试消息即可。接入细节查文档 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 。注意Key 只放服务端环境变量不要写进config.default.ts提交到仓库。Egg.js 的config目录默认会被打包硬编码等于泄露。3. 可复制配置Egg.js 4.0 项目骨架 DDD 分层 TypeScript3.1 初始化 tegg 模板# 创建 DDD TS 风格的项目 npx create-eggbeta --template tegg egg4-ddd-demo cd egg4-ddd-demo npm install生成后的目录结构大致是这样modules是领域核心egg4-ddd-demo/ ├── config/ │ ├── config.default.ts │ └── plugin.ts ├── modules/ │ └── user/ │ ├── controller/ │ │ └── UserController.ts │ ├── service/ │ │ └── UserService.ts │ ├── module.ts │ ├── module.yml │ └── package.json ├── tsconfig.json └── package.json3.2 TypeScript 配置要点tsconfig.json里和 tegg 装饰器相关的几项必须打开否则运行时报「装饰器元数据缺失」{ compilerOptions: { target: ES2022, module: commonjs, experimentalDecorators: true, emitDecoratorMetadata: true, strict: true, esModuleInterop: true, skipLibCheck: true, outDir: dist, baseUrl: ., paths: { /*: [modules/*] } }, include: [modules/**/*.ts, config/**/*.ts] }experimentalDecorators和emitDecoratorMetadata是装饰器注入的命门strict打开后类型提示才完整。paths里的别名让跨模块引用写成/user/service/UserService比相对路径../../清爽。3.3 DDD 分层controller / service / module 各管什么一个领域模块内部按职责分三层以 user 为例// modules/user/service/UserService.ts import { SingletonProto, Inject } from eggjs/tegg; SingletonProto() export class UserService { async findById(id: string): Promise{ id: string; name: string } { // 真实项目里这里走 repository示例直接返回 return { id, name: user-${id} }; } }// modules/user/controller/UserController.ts import { HTTPController, HTTPMethod, HTTPMethodEnum, Inject } from eggjs/tegg; import { UserService } from ../service/UserService; HTTPController({ path: /api/user }) export class UserController { Inject() userService: UserService; HTTPMethod({ method: HTTPMethodEnum.GET, path: /:id }) async detail(ctx: any) { const user await this.userService.findById(ctx.params.id); return { code: 0, data: user }; } }SingletonProto()声明单例服务Inject()自动注入不用再写app.service.user。HTTPController和HTTPMethod把路由声明在业务文件里router.js可以彻底删掉。3.4 接入 AIMCP 装饰器暴露工具Egg.js 4.0 内置 MCP Client/Server用装饰器就能把服务端能力暴露给 Agent// modules/ai/controller/McpController.ts import { MCPController, MCPPrompt, MCPTool } from eggjs/tegg-mcp; MCPController() export class McpController { MCPPrompt() async welcome() { return { content: 我是订单助手可以帮你查订单状态 }; } MCPTool() async queryOrder() { return { toolName: query-order, desc: 按订单号查询状态, parameters: [ { name: orderId, type: string, required: true, desc: 订单号 }, ], }; } }模型侧要调用的地址和 key通过环境变量注入# .env不要提交 TAOTOKEN_BASE_URLhttps://taotoken.net/api TAOTOKEN_API_KEYsk-你的key// config/config.default.ts export default { ai: { baseURL: process.env.TAOTOKEN_BASE_URL, apiKey: process.env.TAOTOKEN_API_KEY, model: gpt-4o-mini, }, };4. 验证请求从启动到 AI 工具调用成功4.1 启动并检查模块加载npm run dev启动日志里会打印已加载的 module 列表确认user和ai都在。如果某个 module 没出现多半是module.yml里name和目录名不一致。4.2 验证普通 HTTP 接口curl http://127.0.0.1:7001/api/user/42预期返回{ code: 0, data: { id: 42, name: user-42 } }这一步通了说明装饰器路由和依赖注入都正常。4.3 验证模型连通性先用 curl 直接打 TaoToken 的接口确认 key 和 base_url 没问题curl https://taotoken.net/api/v1/chat/completions \ -H Authorization: Bearer $TAOTOKEN_API_KEY \ -H Content-Type: application/json \ -d { model: gpt-4o-mini, messages: [{role: user, content: 回复 ok}] }返回里有choices[0].message.content就说明模型侧通了。这一步单独做的好处是后面 Agent 报错时能快速区分是框架问题还是模型入口问题。4.4 验证 MCP 工具被 Agent 识别启动后访问 MCP 服务端点tegg 默认挂在/mcp下用 MCP 客户端或框架自带的调试页查看工具列表应该能看到query-order。如果工具没注册上检查MCPTool()所在类是否被MCPController()包裹以及该 module 是否在module.yml里声明。5. 本篇常见错排查5.1 装饰器报错「Unable to resolve signature」现象Inject()下面出现红色波浪线运行时报Cannot read property userService of undefined。原因tsconfig.json缺emitDecoratorMetadata或者experimentalDecorators被其他配置覆盖。处理确认两项都为true删掉dist重新npm run dev。如果用了ts-node加--compiler-options显式指定。5.2 module 加载失败「module.yml not found」现象启动日志报某个 module 跳过。原因module.yml里的name字段和目录名不一致或者package.json的name没写。处理module.yml保持name: userpackage.json里name: user两者和目录名三者一致。5.3 MCP 工具调用返回 401现象Agent 能列出工具但实际调用时报鉴权失败。原因TAOTOKEN_API_KEY没注入到进程或者.env没被加载。处理Egg.js 默认不读.env用dotenv在config.default.ts顶部import dotenv/config或者直接在启动命令前export。确认process.env.TAOTOKEN_API_KEY有值再启动。5.4 旧项目升级后路由 404现象装了eggjs/tegg-plugin和eggjs/tegg-config后老router.js里的路由失效。原因tegg 接管路由后旧式router.get()声明和装饰器路由的加载顺序有冲突。处理升级期两者可以共存但要确保plugin.ts里 tegg 插件在router之前启用。逐步把router.js里的条目迁到装饰器迁完再删。5.5 类型提示不生效现象IDE 里this.userService没有补全。原因paths别名没配或者 IDE 用的 TS 版本低于 5.0。处理tsconfig.json的paths加上/*重启 TS ServerVS Code 里CtrlShiftP→ Restart TS Server。6. 长期编码与 Agent 场景的下一步如果只是验证模型通不通用模型对话页发一条消息就够了。但要把 Egg.js 4.0 的 Agent 能力真正落到日常编码和长期运行的服务里建议走 Coding Plan把模型调用额度、并发和 Agent 编排统一管起来https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewrite 。接入文档在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite API Key 管理在 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite 。我自己的做法是本地开发用模型对话页快速试 promptCI 里用 Coding Plan 的 key 跑 Agent 回归生产环境把 key 放密钥管理服务Egg.js 侧只读环境变量。这样框架升级、模型切换、额度调整三件事互不干扰。
返回列表