【免费下载链接】stitch-sdk
Generate UI screens from text prompts and extract their HTML and screenshots programmatically.
Stitch SDK 是一个让你用一句话文本就能生成 UI 界面、并程序化提取其 HTML 和截图的 TypeScript SDK。它的有趣之处在于:SDK 本身并不是靠大模型"写"出来的,而是一条零LLM代码生成管线——先抓取 MCP 工具清单,再由确定性脚本编译成强类型 TypeScript SDK。本文将带你完整看懂这条管线的三个阶段、锁文件机制,以及那些防止"悄悄丢数据"的护栏设计。
🗺️ 先看懂全貌:一条 3 阶段管线
传统做法是把 API 文档丢给 LLM 让它生成 SDK,但输出不稳定、每次都不一样。Stitch SDK 走的是另一条路:LLM 只在"设计阶段"提供领域知识,代码生成本身 100% 确定、可复现。整条管线在 RELEASING.md 中有明确顺序:
| 阶段 | 做什么 | 产物 | 谁来做 |
|---|---|---|---|
| Stage 1 · 抓取 | 连接 Stitch MCP 服务器,调用tools/list | tools-manifest.json | 脚本 scripts/capture-tools.ts |
| Stage 2 · 设计 | 把工具映射到领域模型(类与方法绑定) | domain-map.json | 人 / Agent 依据 IR 规范 |
| Stage 3 · 生成 | 校验 IR 并发射 TypeScript 源码 | packages/sdk/generated/src/ | 脚本 scripts/generate-sdk.ts |
| Stage 4+ | 构建、测试、锁文件完整性校验 | 可发布的 npm 包 | CI + scripts/validate-generated.ts |
文件头注释直接写明了原则(见 scripts/generate-sdk.ts):
Deterministic — no LLM involved.(确定性生成,无 LLM 参与)
🔌 第一阶段:从 MCP 服务器抓取原始工具清单
第一步是最"老实"的一步:scripts/capture-tools.ts 用真实的StitchToolClient连上 Stitch 的 MCP 端点,调用listToolsRaw(),把服务器原样返回的工具 schema一字不改地写入 tools-manifest.json。
当前清单共收录了 15 个工具,比如create_project、generate_screen_from_text、edit_screens、get_screen等,每个工具都带有完整的inputSchema/outputSchema(JSON Schema),例如设备类型的枚举值、projects/{project}这样的资源名格式,全部原样保留。
两个值得注意的工程细节:
- 原始即真相:manifest 存的是"RAW"数据;如果服务器 schema 有缺陷,修复动作发生在加载时(见 packages/sdk/src/schema-repair.ts),修复记录会写进锁文件,而不是悄悄改掉原始事实来源。
- 原子写入:先写
.tmp再rename,配合 stitch-sdk.lock 的 SHA-256 哈希,防止半截文件污染管线。
🧩 第二阶段:domain-map.json——管线的"中间表示"
这是整条管线里唯一需要"设计品味"的一步。domain-map.json 把 15 个平铺的 MCP 工具,组织成 4 个领域类:Stitch → Project → Screen / DesignSystem,也就是你最终看到的面向对象 API。
它由两部分构成,结构由 scripts/ir-schema.ts 中的 Zod schema 严格约束:
1.classes——领域类声明
声明每个类的构造参数、工厂方法(如stitch.project(id)这种不发 API 调用就能拿到句柄的方法)、以及手写的"副作用"方法。例如 Screen 类的getHtml/getImage属于二进制下载,无法生成,必须手写(见 domain-map.json)。
2.bindings——工具到方法的绑定
每条绑定声明:调用哪个工具、挂在哪个类的哪个方法上、参数从哪来、返回值如何从响应中"投影"出来。看一个真实例子——generate方法(domain-map.json):
{ "tool": "generate_screen_from_text", "class": "Project", "method": "generate", "args": { "projectId": { "from": "self" }, "prompt": { "from": "param" }, "deviceType": { "from": "param", "optional": true, "default": "DESKTOP" } }, "returns": { "class": "Screen", "kind": "generation", "projection": [ { "prop": "outputComponents", "each": true }, { "prop": "design" }, { "prop": "screens", "each": true } ] } }参数来源(ArgSpec)有四种:self(实例自身字段)、selfArray、param(调用者传入)、computed(模板拼接,如projects/{projectId}/screens/{screenId})。
而projection是精华所在——它把"如何从原始响应里取出屏幕列表"写成了结构化步骤(prop/index/each/find),取代了不可校验的字符串路径。返回值为kind: "generation"时,强制要求用each收集全部结果,防止一次生成多个屏幕却只取到第一个的经典 bug。
⚙️ 第三阶段:确定性发射 TypeScript
scripts/generate-sdk.ts 读取两份输入,经过校验后输出 packages/sdk/generated/src/ 下的 8 个文件。核心机制有四个:
① JSON Schema → TypeScript 类型
jsonSchemaToTs()把工具 schema 递归翻译成 TS 类型:enum变联合类型"MOBILE" | "DESKTOP" | ...,$defs变具名接口,数组元素是联合类型时还会自动加括号(("A" | "B")[])以避免优先级陷阱。
② 投影步骤 → 投影代码
emitProjection()把上面的 projection 步骤翻译成真实代码:简单链变成可选链raw?.outputComponents?.[0],each步骤展开成flatMap,find步骤生成(arr ?? []).find(c => ...)扫描式取值。
③ 参数签名:必需参数在前,可选项归入 options
所有可选参数被收集成一个尾部的options?: { ... }对象。好处是:未来服务器新增参数时,老签名不破坏——这也是 screen.ts 里edit(prompt, deviceTypeOrOptions?, modelId?)这种签名的由来。
④ 响应对象自动缓存
带cache声明的方法(如getHtmlUrl)会先生成一段缓存检查:"生成响应里已经有这个 URL 就直接返回,不发新请求";调用后还会writeBack合并回this.data。这些细节能省掉大量重复 API 调用。
生成结果长什么样?看 packages/sdk/generated/src/screen.ts——每个方法都有 JSDoc 注明它来自哪个 MCP 工具,参数类型从 schema 推导,返回Promise<Generation<Screen, EditScreensResponse>>,连枚举值都是精确的联合类型:
async edit(prompt: string, deviceTypeOrOptions?: ... | { ... }): Promise<Generation<Screen, EditScreensResponse>>🔒 锁文件:让"重新生成"变得可审计
每份生成文件的头部都写着AUTO-GENERATED ... DO NOT EDIT,并嵌入两个源文件的 SHA-256 前缀。stitch-sdk.lock 则记录了三段哈希:manifest、domain-map 和整个生成目录。
这带来三个可验证的性质:
- 字节级可复现:同一份输入,任意机器上生成出的文件逐字节一致(哈希用相对路径、POSIX 规范化,跨机器可移植);
- 幂等:连续跑两次,内容没变就零 diff,连
generatedAt时间戳都不动; - CI 可校验:scripts/validate-generated.ts 在 CI 里重新计算哈希,发现"提交了与锁文件不符的旧代码"会直接红灯,杜绝发布过期 SDK。
🛡️ 护栏:把"LLM 容易犯的错"变成硬错误
这条管线最有意思的部分,是它把历史上真实踩过的坑全部变成了编译期/生成期就爆炸的检查:
| 护栏 | 触发条件 | 效果 |
|---|---|---|
.strict()的 IR schema | domain-map 里出现未知字段 | 直接报错——被静默丢弃的键意味着设计者以为生效了 |
投影校验validateProjection() | 对数组 schema 直接取属性、路径不存在的属性 | 生成前抛出并给出修复提示 |
| 无界数组 lint | 对无maxItems的数组取index/find单元素 | 警告"可能悄悄截断数据";对generate_*/edit_*/apply_*等生成类工具升级为硬错误(generate-sdk.ts) |
| 副作用冲突检查 | 手写扩展方法与生成方法同名 | 报错"扩展方法不得遮蔽生成方法",并校验 spec 文件存在 |
| 损坏的锁文件 | 锁不是合法 JSON | 拒绝运行,绝不静默重置(那会无声丢弃历史记录) |
换句话说:以前靠人肉 review 才能发现的"生成类工具只返回第一个屏幕"这类数据截断问题,现在会在bun run generate阶段直接以❌报错并终止。
🧭 小结:零 LLM 到底省掉了什么
- 可复现:同样的输入永远得到同样的 SDK,哈希可审计,而不是"再生成一次试试";
- 可校验:IR 的每个字段都被 schema 约束,投影路径在生成前就对着 outputSchema 逐段验证;
- 可演化:服务器新增工具时,重跑 Stage 1 抓取 + Stage 3 生成即可,手写扩展方法与生成代码有清晰的边界和命名保护。
如果你想动手体验,仓库是只读的公开镜像;完整流程命令(capture → generate → build → test → validate)都列在 RELEASING.md 中,测试套件里还有 scripts/test/codegen-snapshot.test.ts 用 fixture 对真实管线做快照回归。对 SDK 使用侧的入门(如何用stitch.project()生成屏幕、取 HTML 与截图),可继续阅读 packages/sdk/README.md。
【免费下载链接】stitch-sdk
Generate UI screens from text prompts and extract their HTML and screenshots programmatically.
相关推荐
Wails自动绑定生成机制揭秘:从Go代码到TypeScript类型定义的完整指南
Wails自动绑定生成机制揭秘:从Go代码到TypeScript类型定义的完整指南 Wails框架的自动绑定生成机制是其最强大的功能之一,能够将Go语言的后端代
桌面应用跨平台CLI前端Higress WASM Go SDK 实现 MCP Server 完整指南:从工具开发到 REST-to-MCP 零代码转换
Higress WASM Go SDK 实现 MCP Server 完整指南:从工具开发到 REST to MCP 零代码转换 本篇技术指南围绕 Higress
API网关后端云原生LLM 网关人工智能MCP 服务Stitch SDK接入Vercel AI SDK:让Gemini自主调用MCP工具生成UI界面
Stitch SDK接入Vercel AI SDK:让Gemini自主调用MCP工具生成UI界面 Stitch SDK 是一款开源的 Text to UI 开发
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考