
━━━━━━━━━━━━━━━━━━━━
◆ 起因:一条不太好懂的公告
━━━━━━━━━━━━━━━━━━━━
八月十一号 Anthropic 发了个公告:从八月起,支持该机制的 Claude 模型,生成的文本都会带上一个看不见的水印。(官方口径是"supported Claude model",八月二号及以后推出的新模型先上,旧模型陆续跟进——不是一夜之间全网都变了。)
公告里对技术只有一句话:把一个"不可察觉的水印编织进文本本身"(weaves an imperceptible watermark directly into the text itself)。剩下的就是这个水印的性质——不影响语义、不影响质量、不影响可读性,复制粘贴能带走,重度编辑可能被剥掉。至于它是怎么"编织"进去的,一个字没说。
官方给的理由是欧盟《AI 法案》。这个理由成立,但有三个细节值得先摆出来,不下结论,摆完往下看技术:
其一,日期。 该法案第 50 条的透明度义务,适用日期是 2026 年 8 月 2 日。而水印开始铺开的日期,也是 8 月 2 日。一天不差。
这里得补一句,免得把话说满:欧盟对已经在市场上的生成式 AI 系统留了宽限期,标记义务可以拖到 2026 年 12 月。也就是说,8 月 2 日那天并没有一把刀架在脖子上——真要拖,还能拖四个月。他们选择卡在生效当天开始执行,是主动的,不是被逼到墙角。
其二,范围。 法条管的是欧盟市场。合规的最小做法是给欧盟用户加,别的地区照旧——按区域分流是服务端最基本的操作。他们选的是全球统一执行,包括从来不受该法案管辖的用户。这一步不是法条要求的。
其三,顺序。 加标记的一端已经在跑,读标记的一端还没有——官方说检测支持会在后续提供,没有时间表。也就是说现在这个状态是:输出已经带上标了,但外界没有任何人能读这个标。
三条摆在这儿,各人自有判断。本文不打算论证动机,只打算把那句"编织进文本本身"拆开看看——毕竟不管是谁想做的,东西已经在你的每一次输出里了,搞清楚它是什么,比争论谁的主意有用。
我第一反应是没看懂。文字就是文字,一段话里就那么些字,你往哪儿藏东西? 不像图片——图片有几百万个像素,随便改几个像素的最低位,人眼看不出来,信息就藏进去了。文字没有这种冗余:一句话你改一个字就是改了一个字,读者读得出来。
所以这期就干一件事:把这个"往哪儿藏"搞清楚。找了这个方向最经典的一篇论文,一行一行拆开,还自己写了个几十行的检测器跑了四组实验。结论提前说一句:藏的地方确实存在,但它不在字里,在字被选出来的那一瞬间。
先把背景交代干净。
━━━━━━━━━━━━━━━━━━━━
◆ 1. 事实背景:谁在推、推了什么、什么还没到位
━━━━━━━━━━━━━━━━━━━━
三件事分开说,别混。
第一,做了什么。 支持该机制的 Claude 模型,在文本输出里嵌不可见水印;生成的文件(图片等)另外加一套叫 C2PA 的签名溯源元数据——那是完全不同的技术,本期不展开,只讲文本这一半。
关键在于水印是在模型这一层加的,不是在某个产品的界面上加的。所以只要你用的是支持该机制的模型,不管走的是 API、Claude Code,还是云厂商转售的实例,都一样带标。而且不分地区——法条管的是欧盟,执行是全球的。公告日期是八月十一号,实际八月二号就开始了。
第二,为什么现在做。 欧盟《AI 法案》第 50 条要求:生成合成内容的 AI 系统必须把输出标记成"人工生成",而且标记要机器可读。罚则是最高 1500 万欧元、或全球年营业额的 3%,取高者。Anthropic 签了欧盟的行为准则,然后选择全球统一执行——不是分地区做两套,是让所有人吃同一套合规。
第三,也是最尴尬的一条:验证工具还没有。
官方帮助文档的原话是"我们会在后续技术文档里分享检测机制的细节",并表示会在将来支持用户和第三方检测这些标记——但没有给出任何时间表。
于是现在处在这么个状态:输出已经带上标了,但外界没有任何人能读这个标。 Anthropic 说带了,而目前只有 Anthropic 能证实它带了,也只有 Anthropic 能证实它没带。对一条以"内容溯源"为名的措施来说,这个状态有点绕:它要求你先信它,才能用它去验证别的东西。
还有一条官方自己就承认了的、但很容易被忽略的性质:
────────────────────
💡 水印证明的是"过了这道手",不是"这是它写的"
你用 Claude 翻译自己的文章、润色自己的稿子、把自己写的提纲扩写成正文——出来的东西照样带水印。因为水印是在生成那一刻加的,它记录的是"这段文本从这个模型的采样器里流出来过",不是"这段文本的思想是机器的"。
所以"检测到水印"能推出的结论比想象中窄得多:它说明这段文字经过了 AI,不说明这段文字是 AI 想出来的。而恰恰是"人写 AI 改"这种最认真的用法,最容易被误伤。
反过来也一样:检测不到不等于没用过。改写、翻译、拼接、只截取一小段——都可能让信号弱到测不出来。后面的实验会给出具体到多少比例的数字。
────────────────────
背景就这些。下面进正题。
━━━━━━━━━━━━━━━━━━━━
◆ 2. 藏在哪儿:不是藏在字里,是藏在"选字"那一步
━━━━━━━━━━━━━━━━━━━━
先回忆一下模型是怎么吐字的——这个号讲过很多次,这里只用最后一步。
模型跑完一整轮前向传播,得到的不是一个字,是一张打分表:词表里每个词一个分数(叫 logits,可以理解成"这个词有多合适"的原始得分)。词表通常有三万到十五万个词,所以这是一张十几万行的表。然后把这张表过一遍 softmax 变成概率,再按概率抽一个词出来。
关键在这儿:抽签这一步是有随机性的。
同一个上下文,模型给出的打分表是固定的,但抽出来的词不是唯一的。"今天天气"后面,"很"可能占 30%,"不"占 15%,"真"占 10%……每次生成都可能抽到不同的词。这也是为什么同一个问题问两遍,AI 的回答不一样。
这个随机性,就是藏东西的地方。
如果有人能在抽签之前,偷偷把某一半词的分数抬高一点点——抬得不多,不至于让句子变得奇怪,但足以让这一半词被抽中的次数明显偏多——那么生成出来的文本里,就带上了一个统计上的偏向。单看一个词看不出来,看几百个词,偏向就藏不住了。
这就是水印。它不改变任何一个词的字形,它改变的是"哪些词更容易被选中"的概率分布。
那具体是哪一半词?这就到了那篇经典论文。
━━━━━━━━━━━━━━━━━━━━
◆ 3. 那篇奠基论文:绿名单与红名单
━━━━━━━━━━━━━━━━━━━━
论文是 2023 年 ICML 的《A Watermark for Large Language Models》,六位作者全部来自马里兰大学,第一作者 John Kirchenbauer。这是该方向影响最大的奠基论文之一,后面几乎所有方法要么在改进它,要么在攻击它,业内一般按作者首字母叫它 KGW。
它的做法分三步。为了讲清楚,下面全程用一个玩具例子:假设词表只有 8 个词(真实模型是三万到十五万个,原理完全一样,只是数字大)。
编号: 0 1 2 3 4 5 6 7词: 的 是 在 和 了 人 我 有
第一步:把词表分成两半。
假设模型刚刚吐出的词是"是"(编号 1),我们手上的密钥是 20260814。
① 先算一个种子。 把"前一个词的编号"和"密钥"两个数扔进哈希函数:
种子 = hash(1, 20260814) = 3847592014哈希函数可以理解成一台搅拌机:输入变一点点,输出面目全非;但同样的输入,永远吐出同样的结果。这两条性质缺一不可——前一条保证名单看起来毫无规律,后一条保证检测方事后能一模一样地复现出来。
② 用这个种子洗牌。 把种子交给随机数生成器(就是 random.seed(3847592014) 这一句),然后把 8 个编号洗一遍:
洗牌结果: [5, 2, 7, 0, 3, 6, 1, 4]③ 从中间切一刀。 γ = 0.5,取前一半进绿名单,后一半是红名单:
绿名单: {5, 2, 7, 0} → 人 在 有 的红名单: {3, 6, 1, 4} → 和 我 是 了
这就是"是"这个词后面所对应的那份名单。
关键在于——换一个前序词,整份名单就全变了。 同样的密钥,把前一个词换成"在"(编号 2):
种子 = hash(2, 20260814) = 1029384756 ← 输入只差 1,输出天差地别洗牌结果: [3, 0, 6, 4, 1, 7, 2, 5]绿名单: {3, 0, 6, 4} → 和 的 我 了
"人"刚才还是绿的,现在变红了。 同一个词,在不同位置颜色不同,而且每个词平均一半时间绿、一半时间红。所以任何人拿一大堆文本去统计词频,都看不出任何规律——除非他有那个密钥。
论文特意解释了为什么种子只用前一个词,而不用整句话:
"enabling the red list to be reproduced later without access to the entire generated sequence."
(让红名单事后能被复现出来,而不需要拿到完整的生成序列。)
翻译成人话:检测的时候,只要有这段文本就够了,不需要原始提示词,也不需要模型。
第二步:把绿名单的分数抬一点。
接着上面的例子。模型在"是"后面交出的打分表长这样(logits,随手编的数):
词: 的 是 在 和 了 人 我 有logits: 4.1 0.3 3.8 1.2 2.5 3.5 0.8 1.9颜色: 绿 红 绿 红 红 绿 红 绿
给绿名单那四个各加 δ = 2.0(论文主实验值),红名单原样不动:
词: 的 是 在 和 了 人 我 有加偏置: 6.1 0.3 5.8 1.2 2.5 5.5 0.8 3.9↑+2 ↑+2 ↑+2 ↑+2
然后把这张改过的表过 softmax、抽签。原本"的"(4.1)和"在"(3.8)领先,"人"(3.5)紧随其后——加完之后前三名还是这三个词,但它们全是绿的,抽中绿词的概率从大约一半推到了七成以上。
这一步的位置很要紧:δ 是加在 logits 上、softmax 之前的。也就是说,模型的全部计算此刻已经结束了——这一步发生在模型之后。模型算完它的活、交出打分表,然后有人在表上动了个手脚,才轮到抽签。模型自己不知道这件事。 它交出去的是一张表,至于那张表后来被怎么用,它无从得知。
第三步:不禁止,只是倾斜。
论文其实先提了一个更简单的版本:干脆禁止红名单里的词,只准从绿名单里选。这个版本论文自己叫"硬红名单",检测起来极其干脆,但它有个致命毛病,论文举的例子非常好懂:
"the token 'Barack' is almost deterministically followed by 'Obama' in many text datasets, yet 'Obama' may be disallowed by the red list."
(在很多文本数据集里,"Barack"后面几乎必然跟着"Obama",然而"Obama"可能恰好被红名单禁掉了。)
"Barack"后面不让说"Obama",那说什么? 句子当场就废了。所以论文改成了"软"版本:不禁止,只是让绿名单里的词稍微更容易被选中。该说"Obama"的地方照样说"Obama"——δ=2.0 那点偏置,在一个概率 97% 的词面前根本掀不起浪。只在模型本来就犹豫不决的地方,水印才起作用。
这个"只在犹豫的地方起作用"的性质,是整套方案的命门。后面第 5 节专门做实验看它。
━━━━━━━━━━━━━━━━━━━━
◆ 4. 怎么检测:一个初中就学过的统计量
━━━━━━━━━━━━━━━━━━━━
检测比生成简单得多,而且用的还是刚才那套东西。
假设我们拿到了一段用这个玩具模型生成的文本:
是 人 的 在 有 和 人 的 ……从第二个词开始,逐个查。第一个词"是"跳过——它前面没词,没法算种子。
查"人":它前面是"是",重算一遍第一步那三个动作(哈希 → 洗牌 → 切一刀),得到绿名单 {人 在 有 的}。"人"在里面 → 记一笔绿。
查"的":它前面是"人",重算一遍,得到"人"所对应的那份新名单,看"的"在不在里面。
查"在":它前面是"的",再重算一遍……
就这样一路查到底。每查一个词,都要用它前面那个词重新生成一次名单——因为名单是逐词变的。数完得到一个数:这段文本里绿词有多少个。
然后做一次单比例 z 检验——就是问一句"实际值偏离了期望值几个标准差":
z =(绿词数 − γT)÷ √(T · γ · (1−γ))T 是参与统计的词数。分子是"实际绿词数减去理论期望值",分母是纯随机情况下的标准差。
零假设是这么设的(论文原文):"这段文本是在不知道红名单规则的情况下生成的"。如果这个假设成立,写这段话的人(或机器)根本不可能知道哪些词是绿的,绿词比例就该老老实实等于 γ,也就是 50%。偏离越远,这个假设越站不住。
拿具体数字走一遍。假设上面那段文本一共 200 个词(T = 199,第一个不算),数出来 150 个绿的:
期望值:γT = 0.5 × 199 = 99.5 个 标准差:√(199 × 0.5 × 0.5) = √49.75 ≈ 7.05 z =(150 − 99.5)÷ 7.05 ≈ 7.16
实际比期望多了 50 个绿词,而"正常波动"的尺度只有 7 个。多出来的量是波动尺度的七倍。
这就是 z 值的含义——它不是"绿词多不多",是"多得离谱到什么程度"。抛 200 次硬币,正面比反面多七八个很正常;多五十个,那就不是硬币的问题了。
论文给的判定线是 z > 4,对应误报率 3×10⁻⁵——大约三万分之一。也就是说:一段没加过水印的文本,纯靠运气凑出这么多绿词的概率,是三万分之一。
这套检测最反直觉的一点,论文把它列在设计目标的第一条:
"The watermark can be algorithmically detected without any knowledge of the model parameters or access to the language model API. This property allows the detection algorithm to be open sourced even when the model is not. This also makes detection cheap and fast because the LLM does not need to be loaded or run."
(水印可以在完全不了解模型参数、也不访问语言模型 API 的情况下被算法检测出来。这一特性使得即便模型本身不开源,检测算法也可以开源。这也让检测变得又便宜又快,因为根本不需要加载或运行那个大模型。)
检测不需要跑模型。 不需要几百 GB 的权重,不需要显卡,不需要做一次前向传播,也不需要原始提示词。几十行代码,跑完只要毫秒级。
不过论文这句话有个容易滑过去的边界——原文说的是不需要 model parameters(模型参数),不是什么都不需要。分词器和词表还是要的。
道理在上面那个玩具例子里其实已经摆着了:算种子用的是"前一个词的编号"。编号从哪来?从词表来。所以检测方必须能把文本切成和生成时一模一样的 token,还得知道每个 token 的编号——切法不一致,前后关系就错位,整条名单链全盘皆错。
这东西体积不大,通常也就几 MB,跟几百 GB 的权重完全不是一个量级。开源模型都自带,OpenAI 也发布了官方的 tiktoken 库。
但 Claude 的分词器不公开。
从 Claude 3 开始,Anthropic 就没有发布过分词器,只提供一个"数 token 数量"的接口——它告诉你这段话有多少个 token,但不告诉你是怎么切的。网上那些第三方的 Claude 分词器,要么是调这个接口拿个总数,要么是靠观察流式输出一点点逆向猜出来的近似版(有个开源项目的作者,把自己那份的介绍标题写成《最烂但唯一的 Claude 3 分词器》)。
于是外部要独立验证这个水印,需要的两样东西,恰好一样都没有:
- 密钥
——不公开,检测工具还没发布 - 分词器
——不公开,只有第三方逆向的近似版
密钥这道锁大家都看得见。分词器这道锁很少有人提,但它同样在那儿。
这个细节顺手还解释了另一件事:水印是绑定到具体模型的。 你不能拿一个模型的检测器去测另一个模型的输出——不只是密钥不同,连怎么切词都不一样。所以严格讲,"这段文本有没有水印"这个问题本身就不成立,只能问"这段文本有没有某某模型的水印"。
说到这儿我就想自己试试了。
━━━━━━━━━━━━━━━━━━━━
◆ 5. 自己写一个:四组实验
━━━━━━━━━━━━━━━━━━━━
我按论文的主设置(γ=0.5、δ=2.0、判定线 z>4)写了个几十行的脚本,用模拟的打分表跑了四组实验。
先补充三句这个脚本的边界:
它验不了 Claude。 检测需要密钥,而 Anthropic 的密钥不公开——甚至没说自己用的是不是这套方案。这个脚本做的是"用我自己的密钥加水印,再用我自己的密钥检出来",证明的是这套数学成立,不是"能检测 Claude"。任何声称不用密钥就能检测某家模型水印的工具,都可以直接判为假。
用的是模拟数据不是真模型。 但打分表的形状是按真实模型来造的(概率沿排名幂律衰减,头部一枝独大、长尾几乎为零),所以量级和论文对得上。看结构和趋势,具体数字以论文为准。
词表设的是 4000,不是真实模型的三万到十五万。 这个得专门说一句,因为看代码的人一眼就会发现。降到 4000 纯粹是为了跑得快——生成一个词要给全词表逐个判色、逐个加偏置,词表大一个数量级,脚本就要跑十几分钟。
而它不影响结论,理由在检测公式里摆着:
z =(绿词数 − γT)÷ √(T · γ · (1−γ))
这个式子里根本没有词表大小。 γ 是比例——词表 4000 就切成 2000 对 2000,词表十五万就切成 7.5 万对 7.5 万,每个词落在绿名单里的概率都是 0.5,跟总数多少无关。δ 那边同理:能不能把某个词推上去,取决于头部几个词的概率差距,跟长尾有多长没关系——排第 3000 名和排第 30000 名的词,概率都约等于零,加不加那 2.0 都轮不到它被抽中。
真正影响结果的是熵,不是词表大小,而熵在实验三里是单独拿温度控制的。
实验一:加了能测出来,密钥错了就测不出来。
每格 30 次独立生成、每次 200 个词,取平均:
前两行是意料之中:没加水印时绿词老老实实在 50%,加了水印推到 75.6%,z 值直接爆表。
第三行才是重点。 同一段带水印的文本,把密钥改动一位再检测——绿词比例立刻回到 49.1%,z 值回到零。水印还在那段文本里,一个字没变,但它彻底隐形了。
这一行解释了本文开头那个"外界没人能验"的状态:算法可以完全公开——它本来就公开在论文里;卡住外部验证的从来不是算法,是密钥。
实验二:多长的文本才测得出来?
注意绿词比例从头到尾几乎不变(都在 76% 上下),变的只是证据的份量。这正是统计检验的逻辑:抛十次硬币出七次正面说明不了什么,抛一千次出七百次正面就是铁证。
这里有个需要拆开的宣传口径。论文摘要说水印"少至 25 个词"就能检测(as few as 25 tokens),这句被引用得很多,但它跟另外两个数字容易混:
- 16 个词
——这是"硬红名单"版本的理论下界(全部是绿词时 z 恰好到 4) - 25 个词
——摘要里的口径 - 约 128 个词
——γ=0.5、δ=2.0 这个实际设置真正需要的长度,论文正文自己给的
我这个脚本在 128 词时 z=6.05,跟论文同一个量级。所以"一句话就能被测出来"是不成立的——一条微博、一个函数名、一段代码片段,都低于检测门槛。官方那句"短摘录可能不包含足够的信号",说的就是这件事。
实验三:为什么低熵文本加不上水印。
这是我觉得最有意思的一组。同样 200 个词、同样的 δ=2.0,只改变一件事:模型在写这段话时有多"确定"。
| 测不出 |
熵掉下来,水印跟着消失。 而且不是"能加/不能加"两档,是一条连续下滑的曲线。
道理不难:δ=2.0 是个固定的偏置,它能不能改变结果,取决于对手有多强。模型犹豫的时候,几个候选词概率差不多,加 2.0 就能翻盘;模型确定的时候,top-1 概率占了 97%,加 2.0 连零头都补不上。没有犹豫,就没有可供藏匿的空间。
这也就是上一节 Barack→Obama 那个例子的量化版:那个位置你没有别的词可选,也就没有地方藏东西。
论文没有把这当成一个工程缺陷,而是把它写成了定理。它自己造了一个量叫 spike entropy(表里那个"熵"),专门衡量"这个分布有多不集中",然后用 Theorem 4.2 证明:绿词数量的期望值,下界正比于这段文本的平均熵。 换句话说:
一段文本能塞进多少水印,上限由这段文本自身的熵决定。这是数学上界,不是实现得不够好。
论文还坦白了一个更微妙的后果。它观察到那些测不出水印的低熵片段,往往是模型在背诵训练数据:
"the model regurgitates a copy (or near copy) of human-written text which is therefore not detectable as machine-written."
(模型只是在反刍一份人类文本的复制品或近似复制品,因此它本来也不该、也无法被判定为机器所写。)
模型抄得越像人写的,越测不出来。 而且论文指出这时候问题是双向的:低熵位置不但加不上水印,就算加上了也没意义——因为人和机器在这种位置本来就会写出一样的东西,区分它们本身就没有意义。
实验四:改写多少能洗掉?
水印是统计信号,不是指纹。 指纹要么在要么不在,统计信号是连续衰减的:改 30% 还在检出线上,40% 掉到可疑,70% 才彻底消失。
但我这个实验是随机换词,换完句子就不通顺了,属于极端情况。论文做的是正经攻击实验:用 T5-Large 做同义替换(一个比目标模型小得多的模型),结果是——
10% 的替换预算下,水印强度只掉了 0.01 AUC,几乎纹丝不动。把预算提到 30% 才能有效削弱,但代价是文本的困惑度暴涨 3 倍——通俗说就是句子读起来明显不对劲了。
论文顺手点出了攻击者的根本困境,这句我很喜欢:
"If the attacker had an equally strong language model at hand, there would be no need to use the watermarked API, the attacker could generate their own text."
(如果攻击者手上本来就有一个同样强大的语言模型,那他根本不需要去用带水印的 API——他自己生成就行了。)
你得用一个更弱的模型去洗一个更强的模型的输出,洗的过程本身就在降低文本质量。 洗干净了,东西也不好使了。
不过这个论证有个前提:攻击者手上只有更弱的模型。 这在 2023 年成立,今天就不一定了——开源模型跟前沿模型的差距肉眼可见地在缩小,随便找一个开源模型把文章重新整理一遍,质量不见得会掉。而且那已经不算"改写"了:换一个模型重新采样,每个词都是新模型按自己的分布选的,跟原来那份名单毫无关系——水印不是被洗淡的,是压根没被继承。
说到底,真会费这个劲的能有几个人?大概也就是赶论文的学生。而真正拿 AI 干坏事的那些人——诈骗话术、水军、假新闻——根本不在乎水印,因为收到诈骗短信的人不会先拿去检测一遍。
━━━━━━━━━━━━━━━━━━━━
◆ 6. 这些年做出来的,远不止这一种
━━━━━━━━━━━━━━━━━━━━
上面讲的 KGW 是 2023 年的方案。三年过去,这个方向的论文已经很多了。今年七月有一篇综述(arXiv:2607.10103)把它们梳理了一遍,里面具名的方法有二十多种。挑十种列一下,只说思路,不展开:
| KGW | ||
| 句子级 | ||
| Adaptive-WM | ||
| Unbiased-WM | ||
| SynthID | Nature 2024 | |
| 完全不动分数 | ||
| UPV |
这张表不是罗列,有三行值得单独说说。
第一,Adaptive-WM 和 Unbiased-WM 修的是同一个毛病。 前者干脆只在熵高的地方下手,后者想办法完全不动原分布。它们要解决的,正是第 5 节实验三跑出来的那条曲线——低熵位置加不上、硬加会伤质量。也就是说,我们那个实验里看到的现象,是后面一整支研究的起点。
第二,SynthID 是这张表里唯一真正大规模跑起来的。 其他方案基本还停在论文和开源实现的阶段,而 SynthID 是 Google 拿去在自家产品线上实际部署的东西,也是该领域少数发表在 Nature(2024 年)、并且真的进入大规模产品部署的工作——论文里报告了在 Gemini 线上约两千万条响应的评估。
它的机制跟 KGW 不是一路:不是给绿名单加分数,而是给候选词打上伪随机分数,然后多轮两两淘汰,像打一场锦标赛,最后活下来的那个词被选中。这么做的好处是对文本质量的干扰更小、更适合高吞吐场景——细节够写单独一期,这里点到为止。它同样绕不开熵那个上限。
还有个现实原因让这一行显得特别:Anthropic 用的到底是哪种方案,官方没说。外界猜测可能是类似的路子,但那是猜测,没有证实。
还有一行值得单独说:UPV。它想解决的是本文开头那个问题——外人怎么验。它的办法是让生成和检测用两个不同的神经网络,检测网络可以公开发布,因为从检测网络反推生成规则很难。这条线上还有别的思路,比如用零知识证明让厂商证明"我确实老实跑了检测"却不交出密钥,或者干脆往文本里嵌一个公钥可验的密码学签名。
但每一种都有代价。签名方案安全性最漂亮,代价是一个签名要一两千个词才嵌得下——一条推文根本不够。零知识证明方案不用改现有水印,代价是出一次证明要几十秒到几分钟,只能用在打官司这种场合,日常 API 用不了。
这背后是个绕不开的死结,那篇综述说得很直白:公开密钥或检测接口,就会招来伪造和探测攻击;不公开,又会让人质疑厂商的公平性、透明度和公信力。
也难怪 Anthropic 到现在没说自己用的是哪种。
而 2025 年有一篇专门追问这件事的系统化研究,标题就叫《大模型里的水印,准备好部署了吗?》。它的答案是:
"these techniques have yet to reach their full potential in real-world applications due to their unfavorable impacts on model utility of LLMs and downstream tasks."
(这些技术在现实应用中尚未充分发挥其潜力,原因在于它们对模型效用和下游任务造成的不利影响。)
理由不是"技术不够好",是"用了会影响模型本身的表现"。 这一点在第 5 节其实已经看到了——δ 加得越狠水印越强,文本也越容易走样;论文原作者选 δ=2.0 而不是 δ=10,就是在这条权衡线上找平衡。
━━━━━━━━━━━━━━━━━━━━
◆ 7. 回到最初那个问题
━━━━━━━━━━━━━━━━━━━━
"文字里往哪儿藏东西"——现在有答案了:藏在字被选出来的那一瞬间。
模型算完它的活,交出一张打分表,本来该随机抽签。有人在抽签前,把伪随机选中的那一半词的分数抬高了一点点。抬得不多,不改变任何一个词,也不改变句子的意思——但抬了几百次之后,统计上就留下了痕迹。
这趟拆下来,有三个性质我印象最深:
第一,它是概率的,不是刻上去的。 所以它会衰减,会被稀释,会因为文本太短而测不出来。它给出的从来不是"是"或"否",是一个置信度。
第二,它的容量由文本自身的熵决定。 模型越确定要说什么,越藏不住东西。而模型最确定的时候,恰恰是它在背诵人类写过的东西的时候——那个时候,它写的和人写的本来就一样。
第三,加水印和验水印是两件难度完全不同的事。 加,是采样前的一行代码;验,需要密钥,还需要分词器——而这两样目前都不公开。检测器我几十行就写完了,数学也不复杂——真正卡住外部验证的从来不是算法。
所以最后落回那个还没有答案的问题:Anthropic 承诺的那个检测工具,会长成什么样?
如果是公开算法加托管密钥,那任何人都能独立复现判断,说错了当场能被纠正。如果是一个黑箱接口,你贴进去、它回你是或不是——那它的输出就是终审判决,你没法上诉,因为你无法审计。
两种都能满足法条的"可检测"要求。但 "有验证器"和"你能验证",是两回事。
而按现在的状态往下推,会推出一个有点意外的位置。
把前面那两把锁合起来看:密钥不公开,分词器也不公开。
这里得再谨慎一句:Anthropic 用的到底是不是 KGW 这类方案,官方从没说过。 所以严格讲,我们不能断定它的水印"一定"需要私有分词器和密钥。能确定的只是眼下这个事实——在算法、密钥、检测工具三样都没公开的情况下,外部无法独立复核它给出的任何检测结论。
而这一条就够了。因为不管它内部用的是哪种方案,只要检测材料不公开,能判定"这段文本是不是 Claude 写的"的,目前就只有一方。
于是设想一个不难想象的场景:某天欧盟要查一份文件是不是 AI 生成的,按法条它有权要求可检测。它去问谁?只能去问 Anthropic。 得到的答案是一个它无法复核的结论——因为复核需要密钥和分词器,而那正是它拿不到的两样东西。
于是就出现了这么一个位置:
法条要求的是"输出必须可被检测"。交付出来的是"输出可被我们检测"。形式上完全满足,实质上把一项监管义务,做成了一个别人进不来的位置。 提要求的那一方,最后得回过头来,向被要求的那一方索取答案。
欧盟想要的是监管主权,结果拿到手的是一张问询单——想查,得看人家什么时候把工具做出来。 一边立着全世界最严的规矩却造不出模型,一边守着模型顺手把裁决权也收了:说到底是狗咬狗一嘴毛,谁也别说谁高尚。 唯一确定的是,两边掰扯的时候,账单都记在用户头上——你的每一次输出都带着标,而你既读不了它,也没人问过你愿不愿意。
而且这个位置有个自我维持的性质:只要检测工具一直停在"正在开发中",独占就一直持续。 没有时间表这件事本身,就是最省力的维持方式。
技术上的水印,我们已经拆得够清楚了——它是一次抛硬币前的手脚,会衰减、能被洗掉、遇上低熵文本就失灵。但决定它有多大分量的,从来不是它有多准,而是谁握着那把尺子。
这一点,公告里没说。
━━━━━━━━━━━━━━━━━━━━
◆ 参考资料
━━━━━━━━━━━━━━━━━━━━
Kirchenbauer, Geiping, Wen, Katz, Miers, Goldstein, A Watermark for Large Language Models, arXiv:2301.10226(马里兰大学,ICML 2023;本文详解的那篇,绿/红名单方案的出处)
Dang, Lai, Phan, et al., SoK: Are Watermarks in LLMs Ready for Deployment?, arXiv:2506.05594(2025 年 6 月;本文引用的"尚未充分发挥潜力"那句判断出自这里)
Phan, Dang, Dulal, et al., A Survey on LLM Watermarking: Theory and Deployment, arXiv:2607.10103(2026 年 7 月的预印本;本文那张方法表的来源。注:该文尚未经过同行评审,参考文献存在瑕疵,当索引用可以,别拿它单独扛结论)
European Commission, Quick facts: transparency rules for AI systems(第 50 条适用日期、以及 2026 年 12 月宽限期的出处)
Dathathri et al., Scalable watermarking for identifying large language model outputs, Nature 634, 2024(Google 的 SynthID,锦标赛采样)
Anthropic, How Claude marks AI-generated content, 官方帮助中心(本文引用的官方口径均出自此处)
━━━━━━━━━━━━━━━━━━━━
本期实验脚本 watermark_verifier.py(纯标准库,无依赖,可直接跑)在这里:
https://github.com/lmxxf/ai-theorys-study/tree/main/wechat/assets/280
━━━━━━━━━━━━━━━━━━━━
水印不改变任何一个字,它改变的是哪些字更容易被选中——它动的不是文本,是文本诞生前的那一次抛硬币。
模型越确定要说什么,越藏不住水印。而它最确定的时候,正是它在复述人类已经写过的话——那时候,它写的和人写的本来就没有区别。
检测器几十行就能写完,数学也不难。卡住外部验证的从来不是算法,是密钥在谁手里。
// 靳岩岩的 AI 学习笔记 × Claude 的严谨 × Gemini 的浪漫
2026年8月15日
夜雨聆风