智能交互新范式:拒绝“黑盒”,带你用 MateChat 与 DSL 构建“高可靠”的 NL2UI 引擎

目录

前言

[一、 架构思考:为什么我们需要一个"中间商"?](#一、 架构思考:为什么我们需要一个“中间商”?)

[二、 核心实现:给 AI 立规矩,教它说"DSL"](#二、 核心实现:给 AI 立规矩,教它说“DSL”)

[三、 渲染引擎:把 JSON 变现为 DevUI 组件](#三、 渲染引擎:把 JSON 变现为 DevUI 组件)

[四、 价值闭环:不仅能看,还能"带走"](#四、 价值闭环:不仅能看,还能“带走”)

[五、 场景演示:MateChat 的"双面"能力](#五、 场景演示:MateChat 的“双面”能力)

[六、 总结与展望](#六、 总结与展望)

前言

大家在做后台系统开发时,有没有遇到过这样的场景?运营同事跑过来说:"我想要个简单的库存报表,这就这几个字段,能不能马上弄好?"

这时候,你看着手头堆积如山的需求,心里可能在想:要是能直接跟电脑说一句"给我个库存表",界面就能自己长出来该多好啊!

这就是 NL2UI (Natural Language to User Interface) 的终极梦想------用自然语言直接生成界面。但说实话,让 AI 直接写 Vue 代码稍微有点"吓人",代码质量不可控不说,改起来还费劲。

今天,我们换个思路。我们不追求一步到位的"全自动",而是基于 华为云 DevUI MateChat 组件,打造一个"受限但绝对可靠"的 UI 生成引擎。

我们会用一套自己定义的 JSON DSL(领域特定语言) 作为中间层,让 AI 做"填空题",而不是"作文题"。这样既利用了 AI 的理解能力,又保证了生成的界面是 100% 可用的。

为了方便大家验证,我把这个引擎的完整代码都开源了。大家可以去 GitCode 仓库 https://gitcode.com/kaminono/MateChatNL2UIEngine 看看源码,或者直接点这个 https://mate-chat-nl-2-ui-engine-components.vercel.app/ 在线体验一下"说话变界面"。

一、 架构思考:为什么我们需要一个"中间商"?

在动手写代码之前,我们得先定个基调。要实现 NL2UI,我们面临两个选择:是让 AI 直接吐出 Vue 代码,还是让它生成一个 JSON 数据?

我们坚定地选择了后者。直接生成代码就像是"开盲盒",你永远不知道 AI 会不会引入什么奇怪的依赖或者写出有安全漏洞的逻辑。

而生成 JSON DSL 就稳妥多了。我们把 DevUI 的组件------比如 d-card、d-form、d-chart------看作是乐高积木。我们只允许 AI 挑选这些积木来搭建页面。

我们可以把整个流程看作一个流水线:

  1. Input : 用户在 MateChat 输入自然语言。
  2. Reasoning : LLM 基于 System Prompt 进行意图识别,转化为标准 JSON。
  3. Parser : 前端引擎拦截消息,正则清洗数据,校验 JSON 合法性。
  4. Render : 递归组件读取 JSON,动态映射为 DevUI 组件。

这种"控制反转"的设计,是我们保证系统高可靠性的基石。

二、 核心实现:给 AI 立规矩,教它说"DSL"

搞定了架构,我们来看看核心代码是怎么实现的。这个引擎的"大脑"在 useNlParser.ts 文件里。

我们需要利用 Prompt Engineering(提示词工程),把我们的 DSL 语法"喂"给大模型。我们得明确告诉它:你只能用白名单里的组件,输出格式必须是标准的 JSON。

看看这段真实的代码,我们在 System Prompt 里做了非常严格的约束:

复制代码
// playground/src/nl2ui-engine/composables/useNlParser.tsconst systemPrompt = ``
`你是一个专业的前端 UI 构建专家。你的任务是将用户的自然语言需求转换为特定的 UI DSL (JSON 格式)。`

`### 🔴 严禁使用不存在的组件!只能使用以下白名单:`
`1. 布局: "d-row", "d-col"`
`2. 容器: "d-card" (必须包含 children), "d-form" (children 必须是 d-form-item)`
`3. 表单项: "d-form-item" (props: label), "d-input", "d-select", "d-button"`
`4. 图表: "simple-stat", "simple-chart"`

`### 输出格式规范 (JSON)`
`必须严格遵守以下 JSON 结构,不要包含 markdown 代码块标记:`
`{`
`  "page": { "title": "页面标题", "layout": "grid" | "default" },`
`  "components": [`
`    {`
`      "component": "d-card",`
`      "props": { "title": "卡片标题" },`
`      "children": [ ... ]`
`    }`
`  ]`
`}`
``;`
`

通过这种方式,无论用户怎么描述需求,AI 最终吐出来的都是我们能看懂、能渲染的标准数据。这就像是给 AI 戴上了"紧箍咒",让它的创造力在规则的轨道上运行。

在实际开发中,LLM 经常会在返回的 JSON 外面包裹 Markdown 标记(如 ```json ... ```)。如果不处理,JSON.parse 必挂。 我们在解析层做了一层"清洗":

复制代码
// 解析逻辑片段`
`const parseResponse = (content: string) => {`
`  // 1. 利用正则提取最外层的 {} 内容,去除废话和 markdown 符号`
`  const jsonMatch = content.match(/\{[\s\S]*\}/);`
`  if (!jsonMatch) return null;`
  
`  try {`
`    return JSON.parse(jsonMatch[0]);`
`  } catch (e) {`
`    console.error("JSON 解析失败,AI 生成了非法格式", e);`
`    // 这里甚至可以触发一个重试机制`
`    return null;`
`  }`
`}`
`

三、 渲染引擎:把 JSON 变现为 DevUI 组件

拿到了 JSON 数据,下一步就是把它变成真实的界面。我们在 DslRenderer.vue 里实现了一个递归渲染器。

这个组件的设计非常巧妙,它利用了 Vue 的 h() 函数和 defineAsyncComponent。我们建立了一个组件注册表,按需加载 DevUI 的组件。

这里有个关键点:对于 AI 可能产生的"幻觉"(比如生成了不存在的组件),我们做了兜底处理。

复制代码
// playground/src/nl2ui-engine/components/DslRenderer.vue// 1. 建立组件白名单映射const componentRegistry: Record<string, any> = {`
`  'd-card': defineAsyncComponent(() => import('vue-devui/card')),`
`  'd-form': defineAsyncComponent(() => import('vue-devui/form')),`
`  'd-input': defineAsyncComponent(() => import('vue-devui/input')),`
`  // ... 其他组件`
`};`

`// 2. 核心渲染函数const renderNode = (node: any): any => {`
`  // 兜底策略:如果 AI 生成了纯文本,直接渲染文本if (typeof node === 'string') return String(node);`

`  let Component = componentRegistry[node.component];`
  
`  // 错误处理:遇到未知组件,渲染一个红框提示,而不是让页面崩溃if (!Component) {`
`    return h('div', { style: 'border: 1px dashed red;' }, `[未知: ${node.component}]`);`
`  }`

`  // 递归渲染子节点const children = node.children?.map(renderNode);`
  
`  return h(Component, node.props, { default: () => children });`
`};`
`

这段代码保证了渲染器的健壮性。哪怕 AI 偶尔"发疯",我们的页面也不会白屏,开发者一眼就能看出是哪里出了问题。

递归渲染树 (The Recursive Magic)是引擎最精妙的地方。因为 UI 结构是树形的(Card 里有 Row,Row 里有 Col,Col 里有 Button),我们的渲染函数必须是递归的。

复制代码
const renderNode = (node: any): any => {`
`  if (typeof node === 'string') return node;`

`  const Component = componentRegistry[node.component];`
`  if (!Component) return h('div', { style: 'color:red' }, `[未知组件: ${node.component}]`);`

`  // 核心:处理 props 和 children`
`  // 1. 透传 AI 生成的属性 (如 label, placeholder)`
`  const props = { ...node.props };`

`  // 2. 递归构建子节点`
`  const children = node.children `
`    ? { default: () => node.children.map(renderNode) } // 插槽形式传递子节点`
`    : null;`

`  return h(Component, props, children);`
`};`
`

这段代码仅用十几行,就实现了理论上无限嵌套的 UI 构建能力。

四、 价值闭环:不仅能看,还能"带走"

如果只能在预览里看,那这个工具充其量只是个玩具。为了让它真正产生价值,我们必须实现"从对话到源码"的闭环。

试想一下,你让 AI 生成了一个复杂的表单,觉得效果不错。这时候,你肯定不想照着预览图再去手写一遍代码吧?

所以,我们开发了 useCodeGenerator.ts。它能把当前的 JSON DSL 逆向编译成标准的 Vue SFC(单文件组件)代码。

复制代码
// playground/src/nl2ui-engine/composables/useCodeGenerator.tsconst generateVueCode = (dsl: UiDsl) => {`
`  // 1. 逆向生成 Templateconst templateBody = dsl.components`
`    .map(node => generateTemplateNode(node, 2))`
`    .join('\n');`

`  // 2. 智能分析依赖,生成 Scriptconst imports = analyzeImports(dsl.components);`

`  // 3. 拼接成完整的 Vue 文件字符串return `<template>`
`  <div class="generated-page">`
`${templateBody}`
`  </div>`
`</template>`

`<script setup>`
`import { ${imports.join(', ')} } from 'vue-devui';`
`</script>`;`
`};`
`

在我们的 Demo 右侧,专门做了一个"查看源码"的 Tab。点击它,你就能复制这段生成的代码,直接粘贴到你的项目里。这才是真正的提效

五、 场景演示:MateChat 的"双面"能力

最后,我们看看这套系统在实际场景中的表现。我们设计了一个"左指令、右预览"的布局。

左边是大家熟悉的 MateChat 聊天窗口,它作为交互的入口。用户在这里输入自然语言,比如"帮我生成一个销售看板,要看总收入和活跃用户"。

MateChat 会显示"正在构建组件树...",几秒钟后,右边的预览区就会实时渲染出一个包含数据卡片和图表的 Dashboard。

如果你输入"创建一个用户注册表单,包含用户名和密码",右侧瞬间就会变成一个带有校验规则的 DevUI 表单。

这种"即问即答、即答即现"的体验,彻底改变了我们构建 UI 的方式。

六、 总结与展望

通过这个项目,我们验证了一个核心观点:受限的 DSL 反而是 AI 落地的最佳路径

我们没有追求让 AI 直接写出完美的代码,而是利用 MateChat 做交互,利用 DSL 做约束,利用 DevUI 做渲染。这套组合拳打下来,既保证了系统的稳定性,又发挥了 AI 的灵活性。

未来,这套架构还有很大的想象空间。比如,我们可以把 DSL 喂给后端,直接生成数据库模型;或者结合语音识别,实现"动动嘴做软件"的科幻场景。

希望这个开源项目能给大家带来一点启发,也欢迎大家来 GitCode 提 PR,我们一起把这个 NL2UI 引擎打磨得更强大!

附官方链接:

DevUI

MateChat - 轻松构建你的AI应用

相关推荐
anyup44 分钟前
🔥牛逼!3分钟生成 5 套主题,还能一键切换暗黑模式!
前端·前端框架·uni-app
进击的明明44 分钟前
深入讨论前端开发中的跨域问题🤔
前端
正在走向自律1 小时前
企业微信消息推送全链路实战:Java后端与Vue前端集成指南
前端·vue.js·企业微信·企业微信消息推送·官方企业微信
_一两风1 小时前
《从一道“诡异”输出题,彻底搞懂 JavaScript 的作用域与执行上下文》
前端·ecmascript 6
CoderJia程序员甲1 小时前
GitHub 热榜项目 - 日榜(2025-11-30)
ai·开源·大模型·github·ai教程
lcc1871 小时前
Vue3 CompositionAPI的优势
前端·vue.js
豆奶特浓61 小时前
谢飞机勇闯Java面试:从内容社区的缓存一致性到AI Agent,这次能飞多高?
java·微服务·ai·面试·架构·缓存一致性·feed流
五号厂房1 小时前
聊一聊前端下载文件N种方式
前端
code_Bo1 小时前
使用micro-app 多层嵌套的问题
前端·javascript·架构