
LLM 水印技术:AI 生成内容的溯源方案
概述 随着 LLM 生成内容的大量涌现,如何区分人类与 AI 生成的文本成为版权保护、学术诚信和内容安全的关键挑战。LLM 水印技术通过在生成过程中嵌入统计信号,使后续检测能够判断文本是否由特定模型生成。 2025-2026 年,Google DeepMind 的 SynthID-Text 和 OpenAI 的文本分类器代表了两大技术路线:嵌入水印 vs 后置检测。 一、水印技术分类 类型 原理 优势 局限 基于词表分割 将词表分为绿/绿名单,偏好绿名单词 理论保证、可证明检测 对改写攻击敏感 基于概率偏移 微调采样概率分布 对文本质量影响小 检测需要较长文本 基于语义 嵌入语义级特征 抗改写较强 实现复杂 基于格式 标点、空格等微调 零质量损失 易被格式化清除 二、核心技术:词表分割水印(KGW) 由 Kirchenbauer 等人 2023 年提出,是当前最主流的 LLM 水印方案。 2.1 算法原理 水印嵌入过程: 1. 将词表 V 分为绿名单 G 和红名单 R(基于哈希) 2. 在生成时,对绿名单词的 logit 加 δ 3. 从调整后的分布中采样 水印检测过程: 1. 统计文本中绿名单词的比例 2. 使用 z 检验判断是否超过统计阈值 2.2 代码实现 import torch import torch.nn.functional as F from hashlib import sha256 class KGWWatermark: """ Kirchenbauer et al. 水印方案实现 """ def __init__( self, vocab_size: int, green_list_ratio: float = 0.25, delta: float = 2.0, seeding_scheme: str = "simple_1", hash_key: int = 15485863, # 第100万个质数 ): self.vocab_size = vocab_size self.green_list_ratio = green_list_ratio self.green_list_size = int(vocab_size * green_list_ratio) self.delta = delta self.seeding_scheme = seeding_scheme self.hash_key = hash_key def _get_green_list(self, prev_token: int) -> set: """ 基于前一个 token 生成绿名单 使用哈希确保伪随机但确定性 """ h = sha256(f"{self.hash_key}{prev_token}".encode()).hexdigest() # 用哈希值生成伪随机序列 torch.manual_seed(int(h[:8], 16)) perm = torch.randperm(self.vocab_size) return set(perm[:self.green_list_size].tolist()) def watermark_logits(self, input_ids: torch.Tensor, logits: torch.Tensor) -> torch.Tensor: """ 在 logits 上添加水印 input_ids: [batch, seq_len] 已生成的 token logits: [batch, seq_len, vocab_size] 模型输出 """ batch_size, seq_len, _ = logits.shape watermarked_logits = logits.clone() for b in range(batch_size): for t in range(seq_len): if t == 0: continue # 第一个 token 不加水印 prev_token = input_ids[b, t - 1].item() green_list = self._get_green_list(prev_token) # 对绿名单 token 的 logit 加 delta for token_id in green_list: watermarked_logits[b, t, token_id] += self.delta return watermarked_logits def detect(self, text_tokens: torch.Tensor, z_threshold: float = 4.0) -> dict: """ 检测文本中是否包含水印 """ n = len(text_tokens) if n < 10: return {"detected": False, "reason": "文本过短"} green_count = 0 for i in range(1, n): prev_token = text_tokens[i - 1].item() curr_token = text_tokens[i].item() green_list = self._get_green_list(prev_token) if curr_token in green_list: green_count += 1 # z 检验 expected = self.green_list_ratio * (n - 1) std = (self.green_list_ratio * (1 - self.green_list_ratio) * (n - 1)) ** 0.5 z_score = (green_count - expected) / std if std > 0 else 0 return { "detected": z_score > z_threshold, "z_score": z_score, "green_count": green_count, "total_tokens": n - 1, "green_ratio": green_count / (n - 1), "threshold": z_threshold, } # 使用示例 watermarker = KGWWatermark(vocab_size=50257, green_list_ratio=0.25, delta=2.0) # 生成时加水印 # watermarked_logits = watermarker.watermark_logits(input_ids, logits) # next_token = sample_from(watermarked_logits) # 检测时 # result = watermarker.detect(text_token_ids, z_threshold=4.0) # print(f"水印检测: {result['detected']}, z-score: {result['z_score']:.2f}") 三、SynthID-Text 方案 Google DeepMind 在 2024-2025 年推出的 SynthID-Text 采用更精细的概率偏移方案: ...

