
凌晨,我们把第一个真人的火锅选择喂给模型。
屏幕上的字一个一个往外蹦,写他选的锅底、他下的食材、他在某道菜上停了好几秒才点下去。读到中间某一句,桌子边上几个人忽然都安静了。
那句话我现在还记得。它没说什么大道理,只是把他刚才那一连串”看起来随便点点”的选择,翻译成了一个我们谁都没明说、但又确实是他的人。
有人先开口:“卧槽……这也太像他了吧。”
那一刻我才确信,这东西成了。
一、缘起:AI 当了这么久”回答者”,能不能换它当一次”观察者”?
先交代背景。这是抖音 AI 创变者黑客松,我们要在现场做一个能让观众上手就玩、玩完还想转发的互动装置。
动手之前我们先吵了一架——吵的是方向。
你想想现在的 AI 产品,几乎都是同一个姿势:你输入问题,它输出答案。你是提问者,它是回答者。ChatGPT 是这样,所有”AI 测试""AI 算命”也是这样——本质上都是你先把自己交代清楚,它再告诉你你是谁。
我非常理解这种设计,它高效、直接、好做。但它有个问题:人一旦意识到自己在”被测试”,就会开始表演。 你问我”你是个冒险的人还是稳妥的人”,我多半会挑一个我希望自己是的答案,而不是我真实的样子。
所以我们想反过来试试:
能不能让 AI 闭嘴,先别急着回答,而是安安静静地看你做一件事——看你怎么选、先选什么、在哪儿犹豫——再来告诉你,你是个什么样的人。
把人变成”在做事的人”,而不是”在答题的人”。当你不知道自己正在被解读的时候,你才最真实。
那做什么事好呢?得是个人人都熟、零门槛、还自带现场感的动作。
配火锅。
火锅这个隐喻一摆上桌,整个产品就立住了:
- 锅底,是你的人生底色。
- 食材,是你愿意往人生里投的资源。
- 蘸料,是你处理事情的行为风格。
你以为自己在涮毛肚,其实你在排人生的优先级。一句话能讲明白,这在黑客松现场太重要了——评委和观众没耐心听你解释三分钟。

二、藏起来的设计:好的反转,是让人事后才发现自己被看见了
确定了隐喻,真正花心思的地方是怎么藏。
第一版我们老老实实地在每个锅底下面写上含义:“热烈""稳定""清醒""冒险”。结果一测就废了——用户一眼看到标签,立刻开始挑那个”听起来最好的”。表演又回来了。
于是我们做了个挺反直觉的决定:界面上只留锅底的名字,把它代表什么意思全部藏到最后的报告里。 选的时候你只看到一锅红汤一锅白汤,等报告出来才告诉你,原来你刚才挑的是什么。
这就是现场我们最想要的那个反转——「原来我被看见了」。先让你松弛地玩,玩完再”啪”地一下把你看穿。
还有一个我自己很喜欢的取向:锅底、食材、蘸料全都不限数量,一个都不选也能继续。

很多人第一反应是”这不就乱了套吗”。但恰恰相反——“不选”本身就是一种选择。 一个面对满桌食材一样都不肯下的人,和一个把锅堆满的人,是两种完全不同的人生态度。我们不替用户做减法,把表达的自由还给他。
三、AI 看的不只是你选了什么,还有你怎么犹豫
光记录”选了哪几样”是不够的,那还是在看答案。我们想让 AI 看的是过程。
于是有了底层这套「100 金币人生分配」:假如你有 100 枚金币,会怎么分给财富、爱情、自由、家庭、梦想这五个维度。
每个锅底、每样食材、每味蘸料,背后都挂着一组五维权重。你选得越多,金币就往对应的维度上堆。最后归一化成总和正好 100 的一份”人生账本”。
但真正让它活起来的,是两个修正因子(这段是 scoring.ts 里我改了好几遍的核心逻辑):
const priority = 1 + 1 / (pick.order + 1); // 越早选,权重越高
const hesitation = pick.hesitateMs > 4000 ? 0.85 : 1; // 犹豫超过 4 秒,打折
const mult = priority * hesitation;
翻译成人话:
- 你越早、越果断选的东西,AI 认为那是你越在乎的。
- 你盯着某样东西犹豫了很久才下手,AI 会把它的分量调低——因为那说明你在这件事上是拉扯的、不确定的。
你看,这就不只是”你选了牛肉”,而是”你在牛肉和虾滑之间纠结了五秒,最后选了牛肉”。后者才是一个真实的人。
AI 真正在读的,从来不是你的答案,而是你做选择时那点没说出口的迟疑。

四、十几个小时的剪枝:把能砍的全砍掉,只留”被看见”的那一刻
黑客松最值钱的不是你做了多少,而是你舍得砍掉多少。整个技术方案可以总结成一句话:
客户端扛住 90% 的体验逻辑,服务端只做必须的 AI 代理。
具体几个取舍,每一个背后都是”时间不够”逼出来的:
1)把 AI 写好的人生故事,直接”烤进”分享链接里。
报告页地址长这样:/report/<一长串编码>。这串编码不是数据库 ID,而是把你的选择摘要加上 AI 写好的整段故事,base64 塞进了 URL 本身。
const lite = { b: 选的锅底, i: 食材, c: 蘸料, p: 选择过程, s: story };
return btoa(...) // 整个故事就藏在这串字符里
好处是:报告页生成一张二维码,别人扫码、点开,不需要任何 key、不查任何数据库,直接就能看到你的故事。 黑客松现场没时间搭后端存储,这一招让”扫码分享”这个最出片的环节零成本跑通了。评委看不到你数据库建得多优雅,但能扫码看到一个完整的故事——这笔账很好算。
2)任何 AI 调用失败,都自动回落到确定性模板,现场绝不白屏。
故事走 deepseek-v4-pro,拍照识别气质走 minimax-m3,都经一个 OpenAI 兼容的网关。但现场的网络你永远不能信。所以每一处 AI 调用,超时、报错、没 key,统统返回空字符串,由调用方兜底到一份本地写死的模板故事。
这不是偷懒,是 demo 阶段的保命符。演示翻车只有一种形态,就是白屏。 只要永远有东西能显示,我们就立于不败之地。
3)拍照识别做成流式,边识别边往屏幕上填四个标签。
minimax-m3 看一眼你的照片,整体气质、服饰风格、主色印象、现场状态四个标签,一个一个浮出来。不是转圈等三秒再”啪”全出来,而是让你眼睁睁看着 AI”正在看你”。等待的焦虑,被我们变成了被注视的期待。
至于踩的坑,老黑客松人都懂:隔空手势抓食材那块逻辑我们推翻重写了一次(git 里那条提交我老实写了”干净重做”);还有 Cloudflare 部署时 node 版本和 lockfile 对不上,npm ci 反复报不同步,半夜用 node 22 重生了好几回 package-lock.json 才消停。都是体力活,不细说了。
五、高光时刻:当 AI 写出”有点像他”的那段故事
回到开头那个凌晨。
把所有逻辑串通、第一次拿真人的选择跑完整条链路时,其实我心里是没底的。金币能算对、二维码能扫开,这些我都验证过了。但最后那段 AI 写的人生故事——它到底是会写出一段正确的废话,还是真能”接住”一个人?这个我赌不准。
然后字就一个一个蹦出来了。它没有复述他选了什么,而是顺着那份金币分配和他下手时的那点犹豫,写了一个关于”既想要安稳、又总在某个角落留一道门给冒险”的人。
桌边那句”卧槽这也太像他了”,就是这么来的。
那一刻我突然明白,我们做的根本不是一个测试。让人愿意转发的,从来不是”这个测试结果很准”,而是”原来我以为没人注意的小动作,居然被看见了”。 准不准是其次,被看见才是那根针。

写在最后
这次没拿奖。但现场围着屏幕配火锅、配完盯着报告咂摸半天、然后掏手机扫码的那些人,比任何一块奖牌都让我踏实。我们想要的那个反转,真的在一张张陌生的脸上发生了。
隔空手势的完整装置形态、照片的长期档案,这些还停在线下装置的目标清单里,Web Demo 暂时只跑通了点击和触摸。这是遗憾,但也是下一步。
折腾完这一趟,我最大的收获其实是一句话——
很多 AI 产品不缺模型,缺的是一个让人愿意把真实的自己交出去的场景。
我们没让 AI 变得更聪明,只是让它换了个姿势:从一个急着回答你的人,变成一个安静看你做选择的人。有时候,被好好看一眼,比被准确回答更动人。
你以为自己在配火锅。
其实你正在构建人生。