全部文章

· Casimiro Ferreira· 3 分钟阅读

用机器移植代码,以及我们无法回答的许可证问题

  • FOSS
  • Licensing
  • Open Source
  • Python
  • G2P

我们用 Python 重写了几个老程序。espeak-ng 的 G2P 前端、Cotovia 的加利西亚语 和西班牙语转写规则、AhoTTS 的巴斯克语语言处理、 N3 推理机 EYE,以及 OWL 2 DL 推理机 HermiT。C、C++ 和 Java,大多数已经存在超过十年, 但在各自的领域里仍然是能找到的最好的东西。

动机很平常。一个能对加利西亚语做音素化的 C 程序很棒,直到你想把它塞进 ARM 板上的 Python 语音技术栈里。那时你就需要编译器、工具链、交叉编译、每个平台各自的打包方案, 以及一个必须在其间编排文本的 subprocess 边界。一个 Java 推理机需要 JVM。纯 Python 只需要 pip install。它也更易读:你可以打开决定重音落在哪里的那个文件并直接修改, 而不必了解原始构建系统是怎么运作的。

这些移植是半自主完成的。AI 阅读原始源码并写出 Python 代码;人类主导工作,并将产出 结果与原始二进制文件进行比对校验。在其中几个项目里,我们这边从来没有人读过原始源码。 是模型读的。我们读的是差异对比和一致性测试。

这就留下一个我们必须做出决定、却无法回答的问题:结果是不是一部衍生作品,它归谁 所有?

我们是工程师。这里的内容都不是法律意见,我们也没有资格给出任何法律意见。这只是对 我们所做决定及其背后理由的描述。

两个总被混为一谈的问题

通过阅读源码来重新实现一个程序,并不新鲜。自从有了 Python,人们就一直在把 C 重写 成 Python。新鲜的是这次的安排:阅读者是机器,实现者是同一台机器,而回路中的人类从未 见过原始代码。

这里有两个问题,而几乎每一次相关讨论都会把它们合并成一个。它们其实是独立的。

  1. 产出物到底能不能被拥有? 著作权归属于有作者的作品。如果代码是机器生产的, 谁是作者?
  2. 产出物是不是输入内容的衍生作品? 无论谁是作者——如果确实有作者的话——结果 是否侵犯了原作的权利?

你可以对其中一个问题回答”是”,对另一个回答”否”,任意组合都可能。请把这两个问题 分开来看。

由于后文都建立在这些词汇之上,先说明一些术语。衍生作品(derivative work) 是基于已存在作品的作品——翻译、改编、移植。创作衍生作品的权利属于原作的著作权人。 Copyleft(著佐权) 许可证(GPL 家族)允许你使用和修改代码,条件是你分发的成果 必须保持在相同条款之下。宽松式(permissive) 许可证(MIT、Apache-2.0、BSD) 基本允许你做任何事,包括把结果放进专有软件里。LGPL 介于两者之间:著佐权适用于 库本身,但把它链接进更大的程序并不会强制那个程序也开放。所有这些都建立在著作权之上。 只有当存在可以主张的著作权时,它们才生效。

问题一:是否存在作者?

著作权需要一个人类作者。美国版权局一贯坚持这一立场,在 Thaler v. Perlmutter 一案中, 哥伦比亚特区巡回上诉法院也表示同意:《著作权法》“要求任何符合资格的作品最初必须由 人类创作”(No. 23-5233, D.C. Cir., 2025 年 3 月 18 日;最高法院于 2026 年 3 月拒绝 调卷复审)。欧洲标准形式不同,但落点相似——保护要求”作者自己的智力创作” (author’s own intellectual creation),这预设了存在一个进行创作的作者。

这两种立场都没有说借助 AI 完成的工作就不受保护。它们说的都是:机器独自生成的部分 不受保护。分界线穿过作品内部,而不是绕开它,具体落在哪里取决于人类贡献了多少。在我们 的移植工作中,人类的贡献是真实存在的,但很薄:选择移植目标、组织软件包结构、判断一致性 测试的失败情况。这并不足以明显地让我们成为转写规则的作者。

这就产生了一个尴尬的对象。许可证是权利人授予的许可。如果没有人对产出物享有权利, 仓库根目录下的许可证文件就只是装饰品。请注意这个论点会走向何方:它首先吞噬的是自己 的许可证。任何主张机器生成代码不受任何人拥有的人,都是在主张自己发布条款不可执行—— 这甚至还没轮到讨论上游的权利。

问题二:它是不是衍生作品?

这个问题不在乎谁是作者。侵权与否取决于是否接触过原作,加上是否与其受保护的 表达(expression)——也就是这个东西被写出来的具体方式,而不是它做了什么——存在 实质性相似。

我们确实接触过。模型读过源码。这一半没有争议。

相似性的那一半才是有意思的地方,而且语言的改变所起的作用比人们预想的要小。把一部 小说翻译成另一种语言会产生一部衍生作品;这是教科书式的例子。改变语言可以驳倒逐字 抄袭的指控。但它驳不倒关于结构的指控——变换的顺序、拆分成函数的方式、规则表的形态、 边界情况被划分的方式。

同样值得明说的是:工具不会给任何东西”洗白”。如果你指挥一次复制并发布了结果,做这件 事的人就是你。“是模型写的”并不比”是编译器生成的”更能构成抗辩。

另一方最有力的论点

有一种严肃的观点认为,跨语言的重新实现是没问题的,它值得被完整地陈述,而不是被 一笔带过。

SAS Institute v World Programming 案(欧盟法院,C-406/10,2012 年 5 月 2 日)中, 法院裁定”计算机程序的功能,以及计算机程序为运用其某些功能而使用的编程语言和数据 文件格式,均不构成该程序的一种表达形式”。因此它们不受著作权保护。《软件指令》 (2009/24/EC,第 1(2) 条)对程序任何要素背后的思想和原则也作出了同样的规定。法院 还裁定,被许可人可以研究和观察一个程序的行为以确定其背后的思想,并将其重新实现。

这不是一个技术细节。它意味着一个音素化器所做的事——这个字素序列,在这个上下文中, 变成那个音素——不属于任何人。加利西亚语的重音规则是关于加利西亚语的事实。OWL 2 的 直接语义是一份已发布的 W3C 规范。按照这种解读,一个重现行为而非表达的重新实现是 合法的,而跨语言的重写比复制粘贴离侵权要远得多。

这个论点与我们情况之间的差距在于来源。SAS 案讲的是研究行为。而我们的模型读的 是代码。

已经存在的先例,以及它能延伸多远

“机器产出没有作者,所以不产生著作权”这个论点不是一个思想实验。它在整个行业的 生产实践中都是支撑性的。模型蒸馏和合成训练数据都建立在这个论点之上。

对此最清晰的公开表态来自 Kokoro-82M, 一个广泛使用的开放 TTS 模型。它的模型卡说明该模型完全在宽松许可或不受著作权保护 的音频上训练,并在允许使用的来源中列出了:

Synthetic audio generated by closed TTS models from large providers

(由大型提供商的闭源 TTS 模型生成的合成音频),并附有一条脚注,指向美国版权局的 AI 政策指引。这里的推理链条 和上面一样:音频是由机器生成的,机器产出没有人类作者,所以其中不产生著作权,所以 在其上训练没有什么可侵犯的。该模型以 Apache-2.0 发布。模型卡也划出了一条界线—— 它排除了来自开放 TTS 模型的合成音频以及自定义克隆的声音——这表明作者们思考过 这个论点在哪里停止,而不是把它套用到一切上面。

这里有一点对移植工作来说很重要。这个先例解决了问题的另一半。

Kokoro 的论点是关于输入的。他们所消费的内容本身就是机器生成的,所以他们主张 这些内容原本就不带有著作权。输入不受保护,因此没有什么可继承的。

我们的情况正好相反。我们所消费的内容——espeak-ng 的 C 代码、Cotovia 的 C++ 代码、 HermiT 的 Java 代码——毫无疑问是人类写的,受著作权保护,由数十年前具名的人在具名 的大学里创作。而输出的内容是机器写的。“AI 产出不产生著作权”这个论点落在我们的 输出上,而不是我们的输入上。它不会向上游传导。这再一次是一个会削弱我们自己许可证、 却对上游的权利丝毫无损的论点。

还有一个值得注意的不对称之处。Kokoro 剩余的风险其实基本不是著作权问题,而是 合同问题。闭源提供商的服务条款通常禁止用其输出去训练竞争模型,而你同意过的 条款不会因为其产出被证明不受著作权保护而自动失效。著佐权的运作方式不一样。没有人 点击”我同意”来接受 GPL。它是权利人单方面授予的许可,只有在你需要那份许可的时候—— 也就是说,只有当你所创作的东西是衍生作品的时候——它才对你有约束力。

于是一切又归结到那个没有人回答过的唯一问题上。如果一个跨语言、由机器写成的重新 实现不是衍生作品,那么 GPL 从未生效,它的任何条款都不适用。如果它是衍生作品,那么 GPL 从第一行代码起就已生效。不存在第三种状态,再多关于 AI 作者身份的争论也无法 动摇这根指针。

洁净室,以及两个模型是否构成一个洁净室

对这个问题的经典解法正是”洁净室”(clean room)协议,值得精确地描述一下,因为它 的形式很关键。

一个团队阅读原始代码,写出一份功能规格说明:程序做了什么,以行为的方式描述。另一个 从未见过原始代码的团队,只根据这份规格说明来实现。第二个团队的产出可以被证明并非 抄袭自他们从未见过的表达。个人电脑的 BIOS 正是这样被重新实现的,这也是那次重新 实现得以幸存下来的原因。

一个显而易见的现代做法是,用一个模型来阅读和描述,再用另一个上下文全新的模型来 实现。从结构上看,这是同一个协议。这算不算洁净室?

它的形式是对的。但洁净室不是一个技术构造,而是一个证据性构造。它全部的价值 在于事后能够向那个假定你作弊的人证明这种分离确实存在。所以这种”双模型”版本只有 在整个过程始终保持纪律的情况下才有意义:

  • 双方真正从不共享上下文。不是”我们让它忘记了”——而是分开的运行、分开的记录。
  • 规格说明只承载行为,别无其他。不能有模仿原始代码控制流的伪代码。不能有标识符名称。 不能有函数顺序。这些都属于表达,一份充满这些内容的规格说明只是套了件外衣的原作。
  • 双方的记录都要保存下来,因为一个无法用证据证明的洁净室只是一个说法。

如果阅读那一方泄露了结构,污染就会直接穿透,你得到的就是一个多花了几步、多花了一大笔 token 费用的衍生作品。

我们没有这样做。执行实现的模型直接阅读了源码。这正是为什么 pycotovia 的 README 在仓库里公开写着:

Because the implementing AI read the GPL source, this is not a clean-room reimplementation and we make no such claim. It is a source-derived port.

(因为负责实现的 AI 阅读了 GPL 源码,这不是一次洁净室式的重新实现,我们 也不作此主张。这是一次源码衍生的移植。)

我们宁愿现在就把这句话写下来,也不愿以后再去回答这个问题。

我们做了什么

我们保留了上游的许可证。

espyak 采用 GPL-3.0-or-later,与 espeak-ng 一致。这甚至算不上一个疑难案例:该软件包原封不动地打包了 espeak-ng 自己的数据 文件——dictsourcephsourcelang——任何关于作者身份的理论都碰不到我们原样 复制的文件。上游的数据就在这个 wheel 包里面,所以上游的许可证也随之而来。

pycotovia 采用 GPL-3.0,与 Cotovia (GPL-3.0+)一致。ahotts-g2ppyAhoTTS-Iparrahotsa 采用 GPL-3.0,与 AhoTTS 一致——其许可证文件对语言处理部分标注为 GPL-3.0+。 pyeye 采用 MIT,与 EYE 一致。著佐权进, 著佐权出;宽松式进,宽松式出。

我们这样做,并不是因为我们已经确定这是必须的。我们这样做,是因为这种不对称性无需 知道答案就能替我们做出决定。

我们仍然照常以开源方式发布。著佐权对我们来说几乎没有代价——唯一真正的代价是某个 客户想把代码放进专有产品里,而对于这几个特定的库来说,这种情况很少见。所以在并非 严格必须的情况下选择著佐权,代价几乎为零。

另一种错误则不对称。给本该采用著佐权的东西贴上宽松式许可证,是一个被别人在事后 公开发现的问题,而且是在别人已经在你无权提供的条款下构建了东西之后才发现的。要 解开这个局面,意味着要联系每一个下游用户。

这种不对称性,也是为什么这种错配整体上值得留意的原因。一个 LGPL 原作的结构化移植, 不会仅仅因为用另一种语言重写就自动变成 Apache-2.0——而这正是那种容易产生、却难以 察觉的错配,因为没有任何东西会报错。构建能通过。测试能通过。许可证头文件只是一个 文件。HermiT 是 LGPL 许可,所以我们那个 Python 移植版本的许可问题,正是我们目前 正在重新审视的案例之一——这正是那种平凡而正确的结果:你去检查,然后修正需要修正 的地方。

在如此悬殊的不对称之下,你不需要解决那个法律问题就能做出决定。你只需要选择那条 即使出错也能承受的分支。

同一个问题,指向相反的方向

上面说的都是我们生产的代码。同样的逻辑也适用于我们接收的代码。有人向我们的某个 仓库提交了一个 pull request。这个补丁是模型写的。他们授予了我们什么?

大多数项目用 Developer Certificate of Origin (DCO,开发者原创证书)来处理这个问题——也就是提交信息底部的 Signed-off-by: 那一行。 这是贡献者在签署时所确认的一句简短声明:他们自己创作了这份贡献,或者它来自一个 许可证兼容的来源,并且他们有权在项目条款下提交它。它被有意设计得很轻量。不需要 律师,不需要文书,每个提交一行字。Linux 内核和 QEMU 等众多项目,正是这样确立其 代码来源的。

对于一个由机器写成的补丁,这两个前提都不是理所当然成立的。而无论你选哪条分支, 分岔的结果都是一样的。

如果机器生成的产出不产生著作权,那么贡献者对它就不享有任何权利。也就没有什么可以 授权给你的。

如果换一种方式,把它视为衍生自其训练数据,那么权利——不管这些权利是什么——属于 写出那些数据的人。贡献者手里依然一无所有,依然没有什么可以授权给你。

无论哪种方式,他们都无法授予自己并不拥有的东西。这个签名并非不诚实。贡献者是出于 善意签署的,也确实做了这份工作。它只是空的:转让了一件从来就不属于他的东西。

实际的后果没有听上去那么令人不安,而这两条分支的差异很大。

在第一条分支上,你根本不需要授权。没有人拥有的材料,任何人都可以使用。接受这个 补丁没有问题,也不会发生坏事。悄悄发生变化的是另一个方向:著佐权建立在著作权之上, 它无法附着在不产生著作权的材料上。一个不断累积由机器写成的补丁的 GPL 项目,累积 的是一些其自身许可证可能覆盖不到的部分。许可证仍然在管辖着这个作品在被分发时的 样子。但它内部那个可执行的核心,会悄悄地、缓慢地变薄,没有人会注意到。

第二条分支才是真正有杀伤力的。如果一个模型逐字复现了记忆中的训练数据——这确实会 发生,常见的惯用写法和知名实现比新颖逻辑更容易出现这种情况——那么你就是在一个 无从核实的贡献者的保证之下,接受了别人受著作权保护的代码。DCO 全部的价值,就在于 签署人本身处于能够知情的位置。而在这里,他们并不处于那个位置。

Debian 正在处理这个问题。一项关于 LLM 使用的一般性决议 在 2026 年 7 月 23 日进入讨论阶段,议案单上有五项提案。它们涵盖了整个光谱:提案 A 将修改《社会契约》,全面禁止对软件包、文档和网络资源做 LLM 辅助的贡献;提案 C 要求 贡献者尽量避免使用 LLM,要求项目沟通内容必须由人类独自撰写,并允许各个维护者自行 施加禁令;提案 B、D 和 E 则在一定条件下允许 AI 辅助工作,这些条件分别建立在许可证 核验、贡献者问责、信息披露,以及限制向云服务发送机密材料之上。截至本文撰写之时, 讨论仍在进行,尚未有定论。

这已经是第二次尝试了。2024 年的一次早期尝试 没有形成决议就结束了,而当时停下来的理由值得记住:反对采取行动的意见并不是认为 这种担忧毫无根据,而是认为一条没有人能够执行的规则不值得被采纳。你无法只看一份 diff 就判断出它是谁写的。

这不是一个边缘的担忧。它打击最重的恰恰是那些对代码来源最为谨慎的项目,因为一个 基于 DCO 的项目,其关于代码从何而来的整套模型,都靠着那一份声明支撑。

我们还没有决定该如何处理这个问题,而且我们也没什么资格去要求严格。我们发布的就是 模型写的移植代码。一个既发布机器写的代码、又拒绝接受机器写的贡献的项目,同时持有 两个相互矛盾的立场,而我们不想这样。摆在面前的诚实选项,和 Debian 正在权衡的一样—— 信息披露、贡献者问责,或者一条无法核实的规则——而我们还没有选定其中之一。

争论所沿的另一条轴线

Debian 的辩论是关于来源和许可的。这不是唯一的一条轴线,而第二条轴线和著作权毫无 关系。

Codeberg,一个 FLOSS 代码托管平台,在 2026 年 7 月通过了两项经成员批准的决议, 并阐述了其理由, 措辞几乎没有涉及许可证。他们的反对意见关乎成本和精力:被转嫁到所有人身上的能源与 硬件消耗;迫使小型代码托管平台采取防御措施、也因此妨碍了普通用户的爬虫流量; 发布后从不维护的一次性”氛围编码”(vibe-coded)项目;以及施加在审查者身上的负担:

Maintainers are under an increased work-load due to people submitting (often well-meaning) low-effort, LLM-generated contributions that require substantial amounts of time to review.

(维护者正承受着日益增加的工作负担,因为人们提交了大量——通常是出于善意的—— 低投入、由 LLM 生成的贡献,而审查这些贡献需要耗费大量时间。)

他们的使用条款现在不再鼓励此类项目,由版主逐案适用,而不是大规模删除。

所以目前流传着两个独立的问题,一个项目可以落在这张网格的任何位置:机器写成的代码 是否能被许可授权,以及生态系统是否能承受这样的数量。Debian 正在就第一个问题投票, 尚无结论。Codeberg 已经就第二个问题采取了行动。任何一个结果都不能解决另一个问题, 而一个项目对这两个问题给出的答案,基本上互不相关。

我们不会假装已经解决的那部分

我们或许根本不需要做这一切。

把这三个论点放在一起考虑。功能不受保护——欧盟法院直接这么裁定过。纯粹由机器生成 的产出可能没有人类作者,所以可能不产生需要担心的新著作权,而且尴尬的是,也就没有 我们自己的著作权。而一个真正严守纪律执行的双模型协议,也许就是一个真正的洁净室, 在这种情况下,这次移植根本没有接触过受保护的表达。

如果这三点都成立,其中一些移植本来是可以问心无愧地采用宽松式许可证的。如果一点都 不成立,那么我们保守的选择就是完全正确的。我们不知道究竟是哪一种情况,我们也没有 去验证过。我们没有兴趣成为那个把这个问题盖棺定论的案例。

这个问题不会因为被忽视而消失。这种移植正变得越来越普遍——现在它很廉价,而且有 大量无人维护的 C 代码值得被搬到一个可以被维护的地方去。每一次这样的移植都会面对 同样的两个问题,而大多数移植会用不去问它们的方式来”回答”。每一个接受了非自己所写 补丁的项目也会如此——也就是说,所有项目都会如此。无论你是在写代码,还是仅仅在 接受代码,这些问题都会到来。