一粒沙子,一堆沙子

当 LLM 遇到堆悖论……

2026/03/23 06:37:35
字数: 4.8k , 阅读时长: 18 分钟


一粒沙子,一堆沙子:当 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