一、背景与概述
1.1 行业困境
随着大语言模型能力的指数级跃升,AI 生成用户界面(UI)代码已从概念验证走向工程化落地。然而,当前主流方案普遍面临三大核心困境:
| 困境 | 表现 | 影响 |
|---|---|---|
| 生成质量不可控 | LLM 自由生成的 UI 代码混用内联样式、原生 DOM 操作与框架特定 API | 样式污染、事件泄漏、行为失控,难以纳入组件化体系 |
| 运行时存在盲区 | 传统生成链路止于静态代码输出,LLM 无法感知浏览器真实渲染效果 | 错误配置反复出现,缺乏自修正能力 |
| 能力边界模糊 | LLM 对组件语义、样式变量体系、事件回调规范理解碎片化 | 需要大量 prompt 工程,维护成本高且通用性差 |
1.2 Ooder UI 的演进方向
上述问题本质上指向同一个需求:让 LLM 从"代码生成器"升级为具备工程审计闭环与运行时感知能力的**"智能 UI 工程师"**。
Ooder UI 正是在这一背景下诞生的------一个注解驱动、四分离合规、支持 LLM-Browser 双向观察的智能 UI 组件生成框架。
更重要的是,Ooder UI 正在逐步向 A2UI 原生的 AI UI 能力靠近:
- 从代码生成到组件原生:不再生成独立的 JavaScript 代码文件,而是直接操作 A2UI 框架的原生组件实例
- 从静态输出到运行时融合:LLM 输出直接映射为组件的 Properties/Styles/Events/Behaviors 配置,与框架运行时无缝集成
- 从单向生成到双向闭环:通过 LLM-Browser 双向观察接口,实现"生成 → 审计 → 运行 → 反馈 → 修正"的完整闭环
- 从 Prompt 工程到注解驱动 :通过
@A2uiSkill、@NlpDescription等注解声明式定义组件能力,减少 prompt 维护成本
1.3 核心设计理念
- 声明式组件定义 :通过
@A2uiSkill注解定义组件能力元数据 - 场景化路由:多场景智能匹配,自动选择最佳处理路径
- 四分离合规:Properties / Styles / Events / Behaviors 维度审计
- 闭环迭代:LLM 生成 → 审计 → 反馈修正 → 运行时验证 → 再生成
1.4 技术栈概览
| 层级 | 技术组件 | 职责 |
|---|---|---|
| 路由层 | StudioChatRouter | 场景匹配与分发 |
| 场景层 | ChatScene 实现类 | 业务逻辑处理 |
| 执行层 | FunctionCallingLoopExecutor | 多轮工具调用循环 |
| 审计层 | NlpModuleAuditor | 四分离合规审计 |
| 观察层 | DebugAgent.js + DebugContextManager | LLM-Browser 双向观察 |
| 知识层 | SkillMdLoader | 知识文件加载与工具注册 |
二、系统架构
下图展示了 Ooder UI LLM Deep 匹配模式的整体架构,从用户输入到最终输出合规代码的完整链路:

2.1 核心组件说明
StudioChatRouter(场景路由器)
文件路径: net\ooder\studio\chat\router\StudioChatRouter.java
负责根据用户输入计算各场景的匹配分数,选择最佳场景处理请求:
javascript
public ChatResponse route(ChatRequest request, ChatContext context) {
ChatScene bestScene = null;
double bestScore = -1;
for (ChatScene scene : scenes) {
if (scene.canHandle(request.getContent(), context)) {
double score = scene.matchScore(request.getContent(), context);
if (score > bestScore) {
bestScore = score;
bestScene = scene;
}
}
}
if (bestScene != null) {
return bestScene.handle(request, context);
}
return null;
}
FunctionCallingLoopExecutor(核心执行引擎)
文件路径: \net\ooder\studio\chat\engine\FunctionCallingLoopExecutor.java
实现多轮 Function Calling 循环,支持结构化和文本模式工具调用解析:
javascript
public static class LoopConfig {
private int maxRounds = 5; // 最大循环轮数
private boolean supportsTextMode = true; // 支持文本模式工具调用解析
private long toolTimeoutMs = 30000; // 单工具超时 30s
private long llmTimeoutMs = 120000; // LLM 调用超时 120s
private long totalTimeoutMs = 180000; // 总超时 180s
}
三、场景体系(ChatScene)
Ooder UI 定义了多种 ChatScene 实现,每种场景针对特定类型的任务进行优化:
| 场景类 | 场景ID | 核心能力 | 匹配关键词 |
|---|---|---|---|
| RadChatScene | rad | RAD 快速构建,NLP 组件生成 | 表单、表格、图表、页面 |
| DeepDesignChatScene | deep-design | 深度设计,四分离审计闭环 | 深度设计、复杂布局 |
| SVGDeepDesignChatScene | svg-deep-design | SVG 矢量设计,图形验证 | 流程图、架构图、拓扑图 |
| BpmChatScene | bpm | BPM 流程设计,节点编排 | 流程、节点、审批 |
| SkillsChatScene | skills | 技能管理,插件扩展 | 技能、插件、安装 |
3.1 RadChatScene 实现解析
文件路径: net\ooder\studio\chat\scene\impl\RadChatScene.java
RadChatScene 是最常用的场景,支持通过自然语言快速构建 UI 组件:
javascript
@Override
public double matchScore(String input, ChatContext context) {
if (context != null && "rad".equals(context.getSceneId())) {
return 10.0; // 已锁定场景
}
String lower = input.toLowerCase();
double score = 0;
// UI 上下文关键词
String[] uiContextKeywords = {"组件", "表单", "表格", "树", "图表", "页面", ...};
for (String kw : uiContextKeywords) {
if (lower.contains(kw)) score += 3.0;
}
// 动作关键词
String[] actionKeywords = {"生成", "创建", "构建", "做一个", ...};
for (String kw : actionKeywords) {
if (lower.contains(kw)) score += 2.0;
}
return score;
}
3.2 DeepDesignChatScene 双阶段闭环
DeepDesignChatScene 实现了双阶段闭环流程:
- 阶段1(自由构建) :LLM 自由发挥生成完整的
ood.Class模块代码 - 阶段2(合规修正):根据四分离审计结果逐项修正,迭代最多 3 轮直到评分 ≥ 80
四、Function Calling 循环机制
FunctionCallingLoopExecutor 是整个 LLM Agent 的核心执行引擎,实现了完整的 Function Calling 多轮循环机制:

4.1 双模式工具调用解析
当 LLM 未返回结构化 tool_calls 时,系统会从文本内容中解析三种格式的工具调用:
| 模式 | 格式示例 | 解析方式 |
|---|---|---|
| XML 格式 | toolName{...} | 正则提取 |
| JSON 代码块 | json {"function":"...", "arguments":{...}} |
JSON 解析 |
| 自然语言 | 调用: toolName,参数: {...} | 模式匹配 |
4.2 上下文压缩机制
当估算 token 数超过 200,000 时,自动压缩中间消息:
javascript
private List<Map<String, Object>> compressMessages(List<Map<String, Object>> messages) {
int estimatedTokens = estimateTokens(messages);
if (estimatedTokens <= 200000) return messages;
// 保留首尾,中间截断为摘要
List<Map<String, Object>> compressed = new ArrayList<>();
compressed.add(messages.get(0)); // system prompt
// 中间消息压缩为摘要
String summary = buildSummary(messages.subList(1, messages.size() - 1));
compressed.add(Map.of("role", "system", "content", "[历史摘要] " + summary));
compressed.add(messages.get(messages.size() - 1)); // 最新消息
return compressed;
}
4.3 可用工具列表
RadChatScene 提供了丰富的工具供 LLM 调用:
| 工具名 | 功能 | 参数 |
|---|---|---|
| nlp_build_component | 通过自然语言生成 UI 组件 | description (组件描述) |
| update_component | 更新组件属性 | alias, properties |
| get_component_template | 获取组件四分离模板 | componentType |
| get_style_template | 获取样式模板 | templateId, componentType, theme |
| get_event_template | 获取事件模板 | templateId, componentType |
| get_advanced_knowledge | 获取高级知识 | topic (event/action/style/annotation) |
五、四分离合规审计系统
NlpModuleAuditor 是 Ooder 框架的四分离合规审计引擎,负责对 LLM 生成的代码进行结构化分析和合规评分:

5.1 四分离维度定义
| 维度 | 英文标识 | 检查内容 | 禁止 API |
|---|---|---|---|
| 属性 (Properties) | propertiesScore | 声明式构建、setHost 绑定 | setHtml, innerHTML |
| 样式 (Styles) | stylesScore | setCustomStyle、CSS 变量体系 | 内联 style 属性 |
| 事件 (Events) | eventsScore | 生命周期钩子、组件事件绑定 | addEventListener |
| 行为 (Behaviors) | behaviorsScore | dataUrl 数据驱动 | setTimeout, 手动 DOM |
5.2 分级约束体系
文件路径: net\ooder\studio\chat\scene\impl\NlpModuleAuditor.java
javascript
public enum ConstraintLevel {
MANDATORY, // 架构红线,必须修正 (扣25分)
RECOMMENDED, // 推荐修正 (扣15分)
ENHANCED // 增强优化 (扣5分)
}
5.3 意图感知权重
根据页面类型动态调整四个维度的权重:
javascript
case PORTAL: return new double[]{0.30, 0.20, 0.20, 0.30}; // 门户:属性和行为权重高
case DASHBOARD: return new double[]{0.20, 0.15, 0.25, 0.40}; // 仪表盘:行为权重最高
case FORM: return new double[]{0.35, 0.15, 0.35, 0.15}; // 表单:属性和事件权重高
case LANDING: return new double[]{0.20, 0.35, 0.20, 0.25}; // 落地页:样式权重最高
5.4 遗忘与降级机制
当组件评分过低时,系统会建议遗忘或降级:
- 遗忘分 < 40 :标记为
ABANDON(建议放弃该组件) - 遗忘分 40-70 :标记为
DOWNGRADE(降级为更简单的组件)
六、LLM-Browser 双向观察接口
当前 Ooder UI 的 LLM 交互能力集中在推理阶段 (NLP解析→配置生成→静态审计),但在浏览器真实运行期存在严重盲区。LLM-Browser 双向观察接口设计旨在解决这一问题,实现完整的闭环。
6.1 现状痛点
| 盲区 | 表现 | 影响 |
|---|---|---|
| 运行时错误不可见 | LLM生成的组件在浏览器中报错,LLM无法感知 | 错误配置反复生成,无法自修正 |
| 虚拟DOM树不可查 | 组件的实际渲染结构LLM无法获取 | 布局/嵌套错误无法定位 |
| 四分离数据不可采 | Properties/Styles/Events/Behaviors运行时实际值LLM无法获取 | 样式偏差/事件失效无法诊断 |
| 样式实际展示不可测 | CSS计算值、布局位置、溢出/遮挡LLM无法感知 | 视觉效果与预期不符 |
| 交互行为不可模拟 | LLM无法模拟点击/输入/拖拽等用户操作 | 交互逻辑无法验证 |
6.2 两条反向路径
路径1: 设计期 --- RAD设计器 → 观察接口 → LLM
在设计器中自动打开组件,通过观察接口获取实际位置/样式/四分离数据,动态返回给LLM供参考和修改
路径2: 运行期 --- LLM → 浏览器插件Skills → 单页面调试
允许大模型通过浏览器插件Skills打开单页面调试,进行动作/行为模拟操作,并设计开放接口体系和知识体系给LLM
6.3 架构总览

6.4 设计期观察接口(路径1)
| 接口名 | 功能 | 返回数据 |
|---|---|---|
| observe_component_tree | 观察组件树结构 | 组件层级、属性、样式、事件、行为 |
| observe_component_layout | 观察组件布局 | boundingRect、computedStyle、overflow |
| observe_four_separation | 观察四分离数据 | Properties/Styles/Events/Behaviors 运行时值 |
| observe_style_computed | 观察样式计算值 | CSS变量实际值、主题色值、字体大小 |
| observe_errors | 收集运行时错误 | JS错误、CSS警告、网络错误、控制台日志 |
observe_four_separation 返回示例
javascript
{
"type": "four_separation",
"alias": "mainForm",
"properties": {
"caption": "用户信息",
"columns": 2,
"dock": "fill",
"editable": true
},
"styles": {
"MAINFRAME": { "background": "var(--ood-bg)", "padding": "16px" }
},
"events": {
"SAVE": { "eventClass": "FormCallBack", "eventValue": "SAVE", "bound": true }
},
"behaviors": {
"SUBMIT": { "actionClass": "CustomFormAction", "actionValue": "SUBMIT", "enabled": true }
},
"discrepancies": [
{ "dimension": "styles", "field": "MAINFRAME.background", "declared": "var(--ood-bg)", "computed": "#ffffff" }
]
}
6.5 运行期调试接口(路径2)
| 接口名 | 功能 | 参数 |
|---|---|---|
| debug_open_page | 打开调试页面 | pageUrl, breakOnErrors, collectMetrics |
| debug_simulate_action | 模拟用户操作 | action (click/input/hover/scroll), target, params |
| debug_inspect_dom | 检查DOM状态 | target, depth, includeStyles, includeEvents |
| debug_collect_errors | 收集运行时错误 | debugSessionId |
| debug_screenshot | 截图捕获 | target, format (base64/description) |
6.6 浏览器端 DebugAgent.js
规划文件路径: ood\js\OODDebugAgent.js
javascript
ood.Class('OOD.DebugAgent', 'ood.Module', {
Instance: {
startCollect: function () {
var self = this;
window.onerror = function (msg, url, line, col, error) {
self.reportError('javascript', {
message: msg, source: url, line: line, column: col,
stack: error ? error.stack : ''
});
};
// ... 更多错误采集
},
collectFourSeparation: function (alias) {
var widget = designer.getByAlias(alias, true);
return {
alias: alias,
properties: widget.properties,
styles: widget.CS,
events: widget.events,
behaviors: widget.actions,
discrepancies: this._findDiscrepancies(widget)
};
},
simulateAction: function (action, target, params) {
var widget = SPA.getWidgetByAlias(target);
switch (action) {
case 'click': widget.$dom.click(); break;
case 'input': widget.setValue(params.value); break;
// ... 更多操作
}
return { success: true, action: action, target: target };
}
}
});
6.7 完整闭环流程

6.8 调试上下文注入 LLM
规划文件路径:debug\service\DebugContextManager.java
javascript
public String buildLlmContextSummary(String sessionId) {
DebugContext ctx = contexts.get(sessionId);
StringBuilder sb = new StringBuilder();
sb.append("## 调试上下文\n");
sb.append("阶段: ").append(ctx.phase).append("\n");
sb.append("页面: ").append(ctx.pageUrl).append("\n");
if (!ctx.errorHistory.isEmpty()) {
sb.append("### 运行时错误\n");
for (RuntimeErrorReport report : ctx.errorHistory) {
sb.append("- [").append(report.getSeverity()).append("] ")
.append(report.getMessage()).append("\n");
}
}
if (ctx.lastTreeSnapshot != null) {
sb.append("### 组件树概要\n");
sb.append("组件总数: ").append(ctx.lastTreeSnapshot.getTotalCount()).append("\n");
}
return sb.toString();
}
6.9 与现有架构的集成
| 集成点 | 集成方式 |
|---|---|
| StudioChatRouter | 在合规审计阶段自动添加观察工具 |
| NlpChatInline | 处理调试工具结果,展示组件树/四分离面板 |
| LlmFallbackStep | 注入调试上下文到回退提示 |
| ClsAuditStep | 审计失败时自动触发设计期观察 |
七、Skill 注解驱动体系
Ooder UI 采用注解驱动的方式定义组件能力元数据,实现声明式的组件注册与发现:

7.1 核心注解定义
@A2uiSkill 注解
文件路径: net\ooder\annotation\skill\A2uiSkill.java
javascript
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE})
public @interface A2uiSkill {
String id();
String name() default "";
String description() default "";
String category() default "data-display";
String[] capabilities() default {};
ModuleViewType moduleViewType() default ModuleViewType.NONE;
ComponentType componentType() default ComponentType.MODULE;
int priority() default 100;
}
@NlpDescription 注解
文件路径: net\ooder\engine\llm\annotation\NlpDescription.java
javascript
@Target({ElementType.TYPE, ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface NlpDescription {
String value(); // 自然语言描述
String[] examples() default {}; // 描述示例
String[] synonyms() default {}; // 同义词
int priority() default 0; // 优先级
}
7.2 Skill 实现示例
TreeGridSkill(表格组件)
文件路径: net\ooder\a2ui\nlp\skill\TreeGridSkill.java
javascript
@Component
@A2uiSkill(
id = "treegrid",
name = "表格",
description = "表格/树表组件,用于展示结构化数据,支持编辑、排序、多级树形结构",
category = "data-display",
capabilities = {"data-display", "crud", "pagination", "tree"},
moduleViewType = ModuleViewType.GRIDCONFIG,
componentType = ComponentType.TREEGRID,
priority = 10
)
public class TreeGridSkill extends AbstractA2uiSkill {
@Override
public List<String> getKeywords() {
return Arrays.asList("表格", "列表", "树表", "数据表", "grid", "table");
}
@Override
public String buildGenJson(String moduleName, String caption,
List<String> fields, Map<String, Object> options) {
// 构建组件 JSON 配置
JSONObject treeGridComponent = new JSONObject();
treeGridComponent.put("alias", "mainGrid");
treeGridComponent.put("type", "TreeGrid");
// ... 配置属性
return buildModuleFromTemplate(moduleName, properties, children);
}
}
7.3 元数据类
运行时通过元数据类封装注解信息,支持 Builder 模式构建:
NlpComponentDesc(组件描述元类)
文件路径: net\ooder\engine\llm\meta\NlpComponentDesc.java
javascript
public class NlpComponentDesc {
private String className;
private String description;
private String[] intents;
private List<NlpFieldDesc> fields;
private List<NlpActionDesc> actions;
// 构建 LLM 提示词
public String toPrompt() {
StringBuilder sb = new StringBuilder();
sb.append("组件:").append(className).append("\n");
sb.append("描述:").append(description).append("\n");
// ... 更多信息
return sb.toString();
}
}
八、知识注入与 Prompt 工程
8.1 SkillMdLoader 知识加载
文件路径: net\ooder\studio\chat\engine\SkillMdLoader.java
SkillMdLoader 负责从 SKILL.md 文件中加载、解析和注册整个技能体系:
javascript
// 知识分为两级
private static final Set<String> BASIC_KNOWLEDGE_FILES = Set.of(
"basic.md", "style-quickref.md", "event-quickref.md", "behavior-quickref.md",
"chart-components.md", "display-components.md", "container-components.md"
);
private static final int MAX_KNOWLEDGE_CHARS = 16000; // 基础知识总长度限制
8.2 Prompt 文件结构
知识文件路径: skills\rad-component-reader\
javascript
skills/
└── rad-component-reader/
├── SKILL.md # 技能定义
├── knowledge/
│ ├── basic.md # 基础知识
│ ├── style-quickref.md # 样式快速参考
│ ├── event-quickref.md # 事件快速参考
│ └── _four-separation.md # 高级知识 (以下划线开头)
└── prompts/
├── deep-design.md # 深度设计提示词
├── rad.md # RAD 提示词
└── intent-recognition.md # 意图识别提示词
8.3 deep-design.md 提示词结构
文件路径:resources\skills\rad-component-reader\prompts\deep-design.md
定义了双阶段闭环流程:
- 阶段1:自由构建 - LLM 自由发挥生成完整代码
- 阶段2:合规修正 - 根据审计结果逐项修正
- ood.Class 模块结构模板
- 复杂布局组件选择指南(门户/仪表盘/落地页/控制台)
- CS Key 快速参考表
- CSS 变量体系参考
九、总结
Ooder UI 的 LLM Deep 匹配模式是一个完整的智能 UI 组件生成解决方案,其核心创新点包括:
- 注解驱动的 Skill 体系 :通过
@A2uiSkill、@NlpDescription等注解声明式定义组件能力 - 多场景智能路由:根据关键词匹配分数自动选择最佳处理场景
- Function Calling 循环:支持多轮工具调用,双模式解析,上下文自动压缩
- 四分离合规审计:从 Properties/Styles/Events/Behaviors 四个维度确保代码质量
- LLM-Browser 双向观察:设计期观察 + 运行期调试,实现完整闭环
- 双阶段闭环迭代:自由构建 → 审计反馈 → 合规修正 → 运行时验证
- 知识分级注入:基础知识始终加载,高级知识按需获取
本文深入解析了 Ooder UI LLM Deep 匹配模式的核心实现,包括注解驱动的 Skill 体系、四分离合规审计、以及 LLM-Browser 双向观察接口设计。通过这些机制,实现了从代码生成到运行时验证的完整闭环。