
用AI写小程序这事我前前后后折腾了将近两个月。主力工具是claude-code中途穿插测试了智谱GLM-4.7和Kimi-2.5目标是从零把一个微信小程序商城项目跑起来。结论先说这三款工具都能写代码但真正把它们按在微信小程序这个场景里干活你遇到的坑一点也不比手写代码少甚至更多——因为它们很擅长一本正经地给出不能跑的代码。我这不是否定AI编码恰恰相反我最终留在工作流里的还是它们三个组合着用。只是希望后来者别被AI自动写小程序这类宣传带偏。这篇文章就是我这段时间的踩坑记录包括API细节的幻觉、分页逻辑的半成品、iOS平台特性的答非所问、打包超限这类非常具体的问题我把现象、排查链路和改进方案都写出来给正在用AI写小程序的你做个参考。1. 三款AI工具试水小程序的真实差异化体验先说个背景我之前的主力场景是写内部管理后台和Node.js服务那时候claude-code用得挺顺。这次切到微信小程序后我同时拉上了智谱GLM-4.7和Kimi-2.5倒不是贪多而是想看看国内模型的生态适配到什么程度。用下来的整体感受非常明确工具选型不是看谁的代码能力强而是看在小程序这个特定平台上谁能少胡说八道。1.1 claude-code会话式编码的便利与过时API陷阱claude-code对我来说最大的优势是它能直接读项目里的文件、跑命令甚至帮我分析报错堆栈。当一个小程序页面报wx.xxx is not defined这种错时它确实能顺着上下文找到问题源头。但问题也出在这里它太擅长顺着你问的方向圆回来。比如我让它实现微信小程序的登录态刷新逻辑它给出的wx.login配合wx.request方案本身没问题但把code2Session的请求参数写错了——appid和secret的字段顺序搞反照抄上去接口直接返回40029 invalid code。这类错误单看代码很难发现因为函数调用链是完整的参数位置也确实符合它自己定义的逻辑只有对照微信开放文档才能揪出来。另一个高频坑是生命周期。我让它写用户离开小程序时保存草稿的功能它给出的方案是在wx.onHide里存数据这倒没错但它在App.js里用的是onShow判定冷启动还是热启动对参数options.scene的判断逻辑整个是错的——它把我手写的业务代码和它凭空想象的场景混合在一起生成了一个看起来考虑到了边界情况、实际踩遍边界的代码块。1.2 智谱GLM-4.7中文理解自然但容易生成形似神不似的代码智谱GLM-4.7给我的感觉是中文表达的领悟力确实好。你描述列表上拉加载更多但别让用户在加载时疯狂触发重复请求它能准确捕捉到loading状态锁这个关键点生成的逻辑骨架是标准的。但它的问题在于微信平台知识的沉淀明显不如海外模型预期的那样好。我让它写wx.pageScrollTo配合scroll-view实现回到顶部它给出的代码里混着H5的window.scrollTo和document对象。在小程序环境里这套东西直接在编译阶段就报错可它自己并不觉得有问题。我需要的是一段即使在微信开发者工具里也能直接运行的代码它给的是任何前端项目中都可能见到的拼盘。1.3 Kimi-2.5补丁式修改效率高但有过度修改强迫症Kimi-2.5在修bug场景下的表现最突出。我印象最深的一次小程序商城页面的购物车角标不刷新我给它贴了出错页面的完整代码和报错信息它很快定位到是因为setData的数据路径写错了直接把嵌套对象当成平级字段更新。这个定位速度快于前两个工具修改建议也精准。但它有一个让我很难受的习惯每次修一个问题喜欢顺带优化周边代码。有一次我只让它改一个CSS样式问题它把我同一个页面里的onLoad请求逻辑也重构了。结果样式确实修好了但列表接口的page参数却从1变成了0导致第一页数据查不到。在claude-code里你可以通过文件版本管理把不需要的改动丢弃但Kimi-2.5这边的改动经常是跨多个文件的回滚成本明显更高。1.4 工具的适用边界对比为了让你快速决策我把这三个工具在小程序开发场景里的关键差异做了个表对比维度claude-code智谱GLM-4.7Kimi-2.5项目文件上下文理解强可直接读仓库中需要粘贴代码中上适合报错信息驱动微信API生成准确度中容易用旧版API中下API细节常错中但会编造平台能力列表分页等业务逻辑中上骨架完整中边界常漏中上修正bug快多文件协作改动的可控性高可精确指定一般低易过度修改中文需求理解中强强我的使用策略后来固定成**claude-code负责新页面开发和整体架构智谱GLM-4.7负责把中文需求转化成具体逻辑草稿Kimi-2.5专门用来修review时发现的bug。**这样各取所长也把各自的短板隔离得比较清楚。2. 最先翻车的位置微信API细节里的信息幻觉如果你问我在这些AI写小程序的过程中最常踩、最隐蔽的坑是什么我的回答是它们对微信平台API的知晓度停留在一个模糊的正确水平。你要求写一个功能它们能给出一个结构完整、注释工整的代码块里面的函数名听着都耳熟但拼出来就是和你当前的小程序基础库版本对不上。2.1 wx.request与抓包调试之间的字段错位先说直接触发我深挖这个问题的事件。当时我用Charles抓包排查小程序商城的商品列表接口为什么在真机上返回空数据对照AI生成的请求代码发现一个问题它的wx.request里把参数放在了data对象中这没错但自定义请求头header的字段Content-Type写成了application/x-www-form-urlencoded而后端接口要求的是application/json。抓包时能看到请求发出去了接口也返回了但业务码一直提示参数格式错误。这个坑之所以隐蔽是因为AI代码生成时通常不会主动告诉你这个header要和后端协商。它会默认一个常见值填进去。解决方案并不是换一个工具而是对所有涉及外部接口的请求人工核对一遍header和data的数据结构。我自己后来建立了一条规则凡是有wx.request的页面AI写完代码之后必须附带一份请求/响应字段映射表给我没有这张表的一律打回。2.2 页面设置标题两套API的混淆热词里提到的小程序动态设置标题也是重灾区。微信小程序里有三个长得差不多的APIwx.setNavigationBarTitle、uni.setNavigationBarTitleuni-app和page.setNavigationBarTitle。在不同框架下参数完全一致但调用对象不同。我用原生小程序开发时AI经常把uni.setNavigationBarTitle混进来因为它训练语料里HBuilderX项目太多了。更麻烦的是有一次我用了条件编译代码// #ifdef MP-WEIXIN让AI填里面的逻辑它直接把uni和wx.两个对象交叉混用编译能过运行就报错——因为条件编译代码在微信里仍然会检查uni对象是否存在。这类问题让我意识到跟AI协作时必须在一开始就明确告诉它当前的技术栈边界。我现在的AGENTS.md里写得很清楚原生微信小程序禁止使用uni、taro、document、window只允许wx前缀API和ES6标准语法。有了这个硬性约束犯错概率至少降低一半。2.3 生命周期函数的昨日重现微信小程序的生命周期函数就那么几个onLoad、onShow、onReady、onHide、onUnload。AI对它们的理解总体准确但在场景值和来源页面上容易瞎编。热词里那个微信小程序如何监听用户离开小程序就是典型案例。我分别问了三个AI工具答案惊人一致在App的onHide里写逻辑。这方向没错但它们都没主动提一个关键细节——onHide也会在用户从小程序跳转到另一个小程序、打开微信支付的收银台时触发。对于需要真正离开小程序的场景必须结合wx.onAppHide配合onShow的参数做二次判断或者用wx.getEnterOptionsSync记录前后台切换时间差。AI不会主动把这种边界情况讲全需要你自己逼问它还有哪些情况会触发它才会补上一句话。这类细节在实际项目里不是最耀眼的却恰恰是决定上线后用户是否骂娘的地方。我强烈建议拿到AI生成的含生命周期逻辑的代码后把触发条件写成一个表格逐个场景过一遍别省这一步。2.4 我总结的API核对清单为了避免每次都要重新踩坑我把AI常见幻觉点整理成了一个核对清单。凡是AI生成代码里涉及以下几类的我都默认不可信必须查文档wx.request的header与data字段结构任何与scene场景值、from来源相关的业务判断setNavigationBarTitle、setTabBarBadge、showShareMenu这类UI控制API的使用位置文件上传wx.uploadFile的name和formData字段支付相关wx.requestPayment的参数来源这个AI编造概率极高尤其是时间戳格式所有涉及getSystemInfoSync返回值字段名新版本基础库部分字段已被标记废弃AI容易给旧字段这套清单我贴在项目文档里每次AI生成完代码就对照着勾一遍不核对完不提交。3. 列表加载更多这类经典场景AI为什么总写半成品热词里有微信小程序页面列表加载更多这确实是小程序开发里的高频需求也是AI生成代码最容易看着能跑、实际却有五大缺陷的场景。我让三款AI都写过这个功能总结下来它们的问题高度集中**分页参数从0还是从1开始、是否有总数兜底、重复请求锁、空数据状态。**这四个里AI通常只管第一个和第四个中间两个全靠运气。3.1 一个典型的分页半成品长什么样我用一个简化的代码示例说明问题。这是某AI工具生成的列表加载更多逻辑Page({ data: { list: [], page: 1, hasMore: true, loading: false }, onLoad() { this.loadList(true); }, onReachBottom() { if (!this.data.hasMore) return; this.loadList(false); }, loadList(isRefresh) { if (this.data.loading) return; this.setData({ loading: true }); const page isRefresh ? 1 : this.data.page; wx.request({ url: https://api.example.com/list, data: { page, size: 10 }, success: (res) { const newList isRefresh ? res.data.list : this.data.list.concat(res.data.list); this.setData({ list: newList, page: page 1, hasMore: res.data.list.length 10, loading: false }); }, fail: () { this.setData({ loading: false }); } }); } });这段代码的结构是标准的但放进真实项目里至少有四个问题。第一loadList(true)是放在onLoad里调用的如果用户在onShow里还有别的刷新逻辑两个请求并发时loading锁会让其中一个静默失败列表就停留在旧数据。第二hasMore的判断完全依赖当次返回list长度是否等于size如果后端返回的最后一页正好是10条它就会再多请求一次空页虽然不至于出错但会有多余的请求。第三整个函数没有任何针对res.data.list是否为undefined的防御——接口报错时res.data还在但字段不存在直接.length就崩了。第四它完全没考虑loading状态下的用户提示用户连续滑动时底部什么反馈都没有。AI生成代码有一个通病**它倾向于生成一个理想状态的逻辑而不是生产环境的逻辑。**它知道你要分页却不知道你需要考虑下拉刷新和上拉到底同时触发断网重连后page还停留在错误位置快速滑到页面底部在没有更多数据时不能每次都弹toast这些真实情况。3.2 让AI一次写出完整分页逻辑的办法你当然可以在AI生成完之后再花30分钟补这些边界。但我更推荐在需求描述阶段就把约束写死。现在我在让AI写任何列表页之前会强制它遵守一套自己的分页约束五条首次加载和下拉刷新必须调用同一个reset流程把page重置为1、清空列表、取消所有未完成请求上拉加载必须校验loading和hasMore双重条件且loading锁在success/fail/complete里都要释放接口返回数据必须做字段存在性判断数据为空时显示暂无内容占位图当次返回条数小于size时hasMore直接置false禁止再用相等判断所有请求必须携带一个自增的requestId回调时校验是否为最新一次请求避免旧请求覆盖新数据我最初是在单个页面的prompt里写这五条后来发现效率太低就抽成了AGENTS.md里的公共约定。这样一来不管用哪个AI工具只要它在我的项目目录下运行都会先读取这个文件再生成列表逻辑代码质量一下提升了一个档次。3.3 实测案例同一需求在三款工具上的表现我做了一个简单实验把同样的需求粘贴给三个AI写一个微信小程序商品列表页面支持下拉刷新和上拉加载更多接口返回结构是{ code, data: { list, total } }。结果如下claude-code生成的代码结构最完整但hasMore判断用了page * size total这个方案是对的前提是接口正确返回了total字段。它在onReachBottom里还额外加了一个throttle这一点值得表扬。智谱GLM-4.7生成的代码在concat时没有做去重如果接口分页边界有重复数据列表就会出现重复项。Kimi-2.5的代码用了Promise封装请求看起来更现代但在微信小程序里如果没有开启async/await的编译配置这段代码直接运行会报语法错误。这三份代码单独看都不算错但放到真实项目里你需要再投入20到40分钟修改边界、对接口字段、处理错误提示。这也是我对AI自动完成功能的基本心态它完成的只是骨架血肉必须靠你的业务理解去填充。4. 单选框、导航栏高度、防截屏——小功能里的答非所问如果说列表分页是AI的半成品那一些小功能点就是AI的幻觉重灾区。我挑三个热词里出现的具体功能讲讲它们是怎么答非所问的以及我怎么解决的。4.1 单选框radio-group还是checkboxAI经常分不清微信小程序的单选框组件是radio-group配合radio多选框是checkbox-group配合checkbox。听着简单但AI在生成选择支付方式这类实际上应该用单选框的需求时有时会给出checkbox-group因为它的训练语料里H5表单的typeradio的样式特征太强了。更隐蔽的问题在取值逻辑上。正确的radio-group触发事件里e.detail.value直接就是选中项的value字符串。AI生成的代码有时会写成e.detail.value[0]——这个是checkbox的取值方式放在radio上直接拿到undefined。我在一个会员信息编辑页面遇到这个问题当时AI给我的代码里事件绑定用的是bindchange取值的代码却沿用了上一次生成的checkbox逻辑。这类问题手工排查也能发现但如果不了解两个组件的差异很容易被AI的自信带着走。我的建议是所有表单类组件AI生成完之后立刻在微信开发者工具里手动点一遍确认选中状态和setData后的值。这类交互逻辑用眼睛验比用代码审查更高效。4.2 顶部导航栏高度胶囊按钮适配永远需要自己算热词里那条微信小程序顶部导航栏高度是另一个经典。小程序的自定义导航栏高度并非常量它由状态栏高度加胶囊按钮高度决定而胶囊按钮的位置在不同机型上还有差异。AI对这个问题的处理方式通常是给你一个固定的padding-top: 64px或者statusBarHeight 44px。实际在开发中我用的方案是wx.getMenuButtonBoundingClientRect()拿到胶囊按钮的坐标再结合wx.getSystemInfoSync().statusBarHeight计算导航栏高度。这套逻辑不算复杂但AI生成的概率很低因为它训练数据里大多数示例代码都是固定高度的。更离谱的是有一次AI给了我一个用env(safe-area-inset-top)的方案——那是H5页面的CSS写法小程序自定义导航栏里用这个安卓机直接不生效。我后来干脆把导航栏封装成了一个公共组件所有页面共用同一套高度计算逻辑彻底绕开让AI反复生成的问题。这个组件只让AI写了一次我审核通过之后就作为固定模板存在于项目里后续AI生成的页面都引用这个组件不再单独处理。这是我对抗AI小功能幻觉的核心思路把频次高、易出错的逻辑沉淀成自己的组件而不是每次都让AI从零生成。4.3 苹果防截屏AI会编造平台不存在的能力小程序苹果防截屏这个需求很有代表性因为它触及AI另一个大问题把Android的能力平移给iOS或者干脆编造一个听起来很合理的API。iOS上本身没有完全禁止截屏的公开API微信小程序平台也没有提供直接禁用截屏的能力。常见的方案是检测用户截屏后弹窗提示对应系统相册新增截图检测这在iOS私有API层面是可能的但小程序环境受限以及对敏感页面进行安全水印提示。我在对话中让AI实现iOS禁止截屏它的回答是让我在app.json里设置disableCapture: true——这个配置项在微信小程序里根本不存在。我一度怀疑是某个新出的基础库特性去官方文档里搜了一圈确认它完全是幻觉。应对这类问题我学到的教训是当AI给出一个听起来极为罕见或过于好用的平台能力时先去官方文档确认而不是先往项目里写。手机端可以通过在页面叠加一层cover-view避免内容被系统截屏录制部分安卓商城的防截屏机制iOS端则只能走敏感页面禁用截屏分享引导的路子。这类平台限制问题AI不会比你更懂因为它们没有在一个真实的小程序项目里被微信审核拒绝过。4.4 真机与模拟器的隐藏差异除了具体功能点我还有两个真机环境的坑AI完全无法预警。第一个是wx.getSystemInfoSync()在模拟器上的返回值与实际手机有差异尤其是screenHeight和windowHeightAI拿模拟器数据做布局计算真机上很容易出现底部按钮被遮挡。第二个是输入框type为number时Android和iOS弹出的键盘布局不一样AI生成的适配方案几乎没有一次是合理的我自己在真机上调试后最终选择了统一的typedigit。这类经验性知识恰恰是AI最缺失的。它能给你语法正确的代码但无法告诉你这段代码在vivo手机上键盘会把确认按钮挤到屏幕外。这也是为什么我始终觉得AI可以是一个高效的助手但它不能替代你在真机上的每一次点击。5. 让AI靠谱起来的小程序设计约束清单经过这轮折腾我把自己和AI协作的完整工作流沉淀下来了。不是复杂的框架就是一些写在项目文档里的硬性约束。你如果也想让AI写小程序少踩坑可以直接抄这套思路。5.1 项目级AGENTS.md约束让AI先读规则再写代码对于claude-code这类能读取项目文件的工具我在项目根目录放了一个AGENTS.md里面包括了groupId全部约束。例如这是一个原生微信小程序项目基础库版本为3.x禁止生成uni、taro、document、window、fetch相关代码所有网络请求使用wx.request且请求头必须由开发者确认列表分页必须遵守分页约束五条涉及iOS平台的能力必须先标注未经真机验证所有页面样式优先使用rpx单位禁止硬编码px导航栏高度用户隐私数据相关功能必须添加授权确认流程。这个文件的效果立竿见影。之前AI生成的代码里混入H5 API的概率很高加上约束之后这类低级错误减少了八成。它更像是给AI的入职手册让它在动手之前先搞清楚自己处在一个什么样的项目环境里。5.2 每个功能需求的五段式Prompt生成单个功能时我用的不是简单的一句话需求而是固定的五段式。这段结构我复制给三个AI工具都有效背景这个页面属于什么项目、给谁用、当前技术栈是什么必须写明原生wxml还是别的模板语法需求功能要做什么用户怎么操作操作后要看到什么效果边界哪些情况不能出现比如重复请求、空列表无提示、loading不消失接口后端接口的请求方式、入参字段、出参结构直接粘贴字段示例验收代码需要满足哪些条件才算完成比如能在开发者工具编译通过、真机上onReachBottom正常触发你有没有发现这正好对应了我前面踩过的坑API边界、分页半成品、生命周期细节、真机差异。只要把五段式写清楚AI生成的质量会从60分能用提升到80分可改。5.3 强制要求AI输出风险声明这是我觉得最值回票价的一招。我要求AI在每次生成完代码后额外输出一段本代码中可能存在的风险点至少列出三条不得写无。这不是刁难AI而是在倒逼它正视自己生成代码的不确定性。实践下来它列出的风险点虽然不一定准但往往能提醒我忽略的角落。比如有一次它写道wx.request的回调中未处理HTTP状态码非200的情况可能导致数据解析异常。这一条就帮我补位了一个遗漏的错误处理分支。5.4 明确区分生成与验证阶段最后一条工作流经验让AI写代码但不让AI验证自己写的代码。AI做自测时有一个天然的倾向就是确认自己的代码没问题。它给出的测试用例、边界场景清单往往跟它生成代码时假设的环境一致无法提供真正独立的视角。我都是让A工具生成用B工具review再人工跑真机验证。三款工具交叉使用正是这个工作流的副产品。6. 打包与上线的AI盲区体积超限、签名与隐私协议写代码只是前半段。小程序真正痛苦的阶段在打包上线而AI在这个阶段的帮助非常有限有些地方甚至会误导。热词里那条uniapp微信小程序打包 source size 2612kb exceed max limit 2mb正好戳中。6.1 主包体积超限AI不会主动帮你做分包微信小程序主包大小限制是2MB整个小程序总体积可以更大但主包有硬限制当你用uni-app或原生开发时图片、组件、第三方库很容易就把空间吃满。我遇到的真实情况是打包后source size显示2612KB超了612KB。我让AI分析为什么体积这么大它的第一反应是让我删掉无用的图片资源——这没错但删完还是超。后来我手动检查mini-program目录才发现问题是第三方UI组件库被完整打包进了主包而实际只用到了其中两个组件。AI推荐的用CDN加载图片压缩JS都不是根因正确的做法是启用分包加载把商城的商品详情页、订单列表页拆到subpackages里让主包只保留tabBar页面和公共组件。这个案例让我意识到AI擅长的是代码层面的优化而不是工程层面的架构决策。它会给你一堆减体积的小技巧却不会主动帮你重构目录结构。关于分包我的操作是先手动把页面归类确定哪些页面放主包、哪些放分包然后才让AI去调整对应的app.json配置和页面路径。这里不能偷懒因为AI对页面之间引用关系的理解远不到能自主决策的程度。6.2 隐私协议与用户授权AI的安全意识偏弱小程序审核现在对隐私协议很严格尤其是涉及用户信息收集的功能。AI在生成手机号快捷登录获取用户昵称头像这类代码时经常省略隐私授权弹窗的完整流程。它给出的版本往往是直接调wx.getUserProfile但忽略了app.json里需要先声明requiredPrivateInfos也忽略了用户拒绝授权后的二次引导逻辑。这块我没有找到让AI完全自动化的办法只能自己梳理一份项目隐私清单照着逐项确认。AI能帮你写获取用户信息的代码但它不知道你的小程序后台到底申请了哪些接口权限而这恰恰是审核被拒的重灾区。6.3 版本管理与AI协作的配合方式用AI写代码会引入一个新的工程问题你很难追踪某一段代码是AI写的还是自己写的。我一开始没注意后来发现AI改过的一个文件把之前的兼容逻辑覆盖了而我在review时只关注了它新增的部分。现在我的做法是所有AI改动必须通过git diff显式展示给我看确认之后再提交。并且我在分支命名上会标注feature-ai-xxx方便回退时快速定位。这不影响效率反而省去了很多这行代码是谁加的的扯皮时间。7. 最后再分享一点个人体会这段时间用三款AI工具写小程序最大的收获不是AI效率提升多少而是我看清了它的能力边界在哪。它可以帮你快速搭建一个页面骨架、可以帮你分析报错信息、可以帮你补充边界逻辑但它对微信平台版本演进的感知、对真机差异的认知、对审核规范的敏感度都还远远达不到独立开发者的水平。你要做的是把自己的经验注入到和AI的协作流程中——通过约束文件、通过五段式Prompt、通过强制风险声明——而不是期待AI替你做那些只有真实上线后你才懂的事。我现在的日常流程新功能先让claude-code搭骨架智谱GLM-4.7负责把需求里的中文描述翻译成更精确的逻辑说明Kimi-2.5处理review出来的bug最后我在真机上把所有交互过一遍。这个组合用下来差不多能让AI承担六成到七成的编码工作量。剩下的三四成不是AI偷懒而是那部分工作本来就需要踩过坑的人才能做。