被微信拒审那天,我正蹲在电脑前对着手机看后台状态,页面突然弹出一条红底通知:“当前提交的版本未通过审核,原因:类目与资质要求不符。”那一秒钟,我脑子里不是“改Bug”,而是“我到底做了什么”,因为我这个项目从头到尾都是靠“一个人 + AI”磨出来的:前后大约3万行代码、1.8万张素材,全是我一个人配合各种大模型工具一点一点拼出来的。
那段时间“Vibecoding”这个词还没有现在这么火,但回头看,我做得就是标准的Vibecoding:不懂的交给AI,懂一点的框架自己搭,让AI负责填肉,我负责把控“感觉对不对”。这种模式前期确实爽,功能迭代飞快,但等到平台审核把合规问题砸到脸上时,我才发现自己忽略了一整块工程能力——不是代码能力,而是对一个产品“为什么能上线、凭什么能过审”的判断能力。
这篇复盘,就是想把我从被拒审那天开始做的事、踩的坑、改的路径完整写下来。适合那些一个人在做小程序、想做小游戏、或者准备靠AI辅助冲一个完整产品的人看。不用是科班程序员,但一定要有耐心,因为Vibecoding真正的门槛,不在代码本身,而在“你能不能把AI产出的东西当成半成品来管理”。
1. 为什么我的小程序会变成“3万行代码 + 1.8万张素材”
1.1 项目到底是个什么形态
先说清楚项目定位。它是一个偏“图鉴收藏 + 分类浏览”类型的小程序,用户可以按标签筛选内容、查看大图、收藏夹、离线缓存。没有复杂交易,没有用户私密信息,也没有需要实时通信的能力。这种项目天然适合一个人做,因为核心是内容呈现和交互体验,而不是后端架构。
真正让它变得庞大的,是两个原因:第一,我希望交互不要太“模板化”,所以每个页面都有独立的动效和组件逻辑;第二,内容规模上去了,图片素材为了适配不同尺寸和场景,做了一堆衍生变体,最后就变成了1.8万张素材文件。单看3万行代码和1.8万张素材,好像是个大工程,但拆开看,代码大部分是重复性组件逻辑,素材大部分是同一批原图的尺寸变体、切图、压缩图和特殊效果图。
1.2 “Vibecoding”到底是什么意思
经常有人问我,Vibecoding是不是就是“让AI写代码,自己不动手”?我理解不是。Vibecoding更接近“用感觉驱动开发”:你不需要一开始就把架构想得滴水不漏,而是先有一个产品直觉,然后让AI快速帮你把界面和逻辑跑起来,你再像调音师一样,一点一点调整到“手感对了”的状态。
我的实际工作流程一般是:
- 我先画一个很潦草的手稿,说清楚页面大概长什么样、有什么按钮、点了之后发生什么。
- 把这段描述丢给大模型,让它生成一个“能跑的版本”。
- 我运行、体验、截图,再把截图和问题回传给AI,让它改。
- 改到界面顺眼、交互顺手后,再进入下一个模块。
这种方式最大的优势是产能高。我一个人做这个东西,从立项到第一次提审大概花了两个半月,如果按照传统方式,我不可能在这个时间内写完3万行代码,更别提还有素材生产流程。
1.3 数据和规模的意外膨胀
一开始我真没计划要做这么大。原设想是四五个页面、几百张图就够,结果随着需求越加越多——搜索结果、排序、收藏同步、空态页、引导页、加载动画、分享卡片——每个页面都要配套不同的图片状态,素材数量指数级上升。尤其是加载动画和背景纹理这类的装饰素材,同一套视觉要导出多种尺寸,经常一种尺寸就几百张。
到后面我索性用脚本批量生成,不再手工处理。代码也一样,AI生成的初始版本通常很臃肿,同一个逻辑在不同页面各写了一份,后来为了维护方便,我又重构了一轮,把共用部分抽象成组件,代码量不减反增,但结构清晰了很多。这里也想提醒看到这篇文章的人:AI生成代码很便宜,但“账面上很贵的”反而是你后续维护它的时间。如果你打算长期迭代,尽早做模块拆分,别等AI写出一堆重复代码后才想起来重构。
2. 一个人管理3万行AI代码,我靠的是这套方法
2.1 代码到底分布在哪里
先说代码总量。三万多行听起来吓人,但分布其实很均匀。我按实际用途拆成了五块:
| 模块 | 大致代码量(行) | 说明 |
|---|---|---|
| 小程序页面代码 | 约13000 | 页面逻辑、事件绑定、状态管理 |
| 组件代码 | 约7000 | 公共UI组件、卡片、列表、弹窗 |
| 工具函数与数据层 | 约5000 | 埋点、缓存、请求、格式化 |
| 素材生成脚本 | 约4000 | Python + Node 批量处理图片 |
| 构建与配置 | 约1500 | 打包脚本、manifest、路由配置 |
这个分布背后的逻辑很简单:页面代码是最容易让AI生成的,因为它不需要全局视野;组件代码则是用来约束AI“别再写重复的东西”的关键。
2.2 让AI生成代码时,我会刻意控制上下文大小
很多人用AI写代码时喜欢把整个项目丢给它,希望它“理解所有代码”,但在小程序这种规模下,上下文塞得越满,越容易让AI忽略最近的修改。我的做法是:按文件对话。每次只针对一个文件或一组相关文件提问,并且明确告诉AI“你只需要修改这个函数,不要动其他代码”。
比如我要给列表页加一个懒加载,我会这样告诉AI:
当前文件是 pages/list/index.ts,里面已经有 onReachBottom 方法。现在需要在这个方法里增加分页加载逻辑,要求:不超过50行,保持现有接口不变,错误处理用 catch。
这种“约束式提示”比“帮我优化列表页”有效得多。AI生成的东西会变得很聚焦,不需要我再花大量时间做diff审查。
2.3 版本控制是Vibecoding的生命线
Vibecoding项目里,AI会频繁重写函数,有时候它会把好的逻辑一并删掉,这几乎无法避免。如果不用版本控制,你根本不知道它动了什么。
我使用的流程非常简单:
# 每次AI改完代码后,先本地跑通 git add . git diff --cachedgit diff --cached这步很重要。提交前看一遍diff,确认改动方向和预期一致。虽然AI画龙点睛的能力很强,但它在“删除旧逻辑”这件事上特别激进,经常为了让新功能跑通,顺手把旧函数删了。我至少三次在diff里发现它删掉了埋点上报、错误边界之类看起来“不关键”但实际很重要的逻辑。
另外,遇到合并冲突时,我不急着让AI“解决冲突”,而是自己先看冲突上下文,再决定保留哪边。因为AI并不了解你的整体意图,它只知道当前文件里的这两段逻辑。
2.4 公共抽象层是我坚持让AI照抄的一份代码
为了不让AI每个页面都重新造一套轮子,我写了一个非常基础的公共层,包括请求封装、缓存管理器、图片懒加载、空态组件。然后我要求AI“以后所有新页面一律使用现有工具函数,禁止自行实现”。
这里有个反直觉的点:让AI生成代码时,“复制粘贴”反而比“创新”更重要。你在提示词里越是允许AI自由发挥,它越容易写出不一样风格的代码,后续维护成本越高。我对所有新增逻辑的默认要求是:先看公共层有没有,没有再说。
公共层的代码也不复杂,主要就是统一入口。比如图片加载:
export function loadImage(url: string): Promise<string> { return new Promise((resolve, reject) => { wx.getImageInfo({ src: url, success: (res) => resolve(res.path), fail: reject, }); }); }这种函数谁都会写,但它的意义在于,所有页面都不敢自己搞一套图片加载逻辑。只要公共层存在,AI再生成新页面时会倾向于引用它,因为我在提示词里反复强调过。
3. 1.8万张素材:从AI初稿到管线化管理
3.1 素材是怎么“膨胀”出来的
项目素材包含四类:主视觉插画、图标、卡片背景、动效序列帧。最初我想要的只是几百张主图,但实际交付过程中发现,每次设计变化都会带动一套衍生图变化。最典型的例子是主视觉从“亮色”改成“暗色调”后,所有图标、加载动画、空态页都要重新出一版,旧的又不想删,最后新旧两版素材各占了几千张。
后面我学聪明了,决定把素材生成流程做成“管线”:所有原始AI生成图都放在source/raw目录,不直接用于真机展示;凡是要发布到小程序里的图,全部经过脚本自动处理,从源图得到不同尺寸的压缩版本。
3.2 自建批处理脚本替代手工调整
我用的核心工具是 Python + Pillow(PIL),因为它的生态最成熟,批量改尺寸、转格式、打水印都很方便。下面这段脚本是我整个素材管线的核心,作用是把目录里所有超过某个宽度的图片重采样,同时转成 WebP。
from pathlib import Path from PIL import Image SOURCE_DIR = Path("./source/raw") OUTPUT_DIR = Path("./assets/processed") MAX_WIDTH = 750 for img_path in SOURCE_DIR.rglob("*.png"): img = Image.open(img_path) if img.width > MAX_WIDTH: ratio = MAX_WIDTH / img.width img = img.resize( (MAX_WIDTH, int(img.height * ratio)), Image.Resampling.LANCZOS, ) output_path = OUTPUT_DIR / (img_path.stem + ".webp") img.save(output_path, "WEBP", quality=80) print(f"processed: {img_path.name} -> {output_path.name}")这套脚本最大的好处是,无论AI生成了多少张风格不一致的图,最终处理完的产物在尺寸、格式、质量上都是统一的。这也是我后来能面对1.8万张素材而不崩溃的原因。
3.3 用“索引文件”管理素材,而不是硬编码路径
素材多了以后,最容易出现的问题就是代码里拼文件名拼错。我建立了一个manifest.json,把所有素材的真实路径和配置集中管理。页面加载图片时,不直接写字符串,而是通过一个工具函数查表。
{ "card_001": { "default": "/assets/processed/card_001.webp", "large": "/assets/processed/card_001_large.webp", "blur": "/assets/processed/card_001_blur.webp" } }这样做的原因是,小程序包体有体积限制,不可能把1.8万张全部塞进本地包。真正打包到本地的只有首屏需要的几百张,其余素材放到内容分发链路上按需加载。通过 manifest 文件,前端知道自己要用哪张图、应该去本地取还是远程取。
3.4 包体大小和首屏速度的平衡方案
下面这张表是我压缩前后的数据对比:
| 方案 | 单张平均大小 | 100张总大小 | 首屏加载体验 |
|---|---|---|---|
| 原始 PNG | 1200KB | 120MB | 不可能本地加载 |
| 压缩 PNG | 280KB | 28MB | 仍然偏大 |
| WebP 质量80 | 65KB | 6.5MB | 可接受 |
| WebP 质量60 + 尺寸裁剪 | 28KB | 2.8MB | 流畅 |
最终我选了“WebP 质量80 + 宽750裁剪”作为默认,遇到纹理复杂的图片单独调低到65。其实这一步也很影响审核体验:如果素材图加载太慢,审核人员打开页面时转圈超过两秒,可能直接影响审核结果。
3.5 素材越界问题:给后来者的一个警告
素材管理不只是技术问题,还是内容安全问题。1.8万张图里如果有某几张带外链水印、二维码、真人面部、品牌Logo,都有可能成为审核拒绝的理由。我后面被拒审时,很大一部分精力就是在排查这些素材。
我现在给所有人的建议是:无论AI图片生成工具给出来的图多好看,都要在进入素材库前强制跑一遍内容扫描,包括识别二维码、检测大段文字、查找可疑链接。这个成本远低于被拒审后全量排查的时间成本。
4. 被微信拒审那天,我启动的完整排查链路
4.1 第一次被拒:我收到的是什么反馈
那次提审,后台给出的拒绝理由有两条:
- 当前页面内容涉及信息展示,未选择对应类目,且未提供该分类所需资质。
- 线上版本中部分素材存在明显外部品牌标识,容易引起用户误解。
第一条我还能理解,第二条彻底让我懵了。我一直以为素材都是AI生成的,怎么会带品牌标识?后来我翻了一遍投放区域里的背景纹理图,才发现AI在生成“运动风插画”时,会在角落里画出类似知名品牌的Logo轮廓,虽然不是完完全全的真Logo,但审核人员看第一眼就会觉得是。
这也是Vibecoding项目的独特风险:AI生成的图片未必“干净”,它的训练数据里边角料会混进视觉残留。文字同理,AI画带有文字的海报时经常生成出类似真实品牌名称的字符串。人眼有时会忽略,审核系统不会。
4.2 审核意见背后,到底在检查什么
我后来把这次审核拆解成三个层面,和代码项目里的“代码逻辑、用户体验、合规资质”一一对应:
| 审核层面 | 常见检查点 | 我的问题 |
|---|---|---|
| 代码逻辑 | 是否存在明显崩溃、白屏、反复加载 | 没有大问题 |
| 用户体验 | 页面是否能顺畅走完核心流程 | 基本满足 |
| 合规资质 | 类目是否匹配、内容是否违规、素材是否越界 | 类目不匹配、素材有品牌残留 |
值得注意的是,审核人员并不关心你的AI开发流程,也不关心代码写得高级不高级。他们只会把小程序当作一个真实产品来使用,然后用现行规范来度量它。所以Vibecoding项目最容易输的不是功能,而是“产品化外壳”——包括备案信息、用户协议、隐私保护指引、内容审核机制。
4.3 从确定原因到精确定位素材,我做了什么
拿到拒审原因后,我没有盲目删素材,而是把全量素材跑了一遍自动扫描脚本。脚本主要做三件事:检测图片里是否包含二维码、检测图片文件名和文件夹中是否有敏感关键词、检测图片的尺寸和色彩是否异常。
import re from pathlib import Path from PIL import Image SCAN_DIR = Path("./assets/processed") suspicious_files = [] keywords = ["logo", "brand", "link", "icon_", "ad", "promo"] for img_path in SCAN_DIR.rglob("*.webp"): name = img_path.stem.lower() if any(kw in name for kw in keywords): suspicious_files.append(str(img_path)) continue img = Image.open(img_path) gray = img.convert("L") # 如果整张图中间区域大面积异常明亮,可能隐藏水印 center_box = (int(img.width*0.3), int(img.height*0.3), int(img.width*0.7), int(img.height*0.7)) region = gray.crop(center_box) avg = sum(region.getdata()) / (region.width * region.height) if avg > 220: suspicious_files.append(str(img_path)) print("suspicious:", len(suspicious_files))这个脚本不算精确,但能帮我把1.8万张图缩小到几十张重点名单,然后我再挨个看这几十张,最终在卡片背景里找到了四个问题素材。配合关键词过滤,又排查出十几个命名上带有第三方品牌字母的图标文件。
这整套链路走完大概花了我一个下午,比我最初预计的人工翻图快太多了。
4.4 修复方式与再次提审的经验
定位到问题素材后,我做三件事:
- 把所有可疑素材直接替换成自己重画的纯色几何背景,而不是尝试把Logo“P掉”。审核看的是结果,不是你的意图。
- 在后台把小程序类目改成和“图文内容展示”更匹配的分类,同时上传了对应的内容说明文档。
- 重新提审时,在审核备注里写了“已清理全部外部品牌标识,并更新类目配置,请复核”。
这里有个小技巧:审核备注一定要具体。不要写“已优化产品体验”,而要说清楚“把哪一类内容移除了、类目改成什么、涉及哪些页面”。审核人员每天看很多版本,你帮他省时间,他也会更愿意给你通过。
第二次提审后大约三个小时,状态变成“审核通过”。那一刻我最大的感受不是开心,而是一种后怕:如果第一次没过的时候,我选择“删点图赌一把再提”,而不是把所有素材扫一遍,第二次很可能还是被拒。Vibecoding不是“赌运气”,你得把AI生成的东西当成不可信任的原材料来处理。
5. 一个人 + AI 做完整产品,边界和可复用经验
5.1 哪些事情AI干得好,哪些事情AI根本干不了
经历了这个项目后,我给AI能力画了一条非常清楚的分界线:
AI擅长的:
- 把模糊需求变成可运行的原型代码
- 批量生成重复性的页面逻辑
- 处理素材的转换、格式化、批量整理
- 按照你给的格式写配置文件和工具脚本
AI不擅长的:
- 判断“这个功能是否需要存在”
- 理解平台审核规则背后的业务逻辑
- 做最终的产品走查、内容安全审查
- 维护项目的长期演进而非一次性交付
很多人觉得Vibecoding等于“其实可以不会写代码”,我不同意。你至少得懂基础的程序逻辑、知道版本控制是什么、会看报错信息。AI可以帮你写代码,但没办法帮你“思考产品为什么要这样设计”。被拒审那天我学到的第一课就是:AI做的图再好看,也不能替代你站在用户角度审核一遍自己产品的合规性。
5.2 单人模式的时间和效率账
这个项目从零到上线,我一共花了大概两个半月。其中:
- 第一个月:搭框架 + 让AI产出全部页面内核,大约2万行代码。
- 第三周:批量生产素材,把1.8万张素材管线搭完。
- 最后三周:联调、压缩、修Bug、过审。
如果按传统方式找团队做,同样的工作量需要至少三到四个人力。但Vibecoding不是没有代价:我几乎每天晚上都要花一两个小时review AI生成的代码和素材,周末的时间全部扑在走查上。说白了就是用时间换人力,只不过这个时间消耗比亲自动手写代码小得多。
5.3 给正在或准备走Vibecoding路线的人几条建议
如果你也打算用一个人 + AI的模式去做小程序或小游戏,我比较想让你提前知道这几件事:
- 先定边界再动手。内容生产类工具适合AI,涉及资金交易、用户隐私、实时反馈的产品,AI生成的后端逻辑必须谨慎,最好只做前端Demo,后端找成熟方案。
- 内容越多,越要有“自动审查”的概念。AI生成的图片和文本,一定要经过机器扫描后再入库,不要相信AI的眼睛。
- 版本控制习惯要前置。AI改代码经常顺手牵羊,没有git历史,遇到问题根本没法恢复。
- 审核不是最后一环,而是产品工程的一部分。从第一天做页面时就要考虑“这个页面会不会被审核盯上”,而不是等快上线了才考虑。
- 别迷信一次性生成。最好的Vibecoding节奏是“小步快跑”:每次让AI改一个局部,改完就自己跑一遍,立刻发现和修正。
5.4 最后,我想说点可能不太“正确”的实话
如果你期待一篇“AI取代程序员”或者“一个人也可以轻松做产品”的爽文,我可能会让你失望。Vibecoding这条路有效,但它对个人的基础设施能力要求并不低。你需要会成为AI的“产品经理”:能拆需求、能描述清楚问题、能判断输出质量、能快速定位AI搞出来的问题。
我那天被拒审时,真正让我焦虑的不是改代码,而是发现自己一直在“造功能”,没有认真想过“上线”这件事包含了多少看不见的规则。做一个能跑的小程序,和做一个能上线的小程序,中间差的不是代码量,是长时间跟真实世界规则打交道的经验。AI能帮你写3万行代码,能帮你生成1.8万张素材,但审不过去那一瞬间的落差,还是得你自己面对。
如果你现在也卡在类似的状态,不妨先把产品逻辑放一放,认真审视一遍:我的类目对了没有?用户协议写了没有?素材里有没有自己都没看过的角落?这些补齐之前,代码写再多也只是半成品。