用 GPT 进行设计系统知识蒸馏:从文档到结构化规则的自动提取

📅 2026/7/17 17:35:21 👁️ 阅读次数 📝 编程学习
用 GPT 进行设计系统知识蒸馏:从文档到结构化规则的自动提取

用 GPT 进行设计系统知识蒸馏:从文档到结构化规则的自动提取

一、100 页设计规范 PDF 躺在共享文件夹里吃灰

公司有一套完整的设计规范:PDF 文档 100 页,包含了按钮规格、间距规则、色彩使用指南、状态机定义……每个新入职的前端都需要读一遍。事实是:没人读完过。真实开发流程是"凭感觉写 → Code Review 时被设计走查打回 → 翻 PDF 找对应规则 → 修改"。

问题不在文档的内容质量,在于文档的形态。人类阅读 PDF 很舒服,但机器无法消费。如果每一条设计规则都能被解析为结构化的可执行约束(JSON 格式),就能在 CI 中自动检查、在 IDE 中实时提示。

知识蒸馏(Knowledge Distillation)在 ML 领域指"大模型的知识压缩到小模型",但在设计系统场景中,它的意思是:把非结构化的设计文档蒸馏为结构化的规则库

二、文档 → 规则的蒸馏管道

蒸馏的核心不是"用 LLM 重新写文档",而是让 LLM 从已有文档中提取规则。LLM 擅长做的是:从一段自然语言描述中识别出"主语-谓语-宾语",映射为"设计元素-约束类型-约束值"。

三、蒸馏工具实现

// knowledge-distillation/distiller.ts // 设计系统知识蒸馏引擎 // 从设计文档中自动提取结构化规则 import fs from 'fs'; import path from 'path'; /** 单条设计规则的结构化表示 */ interface DesignRule { /** 规则 ID,唯一标识 */ id: string; /** 规则类型 */ category: 'color' | 'spacing' | 'typography' | 'component' | 'layout' | 'animation'; /** 规则适用对象:'.btn', 'h1', 'input' 等 */ target: string; /** 约束的属性:'font-size', 'border-radius', 'color' 等 */ property: string; /** 约束的运算符 */ operator: 'eq' | 'in' | 'range' | 'gte' | 'lte' | 'oneOf'; /** 约束值 */ value: string | string[] | { min: number; max: number }; /** 原始文档引用(可追溯) */ source: string; /** 蒸馏置信度 0~1 */ confidence: number; /** 能否自动执行 */ autoEnforceable: boolean; } /** * 从 Markdown 设计文档中蒸馏规则 * * 策略:分三步走—— * 1. 按章节分割文档(每个 ## 标题为一个规则域) * 2. 每段送入 LLM 进行结构化提取 * 3. 合并、去重、评分 */ async function distillFromMarkdown(markdownPath: string): Promise<DesignRule[]> { const content = fs.readFileSync(markdownPath, 'utf-8'); const sections = splitIntoSections(content); const allRules: DesignRule[] = []; for (const section of sections) { const prompt = buildDistillationPrompt(section); // 调用 LLM API(此处为接口示意,实际使用 OpenAI/Anthropic API) const rules = await callLLMForRules(prompt); allRules.push(...rules); } return mergeAndDeduplicate(allRules); } /** * 将 Markdown 按 ## 标题分割为章节 */ function splitIntoSections(markdown: string): Array<{ title: string; content: string }> { const sections: Array<{ title: string; content: string }> = []; const lines = markdown.split('\n'); let currentTitle = ''; let currentContent: string[] = []; for (const line of lines) { if (line.startsWith('## ') && !line.startsWith('### ')) { if (currentTitle) { sections.push({ title: currentTitle, content: currentContent.join('\n') }); } currentTitle = line.replace('## ', '').trim(); currentContent = []; } else { currentContent.push(line); } } if (currentTitle) { sections.push({ title: currentTitle, content: currentContent.join('\n') }); } return sections; } /** * 构建蒸馏 Prompt * * 核心指令:从设计文档片段中提取结构化规则 * 输出格式:JSON 数组 * * Prompt 设计要点: * 1. 明确输出 schema——约束 LLM 只能输出合法 JSON * 2. 提供 few-shot 示例——帮助 LLM 理解期望格式 * 3. 要求置信度——让下游能区分"明确的规则"和"推测的规则" */ function buildDistillationPrompt(section: { title: string; content: string }): string { return ` 你是一个设计系统知识蒸馏助手。请从以下设计规范文本中提取结构化规则。 ## 输出格式 每条规则为 JSON 对象,包含以下字段: { "category": "color|spacing|typography|component|layout|animation", "target": "规则适用的设计元素(如 .btn, h1, input, .card 等)", "property": "约束的 CSS 属性(如 font-size, border-radius, color)", "rule": "具体的约束描述(如 字体大小 14px, 圆角 4px, 间距使用 8px 倍数)", "confidence": 0.0-1.0 之间的置信度(原文明确提及=1.0,从上下文推断=0.5-0.8) } ## Few-shot 示例 输入: "所有主按钮的圆角为 4px,hover 时背景色加深 10%" 输出: [ { "category": "component", "target": ".btn-primary", "property": "border-radius", "rule": "border-radius: 4px", "confidence": 1.0 }, { "category": "component", "target": ".btn-primary:hover", "property": "background-color", "rule": "background-color 需比默认态深 10%", "confidence": 0.9 } ] ## 章节标题 ${section.title} ## 章节内容 ${section.content} 请仅输出 JSON 数组,不要输出其他内容。 `.trim(); } /** * 调用 LLM 提取规则(示意实现) * 实际需要替换为 OpenAI/Anthropic SDK 调用 */ async function callLLMForRules(prompt: string): Promise<DesignRule[]> { // 实际实现中,这里调用 GPT-4/Claude API // const response = await openai.chat.completions.create({ // model: 'gpt-4', // messages: [{ role: 'user', content: prompt }], // temperature: 0.1, // 低温度确保输出稳定 // response_format: { type: 'json_object' } // }); // return JSON.parse(response.choices[0].message.content); // 示意返回 return []; } /** * 合并去重:多条规则指向同一个约束时,保留置信度最高的 */ function mergeAndDeduplicate(rules: DesignRule[]): DesignRule[] { const map = new Map<string, DesignRule>(); for (const rule of rules) { // 生成去重 key:category + target + property 的组合 const key = `${rule.category}:${rule.target}:${rule.property}`; if (!map.has(key) || map.get(key)!.confidence < rule.confidence) { map.set(key, { ...rule, id: key }); } } return Array.from(map.values()); }
// knowledge-distillation/rule-to-lint.ts // 将蒸馏出的规则转换为可执行的 Stylelint/ESLint 规则 interface LintRuleGenerator { generateStylelintRule(rule: DesignRule): string; generateESLintRule(rule: DesignRule): string; } /** * 将设计规则转换为 Stylelint 自定义规则代码 */ function designRuleToStylelint(rule: DesignRule): string { switch (rule.category) { case 'color': return generateColorLintRule(rule); case 'spacing': return generateSpacingLintRule(rule); case 'typography': return generateTypographyLintRule(rule); default: return `// TODO: ${rule.category} 类型的规则暂不支持自动生成`; } } /** * 生成颜色规则(示例:检查是否使用了 Tokens 之外的颜色值) */ function generateColorLintRule(rule: DesignRule): string { return ` // 自动生成于设计系统知识蒸馏 // 规则来源:${rule.source} // 置信度:${rule.confidence} module.exports = { rules: { 'color-no-untokenized': { meta: { messages: { rejected: '颜色值应使用设计 Token,不允许硬编码颜色' } }, create(context) { return { Declaration(node) { if (node.prop.includes('color') || node.prop === 'background') { // 检查值是否为 hex 或 rgb(非 var() 形式) if (/^#[0-9a-fA-F]{3,8}$/.test(node.value) || /^rgb/.test(node.value)) { context.report({ node, message: \`颜色 "\${node.value}" 应替换为设计 Token\` }); } } } }; } } } }; `.trim(); } function generateSpacingLintRule(rule: DesignRule): string { return ` // 间距必须是 4px 的倍数 // 来源:${rule.source} module.exports = { rules: { 'spacing-multiple-of-4': { create(context) { return { Declaration(node) { const spacingProps = ['margin', 'padding', 'gap']; if (spacingProps.some(p => node.prop.includes(p))) { const match = node.value.match(/(\\d+)px/g); if (match) { for (const val of match) { const num = parseInt(val); if (num % 4 !== 0 && num !== 0) { context.report({ node, message: \`间距 \${num}px 不是 4px 的倍数,建议使用 \${Math.round(num/4)*4}px\` }); } } } } } }; } } } }; `.trim(); } function generateTypographyLintRule(rule: DesignRule): string { return ''; }

四、蒸馏的准确性边界

LLM 会"发明"文档中不存在的规则。这是蒸馏最大的风险。降低幻觉的策略:

  • 温度参数设 0.1(接近确定性输出)
  • 要求引用原文(每条规则附带source字段,指向原始文档的具体段落)
  • 置信度 < 0.8 的规则必须人工 Review,不能直接入库

公式和数值关系 LLM 处理得很差。"主色加深 10%"这种规则,LLM 可能正确提取为darken(primary, 10%),也可能理解为primary 的 L 分量减少 10——完全是不同的结果。数值型规则只适合做"提取",不适合让 LLM 做"计算"。

文档更新后蒸馏的增量处理。不是每次文档变更都全量蒸馏。更好的方案:对比新旧文档,只对变更的章节重新蒸馏,避免"改了一个按钮的圆角 → 重新蒸馏整个 100 页文档"。

五、总结

设计系统的知识蒸馏是从"人可以读懂"到"机器可以执行"的翻译过程。三个步骤:

  1. 文档分段——按章节切分设计规范文档
  2. LLM 结构化提取——将自然语言规则转为 JSON 格式的约束对象
  3. 规则编译器——将 JSON 约束编译为 Stylelint/ESLint 规则、CI 脚本、IDE 提示

蒸馏不是替代设计文档。文档依然是人阅读的"真理源",蒸馏出的规则库是文档的"可执行镜像"。两者不是竞争关系,而是主从关系——文档变更 → 重新蒸馏 → 规则库同步更新。