EU AI Act Article 50已于2026年8月2日生效,要求生成式AI输出携带机器可读标记;文章实测C2PA元数据在截图/CDN场景会丢失,需叠加不可见水印才能真正存活。
欧盟《人工智能法》第五十条透明度规则于 2026 年 8 月 2 日起正式生效。如果你在一个面向欧盟用户的生成式 AI 功能中嵌入了相关内容,现在你有义务向监管机构提供一个机器可读的标记。常见的捷径——丢一个 C2PA 清单进去就完事——在生产环境中根本站不住脚。以下是真正可行的方案,并附有实现它的代码。
第五十条第二款要求标记必须有效、互操作、稳健且可靠。欧盟实践准则将其解读为至少两个层面:签名元数据(C2PA)加上不可感知的数字水印(SynthID 或同等方案)。指纹识别是可选的第三层。
采用双层方案的原因并非官僚主义。而是截图。
C2PA 存在于 JUMBF 元数据盒中。X 平台在上传时会剥离它。CDN 在优化过程中会剥离它。截图则将其彻底摧毁。微软在 2026 年 2 月的媒体完整性报告中公开承认了这一点:无法防止对出处的所有攻击。
嵌入像素内容的隐形水印可以在这些操作中存活下来,但携带的信息非常有限。你需要两者兼有。
// npm install c2pa-node
import { createC2pa, ManifestBuilder } from 'c2pa-node';
import { readFile, writeFile } from 'node:fs/promises';
const c2pa = createC2pa();
async function signGeneratedImage(inputPath, outputPath, generationMeta) {
const asset = { buffer: await readFile(inputPath), mimeType: 'image/jpeg' };
const manifest = new ManifestBuilder({
claim_generator: 'firesafe/1.0',
format: 'image/jpeg',
title: 'ai-generated-image.jpg',
assertions: [
{
label: 'c2pa.actions',
data: {
actions: [{
action: 'c2pa.created',
digitalSourceType: 'http://cv.iptc.org/newscodes/digitalsourcetype/trainedAlgorithmicMedia',
softwareAgent: generationMeta.modelName,
}],
},
},
{
label: 'com.firesafe.generation',
data: {
model: generationMeta.modelName,
modelVersion: generationMeta.modelVersion,
promptFingerprint: generationMeta.promptHash,
timestamp: new Date().toISOString(),
deployerId: generationMeta.deployerId,
},
},
],
});
const signer = {
type: 'local',
certificate: await readFile('./certs/signing.pem'),
privateKey: await readFile('./certs/signing.key'),
algorithm: 'es256',
tsaUrl: 'http://timestamp.digicert.com',
};
const signed = await c2pa.sign({ asset, manifest, signer });
await writeFile(outputPath, signed.signedAsset.buffer);
return signed.manifest;
}
有两点需要注意。首先,digitalSourceType 字段是审计人员实际会搜索的内容;IPTC 值 trainedAlgorithmicMedia 是 AI 生成内容的标准标志。其次,时间戳授权 URL 如果你想要长期可验证性,就不是可选项。没有可信时间戳的签名,其有效性只等同于你证书的生存期。
如果你已经在使用 Google 的 Imagen 或 Veo 技术栈,SynthID 会在生成时自动应用,你可以通过 Vertex AI API 验证它。如果你是在本地运行 Stable Diffusion 或 Flux,则需要自己添加一个等效方案。以下是 Vertex 的实现路径。
from google.cloud import aiplatform
from google.cloud.aiplatform.gapic.schema import predict
import base64
aiplatform.init(project="your-project", location="us-central1")
def generate_with_synthid(prompt: str) -> bytes:
endpoint = aiplatform.Endpoint(endpoint_name="projects/.../imagen-3")
instance = predict.instance.ImageGenerationPredictionInstance(
prompt=prompt,
add_watermark=True, # SynthID applied on generation
).to_value()
response = endpoint.predict(instances=[instance])
image_b64 = response.predictions[0]["bytesBase64Encoded"]
return base64.b64decode(image_b64)
def verify_synthid(image_bytes: bytes) -> dict:
"""Returns detection score. Above threshold means SynthID present."""
endpoint = aiplatform.Endpoint(endpoint_name="projects/.../synthid-verifier")
instance = predict.instance.VerifierInstance(
image=base64.b64encode(image_bytes).decode(),
).to_value()
response = endpoint.predict(instances=[instance])
return {
"score": response.predictions[0]["score"],
"verdict": response.predictions[0]["verdict"], # "ai" | "human" | "uncertain"
}
检测不是二元的。SynthID 返回一个置信度分数,由你来设定阈值。对于合规日志,要记录原始分数,而不只是判定结果。当监管机构问你如何确定你的标记在压缩后仍然有效时,你需要这些数字。
第五十条第四款将披露义务放在了部署方身上。如果你在产品中提供生成内容,你必须在消费点附加一个人类可感知的提示。这应该是中间件,而不是每个端点的独立决策。
// Express middleware that stamps every AI generated response with a disclosure header
// and, for HTML endpoints, injects a visible label component.
import type { Request, Response, NextFunction } from 'express';
interface AIResponse extends Response {
isAIGenerated?: boolean;
aiModelId?: string;
}
export function aiDisclosureMiddleware(req: Request, res: AIResponse, next: NextFunction) {
const originalSend = res.send.bind(res);
res.send = function (body: any) {
if (res.isAIGenerated) {
res.setHeader('X-AI-Generated', 'true');
res.setHeader('X-AI-Model', res.aiModelId || 'unknown');
if (res.getHeader('Content-Type')?.toString().includes('text/html')) {
const disclosureBanner = `
<div role="status" aria-label="AI generated content notice"
style="position:sticky;top:0;padding:8px;background:#fef3c7;
border-bottom:1px solid #f59e0b;font-size:14px;text-align:center;">
This content was generated with AI (model: ${res.aiModelId}).
</div>`;
body = body.replace('<body>', `<body>${disclosureBanner}`);
}
}
return originalSend(body);
};
next();
}
头部是机器可读的,横幅是人类可感知的。两者都是第五十条第四款下可辩护立场所必需的。
监管机构不会只要求你标记内容。他们会要求你证明你的标记在你自己的输出上是有效的。在你需要之前就把这个端点建好。
from fastapi import FastAPI, UploadFile, HTTPException
from pydantic import BaseModel
import c2pa
app = FastAPI()
class VerificationResult(BaseModel):
c2pa_present: bool
c2pa_signer: str | None
c2pa_ai_flag: bool
watermark_present: bool
watermark_score: float
verdict: str # "compliant" | "partial" | "unmarked"
@app.post("/verify", response_model=VerificationResult)
async def verify(file: UploadFile):
content = await file.read()
# Layer 1: C2PA manifest
c2pa_result = {"present": False, "signer": None, "ai_flag": False}
try:
reader = c2pa.Reader.from_stream(file.content_type, content)
manifest = reader.active_manifest
c2pa_result["present"] = True
c2pa_result["signer"] = manifest.signature_info.issuer
for a in manifest.assertions:
if a.label == "c2pa.actions":
for action in a.data.get("actions", []):
if "trainedAlgorithmicMedia" in action.get("digitalSourceType", ""):
c2pa_result["ai_flag"] = True
except Exception:
pass
# Layer 2: SynthID
wm = verify_synthid(content) # from earlier
# Verdict
if c2pa_result["ai_flag"] and wm["score"] > 0.9:
verdict = "compliant"
elif c2pa_result["ai_flag"] or wm["score"] > 0.9:
verdict = "partial"
else:
verdict = "unmarked"
return VerificationResult(
c2pa_present=c2pa_result["present"],
c2pa_signer=c2pa_result["signer"],
c2pa_ai_flag=c2pa_result["ai_flag"],
watermark_present=wm["score"] > 0.5,
watermark_score=wm["score"],
verdict=verdict,
)
记录每一次调用。当国家主管部门要求提供证明时,"我们本季度的合规率"应该是一个 SELECT 语句,而不是手忙脚乱的搪塞。
第五十条第二款的宽限期将于 2026 年 12 月 2 日到期。如果你的系统在 2026 年 8 月 2 日之前就已上市,你有四个月的时间来添加机器可读标记。在 8 月 2 日之后上线的系统从第一天起就有此义务。8 月 2 日的立即义务是第五十条第一款和第四款下的部署方披露和聊天机器人规则。
自己动手做水印是一个战略性错误。欧盟正在建立一个与实践准则对齐的公共检测能力,其草案正在向 SynthID 兼容方案和 C2PA 兼容清单靠拢。如果你的自定义方案不在那个读取器中,你的标记就不是有效可检测的,而"有效可检测"是法规中四个形容词之一。
最高 1500 万欧元或全球年营业额的 3%,以较高者为准。对于一家 ARR 为 1000 万欧元的初创公司,如果向欧盟用户推送了一个未标记的生成图像功能,最坏情况是 1500 万欧元。对于 ARR 为 50 亿欧元的公司,最坏情况是 1.5 亿欧元。合规努力(一两个 sprint 的工作量)与风险暴露(一整个季度 ARR)之间的差距,是当前 AI 监管中最大的不对称。
将 C2PA 签名接入你的图像、视频和音频生成管道。
在每个支持它的提供商上启用 SynthID(或同等方案)。如果你的提供商不支持,要么换掉,要么投诉。
在每个返回生成内容的端点上添加部署方披露中间件。
建立一个 /verify 端点来检查你自己的标记。
开始记录生成事件,包含模型版本、时间戳、提示指纹和已应用的披露。
与你的 DPO 讨论第十二条的记录保存义务,它是在第五十条之上叠加的。
宽限期已经过去了五天。下一次审计请求将在数周内到来,而不是数年。