我们让她重新拥有形容词。
进食障碍是死亡率最高的精神疾病之一,发病高峰在 15.5 岁,而符合诊断的人里只有 23% 求助过。
中国唯一一项全国面访调查给出的患病率是 0.1%,最大规模的青少年筛查给出的是 21%——两个数字差 200 倍。
「退潮」是给这群人的匿名自助工具。无账号、无登录、数据不出设备。62 屏可跑,接了云函数与模型,构建期 16 项自检——其中四项断言的不是功能,是这个产品的立场。
| 维度 | 数字 | 出处 |
|---|---|---|
| 死亡 | 神经性厌食症的标准化死亡比 SMR = 5.86——死亡风险约为同龄一般人群的 5.9 倍。 自杀 SMR = 31.0;死者中每 5 人有 1 人死于自杀。 |
Arcelus 等 2011, Arch Gen Psychiatry(36 项研究 meta) Chesney 等 2014, World Psychiatry |
| 低龄 | 发病高峰年龄 15.5 岁,中位 18 岁。 48.1% 在 18 岁前起病,82.4% 在 25 岁前。 而发病年龄仍在随出生队列继续下降。 |
Solmi 等 2022, Mol Psychiatry(192 项研究,708,561 人) Favaro 等 2009, J Clin Psychiatry |
| 在涨 | 全球时点患病率从 3.5%(2000–2006)升到 7.8%(2013–2018)。 疫情后加拿大青少年新发厌食月均住院数 +167%。 |
Galmiche 等 2019, Am J Clin Nutr Agostino 等 2021, JAMA Netw Open(6 家儿童医院) |
| 没人管 | 社区中符合诊断的人里,仅 23.2% 寻求过针对进食障碍的治疗。 十年后基本没变(2025 年更新的 meta:32%)。 未治疗病程:厌食 2.5 年 · 贪食 4.4 年 · 暴食障碍 5.6 年。 |
Hart 等 2011, Clin Psychol Rev Ali 等 2025, Int J Eat Disord Austin 等 2021, Eur Eat Disord Rev |
不写「死亡率最高的精神疾病」——这句流传极广的话没有原始文献支持,而按 Chesney 2014 的排序,厌食症低于阿片类与苯丙胺使用障碍。准确的写法是「死亡率最高的精神疾病之一」。数字本身已经够重,不需要一个会被证伪的最高级。
同理不用「每年 10,200 人死于厌食症」——那是美国全部进食障碍的建模推算值(Deloitte 2020),被二手转述挪给了厌食症。
这不是哪一方错了。面访诊断的是成人回顾,筛查量表测的是青少年当下的风险——但这个裂口本身就是临床识别率极低的证据。
| 中国的现状 | 出处 |
|---|---|
| 全国精神卫生调查:进食障碍加权终生患病率 0.1%,六大类障碍中最低 | Huang 等 2019, Lancet Psychiatry(31 省 32,552 名成人) |
| 全国青少年筛查阳性率 21.18%(女生 27.28%) SCOFF 五题量表,阳性只代表疑似风险,不是确诊 | Bao 等 2025, BMC Medicine(41,406 名 10–19 岁) |
| 中国 贪食症患病率约为厌食症的 2 倍且持续上升(GBD 建模) | Li 等 2021, Front Psychiatry |
| 全国第一个进食障碍诊治中心,2017 年 9 月才在上海市精神卫生中心挂牌 | 上海市精神卫生中心 |
| 中国没有任何一项关于「多少患者从未接受治疗」的统计,也没有专科门诊数量的全国统计 | ——检索无果本身即是结论 |
在 DSM-IV 标准的美国全国共病调查中,女性终生患病率是暴食障碍 3.5%、贪食症 1.5%、厌食症 0.9%——暴食障碍高于另外两者之和(Hudson 等 2007, Biol Psychiatry)。(这一条只在 DSM-IV 数据下成立:暴食障碍到 DSM-5 才独立成诊断,而 DSM-5 同时放宽了厌食症标准,两版不可直接比。)
但 GBD 2019 官方只统计厌食与贪食两种。把暴食障碍和其他特定进食障碍纳入之后,额外多出 4190 万此前未被计入的病例(Santomauro 等 2021, Lancet Psychiatry)。
主流叙事把进食障碍讲成失控——binge eating 字面就是「失控进食」。而真正的机制是反的:
一个人不能掌控一切,于是从食物下手——因为食物是唯一可以被完全掌控的东西。限制是掌控,暴食是限制的反弹,清除是对"已经发生"的掌控。三侧共享同一个结构。
由此推出的第一条否决:任何"算给她看"的产品都在喂病。算热量、算 GI、算吸收率、算这一顿之后会怎样——每一个都是给一个掌控欲过剩、且算术能力极强的人一件更精密的仪器。
一个人对食物的语言只剩下数字。她说不出「香」,只能说「多少卡」。所有产品都在给她更准的数字。
| 判断 | 依据 |
|---|---|
| 要解的是留存,不是有效性 | Linardon 2024 的 RCT(n=576)已证 DBT 技能 App 对暴食有效,但同一项研究里干预组 6 周脱落 48%、仅 1/3 完成最后模块。Zainal 2025 的 meta(117 试验 / 279,791 人):脱落更低的试验有提醒、有人的接触、且无游戏化。 |
| 躯体那一层是空的 | 30+ 产品调研:Juniver 覆盖清除型贪食却零字提电解质与清除后护理;单独检索这一类,结果全是文献与治疗中心科普页,无任何消费级产品。 |
| 生成式对话在这个人群里是危险的 | Tessa(NEDA)对已告知患 ED 的用户仍推荐热量限制,一周下架。Pucci 2026 临床标注 268 对中仅 44.7% 安全。CCDH:ChatGPT 对假装 13 岁者给 0 卡计划并教其隐瞒家人。Bilen 2026:五个主流模型给青少年餐单平均低估 695 kcal。 |
| 谁 | 什么时候打开 | 她需要什么 |
|---|---|---|
| 患者端 暴食 / 厌食 / 贪食全谱系 | 大部分是日常——今天的滋味卡、六格、找个人说说话。 少部分是急性期:很想吃 / 正在吃 / 吃完了 / 吃不下。 | 不被评价地过完这一天。急性期需要的是此刻手上能做的一件事,不是分析。 |
| 照护者端 妈妈、爸爸、伴侣、室友、朋友 | 她刚说了一句话,对方不知道该怎么接。 | 知道自己那句好心的话正在起什么作用。核心是行为翻译器,不是话术库。 |
不做患者↔照护者绑定,不共享任何数据。暴食是隐秘的,没人希望身边人知道。照护者自己下载,两端从数据到代码彻底分开——chk.mjs 有一条断言专门检查 care.js 没有引用患者端数据。
早期版本用「照护者几乎全是女性」来论证选题契合女性主题。这是错的——照护劳动过度落在女性身上是需要被改变的现状,不是产品的用户画像。现在照护者端按真实使用者写,不预设性别与身份。
凌晨三点她不会去应用商店搜索、下载、注册。产品定义里"还开着"这句话,靠的就是这个形态。
| 层 | 做法 |
|---|---|
| 形态 | 微信小程序,走体验版(不过审)。62 屏 = 一个页面,单页换内容。体验版需先加白名单,而上限只有 15 人——见第 07 节「上线」 |
| 存储 | 记录、情绪、滋味、对话全部 wx.setStorageSync。数据不出设备——既是隐私设计,也省掉整个后端 |
| 内容层 | 屏级文案的唯一源是可交互原型,screens.js 由 gen.mjs 生成。手改生成物会被覆盖 |
| 唯一的云函数 | cloudfunctions/talk:四个人各自回应一段话。无状态——历史由前端每次带上来,用完就没了 |
| 模型 | 百度文心 4.5(ernie-4.5),走 OpenRouter。密钥在云函数的环境变量里,前端拿不到,反编译也拿不到。模型可换——一个环境变量的事,护栏与人设不依赖具体模型 |
| 物理 | 情绪瓶子是 canvas 2d + 位置约束松弛(PBD),每帧解位置,接加速度计 |
| 构建期工具 | gen.mjs 生成 · chk.mjs 16 项自检 · shot.mjs 用真实 WXSS 渲进 headless Chrome 量一屏装不装得下 |
四个人的回应要在几秒内回来,所以测了六个模型,每个跑四个人各一次:
| 模型 | 耗时 | 结果 |
|---|---|---|
| ernie-4.5(选它) | 3.3s | 中文最自然——「松一下后槽牙」这种细节完全落在人设里 |
| mistral-nemo | 2.1s | 最快,但爱输出双换行和 markdown 星号 |
| llama-3.1-8b | 1.5s | 中文生硬(「这感觉一直持续着」) |
| qwen3.7-flash | — | 返回空 |
| step-3.5-flash / deepseek-v4-flash | — | 同样返回空 |
| hunyuan / minimax | 6–7s | 能用但慢 |
它们都是 reasoning 模型。而 max_tokens 不是上限保护,是模型的写作预算——给 400,思考就把额度花完了,一个字都没输出;给 3000 能出内容,但要 16 秒。
调那个数字是解不开的,得换模型。这一处在两个错误之间来回撞了两轮才看清。
mistral-nemo 快 1.2 秒,但它爱加 markdown 星号 → 被 guard.js 拦掉 → 退回模板。也就是说"快"换来的是"用户经常看到的是模板"。
护栏严格的系统里,模型输出的干净程度比速度重要——脏输出等于没输出。
模型是可换的:改环境变量 TALK_MODEL 即可,人设(persona.js)与护栏(guard.js)都不依赖具体模型。这是三层架构的一个副产品——把"说什么"和"能不能说"分开之后,说话的那一方就变成可替换的了。
患者端 62 屏 · 489 块 · 42 种块型 照护者端 22 屏 · 13 种块型 · 20 条课程 代码 约 4800 行 JS(手写部分:不含生成物 data/screens.js 与截图工具 shot.mjs) 自检 16 项,含 4 条立场断言,exit code 非 0 即构建失败
模型只出现在「四个人」这一层,三道护栏,缺一不可:
人设 四个人各守各的流派,能说的范围各自更窄 ↓ 后置检查 提示词是请求,检查才是保证 ↓ 兜底 不合格不重试、不改写,退回人写的那段
岸(先过这一阵,只给手上动作)· 回声(那句话是谁说的,只拆念头)· 同路(不用先感觉好)· 地面(此刻的身体)
一个只能给手上动作的人,说不出饮食建议;一个只拆念头的人,不会去评价她的身体。四条窄路比一条宽路安全,也比一条宽路好听——四个声音不会糊成同一个。
不合格的输出不改写。改写等于在有害内容上打补丁,而补丁过的那句仍然是模型写的。Pucci 2026 记录的失败模式里就有"免责声明之后照样给建议"——所以不能靠模型自己声明安全。
也不用真人名:精神分析对进食障碍的经典解释是口欲期固着、对母亲的攻击、拒绝性成熟。把这套话对患者说出来,是把病因归到她的欲望和家庭关系上——而那不是模型跑偏,是忠实还原人设的结果。
「我写的滋味」让她从色 / 香 / 味 / 声 / 质地五个角度写下自己记得的样子。想让这条进公共池,要过一道门槛:
| 她写 | 结果 | 屏上那句 |
|---|---|---|
| 恶心 | 不进公共池 | 「这是判断,不是味道。」 |
| 像屎一样 | 不进公共池 | 「这是个比喻。」 |
| 入口即化 | 同样不进 | 理由和「恶心」一模一样——都不是描述 |
| 臭 / 酸了 / 发苦 / 黏手 / 凉了 | 放行 | 那是真实的气味。臭豆腐、臭鳜鱼、蓝纹奶酪 |
如果只让填愉快的感受,那是另一种压力。
| 层 | 有什么 | 为什么 |
|---|---|---|
| 存 | 她写什么都存,永远在她自己手机里 | 产品从头到尾没有否定过她任何一个字 |
| 时间线 | 全都在,包括「恶心」 | 变化要看得见。同一样食物写过很多条,按日期排开——恢复的证据是她自己写出来的,不是产品替她改的 |
| 卡面 | 只放过了门槛的那条 | 那张卡她每天会再看到一次。把最难受那句挂在最显眼的地方,等于每天提醒她一次 |
这三层是绕了很久才拆开的。此前「拒绝还是引导、删掉是不是强权」这个死结解不开,正是因为把存下来和给别人看捆在了一起。它们本来就是两个不同的权限。
第一天卡面上是产品写的滋味描述。她写过之后,那段话被换成她自己的。用久了,整本卡都是她写的。
node .sync-mp/chk.mjs
16 项里有四项断言的不是功能,是这个产品的立场:
任何一条塌了,构建失败。评委问「你怎么保证 AI 不写内容」,答案是一行命令,不是一段话。
「把『她每天经历的事』,做成一个以前没人替她做过的 App」——这就是这个产品的定义。而中文世界确实没有:GBD 2019 中国 BN 患病率约为 AN 两倍,但诊疗聚焦体重恢复;30+ 产品调研里,躯体层是整个品类的空白。
命题原文:「知道自己很累,却分不清是身体累还是精神累;知道自己想要点什么,却说不清那是什么」「忘记了身体的每一个感官都是爱的容器」。
| 命题说的 | 产品里的 |
|---|---|
| 分不清身体累还是精神累 | 地面:手是凉的还是温的,肩膀端着没有 |
| 说不清自己想要什么 | 我写的滋味:五个角度,把形容词还给她 |
| 与他人的关系始于与自己的关系 | 先写后看:没写完自己的,看不到别人写的 |
| 身体的每一个感官都是爱的容器 | 色 / 香 / 味 / 声 / 质地——五个角度就是五个感官 |
「先写后看」这条规则当初定它的理由是"防止她照着别人写",纯功能考虑。而萨福那句"与他人的关系始于与自己的关系",正是这条规则的哲学表述——两边独立推到了同一个地方。
个人参赛。产品决策、调研、文案、设计、前端、云函数、自检工具,一个人做完 62 屏患者端 + 22 屏照护者端、55 种块型、约 4800 行手写 JS。做得完不是因为人更能干,是因为团队里靠人盯的那几环,换成了机器每次构建都会跑一遍的断言。
| 团队里靠人盯的 | 这里换成了什么 |
|---|---|
| 文案改了,要同步到设计稿和代码 | 唯一源 + 生成:文案一个源、视觉一个源,gen.mjs 往下生成,手抄的环节不存在 |
| 互相 review 有没有说错话 | 4 条立场断言:存 ≠ 给别人看、门槛对称不偏向好话、润色过的串联退回、患者端无临床词——写进 chk.mjs,非 0 即构建失败 |
| 设计走查「一屏装不装得下」 | shot.mjs:真实 WXSS 渲进 headless Chrome 量,不靠估 |
| 盯着 AI 别乱说 | guard.js 护栏 + 人写语料兜底:模型不可用时退回人写的话,产品照常用 |
但有一环没法交给机器,也没法交给别人:判断标准本身。四条产品约束(不制造动机、热量作下限、冲突制造症状、那句起作用的话)来自亲历,不来自调研——AI 放大的是判断力,判断力的来源不可替代。这个产品只能由这样一个人起头,做完它却需要一整套机器。
个人参赛。产品决策、调研、文案、设计、前端、云函数、自检工具,全部一人完成。
唯一的外部输入是亲历:作者本人是限制型厌食症康复者。这不是情绪素材,是四条写进 PRD 的产品约束——
| 亲历输入 | 变成了什么 |
|---|---|
| 产品不制造动机 「改变发生在她想改变的时候」 | 产品服务已决定的人,且必须有「我还没打算改变」的入口 |
| 热量作下限而非上限 | 判断标准是"够不够"不是"多不多"。但那是做产品判断的语言,不是给用户的语言——屏上只有桌上有几样 |
| 冲突制造症状 藏食是掌控欲不是浪费 | 照护者端从话术库改成行为翻译器,核心句「你的批评正在生产你想制止的那个行为」 |
| 那句起作用的话 | 「你的人生才刚刚开始,只有你能定义自己」——对应"干错一件事天就塌了",即破戒效应的同一结构。原样放进发作中那一屏 |
这一节写的是被推翻的部分。一个人做完整个产品,最能证明工程能力的不是功能列表,是每一次改动背后可查的理由。
每一次的否决理由都留了档:生物可利用度计算器(不够扎人)· LLM 营养评测基准(不回扣女性)· 清除后躯体层(仍是"算给她看")· 「现在吃得下什么」(限制侧框架,暴食侧不适用)· 混合餐时间曲线(算不了"之后")· 让患者当食物库录入员(那要的正是极度的精确——把症状的核心动作包装成美德)· 接回食物记忆(记忆对这个人群常是创伤)。
第八版才落到「把形容词还给她」。那个探针还顺手杀死了一个我自己提的论点:为验证"AI 系统性高估中餐营养",跑了 5 个模型 × 6 组生熟配对,结果是"没扣"9 组 / "扣了"8 组——随机方差,不是有方向的偏差。论点不成立,方案当场作废。
用这把尺子过了 26 屏,改掉五处:
| 原来 | 改成 |
|---|---|
| 空着的格子不是失分,是一个洞 | 空着的格子不用补。它只说明那会儿没吃上 |
| 水会自己退,你不用看着它 | 今天之后可能会觉得肿,秤上也会重一点。那是水,几天就下去了 ——先说现象再说它是水,顺序反过来才看得懂 |
| 不用记下来,也不用算进什么 | 不用记下来。也不用算成这个月的第几次 |
| 空太久了,身体会自己来找 | 太久没吃东西,那阵饿会自己涨起来 |
| 只是摆在这儿,不是结论 | 就是这么放着。不是要说你什么 |
更早一轮里,三版热量下限文案被一句话推掉:「量不够这样的话其实本质上也是评价」——三版的最后一句主语全是"你",都在下判断,哪怕判的是"不是你的错"。否定式的评价仍然是评价。
canvas 2d + PBD 物理——因为需求从"重力效果"变成"跟着手机晃",而关键帧只能播一条事先算好的轨迹。踩过的坑:珠子出生点写在罐外,容器约束第 0 帧把它瞬移到内壁,而速度是 (x-px)/dt 回写的,那段瞬移被当成一帧走完 → 垂直速度炸到自由落体的四倍,珠子是被弹射进去的。出生点挪进内壁后反弹帧数归零。shot.mjs 的顶部留白算错了 47px,于是一批"测出来装下"的屏在真机上是超的。它必须和运行时的 topPad 一致:(statusBarHeight || 20) + 40。这一段值得单独写,因为它是"效果一般"的真实原因往往在参数里,不在设计里的实例:
| 拍错的 | 后果 |
|---|---|
max_tokens = 3000 | 它不是上限保护,是模型的写作预算——给多少就写多少,于是每次 16 秒。改成 400,变 3 秒 |
| 调小之后 | reasoning 模型直接返回空(思考就把额度花完)。真正的解不是调数字,是换非 reasoning 模型——在这两个错误之间来回撞了两轮 |
| 云函数执行超时 3 秒 | 平台默认值。四个人并发一定超时。默认值不是合理值,是平台不知道你要干什么时的保守值 |
MIN = 8(回复最短字数) | 把「肩膀松一下。」这种正确的回答拦掉 → 退回模板 → 用户抱怨的"太干",一部分是护栏自己造成的 |
护栏拦错的代价不是"少一句话",是用户永远看到模板。
内容检测规则改过三轮,每次都是同一个错——在列词,不在列模式:
/我(懂|听见|明白|知道|感受|陪)/(很|真|挺)(棒|好|厉害)|已经.{0,4}(很好|不错)反向也踩过:用 /—{2,}/ 拦 markdown 分割线,把中文破折号误杀了——而破折号在那 26 屏文案里到处在用。每加一条规则,都要拿该放行的真实样本试一遍。
多轮对话第二轮开始没有回应。查了很久,因为 _hist() 的注释写着「只带这一位说过的和她说过的」——但代码不分人,把四个人的话全传给每一位。模型看到自己"说过"别人的话,人设串掉,输出被护栏拦下。
有一屏「答两个问题,这里给你的东西会更准」,两个答案存进了本地——但全工程没有任何一处读它们,而屏上明写着答「有」会多出哪两屏,那两屏本来就一直在。
看起来在工作的开关比缺功能更伤:用户答完发现什么都没变,下次就不信这个产品说的话。整屏删除,连带清掉块型、事件处理和存储层的三个函数——删屏要连着删存储层,否则下次有人会以为那两个标记还有意义。
微信小程序涉及心理健康内容需要前置审批,而个人主体账号申请不了——不是审得慢,是这条路对个人开发者是关着的。
这个限制有个具体的形态:体验版的白名单上限是 15 人。也就是说在拿到前置审批之前,这个产品最多只能有 15 个用户——而这 15 个还得一个一个手动加微信号。
这句话比"中文世界没有"更硬:是有结构性障碍。上线路径因此是明确的——企业主体 + 医疗机构合作,而这恰好接上商业模式。
不走的四条:不向患者收订阅(付费墙挡在急性期前面是灾难)· 不做广告(进食障碍用户 + 广告定向 = 减肥广告精准投放)· 不做数据变现 · 不把急性期流量导向按分钟计费的心理咨询。
走的一条:机构授权——高校心理中心 / 专科院外延伸 / 企业 EAP。进食障碍在大学生中高发而学校普遍无专门工具;出院后空窗期正是复发高发期;EAP 通常不覆盖进食障碍。付费方明确、预算明确、且不是脆弱的那一方。
# 微信开发者工具打开仓库根目录(miniprogramRoot 指向 04-小程序/),选「小程序模式」 # data/*.js 与 tokens.wxss 是生成物,已在仓库里,导入即可运行 node 04-小程序/.sync-mp/chk.mjs # 16 项自检,clone 下来就能跑
另外两个是作者本机的构建工具,不在提交仓库的运行链上:gen.mjs 从可交互原型抽出屏数据与色板,源文件是工作仓的原型与设计画布,不随参赛仓库提交;shot.mjs 用真实 WXSS 渲进 headless Chrome 量一屏装不装得下,需要 macOS 与本机 Chrome。要验证这个产品的立场,跑 chk.mjs 就够——立场断言全在它里面。
「四个人」需要云函数:部署 04-小程序/cloudfunctions/talk,在云开发控制台给它配环境变量 OPENROUTER_KEY,并把该函数的执行超时从平台默认的 3 秒改大(四个人是并发调用,3 秒一定超时——见第 07 节)。不配密钥也能跑——那一层会退回人写的话。
在这个领域,不做什么比做什么更能体现判断:
任何一屏第一句话不得是指令或提问 · 每一屏都必须有一个不是任务的选项 · 不用「应该」「建议你」「正确做法是」 · 解释放在动作后面且可折叠 · 不出现进度、评价、总结性判断。
三把尺子:说有什么,不说没什么 · 念出来,念整屏 · 屏幕上只有食物。
仓库 github.com/hu2976/ebbing · Tag shenicest-fission
本文档即完整的项目说明。路演文稿见 02-路演PPT.html(单文件,浏览器全屏翻页),作品演示见 03-演示视频.mp4。
(PRD、竞品地形、数据底册属于工作过程稿,不随参赛仓库提交。)
选中任意正文可批注。批注存在浏览器本地,按文档标题索引——标题改了批注会丢。