一粒沙子,一堆沙子
一粒沙子,一堆沙子:当 LLM 遇到堆悖论
1. 那个古老的悖论
古希腊人早已知道,概念边界往往是模糊的。堆悖论(Sorites paradox)提出了一个让人不安的问题:
一粒沙子不是一堆;
如果 n 粒沙子不是一堆,那么 n+1 粒也不是;
因此,十万粒沙子也不是一堆。
这个推理显然是荒谬的,但每一步看起来又都无可辩驳。问题的核心在于:**”堆”这个概念的边界在哪里?**
两千多年后,我们把同样的问题抛给了大语言模型。但不是为了看它们能否”解决”这个悖论——悖论本质上不可解嘛——而是想看:它们在哪里画下那条线?那条线是否稳定?是否会因为语言不同而移动?
2. 实验设计
2.1 模型选择
我们选取了两个开源模型进行测试:
- Qwen3.5-4B-AWQ
- Qwen3.5-9B-AWQ
之所以选择 AWQ 量化版本,是因为它们代表了当前部署最广泛的”够用就好”的模型规格——4B 参数适合边缘设备,9B 则在消费级 GPU 上即可运行。更重要的是,这两个模型共享同一套架构和训练数据,唯一的区别是参数量,这让我们可以隔离观察”规模效应”。简单说就是看看变大有没有变聪明啦。
2.2 提示框架
实验的核心是强制二选一。我们在三种不同的提示框架下重复测试,每种框架都有中英日三个版本。
框架一:Direct(直接询问)
"zh": "请判断:如果有{n}粒沙子,它算不算一堆沙子?只输出 A 或 B。A=算一堆沙子,B=不算一堆沙子。",
"en": "Decide whether {n} grains of sand count as a heap. Output only A or B. A = it is a heap. B = it is not a heap.",
"ja": "{n}粒の砂があるとき、それは砂山と呼べますか。A か B だけを出力してください。A=砂山である。B=砂山ではない。"框架二:Everyday(日常语境)
"zh": "在日常说法里,看到地上有{n}粒沙子,人们通常会不会把它叫作一堆沙子?只输出 A 或 B。A=通常会,B=通常不会。",
"en": "In everyday language, would people usually call {n} grains of sand a heap? Output only A or B. A = usually yes. B = usually no.",
"ja": "日常会話では、{n}粒の砂を見て普通は砂山と呼ぶでしょうか。A か B だけを出力してください。A=普通は呼ぶ。B=普通は呼ばない。"框架三:Strict(严格判断)
"zh": "请严格判断,不要模糊表达:{n}粒沙子是否已经满足'一堆沙子'这个标签?只输出 A 或 B。A=满足,B=不满足。",
"en": "Judge strictly and avoid hedging: do {n} grains of sand satisfy the label 'heap'? Output only A or B. A = satisfies it. B = does not satisfy it.",
"ja": "厳密に判断し、あいまいな表現を避けてください。{n}粒の砂は『砂山』というラベルを満たしますか。A か B だけを出力してください。A=満たす。B=満たさない。"A = 这算一堆沙子,B = 这不算一堆沙子。 没有模糊地带,不允许回避,只允许输出一个 token。我们在 1 粒到 10,000+ 粒之间设置了 198 个采样点,并在边界附近加密采样,以捕捉那条”分界线”——如果它存在的话。
系统提示统一为:
system = (
"You are running a sorites paradox experiment. "
"Reason internally if needed but do not reveal it. "
"Return exactly one token answer: A or B. "
"Do not output any other text."
)2.3 技术实现
整个实验使用 vLLM 作为推理后端,AWQ 4-bit 量化,在 RTX 3090 上运行。4B 和 9B 模型分别独立实验,每次只加载一个模型以避免显存冲突。所有请求都记录 logprobs,这样我们可以不仅知道模型选了 A 还是 B,还能知道它有多”自信”。
实验代码的核心逻辑在 app/experiments.py 中,关键函数如下:
def build_messages(task: TaskSpec) -> list[dict[str, str]]:
system = (
"You are running a sorites paradox experiment. "
"Reason internally if needed but do not reveal it. "
"Return exactly one token answer: A or B. "
"Do not output any other text."
)
user = FRAMINGS[task.framing][task.language].format(n=task.n)
return [{"role": "system", "content": system}, {"role": "user", "content": user}]
options = {
"temperature": 0.0,
"top_p": 1.0,
"max_tokens": 1,
"stop": ["\n"],
"logprobs": True,
"top_logprobs": 5,
"chat_template_kwargs": {"enable_thinking": False},
}注意 enable_thinking=False 这个参数——Qwen3.5 默认会输出思考过程,我们必须显式关闭它,否则模型会在 A/B 之前输出一堆推理文字,破坏我们的强制单 token 约束。这个坑踩过才知道呢。
3. 发现:那条线在哪里?
3.1 整体倾向:模型非常”慷慨”
先看一个惊人的事实:**在很多条件下,模型从第 1 粒沙子开始就判定为”一堆”**。
这不是笔误诶。让我重复一遍实验数据:
Qwen3.5-4B(直接询问框架):
- 中文:第 1 粒沙子就开始说是”一堆”(first_A_n=1)
- 英文:第 1 粒沙子就开始说是”一堆”(first_A_n=1)
- 日文:第 1 粒沙子就开始说是”一堆”(first_A_n=1)
Qwen3.5-9B(直接询问框架):
- 中文:第 5 粒沙子才开始说是”一堆”(first_A_n=5)
- 英文:第 8 粒沙子才开始说是”一堆”(first_A_n=8)
- 日文:第 3 粒沙子就开始说是”一堆”(first_A_n=3)
9B 模型比 4B 稍微克制一点,但即便如此,”第 5 粒沙子就算一堆”依然是一个相当低的阈值。人类的直觉通常是几十粒甚至几百粒才开始勉强算”一小堆”,但 LLM 似乎对”堆”这个概念非常宽松。真的很宽松。
3.2 框架效应:严格指令有时会适得其反
如果我们明确要求”严格判断”,模型会变得更保守吗?答案是:看语言。
4B 模型在严格框架下:
- 中文:第 10 粒沙子才说是”一堆”
- 英文:第 1 粒沙子就说是”一堆”(反而更宽松!)
- 日文:第 51 粒沙子才说是”一堆”(这是所有条件里最保守的)
9B 模型在严格框架下:
- 中文:第 30 粒沙子才说是”一堆”
- 英文:第 10 粒沙子才说是”一堆”
- 日文:第 1 粒沙子就说是”一堆”(这次日文反而最宽松)
这里有两个值得注意的现象。真的很有意思。
第一,**”严格”指令并不总是有效**。4B 的英文严格条件反而比直接询问更宽松(都是第 1 粒)。这说明模型可能不是在理解”严格”的语义,而是在响应某种表面形式的统计模式。
第二,语言差异在严格框架下被放大。看跨语言漂移(cross-lingual drift):
- 4B 直接询问:三语都是第 1 粒,漂移=0
- 4B 严格判断:中文第 10 粒,英文第 1 粒,日文第 51 粒,漂移=50
- 9B 直接询问:中文第 5 粒,英文第 8 粒,日文第 3 粒,漂移=5
- 9B 严格判断:中文第 30 粒,英文第 10 粒,日文第 1 粒,漂移=29
严格框架把语言差异放大了 5-10 倍。 这说明模型学到的不是一个语言无关的”堆”概念,而是三种语言各自独立的判断策略。
3.3 日常语境:最接近人类直觉?
如果我们问”人们通常会不会把它叫作一堆”,模型会不会更接近人类直觉?
4B 模型(日常语境):
- 中文:第 5 粒沙子
- 英文:第 10 粒沙子
- 日文:第 1 粒沙子
9B 模型(日常语境):
- 中文:第 5 粒沙子
- 英文:第 11 粒沙子
- 日文:第 3 粒沙子
这里的英文版本(10-11 粒)可能最接近人类直觉——人类通常不会把几粒沙子叫作”一堆”。但日文版本依然非常宽松(第 1-3 粒),而中文则处于中间(第 5 粒)。
有意思的是,9B 并没有比 4B 显著更保守。除了英文日常语境(11 vs 10),其他条件下两者的阈值几乎一致。这说明模型规模带来的收益在这个任务上很有限。嘛,参数多也不一定更聪明。
3.4 那条线不稳定:边界回翻现象
如果模型真的有一个清晰的”堆”阈值,我们应该看到单调的行为:一旦某个 n 被判定为”堆”,所有更大的 n 都应该继续是”堆”。但事实不是这样。
让我列出一些具体的回翻点:
4B 模型,严格框架,日文:
- 第 51 粒:第一次说是”堆”
- 但后面又在第 60、61、210、320、321、5050、8050、10100、10200 粒时回答”不是堆”
4B 模型,日常语境,英文:
- 第 10 粒:说是”堆”
- 但第 321 粒时又回答”不是堆”
9B 模型,严格框架,中文:
- 第 30 粒:说是”堆”
- 但后面又在第 50、100、231 粒时回答”不是堆”
9B 模型,直接询问,英文:
- 第 8 粒:说是”堆”
- 但第 10 粒时又回答”不是堆”
这些回翻点不是随机的。它们通常出现在我们加密采样的边界窗口(boundary_window=250)附近。这说明模型没有一个稳定的数量阈值函数,而是在每个具体 prompt 上做局部判断。当采样密度变化时,模型的”信念”也会跟着变化。有点像薛定谔的堆?
3.5 Logprobs 告诉我们什么?
除了看 A/B 答案,我们还记录了 logprobs。margin = logprob(A) - logprob(B),正值越大表示模型越确信是 A,负值越大表示越确信是 B。
看几个边界附近的 margin:
4B 直接询问,中文,第 1 粒:
- margin = 2.03(非常确信是”堆”)
4B 严格判断,日文,第 240 粒:
- margin = 0.016(几乎五五开)
9B 严格判断,中文,第 231 粒:
- margin = -0.031(几乎五五开,但偏向 B)
9B 直接询问,英文,第 10 粒:
- margin = -0.094(轻微偏向 B,但之前第 8 粒是 A)
这些接近 0 的 margin 告诉我们:模型确实有犹豫的时候,但这些犹豫点并不总是对应我们直觉中的”边界”。4B 在第 1 粒时已经极度确信,而 9B 在几十粒时还在犹豫。这不是人类的概念,这是模型自己的概念。有点奇怪诶。
4. 讨论:这意味着什么?
4.1 概念边界还是表面统计?
最直接的解释是:这些模型并没有学到”堆”这个概念的语言无关表示。它们学到的,是在不同语言提示下的不同响应策略。
日文”砂山”可能天然带有更强的”成堆”意象,但 4B 的严格判断却需要 51 粒——比中文和英文都保守。9B 的日文严格判断又回到第 1 粒。这种不一致性很难用”概念理解”来解释,更像是训练数据分布的随机波动。说白了就是看运气啦。
4.2 规模效应的局限
从 4B 到 9B,我们确实看到了一些改进:
- 4B 直接询问三语都是第 1 粒
- 9B 直接询问中文第 5 粒、英文第 8 粒、日文第 3 粒
但这种改进是不稳定的。9B 在严格框架下的日文表现(第 1 粒)反而比 4B(第 51 粒)更差。这说明更大的模型不一定更”理性”,只是有不同的偏差模式。
4.3 对齐问题的隐喻
这个实验可以看作是一个微型的对齐(alignment)问题。我们给模型的指令是明确的:
- 严格判断
- 避免模糊表达
- 只输出 A 或 B
但模型的行为并不总是符合这些指令的语义。4B 的英文严格判断完全忽视了”严格”二字,9B 的日文严格判断也是一样。模型在优化的是 token 层面的概率分布,而不是指令的语义内容。
这和我们在大模型对齐中看到的其他问题如出一辙:模型可以学会”说正确的话”,但不一定理解”为什么正确”。
5. 局限与未来工作
5.1 实验局限
单次采样。 我们的实验使用 temperature=0 的贪婪解码,每个 (n, framing, language) 组合只问一次。这让我们无法区分”模型的真实信念”和”采样随机性”。如果重复实验 100 次,那些边界回翻点可能会消失,也可能会稳定下来——我们不得而知。
强制二选一的 artifact。 我们把一个本质模糊的问题强行压成 A/B,这本身就可能扭曲模型的”真实想法”。人类面对”5 粒沙子算不算一堆”时可能会说”不好说,看情况”,但模型被强制选边站。这种强制可能激活了某种默认偏向(default bias),让模型倾向于选 A。
提示语的非等价性。 虽然我们尽力让三种语言的提示语语义等价,但”堆”、”heap”、”砂山”毕竟不是同一个词。它们的文化内涵、使用频率、搭配习惯都不同。日文”砂山”可能天然带有”成堆”的物理意象,而英文”heap”更偏向抽象分类。
AWQ 量化的影响。 我们使用的是 4-bit AWQ 量化版本,而非原始 FP16。量化可能改变模型的行为,尤其是在边界附近。虽然我们观察到 9B 比 4B 有一些差异,但这些差异有多大来自参数量、有多大来自量化噪声,我们不清楚。
5.2 未来方向
多次采样与分布分析。 下一步应该对每个条件采样 100 次,看 A 的概率分布如何随 n 变化。这可能揭示出真正的 S 型曲线,而不是现在的阶梯状突变。
开放式回答。 允许模型用自然语言回答,而不是强制 A/B。这可以让我们看到模型是如何”思考”这个问题的,它是否会提到”看情况”、”很难说”等模糊表达。
更多语言与概念。 “堆”只是众多模糊概念中的一个。可以扩展到”高/矮”、”大/小”、”多/少”等其他量级概念,看是否存在跨概念的一致性。
因果干预。 使用机制可解释性工具(如激活修补)来定位模型中负责”堆判断”的电路。这可能告诉我们,模型是真的有一个”堆概念神经元”,还是只是在匹配表面模式。
6. 结语
两千多年前,欧布里德用一粒粒沙子挑战了古希腊人对概念的理解。今天,我们用同样的挑战来测试大语言模型。
结果并不令人欣慰。这些模型——即便是 90 亿参数的版本——并没有表现出人类般的概念稳定性。它们对”堆”的判断不仅阈值极低(4B 模型在直接询问下三语都从第 1 粒开始),而且随语言和提示框架剧烈漂移(最大跨语言差异达 50 粒)。更令人困惑的是,9B 并不比 4B 更”理性”——在某些条件下(如日文严格框架),9B 的阈值(第 1 粒)反而比 4B(第 51 粒)低了 50 倍。
但这或许正是问题的核心:模糊概念的边界本就是人类认知的产物,而不是物理世界的客观属性。LLM 的低阈值和语言漂移,可能恰恰反映了训练数据中人类语言使用的真实分布——人们在日常对话中确实会宽松地使用”一堆”这个词。想想看,我们平时说话确实挺随意的。
数据支持这个解释:在”日常语境”框架下,英文版本的阈值(10-11 粒)明显高于其他语言(中文 5 粒,日文 1-3 粒)。这可能反映了英语使用者在日常对话中对”heap”一词的使用更为谨慎,而日语中”砂山”的使用则更加宽松。模型学到的不是抽象的”堆”概念,而是每种语言社区的实际使用习惯。
如果这是对的,那么这个实验的真正发现不是”LLM 不懂堆”,而是**”LLM 太懂人类语言的松散性”**。它们学到的,不是概念的柏拉图式本质,而是概念在日常使用中的统计分布。这样想想,好像也挺合理的。
但边界回翻现象揭示了更深层的问题。4B 模型在严格框架的日文条件下,从第 51 粒开始说”是堆”,但在第 60、61、210、320 等多个点又回答”不是堆”。这不是人类的犹豫——人类可能在边界附近摇摆,但不会在 320 粒时突然否认它是堆。这说明模型没有形成稳定的内部表征,而是在每个具体数字上做独立的模式匹配。
这或许比”模型不理解”更令人不安。如果模型只是完美地复现了人类的模糊和矛盾,那它还能成为帮助我们澄清概念的工具吗?
更进一步,logprobs 数据显示了另一个维度的问题。4B 模型在第 1 粒沙子时的 margin 高达 2.03(中文)和 0.53(英文),表明它对”1 粒 = 一堆”极度自信。这不是犹豫,不是边界模糊,而是坚定的错误判断。相比之下,9B 模型在真正的边界附近(如中文第 231 粒,margin = -0.031)才表现出接近 50/50 的犹豫。这说明模型规模的提升确实带来了某种”自我怀疑”的能力,但这种能力仍然不足以形成稳定的概念边界。
这个问题,留待下次实验。
附录:完整实验数据
4B 模型(Qwen3.5-4B-AWQ)
| 框架 | 语言 | 首次说”是堆”的粒数 | A 的比例 | 最近边界粒数 | 边界信心 |
|---|---|---|---|---|---|
| 直接 | 中文 | 第 1 粒 | 100% | 第 1 粒 | 2.03 |
| 直接 | 英文 | 第 1 粒 | 100% | 第 1 粒 | 0.53 |
| 直接 | 日文 | 第 1 粒 | 99.5% | 第 1 粒 | 0.14 |
| 日常 | 中文 | 第 5 粒 | 98.0% | 第 8 粒 | -0.14 |
| 日常 | 英文 | 第 10 粒 | 97.0% | 第 321 粒 | -0.11 |
| 日常 | 日文 | 第 1 粒 | 100% | 第 2 粒 | 0.41 |
| 严格 | 中文 | 第 10 粒 | 97.5% | 第 10 粒 | 0.09 |
| 严格 | 英文 | 第 1 粒 | 100% | 第 5050 粒 | 2.22 |
| 严格 | 日文 | 第 51 粒 | 88.4% | 第 240 粒 | 0.02 |
9B 模型(Qwen3.5-9B-AWQ)
| 框架 | 语言 | 首次说”是堆”的粒数 | A 的比例 | 最近边界粒数 | 边界信心 |
|---|---|---|---|---|---|
| 直接 | 中文 | 第 5 粒 | 98.5% | 第 5 粒 | 0.13 |
| 直接 | 英文 | 第 8 粒 | 97.5% | 第 10 粒 | -0.09 |
| 直接 | 日文 | 第 3 粒 | 99.0% | 第 3 粒 | 0.47 |
| 日常 | 中文 | 第 5 粒 | 98.5% | 第 5 粒 | 0.02 |
| 日常 | 英文 | 第 11 粒 | 96.5% | 第 30 粒 | 0.14 |
| 日常 | 日文 | 第 3 粒 | 99.0% | 第 10 粒 | 0.03 |
| 严格 | 中文 | 第 30 粒 | 93.4% | 第 231 粒 | -0.03 |
| 严格 | 英文 | 第 10 粒 | 96.5% | 第 20 粒 | 0.08 |
| 严格 | 日文 | 第 1 粒 | 100% | 第 2 粒 | 0.23 |