厨菜记是个微信小程序,把自己家做过的菜记下来,一家人共用一份菜单。
它和菜谱平台最大的区别是,你打开看到的每一道菜,都是家里人亲手录的,没有推荐流,没有大 V。撑起它功能的是三个特别常见的场景:收藏了三百个菜谱,真要做那道酸汤肥牛时翻了六分钟,最后点了外卖;下午五点家庭群开始商量"今天吃什么",商量到七点;还有你妈做了一盘很好的红烧狮子头,你让她写下来,她说"这有什么好写的,看着就会了"。
技术是很普通的前后端分离。
小程序端 微信原生框架 + MobX + 分包加载
后端 Spring Boot + MyBatis-Plus + Spring Security/JWT + Redis + MySQL 8
部署 自建 ECS + Nginx 反向代理 + 对象存储存图
功能上就三步:把你家的菜记下来,把家人拉进同一个厨房,然后让一家人点菜、下厨、打分。录菜时食材和调料库会自动沉淀,第二次写"生抽"不用从头输入;每道菜带着做过几次和平均分,12 次 4.8 分的那道就是你们家的固定节目;点餐按早餐、午餐、晚餐、宵夜四个时段组织,下单、上菜、打分一条链走完,评价最后沉回那道菜的分数里。成员分厨师长、管厨、食客三种角色,家庭群里发一张邀请卡片,点进来就在同一个厨房了。
数字是 git ls-files 出来的:小程序 362 个文件 16.6k 行,后端 269 个 Java 文件 13.9k 行,19 张表,21 个页面,25 个组件,从设计到上架五周。
上一个我用 AI 做完的小程序是《签小签》。这是第二次整套这么干,两边后端技术栈一模一样,连 MyBatis-Plus 3.5.3.1 和 Hutool 5.8.15 的版本号都没动。第一次做完可以说运气好,需求简单、坑踩得少;第二次才谈得上方法,因为同一套流程走两遍,才知道哪一步是侥幸、哪一步是必然。所以这篇不再讨论"AI 到底能不能写代码",只讲这次它帮在哪、又坑在哪。跟上次最实在的区别是,这次我给 AI 交付的每一步都先配了一个能自己跑的验证手段。
先把分工说清楚
既然代码大部分是 AI 写的,那"我到底做了什么"这个问题绕不过去。按我实际花时间最多的地方说:需求上做什么、不做什么全是我自己定的,冰箱食材管理那一整套需求是我自己砍掉的,AI 从没主动提过"这个别做"。数据库 19 张表的关系和字段约束得我先想清楚,DDL、注释、实体类它一口气产出。后端分层骨架和一大堆 CRUD 是它的,接口鉴权白名单、防重复提交注解、跨层字段约束是我提的问题——它不会反问我一句"这个字段被绕过前端打进来怎么办"。小程序的页面结构和组件它写得多,交互细节基本是我一句一句磨出来的,后面讲 fab 那七轮就是这件事;分包是我逼它做的,因为不拆也能跑。剩下批量改名、补注释、清死代码这类活整批交给它,我只负责检查有没有改坏。
归纳成一句:它负责把意图变成能跑的东西,我负责判断它变成的是不是我想要的东西。
这个分工有个挺苛刻的前提——我得能看出来哪里不对。看不出来,它就顺着一条我没验证过的假设把代码写得很完整,而且每一处都写得像那么回事。下面几节讲的就是我分别在哪看漏了、又在哪勉强看了出来。
一个刚发生的例子:AI 会漏边界,不会漏实现
厨房名称这个字段,我去核了三层各自写的约束:
前端输入框 maxlength = 20
数据库 DDL `name` VARCHAR(50) NOT NULL
后端 DTO @NotBlank(message = "厨房名称不能为空")
↑ 全仓 grep @Size:出现 0 次
三层各自看都没毛病。问题是三层对长度的上限分别是 20、50、没有。
只要有人不经过那个输入框提交——一个脚本、一个旧版本客户端、以后接进来的微信 AI——写六十个字,服务端不会回一句"名称太长了",而是 MySQL 抛异常,用户面前弹一个"系统繁忙"。
AI 不会主动来告诉你这件事。它写每一层的时候都是局部正确的:约束有啊,库里写着,前端也拦着。缺的是跨层那条不变量,而"三种约束互相之间是什么关系"这个问题,只有一个人脑子里同时装着三处才会想到去问。
现在每让 AI 写完一个模块,我固定追问三句:这个字段的约束在库里、后端、前端分别是什么,不一致会怎样?被绕过前端的调用打到会怎样?这个写接口点两次会怎样?一次一分钟,不追问就是线上。
还有个观察。它特别擅长制造一种"校验很完善"的错觉,@NotNull、@NotBlank 一路挂下来,看着比谁都严谨,实际上一条长度约束、一条范围约束都没有。有注解和有边界是两回事。
九十个文件的批量改动,我怎么确认它没乱来
早期文档和注释里把 dish 写成「菜品」,用户看到的文案一直是「菜谱」,得统一。范围是 45 个 Java、34 个小程序文件、10 篇文档。
人来做的话,最累的不是改,是检查有没有改坏。「菜品」这个词如果出现在 SQL 字段注释里、出现在校验注解的 message 里、出现在拼好的字符串里,一次替换就变成一个 bug。
我分批交给 AI 改,然后只信两道检查。
第一道,纯文字替换不会改变行数,每个文件的增删必须相等:
git diff --numstat
第二道更有用:把新旧两个词都归一成同一个占位符,再逐字节比对,理应完全相同。
git show HEAD:$f | sed 's/菜品/@X@/g' > /tmp/before
sed 's/菜谱/@X@/g' $f > /tmp/after
diff /tmp/before /tmp/after # 期望:没有输出
它不判断"改得对不对",而是先把术语这个变量抹掉,再看两边是不是同一份东西。差一个字节,说明这批改动里掺进了别的东西,单独拎出来审。
结果 90 个文件全过,提交是 362 增 339 删,那 23 行差额来自同一批一起改的 fab 组件。
这里我犯了个挺笨的错,值得记一下:第一版脚本我只归一了 HEAD 那一侧,于是它立刻"证明"了 45 个文件全都有额外改动,我差点以为 AI 把我正在写的功能代码覆盖了。两侧都得归一。当 AI 交付的东西不对劲,先怀疑你自己的验证脚本,它不会主动报告自己测的是个寂寞。
它真正改变的是我会不会去改细节
fab,菜谱页右下角那个悬浮按钮,原来是扇形展开四个纯图标。我一句一句提要求,提了七轮:
提示不要自动隐藏,不要背景气泡,就显示文字 文案改成「点击管理」,不要那么大,不用加粗 放在主按钮正上方,水平居中 给这个文字加一点动画 稍微贴近一点主按钮 菜单展开之后把这个提示隐藏 提示的显示隐藏也增加点动画
七轮之后又把整个展开形态从扇形换成竖向堆叠、圆钮下面带一行文字标签,再来一轮。
要是以前,这些我大概率不会改。为一个提示文字来回改七次 WXSS,收益明显盖不住成本,人的本能是算了吧。现在一次也就二十来秒,"算了"这个选项就不存在了。AI 对独立开发者最实际的价值在这儿:它压低的不是写代码的成本,是你凑合的频率。
不过它确实给我递过坏方案。改完我发现展开时第一条子项的标签和提示文字重叠,当时拿到的建议是整组子项 offsetY 再减 64px——算术上确实推开了,实际会在主按钮和第一个圆钮中间留出一个 43px 的空洞,一眼就不对。最后是绕开位移、用时序解的:transition 分别写在各自的目标状态上,隐藏 0.12 秒抢先淡出,显示加 0.2 秒延迟等子项收回去,顺手把提示的 z-index 降到子项之下。
它知道怎么改,不知道改成那样好不好看。这一步只能我自己来,依据是我在开发者工具里看了它两眼。
这几处它的默认答案我给换了
分包。主包只留 4 个 Tab,其余拆成 7 个分包。它不会主动拆,因为不拆也能跑,而拆要动几十处引用。但小程序主包超限不是慢一点,是构建直接失败。
状态边界。MobX 里只放用户信息和系统配置,页面数据一律留在 data。它的倾向是"要不要给你加个 store 统一管理",这个建议我很怀疑。页面级状态一旦被提到全局,之后每个交互都得考虑一致性,这笔债要半年后才爆。
抽象时机。分页、上传、表单各抽一个 Behavior,规则是同类需求第三次出现才抽。它会在第二次就给你抽象出一个很漂亮、方向错误的接口。
防重复提交。用户对"上菜"双击就是两张订单。我用了自定义 @Repeat 注解加 AOP 切面统一拦在前面,而不是在每个 Service 里写判重。后者它写得很顺手,因为它是一个文件一个文件地思考的。
数据隔离。所有业务查询带 kitchenId,接口级再过一遍 Spring Security。前端只能保证体验,保证不了边界,前面厨房名称那个 20、50、没有,就是同一种病的轻症。
微信 AI 助手能调用你的小程序了,我只开了一半
产品是我自己用 AI 做的,那"被 AI 调用"这件事我认真看了一遍。微信刚上的「微信AI助手接入服务」,后台一个开关,含义是用户可以对微信 AI 说"今晚吃什么",然后 AI 去操作你的小程序。
条款里两条路特别容易看混。一条叫页面交互技术,AI 实时读你的页面、代用户点击,它绑在"接入服务"这个开关本身;另一条是技能调用,平台解析你的代码生成能力描述,那才是自动模式或开发模式管的事。所以我光开接入服务、什么模式都不选,就已经授权 AI 实时驱动我的页面了。
我现在的状态是接入服务开着,自动模式没开。三个原因。
我所有页面都依赖登录态和"当前厨房"上下文,AI 代用户跳进某个分包详情页,没有厨房就是白屏,一个体验断裂的入口比没有入口更糟。AI 代用户点击会真的写进生产库,技能里只要有"新增菜谱""上菜"这类写操作,脏数据直接进来,前面那个缺 @Size 的厨房名称就是这类场景的预演。第三,家庭菜谱是人家的私事,条款写的是平台可以"获取小程序服务页面进行识别读取、分析处理",把别人家的家宴放进这条链路,我目前找不到一个说得通的理由。
如果你也准备接,建议先把这几件做掉:未登录、未选厨房时页面要能优雅降级而不是骨架屏转圈;所有写接口服务端二次校验加幂等;去后台确认有没有历史生成的技能残留。另外「小程序个性化推荐」是另一个独立开关,别和这个混为一谈。
入口带来的是流量还是差评,取决于你的页面在没有人在场的时候会不会塌。
产品里没有 AI,这件事我想清楚过
总有人问为什么不加 AI 推荐。
"今天吃什么"不是推荐问题。算法推给你一道全网都在推的黄焖鸡,可你老婆不吃辣、你爸血糖高,真正的答案是"昨天她点了还没吃的那道"。这需要一份一家人共同维护的清单,模型帮不上。
家常菜也不是生成题。大模型能写出一份无可挑剔的狮子头教程,但它写不出我妈那盘为什么糖要早放、为什么要先过一遍油。这类信息只有一个来源,就是那个不肯写字的人。
再就是成本。个人主体小程序接一个大模型能力,token 的钱、内容审核、免责声明、模型幻觉带来的差评,全是我的,而它换来的增益只是把用户已经知道的东西再说一遍。
所以下一步我把 AI 放在别的位置:让用户真正做过的菜能被整理成结构化的菜谱文本分享出去,v2 菜谱分享还在设计,那里"整理"是有真实价值的。推荐我暂时不做。
我开发已经完全靠 AI,和我这个产品要不要有 AI,是两个不相干的决定。
现状,以及欢迎来试
一个人维护,迭代不快,偶尔会有你没碰到的 bug,前面那个超长名称就是。目前没有广告、没有会员、没有付费墙,所有功能开着;以后要收费也是扩容、模板那一类,不会把已经免费的东西锁进抽屉。v2 分享在设计中,订阅消息搁置了。
好处是,没有人为 KPI 给你加一个你不想看的弹窗。
想试的话微信搜「厨菜记」。首次进入会自动创建一个默认厨房,选几个分类就开始,不用注册、不用授权一堆用不上的权限。一个人用也行,当个只装你自己菜谱的笔记本;不过"点菜、下厨、打分"这条链,得有两人才热闹得起来。
最后
AI 给我的不是生产力翻倍这种虚的,是两件很具体的事:把不该人干的活真拿走了(九十个文件的迁移、十九张表的注释),把改细节的成本压到我会去改的程度。
它替不了的部分同样具体:三层字段约束对不对、改完好看不好看、哪个入口不该开、什么问题不该用 AI 解决。
两次做下来我更信一句,能复用的不只是代码,还有骨架和验收方式。签小签把这套 Spring Boot 分层、鉴权、部署趟平了,我这五周省下来的时间没拿去做功能,全换成了验证手段——批量改动的回归门、跨层约束的追问清单、每个模块写完再问一遍边界。
有想问的或者想吐槽体验的,评论区聊。