
如果最近留意过 Linux 内核开发相关的邮件列表和技术讨论会发现一个高频词正在从 AI 应用层渗透到内核开发圈LLM。过去我们聊大语言模型说的是 chat、Agent、RAG但内核社区真正关心的不是让 LLM 写一个聊天机器人而是一个很具体的问题当 LLM 越来越多地参与驱动代码的生成、修改和审查时drivers/staging 目录到底应该执行什么样的策略这篇文章不是从 AI 应用开发者的视角去讲“怎么调用大模型接口”而是从内核维护和补丁评审的角度拆解LLM policy for drivers/staging/ going forward这个主题。我会先解释这个策略为什么出现在 staging 目录再说明一套可落地的策略应该包含哪些构成最后给出一个最小可运行的“LLM 预审补丁”流程示例包括配置、脚本、运行验证和常见排错。如果你正在参与内核驱动开发或者你在公司内部负责开源代码合入前的质量审查这篇文章能帮你回答三个问题LLM 在内核代码审查里到底能干什么、不能干什么怎么设计一套安全边界清晰的接入策略以及如何验证这套策略真的有效。1. 为什么 staging 目录会成为 LLM 进入内核的第一站先解释背景。drivers/staging 是 Linux 内核里一个特殊的目录专门用来接收还没有达到主线质量标准的驱动代码。新驱动可以先合并进 staging通过持续修复、清理、补测试逐步满足内核社区的代码规范再考虑移动到正式目录。对内核社区来说这个目录是“新代码进入内核的前置等待区”对很多硬件厂商和开源开发者来说这是让驱动被内核接受的快速通道。问题在于staging 目录长期存在两个矛盾。第一补丁数量多且重复性问题高。代码风格不符合checkpatch规范、缺少必要的错误处理、注释不清晰、Kconfig 依赖配置错误、内存分配没有检查返回值这些是非常典型的新驱动代码问题。维护者每天要花大量时间在“格式修正”和“基础健壮性检查”上真正需要深度判断的架构问题反而被挤占了。第二很多提交者并不熟悉内核社区的规范化流程。硬件工程师、嵌入式开发者、芯片厂商的 BSP 工程师擅长写驱动逻辑但未必熟悉内核的补丁格式、提交信息规范、review 流程。一个经验丰富的维护者扫一眼补丁能立刻发现十几处问题但让新手自己反复自查效率很低。这就是 LLM 的切入点。从当前技术能力来看大语言模型非常适合做“高频、低判断成本、有明确规则可循”的代码初筛。格式问题、命名问题、遗漏的错误分支、明显的资源未释放这些恰恰是 LLM 比较擅长的模式识别。而 staging 目录正好积累了海量同类补丁构成了天然的训练和测试场景。更关键的是staging 目录的实验成本相对低。它本身就是“未达到最终标准”的代码聚集地即使 LLM 建议有偏差不会直接破坏内核核心模块。所以如果要在内核社区中试验 LLM 辅助代码审查drivers/staging 是最合理的切入点。这也是相关讨论中把位置限定在drivers/staging/ going forward的原因范围先行避免在核心目录做不可控实验。但这里要给出一个明确判断LLM 适合放在“入口预筛”这一层而不是“出口决策”这一层。它可以帮维护者把 80% 的重复劳动消化掉但不能让它决定“这个驱动是否合格”。策略设计的核心不是让 LLM 变得更权威而是给它的使用划出边界。2. 所谓“LLM policy”到底在定义什么“policy”这个词很容易被误解成“我们是否允许用 LLM”。实际上允许或禁止只是一种最简单、最粗颗粒度的策略。真正有价值的 LLM 策略是在回答下面四个问题范围LLM 被允许处理哪些代码和哪些任务方式LLM 的审查结果是作为“建议”还是作为“阻断条件”责任如果 LLM 的建议有误谁负责最终判断审计LLM 给出的结果是否能被追溯、复现和评估这四个问题缺一不可。很多团队在引入 AI 辅助代码审查时只关注了“方式”比如写一个提示词然后把 LLM 输出贴到 PR 里。但如果没有定义范围和责任很快会出现两种极端要么 LLM 的建议被盲目接受引入隐性风险要么 LLM 的建议被维护者全部忽略工具形同虚设。从相关社区讨论来看更稳的策略是“分层治理”。也就是说不是一刀切地要求所有补丁都过 LLM而是按任务类型和代码路径进行分流。比如针对 staging 新驱动代码LLM 可以执行“格式与常见缺陷预筛”。针对已进入 RC 阶段的修复补丁LLM 不参与因为这类补丁风险高、时间敏感。针对安全相关修复LLM 可以帮忙检查但绝不能由 LLM 直接给出合入结论。另外策略必须有“人机分工”的描述。最合理的定位是把 LLM 视作“一个很勤奋但经验不足的初级审查员”。它可以快速找出可疑点但每个可疑点都需要具备内核开发经验的维护者确认。这个定位可以帮助团队避免两个极端过度信任和完全排斥。还有一个容易忽略的点是数据边界。内核补丁涉及厂商未发布的硬件信息、内部接口设计以及潜在的安全漏洞描述。如果把补丁内容直接提交给第三方 LLM API会带来信息泄露风险。因此策略中应当包括“哪些代码不允许发送到外部 LLM 服务”以及“是否需要在本地部署模型”。这一条在后续落地时会直接影响脚本设计。所以结论是LLM policy 不是一纸禁令也不是一份使用手册而是给 LLM 参与代码审查这件事建立一套可执行、可回滚、可问责的流程规范。3. staging 代码的典型特征与 LLM 适配性分析要设计策略先得知道 staging 代码里最常见的问题是什么。这里不做枚举式罗列而是用一张表把“典型问题类型”和“LLM 适配度”对应起来。问题类型典型表现LLM 适配度说明格式与风格缩进混乱、超长行、函数命名不规范高规则明确模式固定LLM 表现稳定基础健壮性未检查kzalloc返回值、缺少goto err清理高代码模式常见LLM 很擅长识别遗漏错误处理逻辑返回值判断错误、错误码映射不准确中LLM 能发现明显异常但对内核错误码语义理解有限并发与锁锁顺序不当、未正确使用mutex/spinlock低需要全局上下文LLM 容易给出误判架构与抽象驱动与总线层耦合过重、接口设计不合理低需要维护者经验和社区长期共识文档与注释Kconfig 说明缺失、模块描述不清晰高语义生成能力强适合检查覆盖度补丁元信息Signed-off-by缺失、提交信息不完整高强规则可代码化判断也适合 LLM 检查从这张表可以得出一个清晰的结论LLM 在 staging 目录的“初筛层”价值最大在“架构评审层”价值有限。很多新手在尝试用 LLM 做代码审查时犯的错误是让 LLM 看一个完整的驱动文件然后问“这个代码有什么问题”。输出结果往往非常笼统甚至会给出错误的优化建议。正确做法是给 LLM 定义非常窄的任务例如只检查本次补丁涉及的文件。只查找某个特定类型的问题。只输出符合规则列表的异常点。换句话说不是 LLM 本身能力不够而是任务定义太宽泛。审查任务越具体LLM 输出越可靠。这也是为什么策略中需要包含“任务清单”或“检查项列表”而不是一句“让 AI 审查代码”就完事。这里还要澄清一个常见误区LLM 不是checkpatch的替代品。checkpatch.pl是内核自带的规则检查脚本规则明确、执行稳定这类工作根本不需要 LLM。LLM 的真正优势是处理“没有现成脚本规则但又有明显模式”的问题比如“函数过长且责任不单一”“错误处理路径可能遗漏了某个条件”“新增的配置文件没有在 Makefile 中引用”。所以在实际策略设计中我更推荐的做法是先用传统工具做硬性规则检查再把 LLM 用在传统工具覆盖不到的地方。两者是接力关系不是竞争关系。4. 一套可落地的 LLM 审查策略设计现在我们进入“怎么设计一套策略”的部分。这里不讨论复杂的官僚流程只讲可执行的分层结构。我建议把整个流程设计成三层第一层传统静态规则层运行checkpatch.pl、编译检查、稀疏检查sparse、smatch等既有工具。这层不涉及 LLM负责拦截所有可以通过硬规则识别的问题。这一层的优势是确定性高、问题可复现、误报率可控。第二层LLM 预审层把通过第一层检查的补丁发给 LLM按预定义的任务清单做“常识性缺陷”预审。LLM 输出结构化结果格式是“问题位置 问题类型 可能原因 建议”。输出不直接标注“必须修改”而是标明“建议人工确认”。第三层人工评审层维护者查看第一层的工具输出和第二层的 LLM 建议结合自己的经验做最终判断。只有这一层可以决定补丁是否进入下一阶段。LLM 在这个流程里承担的角色是“信息增强”不是“决策替代”。在这个三层结构里策略要定义的关键点是哪些补丁必须走第二层哪些可以跳过。比如新增文件超过 500 行的驱动补丁必须走 LLM 预审。只修改注释、文档、Kconfig 描述的补丁可以跳过 LLM 预审。涉及 DMA、中断、并发控制的补丁LLM 预审结果只做参考必须由指定维护者人工评审。任何情况下LLM 输出不得直接作为Acked-by或Reviewed-by的依据。策略还要定义“回滚路径”。如果 LLM 预审服务出现故障或者某个阶段的误报率明显升高流程应该自动降级为“传统工具 人工评审”不能因为工具故障阻塞补丁合入。下面用一个最小可运行的示例来演示第二层怎么落地。5. 配置示例与实现最小 LLM 预审流程这一节给出一个可以在本地跑通的最小示例。为了不依赖特定厂商的 API代码中使用环境变量传入 API 地址和密钥模型名称也通过配置指定。实际使用时要根据你选择的模型服务商调整地址和认证方式。5.1 准备环境建议准备一台 Linux 开发机安装 Python 3.9并准备一个可以访问 LLM API 的环境。为了演示我们将项目结构设计为llm-staging-review/ ├── config.yaml ├── prompt_template.md ├── review_diff.py └── run_review.sh如果不想把配置放在代码里可以把 API 地址和密钥写入环境变量这是更安全的做法。后面示例会同时展示两种方式。5.2 定义配置文件配置文件用来切分任务范围。下面是一个config.yaml示例# 文件路径llm-staging-review/config.yaml llm: api_url_env: LLM_API_URL api_key_env: LLM_API_KEY model: your-model-name # 以实际可用模型为准 temperature: 0.1 max_tokens: 1000 review: # 只检查本次 diff 中新增或被修改的 .c / .h 文件 file_extensions: - .c - .h # 检查项清单每个检查项会写入提示词 check_items: - kmalloc/kzalloc/devm_kzalloc 返回值是否检查 - 错误处理路径中是否有资源泄漏 - 是否存在明显变量未使用或类型不匹配 - 注释是否与实际代码逻辑一致 safety: # 超过该行数的文件不发送给外部 LLM防止泄露过多代码 max_file_lines: 800 # 禁止发送到外部 LLM 的路径关键字 blocked_path_keywords: - firmware - internal这里有两个安全设计值得解释。第一max_file_lines用来限制单个文件发送规模避免把整个大驱动文件一次性抛给外部模型。第二blocked_path_keywords用于识别敏感路径凡是路径包含firmware或internal的文件直接跳过 LLM 预审防止敏感代码外传。5.3 编写提示词模板提示词模板是整个预审流程的核心。模板越结构化输出越容易解析。下面是一个最小模板# 文件路径llm-staging-review/prompt_template.md 你是一名 Linux 内核驱动代码审查助手。你负责对以下补丁进行预审目标不是做完整代码评审而是只查找预定义检查项中可能存在的问题。 请严格按以下步骤执行 1. 阅读补丁中涉及的每个文件。 2. 只检查下面列出的检查项不要扩大审查范围。 3. 对每个发现的问题按以下格式输出 - 文件路径 - 行号如果可以从 diff 中判断 - 问题类型 - 可能原因 - 严重程度高 / 中 / 低 - 人工确认建议需要 / 可以忽略 检查项 {% for item in check_items %} - {{ item }} {% endfor %} 注意 - 如果某检查项没有发现问题不要编造问题。 - 不要修改补丁不要提供完整重写代码。 - 不要给出与检查项无关的优化建议。 - 不要输出 Markdown 表格逐条列出即可。模板中使用了简单的变量占位语法。在实际脚本中将当前补丁的 diff 内容追加到模板之后再发送给 LLM。这种“规则前置 问题后置”的结构能显著减少 LLM 自由发挥的空间。5.4 编写调用脚本下面用一个 Python 脚本读取配置和 diff然后调用 LLM API。这里仅演示流程不绑定具体 SDK使用标准库urllib发送 HTTP 请求方便替换成任意 API 服务。# 文件路径llm-staging-review/review_diff.py import json import os import subprocess import sys import urllib.request import yaml def load_config(pathconfig.yaml): with open(path, r, encodingutf-8) as f: return yaml.safe_load(f) def get_diff(base_commit, head_commit): cmd [git, diff, base_commit, head_commit] result subprocess.run(cmd, capture_outputTrue, textTrue) if result.returncode ! 0: print(git diff 执行失败, result.stderr) sys.exit(1) return result.stdout def filter_diff_by_extensions(diff, extensions): 简单过滤这里为了演示只检查 diff 文本中出现的文件扩展名。 更严谨的做法是用 git diff --name-only 获取文件列表后逐文件读取。 lines diff.splitlines() filtered [] for line in lines: if line.startswith( b/) or line.startswith(--- a/): if any(line.endswith(ext) for ext in extensions): filtered.append(line) else: filtered.append(line) else: filtered.append(line) return \n.join(filtered) def build_prompt(config, diff_text): with open(prompt_template.md, r, encodingutf-8) as f: template f.read() check_items \n.join(f- {item} for item in config[review][check_items]) template template.replace({% for item in check_items %}, ) template template.replace({% endfor %}, ) template template.replace({{ item }}, check_items) prompt template \n\n以下是补丁内容\ndiff\n diff_text \n\n return prompt def call_llm(config, prompt): api_url os.environ.get(config[llm][api_url_env]) api_key os.environ.get(config[llm][api_key_env]) if not api_url or not api_key: print(请先设置环境变量 LLM_API_URL 和 LLM_API_KEY) sys.exit(1) payload { model: config[llm][model], messages: [{role: user, content: prompt}], temperature: config[llm][temperature], max_tokens: config[llm][max_tokens], } req urllib.request.Request( api_url, datajson.dumps(payload).encode(utf-8), headers{ Content-Type: application/json, Authorization: fBearer {api_key}, }, methodPOST, ) with urllib.request.urlopen(req, timeout120) as resp: body json.loads(resp.read().decode(utf-8)) return body[choices][0][message][content] def main(): if len(sys.argv) 3: print(用法python review_diff.py base_commit head_commit) sys.exit(1) base_commit sys.argv[1] head_commit sys.argv[2] cfg load_config() diff_text get_diff(base_commit, head_commit) filtered filter_diff_by_extensions(diff_text, cfg[review][file_extensions]) prompt build_prompt(cfg, filtered) result call_llm(cfg, prompt) print(result) if __name__ __main__: main()再提供一个简单的 shell 包装脚本方便设置环境变量并运行# 文件路径llm-staging-review/run_review.sh #!/usr/bin/env bash set -euo pipefail export LLM_API_URL${LLM_API_URL:-https://api.example.com/v1/chat/completions} export LLM_API_KEY${LLM_API_KEY:-} if [ -z $LLM_API_KEY ]; then echo 请设置 LLM_API_KEY 环境变量 exit 1 fi python3 review_diff.py $1 $2执行前需要给脚本添加执行权限chmod x run_review.sh5.5 运行与验证假设你的代码仓库里有一个本次要审查的补丁运行方式如下export LLM_API_URLhttps://api.example.com/v1/chat/completions export LLM_API_KEYyour-secret-key ./run_review.sh HEAD~1 HEAD正常输出应该是结构化的“问题清单”每一条包含文件路径、行号、问题类型、严重程度和人工确认建议。判断运行是否成功可以从三个方面看脚本退出码为 0。输出内容不等于空。输出条目都是预定义检查项相关的问题而不是泛泛的“代码质量建议”。如果输出为空可能有两种情况本次补丁确实没有命中检查项或者提示词被模型误解。可以手动把构建好的 prompt 打印出来检查一次。6. 如何评估 LLM 预审的效果部署一个流程不等于流程有效。真正困难的是评估“LLM 预审到底带来了多少价值”。我的建议是不要凭感觉判断而是搭建一个简单的回测机制。第一步收集历史数据。从 staging 目录的 git 历史中抽取最近 50 到 100 个补丁这些补丁已经被维护者评审并合入相当于有了一份经过人工确认的“标准答案”。第二步对这些历史补丁运行 LLM 预审。把 LLM 输出中标记为“高严重程度”的问题与维护者实际提出的修改意见做对比。第三步计算两个关键指标检出率维护者提出的问题中有多少比例被 LLM 提前发现。这个指标衡量 LLM 的“覆盖能力”。误报率LLM 输出中被维护者判定为“错误或不适用”的问题占全部输出的比例。这个指标衡量 LLM 的“信任成本”。一个比较合理的目标是检出率高于 60%误报率低于 30%。如果误报率偏高说明检查项定义不够准确或者提示词边界不够清晰需要调整。这里提醒一点不要追求 100% 检出率。LLM 预审的目标是过滤重复性劳动不是替代人工评审。即使检出率只有 50%如果能帮维护者节省一半的“格式修正”时间策略依然有效。还可以在流程中引入“打标反馈”。维护者在人工评审时可以对 LLM 的建议标记“有用 / 无用 / 误报”这些标记可以积累成下一轮策略优化的数据。这一步听起来麻烦但它是让策略持续有效的核心。7. 常见问题与排查方法在实际落地过程中团队会遇到不少问题。下面列几个典型场景并给出排查路径。问题现象可能原因排查方式解决方案LLM 预审输出大量与检查项无关的建议提示词边界不清晰模型自由发挥查看发送给模型的完整 prompt确认模板规则是否明确在提示词中显式添加“只输出与检查项相关的问题”“禁止额外建议”对同一个补丁多次运行输出结果不稳定模型采样温度过高或输入端缺少确定性约束降低 temperature尝试将 temperature 设为 0 或 0.1固定配置中的 temperature并对比多次输出敏感路径的代码出现在 diff 中过滤逻辑只检查扩展名没检查路径关键字检查filter_diff_by_extensions是否实际过滤了 diff 头部文件路径增加基于git diff --name-only的路径关键字过滤并跳过敏感文件调用 LLM API 超时补丁 diff 过大或服务端响应慢检查 diff 行数查看服务端日志按文件拆分审查或对超大补丁跳过 LLM 预审模型把“建议”写成了“必须修改”提示词没有强调 LLM 输出只是参考检查提示词中的角色定义和输出格式要求在模板中明确“所有输出都是建议不是结论”外部服务不可用时流程被阻塞缺少降级机制确认策略中有没有定义降级路径增加备用本地规则检查或者在 API 失败时自动跳过 LLM 预审并通知维护者还有一个很容易被忽略的问题diff 解析不完整。很多初学者直接把git diff的全量输出发给 LLM结果模型只能看到部分文件或把上下文理解错。更稳妥的做法是先用git diff --name-only获取文件列表再逐个文件构建 diff 文本最后把文件路径和具体 diff 段一起发给模型。这样可以显著降低误报。8. 工程建议与安全边界最后这一节我给出团队落地这套策略时的工程建议。这些建议不只在 staging 目录适用对任何想在内核开发流程中引入 LLM 的团队都有参考价值。第一坚持“传统工具优先”。能用脚本解决的问题不要用 LLM。格式检查、编译错误、明显的未使用变量都应该交给确定性工具。LLM 只处理规则难以覆盖的语义问题。这样既能保证准确率也能减少对模型服务的依赖。第二严格限制外部数据流。不要把整个仓库或敏感驱动文件发送给第三方 API。建议在本地部署模型或者只发送必要的 diff 片段。对涉及未发布硬件信息和潜在安全漏洞的补丁宁可跳过 LLM 预审也不要把数据泄露出去。第三保留完整的审计链路。每次 LLM 预审的输入、输出、模型版本、配置参数都应该记录下来。这样当某个建议被证明是错误时可以回溯是模型问题、提示词问题还是检查项定义问题。第四最小权限原则。执行 LLM 预审的账号只应该拥有读取代码仓库的权限不拥有合入权限。脚本运行环境和 API 密钥要分开管理密钥不能硬编码在代码仓库中。第五策略要可回滚。在引入 LLM 预审的初期建议采用“影子模式”LLM 的结果只展示给维护者不影响合入门禁。运行两到四周后根据检出率和误报率再决定是否把 LLM 预审作为正式合入流程的一环。第六不要在夜间自动化合入。即使以后流程越来越成熟也不建议让 LLM 预审结果直接驱动自动化合入。内核代码的合入决定应该始终由有责任意识的人来做。这些原则其实不复杂但执行中很容易变形。最容易犯的错误是初期尝到甜头后不断扩大 LLM 的权限范围。等到某个错误建议被自动合入才发现边界已经被突破。所以策略的价值不在于写得多严密而在于边界是否能被长期坚持。9. 总结与后续方向回到最初的问题LLM policy for drivers/staging/ going forward 应该是什么样从当前技术成熟度和内核社区的工作方式来看更合理的策略不是全面拥抱也不是完全排斥而是把 LLM 定位成 staging 目录补丁的“预审助手”。它帮助维护者过滤重复性问题提高补丁初筛效率但所有决策权仍然保留在人工评审环节。策略的边界、数据安全、审计链路和降级路径比模型本身的能力更值得花时间设计。如果你接下来想继续研究可以沿着三个方向深入。第一用历史补丁数据对 LLM 预审做量化回测建立自己团队的评价指标。第二尝试在本地部署一个开源模型把数据安全边界彻底控制在自己手里。第三把这条流程从 drivers/staging 逐步扩展到团队负责的其他模块但每一步都要先定义好范围、责任和回滚方案。内核开发的严谨性来自流程而不是来自某一个工具。LLM 可以成为这个流程的一部分但前提是它待在适合自己的位置上。