110 token/s、19MB证明、17秒CPU验真:Anthropic开源FlashProve,把模型调包变成一道数学题

110 token/s、19MB证明、17秒CPU验真:Anthropic开源FlashProve,把模型调包变成一道数学题

Part One:你付的是旗舰的钱,跑的是不是旗舰的模型?

2026年11月2日,Anthropic 前沿红队发了一篇研究博客,标题很朴素:《大语言模型可证明推理的进展》。11月4日,配套代码正式开源,名字叫 FlashProve。

它要解决的问题,一句话就能说完:

你调用一个模型,怎么证明返回给你的这段文字,真的是你付钱的那个模型生成的?

这个问题在今天已经不再是理论问题。三种场景天天在发生:

第一种,模型被调包。 第三方路由平台转发请求,为了省成本把用户指定的高性能模型换成一个便宜的小模型。回答质量可能还不错,用户只会觉得"今天怎么有点笨",但拿不出任何证据。

第二种,输出被篡改。 推理服务器被攻破,攻击者在正常的 token 流里混入恶意内容(比如让模型返回一段引导用户执行恶意代码的回答),藏在真实回答中间。

第三种,评估对象不一致。 独立评测机构在模型发布前后做安全评估,但如果无法确认被测的就是实际部署的那个模型,整份评估报告的可信度就是零。

Anthropic 在博客里写了一句让人后背发凉的话:

随着模型越来越强、能自我部署,一个更高级的模型完全可能顶替获批的弱模型上岗,再装成弱模型的样子,躲开本该施加在它身上的监控。

这就是"可证明推理"(Provable Inference,PI)要解决的核心:让一个算力有限、完全不知道权重的用户,能验证一段输出确实来自他指定的那个模型。

传统办法只有一条:拿到权重自己重跑一遍。但前沿模型的权重是各家命根子,而且 4000 亿参数的模型,普通人和评测机构都养不起那个机房。

所以答案是密码学。具体来说,是 zkSNARK(零知识简洁非交互式知识论证)——证明方用一个很短的"证书",向验证方证明某个计算被正确执行了;证书是零知识的(不泄露权重、中间值、哪些专家被激活),也是简洁的(验证开销远低于自己跑一遍)。

Anthropic 把这件事做到了什么程度?看三个数字:

  • 单张 H100,证明生成 110 token/s
  • 每 1024 token 请求,证明文件约 19MB(精确值 18.78MB)
  • 24 线程 CPU,验一份证明 17 秒,不需要 GPU

对照一下历史,就知道这三个数字有多离谱。此前唯一公开过对同一个模型(Llama 4 Maverick)做证明的开放系统是 VerInf,它的成绩是 0.02 token/s——1000 token 要跑 14.3 小时,证明文件 93.6GB,验证要将近一天。

110 除以 0.02,是 5500 倍。

Part Two:三步验真——按手印、开证明、验真伪

FlashProve 的流程拆得非常干净,只有两方(模型服务方是证明者,用户是验证者)和两个阶段。

┌─────────────────────────────────────────────────────────────────────┐
│                    OFFLINE PHASE  (once per model)                   │
│                                                                      │
│   Model weights (400B MoE, 4-bit, ~232GB)                            │
│            │                                                         │
│            ▼                                                         │
│   ┌────────────────────────────┐                                     │
│   │  Hiding commitment         │  ← 39 min on 1× H100                │
│   │  (short fingerprint,       │    good for ~16M requests           │
│   │   weights stay hidden)     │    client downloads ~6.5MB total    │
│   └────────────┬───────────────┘                                     │
└────────────────┼─────────────────────────────────────────────────────┘
                 │  published commitment
                 ▼
┌─────────────────────────────────────────────────────────────────────┐
│                    ONLINE PHASE  (per request)                       │
│                                                                      │
│   prompt (1024-token window) + output tokens                         │
│            │                                                         │
│            ▼                                                         │
│   ┌────────────────────────────┐    ┌──────────────────────────┐     │
│   │  Prover (1× H100)          │    │  Proof file ~18.78 MB    │     │
│   │  · record computation      │───▶│  · hides weights         │     │
│   │    trace (matmul, round,   │    │  · hides intermediate    │     │
│   │    nonlinearity)           │    │    values                │     │
│   │  · prove trace used        │    │  · hides which experts   │     │
│   │    committed weights       │    │    actually ran          │     │
│   │  · batch up to 64 requests │    └────────────┬─────────────┘     │
│   └────────────────────────────┘                 │                   │
└──────────────────────────────────────────────────┼───────────────────┘
                                                   ▼
┌─────────────────────────────────────────────────────────────────────┐
│                    VERIFIER  (user side)                             │
│                                                                      │
│   inputs: commitment + prompt + reply + proof                        │
│            │                                                         │
│            ▼                                                         │
│   ┌────────────────────────────┐                                     │
│   │  cp_verify (C++, fast)     │  17 s on 24 threads                 │
│   │    → accept / reject       │  21 s on 1 thread                   │
│   │                            │  no GPU, no weights                 │
│   │  lean-verify (Lean, slow)  │  provably accepts only what the     │
│   │    → formally guaranteed   │  soundness theorem accepts          │
│   └────────────────────────────┘                                     │
└─────────────────────────────────────────────────────────────────────┘

第一步,离线"按手印"。 模型上线前,服务方在单张 H100 上花约 39 分钟,对模型权重生成一个密码学承诺(commitment)——可以理解成权重的数字指纹。这串指纹能钉死一组确切的权重(改一个参数就对不上),但外界光看指纹绝无可能反推出权重。这个承诺大约对 1600 万次请求有效,之后要重新生成。客户端首次下载承诺、离线证明和一个链接证明,共约 6.5MB。

第二步,在线"开证明"。 每处理一次请求,证明方记录模型推理的计算轨迹(矩阵乘法、取整、非线性运算),然后生成一份证明,说明这些运算用的确实是承诺里那组权重,并且按指定规则得到了这串输出。一批最多处理 64 个请求,各请求的部分证明步骤在 GPU 上并发执行,整批共享用于核验承诺的查询数据。

第三步,客户端"验真伪"。 用户拿着承诺、输入、输出和证明文件,在普通 CPU 上跑验证器,17 秒拿到判决。全程不要权重,不要 GPU。

代码上,这个流程可以写成非常直白的三段:

import hashlib
import secrets


def offline_commit(weights_bytes: bytes, nonce: bytes | None = None) -> dict:
    """
    Offline phase, simplified: build a hiding commitment to the weights.

    Real FlashProve uses a zkSNARK-friendly polynomial commitment so that
    later proofs can *open* specific entries without revealing the rest.
    Here we only model the hiding + binding properties.
    """
    if nonce is None:
        nonce = secrets.token_bytes(32)

    # A hiding commitment = hash(nonce || weights).
    # Without the nonce you cannot brute-force weights from the digest,
    # and you cannot find two (nonce, weights) pairs with the same digest.
    digest = hashlib.blake2b(nonce + weights_bytes, digest_size=32).hexdigest()

    return {
        "commitment": digest,
        "nonce_kept_by_prover": True,   # verifier never sees this
        "weights_hidden": True,
        "size_bytes": 32,
    }


def online_prove(commitment: str, prompt: str, output_tokens: list[int],
                 computation_trace: dict) -> dict:
    """
    Online phase, simplified: assert that the committed model, run on this
    prompt, produces exactly these tokens.

    A real proof is ~18.78MB of zkSNARK data; here we only model what the
    proof *claims* and what it *hides*.
    """
    claims = {
        "statement": "committed_model(prompt) == output_tokens",
        "commitment": commitment,
        "checked_tokens": len(output_tokens),
    }
    hides = {
        "weights": True,
        "intermediate_values": True,
        "expert_selection_per_layer": True,
        "architecture": False,          # explicitly NOT hidden
    }
    return {
        "claims": claims,
        "hides": hides,
        "proof_size_mb": 18.78,
        "prover_gpu": "1x H100",
        "prover_seconds_per_batch_of_24": 223,
    }


def verify(commitment: str, prompt: str, output_tokens: list[int],
           proof: dict) -> dict:
    """
    Verifier side: cheap, no GPU, no weights.
    """
    ok = (
        proof["claims"]["commitment"] == commitment
        and proof["claims"]["statement"] == "committed_model(prompt) == output_tokens"
    )
    return {
        "accepted": ok,
        "verify_seconds_24_threads": 17,
        "verify_seconds_1_thread": 21,
        "gpu_required": False,
        "weights_required": False,
    }


if __name__ == "__main__":
    fake_weights = b"\x00" * 1024  # stand-in for ~232GB of quantized weights
    c = offline_commit(fake_weights)
    print(f"commitment: {c['commitment'][:16]}...  ({c['size_bytes']} bytes)")

    p = online_prove(c["commitment"], "explain zkSNARKs", [1, 2, 3], {})
    print(f"proof size: {p['proof_size_mb']} MB, hides weights: {p['hides']['weights']}")

    v = verify(c["commitment"], "explain zkSNARKs", [1, 2, 3], p)
    print(f"accepted: {v['accepted']}, GPU needed: {v['gpu_required']}")

这段代码故意写得很浅,但它把整个系统的信息流画清楚了:承诺是公开的、证明是随请求下发的、验证是完全离线的。 三者之间唯一的联系就是那个 32 字节的承诺摘要。也正因为如此,一个攻击者即使完全控制了推理服务器,也没法为错误的权重伪造出有效证明——除非他能攻破 BLAKE2。

Part Three:110 token/s 是怎么来的——三招工程优化

密码学协议本身是公开的、教科书级的。真正难的是把它压到单张 H100 上能跑。Anthropic 的工程优化有三招,每一招都值得单独讲。

第一招:让证明工作量跟着"实际激活的专家"走。

Llama 4 Maverick 是 MoE 架构,每个 MoE 层从 128 个路由专家里选 1 个运行,另有 1 个共享专家。所以每个 token 只激活 4000 亿参数中的约 170 亿。

如果证明要覆盖全部 4000 亿参数,那根本跑不动。FlashProve 的做法是:计算轨迹里只记录实际运行的那些专家,证明工作量正比于激活参数(170 亿)而不是全部参数(4000 亿),同时还要额外检查"路由器有没有选对专家"。

这里有个精妙之处:证明必须隐藏"到底选了哪些专家"。因为专家选择本身就是模型的商业机密——泄露了就等于泄露了路由策略。所以它要在"只证明激活部分"和"不泄露激活的是哪部分"之间同时成立。

# Why MoE sparsity is the single biggest lever on proving cost
def moe_proving_cost(total_params_b=400, active_per_token_b=17,
                     n_experts_per_layer=128, layers=48):
    """
    Prover work is proportional to the experts that actually ran,
    not to the full parameter count.
    """
    dense_relative = total_params_b / active_per_token_b
    # Per layer: 1 of 128 routed experts + 1 shared expert
    experts_active_per_layer = 2
    sparsity_ratio = experts_active_per_layer / (n_experts_per_layer + 1)

    return {
        "total params (B)": total_params_b,
        "active per token (B)": active_per_token_b,
        "dense-equivalent slowdown": f"{dense_relative:.1f}x",
        "experts active per layer": f"{experts_active_per_layer} of {n_experts_per_layer + 1}",
        "sparsity ratio": f"{sparsity_ratio:.1%}",
        "layers": layers,
        "consequence": "proving cost tracks 17B, not 400B",
        "extra burden": "must also prove router picked the right expert, "
                        "while hiding which expert was picked",
    }


for k, v in moe_proving_cost().items():
    print(f"  {k:28s} {v}")

这一招的杠杆率是 23.5 倍。 换句话说,如果 FlashProve 不是专门为 MoE 设计,它的吞吐会掉到个位数 token/s。

第二招:把模型切成段,用主机内存养 GPU。

4000 亿参数的 4 比特量化版本约 232GB,单张 H100 只有 80GB 显存,装不下。

FlashProve 的做法是:权重放在普通主机内存里,逐段加载进 GPU,一段一段地证明。 最终的效果是——一张 80GB 显卡,配约 290GB 主机内存,就能跑起来。

这个数字很关键,因为它意味着这套系统不需要什么特殊硬件:一台常规的 8 卡机里抽一张卡出来,加满内存,就能当证明服务器。它不是"只有 Anthropic 才能跑"的东西。

第三招:事后批处理,一次开承诺服务一整批。

这一招直接决定了吞吐从 17.6 涨到 110。

系统不是"来一个请求就证明一个",而是先把整段文本读完(像 prefill 那样并行处理),再一批一起证明,而且每批只开一次权重承诺,而不是每个请求开一次。

看数据:单独处理一个请求,生成一份证明约 58 秒;一批处理 24 个请求,总耗时约 223 秒。 按请求窗口里的全部 token 统计,吞吐从 17.6 token/s 提到 110 token/s。

# Batching: the single change that took throughput from 17.6 to 110 tok/s
def batching_throughput(window_tokens=1024):
    single = {
        "requests": 1,
        "total_seconds": 58,
        "tokens": window_tokens,
    }
    batched = {
        "requests": 24,
        "total_seconds": 223,
        "tokens": 24 * window_tokens,
    }

    single_tps = single["tokens"] / single["total_seconds"]
    batched_tps = batched["tokens"] / batched["total_seconds"]

    return {
        "single request (s)": single["total_seconds"],
        "single throughput (tok/s)": f"{single_tps:.1f}",
        "batch of 24 (s)": batched["total_seconds"],
        "batched throughput (tok/s)": f"{batched_tps:.1f}",
        "speedup": f"{batched_tps / single_tps:.1f}x",
        "per-request amortized (s)": f"{batched['total_seconds'] / 24:.1f}",
    }


for k, v in batching_throughput().items():
    print(f"  {k:28s} {v}")

批处理把"每请求 58 秒"压成了"每请求 9.3 秒",靠的不是更快的算法,而是把固定的开销(开承诺、准备查询数据)摊到 24 个请求上。这和 GPU 推理的 batch 是同一个道理,只不过这里的"固定开销"是密码学承诺。

Part Four:一个更值得看的对照——从 0.001 到 110

单个数字没有意义,把它放进 zkML 的演进史里才有。

# The zkML throughput curve, in tokens per second
def zkml_history():
    rows = [
        ("2017  SafetyNets",        "MNIST 2-conv CNN",       None,  "verified, not throughput"),
        ("2021  zkCNN",             "VGG-16 (15M)",           None,  "88.3 s per proof"),
        ("2024  ZKML GPT-2",        "117M",                   0.006, "159 s per token"),
        ("2024  Modulus GPT-2 XL",  "1.5B",                   0.0,   "over 90 hours"),
        ("2023  EZKL",              "1M GPT-style",           0.001, "966 s per token"),
        ("2024  zkLLM",             "LLaMA-2-13B",            2.5,   "batch, 2048-token input"),
        ("2025  zkGPT",             "GPT-2",                  0.05,  "21.8 s per token"),
        ("2025  zkPyTorch",         "Llama-3 8B",             0.007, "150 s per token, 1 CPU core"),
        ("2025  ZKTorch",           "GPT-J 6B",               0.001, "~20 min"),
        ("2026  VerInf",            "Llama 4 Maverick 400B",  0.02,  "14.3 h for 1k tokens, 93.6GB proof"),
        ("2026  DeepProve",         "Gemma 3",                1.4,   "2.9 tok/s on GPT-2, 31 distributed"),
        ("2026  SASH prover",       "Llama 3.1 8B",           1.25,  "single H100"),
        ("2026  FlashProve",        "Llama 4 Maverick 400B",  110.0, "1x H100, 19MB proof, 17s verify"),
    ]

    print(f"{'System':<26}{'Model':<28}{'tok/s':<10}{'Note'}")
    print("-" * 104)
    for name, model, tps, note in rows:
        tps_s = f"{tps}" if tps is not None else "n/a"
        print(f"{name:<26}{model:<28}{tps_s:<10}{note}")


zkml_history()

print("\nFlashProve vs VerInf on the SAME model (Llama 4 Maverick):")
print(f"  throughput: 110 / 0.02 = {110 / 0.02:.0f}x")
print(f"  proof size: 93.6 GB / 0.019 GB = {93.6 / 0.019:.0f}x smaller")
print(f"  verify time: ~1 day -> 17 s")

这张表里最值得注意的不是 110 这个数,而是两条曲线:

第一条,模型规模在涨,但证明吞吐也在涨。 2024 年 zkLLM 证明 130 亿参数的模型只有 2.5 token/s,2026 年 FlashProve 证明 4000 亿参数(激活 170 亿)的模型有 110 token/s。参数涨了 30 倍,速度涨了 44 倍。 这在密码学工程里是很罕见的——通常是规模一大,开销就爆掉。

第二条,同一模型上的横向对比才是硬指标。 VerInf 和 FlashProve 证的是同一个 Llama 4 Maverick:0.02 对 110,是 5500 倍;证明文件 93.6GB 对 19MB,小了 4900 倍;验证时间从"将近一天"到 17 秒。

Anthropic 自己在博客里下的判断很克制,但信息量很大:

这些数字说明可证明推理在过去几年进步极其陡峭。它们应该更新我们对"零知识能证明什么"的先验。

这句话的潜台词是:过去大家认为"零知识证明大模型"在工程上不现实,现在这个判断需要修正了。

Part Five:代价是什么——70 到 95 倍 GPU 时间

任何技术都必须算账。FlashProve 的账很清楚:

生成证明所需的 GPU 时间,约为普通 vLLM 推理的 70 到 95 倍。

具体测法:用同一个模型的 FP8 版本在 8 张 H100 上跑 vLLM,按每张卡算,证明一批 24 个请求耗时约为 vLLM 处理同一批请求的 72 倍(多次运行在 66 到 77 之间);如果让 vLLM 跑到最高负载,这个倍数升到约 94 倍。

# What 70-95x GPU time means in practice
def proving_overhead(overhead_low=70, overhead_high=95,
                     h100_hourly_usd=2.0, tokens=1_000_000):
    """
    Translate the GPU-time multiplier into money per million tokens.
    """
    # Assume vLLM serves ~2000 tok/s per H100 for a 17B-active MoE at high load
    vllm_tps = 2000
    base_gpu_hours = tokens / vllm_tps / 3600

    rows = []
    for label, mult in [("proving, low end", overhead_low),
                        ("proving, high end", overhead_high)]:
        gpu_hours = base_gpu_hours * mult
        cost = gpu_hours * h100_hourly_usd
        rows.append((label, f"{gpu_hours:.1f}", f"${cost:.2f}"))

    print(f"{'Case':<22}{'GPU-hours / 1M tok':<22}{'Cost @ $2/h'}")
    print("-" * 62)
    for label, gh, cost in rows:
        print(f"{label:<22}{gh:<22}{cost}")

    print(f"\nBaseline (vLLM only): {base_gpu_hours:.2f} GPU-hours, "
          f"${base_gpu_hours * h100_hourly_usd:.2f}")
    print("\nInterpretation: proving is not free, but it is a *bounded* multiple —")
    print("two orders of magnitude, not six. That is what makes it deployable at all.")


proving_overhead()

这个代价意味着什么?

它意味着 FlashProve 不是给每一次 API 调用都附证明的。110 token/s 的证明速度,对应的是普通推理 2000 token/s 量级——如果全量开启,整个服务的成本会翻 70 倍以上,没人付得起。

所以现实中的用法一定是抽样:只对需要审计的那部分流量出证明。Anthropic 在博客里把这个设计说得很明确——他们选的是事后证明(post-hoc proving),而不是在线内联证明(in-line proving):

内联方案追求极快,可能为了效率牺牲安全性;事后方案允许更慢,因而不必做这种取舍。但事后证明也有局限:重算带来的复杂度、拿到保证的延迟,以及内在的非确定性。

这个取舍很值得记:“事后证明"意味着你拿到一段输出时,保证是延迟到达的。 对实时对话这不重要,对合规审计完全够用。但如果你的场景要求"每一秒的流量都被实时证明”,那这套方案就不合适。

另外几个必须说清的硬约束:

  • 上下文只有 1024 token。 这跟前沿模型动辄几十万到上百万的上下文窗口差了三个数量级。长上下文、大规模 Agent 工作流、复杂多轮交互,目前都没解决。
  • 只证明整数模型 + 贪心解码。 系统证明的是权重的精确整数版本,且断言"每个被检查的 token 是该模型的贪心选择"。浮点实现或采样解码,可能在某个位置偏离,不再与所证计算完全一致。
  • 一次请求只查一个 token。 测试中每个 1024 token 的请求窗口,每份证明只检查紧随提示词之后的那一个输出 token。研究团队也测了"检查回复里每个 token"的情况,证明生成耗时没有可测差异,但只统计被检查的回复 token 时吞吐约 39.1 token/s。
# Cost model for sampling: full proof coverage is not the intended use
def sampling_policy(total_requests_per_day=10_000_000,
                    full_proof_cost_multiple=70,
                    audit_fraction=0.001):
    """
    Prove a sample of traffic, not all of it.
    """
    audited = int(total_requests_per_day * audit_fraction)
    # Cost is only paid on audited requests
    effective_multiple = 1 + (full_proof_cost_multiple - 1) * audit_fraction

    return {
        "daily requests": f"{total_requests_per_day:,}",
        "audited requests": f"{audited:,}",
        "audit fraction": f"{audit_fraction:.2%}",
        "effective cost multiple": f"{effective_multiple:.3f}x",
        "detection logic": "random audit makes substitution a losing bet: "
                           "one caught sample voids the provider's whole claim",
    }


for k, v in sampling_policy().items():
    print(f"  {k:26s} {v}")

这个抽样模型解释了为什么 70 倍开销是可以接受的:不是因为它便宜,而是因为你不需要每次都付。 就像审计不是查每一张发票,而是随机抽查——只要抽样是随机的、且被抓到一次的代价远大于作弊收益,威慑就成立了。

Part Six:Lean 的赌注——当人类审不完 400MB 证明

这是我认为整件事里最有意思的一层。

FlashProve 的代码仓库,语言构成是这样的:

语言占比
Lean 4(形式化证明)95.2%(约 398MB)
C++1.4%
Python1.3%
CUDA0.9%

一个模型推理仓库里,95% 的代码是数学证明。 配套还有一份 114 页的协议规范论文和一份 23 页的技术报告。

为什么?Anthropic 自己解释了:

密码学代码是出了名的脆弱、容易出错。你今天发布的代码,用户凭什么信任?

密码学代码的特殊性在于:一个符号写反、一处随机数掩码漏掉,整座安全大厦瞬间坍塌。 而 FlashProve 的核心逻辑是 Claude 写的——Anthropic 自己承认:“Claude 擅长优化,但常常做出难以评估的决策,尤其是在大型复杂系统里。”

人类专家不可能靠肉眼逐行审完几亿行中间推导。于是他们换了个思路:不去审中间过程,只审最顶层的六条安全定义,让 Lean 的编译器内核去逐行核对中间的一切。

三条顶层性质(在随机预言机模型下陈述):

  1. 完备性(completeness):诚实的证明方生成的证明一定会被接受。
  2. 可靠性(soundness):任何伪造证明都会被拒绝,除非以可忽略的概率。
  3. 零知识(zero-knowledge):证明不泄露关于权重的任何信息,超出验证者从回答本身能推断的部分。

只要这三条顶层定理"说的是对的",中间那近 400MB 的繁琐归约哪怕人类一眼不看,Lean 的内核已经替人类把住了关。 这是"信任最小化"的一个非常漂亮的实践:把信任从"人的审查能力"转移到"编译器内核的正确性"。

# The three top-level properties, stated as assertions a checker could test
def check_properties():
    """
    Informal restatement of what Lean proves. Not a formal proof — just
    the shape of the three claims.
    """
    properties = {
        "completeness": {
            "claim": "honest prover's proof is accepted",
            "failure mode if violated": "honest providers get wrongly rejected",
            "who depends on it": "the provider",
            "lean statement": "forall stmt, is_true stmt -> verify (prove stmt) = accept",
        },
        "soundness": {
            "claim": "no valid proof exists for a false statement",
            "failure mode if violated": "a cheater can substitute a model and pass",
            "who depends on it": "the verifier",
            "lean statement": "forall stmt proof, verify proof = accept -> is_true stmt",
        },
        "zero_knowledge": {
            "claim": "proof leaks nothing about weights beyond the reply",
            "failure mode if violated": "provider's IP leaks through proofs",
            "who depends on it": "the provider",
            "lean statement": "exists simulator s.t. proof ~ simulator(commitment, stmt)",
        },
    }

    for name, d in properties.items():
        print(f"\n[{name}]")
        for k, v in d.items():
            print(f"  {k:26s}: {v}")

    print("\nKey asymmetry:")
    print("  soundness  depends ONLY on the verifier  -> provide a Lean verifier")
    print("  zero-knowledge depends ONLY on the prover -> no Lean prover is practical")
    print("  completeness depends on BOTH              -> test prover against Lean verifier")


check_properties()

但这里必须说清两个信任缺口,Anthropic 自己也列了:

缺口一:形式化陈述本身要人工审计。 Lean 证明的是"这些数学陈述成立",但不保证"这些陈述就是你想表达的意思"。这个只能人来做(虽然比审证明轻松得多)。他们提供了一个交互式可视化工具 STATEMENTS.html 来帮忙。

缺口二:可执行代码要审计,确认它和形式化协议一致。 论文、快速 C++ 代码都是从 Lean 协议派生出来的,但三者是否互相匹配,官方不做保证。

所以在验证器上,他们给了两个:

  • cp_verify(C++,快):日常用,17 秒,不带形式化保证。
  • lean-verify(Lean,慢):Lean 证明它只接受"可靠性定理所允许的东西"。

这个分工的逻辑值得记住:可靠性只取决于验证器。 因为"有证明"这件事的全部价值就在于——只要你信任验证器,你就可以完全不信证明方。所以验证器必须有形式化保证;而证明器不必,因为它本来就是被怀疑的对象。

Part Seven:它证明的是来源,不是正确性

这是最容易被误读的一点,必须单独拎出来。

FlashProve 证明的是"这段输出确实来自那组权重",而不是"这段输出是对的"。

如果承诺的那个模型本身就产生了幻觉、就是给了错误答案,证明照样能通过——因为证明只断言"计算被正确执行了",不断言"结果在语义上正确"。

这个区分看起来是抠字眼,实际上决定了它能用在哪、不能用在哪:

# What a proof does and does not establish
def proof_scope():
    establishes = [
        "the reply came from the committed weights",
        "the committed weights were run on this exact prompt",
        "the checked token is that model's greedy choice",
        "no token in the stream was tampered with after generation",
    ]
    does_not_establish = [
        "the reply is factually correct",
        "the reply is safe",
        "the model is the one the provider advertised by name "
        "(only that it matches the published commitment)",
        "the architecture is hidden (it is NOT hidden)",
        "the hardware is not simultaneously training something else",
        "side channels (e.g. proving time) leak nothing",
    ]

    print("PROVES:")
    for i, s in enumerate(establishes, 1):
        print(f"  {i}. {s}")
    print("\nDOES NOT PROVE:")
    for i, s in enumerate(does_not_establish, 1):
        print(f"  {i}. {s}")


proof_scope()

注意第 3 条和第 6 条,这是最容易被忽略的两个边界。

第 3 条:证明绑定的是"承诺",不是"模型名字"。所以一个服务商完全可以在官网写"我们提供 Claude",然后承诺的是另一个模型的权重——证明会通过,因为它只证明"和承诺一致"。 要让它有意义,前提是承诺本身是公开的、可追溯的、且和品牌声明绑定的。这是一个治理问题,不是密码学问题。

第 6 条:Anthropic 明确把侧信道攻击列为"本次发布范围之外"。也就是说,通过测量证明生成耗时的差异,理论上可能推断出权重信息。这不是致命的(要拿到有意义的信号需要极强的测量能力),但它意味着"零知识"这个保证有明确的适用边界:证明文件本身不泄露,但生成过程的时间特征没被约束。

Part Eight:判断与边界

第一,这件事真正的意义不是"能验证模型",而是把"信任"从组织问题变成了数学问题。 在此之前,你信任服务商靠的是合同、声誉、审计报告——全是社会机制。现在多了一条纯技术路径:一段输出加一份 19MB 的证明,17 秒 CPU 就能判真假。这条路径不依赖任何中心化机构,也不要求服务商交出半行权重。 对模型 API 这个高度不透明的供应链来说,这是一个结构性的变化。

第二,5500 倍这个数字,真正的含义是"可行性门槛被跨过了"。 0.02 token/s 意味着证明一个 1000 token 的回答要 14 小时——这在任何场景下都不可用,只能当论文。110 token/s 意味着证明时间和生成时间进入了同一个数量级(虽然还是慢 70 到 95 倍),于是"抽样证明"这个工程折中才成立。技术从"不可用"到"可用但贵",是一道远比"贵"到"便宜"更重要的坎。

第三,MoE 稀疏性是这次突破的关键杠杆,而它同时是一个局限。 23.5 倍的杠杆来自"只证激活的专家"。但这也意味着:如果模型是稠密的(比如很多 30B、70B 的 dense 模型),这套优化的收益就消失了。 Anthropic 自己在局限里写了"系统假设服务的是 MoE 架构"。所以这不是一个通用方案,而是一个为当下主流架构定制的方案——这没什么不对,但抄的时候要知道前提。

第四,Lean 那一层是给"AI 写密码学代码"这个新现实准备的答案。 这次项目的代码、论文、测试、对比、审校几乎全部由 Claude 完成,人类只敲定了 6 条顶层安全定义。这在两年前是不可想象的。而它之所以能被接受,恰恰是因为人类放弃了对中间过程的审查,改用机器可检查的形式化证明来兜底。 这个模式很可能会被反复复用:AI 负责规模,形式化方法负责正确性,人类负责定义"什么叫对"。

第五,也是最需要克制的一点:这仍然是一个研究原型,官方原话是"分享中间进展,而非完成的研究议程"。 1024 token 上下文、整数模型、贪心解码、不隐藏架构、侧信道未覆盖、C++ 验证器无形式化保证——五条限制里任何一条都可能在某些场景下成为硬墙。而且 Anthropic 特别说明,这个项目和他们 RSP 路线图里"2026 年 9 月 30 日前交付可证明推理原型"的承诺是两个不同的项目(那个是通过签名推理流量 + 在可信服务器上重算来实现的),本次是走密码学的另一条路。

一个可跟踪的框架:以后看到任何"可验证 AI"的说法,问五个问题——①证明的是什么(来源、正确性、还是合规)?②验证成本是多少(需要 GPU 还是 CPU,几秒还是几小时)?③覆盖多少(全量还是抽样,多长上下文)?④信任根在哪(密码学假设、可信硬件、还是某个机构的签名)?⑤形式化保证覆盖到哪一层(协议、代码、还是都没有)? 这五个问题问下来,“可验证"这三个字到底是营销还是工程,基本就清楚了。

来源:Anthropic, “Progress on provable inference for large language models”(Frontier Red Team,2026-11-02),https://www.anthropic.com/research/provable-inference;GitHub anthropics/FlashProve(Apache 2.0,含 prover、C++ fast verifier、Lean verifier、Lean proofs 与 STATEMENTS.html);36氪《Anthropic亲手终结「套壳AI」,17秒扒下假模型头套,验身速度快5000倍》(2026-11-04);智东西《17秒验明AI真身!Anthropic开源可证明推理系统,能抓模型调包》(2026-11-04);MarkTechPost, “Anthropic Releases FlashProve: Cryptographic Proofs That a Reply Came From Committed Weights”(2026-11-03)。文中的承诺-证明-验证简化实现、MoE 成本模型、批处理吞吐换算、GPU 成本估算、抽样审计模型均为基于公开数据的推演与示意,非官方数据;官方明确说明本发布为研究原型,仅分享中间进展。