「AI生成的随机数」是个近几年被反复讨论的话题。很多人以为把 Prompt 扔给大模型、让它“随便想一个数”,就能得到真正的随机结果。实际验证之后会发现,AI 生成的随机数往往带有明显的统计偏差、可复现倾向和上下文记忆,跟经典伪随机数生成器(PRNG)甚至真随机数发生器(TRNG)都存在本质差异。
这篇文章不站在概念层面空谈,而是把随机数生成这件事拆成可验证的技术流程:AI 生成数字的方式、随机性检验方法、批量调用场景、接口集成、显存和性能观察、常见失败原因。读者看完之后能自己判断“AI 生成的随机数到底能不能用”,并且知道在什么场景下该选哪种方案。
1. 核心概念速览
| 能力项 | 说明 |
|---|---|
| 核心问题 | AI 生成的数字序列是否满足统计学随机性要求 |
| 生成原理 | 大语言模型根据上下文做概率采样,不是从物理熵源取数 |
| 传统对照 | 伪随机数生成器(如梅森旋转算法、线性同余法)和真随机数生成器 |
| 随机性检验 | 卡方检验、游程检验、K-S 检验、NIST SP 800-22 统计测试套件等 |
| AI 可选采样方式 | top-k、top-p、temperature 参数调整,影响输出多样性 |
| 推荐验证方式 | 用公开统计测试工具对 AI 输出序列做均匀性、独立性和熵值分析 |
| 适用场景 | 非安全类模拟、抽样、数据增强、教学演示、备选随机源 |
| 不适合场景 | 密钥生成、验证码安全、加密随机盐、抽奖防作弊、密码学安全随机数 |
| 典型部署环境 | 可调用本地或云端大模型 API,CPU 即可完成推理,GPU 主要用于加速采样 |
这里有一个容易被忽略的点:我们在讨论“AI 生成随机数”的时候,真实对象是大语言模型的解码采样过程。它本质上是“根据训练数据和上下文预测下一个 Token”,并不是一个专门做随机数生成的算法。明白了这一点,后面讨论随机性测试才会有依据。
2. AI 生成随机数的原理与随机性来源
2.1 大模型如何“生成”数字
大模型生成文本时,每一轮都会根据当前输入的 Token 序列计算下一个 Token 的概率分布,然后从分布中挑选一个 Token。常见的解码策略有:
- Greedy Decoding:每次都选概率最大的 Token,结果稳定但几乎没有随机性。
- Beam Search:维护多个候选序列,最终取整体概率最高的结果,也不适合生成随机数。
- 随机采样:根据概率分布做抽样,配合 temperature、top-k、top-p 参数调整输出多样性。
随机采样是大模型生成随机数的主要途径。当我们要求模型“给我一个 1 到 100 之间的随机整数”时,模型本质上是在学到的 Token 概率分布上做采样,而不是测量某个物理过程。
2.2 真随机数、伪随机数与 AI 随机数的区别
| 类型 | 随机性来源 | 典型实现 | 特点 |
|---|---|---|---|
| 真随机数 TRNG | 物理过程:热噪声、光电效应、量子效应 | 硬件随机数生成器、特定噪声采样设备 | 不可预测,适合密码学场景 |
| 伪随机数 PRNG | 算法和种子 | Python random 模块、NumPy RandomState、Java Random | 速度快、可复现、种子相同时序列一致 |
| AI 生成随机数 | 模型参数和上下文 | 大模型 API 或本地模型采样 | 分布受训练数据影响,输出可复现,速度慢 |
关键点是:AI 生成随机数,既不依赖物理熵源,也不是严格意义上的周期性算法。它像是一个“被训练过的采样器”,输出分布往往偏向训练数据中出现频率较高的模式。例如,让模型生成 0 到 9 的数字,某些数字出现的概率可能明显高于平均值。
2.3 为什么 AI 生成随机数容易“不够随机”
模型并不知道“均匀随机”的数学含义,它只是从数据中学到了语言模式。以下是常见偏差来源:
- 训练数据分布:人类写出的随机数并不是真正均匀分布的,模型会模仿这种不均匀性。
- 上下文影响:之前的数字或文本会改变模型的下一个预测。例如生成“1, 3”之后,模型可能倾向于生成 5 或 7,因为训练数据里常见等差数列。
- 采样参数设置:temperature 过低会降低多样性;top-p 过小会只保留概率最高的少数候选 Token。
- Token 粒度问题:数字可能被拆成多个 Token,模型在 Token 级别分配概率,不保证整数级别均匀。
所以,直接让 AI 生成随机数,得到的序列大概率会在统计测试中挂掉。
3. 环境准备与最小代码示例
验证 AI 生成随机数不需要很高配置。CPU 就可以跑本地小模型;如果调用云端 API,则只依赖网络和 API Key。下面给出一套适用于各种接入方式的通用验证思路。
3.1 本地模型路径
本地推理适合使用 4G 到 8G 显存的消费级显卡,也可以直接跑 CPU 推理,只是采样速度会明显变慢。部署模型的工具可选 vLLM、Ollama 或 llama.cpp。需要注意:显存占用取决于模型参数量、量化精度和上下文长度,实际占用需要以本机测试为准。
3.2 Python 环境
建议使用 Python 3.10 以上版本,准备以下依赖:
pip install requests numpy scipy这里不依赖特定深度学习框架,因为验证重点是输出序列的统计性质,不是模型训练。如果你要本地加载模型,再按模型框架安装 torch 或 transformers。
3.3 调用 AI 接口获取数字
下面以 OpenAI 兼容接口为例,写一个可替换的调用模板。实际项目请按你使用的 API 地址、模型名和密钥调整。
import requests import json api_url = "http://127.0.0.1:8000/v1/chat/completions" api_key = "your-api-key" def generate_random_numbers(count): numbers = [] for _ in range(count): payload = { "model": "your-model-name", "messages": [ {"role": "system", "content": "You are a random number generator."}, {"role": "user", "content": "Generate a random integer between 1 and 100. Output only the number."} ], "temperature": 1.0, "max_tokens": 8, "top_p": 0.9 } headers = { "Content-Type": "application/json", "Authorization": f"Bearer {api_key}" } resp = requests.post(api_url, json=payload, headers=headers, timeout=30) result = resp.json() content = result["choices"][0]["message"]["content"].strip() numbers.append(int(content)) return numbers if __name__ == "__main__": samples = generate_random_numbers(100) print(samples)这里强调一个要点:每次调用都重新请求模型,得到的序列基本不会重复。但如果你把 temperature 设为 0,模型可能每次输出同一个数字,这会让“随机数生成”彻底失效。
3.4 使用经典 PRNG 作为对照
为了对比,准备一组经典 PRNG 输出。Python 的 random 模块基于梅森旋转算法,虽然不属于密码学安全类,但统计均匀性远超常见大模型输出。
import random random.seed(2025) samples_prng = [random.randint(1, 100) for _ in range(100)] print(samples_prng)后续所有统计检验,都应同时输入 AI 输出序列和 PRNG 输出序列,对照观察差异。
4. 随机性统计检验方法
判断一组数字是否足够随机,不能靠肉眼。需要借助统计学检验。以下是几个常用且可以快速上手的检验方式。
4.1 卡方检验
卡方检验用于验证观测频数与期望频数是否一致。例如生成 0 到 9 之间的 1000 个数字,理论上每个数字应出现约 100 次。卡方统计量越大,说明偏离均匀分布越明显。
from scipy.stats import chisquare def chi_square_test(data, num_buckets=10, expected_ratio=0.1): observed = [0] * num_buckets for value in data: if 0 <= value < num_buckets: observed[value] += 1 total = len(data) expected = [expected_ratio * total] * num_buckets stat, p_value = chisquare(observed, expected) return stat, p_value如果 p 值低于 0.05,可以认为观测频数与均匀分布差异显著。
4.2 游程检验
游程检验用于判断序列中连续相同性质元素的数量是否正常。例如把数据分成“高于中位数”和“低于中位数”两类,然后统计连续上升或连续下降的次数。
def runs_test(data): threshold = sum(data) / len(data) signs = [1 if value >= threshold else 0 for value in data] runs = 1 for i in range(1, len(signs)): if signs[i] != signs[i - 1]: runs += 1 n1 = sum(signs) n2 = len(signs) - n1 runs_expected = (2 * n1 * n2) / (n1 + n2) + 1 return runs, runs_expected游程过多或过少,都说明序列呈现某种结构,而不是随机。
4.3 信息熵
信息熵衡量序列的不确定性。对于取值 0 到 255 的字节数据,理想随机序列每个值出现概率接近 1/256,熵接近 8。对于 0 到 99 的整数序列,最大熵约是 log(100)/log(2)。
import math def entropy_estimate(data): total = len(data) counter = {} for value in data: counter[value] = counter.get(value, 0) + 1 entropy = 0.0 for count in counter.values(): p = count / total entropy -= p * math.log2(p) return entropyAI 生成序列熵值通常低于理想值,因为模型会避开一部分低频 Token。
4.4 NIST SP 800-22 测试套件
NIST SP 800-22 是美国国家标准与技术研究院发布的随机数统计测试套件,覆盖频数测试、块内频数测试、游程测试、最长游程测试、离散傅里叶变换测试、非重叠模板匹配等多项内容。它更适合检测密码学随机数生成器,但也可以用于 AI 输出序列的宏观评估。
实际操作时,可以把生成的数字转换为二进制位串,然后运行 NIST 工具或 Python 开源实现。需要准备足够长的样本,例如至少 100 万比特,否则部分测试项目没有统计意义。
5. AI 生成随机数的验证结果与典型表现
在真实测试中,AI 生成随机数通常会表现出以下规律:
5.1 数字分布不均匀
让小模型连续生成 1000 个 0 到 9 的整数,预期每个数字出现 100 次。实际结果往往某些数字出现 120 次以上,另一些数字不到 80 次。卡方检验 p 值大概率小于 0.05。
5.2 存在上下文记忆
让模型连续生成 20 个数,然后重置会话,对同一个 Prompt 重复提问。如果 temperature 为 0,两次结果相同;如果 temperature 较高,两次结果不同但字符规律相近。
5.3 尾数偏好现象
很多模型倾向于输出以“0 1 2 5 7 8”结尾的数字,而回避“4 6 9”。这可能来自训练数据的模式偏差。
5.4 与参数强相关
temperature 从 0.2 调到 1.5,输出分布的均匀性会变化。调低 temperature 会让模型更保守,甚至反复输出同一个数;调高 temperature 会增加输出变化,但也会引入无效 Token,例如输出“87\n88”或多行文本。
5.5 运维成本高
生成 1000 个随机数,如果走普通对话接口,需要发起 1000 次 HTTP 请求,耗时可能达到几分钟甚至更久。经典 PRNG 在本地生成 1000 个随机数不到 1 毫秒,差距非常大。
6. 接口 API 与批量任务设计
如果你确实需要把 AI 随机数接入业务系统,不要一个数字发一个请求。更合理的方案是批量生成并缓存,再做后处理。
6.1 单次批量生成
让模型一次输出多个数字,用逗号或换行分隔,减少请求次数。
curl http://127.0.0.1:8000/v1/chat/completions \ -H "Content-Type: application/json" \ -H "Authorization: Bearer your-api-key" \ -d '{ "model": "your-model-name", "messages": [ {"role": "system", "content": "You are a random number generator."}, {"role": "user", "content": "Generate 100 random integers between 1 and 100. Output numbers separated by commas."} ], "temperature": 1.2, "max_tokens": 512 }'响应中可能包含模型自然语言的前缀后缀,例如“好的,以下是生成的随机数:”。需要在后处理中提取数字部分。
6.2 批量队列与失败重试
设计批量任务时,建议加上任务队列、超时控制和失败重试。参考流程:
- 准备输入任务列表,每条任务包含一个 Prompt 或一组 Prompt。
- 使用并发线程限制请求频率,避免触发服务限流。
- 对返回结果做正则提取,过滤非数字内容。
- 保留原始响应日志,方便排查模型输出异常。
- 如果单次请求失败,间隔重试,最多重试 3 次。
import re import time import requests def extract_numbers(text): matches = re.findall(r"\b\d+\b", text) return [int(num) for num in matches] def batch_generate(tasks, interval=0.5): results = [] for task in tasks: for attempt in range(3): try: numbers = generate_random_numbers_from_task(task) results.append(numbers) break except Exception as e: if attempt == 2: results.append({"error": str(e), "task": task}) else: time.sleep(interval * (attempt + 1)) return results6.3 接口安全边界
如果对外提供随机数接口,必须限制访问范围。不要开放公网无鉴权端口,不要用 AI 生成随机数作为优惠券码、激活码、抽奖种子等依赖不可预测性的凭证。AI 生成结果一旦被攻击者掌握采样参数或模型版本,就有被还原的风险。
7. 性能观察与资源占用
7.1 延迟对比
- PRNG:生成 100000 个随机整数耗时通常在毫秒级别。
- 本地 AI 模型:生成一个数字需要一次前向推理,CPU 上可能耗时几百毫秒到数秒,GPU 上可能几十毫秒到几百毫秒。
- 云端 API:单次请求延迟主要受网络和服务器负载影响,100 次串行请求可能耗时几分钟。
7.2 显存与内存
本地模型显存占用取决于模型大小和量化等级。7B 模型的 4-bit 量化版本在消费级显卡上可以运行,但仍需预留足够显存给上下文窗口。CPU 推理则主要消耗内存,速度较慢。更稳妥的方式是先做小模型测试,观察任务管理器中的显存曲线,再决定是否换更大模型。
7.3 吞吐量评估
评估 AI 生成随机数的吞吐量,建议关注两个指标:
- 每秒完成请求数(Requests Per Second)。
- 有效数字输出比率(有效数字数量除以总 Token 数)。
当 temperature 设置偏高时,模型可能输出无意义的连接词,有效数字比率下降,间接推高成本。
7.4 稳定性观察
稳定性测试包括连续调用 100 次接口,观察失败率、超时率、响应内容变化。大模型服务在高峰期可能出现响应延迟增加或内容截断,需要在业务侧增加长度校验。
8. 常见问题与排查方法
| 问题现象 | 可能原因 | 排查方式 | 解决方案 |
|---|---|---|---|
| 每次生成结果完全一样 | temperature 过低或模型处于贪心解码模式 | 检查采样参数和请求配置 | 调高 temperature,开启随机采样 |
| 生成结果包含中文解释 | 提示词约束不够或 max_tokens 太长 | 查看完整响应日志 | 使用后处理提取数字,或要求“只输出数字” |
| 数字分布明显偏差 | 模型训练数据固有偏差 | 做卡方检验,对比多个模型 | 增加序列长度,或改用 PRNG |
| 批量任务卡住 | 请求超时设置过短或并发过高 | 查看日志和任务队列 | 增加超时时间,降低并发数 |
| API 调用 404 | 接口地址或模型名错误 | 检查服务端日志和接口文档 | 替换成实际可用的接口路径 |
| 本地模型显存溢出 | 模型过大或上下文过长 | 观察显存占用曲线 | 换小模型,或降低上下文长度 |
| 输出数字有偏多位数 | Prompt 要求不明确 | 检查返回内容格式 | 规定生成范围,例如“1 到 100 之间的整数” |
| 数字分布均匀但仍是顺次序列 | 采样参数过于机械 | 分析游程检验结果 | 增加 temperature 和随机种子策略 |
9. 最佳实践与使用建议
9.1 什么时候可以用 AI 生成随机数
- 模拟实验但允许一定偏差的场合。
- 需要“看起来随机”的展示数据。
- 文本生成场景中需要插入一个变化数字。
- 教育和教学演示,用来解释采样、温度和概率分布。
9.2 什么时候必须放弃 AI 随机数
- 密码学密钥、盐值、初始化向量。
- 抽奖开奖、优惠券码、防作弊 token。
- 对统计均匀性有严格要求的蒙特卡洛模拟。
- 大规模数据库主键或幂等键生成。
这些场景应该使用secrets、硬件随机数或通过系统熵源实现的 CSPRNG。
9.3 工程化建议
第一,保留对照实验。写脚本同时采集 AI 输出和 PRNG 输出,计算分布均值、方差和 p 值。第二,把模型输出结果做后处理,比如对模型输出的数字取哈希,再用哈希结果映射到目标范围。这不会从根本上解决“熵不足”的问题,但可以抹掉部分可见规律。第三,控制采样参数。temperature 调到 0.8 以上,top_p 设置 0.9 左右,避免模型走捷径输出固定值。第四,建立输出日志。保存原始模型响应和最终使用的数字,方便回溯分析。
9.4 合规与安全边界
使用公开 API 时,要遵守模型服务商的使用条款,不要发送敏感数据作为 Prompt。随机数服务如果涉及生成优惠券、邀请码或验证码,必须接入审计日志,并确保高权限操作不会依赖 AI 输出。人脸生成、声音模拟、文档解析等 AI 功能均有合规要求,务必在授权范围内使用。涉及真实用户数据时,要做隐私脱敏处理。
10. 总结与下一步
AI 生成的随机数,从统计检验角度看,大概率不是好用的随机数。它的优势在于“生成方式便捷”,不需要额外硬件,调用一个对话接口就能拿到数字;劣势在于分布不均匀、上下文敏感、延迟高,而且容易被复现。想验证这个问题,建议先按这篇文章的流程采集 1000 个样本,跑一次卡方检验和游程检验,你会直观看到 p 值和游程数量的异常。
最容易踩的坑是:把 AI 生成随机数直接用到安全和防作弊场景。随口让模型“随便生成一个数”不代表不可预测,更不代表均匀随机。正确做法是明确区分用途:普通数据模拟可以偶尔用 AI,安全场景必须用 CSPRNG,统计实验应使用专业 PRNG 或硬件随机源。
下一步可以做的方向有:把 AI 模型的输出作为噪声源之一,与系统熵源混合后再做哈希映射;或者用大量 AI 输出训练一个偏差补偿模型,尝试修正分布;更实用的做法是,写一套自动化随机性测试脚本,每次换模型、换采样参数后都跑一遍统计检验,形成自己的“随机性评测基准”。这样下次再有人问“AI 生成的随机数真的随机吗”,你就能直接用数据回答。