OpenTiny 是面向企业级场景的前端 AI 应用一体化开发平台。包括AI对话组件、生成式UI、WebMCP SDK等面向AI智能化场景的项目,可以帮助企业项目搭建业务场景的智能助手,增强大模型显示与交互效果,让用户使用自然语言即可帮助完成页面操作。
受益点: 通过本次实操,开发者可以了解Web场景便捷集成MCP工具实现精准AI操作,使用GenUI SDK丰富AI可视化交互方式。
体验点:
- 通过码道结合OpenTiny智能化Skill,集成Next SDK,使用标准WebMCP协议与Skill能力让AI扩展更多能力,实现自然语言智能操作。
- 体验生成式UI,通过丰富的UI界面进行AI交互。 本手册将通过四步实操,为现有 Vue 3 + Vite 业务应用添加 TinyRobot Chat、 GenUI SDK、业务 WebMCP 与 WebSkills,以及 PageTool。
实践效果如下:
本手册将通过四步实操,为现有 Vue 3 + Vite 业务应用添加 TinyRobot Chat、GenUI SDK、业务 WebMCP 与 WebSkills,以及 PageTool。
环境准备
- 码道 Agent 开发工具。
- 安装
opentiny-next-app-integrationSkill- 安装命令:
npx skills add opentiny/agent-skills --skill opentiny-next-app-integration
- 安装命令:
- Node.js 与 pnpm。
本手册使用 codelabs-demo 项目 作为示例 Demo。
codelabs-demo 是一个基于 OpenTiny Vue 的电商管理后台系统,主要提供:
- 概览大盘,展示销售额、库存量和待处理价保等业务指标;
- 库存、订单和价保管理,支持新增入库、订单搜索与状态筛选、价保申请与审批等
图例:电商管理系统-概览大盘
图例:电商管理系统-库存管理
在 Windows、Linux 或 macOS 终端中执行以下命令,获取并启动示例项目:
npx --<span>yes</span> degit opentiny/community-resources/events/hc-2026/codelabs-demo codelabs-demo
<span>cd</span> codelabs-demo
pnpm install
pnpm dev
完成本手册的四步实操后,开发者可以在 codelabs-demo 中:
- 打开 TinyRobot 对话框,选择已配置的模型并进行对话;
- 启用 GenUI SDK,让模型返回结构化、可交互的界面;
- 使用自然语言按订单号、客户或状态查询订单,并查看订单详情;
- 让 AI 导航到订单管理页面,完成的页面查询。
Step 1:添加 TinyRobot Chat
发送如下指令给 Agent
/opentiny-next-app-integration 为当前项目添加 TinyRobot Chat。
Agent 完成代码接入后,根据项目中的 .env.example,在本地 .env 中填写准备使用的模型 Key,例如:
VITE_DEEPSEEK_API_KEY=<你的 DeepSeek API Key>
# 或
VITE_ALIYUN_DASHSCOPE_KEY=<你的 Aliyun DashScope API Key>
如果还没有模型 Key,可以参考 DeepSeek API Key 获取指引 或 Aliyun DashScope API Key 获取指引 完成申请。
配置完成后,你能看到业务页面中出现 TinyRobot 对话入口。打开对话框后可以选择已配置的模型,发送消息并能接收模型回复。
Step 2:集成 GenUI SDK
集成 TinyRobotChat 后发送:
/opentiny-next-app-integration 在当前 TinyRobot Chat 中集成 GenUI SDK。
Agent 完成后,在本地 .env 中填写 GenUI SDK 服务地址和 Prompt ID:
# 下面是 TinyRobot 产品态的 VITE_GENUI_URL 和 VITE_GENUI_PROMPT_ID
VITE_GENUI_URL=https://chat.bytedev.site/api/v1/ai/prompt/chat/completions
VITE_GENUI_PROMPT_ID=f6a112c8ac8160211886e5eeffcfd037
完成后你能看到 Sender 底部工具多出了 GenUI SDK 功能按钮。可以发送提示词让AI生成可交互的UI回复。
下图示例的提示词:
我想定制一个今天运动的清单,请给我一个交互界面:用开关(Switch)让我选择‘是否去健身房’。用单选框(Radio)让我选择‘跑步、游泳、瑜伽’中的一项。用一个滑动条(Slider)让我选择今天预计运动的分钟数(范围 0 到 120 分钟)。
Step 3:接入 WebMCP 与 WebSkills 基础设施
发送如下指令给 Agent:
/opentiny-next-app-integration 为当前项目接入第三步 WebMCP 与 WebSkills 基础设施。
Agent 完成后,会把页面通过 document.modelContext 注册的工具连接到 TinyRobot,并加载 src/skills/**/SKILL.md 中的业务说明。
基础设施接入完成后,开发者需要补充两部分代码:
- 注册MCP工具:在对应 Vue 页面挂载时,通过
document.modelContext.registerTool()注册当前页面提供的能力;页面卸载时使用AbortController注销,避免模型继续看到已经不可用的工具。 - 编写业务 Skill:在
src/skills/<业务名>/SKILL.md中说明这些工具何时使用、如何传参以及怎样处理结果。
注册MCP工具
工具名称、参数和执行逻辑由开发者根据真实业务定义。Agent 不根据页面字段、按钮或示例工程自行生成业务工具。
注册工具时需要提供:
name:稳定且唯一的工具名;description:工具用途、适用条件和限制;inputSchema:参数名称、类型、必填项和枚举值;execute:调用现有业务状态或服务,并返回真实结果。
比如 codelabs-demo 在 src/views/orders/index.vue 中,注册如下两个工具
| 工具 | 输入 | 作用 |
|---|---|---|
| `order_query` | 可选订单号、客户姓名和订单状态 | 查询订单列表,并同步页面筛选条件 |
| `order_detail` | 必填完整订单号 | 查询详情,并将页面列表定位到该订单 |
下面示例代码也可以在 registerTool.ts 查看
<span>import</span> { nextTick, onMounted, onUnmounted } <span>from</span> <span>'vue'</span>
<span>type</span> <span>OrderQueryInput</span> = {
orderId?: <span>string</span>
customerName?: <span>string</span>
status?: <span>OrderItem</span>[<span>'status'</span>]
}
<span>const</span> abortController = <span>new</span> <span>AbortController</span>()
<span>onMounted</span>(<span>() =></span> {
<span>const</span> modelContext = (<span>document</span> <span>as</span> <span>any</span>).<span>modelContext</span>
<span>if</span> (!modelContext?.<span>registerTool</span>) <span>return</span>
modelContext.<span>registerTool</span>(
{
<span>name</span>: <span>'order_query'</span>,
<span>description</span>: <span>'查询订单列表,可按订单号、客户姓名或状态筛选;不传参数时返回全部订单。'</span>,
<span>inputSchema</span>: {
<span>type</span>: <span>'object'</span>,
<span>properties</span>: {
<span>orderId</span>: {
<span>type</span>: <span>'string'</span>,
<span>description</span>: <span>'订单号,如 ORD-5X9A2B'</span>,
},
<span>customerName</span>: {
<span>type</span>: <span>'string'</span>,
<span>description</span>: <span>'客户姓名,支持模糊匹配'</span>,
},
<span>status</span>: {
<span>type</span>: <span>'string'</span>,
<span>enum</span>: [<span>'Pending'</span>, <span>'Shipped'</span>, <span>'Delivered'</span>, <span>'Refunded'</span>, <span>'Cancelled'</span>],
<span>description</span>: <span>'订单状态'</span>,
},
},
},
<span>execute</span>: <span>async</span> ({ orderId, customerName, status }: <span>OrderQueryInput</span>) => {
<span>const</span> normalizedOrderId = orderId?.<span>trim</span>().<span>toLowerCase</span>()
<span>const</span> normalizedCustomerName = customerName?.<span>trim</span>().<span>toLowerCase</span>()
<span>const</span> result = orderList.<span>value</span>.<span>filter</span>(<span>(<span>order</span>) =></span> {
<span>const</span> matchesOrderId = !normalizedOrderId || order.<span>id</span>.<span>toLowerCase</span>().<span>includes</span>(normalizedOrderId)
<span>const</span> matchesCustomerName =
!normalizedCustomerName || order.<span>customerName</span>.<span>toLowerCase</span>().<span>includes</span>(normalizedCustomerName)
<span>const</span> matchesStatus = !status || order.<span>status</span> === status
<span>return</span> matchesOrderId && matchesCustomerName && matchesStatus
})
filterStatus.<span>value</span> = status ?? <span>''</span>
searchText.<span>value</span> = orderId?.<span>trim</span>() || customerName?.<span>trim</span>() || <span>''</span>
<span>const</span> text =
result.<span>length</span> === <span>0</span>
? <span>'未找到符合条件的订单。'</span>
: <span>`找到 <span>${result.length}</span> 条订单:\n<span>${result
.map(
(order) =>
<span>`- <span>${order.id}</span>|<span>${order.customerName}</span>|<span>${order.productName}</span>|¥<span>${order.totalAmount.toLocaleString()}</span>|<span>${statusLabelMap[order.status]}</span>`</span>,
)
.join(<span>'\n'</span>)}</span>`</span>
<span>return</span> {
<span>content</span>: [{ <span>type</span>: <span>'text'</span>, text }],
}
},
},
{ <span>signal</span>: abortController.<span>signal</span> },
)
modelContext.<span>registerTool</span>(
{
<span>name</span>: <span>'order_detail'</span>,
<span>description</span>: <span>'根据完整订单号查询订单详情,并同步筛选页面订单列表。'</span>,
<span>inputSchema</span>: {
<span>type</span>: <span>'object'</span>,
<span>properties</span>: {
<span>orderId</span>: {
<span>type</span>: <span>'string'</span>,
<span>description</span>: <span>'完整订单号,如 ORD-5X9A2B'</span>,
},
},
<span>required</span>: [<span>'orderId'</span>],
},
<span>execute</span>: <span>async</span> ({ orderId }: { <span>orderId</span>: <span>string</span> }) => {
<span>const</span> normalizedOrderId = orderId.<span>trim</span>().<span>toUpperCase</span>()
<span>const</span> order = orderList.<span>value</span>.<span>find</span>(<span>(<span>item</span>) =></span> item.<span>id</span>.<span>toUpperCase</span>() === normalizedOrderId)
filterStatus.<span>value</span> = <span>''</span>
searchText.<span>value</span> = order?.<span>id</span> ?? orderId.<span>trim</span>()
<span>await</span> <span>nextTick</span>()
<span>if</span> (!order) {
<span>return</span> {
<span>content</span>: [{ <span>type</span>: <span>'text'</span>, <span>text</span>: <span>`未找到订单号为 <span>${orderId}</span> 的订单。`</span> }],
}
}
<span>const</span> text = <span>`订单详情(<span>${order.id}</span>):
- 客户:<span>${order.customerName}</span>
- 联系电话:<span>${order.customerPhone}</span>
- 商品:<span>${order.productName}</span>
- 数量:<span>${order.quantity}</span>
- 单价:¥<span>${order.unitPrice.toLocaleString()}</span>
- 总金额:¥<span>${order.totalAmount.toLocaleString()}</span>
- 支付方式:<span>${order.paymentMethod}</span>
- 状态:<span>${statusLabelMap[order.status]}</span>
- 下单时间:<span>${order.createdAt}</span><span>${order.shippedAt ? <span>`\n- 发货时间:<span>${order.shippedAt}</span>`</span> : <span>''</span>}</span>
页面定位:订单列表已筛选到 <span>${order.id}</span>。`</span>
<span>return</span> {
<span>content</span>: [{ <span>type</span>: <span>'text'</span>, text }],
}
},
},
{ <span>signal</span>: abortController.<span>signal</span> },
)
})
<span>onUnmounted</span>(<span>() =></span> {
abortController.<span>abort</span>()
})
编写业务 Skill
可执行工具定义了 AI 能做什么,业务 Skill 则指导 AI 正确使用这些工具。业务 Skill 应说明:
- 哪些用户意图适合使用当前业务能力;
- 当前有哪些可用工具;
- 如何把用户表达转换为工具参数;
- 什么情况下选择哪个工具;
- 如何根据工具的真实返回结果回答用户,以及如何处理参数不足、未找到或执行失败。
比如 codelabs-demo 新增 src/skills/orders/SKILL.md:
下面示例代码也可以在 webmcp-skill.md 查看
---
name: orders
<span>description: 订单查询技能。当用户需要查询订单列表、订单状态、客户订单或指定订单详情时使用。
---</span>
<span># 订单查询</span>
你负责协助用户查询订单信息。
<span>## 适用范围</span>
这些工具只在订单管理页面挂载后可用。
如果订单工具当前不可用,提示用户先进入订单管理页面,不要虚构查询结果。
<span>## 可用工具</span>
<span>-</span> <span>`order_query`</span>:查询订单列表,支持按订单号、客户姓名和订单状态筛选。
<span>-</span> <span>`order_detail`</span>:根据完整订单号查询详情,并同步筛选页面订单列表。
<span>## 参数规则</span>
<span>### orderId</span>
订单号格式类似 <span>`ORD-5X9A2B`</span>。
<span>-</span> 用户提供完整订单号并要求查看详情时,调用 <span>`order_detail`</span>。
<span>-</span> 用户只想在列表中搜索订单时,调用 <span>`order_query`</span>。
<span>### customerName</span>
支持按客户姓名模糊查询,使用 <span>`order_query`</span>。
<span>### status</span>
只允许使用以下值:
<span>-</span> <span>`Pending`</span>:待发货
<span>-</span> <span>`Shipped`</span>:已发货
<span>-</span> <span>`Delivered`</span>:已签收
<span>-</span> <span>`Refunded`</span>:已退款
<span>-</span> <span>`Cancelled`</span>:已取消
<span>## 工具选择</span>
<span>1.</span> 查询指定订单详情:调用 <span>`order_detail`</span>。
<span>2.</span> 按客户、状态或多个条件筛选:调用 <span>`order_query`</span>。
<span>3.</span> 用户没有提供足够的必填参数时,先向用户询问。
<span>4.</span> 工具返回未找到时,如实告诉用户,不得补造订单。
<span>5.</span> 最终回答只能使用工具实际返回的信息。
<span>6.</span> <span>`order_detail`</span> 已返回页面筛选结果时,无需使用 PageTool 重复确认;其他未完成任务不受此限制。
如果上述示例代码不满足你的业务需求,可以使用 Agent 生成业务代码,可用提示词如下:
/opentiny-next-app-integration 根据以下已确认的业务定义,为 codelabs-demo 补充 Step 3 订单工具和 Skill:
- 在 src/views/orders/index.vue 注册 order_query 和 order_detail。
- order_query 支持按订单号、客户姓名和订单状态查询,并同步页面筛选条件。
- order_detail 根据完整订单号查询订单详情,同步将页面列表筛选到该订单;工具结果只反馈已经完成的详情查询和页面筛选。
- 两个工具复用页面现有的 orderList,不创建模拟数据。
- 工具只在订单管理页面打开期间注册并可调用。
- 在 src/skills/orders/SKILL.md 中说明工具用途、参数规则、选择条件和失败处理;专用工具已返回页面定位结果时,无需使用 PageTool 重复确认,其他未完成任务不受此限制。
实现模板:
- 在 onMounted 中调用 document.modelContext.registerTool({ name, description, inputSchema, execute }, { signal }) 注册工具。
- 两个工具共用一个 AbortController.signal,并在 onUnmounted 中调用 abort() 注销。
- SKILL.md 使用包含 name 和 description 的 YAML frontmatter,并包含“适用范围”“可用工具”“参数规则”和“工具选择”。
只实现上述能力,不新增或推测其他业务工具。完成后检查代码接入,不发送模型消息。
使用 WebMCP 获取订单数据
- 进入订单管理页面后,Chat 应用中查询订单时,AI 会根据 tools 或 Skill 指令(如果AI使用了Skill的话) 选择
order_query或order_detail。 - AI 回复内容和订单页面会使用同一份业务数据。
进入订单管理页面后,在 Chat 应用中输入以下提示词,验证 AI 调用 order_detail 查询真实订单数据:
请查询订单 ORD-5X9A2B 的详细信息。
Step 4:接入 PageTool 页面查询与导航
发送如下指令给 Agent:
/opentiny-next-app-integration 为当前项目接入 PageTool。
Agent 完成后,会接入项目当前版本提供的 PageTool 和 TinyRobot adapter。
PageTool 接入完成后,开发者需要补充两部分代码:
- 配置页面访问范围:在真实业务页面中标记允许 PageTool 查询、定位或导航的元素,并按需排除不允许访问的区域。
- 编写 PageTool Skill:在
src/skills/<业务名>/SKILL.md中说明允许处理的用户意图、页面目标、操作流程和安全边界。
补充下面的页面目标时,使用同一份 action/target 声明配置 adapter policy,并与实际交互元素上的 data-page-tool-* 保持一致。页面属性提供稳定语义,adapter policy 负责执行前授权,两者不能互相替代。
配置页面访问范围
标记可访问元素时,使用 data-page-tool-* 属性:
<span><<span>a</span> <span>href</span>=<span>"/hello"</span>
<span>data-page-tool-id</span>=<span>"稳定标识"</span>
<span>data-page-tool-action</span>=<span>"navigation"</span>
<span>aria-label</span>=<span>"名称"</span>></span>
<span></<span>a</span>></span>
data-page-tool-id:页面目标的稳定且唯一的业务标识;data-page-tool-action:允许的动作类别,例如query或navigation;aria-label:供 PageTool 和辅助技术识别的可访问名称。
比如给 codelabs-demo 的订单页面增加以下能力:
| 页面目标 | 允许的动作 | 作用 |
|---|---|---|
| `orders-page` | `query` | 查询订单管理页面结构 |
| `orders-list` | `navigation` | 滚动定位到订单列表 |
| `orders-navigation` | `navigation` | 从左侧导航进入订单管理页面 |
给页面元素添加 PageTool 属性
在 src/views/orders/index.vue 中,将:
<span><<span>div</span> <span>class</span>=<span>"orders-view"</span>></span><span></<span>div</span>></span>
修改为:
<span><<span>div</span>
<span>class</span>=<span>"orders-view"</span>
<span>data-page-tool-id</span>=<span>"orders-page"</span>
<span>data-page-tool-action</span>=<span>"query"</span>
<span>aria-label</span>=<span>"订单管理页面"</span>
></span><span></<span>div</span>></span>
允许 PageTool 滚动定位到订单列表,将:
<span><<span>div</span> <span>class</span>=<span>"table-container"</span>></span><span></<span>div</span>></span>
修改为:
<span><<span>div</span>
<span>class</span>=<span>"table-container"</span>
<span>data-page-tool-id</span>=<span>"orders-list"</span>
<span>data-page-tool-action</span>=<span>"navigation"</span>
<span>aria-label</span>=<span>"订单列表"</span>
></span><span></<span>div</span>></span>
允许 PageTool 点击左侧“订单管理”进入订单页面,在 src/App.vue 中将:
<span><<span>router-link</span>
<span>to</span>=<span>"/orders"</span>
<span>class</span>=<span>"nav-item"</span>
<span>active-class</span>=<span>"active"</span>></span>
<span></<span>router-link</span>></span>
修改为:
<span><<span>router-link</span>
<span>to</span>=<span>"/orders"</span>
<span>class</span>=<span>"nav-item"</span>
<span>active-class</span>=<span>"active"</span>
<span>data-page-tool-id</span>=<span>"orders-navigation"</span>
<span>data-page-tool-action</span>=<span>"navigation"</span>
<span>aria-label</span>=<span>"进入订单管理"</span>
></span><span></<span>router-link</span>></span>
配置 PageTool 黑名单
如果业务页面中不允许 PageTool 查询或操作的区域,可以修改 PageTool 配置。TinyRobot 对话框已经在 PageTool 配置中排除。
具体路径以项目实际代码为准,可以搜索 registerPageAgentTool 或 setPageAgentToolConfig 定位。找到 a11yConfig.blacklist 后,在保留已有配置的基础上追加业务区域选择器,例如:
<span>registerPageAgentTool</span>({
<span>// 保留项目已有的其他 PageTool 配置</span>
<span>a11yConfig</span>: {
<span>blacklist</span>: [
<span>'.chat-add-window'</span>,
<span>'.chat-add-launcher'</span>,
<span>'[data-page-tool-exclude="true"]'</span>,
<span>'<不允许访问的业务区域选择器>'</span>,
],
<span>// 保留项目已有的 whitelist 和 exposedAttributes</span>
},
})
编写 PageTool Skill
PageTool Skill 应说明:
- 哪些用户意图可以使用 PageTool;
- 可以操作哪些页面目标以及允许的动作;
- 什么情况下应优先调用 Step 3 注册的专用业务工具;
- 哪些操作必须禁止。
Skill 中的目标和动作必须与页面代码一致。提交、删除、发布、支付等操作必须使用带权限校验和确认机制的专用工具,不能通过 PageTool 或 Skill 开放。
比如 codelabs-demo 项目,在 src/skills/orders/SKILL.md 末尾加入:
下面示例代码也可以在 pagetool-skill.md 查看
<span>## PageTool 页面目标</span>
<span>-</span> <span>`orders-page`</span>:订单管理页面;允许动作:<span>`query`</span>。
<span>-</span> <span>`orders-list`</span>:订单列表;允许动作:<span>`navigation`</span>,仅用于滚动定位。
<span>-</span> <span>`orders-navigation`</span>:左侧“订单管理”导航;允许动作:<span>`navigation`</span>,仅用于进入订单页面。
<span>## PageTool 与业务工具边界</span>
<span>-</span> PageTool 只用于上述页面目标的查询、滚动和导航。
<span>-</span> 查询订单数据并在页面中定位订单时,使用 <span>`order_query`</span> 或 <span>`order_detail`</span>,不使用 PageTool 读取订单数据或操作搜索框。
<span>-</span> <span>`order_detail`</span> 已返回页面筛选结果时,无需使用 PageTool 重复确认;其他未完成任务不受此限制。
<span>## PageTool 禁止操作</span>
<span>-</span> 不操作未在“PageTool 页面目标”中声明的元素。
<span>-</span> 不使用 <span>`fill`</span>、<span>`select`</span> 或 <span>`executeJavascript`</span>。
<span>-</span> 不使用 PageTool 提交、删除、发布、支付或执行其他副作用。
如果上述示例代码不满足你的业务需求,可以使用 Agent 生成业务代码,可用提示词如下:
/opentiny-next-app-integration 根据以下已确认的页面访问范围,为 codelabs-demo 补充 Step 4 PageTool 业务代码:
- 在 src/views/orders/index.vue 添加 orders-page,允许 query。
- 在订单列表添加 orders-list,允许 navigation,仅用于滚动定位。
- 在 src/App.vue 的“订单管理”导航添加 orders-navigation,允许 navigation。
- 使用同一份 action/target 声明配置 adapter 的 PageTool policy,并与页面上的 data-page-tool-* 保持一致。
- 在 src/skills/orders/SKILL.md 中补充上述页面目标、业务工具边界和禁止操作。
- PageTool 只负责已声明的页面查询和导航;查询订单数据并在页面中定位订单时,使用 order_query 或 order_detail。
- order_detail 已返回页面筛选结果时,无需使用 PageTool 重复确认;其他未完成任务不受此限制。
- 不开放表单填写、脚本执行、提交、删除、发布或支付操作。
只实现上述目标,不新增或推测其他页面目标。
使用 PageTool 导航页面
- AI 可以根据一条用户消息,通过
orders-navigation进入订单管理页面,查询订单详情并在页面中定位该订单。 - 对单个订单查询,预期最短调用链为:PageTool 观察当前页面 → PageTool 点击订单导航 →
order_detail查询并定位 → AI 回复,无需使用 PageTool 重复确认。
在非订单页面打开 Chat 应用并输入以下业务提示词,来验证 AI 自动导航能力:
请查询订单 ORD-5X9A2B 的详细信息,并在页面中定位到这条订单。
page-tool 自动导航到订单管理页面
然后筛选出订单,输出订单详情
关于 OpenTiny
OpenTiny 是面向企业级场景的前端 AI 应用开发平台。平台依托生成式 UI与WebMCP两大核心底层技术,打造适配 Agent 智能应用生态的 NEXT-SDKs、AI 扩展工具、TinyRobot 对话 AI 组件库、GenUI SDK生成式 UI 、WebAgent 智能代理等系列产品,能够依托 AI 解析用户需求意图,自动驱动任务执行,助力企业现有业务系统快速完成智能化升级。
同时 OpenTiny 沉淀成熟通用前端基建能力:提供跨端、跨框架、跨版本的 TinyVue 组件库,配套基于 Angular+TypeScript 技术栈的 TinyNG 组件库;内置可高度自定义拓展的低代码引擎 TinyEngine,搭配 TinyPro 中后台业务模板、TinyCLI 命令行工具等配套工具链,全方位赋能开发者高效搭建各类 Web 端企业应用。
欢迎加入 OpenTiny 开源社区。添加微信小助手:opentiny-official 一起参与交流前端技术~
OpenTiny 官网:opentiny.design
GenUI SDK 代码仓库:github.com/opentiny/ge… (欢迎star ⭐)
如果你也想要共建,可以进入代码仓库,找到 good first issue标签,一起参与开源贡献~如果你有任何问题,欢迎在评论区留言交流!
从对话组件到 MCP 工具与 PageTool 权限边界,四步路径清晰可复用,适合前端团队为存量中后台系统快速加装自然语言操作能力。