本文从一个AI代码审查工具(vibe-review)中约束反证(constraint refutation)机制的设计与实践出发,考察当同一个LLM既生成缺陷假说又试图否证该假说时所遭遇的结构性困难。借助Popper的证伪主义、Hegel关于自我意识之辩证法中对独立他者性的要求,以及Wittgenstein关于规则遵循与实践之关系的论述,本文论证:单体agent的自我否证在逻辑形式上模仿了对抗性推理,但在结构上无法实现对抗性推理所要求的认知独立性。形式化反证框架的实际效用不在其逻辑形式,而在其所编码的物质性实践。
Anerkennung (承认:自我意识只有在被一个独立的他者承认时才获得确定性)
1. 经验起点
问题来自一个具体的工程决策。vibe-review是一个基于Claude Code的代码审查skill,它在审查C++和Python代码时面临所有静态分析工具共享的核心困境:误报率。一个未经验证就报出的“可能空指针解引用“会迅速摧毁开发者对工具的信任。传统静态分析工具(Coverity、PVS-Studio)用数据流分析和符号执行来降低误报。vibe-review采用了一种不同的策略:约束反证。
机制如下。对每个非“确定“置信度的发现,审查agent执行一个三步过程。第一步,按缺陷类别枚举反证条件集合,即“若成立则此发现为误报“的充分条件。第二步,对每个条件用工具(Read/Grep/git show)验证其是否成立。第三步,若任一条件成立则抑制该发现;若所有条件不成立则升级置信度;若无法判定则标注“待确认“。
每类缺陷有预置的反证条件清单。空指针解引用的反证条件包括:调用链上游已判空、构造函数保证非空、值域约束排除null。整数溢出的反证条件包括:操作数受业务约束(枚举值、小常量)、类型提升后安全。资源泄漏的反证条件包括:RAII/智能指针管理、析构函数自动释放。一个独立维护的误报知识库固化了已确认的豁免模式。
这个设计的知识谱系是明确的:它受腾讯LLM4PFA工作启发,后者在Linux Kernel等项目上实现了72%-96%的误报过滤率。vibe-review将“先提取约束、再验证可行性“的思路适配到交互式审查场景。
表面上看,这套机制工作得相当好。但在仔细审视其认识论结构后,一个根本性的问题浮现了。
2. Popper:表面的契合
约束反证的逻辑形式可以精确地映射到Popper的证伪主义。在《猜想与反驳》(1963)中,Popper论证:一个理论的科学地位不在于它能被多少证据支持,而在于它原则上可以被经验反驳(falsifizierbar)。理论的可信度通过否证尝试来衡量:一个经历了严格检验仍未被否证的理论,比一个未经检验的理论更值得暂时接受。
vibe-review的反证过程形式化地表达了这一思路:
\begin{algorithm}
\caption{Constraint Refutation}
\begin{algorithmic}
\REQUIRE Finding $P$ = ``code contains defect $X$''
\STATE Enumerate sufficient conditions $\{C_1, \ldots, C_n\}$ for $\neg P$
\FOR{each $C_i$}
\STATE \CALL{ToolVerify}{$C_i$}
\ENDFOR
\IF{$\exists\, C_i = \textbf{true}$}
\STATE $\neg P$ holds $\rightarrow$ \textbf{suppress} finding
\ELSIF{$\forall\, C_i = \textbf{false}$}
\STATE $P$ confidence $\uparrow$ $\rightarrow$ \textbf{report} with evidence
\ELSE
\STATE $C_i$ undecidable $\rightarrow$ \textbf{mark} ``pending''
\ENDIF
\end{algorithmic}
\end{algorithm}
发现P的可信度不由支持它的证据数量决定,而由它存活的否证尝试数量决定。映射如此自然,以至于很难看出问题所在。
问题不在Popper框架本身,而在其隐含前提:执行否证的agent与提出假说的agent之间必须存在某种形式的认知独立性。Popper的科学共同体模型中,提出理论的科学家和设计关键实验的科学家可以是不同的人,他们有不同的理论承诺、不同的偏见、不同的盲点。正是这种多元性使得否证具有认识论力量。当提出假说和执行否证的是同一个agent、同一个上下文窗口、同一次推理过程时,这个前提被违反了。
3. Hegel:承认需要独立的他者
在《精神现象学》(1807)自我意识章节中,Hegel展开了一个关于承认(Anerkennung)的辩证法,其核心命题是:自我意识只有通过一个独立的他者意识的承认才能获得确定性。这不是一个关于社会性的心理学观察,而是一个关于自我认知之结构的存在论论题。
Hegel的论证路径如下。自我意识最初试图通过否定他者来确立自身(主奴辩证法的起点)。但纯粹的否定不产生承认:如果他者被完全消灭或完全臣服,他者就不再是一个能够给予有效承认的独立意识。主人从奴隶那里获得的承认是空洞的,因为奴隶的承认不是出于自由判断而是出于服从。有效的承认要求他者保持其独立性(Selbständigkeit)。
将此应用于约束反证。LLM提出一个发现(“第142行存在空指针解引用”),然后同一个LLM在同一个推理过程中试图否证这个发现。否证扮演了“独立他者“的角色,但这个他者没有独立性。它的全部认知状态(权重、注意力分布、已生成的token序列)与提出发现的agent完全同一。
结果是:否证对发现的“承认“(确认发现经受住了否证检验)在Hegel的意义上是空洞的,因为它来自一个没有独立性的意识。
具体的行为表现印证了这一分析。当LLM对一个发现“确信“时(前序token序列已积累了大量支持证据),后续生成的否证条件倾向于是容易驳回的稻草人。模型列出几个反证条件,快速地逐一排除,然后“升级为较确定“。否证过程走了一个形式上完整但实质上空洞的流程。反向的偏差同样存在。当LLM对一个发现本身就不确定时,否证条件倾向于被过度热情地接受。一个含糊的“可能由RAII管理“就足以抑制一个本该报出的资源泄漏。
两种偏差的方向相反,但根源相同:否证的结论被先验地编码在了生成否证之前的上下文中。自回归模型的每个token都以所有先前token为条件。当模型已经生成了一个高置信度的发现时,否证token在一个偏向于确认该发现的条件分布中被采样。当模型已经生成了一个低置信度的发现时,否证token在一个偏向于撤回该发现的条件分布中被采样。这不是需要通过更好的prompt engineering来修复的偶然偏差,而是自回归生成的结构性特征。在Hegel的术语中:单体意识无法通过内部运动获得它只能通过与独立他者的遭遇才能获得的东西。
4. Wittgenstein:规则与实践
这个分析引出一个更激进的命题:约束反证框架的形式逻辑结构是附带现象(epiphenomenal)。真正降低误报的机制是别的东西。
Wittgenstein在《哲学研究》(1953)§§185-242的规则遵循论述中,摧毁了一个根深蒂固的哲学图像:遵循规则在于心灵中把握了规则的内容,然后将这个内容应用到具体情形。Wittgenstein论证:没有任何心灵状态能够决定规则在一个新情形中的正确应用。规则的意义不在于某种内在的理解,而在于实践中一致的应用模式。“遵循规则是一种实践”(Das Befolgen der Regel ist eine Praxis, §202)。
将此应用于约束反证。框架规定了一个形式化的三步流程:枚举条件、工具验证、判定。这个逻辑结构看起来是推理的骨架。但仔细检查会发现:真正产生认知效果的不是这个逻辑结构,而是嵌入在其中的具体工具调用指令。
“报空指针前先grep调用者“是一个具体的物质性实践:它导致模型执行一个Grep工具调用,返回调用链上游的实际代码,模型基于这段代码做出判断。这个实践无论是否被包裹在“反证“的逻辑框架中,都会产生相同的认知效果。
一个思想实验可以使这一点更清晰。将约束反证完全重写,去掉所有关于“反证“、“否证”、“falsification“的认识论术语,替换为一个纯粹的工具调用checklist:
\begin{algorithm}
\caption{Pre-report Checklist}
\begin{algorithmic}
\STATE \textbf{before} null-deref $\rightarrow$ \CALL{Grep}{all callers}
\STATE \textbf{before} overflow $\rightarrow$ \CALL{Read}{operand range}
\STATE \textbf{before} leak $\rightarrow$ \CALL{Grep}{RAII / smart pointer}
\STATE \textbf{before} race $\rightarrow$ \CALL{Grep}{all references}
\end{algorithmic}
\end{algorithm}
这个checklist与当前的约束反证框架在功能上等价。它们导致相同的工具调用、产生相同的证据、支持相同的判断。区别仅在于包裹物质实践的叙事框架:一个声称自己在做形式化推理,另一个诚实地承认自己在执行checklist。
在Wittgenstein的分析框架下,这不是一个意外发现。规则(约束反证的逻辑结构)不具有超越实践(工具调用)的独立因果力。认为逻辑框架“指导“了工具调用,就像认为心灵中对规则的把握“指导“了行为一样,是Wittgenstein所诊断的哲学幻觉。是实践在做工作,不是关于实践的理论。
5. 结构性不对称
约束反证还有一个结构性缺陷,它不依赖于前述的单体agent问题。
反证只作用于发现,不作用于未发现。它是一个单向过滤器:减少假阳性,对假阴性完全无能为力。没有一个对称的步骤规定:“对于你未报出的每类缺陷,证伪’此处没有该缺陷’这个命题。“vibe-review的必检规则(要求对diff中每个格式化调用、每个指针操作、每个数组访问逐条检查)部分地补偿了这一缺陷,但那是正向枚举,不是反证。两者的认识论地位不同。
这个不对称性恰好映射到Popper证伪主义本身的一个已被广泛讨论的局限。Popper提供了一个拒绝假说的方法(证伪),但没有提供一个生成假说的方法。Kuhn在《科学革命的结构》(1962)中指出:Popper的框架假设了候选理论已经被提出,然后对其执行否证检验;但理论从何而来,Popper的框架保持沉默。
在代码审查的语境中:约束反证假设了候选缺陷已经被识别,然后对其执行否证检验;但LLM是否识别了所有候选缺陷,这个问题在反证框架之外。一个完备的形式化方法需要对两个方向都施加约束。当前设计对“少报“这个方向是结构性地开放的。
6. 诚实的自我理解
上述分析并不导向“约束反证应该被删除“这个结论。它导向的是一个关于其认识论地位的更诚实的理解。
约束反证的实际价值有三个层面。其一,它迫使LLM在报出发现前执行一组具体的工具调用。这些工具调用引入了模型自身推理之外的外部信息(代码库中的实际代码),这是真正降低误报的机制。其二,它将资深reviewer头脑中隐性的验证步骤编码为显式的流程。一个资深C++审查者在看到裸指针解引用时会自动检查调用链上游是否有判空;约束反证将这个隐性习惯显式化,使LLM也能系统地执行。其三,生成的反证文本(“已检查调用链上游3处调用点,均未检查返回值”)给人类reviewer提供了可审核的证据链。
这三个价值都是真实的。但注意:它们都不依赖于“反证“的逻辑形式。第一个是工具调用的价值。第二个是checklist的价值。第三个是审计追踪的价值。形式化反证框架将这三个独立的价值包裹在一个看起来像推理的叙事中,但叙事不是推理的原因,是推理的副产品。
如果要让反证获得它声称拥有的认识论力量,需要结构性的改变而非prompt层面的优化。一条可能的路径是dual-agent架构:一个agent执行审查并报出发现,另一个独立的agent(不同的prompt、不同的上下文、最好是不同的模型实例)对这些发现执行否证。两个agent之间的信息隔离制造了Hegel所要求的独立他者性。否证agent不知道审查agent的推理过程,只知道其结论和支持证据。它必须独立地评估这些证据是否充分。这不是技术上的空想:vibe-review的batch模式已经将多个PR的审查拆分到独立的Claude Code子进程中并行执行,将同一机制应用于“审查agent vs. 否证agent“的拆分在工程上是直接的。缺少的不是技术能力,而是对问题之认识论结构的认识。
一个知道自己的否证是独白的系统,比一个误以为自己在进行对话的系统更可靠。前者诚实地依赖其物质实践(工具调用和checklist)的有效性;后者在形式化推理的幻觉中放松了对物质实践的要求。诚实的自我理解不削弱系统的能力,它精确地定位了能力的来源。
参考文献
- Hegel, G. W. F. (1807). Phänomenologie des Geistes. Bamberg und Wuerzburg: Goebhardt.
- Kuhn, T. S. (1962). The Structure of Scientific Revolutions. Chicago: University of Chicago Press.
- Popper, K. R. (1963). Conjectures and Refutations: The Growth of Scientific Knowledge. London: Routledge.
- Wang, H. et al. (2025). LLM4PFA: LLM-Powered Path Feasibility Analysis for Eliminating False Alarms. arXiv preprint arXiv:2506.10322.
- Wittgenstein, L. (1953). Philosophische Untersuchungen. Oxford: Blackwell.