首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >OODUI重磅升级:以用户交互为中心的 AI 原生UI架构

OODUI重磅升级:以用户交互为中心的 AI 原生UI架构

原创
作者头像
OneCode
发布于 2026-10-27 20:15:59
发布于 2026-10-27 20:15:59
1970
举报
文章被收录于专栏:ooderAgentooderAgent

Architecture Design · AI-native UI

以用户交互为中心的 AI 原生架构

A/B/C 分层不是目的,而是为了让「一次用户交互」在三层各自得到正确的支撑:A 提供渲染与协议,B 提供领域语义与授权,C 提供确定性能力。同一个 B 之上,同时支撑页面模式(UI + 小助手)与对话模式(chatnext 原生),并通过五个接缝完成双向转换。

01设计出发点:交互是三层共同的输出

多数分层讨论从「代码归属」出发,结果是把架构讲成了目录结构。本文换一个起点:从一次用户交互往回推 —— 用户点一个按钮、或说一句话,系统需要什么,就分什么层。

一次完整的交互需要四件东西:看得见的界面、听得懂的语言、做得对的动作、留得下的痕迹。它们分别落在 A、B、C 三层,且任何一层缺位,交互就会在某处断掉。

交互要素

用户感受

由谁支撑

界面(看得见)

「我知道现在在哪、能做什么」

A:令牌 + ood.UI.* + .cls 渲染

语义(听得懂)

「它理解我说的是什么业务」

B:领域模型 + 视图契约 + 场景与工具白名单

动作(做得对)

「结果是对的,而且不会越权」

B 授权与规则 + C 确定性实现

痕迹(留得下)

「出问题能查、能回滚」

A 事件账本 + C 幂等与审计写入

这个起点带来的第一个结论

既然「界面」与「语义」是两类不同的东西,那么交互外壳天然可以替换,而语义与动作不能。这就是后文 A/B/C 分层的由来,也是「一个 B、两种交互」能够成立的根据。

02A/B/C 架构:一表看清三层分工

A/B/C 分别回答三个不同的问题,并对应三种不同的变化频率。先看结论表,再看职责细节。

2.1 三层分工(结论先行)

层

名称

回答什么问题

承载内容

变化频率

归属

A

平台基线

怎么渲染、怎么传事件、怎么落盘

令牌 L0–L2、ood.UI.* 组件、SSE 事件域、buildView → .cls 三地址

月(平台统一升级)

ooder-pro · ouc-core · ood-codegen-*

B

领域宿主

业务是什么、谁能看、谁能改

实体/视图契约注解、modules.yaml、authz/roles.yaml、agents.yaml、flow-decl

客户周期(可配置)

ooder-domain-{domain}

C

业务实现

具体怎么算、怎么取数、怎么落库

服务、场景、编排、外部适配、{X}APIImpl、六类技能载体

天级(可自助)

ooder-biz-{domain}

判据(一句话记住三层)

能被平台反射读取的元数据,必须在 A/B 的注解里;与类无关、客户可改的运维面配置,必须在 B 的 YAML 里;任何「拼装产物」的代码都不许留在 C。

2.2 为什么是「以用户交互为中心」

三层不是按技术栈切的,而是按交互链路切的:

一层管「看起来对不对」

A 只做渲染与协议,不含业务判断。因此换 A 不会改变业务,换业务也不会动 A。

一层管「理解与约束」

B 决定用户看到哪些字段、能点哪些动作、谁能改什么 —— 它是「交互语义」的唯一出处。

一层管「算得对」

C 只接收结构化入参、只返回结构化结果;不读界面、不返回 UI 片段、不吞异常。

2.3 依赖方向与不变式

代码语言:javascript
复制
A(平台基线)  ←──  B(注解 + 声明)  ←──  C(实现)

① B 不得依赖 A 的生成器;C 不得反向依赖 A 的内部实现
② C 不得依赖其它 C 包或非本域 B 包
③ ooder-pro 不得反向依赖任何 ooder-biz-* / ooder-domain-*
④ .cls 只由 buildView 产出,三地址(VFS / export / workspace)字节一致

图 1 两种外壳共用 A 的渲染能力、共享 B 的领域语义、调用同一份 C 能力

03A 层:两种外壳共用的渲染与协议基线

A 层的判断标准只有一条:它是否对所有业务都成立。成立才进 A,否则归 B 或 C。

3.1 A 层提供什么

能力

内容

为什么在 A

令牌体系

L0 原始值 → L1 语义色 → L2 组件令牌(theme-vars.css 唯一变量源)

所有业务共用同一套视觉基线

组件与渲染

ood.UI.*(表格/表单/树/页签/工具栏/菜单/对话框…)

两种外壳用的是同一批组件

契约序列化

C2UFactory.buildView → .cls 三地址

页面模块的唯一产出通道

事件与协议

SSE 事件域、Bus、EventStore、A2A 任务协议

跨外壳统一的通信语义

可访问性基线

焦点环、键盘模型、role/aria-* 自动补齐

一次实现,全局生效

3.2 A 层提供的组件能力基线

这些能力是「外壳可以依赖的约定」,而不是某个页面的修饰:

能力

对外契约

取值

密度三档

setDensity('compact'|'cozy'|'comfortable')

表头 26/30/38、行 24/28/34、字 12/13/14px

列宽持久化

拖拽手柄 + colWidthKey

存储键 ood-treegrid-cols:<key>,渲染后自动恢复

键盘模型

方向键 / Home / End / Enter / Esc

表格、树、页签、菜单、分页统一可达

ARIA 自动补齐

setARIA() 渲染后调用

grid/row/columnheader/gridcell、tree/treeitem、tab/tabpanel

三态覆盖

showState('empty'|'loading'|'error') + clearState()

role=status + aria-live=polite

页签形态

setVariant('line'|'card'|'segmented')

line 2px 主色下划线;segmented 胶囊

页签滚动

setScrollMode(true)

页签保持自然宽度,滚轮纵向转横向

树能力

search() / setLazyLoader() / 缩进 token

命中高亮;懒加载占位;--ood-treebar-indent

工具栏与菜单

ToolBar 40/48 + 左标题右操作;MenuBar/PopMenu 语义

子菜单内 →/← 可切顶层,焦点不丢

04C 层:能力定型,完全独立于 UI

C 层的目标只有一个:把业务能力做成可被任何外壳调用的确定性单元。

4.1 六类能力载体

载体

契约强度

典型用途

与 UI 的关系

capability

60

平台级工具函数(查询、计算、转换)

无

chat_tool

50

对话可调用工具

无(由 Agent 决定何时调用)

chat_scene

45

领域场景(提示词 + 工具白名单)

弱(可被页面小助手复用)

nlp_skill

40

意图 → 动作映射

无

unified_action

30

统一动作入口(按钮/命令共用)

弱(同一动作两种触发)

declarative

20

声明式流程 / 规则

无

载体优先级不只是注册顺序,而是契约强度:越靠前越不依赖外部状态,越适合被任意外壳复用。「同一能力两种 UI 都能用」不是靠适配器堆出来的,而是定义时就排除了 UI 依赖。

4.2 目录层 ≠ 驻留层

层

回答

口径

目录层 Catalog

「有哪些技能」,每 skillId 唯一

253(code 246 + declarative 7)

驻留层 Residency

「谁能执行」,(skillId, nodeId) 多份

499(246×2 宿主 + 7)

技能存在性必须问目录层,不能用驻留行数代替 —— 否则换个外壳,统计口径跟着变。

4.3 执行体与界面卡片:只做寻址对齐

codeAgent 6 个能力域执行体与前端 6 张快捷卡 1:1,但这层关系只用于寻址。执行体本身不依赖卡片:A2A 调用、流程节点调用、其它 Agent 委派都能直接命中。

代码语言:javascript
复制
C 端能力的「三不」约束
  ① 不读 UI 状态     入参只有显式 id / 结构化条件,没有「当前选中行」
  ② 不返回 UI 片段   返回结构化结果 + 产物引用,由外壳决定渲染
  ③ 不吞异常         失败必须带错误码与原因(禁止静默降级)

05B 层:领域逻辑不变,交互外壳可换

B 是全文的重心:它既是领域逻辑的家,也是两种交互的唯一汇聚点。

5.1 B 层持有什么

类别

载体

内容

为什么在 B

领域模型

Java 注解

@DBTable/@DBField/@Uid/@Ref

平台反射装配元数据

视图契约

Java 注解

@ModuleAnnotation/@TreeGridViewAnnotation/@FormAnnotation/@PageBar

buildView 读注解出 .cls

动作入口

Java 注解

@APIEventAnnotation(bindMenu, autoRun)

按钮与对话走同一入口

模块与菜单

YAML

module/modules.yaml

客户端可改,不编译进类

授权 / 角色矩阵

YAML

authz/roles.yaml:角色 → 动作 / 字段 / 数据范围

客户差异大,且必须可审计可回滚

执行体名册

YAML

agents.yaml:capability / capabilityDomain / skillIds

两种外壳共用同一份名册

流程

JSON

flow-decl/{flowId}/definition.json

人工门与上下文装载由流程声明

一条不能让步的边界

科室级 / 字段级 / 状态级的可见性与可操作性,必须在 B 的 YAML 中由业务人员可视化配置。它是客户侧事实、是组织 × 流程状态的笛卡尔积、需要可 diff 可回滚 —— 因此不交给模型自由生成。

5.2 一份声明,两种投影

图 2 同一份 B 声明向上投影成两种交互;共享内核保证同源

5.3 模式选择矩阵

场景特征

选择

理由

高频、结构化、批量录入

页面模式

表格的密度与批量效率不可替代

细粒度授权、字段级可见性

页面模式

约束需要「看得见地配置与核对」

目标导向、步骤不固定

对话模式

用户说不清路径,只要结果

跨系统取数 + 多步分析 + 出图

对话模式

流式过程与图表即时绘制是核心体验

需留痕的审批与对外承诺

两模式混用

对话发起 → 人工门确认 → 落回页面台账

既有系统改造(前端不能重做)

页面模式

零侵入获得 NLP 与智能操作

5.4 为什么汇聚点必须在 B

  1. 不能放 A:A 是所有人的基线,写进某个业务的交互偏好会逼迫其它业务;A 改一次,全平台回归。
  2. 不能放 C:C 一旦感知 UI,就无法被 A2A、流程节点、其它 Agent 复用 —— 直接违背「能力独立于 UI」。
  3. 只能在 B:B 本就是「业务是什么」的声明层,天然同时服务「页面怎么摆」与「对话怎么问」;它既懂领域,又不负责渲染。

06双模式转换:五个接缝与状态随行规则

「两种模式」听起来像两套系统。实际上 B 只做一件事:把同一份声明投影到五个可替换的接缝上,并在切换时按规则搬运状态。

6.1 五个接缝(模式差异的全部落点)

接缝

页面模式(UI + 小助手)

对话模式(chatnext 原生)

共同来源(B/A)

① 入口

菜单 / 工具栏 / 行命令 / 右下浮层

输入框 / 快捷卡 / @执行体

modules.yaml 菜单 + entryProfile 档位

② 动作

@APIEventAnnotation(bindMenu) 绑定按钮

同一注解暴露为工具 / 场景动作

同一份动作入口(unified_action)

③ 上下文

页面级:类名 / 选中行 / 当前节点

会话级 + 任务级:conversationId / contextRef

两者都读「画布通道状态」canvasChannel

④ 产出

.cls 组件树;表格刷新 / 表单回填 / 画布写指令

Markdown / 图表 / 产物卡 / 设计器预览

A 层同一批组件 + A2UI 渲染能力

⑤ 人工门

页面内行内二次确认(armConfirm)

对话内确认卡(ConfirmBar,唯一出口)

同一 human 事件域与超时策略

关键点

五个接缝里,②动作 与 ⑤人工门 完全共用实现,只是渲染位置不同;①入口 与 ④产出 由外壳各自实现;③上下文 通过「画布通道 + 对象标识」对齐。因此模式转换不是数据迁移,而是外壳替换 + 状态搬运。

6.2 切换时什么跟着走、什么不跟

状态

是否随行

载体

说明

业务对象标识(主键 / id)

随行

页面级上下文 → contextRef

从表格某行「带着它去问」

筛选条件 / 期间 / 主体

随行

标量上下文(只出标量)

避免「问的是这个期间、答的是别的期间」

任务上下文(步骤 + 产物)

随行

contextRef(任务上下文存储)

跨轮次承接,可回读

画布通道可达性

随行

canvasChannel / canvasPage

决定能否直接下发写指令

滚动位置 / 展开折叠

不随行

各外壳本地状态

属于瞬时展示状态,搬运反而打断

输入框草稿

不随行

各外壳本地存储

避免把页面查询词误当成对话输入

6.3 双向携带的两个动作

页面 → 对话:带着对象去问

小助手读取当前页类名、选中行与画布通道状态,作为标量上下文下发;用户不必重复「我在看哪个部门」。

对话 → 页面:展开到页面

对话产出可用 .cls 片段或设计器预览呈现;用户点「展开」即进入页面模式,在同一对象上继续结构化操作。

共同前提

两个动作都要求「对象标识」在两侧同构 —— 这正是 B 的视图契约(同一 id 语义)所保证的。

6.4 转换不变量(换外壳不换语义)

不变量

含义

保障方式

同一权限判定

按钮能点的,对话未必能点;反之亦然 —— 判定逻辑只有一处

动作入口唯一(@APIEventAnnotation / unified_action)

同一审计留痕

无论谁触发,写操作都进同一份审计

C 侧写路径统一,不区分调用方

同一幂等键

重复触发不产生重复数据

业务键在 C 侧定义(如去重键三段回退)

同一失败原因码

报错文案可以不同,原因码必须相同

UNDELIVERABLE / OP_NOT_IN_DOMAIN / COMPILATION_FAILED 等原样透出

同一人工门策略

红线节点的超时行为不因外壳而变

红线统一按 ESCALATE_HUMAN 处理

07共享内核:上下文与智能操作转换

7.1 上下文:三级 + 一通道

级别

内容

两种模式如何使用

会话级

conversationId / sessionId / workMode

对话:会话主线;页面:小助手复用隐式会话

任务级

contextRef(步骤 + 产物)

对话:跨轮次承接;页面:带入当前编辑对象

页面级

当前页类名、选中行、当前节点

对话:作为意图约束;页面:小助手直接读取

画布通道

canvasChannel: connected|connecting|offline + canvasPage

决定能否直接下发写指令,避免离线时假装成功

代码语言:javascript
复制
// 只出标量,不新造事件名;取不到即省略该键(不发空串占位)
context() → { canvasChannel: 'connected' | 'connecting' | 'offline', canvasPage: 'view.Fef' }

7.2 智能操作转换:一句话 → 一个可执行动作

图 3 智能操作转换:意图、动作选择、执行共用;入口与出口由外壳决定

08A2UI:两种模式下的补充层

A2UI 不是「第三种 UI」,而是把 Agent 产出编译成可交互界面的补充层 —— 它在两种模式下都生效,用法不同。

能力

对话模式

页面模式

Markdown 渲染

对话正文主体(流式节流)

浮层说明;可「展开到页面」

图表即时绘制

LLM 下发 spec → 前端编译 ECharts option

画进页面容器,替代静态报表

组件树渲染

产物卡 / 设计器预览(.cls 片段)

主界面本身就是 .cls 组件树

HUMAN 交互

对话内确认卡(ConfirmBar)

页面内 armConfirm 或浮层确认卡

无头操作

对话直接下发画布写指令

小助手读页面上下文后调用页面写通道

页面模式里 A2UI 是本体,对话模式里 A2UI 是补充;两者共用同一套渲染能力(令牌 + ood.UI.* + .cls),所以视觉与语义不会分裂。

09chatnext:交互架构与插件体系

9.1 三栏骨架

区域

职责

承载组件

左栏

会话与业务入口(全部 / 待办 / 进行中 / 草稿 / 历史 / 业务域)

ConvoList / Shell

中栏

对话主线:输入 → 流式 → HUMAN → 产出

MessageList / Composer / ConfirmBar / ArtifactBar

右栏

业务侧栏(流程办理台、工具、上下文、工作区)

插件挂载点 + Panels / WorkspacePanel

事件按域拆分并由 Bus + EventStore 分发:stream / tool / phase / human / flow / artifact / agent / collab / docctx / skill / conn。域侧只按事件名分派,不认识具体插件。

9.2 插件体系:一个装配器、五条契约

代码语言:javascript
复制
PluginResolver(profile, options)
  ① profile.plugins[id] × 注册表            → 实例化哪些插件
  ② flagMode: default-on | opt-in | truthy  → profile 字段启用/显隐
  ③ mountPoint(profile 或 ctor.mountSpec)  → 挂到哪个挂载点
  ④ subscribes: [{event, slot, method}]     → 声明式订阅
  ⑤ defaultEnabled                           → 未声明时是否参与装配

插件

目录

作用

BpmContextAdapter

plugins/bpm

把流程 / 节点上下文注入对话

BpmHumanOps

plugins/bpm

委托 / 退回 / 收交 / 办结

BpmViewAction

plugins/bpm

流程视图动作

DesignerCardPlugin

plugins/bpm

设计器产出卡

PropertyCardPlugin

plugins/bpm

属性卡

CompanyPicker

plugins/finance

主体(公司)选择

ConfigPanel

plugins/finance

财务域配置面板

FlowSnapshot

plugins/flow

流程快照渲染

PageChannelBridge

plugins/page

画布通道状态(→ 无头操作)

DynamicGraphicsPlugin

plugins/views

动态图形(spec → 图表)

三个设计取向

① 内核零业务名词:装配器只认 id / mountPoint / subscribes。② 域不认识插件:按事件名双向解耦。③ 缺失即降级:插件未加载只告警一次,主链路照常运行。

9.3 入口档位

同一套内核通过 entryProfile 派生不同产品形态:finance-agent、codeagent-agent、dev-agent、edu-teacher、kb-agent、patent-agent、page-workbench、code-workbench 等,共 16 个档位。差异全部由 profile 声明(启用哪些插件、挂哪些面板、用什么文案),内核不写分支。

10界面实证:七张运行态截图

三栏工作台(3840×2160 原图):左=会话与业务入口;中=对话与输入(模式切换、模型选择);右=「流程办理台」插件面板(300 条流程实例 + 当前节点 + 操作结果)。右栏即插件挂载点,未在 profile 声明的插件不会出现

思考块 + Markdown:推理可折叠,正文按层次呈现

Markdown 表格:口径与明细用表格表达,可直接复制

@执行体:显式指定由谁执行,避免「猜」

工具调用:工具面以白名单暴露,调用过程可见

结果卡:结论 + 依据 + 可下载产物

技能市场:技能可安装与授权,与「C 端能力独立于 UI」一致

11Agent UI 体验七层模型

架构解决「能不能」,体验解决「顺不顺」。七层模型把「顺不顺」拆成可验收项。

L1 输入层Composer多模态 · 上下文徽标 · @执行体 · 中断与重试L2 语义层意图与澄清低置信追问 · 歧义用 CHOICE · 阈值单一真源L3 过程层流式可观测首字节 · 思考折叠 · 工具/阶段 · 可取消 · 失败带原因L4 决策层HUMAN 交互四类交互 · 超时按风险分级 · 红线默认升级人工L5 产出层MD/图表/产物MD 为核心 · source/asOf 强制 · 产物可下载L6 协作层A2A 协作委托台账 · 并行汇聚 · 越域带原因拒绝L7 可信层:事件账本 · 口径来源 · 可复现 · 变更留痕

图 4 七层体验模型:L3–L5 决定「敢不敢用」,L6–L7 决定「能不能规模化」

层

关键设计

度量

L1 输入

上下文徽标、@执行体、流式期可取消

二次补充率 ↓

L2 语义

低置信追问、CHOICE 消歧、阈值分层

澄清命中率 ↑,误切场景 ↓

L3 过程

首字节优先、思考折叠、工具/阶段可见、失败带原因

首字节 <1.5s,静默失败 0

L4 决策

CONFIRM/INPUT/CHOICE/FILE_UPLOAD × AUTO_CONFIRM/AUTO_REJECT/ESCALATE_HUMAN

红线人工介入 ≈100%

L5 产出

MD + 图表即时绘制 + 产物卡;source/asOf 强制

产出采纳率 ↑

L6 协作

委托台账、replyNodeId、AND_SPLIT/JOIN

失败可定位率 100%

L7 可信

EventStore、审计摘要、.oodbak/发布台账

可复现率 ↑

12边界与结论

12.1 边界(设计上不做的事)

边界一:授权约束不交给模型

科室级、字段级、状态级的可见性与可操作性,由业务人员在 B 的 YAML 中可视化配置。让模型生成授权,等于把审计能力交给被审计对象。

边界二:失败必须带原因

UNDELIVERABLE / OP_NOT_IN_DOMAIN / COMPILATION_FAILED 原样透出。静默降级会让两种模式都「对不上」,也就谈不上同源。

边界三:红线不自动放行

涉钱、涉合同、涉对外承诺的节点,即使调用方传了自动确认,超时也按 ESCALATE_HUMAN 处理 —— 这是代码里的约束,不依赖文档约定。

12.2 结论

  1. A/B/C 是按交互链路切的分层,不是按技术栈:A 管看得见、B 管听得懂与不越权、C 管算得对。
  2. C 端先定型,UI 后装配。 只吃结构化入参、只出结构化结果,因此能被对话、页面、A2A、流程节点同时复用。
  3. B 是双模式的唯一汇聚点。 五个接缝里,动作与人工门完全共用,入口与产出由外壳实现,上下文用对象标识与通道状态对齐。
  4. 转换是外壳替换,不是数据迁移。 随行的是业务对象、筛选条件、任务上下文与通道状态;不随行的是滚动位置与草稿。
  5. A2UI 是补充层,不是第三种 UI。 它在页面模式里是本体、在对话模式里是补充,但共用同一套渲染能力。

文中数值与契约来自源码与运行态实测;截图为真实运行环境归档(三栏工作台为 3840×2160 原图)。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

目录
  • 以用户交互为中心的 AI 原生架构
  • 01设计出发点:交互是三层共同的输出
  • 02A/B/C 架构:一表看清三层分工
  • 2.1 三层分工(结论先行)
  • 2.2 为什么是「以用户交互为中心」
  • 一层管「看起来对不对」
  • 一层管「理解与约束」
  • 一层管「算得对」
  • 2.3 依赖方向与不变式
  • 03A 层:两种外壳共用的渲染与协议基线
  • 3.1 A 层提供什么
  • 3.2 A 层提供的组件能力基线
  • 04C 层:能力定型,完全独立于 UI
  • 4.1 六类能力载体
  • 4.2 目录层 ≠ 驻留层
  • 4.3 执行体与界面卡片:只做寻址对齐
  • 05B 层:领域逻辑不变,交互外壳可换
  • 5.1 B 层持有什么
  • 5.2 一份声明,两种投影
  • 5.3 模式选择矩阵
  • 5.4 为什么汇聚点必须在 B
  • 06双模式转换:五个接缝与状态随行规则
  • 6.1 五个接缝(模式差异的全部落点)
  • 6.2 切换时什么跟着走、什么不跟
  • 6.3 双向携带的两个动作
  • 页面 → 对话:带着对象去问
  • 对话 → 页面:展开到页面
  • 共同前提
  • 6.4 转换不变量(换外壳不换语义)
  • 07共享内核:上下文与智能操作转换
  • 7.1 上下文:三级 + 一通道
  • 7.2 智能操作转换:一句话 → 一个可执行动作
  • 08A2UI:两种模式下的补充层
  • 09chatnext:交互架构与插件体系
  • 9.1 三栏骨架
  • 9.2 插件体系:一个装配器、五条契约
  • 9.3 入口档位
  • 10界面实证:七张运行态截图
  • 11Agent UI 体验七层模型
  • 12边界与结论
  • 12.1 边界(设计上不做的事)
  • 12.2 结论
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档