恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
TokUI 给 AI 发明一种语言:用 DSL 打通流式渲染的 UI 语言
首页
资讯中心
/
TokUI 给 AI 发明一种语言:用 DSL 打通流式渲染的 UI 语言
TokUI 给 AI 发明一种语言:用 DSL 打通流式渲染的 UI 语言
发布时间:2026/9/29 20:25:00
1. 当 AI 开始画界面为什么老语言都不够用了你可能已经习惯了让大模型帮你写一段 HTML或者吐一段 JSON 再交给前端组件库渲染。这套流程在“一次性生成”的场景里跑得挺顺但只要你想让界面边生成边显示问题立刻暴露HTML 标签太长Token 烧得心疼JSON 结构一旦被切断整个解析直接崩掉Markdown 倒是能流式输出可它没法表达按钮、表格、表单这些可交互组件。TokUI 想解决的就是这件事——它给 AI 发明了一种专门用来描述 UI 的语言一套面向流式渲染的 DSL。简单说TokUI 是一套 AI 原生的 UI 描述语言用极短的标识符描述组件、属性和嵌套关系解析器能在任意字符位置被切断后继续工作适合大模型逐 Token 输出界面的场景。它适合谁适合正在做 AI 对话产品、智能体界面、实时数据看板并且被“流式渲染 UI”卡住的前端和后端同学。我试过用传统方案硬扛流式 UI让模型输出 JSON前端用增量解析库去补全括号。结果是模型偶尔漏个引号整个界面就白屏换成 HTMLToken 消耗直接翻倍长对话里成本肉眼可见地涨。TokUI 的思路不是改造 HTML 或 JSON而是从 AI 的生成特征出发重新设计语法。这篇文章我会交付一套可复制的 DSL 配置骨架再带你走一遍流式渲染的验证步骤让你能自己跑通“AI 输出界面结构、前端实时解析渲染”这条链路。2. 前置准备拿到 TaoToken 的调用凭证TokUI 本身是 UI 语言和渲染引擎它不负责模型调用。你要让 AI 生成 TokUI DSL得先有一个能稳定调用大模型的入口。这里我用 TaoToken 来做模型接入它的接口兼容主流协议配置成本低适合拿来跑这类生成式 UI 的实验。开始之前你需要准备两样东西一个可用的 API Key以及确认你要调用的模型名称。TaoToken 的 API 地址是https://taotoken.net/api这个地址在配置里会反复用到。API Key 的创建入口在控制台的 API Keys 页面你可以直接访问https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewrite去生成。注意API Key 只在创建时完整显示一次复制后妥善保存。不要把它写进前端代码或提交到公开仓库建议放在服务端环境变量里由后端代理转发请求。如果你还没决定用哪个模型可以先到模型对话页面体验一下不同模型的输出风格入口是https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewrite。对于 TokUI DSL 这种结构化输出建议选指令遵循能力强的模型生成出来的标签闭合和属性格式会更规整。环境上你只需要 Node.js 18 以上以及一个能发 HTTP 请求的终端。下面所有示例我都用 Node.js 写方便你直接复制运行。3. 可复制的 TokUI DSL 配置骨架这一节是核心。我会先给你一份最小可用的 DSL 骨架再解释每个部分为什么这么设计最后给出让模型稳定输出这套 DSL 的提示词配置。3.1 DSL 骨架长什么样TokUI DSL 的写法非常紧凑。一个带标题、文本和按钮的卡片大概是这样[card tt:设备状态 stripe [p tx:当前在线设备 12 台] [btn tx:刷新 clk:refresh v:primary,sm] ]对照一下 HTML 版本同样的结构要写div、h3、p、button加上一堆classToken 数量差了好几倍。TokUI 用tt代表 titletx代表 textclk代表 onclickv代表 variant布尔属性像stripe只写 key 不写值。内容直接跟在标签后面不需要开闭标签成对包裹。3.2 三层结构语法、语义、协议理解 TokUI 要抓住它的三层设计。最底层是 DSL 语法定义组件怎么写、属性什么格式、怎么嵌套。中间层是组件语义定义有哪些组件类型、各自接受什么属性。TokUI 注册了 150 多个组件覆盖基础组件、表格、表单、布局、图表、AI 对话组件和灯箱组件七大类。最上层是协议层定义前后端怎么传输、前端怎么解析、渲染引擎怎么绑定事件。协议层支持三种模式一次性渲染、流式渲染、SSE 连接。我们这篇重点验证流式渲染因为它最能体现 TokUI 的价值。3.3 让模型稳定输出 DSL 的提示词配置模型不会天生就会写 TokUI DSL你需要在系统提示里把语法规则喂给它。下面这份配置可以直接用你是一个 UI 生成器只输出 TokUI DSL不要输出任何解释文字。 语法规则 1. 组件用方括号包裹格式为 [组件名 属性:值 属性:值] 2. 高频属性使用短标识符tttitle, txtext, clkonclick, phplaceholder, vvalue 3. 布尔属性只写 keyreq必填, stripe斑马纹, dis禁用 4. 多值属性用逗号分隔例如 v:primary,sm 5. 文本内容直接写在标签后例如 [p 这是一段文字] 6. 嵌套组件直接写在父组件内部解析器支持隐式闭合 可用组件示例 card, p, btn, table, form, input, chart, progress 输出要求 - 只输出 DSL不要 Markdown 代码块包裹 - 每个组件独占一行便于流式解析 - 不要输出 HTML 或 JSON这份提示词的关键在于“只输出 DSL”和“每个组件独占一行”。前者避免模型夹带解释文字污染解析后者让流式渲染时每一行到达就能立即处理不用等整个结构闭合。3.4 流式请求的代码骨架下面这段 Node.js 代码把 TaoToken 的流式接口和 TokUI 的解析串起来。你可以直接保存成stream-ui.mjs运行const API_URL https://taotoken.net/api/v1/chat/completions; const API_KEY process.env.TAOTOKEN_API_KEY; const systemPrompt 你是一个 UI 生成器只输出 TokUI DSL...; // 填入 3.3 的完整提示词 async function generateUI(userInput) { const resp await fetch(API_URL, { method: POST, headers: { Content-Type: application/json, Authorization: Bearer ${API_KEY}, }, body: JSON.stringify({ model: 你的模型名称, stream: true, messages: [ { role: system, content: systemPrompt }, { role: user, content: userInput }, ], }), }); const reader resp.body.getReader(); const decoder new TextDecoder(); let buffer ; while (true) { const { done, value } await reader.read(); if (done) break; buffer decoder.decode(value, { stream: true }); const lines buffer.split(\n); buffer lines.pop(); for (const line of lines) { if (!line.startsWith(data: )) continue; const payload line.slice(6).trim(); if (payload [DONE]) continue; const json JSON.parse(payload); const delta json.choices?.[0]?.delta?.content; if (delta) { process.stdout.write(delta); // 这里替换成 TokUI 解析器调用 } } } } generateUI(生成一个展示服务器状态的卡片包含标题、在线数量和一个刷新按钮);这段代码做了三件事发起流式请求、按行切分 SSE 数据、把每个增量 Token 交给下游处理。真正接 TokUI 渲染引擎时把process.stdout.write(delta)换成解析器的feed(delta)方法即可。4. 验证请求跑通流式渲染代码写好了接下来验证它是否真的能流式产出可解析的 UI 结构。4.1 运行并观察输出先在终端设置好 Key再运行脚本export TAOTOKEN_API_KEY你的Key node stream-ui.mjs如果配置正确你会看到 DSL 一行一行地打印出来类似[card tt:服务器状态 stripe [p tx:当前在线 12 台] [progress id:load v:35] [btn tx:刷新 clk:refresh v:primary,sm] ]注意观察输出的节奏它不是等所有内容生成完才一次性出现而是逐行、逐段地冒出来。这就是流式渲染的基础——每个组件行到达时解析器就能立即处理并交给渲染引擎。4.2 验证增量更新指令TokUI 有一个很实用的upd指令用来更新已渲染组件的属性不需要重绘整个界面。你可以在提示词里追加一句“生成一个进度条然后用 upd 指令把进度从 35 更新到 67”观察模型输出[progress id:load v:35] [upd id:load v:67]前端解析到upd时只更新id为load的组件属性值。这个机制让实时数据推送变得很轻——股票价格变动、设备状态刷新、订单进度推进都只需要发一条极短的指令。4.3 验证容错能力TokUI 解析器内置了隐式闭合机制。你可以故意构造一段不完整的 DSL 来测试[card tt:测试 [p tx:第一段] [p tx:第二段第二个p标签没有闭合。在 HTML 里这可能导致结构错乱但 TokUI 解析器会在遇到新的同级标签或流结束时自动补全。你可以在解析器里加一行日志确认它没有抛异常而是正常输出了两个段落组件。4.4 成功结果的判断标准一次成功的流式渲染验证应该满足三个条件第一DSL 逐行到达时解析器不报错第二界面组件随 Token 到达逐步出现而不是最后一次性刷新第三upd指令能正确更新指定组件的属性。三条都通过说明你的 TokUI 流式链路已经打通。5. 本篇常见错误排查跑不通的时候大概率是下面几个问题之一。模型输出夹带了 Markdown 代码块。表现是解析器收到text这样的行直接报错。原因是系统提示里没有明确禁止代码块包裹。解决办法是在提示词里加一句“不要用 Markdown 代码块包裹输出”并且在解析器里对开头的行做过滤。流式数据被截断导致 JSON 解析失败。表现是JSON.parse抛异常。这通常是因为 SSE 数据按\n切分时某一行还没接收完整就被处理了。注意上面代码里buffer lines.pop()这一行它把最后一段不完整的行留到下一轮这是处理流式 SSE 的标准做法别省掉。API 返回 401 或 403。检查TAOTOKEN_API_KEY是否设置成功以及请求头里Authorization的格式是不是Bearer加 Key。如果 Key 是在控制台刚创建的确认没有多余空格。模型不按 DSL 格式输出。表现是返回自然语言或 HTML。这多半是模型选择问题指令遵循弱的模型对自定义语法的遵守度差。换一个指令遵循能力强的模型或者把提示词里的语法规则再精简、再强调“只输出 DSL”。组件不渲染但解析没报错。检查组件名是否在渲染引擎的注册表里。TokUI 注册了 150 多个组件但如果你用了未注册的组件名解析器可能静默跳过。对照组件文档确认名称拼写。流式输出卡住不动。检查stream: true是否设置以及服务端是否支持流式。另外确认读取循环里没有阻塞操作reader.read()是异步的别在里面做同步耗时计算。6. 把 TokUI 接进你的 AI 产品走到这里你已经有了可复制的 DSL 骨架、可运行的流式请求代码以及一套排障清单。接下来就是把它接进真实产品。如果你主要在做长期编码和智能体方向需要更稳定的调用配额和更完整的工程支持可以了解一下 Coding Plan入口在https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewrite。接入过程中遇到协议细节问题接入文档在https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewrite里面有完整的接口说明和参数对照。我的建议是先把上面那段stream-ui.mjs跑通确认 DSL 能逐行产出再去接 TokUI 的渲染引擎。很多同学一上来就搭完整前端结果解析层的问题和渲染层的问题混在一起排查起来很痛苦。分层验证先通链路再调样式会省下大量时间。