☰
揭秘 Stitch SDK 零LLM代码生成管线:从 MCP 工具清单到强类型 TypeScript SDK 的完整指南
2026/10/11 14:55:43 网站建设 项目流程

【免费下载链接】stitch-sdk

Generate UI screens from text prompts and extract their HTML and screenshots programmatically.

项目地址:https://gitcode.com/gh_mirrors/st/stitch-sdk
点击查看免费下载

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/listtools-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 schemadomain-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.

项目地址:https://gitcode.com/gh_mirrors/st/stitch-sdk
点击查看免费下载

相关推荐

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

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

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

立即咨询