Intelligent UI:把 DSH 长回答变成可本地交互的声明式卡片

前言

在 DeepSeek Harness(DSH)里,模型往往一次吐出并列参数、步骤对比、表格或图表说明,读者只能顺着长段落自己扫读、脑内重组。生成式界面(Generative UI)的思路是:让模型写一份声明式 spec,客户端按 spec 渲染成卡片,拖动、切换在浏览器本地完成,只有用户点提交才把结果作为普通消息送回模型。an-an-618/dsh-intelligent-ui 是面向 DSH 的客户端插件:Host 把 spec 编译成纯 JSON program,Client 用不执行模型代码的解释器渲染,并通过 presentationMeta 挂到 toolview 与 turnTail。下面介绍它解决什么问题、怎么装、怎么用。

这是什么

维护者 an-an-618,分类为 客户端。一句话定位(README):模型写声明式 spec,Host 编译成 JSON program,Client 解释器在本地维护状态并渲染交互卡片;显式提交才回传,本地操作不消耗 token。

架构借鉴社区实现 @comeonzhj/dsh-intelligent-ui 的分层(声明式 spec、宿主编译、presentationMeta、toolview + turnTail、本地交互、显式提交),但 v4 起不执行任何模型生成的 JavaScript,只解释 Host 编译出的纯数据 program。

当前包版本 6.5.0(package.json),许可证 MIT,要求 DSH >=0.2.1-rc.2。

核心功能

两个工具

工具 用途 提交
render_ui 交付卡:信息、表格、图表、参数预览;卡片即回答,调用后停下 无提交按钮;滑块/开关只驱动卡片内部展示
ask_with_ui 提问卡:需要确认、选择或填写参数,并把结果交回模型 底部一个提交按钮,可带可选备注

二者都接受 spec 对象,或紧凑 JSON 文本 source(二选一)。source 适合长卡片:流式阶段工具行先出现只读预览,控件逐步出现;settle 后由 turnTail 渲染完整可交互卡片,编译产物与对象模式一致。

提交回模型的是普通用户消息,例如:

[Intelligent UI] Team plan estimate
- seats: 10
- yearly: on
note: 4 月开始,需要发票

spec 能表达什么

spec.controls 是递归节点树,容器最多 4 层、整卡 120 个节点。布局含 section、box、row、columns、grid、tabs、list 等;展示含标题、表格、键值、步骤条、代码块、迷你折线、图片等;交互含滑块、开关、下拉、输入、评分、choice 等;图表支持 bar、line、area、pie、donut、scatter、heatmap,带 id 的部分图表可点击 category 并提交。

表达式写作 {= 表达式 }(旧写法 {{ }} 编译器仍接受,但系统提示词里不得出现双花括号,否则 DSH 会当成模板变量导致每轮失败)。控件与字段限制见仓库 CONTRACT.md 与 Host 系统提示词段。

系统提示词默认 应出尽出:回答里只要有并列信息、参数、步骤、对比、数据、表格、图表、代码或可调选择,就优先出卡片;纯文字留给一句话事实和闲聊。可通过配置改为平衡模式(见下文)。

Host 与 Client 分工

文件 作用
index.js Host:注册工具、编译 spec、挂系统提示词
client.js 浏览器半体:解释 program、本地状态、提交、turnTail
lib/compile.js 等 编译、表达式 AST(不 eval)、控件目录与校验

安装与启用

插件以当前 DSH 进程权限运行;安装前建议浏览 GitHub 仓库 源码与 MIT 许可证。DSH 生态是「一切皆插件」;SkillHub 目录页 等社区站点与 DeepSeek / 幻方无官方从属关系,索引源需自行添加。

从插件市场安装(推荐)

  1. 打开「插件 → 发现」,在索引源里添加:
https://cdn.jsdelivr.net/gh/an-an-618/dsh-intelligent-ui@main/market/index.json
  1. 搜索 Intelligent UI 或「智能界面」,安装后 重启 DSH。索引指向固定 commit,安装可复现。

直接安装(固定 commit)

plugin_manager(action: "install_bundle", target: "git+https://github.com/an-an-618/dsh-intelligent-ui.git#289674809a88fbd347f0e3c2f0c12f3b8b3ae807")

安装后重启 DSH 生效。

从本地目录安装(开发)

plugin_manager(action: "install_bundle", target: "/absolute/path/to/intelligent-ui")

开发者在装进 desktop 前可先跑自检,并在隔离 profile 或新会话试一轮,确认无 turn/end error:

node scripts/check.mjs

移除 bundle:

plugin_manager(action: "remove_bundle", target: "@an-an-618/dsh-intelligent-ui")

配置

cordis.patch.yml 中常见项:

设置 默认 说明
prompt true 是否把 spec 说明挂到系统提示词
language zh 工具描述与 ask 默认按钮语言(zh / en)
outputPolicy cards-first cards-first 应出尽出;balanced 仅在结构化回答时优先卡片
imageHosts [] 图片主机白名单;空表示不限制主机
allowHttpImages false 默认仅 https:// 图片;私有地址永远拒绝

改 outputPolicy 后需重新加载插件(移除再安装或重启 DSH)。若环境提供 Settings 服务,可在 插件 → 智能界面 页面切换「应出尽出 / 平衡模式」并保存到 profile patch。

典型用法

先做一张带本地计算的交付卡,模型调用 render_ui 并传入如下结构的 spec(节选自 README):

{
  "spec": {
    "title": "Team plan estimate",
    "description": "每月约 ${= seats * 29 },按年付 ${= seats * 29 * 12 }/年",
    "state": { "seats": 8, "yearly": true },
    "controls": [
      { "kind": "heading", "text": "席位与周期" },
      { "kind": "slider", "id": "seats", "label": "席位数", "min": 1, "max": 50, "step": 1 },
      { "kind": "switch", "id": "yearly", "label": "按年付费" },
      { "kind": "stat", "label": "预计月费", "value": "${= seats * 29 }", "hint": "不含税" },
      { "kind": "chart", "chart": "bar", "categories": ["Q1", "Q2", "Q3", "Q4"],
        "series": [{ "name": "收入", "values": [12, 18, "{= seats * 2}", "{= seats * 3}"] }], "height": 180 }
    ]
  }
}

需要用户确认参数并回传时,改用 ask_with_ui,对交互控件可加 "required": true;提交前会校验当前可见必填项,不满足则不发送并在字段旁提示。

嵌套布局示例(section / row / columns):

{
  "kind": "section",
  "title": "季度概览",
  "children": [
    { "kind": "row", "children": [
      { "kind": "stat", "label": "收入", "value": "$12,480" },
      { "kind": "badge", "text": "**+12%**", "tone": "success" }
    ] },
    { "kind": "columns", "columns": [
      { "children": [{ "kind": "chart", "chart": "area", "categories": ["Q1","Q2","Q3"], "series": [{ "values": [12, 18, 24] }] }] },
      { "children": [{ "kind": "keyValue", "items": [{ "label": "客户", "value": "Acme" }] }] }
    ] }
  ]
}

经过上面的步骤,同一轮对话里卡片可承载科目、难度、选项与开始按钮;选择在本地完成,提交后作为一条普通用户消息继续对话。

适用场景与注意

适合希望在 DSH 对话里把结构化回答变成可扫读、可微调的界面,又不想为每次交互多烧 token 的开发者与用户。render_ui 适合展示与预览;需要回传选择或参数时必须用 ask_with_ui。

已知限制(README):

  • 工具调用行只显示摘要;完整可交互卡片在本轮末尾 turnTail。追问请用卡片本身或 ask_with_ui。
  • 卡片草稿存在当前标签页 sessionStorage,刷新可恢复;换会话、关标签或提交成功后不保留。
  • 表达式仅算术、比较、逻辑、三元与 item.field 一级属性,无函数、循环或数组索引。
  • 流式预览只读:控件禁用、无提交、无 required 校验;完整交互等最终卡片。
  • 不支持 HTML、原始 CSS、事件回调;图片与链接仅 http/https。

开发与回归可零依赖运行:

node test/host.test.mjs
node test/client.test.mjs

结尾

dsh-intelligent-ui 把「一段文字」拆成「文字 + 声明式卡片」:Host 编译、Client 本地解释、显式提交才回模型。安装走市场索引或 plugin_manager 固定 commit;行为与策略在 cordis.patch.yml 与插件设置页可调。

羽毛球分组比赛记分
小程序二维码

欢迎使用《羽毛球分组比赛记分》微信小程序

小夜