SYSTEM OK | ACTION CONTRACTS 247 DOMAINS 35 DEMO ENVIRONMENT 无需申请 | 服务热线 18926139835
首页/洞察/技术系列/EAMX 2.0 技术架构全景

EAMX 2.0 技术架构全景

本文给出 EAMX 2.0 的技术结构:247 条动作契约如何组织、11 个插件模块如何注册、14 个 Agent 如何协作、CASL 同构权限如何裁决, 以及一次架构评审触发的三阶段重构。各层之间的边界与调用关系在同一份结构下逐层展开。

作者 EAMX 产品团队 发布 2026-09-28 阅读 约 12 分钟 专题 技术系列

01定位与边界

EAMX 2.0 是面向企业设备资产管理的 AI 原生系统。与既有做法的差别集中在操作入口: 使用者以自然语言对话完成设备建档、故障报修、备件查询等事务,不必在数十个菜单与表单之间逐项填写。 设备的原始数据因此可由系统侧获取,而不完全依靠人工录入。

技术定位由五项构成:多租户 SaaS 部署、插件化业务模块、AI 处理管道、CASL 权限体系, 以及以 MCP 协议暴露的标准工具面。五项并非并列的功能清单,而是同一条调用链上的四层结构与一个对外接口。

本文的口径

本文只描述实现结构,不承诺识别准确率 100%,不承诺完全无人值守。 文中的动作契约数量、业务域数量与工具数量均为系统当前状态的导出结果,会随版本迭代变化; 核验时以演示环境的实时返回为准,本页数字不作为核验依据。 核验方式 →

02全栈技术栈与关键取舍

系统采用前后端分离结构,中间以一个共享包收敛两侧共同依赖的类型与规则。共享包不含业务逻辑, 只提供插件接口、权限构建器与工具类型三类定义。

技术栈分层
前端   React 19 + TypeScript / Vite 7 构建
        wouter 路由 + React Query 状态
        shadcn/ui 组件库(55 个组件)
        CASL 前端权限消费
共享包  packages/core:插件注册表 · 权限构建器 · 类型定义
后端   Express 5 + TypeScript
        Drizzle ORM(类型安全 SQL)
        PostgreSQL 16(主库 + pgvector + Session)
        Vercel AI SDK(工具调用 + SSE 流式)
        OpenAI 兼容接口(模型代理)· pino-http 日志
表 1 · 五项关键架构选择
决策选型理由
前后端共享类型packages/core 工作区包权限码、插件接口与工具类型只有一个定义处,两侧不会各自漂移
数据访问Drizzle ORM类型安全的 SQL 构造器,编译期即可发现字段与表名错误,运行时不引入额外开销
模型调用Vercel AI SDK streamText原生支持工具调用与流式输出,管道无需自行实现流式协议
权限CASL createMongoAbility支持带条件的动态规则,前后端可共用同一套判定
模型代理OpenAI 兼容接口更换模型厂商只需修改一处地址与模型标识,业务代码不变

上述结构的直接后果是:权限判定与工具定义不依赖具体模型厂商。模型选择因此属于配置项, 而不进入架构层。这一点在第 07 节展开。

03多租户与数据隔离

所有业务表以 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);
}

// auth.ts — writeAdminSession(跨租户管理者会话)
s.isAdmin = true;
s.tenantId = null;  // 空值表示跨租户
s.dataScope = "all";

系统选择应用层隔离,未采用 PostgreSQL 的行级安全策略,理由有三点:

  • 租户条件在 ORM 层统一生成,不依赖数据库侧策略是否配置完整,也不会因策略遗漏而放开数据;
  • 查询计划可预测,不受策略优化行为的影响;
  • 租户条件在代码中显式可见,评审时可按查询逐条核对。

跨租户读取由一个显式的管理者会话承担:会话中 isAdmin 置为 true、 tenantId 置为空值,查询层在 tenantId 为空时跳过租户条件,因此可读取全局数据。 该标记仅由平台管理侧会话写入,业务角色不具备。

该设计把隔离责任集中在一处:只要租户条件全部由同一函数生成,遗漏的可能性即被限制在该函数的范围之内。

租户条件与数据范围是两个维度:前者划定可见的租户边界,后者划定可见的组织层级。 两者都在服务端依据会话确定,不由请求方传入;权限清单同样在服务端生成, 因此同一账号在不同租户下的可见范围由服务端裁决,而非由发起调用的界面决定。

04插件化架构:11 个模块

系统按业务域拆分为 11 个插件模块,每个模块自带路由前缀、权限码、导航声明与生命周期回调。 模块之间不直接引用彼此的代码,跨模块协作通过审批流与生命周期事件完成。

表 2 · 11 个插件模块
插件 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数据分析与报表

模块通过 PluginManifest 接口声明自身要素,由注册中心统一聚合权限码与导航项,并统一挂载路由。 声明内容与注册逻辑分别如下。

PluginManifest · 模块声明字段
plugins/equipment/equipment.plugin.ts

id                模块唯一标识
version            版本号
name               模块名称
permissions        该模块的全部权限码
navItems           前端导航声明
approvalSupport    审批单据类型声明
lifecycleHandlers  生命周期事件回调
createRouter       返回 Express Router
插件注册中心与启动顺序
// packages/core/src/plugin-registry.ts(74 行)
register(plugin)      校验依赖后登记模块
getAllPermissions()   聚合全部插件权限码
getAllNavItems()     聚合全部导航项
mountAll(router)     统一挂载各模块路由

启动顺序
index.ts → app.ts(实例化 Express)→ routes/index.ts(构建主路由)
→ _registry.ts(依次注册 11 个插件)→ pluginRegistry.mountAll(mainRouter)
→ 挂载 AI 对话路由与认证路由
→ 中间件链:pino-http → cors → json → session → requireAuth → buildAbility

注册中心本身只有 74 行,承担四件事:校验依赖、登记模块、聚合权限与导航、挂载路由。 其价值在于扩展成本:新增一个业务模块只需新增一个插件并声明依赖,既有模块不做改动; 一个模块的权限码与导航集中在自身清单内,评审时可按模块核对。

依赖校验在注册阶段完成:模块声明的依赖若尚未登记,注册中心立即中止启动并报出缺失项, 使缺失依赖在启动时暴露,而不遗留到运行期。插件的加载顺序因此是显式约束,不作为运行期约定。

05AI 管道的四个阶段

对话请求进入系统后沿一条固定管道处理,分为四个阶段。意图预处理的超时预算为 100 毫秒, 超出即转入兜底分类,不阻塞主链路。

POST /api/ai/chat · 管道全景
[100ms 超时] 意图预处理 IntentAgent.preprocessIntent()
  Step 1  别名解析(entity_aliases 表查询)
  Step 2a 静态关键词匹配(内存,0ms)
  Step 2b 意图模式库(intent_patterns 表)
  Step 3  模型兜底分类(约 200ms)

Orchestrator.streamOrchestrator()
  阶段一  上下文构建(系统提示 + 实体 + 意图模式)
  阶段二  图片预处理(视觉模型 → 文字摘要拼入上下文)
  阶段三  推理与工具调用(流式输出 + 按权限过滤后的工具清单)
  阶段四  学习回写(异步记录意图与参数的对应关系)
  • 阶段一 · 上下文构建。将系统提示、实体信息与意图模式拼装为一次推理的输入。
  • 阶段二 · 图片预处理。请求含图片时,先由视觉模型转为文字摘要,再拼入上下文。
  • 阶段三 · 推理与工具调用。模型以流式方式输出,并在按权限过滤后的工具清单内发起调用;调用由对应 Agent 执行,结果以结构化卡片返回界面。
  • 阶段四 · 学习回写。记录本次意图与参数的对应关系,供后续同类请求直接命中;该环节异步执行,不影响响应时间。

意图预处理自身采用三层策略:别名解析、静态关键词与意图模式库、模型兜底分类。 三层按成本从低到高排列,命中越靠前,响应越快;仅当三层均未命中时才进入兜底分类。 三层的分工、优先级与兜底顺序见本专题第 02 篇。

0614 个 Agent 的职责划分

系统内的 AI 能力由 14 个 Agent 组成,每个 Agent 承担一类任务并拥有明确的职责边界。 Agent 不直接访问数据库,其操作一律通过统一执行管道调用动作契约, 因此权限裁决、状态校验与审计记录的口径与人工操作完全一致。

表 3 · AI 管道中的主要组件
组件职责
coordinator.agent.ts核心调度:把意图路由到子 Agent,生成 SSE 流
intent.agent.ts意图识别三层策略与意图学习
equipment.agent.ts设备台账操作、设备画像、动态表单构造
fault.agent.ts故障上报、查询与分派
maintenance.agent.ts维护工单操作
inventory.agent.ts库存查询、备件推荐与出入库
analytics.agent.ts报表生成与数据统计
external-knowledge.agent.ts外部知识库检索增强
intent-suggestion.agent.ts意图建议补全
nameplate-extractor.ts铭牌识别两阶段管线
field-classifier.ts字段分类(代码查表,不调用模型)
rag.ts向量检索增强生成

说明:系统内共 14 个 Agent,上表列出其中承担主要职责的组件;完整清单以系统导出为准。

上述 Agent 与人工操作共用同一条执行管道与同一套权限规则,调用通道不影响裁决结果。 动作契约、三条通道与权限边界的完整说明见 AI 原生与 Agent 接入。

07模型分层与厂商无关

管道按任务性质使用三类模型,不以单一模型承担全部环节,避免高成本模型被长期占用在短任务上。

模型配置 · 三项分工
AI_CHAT_MODEL    主推理模型(工具调用、多轮推理)
AI_FAST_MODEL    意图分类与短响应
AI_VISION_MODEL  铭牌识别与图片理解

三项配置均指向 OpenAI 兼容接口,由代理层统一转发。更换模型厂商或版本时, 业务代码、动作契约与工具定义均不做修改;不同任务也可独立调整模型, 例如仅替换视觉模型而不影响主推理链路。

该安排把模型选择降为配置项,而不作为架构约束。对外表述中,模型能力不构成系统的能力主张—— 系统的能力边界由动作契约与权限裁决决定,模型只负责在边界内组织调用。

分层同时约束了成本结构:意图分类一类短任务不进入主推理模型,多轮推理与工具调用不由快速模型承担。 各层职责在配置中固定,运行期不相互替用;调整其中一层不影响另外两层的调用方式。

08权限:同一套规则的三次投影

权限体系由一份规则同时供后端中间件与前端组件使用,两侧不各留一套判定。 权限码按「资源 × 动作」组织,当前覆盖 247 条动作契约与 35 个业务域; 数据范围按五个维度裁决,集团可见全域,所属单位只见本单位; 越权条件以动态规则表达,例如申请金额达到阈值时改由上级审批。

同构消费 · 后端与前端
// Express 中间件:每个请求构建 ability 并挂载到 req
app.use(buildAbilityMiddleware);

// 路由守卫
router.post("/equipments", requireAbility("create:Equipment"), handler);

// React 组件:消费同一份规则
const ability = useAbility();
{ability.can("create", "Equipment") && <CreateButton />}

Web 控制台、内嵌 AI 助手与 MCP 工具三条通道共用同一套裁决逻辑,身份来源不同而判定口径相同。 权限判定在服务端完成:工具清单由服务端按账号权限生成,客户端拿到的清单即为服务端的授权结果, 前端不存在可绕过的调用路径;演示账号为全部试用权限,其清单覆盖站内所述的动作契约。

写操作经过的七道环节

executeAction · 三条通道共用的执行管道
参数校验 → 权限裁决 → 预演 → 人工确认 → 幂等键 → 执行 → 审计

七道环节在同一处实现。调用方为 Web 控制台、内嵌 AI 助手或外部 Agent,经过的环节相同。

七道环节中的权限裁决与本节所述规则同源;审计记录通道、身份、动作、参数与结果。 一次资产状态变更的全部要素因此可在事后还原,且还原口径不随调用通道变化。 高危动作在动作定义上标注确认要求,未携带确认一律拒绝执行;执行前的预演返回将要发生的结果,不写入数据。

09通知分发:由模型判断收件人与渠道

通知分发不采用固定规则表,而由模型在候选集合内作出判断,历史通知记录作为判断依据之一。

业务事件 → 读取事件配置 → 解析候选接收人 → 读取历史记录 → 模型决策 → 渠道过滤 → 发送

决策内容包括发给谁、发什么内容、走哪个渠道;渠道过滤在发送前执行。

渠道以策略模式实现:站内信、短信、企业即时消息与邮件各为一个独立策略, 新增渠道只需注册新策略,分发主流程不做修改。该安排使渠道扩展与决策逻辑解耦, 新增一种通知方式不需要重新调整分发流程。

10三阶段架构重构

2026 年 5 月的一次架构评审诊断出四处问题,随后分三个阶段完成重构。 三个阶段按风险从低到高排列:先收敛数据访问入口,再把 AI 管道中的硬编码规则移出, 最后把工具清单直接投影为 MCP 接口。每一阶段的改动都以可核对的代码范围为单位,而非以模块整体替换。

表 4 · 三阶段重构
阶段内容改动量
Phase 1引入 Service 层:路由不再直接操作数据库,改由 Service 封装14 个 Service 类
Phase 2AI 管道去硬编码:调度器由 880 行重构为 233 行编排器与工具注册表调度器精简至约四分之一
Phase 3工具注册表直接输出 MCP 工具清单,不再另建一套接口描述MCP 服务端 66 行

重构遵循四条原则:Service 层是唯一真相源,路由只做参数校验与调用;协调器只做编排,不做决策; 生命周期总线是唯一的副作用通道;学习机制优先于硬编码规则。 四条原则的落点均在代码结构上,因此可通过代码评审逐条核对。

Phase 1 完成之后,写操作统一经 Service 层封装,路由只保留参数校验与调用, 数据访问入口因此可枚举;Phase 2 与 Phase 3 的改动都建立在这一入口之上。

11核心模块与代码规模

表 5 · 核心模块与代码规模
模块核心文件行数
插件系统packages/core/src/plugin-registry.ts74
权限构建packages/core/src/ability.ts132
编排器api-server/src/ai/orchestrator.ts233
意图识别api-server/src/agents/intent.agent.ts611
铭牌识别api-server/src/agents/nameplate-extractor.ts171
字段分类api-server/src/agents/field-classifier.ts232
工具注册表api-server/src/ai/tool-registry.ts86
MCP 服务端api-server/src/mcp/server.ts66

行数为当前版本的统计结果,随版本迭代变化。

框架代码保持克制:插件注册中心 74 行,工具注册表 86 行,MCP 服务端 66 行。 核心逻辑集中在业务 Agent 与权限构建器,框架只承担登记、聚合与挂载。 这一分布使得结构变更的影响面可估计:调整框架不触及业务逻辑,调整业务模块不触及框架。

行数是一种便于核对的观察口径:模块数量反映的是边界划分,行数反映的是改动落点。 框架层三项合计不足三百行,意味着结构层面的调整可以在有限的代码范围内完成,评审时也可按行定位。

12作者与依据

作者
EAMX 产品团队 · 产品与解决方案
依据
2026 年 5 月架构评审的诊断结论与三阶段重构记录;系统当前版本的结构导出结果
数据来源
动作契约清单(可由演示环境实时导出)、插件注册中心的权限与导航聚合结果、核心模块行数统计
引用标准
认证的对象是组织,而非软件——任何声称「某系统通过 ISO 55001 认证」的表述,均与 ISO 55001 所界定的认证对象不符。
更新日期
2026-09-28
01相关产品能力

本文所述的结构,对应哪些能力

本页说明系统内部如何实现;下列各页说明能力本身与使用方式。

02相关文章

同专题与跨专题的延伸

本文的结构可以逐项核对

247 条动作契约、35 个业务域、该账号可见工具数由端点实时返回、14 个 Agent 与 11 个插件模块—— 上述各项均无需采信本文陈述,可由演示环境导出结果自行比对。

信息中心 / 技术评估
要看接入细节与实现口径
执行层 / 业务部门
关心这些结构带来的实际变化