EAMX 2.0 技术架构全景:一个 AI-Native 设备管理系统的诞生

前端 React 19 后端 Express 5 packages/core 14 个 AI Agent · Vercel AI SDK · SiliconFlow
一个设备管理系统从传统 CRUD 到 AI-Native 需要迈过几道坎?本文拆解 EAMX 2.0 的完整技术架构:11 个插件的模块化设计、14 个 AI Agent 的协作管线、CASL 同构权限体系、以及一次架构评审触发的三阶段重构。

1. 项目定位

EAMX 是一个 AI-Native 企业设备资产管理系统(CMMS),对标 MaintainX。核心差异化在于:用户通过自然语言对话完成设备建档、故障报修、备件查询等操作,而不是在几十个菜单和表单中手动操作。

技术定位:多租户 SaaS + 插件化架构 + AI 管道 + CASL 权限 + MCP 标准工具暴露

💡 为什么选择 AI-Native 而不是"AI加持"?

传统 EAM 产品是先有流程、再叠加 AI 功能。EAMX 从第一天起就把 AI Agent 作为主交互入口,所有业务逻辑通过 Tool Calling 触达,AI 不是装饰,是操作系统。

2. 全栈技术栈一览

┌─ 前端 ─────────────────────────────────────┐
│  React 19 + TypeScript                      │
│  Vite 7 (构建)                              │
│  wouter (路由) + React Query (状态)          │
│  shadcn/ui (55 个组件)                       │
│  CASL (前端权限消费)                         │
├─────────────────────────────────────────────┤
│  packages/core (前后端共享)                   │
│  PluginRegistry / Ability Builder / Types    │
├─ 后端 ─────────────────────────────────────┐
│  Express 5 + TypeScript                     │
│  Drizzle ORM (类型安全 SQL)                  │
│  PostgreSQL 16 (主库 + pgvector + Session)   │
│  Vercel AI SDK (Tool Calling + SSE)         │
│  OpenAI 兼容 API (SiliconFlow 代理)          │
│  pino-http (日志)                            │
└─────────────────────────────────────────────┘

每一个技术选型背后都有明确的理由,下表列出关键决策:

决策选型理由
前后端共享类型packages/core pnpm workspace权限码、插件接口、Tool 类型共享
ORMDrizzle ORM类型安全的 SQL builder,无运行时开销
AI SDKVercel AI SDK streamText原生 Tool Calling + SSE 流式
权限CASL createMongoAbility前后端同构,条件权限支持
模型代理OpenAI 兼容 API → SiliconFlow一行 baseURL 切换任意模型厂商

3. 多租户架构

3.1 租户隔离策略

所有业务表以 tenant_id 为第一隔离维度:

-- 所有查询自动注入租户条件
SELECT * FROM equipments WHERE tenant_id = $1;
// Drizzle ORM 层:租户过滤器工具函数
export function wt<T>(tenantId: string | null, ...conditions: SQL[]) {
  return and(eq(table.tenantId, tenantId), ...conditions);
}

选择应用层隔离而非 PostgreSQL Row-Level Security,理由有三:

  • Drizzle ORM 层面统一处理,不会因遗漏 RLS 策略导致数据泄露
  • 查询计划可预测,不依赖 PostgreSQL 的 RLS 优化器行为
  • 开发时更直观——"看到 tenant_id 条件就是安全的"

3.2 跨租户管理

平台超级管理员(isAdmin=true, tenantId=null)可以跨越租户边界:

// auth.ts — writeAdminSession
s.isAdmin = true;
s.tenantId = null;  // null = 跨租户
s.dataScope = "all";

在 Drizzle 查询层,tenantId=null 时跳过租户过滤,从而看到全局数据。这个设计让平台运营人员能够在单一界面管理所有租户,而不需要切换账号。

4. 插件化架构:11 个独立模块

4.1 插件清单

插件 ID路由前缀职责
core-data/departments, /users, /roles, /admin, /workflows...组织架构、用户、审批流核心
equipment/equipments, /equipment-categories, /locations设备台账
technical-standards/technical-standards技术标准
work-orders/work-orders工单管理
pm-plans/pm-plans预防性维护
fault-reports/fault-reports故障上报
inventory/inventory, /spare-parts, /purchase-requests库存备件
notifications/notifications通知中心
ai-chat/ai-chat, /ai-sessions, /ai-workflowAI 对话
ai-suggestions/ai-suggestionsAI 建议中心
reports/reports数据分析

4.2 插件自描述

每个插件按 PluginManifest 接口声明自己的五要素:

// plugins/equipment/equipment.plugin.ts
export const equipmentPlugin: PluginManifest = {
  id: "equipment",
  version: "2.0.0",
  name: "设备台账",
  permissions: [ /* 该模块的所有权限码 */ ],
  navItems: [ /* 前端导航声明 */ ],
  approvalSupport: [{ documentType: "equipment", label: "设备信息变更" }],
  lifecycleHandlers: {
    "approval.approved": async (payload) => { /* 审批通过后更新设备状态 */ },
  },
  cronJobs: [],
  createRouter: () => { /* 返回 Express Router */ },
};

4.3 PluginRegistry 核心

整个注册中心只有 74 行代码,核心逻辑极简:

// packages/core/src/plugin-registry.ts
class PluginRegistry {
  private plugins = new Map<string, PluginManifest>();

  register(plugin: PluginManifest): void {
    // 依赖检查
    for (const dep of plugin.dependencies ?? []) {
      if (!this.plugins.has(dep)) throw new Error(`缺少依赖: ${dep}`);
    }
    this.plugins.set(plugin.id, plugin);
  }

  getAllPermissions(): PermissionDefinition[] { /* 聚合所有插件权限 */ }
  getAllNavItems(): NavItem[] { /* 聚合导航 */ }
  mountAll(router: Router): void { /* 统一挂载路由 */ }
}

4.4 启动流程

index.ts
  → app.ts (Express 实例化)
    → routes/index.ts (构建主 Router)
      → _registry.ts (注册所有插件)
        → pluginRegistry.register(coreDataPlugin)
        → pluginRegistry.register(equipmentPlugin)
        → ...
      → pluginRegistry.mountAll(mainRouter)
        → 每个插件的 createRouter() 挂载到主路由
      → 注册 AI Chat 路由、认证路由等
    → Express 中间件链
      → pino-http → cors → json → session → requireAuth → buildAbility

✅ 插件化的实际收益

新增一个业务模块(如"合同管理")只需实现 PluginManifest 接口,在 _registry.ts 中注册一行,完全不需要修改主应用代码。权限、导航、审批流自动集成。

5. AI 管道架构

5.1 管道全景

POST /api/ai/chat
  │
  ├─ [100ms 超时] IntentAgent.preprocessIntent()
  │   ├─ Step 1: 别名解析 (entity_aliases DB lookup)
  │   ├─ Step 2a: 静态关键词匹配 (内存, 0ms)
  │   ├─ Step 2b: 意图模式库 (intent_patterns DB)
  │   └─ Step 3: LLM 兜底分类 (AI_FAST_MODEL, ~200ms)
  │
  └─ Orchestrator.streamOrchestrator()
      ├─ Phase 1: Context Build (System Prompt + Entity + Patterns)
      ├─ Phase 2: 图片预处理(视觉模型 → 文字摘要拼入)
      ├─ Phase 3: LLM Reasoning (streamText + Tool Calling)
      │   ├─ Tool 注册项按 CASL 权限过滤
      │   └─ Agent 执行 → UI Card 返回
      └─ Phase 4: Learning (fire-and-forget 记录意图模式)

这条管道的精妙之处在于渐进式降级:0ms 关键词命中 → DB 模式匹配 → LLM 兜底。大多数常见意图在内存层就被命中,避免每次都走 LLM,成本和延迟双降。

5.2 14 个 AI Agent

Agent职责
coordinator.agent.ts核心调度器:路由意图到子 Agent,生成 SSE 流
intent.agent.ts意图识别三层策略 + 意图学习
equipment.agent.ts设备 CRUD、360° 画像、DynamicForm 构造
fault.agent.ts故障上报、查询、分派
maintenance.agent.ts维护工单操作
inventory.agent.ts库存查询、备件推荐、出入库
analytics.agent.ts报表生成、数据统计
external-knowledge.agent.ts外部知识库 RAG 检索
intent-suggestion.agent.ts意图建议补全
nameplate-extractor.ts铭牌 OCR 两阶段管线
field-classifier.ts字段分类(纯代码查表)
rag.tspgvector 检索增强生成

5.3 模型分层策略

AI_CHAT_MODEL=deepseek-ai/DeepSeek-V3.2   # 主推理模型 (Tool Calling)
AI_FAST_MODEL=deepseek-ai/DeepSeek-V3.2    # 意图分类、快速响应
AI_VISION_MODEL=Qwen/Qwen3-VL-32B-Instruct # 铭牌 OCR、图片识别

通过 OpenAI 兼容 API 的 baseURL 统一代理到 SiliconFlow,一行配置切换模型厂商。这个设计的战略意义是:无论是 DeepSeek、Qwen 还是未来的任何模型,都不需要改业务代码。

6. CASL 同构权限体系

6.1 架构要点

  • 26 个 Subjects(Equipment, WorkOrder, FaultReport, SparePart…)
  • 19 个 Actions(read, create, update, delete, dispatch, approve, grab…)
  • 3 层数据范围:all / department / self
  • 条件权限:动态规则如 { requisition.amount >= 5000 }
  • 前后端同构packages/core/src/ability.ts 中的 buildAbilityFromPermissions() 同时被 Express 中间件和 React AbilityProvider 消费

6.2 后端权限中间件

// Express 中间件:每个请求构建 ability 挂载到 req
app.use(buildAbilityMiddleware);

// routes 中的守卫
router.post("/equipments", requireAbility("create:Equipment"), handler);

6.3 前端权限消费

// React 组件中
const ability = useAbility();
{ability.can("create", "Equipment") && <CreateButton />}

⚠️ 前后端同构的边界

前端权限判断只用于 UI 可见性控制(隐藏按钮/菜单),后端永远是真正的守门人。能在前端隐藏 UI 是体验优化,不是安全保障。

7. 通知系统:LLM 决策分发

业务事件触发 dispatch
  → 查询事件配置(是否开启)
  → 解析候选接收人(contextual-user-resolver)
  → 拉取历史通知记忆
  → LLM 决策:发给谁、发什么内容、走什么渠道
  → 渠道过滤(站内信 / 短信 / 钉钉 / 邮件)
  → 发送

关键设计:通知渠道是 NotificationDispatcher 的策略模式,新增渠道(如钉钉工作通知)只需注册新策略。让 LLM 决策"发给谁"这件事初看反直觉,但实际场景中,"工单超时该通知谁"往往依赖上下文——是通知当班人员、还是值班经理、还是设备负责人,LLM 比硬编码的规则引擎更灵活。

8. 三阶段架构重构

2026 年 5 月的架构评审诊断了 4 个系统性问题,触发了三阶段重构:

阶段内容改动量
Phase 1Service 层引入 — 路由不再直接操作 DB,通过 Service 封装14 个 Service 类
Phase 2AI 管道去硬编码 — Coordinator 从 880 行重构为 233 行 Orchestrator + Tool Registrycoordinator.agent.ts 精简
Phase 3MCP Server 顺手牵羊 — Tool Registry 直接输出 MCP tools/listmcp/server.ts 66 行

重构的核心原则:

  • P2:Service 层是唯一真相源,路由只做参数校验和调用
  • P3:协调器只做编排,不做决策
  • P4:LifecycleBus 是唯一副作用通道
  • P5:学习优于硬编码

Phase 3 是这次重构最出乎意料的收益:因为 Tool Registry 已经把每个 AI Agent 的工具描述标准化了,只需要 66 行代码就完成了 MCP Server 的实现。EAMX 的每一个 AI 能力,现在都可以通过标准 MCP 协议暴露给外部系统(钉钉、企业微信、第三方 AI 应用),零额外工作量。

9. 核心文件索引

模块核心文件行数
架构评审qod/architecture-review-2026-05-08.md557
AI 架构qod/ai-architecture-v2.md900+
插件系统packages/core/src/plugin-registry.ts74
权限packages/core/src/ability.ts132
编排器artifacts/api-server/src/ai/orchestrator.ts233
意图识别artifacts/api-server/src/agents/intent.agent.ts611
铭牌 OCRartifacts/api-server/src/agents/nameplate-extractor.ts171
字段分类artifacts/api-server/src/agents/field-classifier.ts232
Tool Registryartifacts/api-server/src/ai/tool-registry.ts86
MCP Serverartifacts/api-server/src/mcp/server.ts66

📌 本系列后续文章

后续 9 篇文章将对上述每个模块做深度拆解:从代码实现、性能优化、到踩坑复盘。下一篇将深入意图识别三层策略——如何用渐进式架构在 0ms 到 200ms 之间精准判断用户意图。

准备好让AI管理你的设备资产了吗?

EAMX提供永久免费版,无需信用卡,2周内完成部署。加入1000+工厂已在使用的AI原生EAM系统。