☰
用 Skill 给 AI 立规矩:码道+OpenTiny 生成规范页面
2026/11/4 4:31:12 网站建设 项目流程

AI写页面最大的问题,不是写不出来,而是不听话。你说"给我来一个带筛选条件的表格页",它能给你拼出一个混合了Bootstrap表格、Element弹窗、自制样式的缝合怪,项目里明明有OpenTiny组件库却不知道用。我最近把码道和OpenTiny的智能化Skill搭在一起,专门治这个毛病:码道负责理解需求,Skill负责给AI立规矩,让生成结果始终贴着OpenTiny组件库的规范和API来。这篇文章把我怎么搭、怎么调、翻过哪些车都写出来,对正在折腾AI页面生成、低代码平台、Agent技能包开发的同学应该有点用。

我先说下背景。这个思路其实是从"给AI写提示词"升级过来的。很多人以为让AI好好用组件库,只需要在系统提示词里写一句"请使用OpenTiny组件",事实远没那么简单——长对话一到后面,模型就开始自由发挥了。Skill这个概念这几年在Claude Code、Codex、Cursor社区里非常火,热度词里面能看到一堆人讨论什么是skill、skill和agent的区别、怎么开发一个完善skill。说白了,Skill是一份可复用的"行为契约+工具箱"。把它和码道、OpenTiny一结合,页面才能算得上真正"听话"。

1. 先理顺三件事:码道是什么、OpenTiny特殊在哪、Skill解决什么问题

1.1 码道:负责"听懂需求"的编排层

码道不是传统意义上的低代码拖拽平台,它更像一个AI原生的页面编排层。你输入一段自然语言需求,它把需求拆成页面结构、数据字段、交互逻辑,再转化成可运行的工程代码。这个定位很关键:它擅长"听懂人话",但它自己并不知道应该按哪套组件规范来落地。

所以码道需要一个外挂的"约束系统"。没有约束的时候,它在组件选择上是短视的——哪个组件在训练数据里出现得多,它就倾向用哪个,哪怕你的项目根本不依赖那套库。这就是为什么很多AI生成代码"能跑但不属于你的项目"。

我在实际使用中发现,码道对上下文的管理还比较规范,能支持自定义的Skill目录和工具调用。也就是说,我们可以把"OpenTiny如何用"这个领域知识完整地塞进去,而不是靠一句提示词碰运气。这让我觉得这条路能走通。

1.2 OpenTiny不是又一个组件库,是"企业前端规范"的合集

OpenTiny是开源社区里比较活跃的企业级前端解决方案,其中最出名的就是 @opentiny/vue 组件库,表单、表格、弹窗、级联、树等常用组件覆盖得挺全。它的特别之处在于,不只是代码层面的组件,而是把企业产品前端的一致性要求都装进去了。

具体来说,至少包含几个层面:

  • 统一的组件API:表格就是t-table,列配置走columns,分页有pager。AI只要照着API写,不需要自己发明轮子。
  • 设计令牌体系:颜色、间距、圆角、字体都有token支持,切换主题和暗黑模式有标准路径。
  • 国际化方案:文案从i18n统一管理,硬编码在组件里是"违规行为"。
  • 无障碍规范:很多企业客户对可访问性有硬性要求,AI很难自发考虑到这一点。

传统前端开发时,这些由团队规范、Code Review和设计系统来保障。AI写代码的时候没有这些防线,如果不给它一个明确的"OpenTiny领域知识包",它就很容易产出风格不统一、API瞎猜、主题完全不匹配的页面。OpenTiny存在的意义,就是把这些复杂规范沉淀成一套可以被程序化引用的标准——而这恰恰也是可以被Skill"背下来"的。

1.3 智能化Skill:不是普通提示词,是"技能包"

最近技术社区里"Skill"的热度高得离谱,很多人问什么是skill、skill和agent的区别。我给出我理解的一个直观类比:Agent是那个坐在工位上的"程序员",Skill是他工位上贴着的工作手册和工具箱。Agent负责理解上下文、做决策,Skill负责规定"做这件事必须按什么流程、必须用什么工具、必须满足什么验收条件"。

和普通提示词对比,Skill的差别很大。普通提示词是你每次都得先写一长段要求,模型听不听看心情;Skill是一个自包含的小项目,通常包含SKILL.md主文件、辅助脚本、参考资产、示例产物,它有自己的版本号,可以被Git管理,可以跨项目复用。

举个具体例子。一份普通的提示词可能是"请用OpenTiny组件库帮我写个页面",而一份OpenTiny Skill会把下面这些都写清楚:

  • 你被允许使用的组件清单,以及对应的导入路径
  • 表格列配置的标准结构
  • 表单校验规则怎么写
  • 哪些常见的"看起来没问题"的写法其实是违规的
  • 生成前需要向用户确认哪些模糊信息

在码道中接上这样的Skill之后,AI的行为就从"自由发挥"变成了"按手册施工"。从我的测试结果来看,效果差别非常明显。

2. Skill真正要解决的是"行为一致性",不是"回答正确性"

2.1 提示词会漂移,Skill不会

有一段时间,我尝试只在码道的系统提示词里写"所有组件必须使用OpenTiny"。前两轮对话确实有效,可一旦上下文变长,或者用户补充了几个需求,AI就开始"失忆"。它可能会在某个按钮上突然用回原生HTML,或者弹窗组件写成了别的库的语法。

这种行为不一致现象,做AI应用的人都遇到过。原因在于:系统提示词虽然是对话初始的强指令,但随着多轮对话增补信息,模型注意力会被后续内容稀释,早期指令的约束力会下降。就像开会时领导开场说了三条规定,结果开了两小时会后,大家只记得最新的琐碎讨论。

Skill解决这个问题的思路很优雅。它不是一个被"夹带"在对话流里的指令,而是Agent每次进入任务时主动去加载的独立文档。在码道这类平台里,Skill通常和对话上下文分离管理,Agent会在任务开始时把SKILL.md连同相关资产一起读入,并且可以反复引用。因为它是文件、有版本、有结构,而不是飘在系统提示词里的一句话。

2.2 SKILL.md的主体结构长什么样

我一开始以为Skill就是一篇写得更详细的提示词,后来发现自己错了。一份能稳定工作的SKILL.md,其实是"角色定义+工作流程+硬性规则+参考手册+验收标准"的组合体。下面我给一个简化但完整的例子,建议大家照着这个骨架写第一版。

--- name: opentiny-page-builder description: 按 OpenTiny 组件库规范生成企业级前端页面 version: 0.2.0 license: MIT --- ## 角色 你是一名资深前端工程师,专注于使用 @opentiny/vue 组件库 开发企业级中后台页面。你熟悉 OpenTiny 的设计原则、组件 API 和工程规范。 ## 核心目标 将用户需求转化为符合 OpenTiny 规范的 Vue3 页面代码, 确保组件使用正确、结构清晰、可维护。 ## 硬性规则 1. 只允许使用 @opentiny/vue 以及 Vue3 原生能力。 2. 表格必须使用 TinyTable(t-table),列定义写入 columns 配置,禁止在模板里手写 td/th。 3. 弹窗必须使用 TinyModal,禁止自行拼接遮罩层。 4. 表单必须使用 TinyForm + TinyFormItem,校验规则写 rules 属性,禁止在 submit 里手动判断全局变量。 5. 任何组件样式覆盖都必须通过设计令牌变量实现, 禁止在页面内写死颜色值。 6. 所有中文文案必须放入 locale 文件,禁止硬编码。 ## 工作流程 1. 向用户确认页面类型和核心数据字段。 2. 抽取实体字段,明确每个字段的类型和展示方式。 3. 输出页面 JSON Schema,经用户确认后生成代码。 4. 生成代码后执行 scripts/verify-tiny.py 自检。 5. 输出最终代码,并说明每个模块的用途。 ## 组件速查 - 表格:t-table,props: columns, data, row-key columns 每项包含: prop, label, width, align, slots - 分页:t-pager,props: total, page-size, current-page - 弹窗:t-modal,props: visible, title, footer, width - 表单:t-form,props: model, rules - 输入框:t-input,支持 v-model

这段SKILL.md并不算完美,但它已经是"契约"而不是"建议"。里面的每条硬性规则都对应一类真实出现过的错误——比如刚开始AI会自己在模板里写一堆style,我加一条"禁止硬编码颜色值"后,这个问题立刻变少了。所以我的建议是:不要一开始追求SKILL.md写得又全又完美,先把最常见的错误行为变成规则,后续再慢慢补。

2.3 Skill、MCP和harness到底怎么配合

社区里争论"skill和agent的区别"之后,紧接着又会遇到MCP和harness两个概念,很多新人容易绕晕。这里我用一张表把它们的角色理顺。

概念类比职责
Agent柜台值班员理解任务、拆解步骤、决定调用什么能力
Skill岗位手册和工具箱定义怎么做一件事,包含流程、规则、脚本和示例
MCP快递网络提供外部数据和工具,比如拉取OpenTiny组件属性定义、后端接口文档
Harness值班室的运行环境负责加载Agent、挂载Skill、配置MCP Server、维护上下文

放到OpenTiny这个例子里:harness决定Agent在启动时把opentiny-page-builder这个Skill读进上下文;Skill告诉Agent应该使用哪些组件,但组件最新版的props和类型定义,可以通过一个OpenTiny元数据MCP Server实时拉取,保证信息不落后于组件库发版。这三层配合好之后,AI才能做到"既懂规矩,又有最新情报"。

3. 手写一个"OpenTiny页面生成"Skill的完整过程

3.1 先定场景:固化的高频任务

写Skill之前最忌讳空想。我的做法是先把团队里大量的页面需求归类,找出最重复的那一类。最后发现,"搜索列表页"占了中后台需求的大头——一个筛选表单、一个结果表格、分页加若干操作按钮,结构高度重复。

为了让Skill一开始就有明确的边界,我把它定位成只负责生成"搜索列表页"和"普通表单页"。这两个场景自带清晰的组件映射:筛选表单对应TinyForm和TinyInput/TinySelect/TinyDatePicker,结果表格对应TinyTable和TinyPager。

这也意味着,SKILL.md的开头必须写明适用场景,免得AI拿一个复杂的树形交互需求过来,硬要用这个Skill处理,最后两边都别扭。

3.2 目录结构设计

我把Skill做成一个完整的目录,丢进Git仓库,一个版本一个摘要。目录长这样:

opentiny-page-builder/ ├── SKILL.md ├── scripts/ │ ├── schema-gen.py │ └── verify-tiny.py ├── assets/ │ ├── components.md │ └── biz-fields.md └── examples/ ├── order-search-page.json └── user-list-page.json

SKILL.md是主入口,Agent启动时必读;assets里的components.md是组件属性参考,不需要全文进上下文,按需检索;examples里的JSON是少样本示例,能显著提升AI输出的稳定性。scripts目录放实际可执行的脚本,它们不是给用户看的,而是给Agent调用的"校验器"和"生成器"。

3.3 从自然语言到页面JSON:schema-gen脚本干了什么

AI直接输出Vue模板不难,但难在"需求理解"和"组件映射"两步。我写了一个轻量的schema-gen.py,让Agent先产出中间JSON,再根据JSON生成最终代码。这相当于加了一道"翻译中间层"。

#!/usr/bin/env python3 """将自然语言抽取出的字段列表,映射为 OpenTiny 页面 JSON Schema。""" import json import sys FIELD_TYPE_MAP = { "订单号": ("input", "order_no"), "客户名称": ("input", "customer_name"), "状态": ("select", "status"), "日期范围": ("date-picker-range", "created_at"), } def build_schema(fields: list[str]) -> dict: form_items = [] for field in fields: ftype, key = FIELD_TYPE_MAP.get(field, ("input", field)) form_items.append({ "type": ftype, "field": key, "label": field, "span": 8, }) return { "page_type": "search-list", "search_form": form_items, "table": { "columns": [ {"prop": "order_no", "label": "订单号", "width": 180}, {"prop": "customer_name", "label": "客户名称", "width": 160}, {"prop": "status", "label": "状态", "width": 100}, ], "row-key": "id", "pager": True, }, } if __name__ == "__main__": fields = sys.argv[1].split(",") print(json.dumps(build_schema(fields), ensure_ascii=False, indent=2))

这段代码的核心逻辑很简单:把用户描述里的字段名映射成OpenTiny表单组件类型和字段key。实际项目里,这个映射表应该来自后端数据字典,而不是写死。我这里只是演示思路——有了这个JSON中间层,AI后续去套t-table、t-form的模板就会非常稳定,因为字段和列都已经是结构化数据了。

3.4 校验脚本:让产出从"看起来对"变成"能跑"

光有生成规则还不够,AI偶尔还是会犯错。我在Skill里放了第二个脚本verify-tiny.py,让Agent在交付代码之前跑一次自检。校验思路不是解析JSX或Vue完整语法——那太重了,而是用正则和简单的标签匹配,抓最容易发生的低级错误。

#!/usr/bin/env python3 """扫描生成的 Vue 模板,检查是否触犯 OpenTiny 硬性规则。""" import re import sys FORBIDDEN_PATTERNS = [ (r"<table", "禁止原生 table 标签,应使用 t-table"), (r"style=\"[^\"]*#[0-9a-fA-F]{3,6}", "禁止内联写死颜色"), (r"<div[^>]*class=\"modal", "禁止模拟弹窗,应使用 t-modal"), ] def check(template_path: str) -> bool: with open(template_path, encoding="utf-8") as f: content = f.read() passed = True for pattern, message in FORBIDDEN_PATTERNS: if re.search(pattern, content): print(f"[FAIL] {message}") passed = False if not re.search(r"<t-table", content): print("[FAIL] 未找到 t-table 组件,搜索结果页面必须有表格") passed = False if passed: print("[PASS] 模板通过 OpenTiny 基础校验") return passed if __name__ == "__main__": sys.exit(0 if check(sys.argv[1]) else 1)

有同学可能会问,为什么要用这么"笨"的正则,而不是直接用ESLint或者Vue编译器解析?因为在Agent的运行时环境里,我们不需要一个完美地type-check整个项目的重型工具,我们需要的是快速、低误报、能给出明确改进信息的检查器。正则虽然粗糙,但对"禁用原生table、禁写死颜色、禁用自制弹窗"这类规则来说完全够用。等Skill稳定后,再换成AST级别的校验也不迟。

3.5 在码道中挂载Skill

把Skill目录放到码道能识别的路径后,需要在Agent配置里声明启用。不同平台的写法略有差异,但思路一致:声明Skill的名称、入口文件、可选依赖的MCP服务。举一个比较常见的配置片段:

{ "agent": "opentiny-page-agent", "skills": [ { "name": "opentiny-page-builder", "path": "/skills/opentiny-page-builder", "entry": "SKILL.md", "enabled": true } ], "mcp_servers": [ { "name": "opentiny-meta", "command": "npx mcp-server-opentiny-meta" } ] }

配置完先跑一个最简单的冒烟测试:让Agent生成一个只有一个表单的页面,看它有没有正确读取SKILL.md,有没有乱用组件。这一步能过滤掉八成环境问题,例如路径不对、脚本权限缺失、MCP server没起来,而不是等到真做复杂页面时才发现问题。

4. 实际跑一遍:让页面从"听懂话"到"办成事"

4.1 一句话需求走完整流程

我用一个非常接近日常工作的需求来测试。原始输入只有一句话:"做一个销售订单查询页面,顶部是筛选项:订单号、客户名称、状态、下单日期范围;下面表格展示订单列表,支持分页和批量导出。"

接入Skill后,Agent的行为明显和以前不一样了。它没有上来就贴代码,而是先按SKILL.md里的工作流程反问了我一句:"批量导出的按钮是放在表格工具栏还是左下角?日期范围精确到时分吗?"这个变化很重要——它证明Skill中的"先确认模糊点"环节生效了,而不是把猜测当成事实。

确认完之后,Agent输出了页面JSON Schema,再生成Vue模板。产物结构大概是这样:顶部t-form内联表单,四个筛选项字段;中间是t-table,columns里包含订单号、客户名称、状态、下单时间、操作列;底部t-pager;工具栏放了一个"批量导出"按钮。关键代码片段如下:

<template> <div class="order-search-page"> <tiny-form :model="queryForm" inline> <tiny-form-item label="订单号"> <tiny-input v-model="queryForm.orderNo" /> </tiny-form-item> <tiny-form-item label="状态"> <tiny-select v-model="queryForm.status" :options="statusOptions" /> </tiny-form-item> </tiny-form> <tiny-table :columns="columns" :data="tableData" row-key="id"> <template #operation="{ row }"> <tiny-button @click="handleView(row)">查看</tiny-button> </template> </tiny-table> <tiny-pager :total="total" :page-size="queryForm.pageSize" /> </div> </template>

代码跑起来之后,UI整体是OpenTiny的主题风格,没有出现那种"一个页面三种组件风格"的乱象。从输入一句话到拿到代码,整个过程大约5分钟,比我自己手抄一个列表页快不少。

4.2 有Skill和没Skill的差异有多大

我在同一个码道Agent上做了对比测试——关闭Skill和开启Skill,分别让它处理同样的5个页面需求。结果差异非常明显。

对比维度无Skill有Skill
组件规范符合度约30%准确90%以上准确
是否需要人工修正结构经常重写微调字段即可
页面风格一致性每页都不一样基本一致
平均生成时间8分钟5分钟
一次通过率20%左右70%左右

最让我意外的是"一次通过率"的变化。本来我以为只是风格变好了,实际发现错误率也大幅下降,因为verify-tiny.py会把常见低级错误在交付前就拦下来。对于中后台页面这种"批量生产"场景,AI从要改三次才能用,变成了一次差不多能用,这里面的效率提升是实打实的。

4.3 Skill也会翻车的几种情况

没有完美的Skill,我在测试中也踩到了几个翻车现场。第一种是需求本身模糊到了AI无法确认的程度,比如"做一个统计页面",它不知道你要的是表格还是图表、指标卡还是趋势图。对这种情况,SKILL.md里就算写了"先确认需求"也架不住用户不想打字,AI只好硬猜,最后产出自然不理想。

第二种是复杂交互场景。当前Skill只覆盖搜索列表和普通表单,一旦遇到树形表格、跨行合并、批量审批流,它生成的代码会显得很吃力。所以我在SKILL.md开头明确写了适用范围,超出范围时AI需要提醒用户"这个Skill不擅长当前场景",而不是硬撑。

第三种是后端字段信息缺失。页面生成得再漂亮,数据联调时发现字段名对不上,还是要返工。我的解决思路是,把数据字典或者接口Mock配置也做成assets里的biz-fields.md,让Skill能同时参考字段定义生成页面。这样页面从一开始就对齐真实接口,返工率又降了一截。

5. 写Skill最容易踩的坑和我的调试习惯

5.1 坑位一:SKILL.md写成了"百科全书"

很多第一次写Skill的同学,恨不得把所有组件文档塞进去,结果就是SKILL.md动辄上万字,AI读一遍都要浪费大量token,反而抓不住重点。我的经验是:SKILL.md只保留高频组件和高频规则,每种组件给一个最小可用示例;一些低频组件的完整API,放到assets/components.md里,AI按需检索,或者通过MCP Server热拉取。

这就像是给新员工发入职手册,你不可能把全公司所有系统文档都印在上面,而是给一份"员工手册+办公系统操作说明",其余深水区让他在需要时再去查。

5.2 坑位二:规则写太死,AI不敢动弹

一开始我踩过另一个极端:为了杜绝AI自由发挥,我把规则写得非常僵化,比如"表格列宽只能使用默认值""任何地方都不允许自定义样式"。结果AI确实不乱写了,但它给所有列都用了同样宽度,页面看起来非常死板,而且它连很合理的UI微调都不敢做。

后来我把规则分成两档。硬性规则,比如"禁止使用原生table、禁止硬编码颜色",这类违反就是真错误,必须拦住;默认偏好,比如"推荐使用8栅格布局""推荐用设计令牌定义间距",这类AI可以参考,但需要用户确认后调整。这样既保住了底线,又不至于扼杀灵活性。

5.3 坑位三:没有AI的自检环节

最要命的一种坑是,SKILL.md里只写了"怎么干活",没写"怎么检查自己干得好不好"。模型其实很愿意配合自检,但如果你不给路径,它交付完就跑了。现在我在SKILL.md的最后一段固定放一个"输出前自检清单":是否只用OpenTiny组件?是否有硬编码中文?是否经过verify-tiny.py校验?表格列配置是否符合columns规范?这一小段把最后一道防线补上了。

5.4 建立一套"回归测试"意识

Skill开发最忌讳只测一次就完事。我现在维护Skill像维护业务代码一样:每个版本跑一遍设计好的冒烟用例集,大概8个典型需求,覆盖列表页、表单页、弹窗、分页、空状态、错误输入等。任何一次改规则,都要回归一遍,防止"修好了A,搞坏了B"。

我把每次翻车案例也记进项目里的KNOWN_ISSUES.md,这个文件反过来又成了资产——AI在下一次生成时读到这些历史错误,等于有了前人的经验教训。目前我已经积累了七八条,其中最有用的比如"日期范围默认值不要写today(),应写默认空,避免时区问题",已经沉淀成了SKILL.md里的硬性规则。

写到这里,想分享一个自己折腾这套OpenTiny智能化Skill的真实体会。我最开心的不是页面生成速度快了多少,而是代码评审的时候,大家不再为一个按钮到底是自带样式还是组件样式争来争去,页面长出来就是一套规范的样子。如果你也在琢磨AI页面生成,我的建议是先别贪多,挑一个高频场景,比如搜索列表页,把Skill写扎实、配上校验脚本、沉淀翻车案例,然后你就会发现,AI写页面这件事终于从"能生成"跨到了"能交付"。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询