Linux 无线子系统维护者对 AI 生成的补丁公开表达过明确的拒绝态度,这件事在内核开发社区里引发了不小的讨论。很多人以为维护者是在否定 AI 写代码这件事,实际上他们否定的是一类被称为“AI Slop”的补丁:看起来结构完整,实际上缺少上下文、缺少理由、缺少验证,甚至可能连编译都没有通过。真正让维护者疲惫的,不是“补丁由谁生成”,而是“提交者有没有对补丁负责”。
这篇文章会围绕这条主线展开:先说明维护者为什么对低质量 AI 补丁如此敏感,再梳理 Linux 无线补丁从生成到合入经历的完整链路,然后给出“用 AI 辅助生成补丁、但由人来保证质量”的可行工作流,最后提供一套提交前自查清单和常见拒绝原因速查表。适合三类读者阅读:准备给内核社区提交补丁的开发者、使用 Realtek 等无线网卡驱动并需要维护补丁的嵌入式工程师、以及希望在团队内部引入 AI 辅助代码开发但担心代码质量失控的技术负责人。
1. 维护者真正不满的不是 AI,而是“AI Slop”补丁
1.1 事件结论需要先拆开看
Linux 无线子系统维护者每天要处理大量补丁,覆盖 mac80211/cfg80211 框架、各类无线网卡驱动、以及和蓝牙共存、电源管理、固件加载等底层逻辑。这些代码直接运行在用户的网卡上,补丁一旦出错,轻则掉线,重则内核崩溃。
维护者在公开讨论中表达对 AI 生成补丁的不满,本质上是在表达对“提交质量”的不满。AI 本身不会提交补丁,补丁最终由开发者发送,开发者必须为补丁的正确性负责。如果开发者把 AI 生成的代码未经检查就发到内核邮件列表,维护者就会把它当作“垃圾补丁”处理,而不是花时间逐行猜测提交者想做什么。
这里要区分两个概念:AI 辅助开发,和 AI 自动生成补丁。前者是使用工具提高效率,后者是把工具当作“自动提交器”。维护者反对的一直是后者。
1.2 什么是“AI Slop”补丁
“Slop”在英文网络社区里常用来形容大量、廉价、未经筛选的 AI 输出内容。“AI Slop”补丁就是指那些带有明显 AI 生成痕迹、但缺少工程验证的补丁。这类补丁通常有下面几个特征:
- 只修改了代码,但没有说明“为什么改”。
- commit message 写得很长,却没有一句能解释实际问题。
- 补丁上下文是从别的驱动里复制来的,函数名和调用路径对不上。
- 缺少 Signed-off-by、Reported-by、Tested-by 等必要标签。
- 没有经过编译验证,甚至格式错误导致 patch 无法应用。
这些补丁最危险的地方在于“看起来合理”。AI 生成的代码通常语法正确、命名规范,但它并不理解真实硬件的行为。无线驱动中常见的固件版本判断、寄存器读写、中断处理逻辑,一旦“看着像那么回事”的代码进入主线,排查问题的时间成本会非常高。
1.3 维护者的时间成本是根本问题
内核维护者大多是志愿工作或者公司支持的开发者,他们不可能替每个提交者做完整测试。维护者审查一个补丁时,真正在看三件事:
- 这个改动是否解决了真实问题。
- 改动是否影响了其他路径。
- 提交者是否理解自己的代码。
AI 生成的补丁往往只能回应第一点,而且经常是“看起来回应了”。一个补丁如果无法让维护者快速理解“为什么会有这个改动”,就会被要求重写或者直接拒绝。
维护者的时间非常有限。一个高质量的补丁应该把“审查成本”降到最低,而不是增加审查负担。这是理解所有拒绝反馈的底层逻辑。
2. Linux 无线补丁从生成到合入要过哪些关卡
2.1 无线子系统与驱动开发现状
Linux 内核的无线子系统主要由 cfg80211 和 mac80211 组成。cfg80211 负责向上层提供配置接口,mac80211 负责管理无线协议状态机,具体的驱动则接入这两个框架。常见的无线驱动包括 Intel 的 iwlwifi、Qualcomm Atheros 的 ath 系列、MediaTek 的 mt76、Realtek 的 rtw88/rtw89 等。
很多 Realtek 网卡型号最初只有厂商驱动的 out-of-tree 版本,后来才逐步被社区整合进主线。因为这个过程涉及大量驱动移植工作,很多人会尝试用 AI 工具帮忙写代码、生成补丁、补 commit message。这也解释了为什么“Realtek 8821CE”“Realtek 8852BE”“Realtek 8812BU”这些关键词经常和“Linux 补丁”一起出现。
需要注意的是,out-of-tree 驱动和内核主线驱动对补丁的要求并不完全相同。out-of-tree 驱动可以由厂商维护者决定合并规则,主线内核则必须遵守内核社区的统一流程。下面重点讲主线补丁的标准链路。
2.2 一次补丁提交的完整链路
一个补丁从开始编写到被维护者合入,至少经历下面这些环节:
- 准备内核源码,明确当前分支基线。
- 修改代码,确保可以编译。
- 本地测试功能,至少验证正常路径。
- 运行
scripts/checkpatch.pl检查代码风格。 - 使用
git commit -s提交,并写清楚提交信息。 - 使用
get_maintainer.pl找到正确的维护者和邮件列表。 - 使用
git format-patch生成补丁文件。 - 发送补丁给维护者和相关列表。
- 收到 review 意见后修改,发送 v2、v3。
- 维护者合入补丁,进入 next 或 merge window。
AI 工具可以参与前四步中的一部分,但第 5 步到第 8 步必须由人来确认。很多“AI Slop”补丁恰恰在第 8 步被拦下来,因为维护者一看提交信息就知道补丁没有被认真对待。
2.3 工具链对齐:format-patch、checkpatch、get_maintainer
无论补丁是不是 AI 生成的,工具链对齐都是基本要求。先看维护者查询命令:
./scripts/get_maintainer.pl --separator , --nokeywords 0001-wifi-sample-fix-description.patch这个命令会列出该补丁涉及的维护者、子系统、邮件列表。发送补丁前一定要运行,不能只发给一个看起来相关的维护者。
再看代码风格检查:
./scripts/checkpatch.pl --no-tree --strict 0001-wifi-sample-fix-description.patch--strict会开启更严格的检查,包括注释风格、行长度、括号位置等。对于首次提交,建议提前用--fix参数自动修复部分风格问题:
./scripts/checkpatch.pl --no-tree --strict --fix 0001-wifi-sample-fix-description.patch注意--fix会修改原始文件,不是直接修改 patch,所以运行前先确认工作区是干净状态。
最后是生成补丁:
git format-patch -1 -o patches/-1表示生成最近一次提交的补丁,-o patches/指定输出目录。生成后要打开补丁文件,重点检查补丁头和 diff 内容是否完整。
补丁不是一段代码片段,而是提交者写给维护者的一封说明信。代码只回答问题“改了什么”,提交信息必须回答问题“为什么改”。
3. 用 AI 辅助补丁开发正确的工作流
3.1 AI 适合做“草稿”而不是“成品”
AI 在补丁开发流程里能帮上忙,但只适合产出草稿,不适合产出最终提交物。具体来说,下面这些环节很值得用 AI:
- 根据代码 diff 生成 commit message 的初始草稿。
- 解释一个陌生函数调用链的作用,帮助提交者理解代码。
- 把某种风格的代码转换成内核风格。
- 整理编译错误日志,协助快速定位问题。
这些环节的共同点是“结果会被人工再次确认”,而“AI 生成一个可以直接发给维护者的补丁”并不符合这个条件。差异在于:commit message 草稿可以改,错误日志理解可以帮助排查,但补丁 diff 是最终交付物,一旦发送,维护者看到的每一行都必须由提交者负责。
3.2 AI 生成补丁的典型问题和识别方式
AI 补丁虽然语法正确,但在内核审查里经常会暴露出一批规律性问题。下面这张表总结了常见情形:
| 典型问题 | 现象 | 本质原因 | 正确做法 |
|---|---|---|---|
| 上下文不对 | 补丁改的是 A 驱动,却引用了 B 驱动的结构体 | 模型缺乏内核代码库上下文 | 先完整阅读驱动文件,再让 AI 生成参考 |
| 提交信息空洞 | “Fix issue”或“Improve code”没有任何细节 | 没有把真实调试过程写进提示词 | 用真实日志、错误现象、测试结果重写提交信息 |
| 缺少合法标签 | 没有 Signed-off-by、Fixes、Reported-by | 提交者不了解内核补丁规范 | 人工补充,不能只依赖 AI |
| 未验证代码 | 代码依赖某宏或函数,但实际不存在 | 模型基于概率生成,不是真实编译 | 本地编译,至少一次性通过 |
| 风格不一致 | 使用 tab 与空格混用、非内核注释风格 | 没有指定内核风格 | 先跑 checkpatch,再让 AI 修改格式问题 |
这五个问题的共同点是:AI 只能基于训练数据推测,无法感知当前内核仓库的真实状态。因此,审查补丁的人必须能回答“这段代码引用的函数在哪里定义”这个问题。如果回答不了,就不应该发送。
3.3 推荐工作流与脚本示例
一个可靠的工作流可以定义为五步:
- 人工定位问题,收集现象、日志、复现环境。
- 让 AI 根据这些信息生成补丁或 commit message 草稿。
- 人工阅读草稿,对照源码确认每一行 diff 是否有效。
- 本地编译、运行测试、跑 checkpatch。
- 确认无问题后,发送补丁。
为了减少人为疏漏,可以在仓库里放一个提交前检查脚本。下面是一个简单的 shell 示例:
#!/usr/bin/env bash set -euo pipefail PATCH="${1:-}" if [[ -z "$PATCH" ]]; then echo "usage: $0 <patch-file>" exit 1 fi echo "[1/3] checkpatch" ./scripts/checkpatch.pl --no-tree --strict "$PATCH" || true echo "[2/3] required tags" for tag in "Subject:" "Signed-off-by:"; do if grep -q "$tag" "$PATCH"; then echo "OK - $tag" else echo "MISS - $tag" exit 1 fi done echo "[3/3] patch stat" git apply --stat "$PATCH"脚本的作用不是判断补丁是否“正确”,而是强制提交者在发送前至少思考三件事:代码风格、必要标签、改动范围。如果 AI 生成的补丁连这三步都过不了,就不应该进入人工 review。
这个脚本适合放在内核仓库之外,比如个人开发目录下,避免污染内核源码树。生产环境还可以把它接入 CI,任何未通过静态检查的补丁都不能进入合并队列。
4. 一个可审查补丁的教学示例
4.1 示例目标:修正驱动模块参数说明
为了把上面流程串起来,下面用一个教学示例演示。假设某个无线网卡驱动中有一个模块参数disable_msi,原本用于控制是否禁用 MSI 中断,但注释写得不清楚,用户无法理解默认行为。我们要修改描述,让它更易读。
这是一个很小的改动,但足以展示补丁格式、commit message 和 checkpatch 检查的完整过程。下面的代码片段只是示例,实际驱动中的函数和参数名以你的代码为准。
修改前:
static bool disable_msi; module_param(disable_msi, bool, 0644); MODULE_PARM_DESC(disable_msi, "Disable MSI interrupts (0 = enable MSI, 1 = disable MSI)");修改后:
static bool disable_msi; module_param(disable_msi, bool, 0644); MODULE_PARM_DESC(disable_msi, "Force legacy interrupts instead of MSI (default: false)");这个修改看起来简单,但它真正在改的是“接口文档”。用户模块参数时,描述会影响加载时的提示信息。如果描述只写“Disable MSI interrupts”,用户无法知道默认值是什么,也不知道是否应该主动打开。
4.2 修改代码和提交信息
提交信息是补丁的一部分,不能只写“Update description”。要说明为什么原来的描述不够好,以及新的描述想解决什么问题。
示例提交信息:
wifi: sample: make module parameter description clearer The previous description only mentioned "Disable MSI interrupts" without explaining the default value or why a user would want to disable MSI. Reword it to describe the effect and the default. Signed-off-by: Your Name <you@example.com>注意格式:第一行是标题,使用“子系统: 模块: 简短描述”的格式。空一行后写正文。最后是Signed-off-by。这个标签不是口头承诺,而是表示提交者熟悉开发者来源证书并同意代码被合入内核。
如果修改是为了修复某个具体的 bug,还需要加入Fixes:标签,指向第一次引入问题的提交哈希。AI 很难自己准确判断该写哪个提交,所以这个标签通常需要人工补充。
4.3 生成补丁、自查并输出 diff
修改完成后,按下面顺序操作:
git add drivers/net/wireless/sample/sample.c git commit -s git format-patch -1 -o patches/git commit -s会自动添加Signed-off-by。如果之前用git commit提交,没有加-s,补丁会缺少必要标签,维护者会直接要求重新提交。
生成的补丁文件大致长这样:
From 1234567890abcdef1234567890abcdef1234567 Mon Sep 17 00:00:00 2001 From: Your Name <you@example.com> Date: Mon, 1 Jan 2024 10:00:00 +0800 Subject: [PATCH] wifi: sample: make module parameter description clearer The previous description only mentioned "Disable MSI interrupts" without explaining the default value or why a user would want to disable MSI. Reword it to describe the effect and the default. Signed-off-by: Your Name <you@example.com> --- drivers/net/wireless/sample/sample.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/net/wireless/sample/sample.c b/drivers/net/wireless/sample/sample.c index aabbccdd..eeff0011 100644 --- a/drivers/net/wireless/sample/sample.c +++ b/drivers/net/wireless/sample/sample.c @@ -123,7 +123,7 @@ static bool disable_msi; module_param(disable_msi, bool, 0644); MODULE_PARM_DESC(disable_msi, - "Disable MSI interrupts (0 = enable MSI, 1 = disable MSI)"); + "Force legacy interrupts instead of MSI (default: false)");发送前再运行一次 checkpatch:
./scripts/checkpatch.pl --no-tree --strict patches/0001-wifi-sample-make-module-parameter-description-clearer.patch正常输出应为:
total: 0 errors, 0 warnings, 0 checks此时才可以把补丁发送给维护者。这个过程无论有没有 AI 参与都不能省略。如果 AI 生成的是完整补丁,必须把它还原成上面的检查路径,而不是直接发送。
5. 提交前自查清单与维护者拒绝原因速查表
5.1 提交前 10 项自查
发送补丁前,可以对照这份清单逐项确认。任何一项不通过,都不要发送。
- 补丁是否基于最新的上游分支生成,而不是基于本地随意改过的基线。
- 是否使用
git format-patch生成,而不是手动复制 diff。 - 补丁头部是否包含
Subject: [PATCH]且标题符合“子系统: 模块: 描述”格式。 - 是否有
Signed-off-by,且填写的邮箱与提交邮箱一致。 - 是否用
checkpatch.pl检查并清零关键错误。 - 是否在真实环境中编译过,编译日志中是否有与补丁相关的 warning。
- 是否运行过基本功能测试,至少验证正常路径。
- 是否正确使用
get_maintainer.pl找到维护者和邮件列表。 - 是否在补丁正文里说明了“为什么改动”,而不只是“改了什么”。
- 如果这是第 2 版或第 3 版补丁,是否在标题中标注
[PATCH v2],并在正文中说明相对上一版的变化。
这份清单并不复杂,但几乎所有的“AI Slop”补丁都会在某一项上失败。
5.2 常见拒绝原因速查表
维护者拒绝补丁时,通常会给出原因,有时只是简单回复 “NACK” 或者 “Please fix”。不要看到拒绝就灰心,把原因对照下表处理:
| 拒绝反馈或现象 | 常见原因 | 检查方式 | 处理建议 |
|---|---|---|---|
| 缺少 Signed-off-by | 提交时没有加-s | grep 补丁文件 | 重新生成补丁并补充标签 |
| 无法应用补丁 | 基线不对或上下文偏移 | git apply --check | rebase 到最新上游 |
| checkpatch 报错 | 风格不符合内核规范 | 运行 checkpatch | 用--fix自动修正或手动修改 |
| 提交信息没有解释为什么 | AI 生成的空洞描述 | 阅读 commit message | 重写正文,加入实际调试信息 |
| 发送给了错误维护者 | 没有运行 get_maintainer | 查看补丁头 | 重新发送到正确列表 |
| 缺少 Fixes 标签 | 修复 bug 但没有关联提交 | 查找引入 bug 的 commit | 用git log -S定位并补充 |
| 改动太宽泛 | 一个补丁混入多个不相关问题 | 查看 diff stat | 拆分成多个独立补丁 |
| 疑似 AI 生成且未验证 | 代码引用不存在的符号 | 尝试编译并检查符号 | 逐行审查,补充测试 |
这张表也可以作为 patch review 的工具清单。无论是送审前还是收到反馈后,按表操作都能降低来回次数。
5.3 维护者反馈后如何复盘
收到 review 意见后,不要只修改代码,还要检查反馈背后暴露的流程问题。如果维护者说“这段代码没有错误处理”,除了补上错误处理,还要反思为什么第一次提交漏掉了。如果维护者说“提交信息太模糊”,应该回去收集当时的实际日志,而不是把 AI 生成的内容再润色一遍。
对于 AI 辅助开发的团队,建议把每次 review 意见记录下来。积累一段时间后,就能形成团队的“review 缺陷库”,再把缺陷库写进 AI 提示词中,让下一次生成避免同类问题。这个过程才是 AI 辅助开发的正确闭环:不是让 AI 直接产出最终结果,而是让 AI 在人类反馈中逐步逼近社区可接受的质量。
6. 在开源协作与生产内核维护中的实践建议
6.1 开源补丁协作的底层契约
内核补丁的提交本质上是一个协作契约:提交者承诺补丁是自己的工作或有权提交,维护者承诺会认真审查。Signed-off-by是这个契约的凭证,它不只是格式要求,而是开发者证书的一部分。AI 工具无法承担这个承诺,它只是一个生成器,真正的责任主体永远是提交者。
这也是维护者对 AI 生成补丁保持警惕的重要原因。社区可以接受你“用了工具”,但无法接受你用工具替代“理解”。即使补丁被拒绝,只要你愿意解释背景、补充测试,维护者通常会给机会。最差的处理方式是发了一堆补丁,然后说“这是 AI 写的,我不太清楚为什么这么改”。
6.2 生产内核维护如何引入 AI 工具
如果你不是给上游社区贡献代码,而是在公司内部维护嵌入式 Linux 内核或驱动,AI 工具的使用尺度可以更灵活,但质量门禁不能放松。生产内核维护中,建议把 AI 工具限制在三个场景:
- 生成 backport 补丁的初稿,例如把上游修复移植到老内核。
- 根据编译失败日志生成排查建议。
- 自动整理内部补丁的 commit message 草稿。
这三个场景都要求最终结果经过同一套质量门禁:编译通过、检查清单通过、至少一个人 review。生产环境还应该额外关注补丁对应的产品验证,包括固件版本、硬件型号、无线吞吐、功耗、稳定性测试。不要因为补丁来自 AI 就降低验证标准,也不要因为补丁来自资深工程师就跳过验证。
6.3 长期价值:让“被审查过的代码”成为你的训练语料
如果团队正在训练或微调内部的代码辅助模型,最有价值的数据不是互联网上的通用代码,而是“被维护者接受过”的历史补丁和对应 review 对话。这些数据包含了大量上下文:为什么这个改动是必要的、reviewer 关注什么、哪些写法会被拒绝。
实际落地时,可以把历史补丁整理成规范化的记录,包括问题现象、补丁 diff、review 反馈、最终合入版本。用这些记录去校准 AI 提示词,模型会逐渐学会“如何写一个可审查的补丁”。这个工作比让 AI 直接生成代码更值得投入,因为它解决的是补丁最难的部分:上下文理解。
内核无线子系统的特殊之处在于驱动代码需要贴近硬件行为,AI 很难从训练数据里获得真实硬件寄存器、固件交互的完整知识。因此这个领域尤其适合“AI 出草稿、人做验证”的模式。使用 AI 补丁开发工具时,应当把提示词写得足够具体,给出实际驱动路径、函数名、错误日志、硬件型号,而不是泛泛地要求“帮我写个修复补丁”。
维护者的立场不是要拒绝效率工具,而是要求每个人对自己发出的补丁负责。对开发者来说,最好的应对方式不是放弃 AI,而是把 AI 当成一面能快速生成初稿的镜子,然后再用编译、测试、代码审查这面更可靠的镜子去照出问题。