EAMX 2.0 是面向企业设备资产管理的 AI 原生系统。与既有做法的差别集中在操作入口: 使用者以自然语言对话完成设备建档、故障报修、备件查询等事务,不必在数十个菜单与表单之间逐项填写。 设备的原始数据因此可由系统侧获取,而不完全依靠人工录入。
技术定位由五项构成:多租户 SaaS 部署、插件化业务模块、AI 处理管道、CASL 权限体系, 以及以 MCP 协议暴露的标准工具面。五项并非并列的功能清单,而是同一条调用链上的四层结构与一个对外接口。
本文只描述实现结构,不承诺识别准确率 100%,不承诺完全无人值守。 文中的动作契约数量、业务域数量与工具数量均为系统当前状态的导出结果,会随版本迭代变化; 核验时以演示环境的实时返回为准,本页数字不作为核验依据。 核验方式 →
系统采用前后端分离结构,中间以一个共享包收敛两侧共同依赖的类型与规则。共享包不含业务逻辑, 只提供插件接口、权限构建器与工具类型三类定义。
| 决策 | 选型 | 理由 |
|---|---|---|
| 前后端共享类型 | packages/core 工作区包 | 权限码、插件接口与工具类型只有一个定义处,两侧不会各自漂移 |
| 数据访问 | Drizzle ORM | 类型安全的 SQL 构造器,编译期即可发现字段与表名错误,运行时不引入额外开销 |
| 模型调用 | Vercel AI SDK streamText | 原生支持工具调用与流式输出,管道无需自行实现流式协议 |
| 权限 | CASL createMongoAbility | 支持带条件的动态规则,前后端可共用同一套判定 |
| 模型代理 | OpenAI 兼容接口 | 更换模型厂商只需修改一处地址与模型标识,业务代码不变 |
上述结构的直接后果是:权限判定与工具定义不依赖具体模型厂商。模型选择因此属于配置项, 而不进入架构层。这一点在第 07 节展开。
所有业务表以 tenant_id 作为第一隔离维度,查询条件由统一工具函数注入,
业务代码不自行拼接租户条件,也不允许绕开该函数直接查询。
系统选择应用层隔离,未采用 PostgreSQL 的行级安全策略,理由有三点:
跨租户读取由一个显式的管理者会话承担:会话中 isAdmin 置为 true、
tenantId 置为空值,查询层在 tenantId 为空时跳过租户条件,因此可读取全局数据。
该标记仅由平台管理侧会话写入,业务角色不具备。
该设计把隔离责任集中在一处:只要租户条件全部由同一函数生成,遗漏的可能性即被限制在该函数的范围之内。
租户条件与数据范围是两个维度:前者划定可见的租户边界,后者划定可见的组织层级。 两者都在服务端依据会话确定,不由请求方传入;权限清单同样在服务端生成, 因此同一账号在不同租户下的可见范围由服务端裁决,而非由发起调用的界面决定。
系统按业务域拆分为 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-workflow | AI 对话与会话管理 |
ai-suggestions | /ai-suggestions | AI 建议中心 |
reports | /reports | 数据分析与报表 |
模块通过 PluginManifest 接口声明自身要素,由注册中心统一聚合权限码与导航项,并统一挂载路由。
声明内容与注册逻辑分别如下。
注册中心本身只有 74 行,承担四件事:校验依赖、登记模块、聚合权限与导航、挂载路由。 其价值在于扩展成本:新增一个业务模块只需新增一个插件并声明依赖,既有模块不做改动; 一个模块的权限码与导航集中在自身清单内,评审时可按模块核对。
依赖校验在注册阶段完成:模块声明的依赖若尚未登记,注册中心立即中止启动并报出缺失项, 使缺失依赖在启动时暴露,而不遗留到运行期。插件的加载顺序因此是显式约束,不作为运行期约定。
对话请求进入系统后沿一条固定管道处理,分为四个阶段。意图预处理的超时预算为 100 毫秒, 超出即转入兜底分类,不阻塞主链路。
意图预处理自身采用三层策略:别名解析、静态关键词与意图模式库、模型兜底分类。 三层按成本从低到高排列,命中越靠前,响应越快;仅当三层均未命中时才进入兜底分类。 三层的分工、优先级与兜底顺序见本专题第 02 篇。
系统内的 AI 能力由 14 个 Agent 组成,每个 Agent 承担一类任务并拥有明确的职责边界。 Agent 不直接访问数据库,其操作一律通过统一执行管道调用动作契约, 因此权限裁决、状态校验与审计记录的口径与人工操作完全一致。
| 组件 | 职责 |
|---|---|
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 接入。
管道按任务性质使用三类模型,不以单一模型承担全部环节,避免高成本模型被长期占用在短任务上。
三项配置均指向 OpenAI 兼容接口,由代理层统一转发。更换模型厂商或版本时, 业务代码、动作契约与工具定义均不做修改;不同任务也可独立调整模型, 例如仅替换视觉模型而不影响主推理链路。
该安排把模型选择降为配置项,而不作为架构约束。对外表述中,模型能力不构成系统的能力主张—— 系统的能力边界由动作契约与权限裁决决定,模型只负责在边界内组织调用。
分层同时约束了成本结构:意图分类一类短任务不进入主推理模型,多轮推理与工具调用不由快速模型承担。 各层职责在配置中固定,运行期不相互替用;调整其中一层不影响另外两层的调用方式。
权限体系由一份规则同时供后端中间件与前端组件使用,两侧不各留一套判定。 权限码按「资源 × 动作」组织,当前覆盖 247 条动作契约与 35 个业务域; 数据范围按五个维度裁决,集团可见全域,所属单位只见本单位; 越权条件以动态规则表达,例如申请金额达到阈值时改由上级审批。
Web 控制台、内嵌 AI 助手与 MCP 工具三条通道共用同一套裁决逻辑,身份来源不同而判定口径相同。 权限判定在服务端完成:工具清单由服务端按账号权限生成,客户端拿到的清单即为服务端的授权结果, 前端不存在可绕过的调用路径;演示账号为全部试用权限,其清单覆盖站内所述的动作契约。
七道环节在同一处实现。调用方为 Web 控制台、内嵌 AI 助手或外部 Agent,经过的环节相同。
七道环节中的权限裁决与本节所述规则同源;审计记录通道、身份、动作、参数与结果。 一次资产状态变更的全部要素因此可在事后还原,且还原口径不随调用通道变化。 高危动作在动作定义上标注确认要求,未携带确认一律拒绝执行;执行前的预演返回将要发生的结果,不写入数据。
通知分发不采用固定规则表,而由模型在候选集合内作出判断,历史通知记录作为判断依据之一。
决策内容包括发给谁、发什么内容、走哪个渠道;渠道过滤在发送前执行。
渠道以策略模式实现:站内信、短信、企业即时消息与邮件各为一个独立策略, 新增渠道只需注册新策略,分发主流程不做修改。该安排使渠道扩展与决策逻辑解耦, 新增一种通知方式不需要重新调整分发流程。
2026 年 5 月的一次架构评审诊断出四处问题,随后分三个阶段完成重构。 三个阶段按风险从低到高排列:先收敛数据访问入口,再把 AI 管道中的硬编码规则移出, 最后把工具清单直接投影为 MCP 接口。每一阶段的改动都以可核对的代码范围为单位,而非以模块整体替换。
| 阶段 | 内容 | 改动量 |
|---|---|---|
| Phase 1 | 引入 Service 层:路由不再直接操作数据库,改由 Service 封装 | 14 个 Service 类 |
| Phase 2 | AI 管道去硬编码:调度器由 880 行重构为 233 行编排器与工具注册表 | 调度器精简至约四分之一 |
| Phase 3 | 工具注册表直接输出 MCP 工具清单,不再另建一套接口描述 | MCP 服务端 66 行 |
重构遵循四条原则:Service 层是唯一真相源,路由只做参数校验与调用;协调器只做编排,不做决策; 生命周期总线是唯一的副作用通道;学习机制优先于硬编码规则。 四条原则的落点均在代码结构上,因此可通过代码评审逐条核对。
Phase 1 完成之后,写操作统一经 Service 层封装,路由只保留参数校验与调用, 数据访问入口因此可枚举;Phase 2 与 Phase 3 的改动都建立在这一入口之上。
| 模块 | 核心文件 | 行数 |
|---|---|---|
| 插件系统 | packages/core/src/plugin-registry.ts | 74 |
| 权限构建 | packages/core/src/ability.ts | 132 |
| 编排器 | api-server/src/ai/orchestrator.ts | 233 |
| 意图识别 | api-server/src/agents/intent.agent.ts | 611 |
| 铭牌识别 | api-server/src/agents/nameplate-extractor.ts | 171 |
| 字段分类 | api-server/src/agents/field-classifier.ts | 232 |
| 工具注册表 | api-server/src/ai/tool-registry.ts | 86 |
| MCP 服务端 | api-server/src/mcp/server.ts | 66 |
行数为当前版本的统计结果,随版本迭代变化。
框架代码保持克制:插件注册中心 74 行,工具注册表 86 行,MCP 服务端 66 行。 核心逻辑集中在业务 Agent 与权限构建器,框架只承担登记、聚合与挂载。 这一分布使得结构变更的影响面可估计:调整框架不触及业务逻辑,调整业务模块不触及框架。
行数是一种便于核对的观察口径:模块数量反映的是边界划分,行数反映的是改动落点。 框架层三项合计不足三百行,意味着结构层面的调整可以在有限的代码范围内完成,评审时也可按行定位。
本页说明系统内部如何实现;下列各页说明能力本身与使用方式。
247 条动作契约、35 个业务域、该账号可见工具数由端点实时返回、14 个 Agent 与 11 个插件模块—— 上述各项均无需采信本文陈述,可由演示环境导出结果自行比对。