ClaudeCode+GLM双模型协同编程:Vibe Coding实战指南
1. 项目概述当代码生成不再“单打独斗”而是双模型协同编排“ClaudeCode GLM 进行 Vibe Coding”——这个标题乍看像一句极客圈的暗号但背后是一次真实、可复现、且已在多个中小型开发团队落地的工程实践升级。它不是简单地把两个大模型并排放在一起而是构建了一套有明确角色分工、信息流向可控、反馈闭环可调的轻量级协同编码工作流。我从去年底开始在内部工具链中试点这套模式最初是为了解决一个非常具体的问题前端同学写 React 组件时ClaudeCode 能快速生成结构清晰、TypeScript 类型完备的骨架但对国内主流 UI 库如 Arco Design、NutUI的组件命名习惯、Props 约定、主题变量注入方式总是“差一口气”而本地部署的 GLM-4-9B 模型虽在中文语义理解、上下文连贯性上更贴合国内开发者的表达逻辑却缺乏对现代前端工程链路Vite TSX SWC的原生认知深度。于是我们没去硬训一个“全能模型”而是让 ClaudeCode 做“架构师接口定义者”GLM 做“本地化实现者业务语义翻译官”中间用一套极简的 JSON Schema 协议做“语言转换器”。这种组合不是拼凑而是基于能力边界的理性拆分ClaudeCode 处理抽象层API 设计、状态流、错误边界GLM 处理具象层组件渲染逻辑、表单校验文案、Toast 提示语本地化、与内部微前端基座的通信桥接。它不追求“一键生成完整应用”而是确保每一段被生成的代码都带着可追溯的意图、可验证的约束、可插拔的上下文。适合正在用 LLM 辅助开发但常遇到“生成代码跑不通”“改三遍才像人写的”“中文需求转代码总漏细节”的中高级前端/全栈工程师也适合技术负责人评估如何在不推翻现有基建的前提下渐进式提升团队 AI 编程采纳率。2. 核心设计思路为什么是 ClaudeCode GLM而不是其他组合2.1 能力图谱错位匹配不是“谁更强”而是“谁更准”很多人第一反应是“为什么不直接用 GPT-4 Turbo 或 Qwen2.5它们参数更大、上下文更长。” 这恰恰是我们踩过坑后最核心的认知转变——在真实编码场景中“强”不等于“准”“全”不等于“稳”。我们做过横向对比测试给定同一份 PRD“用户登录页需支持手机号验证码、微信快捷登录、记住我、密码找回样式按公司 Design Token v3.2”让 ClaudeCode-3.5、GPT-4o、GLM-4-9B量化版、Qwen2.5-7B 各自生成 React TypeScript 实现。结果很反直觉GPT-4o 生成的代码语法最华丽用了大量useMemo和useCallback但其中 37% 的依赖数组写错导致useEffect无限循环Qwen2.5 在中文提示词下表现稳定但对arco-design/web-react的Input.Password组件的visibilityToggle属性名识别错误写成了showPasswordToggleGLM-4-9B 生成的 JSX 结构最“土”没有花哨 Hook但所有组件 import 路径、Props 名称、Token 变量引用如--arcoblue-6全部精准匹配公司内部文档ClaudeCode-3.5 生成的代码里AuthContext的 Provider 结构、loginWithWechat()的 Promise 返回类型、甚至handleFormSubmit中对zodschema 的safeParseAsync调用都完全正确但它把微信图标写成了IconWechat /而我们实际用的是WeChatIcon /。这揭示了一个关键事实ClaudeCode 的强项在于“工程契约意识”——它对现代前端框架的约定、类型系统、异步处理范式有近乎本能的尊重GLM 的强项在于“语境锚定能力”——它能从你一句“那个蓝色按钮要和首页保持一致”里自动关联到 Design Token 文档第 4.2 节的--primary-color定义并在 CSS-in-JS 中正确注入。它们的能力边界天然互补而非重叠。强行用一个模型覆盖全部就像让一个擅长画建筑蓝图的设计师去亲手砌每一块砖——蓝图再精准砌砖的手感和材料特性他并不熟悉。2.2 架构选型为什么拒绝“模型融合”或“微调”坚持“协议驱动协同”市面上常见两种思路一是用 LoRA 微调一个基础模型如 Qwen注入公司代码库知识二是用 RAG 技术把内部 Wiki、组件库文档喂给向量库让模型实时检索。我们试过效果都不理想。微调的问题在于“泛化失焦”当你把 200 个内部组件的 Props 文档微调进去模型在生成新组件时会过度拘泥于已有模式比如看到“表单”就必加Form.Item哪怕需求只是个简单搜索框RAG 的问题则是“检索噪声”当提示词是“实现一个带 loading 状态的按钮”向量库可能召回“Button 组件 API 文档”“Loading 组件文档”“全局状态管理文档”三份内容模型需要自己判断优先级而它的判断常出错——曾有一次它把 Loading 文档里的spin属性名错误地覆盖到了 Button 的loading属性上生成了Button spin{true} /。所以我们彻底转向“协议驱动协同”不改变任一模型的原始能力只定义它们之间交换什么、怎么交换、交换后怎么用。整个流程只有三个刚性环节ClaudeCode 输出“契约层”JSON包含interfaceDefsTypeScript 接口定义、apiEndpointsMock API 路径与响应结构、stateFlow状态变更图用 Mermaid 语法描述但仅作注释不执行、uiConstraintsUI 约束如“主按钮必须使用 primary token”“错误提示需在输入框下方”GLM 接收 JSON输出“实现层”TSX严格按interfaceDefs实现组件 Props 类型按apiEndpoints封装fetch调用按uiConstraints选择对应组件和样式人工审核点设在 JSON 生成后、TSX 生成前这是最关键的“人机协作闸门”。开发者只需花 30 秒确认 JSON 里的接口名、字段类型、API 路径是否符合预期一旦确认后续 TSX 生成即视为可信。这个设计牺牲了“全自动”但换来了“可解释、可调试、可归责”。当生成的代码出问题你能立刻定位是契约错了ClaudeCode 问题还是实现错了GLM 问题而不是面对一团混沌的“AI 黑箱输出”。2.3 “Vibe Coding” 的本质不是写代码是校准意图共振频率“Vibe Coding”这个词容易被误解为“随性编码”其实它来自音乐制作术语“vibe matching”——指不同音轨在节奏、调性、情绪上达成微妙共振。在我们的实践中它特指开发者输入的自然语言提示Prompt与 ClaudeCode 生成的契约 JSON与 GLM 生成的最终代码在“业务意图”这一维度上保持高度一致。例如当你写提示“做个登录弹窗微信登录按钮要大一点显得更友好”ClaudeCode 的 JSON 里uiConstraints字段会明确写出wechatButtonSize: largeGLM 的 TSX 里就会用Button sizelarge icon{WeChatIcon /} /而不是默认的sizedefault。这种一致性不是靠模型“猜”而是靠我们在协议中强制定义了uiConstraints的 Schema要求所有视觉相关约束必须用预设枚举值small | medium | large | fullWidth杜绝自由发挥。我们甚至为此写了简单的 Schema 校验脚本如果 ClaudeCode 输出的 JSON 不符合该 Schema流程就中断提示“请重新描述 UI 约束”。这看似增加了步骤实则大幅减少了后期返工——因为“大一点”这种模糊表述在契约层就被翻译成了机器可执行、人可验证的精确指令。3. 核心细节解析从协议定义到本地部署的实操要点3.1 协议 Schema 设计让两个模型“说同一种话”协议的核心是一个精简但覆盖关键维度的 JSON Schema。我们刻意避免过度设计只保留开发中最常出错、最需对齐的 5 个字段。Schema 本身用 TypeScript Interface 描述方便前端同学直接复用为类型定义interface CodingContract { // 1. 接口定义ClaudeCode 必须输出GLM 必须严格实现 interfaceDefs: { componentName: string; // 组件名如 LoginForm propsInterface: string; // 完整的 TS 接口字符串含 JSDoc contextInterface?: string; // 可选Context 类型 }; // 2. API 约定定义组件依赖的后端接口 apiEndpoints: { login: { method: POST; path: /api/v1/auth/login; response: { token: string; user: { id: number } } }; sendCode: { method: POST; path: /api/v1/sms/send; response: { codeId: string } }; }; // 3. 状态流用 Mermaid 注释描述不执行仅作人审依据 stateFlow: string; // 如 state --|submit success| redirectHome\nstate --|error| showToast // 4. UI 约束强制枚举杜绝模糊表述 uiConstraints: { primaryColorToken: --arcoblue-6; // 必须是 Design Token 名 buttonSize: large | medium | small; // 枚举值 formLayout: vertical | horizontal; // 枚举值 }; // 5. 工程约束告诉 GLM 当前项目的技术栈 engineeringContext: { framework: react; typescriptVersion: 5.3; uiLibrary: arco-design/web-react; bundler: vite; }; }提示这个 Schema 是我们迭代 7 个版本后的结果。早期版本包含animationEffects动效要求、accessibilityRules无障碍规则等字段但发现 ClaudeCode 生成时极易遗漏导致流程中断。后来我们遵循“最小可行契约”原则只保留 5 个高频、高影响字段其余细节如动效交由 GLM 在实现层根据engineeringContext.uiLibrary自动推断——因为 Arco Design 的 Button 组件sizelarge本身就带入场动画无需额外声明。3.2 ClaudeCode 调用配置如何让它“只说契约不说实现”ClaudeCode 默认行为是直接生成代码我们必须用 System Prompt 强制其切换到“契约师”角色。关键在于三点角色定义、输出格式锁定、错误兜底机制。System Prompt精简版实际使用中为 320 字你是一名资深前端架构师专精于 React TypeScript 工程规范。你的唯一任务是根据用户需求输出严格符合 CodingContract Schema 的 JSON 对象。禁止输出任何代码、HTML、CSS、Markdown 解释、额外说明。如果需求模糊如未指定 UI 库必须用 JSON 字段 errors: [请明确指定使用的 UI 组件库如 arco-design/web-react] 表示而非猜测。输出必须是纯 JSON无任何包裹如 json ... 无 BOMUTF-8 编码。实操心得我们发现 ClaudeCode 对interfaceDefs.propsInterface的生成质量极高但常把contextInterface写成空对象{}。解决方案是在 System Prompt 末尾加一句“若组件无需 Context请省略 contextInterface 字段而非输出空对象。” 这样它就学会了“省略即否定”。对于uiConstraints我们给它一个内部词典映射表作为 Prompt 的一部分大一点 - large 小一点 - small 和首页一样 - --arcoblue-6 用公司蓝 - --arcoblue-6 文字居中 - center这比让它自己“理解”中文更可靠。这个词典是团队共同维护的每周同步更新。3.3 GLM 本地部署与调优轻量化、低延迟、高可控我们选用 GLM-4-9B-ChatINT4 量化版部署在一台 24GB 显存的 RTX 4090 工作站上。不选更大模型是因为实测发现在“契约→实现”这个窄任务上9B 模型的准确率按字段匹配度计算已达 92.7%而 32B 模型仅提升至 94.1%但推理延迟从 850ms 升至 2.3s破坏了“即时反馈”的 Vibe 感。部署方案采用 Ollama 自定义 Modelfile关键配置如下# Modelfile FROM glm4:9b-chat-q4_0 # 设置系统提示锁定角色 SYSTEM 你是一名专注 React 组件实现的前端工程师技术栈为React 18, TypeScript 5.3, arco-design/web-react v3.12。 你的输入是 CodingContract JSON。你的输出必须是1) 一个完整的 .tsx 文件内容含 import、组件定义、导出2) 无任何额外解释、无注释、无 Markdown 包裹3) 所有 Props 类型必须严格匹配 interfaceDefs.propsInterface4) 所有 UI 元素尺寸、颜色必须严格匹配 uiConstraints。 # 指定 API 端口与上下文长度 PARAMETER num_ctx 4096 PARAMETER num_predict 2048 PARAMETER temperature 0.3 PARAMETER top_p 0.9注意temperature 0.3是关键。我们测试过 0.1过于死板无法处理契约中未明确定义的边缘 case如“微信图标旁加个文字说明”和 0.7过于发散会擅自添加useEffect监听全局键盘事件。0.3 是在“严格遵循契约”和“合理补全细节”之间的最佳平衡点。另外num_predict 2048确保能生成完整组件含所有 import 和逻辑避免被截断。3.4 工程集成如何嵌入现有开发流不增加负担我们没有开发独立 App而是将整个流程封装成 VS Code 插件开源在 GitHub名为vibe-coder。插件核心逻辑只有 3 个命令Vibe: Generate Contract选中一段自然语言需求或光标所在行调用 ClaudeCode API生成 JSON 并在新编辑器标签页打开自动格式化Vibe: Validate Send to GLM点击按钮运行本地 Schema 校验脚本。通过则调用本地 Ollama API将 JSON 发送给 GLM失败则高亮错误字段并给出修复建议如“uiConstraints.buttonSize 值 big 不在允许枚举中请改为 large”Vibe: Insert ComponentGLM 返回 TSX 后自动插入到当前文件光标位置并添加// Generated by Vibe Coding on ${date}注释。整个过程平均耗时 4.2 秒ClaudeCode 1.8s 校验 0.3s GLM 2.1s比手动敲一个完整登录组件平均 6.5 分钟快两个数量级。更重要的是它把“写代码”这个动作拆解为“确认契约”人脑和“执行实现”AI 脑两个清晰阶段开发者注意力始终聚焦在“意图是否被正确捕获”上而非“语法怎么写”。4. 实操过程详解从零开始搭建你的 Vibe Coding 环境4.1 环境准备硬件、软件与账号清单搭建环境不需要昂贵服务器一台性能尚可的个人工作站即可。以下是我们的生产环境配置清单已验证稳定运行 6 个月类别具体配置说明硬件CPU: AMD Ryzen 9 7950X (16核32线程)GPU: NVIDIA RTX 4090 (24GB VRAM)RAM: 64GB DDR5SSD: 2TB NVMeGPU 是关键RTX 4090 的 INT4 推理速度是 RTX 3090 的 2.8 倍CPU 和 RAM 主要用于 VS Code 和本地服务非瓶颈。操作系统Ubuntu 22.04 LTS推荐或 Windows 11 WSL2Linux 下 Ollama 部署更稳定Windows 用户务必用 WSL2原生 Windows 版 Ollama 对 GLM 支持不佳。必备软件- Node.js v20.12- Python 3.10- Ollama v0.3.5- VS Code v1.88Node.js 用于运行 VS Code 插件Python 用于本地校验脚本用jsonschema库Ollama 是 GLM 运行时VS Code 是主编辑器。账号与密钥- Anthropic API KeyClaudeCode- 无其他第三方账号我们使用 Anthropic 官方 API不走代理或第三方网关确保请求稳定。Key 存储在 VS Code 的settings.json中加密处理。提示如果你的 GPU 显存不足 24GB可用glm4:9b-chat-q4_k_m更激进的量化版它能在 12GB 显存如 RTX 3060 12G上运行但首 token 延迟会升至 1.2s整体体验稍逊。绝对不要尝试q2_k精度损失过大uiConstraints字段匹配错误率飙升至 35%。4.2 步骤一部署 GLM-4-9B 到本地 Ollama这是整个流程的基石必须一次成功。以下是详细命令流每一步都附带验证方法1. 安装 Ollama# Ubuntu curl -fsSL https://ollama.com/install.sh | sh # 启动服务并验证 ollama serve curl http://localhost:11434/api/tags # 应返回 {}表示服务正常2. 创建并运行 GLM Modelfile# 创建 Modelfile cat Modelfile EOF FROM glm4:9b-chat-q4_0 SYSTEM 你是一名专注 React 组件实现的前端工程师技术栈为React 18, TypeScript 5.3, arco-design/web-react v3.12。 你的输入是 CodingContract JSON。你的输出必须是1) 一个完整的 .tsx 文件内容含 import、组件定义、导出2) 无任何额外解释、无注释、无 Markdown 包裹3) 所有 Props 类型必须严格匹配 interfaceDefs.propsInterface4) 所有 UI 元素尺寸、颜色必须严格匹配 uiConstraints。 PARAMETER num_ctx 4096 PARAMETER num_predict 2048 PARAMETER temperature 0.3 PARAMETER top_p 0.9 EOF # 构建模型首次需下载约 5.2GB ollama create vibe-glm -f Modelfile # 验证模型是否可用 ollama run vibe-glm Hello # 应快速返回类似 Hello! How can I help you today? 的响应3. 关键验证测试契约解析能力# 准备一个最小契约 JSON保存为 test-contract.json { interfaceDefs: { componentName: TestButton, propsInterface: interface TestButtonProps {\n onClick: () void;\n children: string;\n} }, uiConstraints: { buttonSize: large, primaryColorToken: --arcoblue-6 } } # 调用模型传入 JSON 字符串 echo $(cat test-contract.json) | ollama run vibe-glm # 预期输出应为合法 TSX无额外文本 import React from react; import { Button } from arco-design/web-react; interface TestButtonProps { onClick: () void; children: string; } export const TestButton: React.FCTestButtonProps ({ onClick, children }) { return Button sizelarge style{{ --primary-color: var(--arcoblue-6) }} onClick{onClick}{children}/Button; };实操心得如果输出包含Here is the implementation:或 tsx等前缀说明 SYSTEM Prompt 未生效。检查 Modelfile 中SYSTEM指令是否在FROM之后、PARAMETER 之前且引号闭合正确。我们曾因一个中文全角引号导致失败调试了 2 小时。4.3 步骤二配置 VS Code 插件与 ClaudeCode API我们使用开源插件vibe-coderGitHub 仓库github.com/your-org/vibe-coder它已预置了 ClaudeCode 调用逻辑和本地 GLM 调用逻辑。安装步骤如下1. 安装插件# 在 VS Code 中按 CtrlShiftP输入 Extensions: Install from VSIX # 选择下载好的 vibe-coder-1.2.0.vsix 文件从 GitHub Release 页面下载2. 配置 API Key 与本地模型在 VS Code 设置settings.json中添加{ vibeCoder.anthropicApiKey: sk-ant-api03-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx, vibeCoder.glmEndpoint: http://localhost:11434/api/chat, vibeCoder.glmModelName: vibe-glm }3. 验证全流程新建一个.tsx文件输入任意自然语言需求如实现一个带加载状态的提交按钮点击后禁用显示“提交中...”成功后显示“提交成功”3秒后恢复。选中此行按CtrlShiftP输入Vibe: Generate Contract回车。观察新标签页应出现格式化 JSONinterfaceDefs.propsInterface包含loading: boolean和onSuccess: () voiduiConstraints包含buttonSize: medium。点击Vibe: Validate Send to GLM按钮。等待几秒观察状态栏应显示Vibe Coding: Component generated successfully。按CtrlShiftP输入Vibe: Insert Component回车。光标处应插入完整、可运行的 TSX 组件。注意首次运行时Ollama 可能因缓存未热身GLM 响应稍慢约 3.5s。连续运行 3 次后VRAM 缓存建立稳定在 2.1s。这是正常现象无需干预。4.4 步骤三编写你的第一个 Vibe Coding 组件现在让我们用一个真实业务场景——“商品详情页的收藏按钮”——来走一遍完整流程。这个例子能体现 Vibe Coding 在处理“状态联动”和“UI 约束”上的优势。1. 输入自然语言提示在 VS Code 中实现一个商品详情页的收藏按钮。未收藏时显示空心爱心图标点击后变为实心爱心显示“已收藏”并触发收藏 API已收藏时显示实心爱心点击后变为空心显示“取消收藏”并触发取消 API。按钮大小为 large颜色用 --arcored-5收藏红悬停时颜色加深。需要支持 loading 状态。2. ClaudeCode 生成的契约 JSON关键字段节选{ interfaceDefs: { componentName: ProductFavButton, propsInterface: interface ProductFavButtonProps {\n /** 商品 ID */\n productId: number;\n /** 当前是否已收藏 */\n isFavorited: boolean;\n /** 收藏状态变更回调 */\n onToggle: (isFavorited: boolean) void;\n /** 加载中状态 */\n loading: boolean;\n} }, apiEndpoints: { favorite: { method: POST, path: /api/v1/product/favorite, response: { success: true } }, unfavorite: { method: DELETE, path: /api/v1/product/favorite/{productId}, response: { success: true } } }, uiConstraints: { buttonSize: large, primaryColorToken: --arcored-5, hoverColorToken: --arcored-7 } }3. GLM 生成的 TSX经格式化后import React, { useState } from react; import { Button, IconHeart, IconHeartFill } from arco-design/web-react; interface ProductFavButtonProps { /** 商品 ID */ productId: number; /** 当前是否已收藏 */ isFavorited: boolean; /** 收藏状态变更回调 */ onToggle: (isFavorited: boolean) void; /** 加载中状态 */ loading: boolean; } export const ProductFavButton: React.FCProductFavButtonProps ({ productId, isFavorited, onToggle, loading, }) { const [isHovered, setIsHovered] useState(false); const handleClick async () { if (loading) return; try { if (isFavorited) { // 调用取消收藏 API await fetch(/api/v1/product/favorite/${productId}, { method: DELETE, }); onToggle(false); } else { // 调用收藏 API await fetch(/api/v1/product/favorite, { method: POST, headers: { Content-Type: application/json }, body: JSON.stringify({ productId }), }); onToggle(true); } } catch (error) { console.error(收藏操作失败:, error); } }; const buttonStyle { --primary-color: var(${isHovered ? --arcored-7 : --arcored-5}), }; return ( Button sizelarge style{buttonStyle} onClick{handleClick} onMouseEnter{() setIsHovered(true)} onMouseLeave{() setIsHovered(false)} loading{loading} icon{ isFavorited ? IconHeartFill / : IconHeart / } {isFavorited ? 已收藏 : 收藏} /Button ); };实操心得这个组件里GLM 自动实现了useState管理 hover 状态、fetch调用的完整封装、onMouseEnter/Leave的绑定且所有style写法、icon组件名、size属性值都 100% 匹配 Arco Design v3.12 文档。它甚至正确处理了loadingProp 的禁用逻辑if (loading) return。这些都不是我们教它的而是它在engineeringContext和uiConstraints的双重约束下自主推断出的最优解。这就是“Vibe”——模型在契约框架内找到了与你业务语境最和谐的实现频率。5. 常见问题与排查技巧实录那些文档里不会写的坑5.1 问题速查表高频故障与一键修复问题现象根本原因一键修复方案预防措施ClaudeCode 返回{errors: [请明确指定使用的 UI 组件库...]}提示词中未提及 UI 库名称或用了模糊表述如“用公司组件”在提示词末尾追加明确语句“使用 arco-design/web-react v3.12 组件库”在 VS Code 插件设置中预置常用 UI 库模板输入/arco自动补全。GLM 生成的 TSX 中import 路径错误如import { Button } from arcoGLM 训练数据中存在旧版 Arcov2.x的导入路径未被engineeringContext完全覆盖在 Modelfile 的SYSTEM提示中增加一句“所有 import 必须使用完整包名如arco-design/web-react禁止缩写或别名。”每次更新 UI 库大版本同步更新 Modelfile 的SYSTEM提示。生成的组件中fetch调用未处理Content-TypeheaderapiEndpoints中未定义headers字段GLM 默认不加在契约 Schema 中为apiEndpoints的每个 endpoint 增加可选字段headers: Recordstring, string并在 ClaudeCode 的 System Prompt 中要求“若 API 需要 JSON body必须在 headers 中指定Content-Type: application/json”将此规则写入团队《AI 编程协作规范》第一条。VS Code 插件报错Failed to connect to localhost:11434Ollama 服务未启动或端口被占用终端执行ps aux | grep ollama查进程kill -9 pid后重试ollama serve或修改settings.json中vibeCoder.glmEndpoint为http://127.0.0.1:11434/api/chat在插件启动时自动检测 Ollama 状态失败则弹窗提示“请运行ollama serve”。生成的组件中useState初始化值与props类型不匹配如const [count, setCount] useState(0)但 props 无 countGLM 错误地引入了无关状态在SYSTEM提示末尾加“禁止创建任何未在 interfaceDefs.propsInterface 中声明的 state 变量。所有状态必须源于 props 或 API 响应。”在本地校验脚本中增加 AST 分析扫描生成代码中的useState调用比对 props 接口不匹配则报错。5.2 深度避坑三个“你以为的常识其实是最大陷阱”陷阱一“越详细的提示词生成效果越好”——错我们曾以为把 PRD 文档全文粘贴给 ClaudeCode它就能生成完美契约。结果恰恰相反当提示词超过 300 字ClaudeCode 开始“抓重点失焦”。它会忽略掉“按钮必须支持无障碍 ARIA 标签”这样的关键约束而去过度关注“页面顶部要有品牌 logo”这种 UI 层面的次要信息。真实经验是提示词必须遵循“3-3-3 原则”——3 个核心功能点如“收藏/取消”、“加载状态”、“悬停变色”、3 个关键约束如“用 --arcored-5”、“sizelarge”、“调用 /api/v1/product/favorite”、3 个禁止项如“不使用任何第三方图标库”、“不引入新 state”、“不写 CSS 类”。超过这个范围就用“详见附件”引导让 ClaudeCode 专注契约把细节留给 GLM 实现。陷阱二“GLM 生成的代码只要能跑通就行”——危险初期我们只验证组件能否编译、能否渲染结果上线后发现严重问题GLM 生成的fetch调用全部用了await但没做try/catch。当网络超时整个组件白屏。这不是 Bug而是能力边界——GLM 擅长“按契约实现”但不擅长“防御性编程”。我们的解决方案是在 VS Code 插件中集成 ESLint 规则typescript-eslint/no-unsafe-argument和typescript-eslint/no-floating-promises生成代码后自动运行eslint --fix。这相当于给 GLM 加了一道“安全护栏”它负责“写对”ESLint 负责“写稳”。现在所有生成的组件fetch调用都自动包裹try/catchPromise 都有.catch()或await无需人工检查。陷阱三“模型越新效果越好”——未必去年我们升级到 GLM-4-9B发现对uiConstraints.buttonSize的枚举匹配率从 92.7% 降到了 89.3%。排查发现新版本在训练时加入了更多通用网页数据削弱了对特定 UI 库的“肌肉记忆”。**最终我们回退到 GLM-4-9B
