ZorvAI · GenUI 技术构架与功能介绍
版本:v1.0.89 / 2026-09-12 开源地址:github.com/Quor-a/Zorv... 本文基于当前源码(commit
1fefa2f)编写,覆盖「全屏 GenUI 模式」与「返回 ZorvAI 对话框」修复后的真实架构。
一、GenUI 是什么
GenUI 是 ZorvAI 内置的**「生成式界面」(Generative UI)**能力:用户用一句话下指令,AI 不只是回一段文字,而是 直接生成一整个可交互的 HTML 界面(仪表盘、卡片、表单、图表、工具面板......),整屏即 AI 的回复。
它在 ZorvAI 里有 两条集成路径,二者共享同一套渲染引擎与工具系统,但承载位置不同:
| 路径 | 承载位置 | 入口 | 状态 |
|---|---|---|---|
| ① 全屏模式 | 与文本对话框平级的整屏生成器 | QuroGenUiApp / GenScaffold |
主推,本文重点 |
| ② Surface 变体 | 嵌在普通对话里的画布 | GenUiSurfaceScreen + QuroChatViewModel.generateGenUi |
历史兼容,已并入主对话管线 |
切换方式:对话框控制条把会话类型切到 genui → QuroMainScreen 改挂 QuroGenUiApp 全屏界面。
二、整体架构总览
模块边界铁律 :genui 是被 app 依赖的库模块,绝不能反向依赖 app 。跨模块一律用 函数型回调 / 接口 (genui 声明、app 实现),例如 onPushToChat: (html, title) -> Unit, GenUI 不 import QuroChatViewModel。
三、分层文件索引
入口与界面壳
genui/app/QuroGenUiApp.kt------ 全屏模式根 Composable,含设置子页路由(灵魂/记忆/权限/模型/设置)。genui/app/ui/shell/GenScaffold.kt------ 核心界面壳:画布状态机(决策/工具/等待/渲染/完成/失败)、思考时间线、 界面栈、历史浏览、三种原生叠加层(XML / Compose / Canvas)。generate()启动AgentLoop,onDone触发回写。
智能体主循环
genui/app/agent/AgentLoop.kt------ 两阶段 Agent 循环(决策轮 + 渲染轮),结构化事件流AgentEvent。genui/app/agent/Soul.kt------ 灵魂卡(AI 自动孵化的人格 + 视觉签名),注入渲染轮提示词。genui/app/agent/AgentMemory.kt------ 记忆库,委托QuroMemoryRepository(group=genui)。genui/app/agent/ToolGate.kt------ GenUI 权限策略存储(L1--L5),落点SharedPreferences("quro_genui_toolgate")。genui/app/agent/tools/ZorvToolAdapter.kt------ 工具适配层,把工具整体对接 ZorvAI 完整工具系统。genui/app/agent/tools/BuiltinTools.kt------ GenUI 原生私有小工具集(已弃用,保留参考)。
模型与协议
genui/app/llm/LLMClient.kt/FastClient.kt------ 主模型通道 / 快速模型预检通道。genui/app/llm/Prompts.kt------ 系统提示词(灵魂 + 记忆索引 + 界面历史 + 输出契约)。genui/app/llm/ProviderPresets.kt------ 供应商预设。genui/app/store/GenStore.kt/ModelProvider.kt/QuroGenUiBridge.kt------ 本地存储 + 模型配置桥(←QuroModelConfigRepository)。genui/app/store/Protocol.kt------ 协议枚举(OPENAI / 其他)。
渲染引擎
ui/genui/GenUiCanvas.kt------ 端上唯一渲染责任 :WebView +__moHostMoBridge,流式document.write。genui/app/render/A2UIRenderer.kt------ A2UI 渲染器(忠实移植)。genui/app/render/XmlLayoutRenderer.kt/ComposeDescRenderer.kt/CanvasNativeView.kt------ 三种原生通道渲染。genui/app/render/RenderChannel.kt/RuntimeRegistry.kt/CodeLangRegistry.kt------ 渲染通道分派、运行时注册、代码语言。
返回 ZorvAI 对话框(修复后)
ui/QuroChatViewModel.kt------pushGenUiHtmlToChat(html, title):把 HTML 包成 ```````miniapp```` 围栏写入当前会话。ui/QuroMainScreen.kt------ 传 lambdaonPushToChat = { html, title -> chatVm.pushGenUiHtmlToChat(...) }。
四、生成时序(决策轮 + 渲染轮)
决策轮 (provider.protocol == OPENAI 才启用 function calling):
- 系统提示强制「禁止写 HTML,只决定工具调用 / 回
NO_TOOLS」。 - 工具轮数不腰斩:模型想查多少轮查多少轮,靠两道安全闸兜底------ ① 死循环检测(完全相同 tool+args 重复达到阈值);② 很宽松的总时长上限。
- 工具结果回填上下文;模型自行收尾后进入渲染轮。
渲染轮(流式、不带 tools):
- 全部上下文(含工具结果)折成 user 备注交给模型,逐字输出
<!DOCTYPE html>文档。 - 流式增量经
onHtmlDelta实时document.write到GenUiCanvas(截断在标签中间也安全)。 - 灵魂卡视觉签名在此轮注入,决定 UI 美学方向。
- 完成
document.close(),onDone(full, title)出口。
五、工具委派:对接 ZorvAI 完整工具系统
早期 GenUI 全模式用私有 BuiltinTools(~30 个小工具,与 ZorvAI 主对话是两套孤岛)。现已整体替换为 ZorvToolAdapter,对外暴露与 BuiltinTools 同形成员(declarations / execute / gateFor / gate / memory), AgentLoop 仅一行改动(BuiltinTools → ZorvToolAdapter),决策轮/渲染轮逻辑零改动。
- declarations() →
QuroToolRegistry.coreSpecs():主对话默认下发的完整工具集 (终端 / ACI / MCP / CMS / Linux 环境 / 屏幕控制 / 文件 / 记忆 / 经验 / 动态 UI 等)。 - execute(name, args) →
QuroToolCall→QuroToolEngine(registry).execute(...):droid-mcp 派发, 复用主对话同一套真实工具实现。 - 权限 :真正执行由
QuroToolEngine内的QuroPermissionHolder把关(与主对话一致),ZorvGate对决策轮一律放行,避免双重弹窗;GenUI 的ToolGate(L1--L5)保留作「权限设置屏」数据落点,grantAlways把偏好固化到共享 SP。 - 记忆 :仍用已对接的
AgentMemory(→QuroMemoryRepository,group=genui)。
六、三子系统对接 ZorvAI 共享存储
GenUI 设置页的「记忆库 / 工具权限 / 模型服务」三个子系统,已从 GenUI 私有存储迁到 ZorvAI 共享域:
| 子系统 | 原存储 | 现对接 | 隔离/落点 |
|---|---|---|---|
| 记忆库 | filesDir/gen/* |
QuroMemoryRepository |
group=genui 隔离,确定性 id=genui:<key> |
| 工具权限 | gen/toolgate.json |
SharedPreferences("quro_genui_toolgate") |
审计日志仍文件式 gen/audit.jsonl |
| 模型服务 | GenUI 私有 GenStore | QuroModelConfigRepository |
固定 id=quro_main,与文本对话共用同一份配置 |
设计原则:三处均保持公共 API 签名不变 ,仅改底层落点,降回归风险。 ⇒ GenUI「模型服务」页直接编辑全应用共用的那份模型配置,不再需要进 GenUI 单独加供应商。
七、返回 ZorvAI 对话框(本次修复核心)
问题 :GenUI 全屏生成完成后,整屏 HTML 只进自身画布 / 界面栈,从不回写 ZorvAI 文本对话框。 用户要的是「生成的东西出现在普通对话里,能翻回来看、能点开」。
修复 (GenScaffold.onDone → onPushToChat(full, title)):
- 用 ```````miniapp```` 围栏包裹整屏 HTML,写一条
MsgBlock.MiniApp气泡------复用既有小程序 WebView 渲染通路。 - 关键技巧:裸 HTML 会被
parseBlocks的isFullHtmlDocument误判成Code("html")代码块(不渲染), 必须加miniapp围栏才能走MiniAppWebView真实渲染。 - 跨模块用函数型回调:
onPushToChat: (html, title) -> Unit(GenScaffold/QuroGenUiApp声明,QuroMainScreen用 lambda 桥接chatVm.pushGenUiHtmlToChat,chatVm是:app内 QuroApp 单例)。
已知取舍:MiniApp 气泡 WebView 不含 GenUI 的
/assets/runtimes(echarts/three...)与__moHostMoBridge, 图表库/设备桥在气泡内可能不生效(HTML 结构仍渲染)。全屏画布仍是完整体验面,对话框气泡是「返回/预览」。 「一层一层」流式增量回写未做(onDone 一次性回写整屏)。
八、功能清单
生成能力
- 一句话生成完整可交互 HTML 界面(仪表盘 / 卡片 / 表单 / 图表 / 工具面板)。
- 两阶段 Agent:自主调研(工具调用)→ 流式渲染,工具轮数不腰斩。
工具与能力
- 复用 ZorvAI 完整工具系统:终端、ACI、MCP、CMS、Linux 环境、屏幕控制、文件、记忆、经验、动态 UI。
- 灵魂卡人格 + 视觉签名注入,决定生成界面的美学风格。
界面与交互
- 画布状态机:决策 / 调用工具 / 等待授权 / 绘制 / 完成 / 失败,实时状态行。
- 思考时间线:决策与工具全过程结构化呈现,含参数、耗时、结果摘要。
- 界面栈:多次生成可翻看的历史浏览。
- 三种原生叠加层:XML / Compose / Canvas(AI 声明通道时在画布上叠真实原生渲染)。
- 深色模式:画布背景随
darkMode(#0F1115/#FCFAF5)。
设置子系统(已对接共享存储)
- 灵魂 / 记忆库 / 工具权限 / 模型服务 四个单字直达设置页。
- 模型服务与文本对话共用同一份配置。
与对话框联动
- 全屏生成结果回写 ZorvAI 对话框为 MiniApp 气泡(可翻看、可点开)。
- 历史界面可从界面栈或对话框气泡回放。
九、版本与发布
- versionName
1.0.89/ versionCode1089 - 构建风味
full(含 MNN / llama.cpp 本地推理引擎,Release 签名) - 桌面 APK:
ZorvAI_v1.0.89_full-release.apk - Release:github.com/Quor-a/Zorv...
- 下载:github.com/Quor-a/Zorv...
- 源码:github.com/Quor-a/Zorv...
十、已知取舍与后续
- MiniApp 气泡运行时不完整 :气泡 WebView 不含 GenUI
/assets/runtimes与 MoBridge, 图表库/设备桥在气泡内可能不生效。若要 1:1 还原,需让气泡复用GenUiCanvas资产加载器。 - 流式增量回写未做 :
onDone一次性回写整屏,未实现「一层一层」流式返回对话框。 - 模块边界 :
genui库模块不得反向依赖app,跨模块一律函数型回调/接口。 - Surface 变体 :
GenUiSurfaceScreen已并入主对话管线,作为历史兼容保留。