之前有个运营朋友找我帮忙,说她让AI帮她做了个抽奖工具,结果用了两次,发现每次中奖的都是名单里排在前面的几个人。她以为是自己的问题,改了好几次提示词,还是不对。
后来我看了一眼,问题很简单:她让AI「随机选一个名字」,AI就真的在对话里「选」了一个——不是程序跑出来的,是模型根据上下文「觉得」应该选谁。
这不是随机,这是模型的偏好。
AI生成随机数,为什么不靠谱
说真的,这个坑我自己也踩过。
大语言模型本质上是在预测「下一个最合理的词」。当你问它「从1到100随机给我一个数字」,它给出的数字在统计上是有规律的——某些数字出现频率明显更高,比如17、42、7这类在训练数据里频繁出现的「感觉随机」的数字。
这不是bug,是模型的工作原理决定的。它没有真正的随机数生成器,它只有概率分布。
所以抽奖、打乱顺序、随机分组这类场景,你不能让模型「想」一个结果,必须让程序跑一个结果。`Math.random()`、`crypto.getRandomValues()`,这些才是真正的随机源。
用HTML单文件做抽奖工具,比你想的简单
想清楚这个之后,我帮那个朋友重新做了一版。思路很直接:
一个HTML文件,所有逻辑写在里面,不依赖任何后端。用AI辅助写代码,但随机逻辑部分明确告诉AI:用`crypto.getRandomValues()`实现Fisher-Yates洗牌算法,不要让模型在运行时「选择」结果。
核心代码大概长这样:
function shuffle(arr) {
const array = [...arr];
for (let i = array.length - 1; i > 0; i--) {
const j = Math.floor(crypto.getRandomValues(new Uint32Array(1))[0] / (0xFFFFFFFF + 1) * (i + 1));
[array[i], array[j]] = [array[j], array[i]];
}
return array;
}这段逻辑AI可以帮你写,但「用哪个随机源」这个决策必须是你来定,不能让AI自己发挥。
界面部分就简单了:一个文本框粘贴名单,一个输入框填抽几个,一个按钮触发,结果显示在页面上。让AI帮你做样式,做动画,完全没问题,这些不影响结果的正确性。
用HTML在线运行调试的时候,能直接在浏览器里跑,改完立刻看效果,不用搭任何本地环境。
本地能跑,但发不出去——这才是真正的卡点
工具做好了,朋友说:「我怎么把这个发给同事用?」
这是独立开发者做HTML工具最常见的卡点。本地打开没问题,但你没办法把一个本地文件路径发给别人访问。
以前的办法是自己买服务器、配Nginx、搞域名,光这一套就能劝退大半人。
现在的路径短多了。做好的HTML单文件,直接走Web应用托管发布出去,就有一个能发链接的地址,对方打开浏览器就能用,不用装任何东西。
这对运营场景特别实用。抽奖、投票、报名收集、活动倒计时,这类工具的生命周期往往就一两次活动,不值得专门搭一套服务,但又必须能让别人访问到。
HTML单文件+托管发布,是目前成本最低的路径。
让AI做工具,但别让AI做决策
这件事让我想清楚了一个分工原则:
AI适合帮你写界面、写样式、写交互逻辑、处理文本——这些地方「差不多对」就够用了。
但涉及到结果必须客观正确的地方——随机、计算、数据处理——你需要的是程序执行,不是模型推理。
市场上现在很多「AI生成工具」的坑,都出在这里。不是AI写不了代码,是有些人把「让AI生成代码」和「让AI在运行时做判断」混在一起了。
前者没问题,后者在抽奖这类场景里会出错。
如果你也在用AI帮自己做小工具,这个分工值得记一下。工具的骨架和皮肤交给AI,但核心逻辑的正确性要自己把关——哪怕只是确认一下它用的随机函数是不是真随机。
现在可以做的一个小动作:把你手头某个依赖「AI选择」的工具翻出来看看,确认一下随机逻辑是程序跑的还是模型想的。