LocalAI 的 AI 辅助贡献政策:Signed-off-by、Assisted-by 与人类责任边界
当开发者借助 AI 编码助手为开源项目写代码时,"这段代码的责任归谁、提交历史如何署名"往往是容易被忽视的合规问题。LocalAI 在其 .agents/ai-coding-assistants.md 中给出了一套完整、可执行的答案:明确禁止 AI 代理添加 Signed-off-by 与 Co-Authored-By 尾注,要求以 Assisted-by 尾注记录 AI 参与,并把维护者运行的自动化脚本列为唯一例外。读完本文,你将掌握 LocalAI 对 AI 辅助贡献的完整署名规范、MIT 许可证约束下的代码引入规则,以及人类提交者在代码审查与验证环节不可推卸的责任清单,能够据此规范自己(或自己所配置的 AI Agent)的提交流程。
政策背景:对齐 Linux 内核的 AI 辅助贡献准则
LocalAI 的 AI 辅助贡献政策与 Linux 内核项目对 AI 编码助手的规定保持一致,并针对自身的许可证和代码布局做了适配。原文明确指出:如果政策有任何不清晰之处,内核文档是判断意图的权威参考。
这套政策在仓库中的落点有三处,构成"入口—细则—摘要"的三级结构:
- AGENTS.md(根目录下的 CLAUDE.md 是指向它的符号链接)是 Claude Code、Cursor、Copilot、Codex、Aider 等 AI 编码助手的统一入口,以索引方式列出
.agents/目录下的各主题指南,其中"Policy for AI-Assisted Contributions"一节直接复述了署名三条铁律,并链接到本政策全文; .agents/ai-coding-assistants.md是政策的完整正文,也是本文的主语;- CONTRIBUTING.md 的"AI Coding Assistants"章节给出面向人类贡献者的摘要版本,与全文互为印证。
同时,文档要求 AI 工具遵循项目标准的开发流程,并明确引用了三个配套文档:CONTRIBUTING.md(开发流程、提交规范、PR 指南)、.agents/coding-style.md(代码风格、editorconfig、日志与文档约定)、.agents/building-and-testing.md(构建与测试流程)。
许可证与法律要求
所有贡献必须满足 LocalAI 的许可证要求,具体有三条:
- LocalAI 采用 MIT 许可证,见仓库根目录的 LICENSE 文件(版权声明为 2023–2025 年 Ettore Di Giacinto)。
- 新增源码文件在适用处应使用 SPDX 许可证标识
MIT——即在文件头以标准 SPDX 形式标注许可证类型。 - 贡献必须与 MIT 许可证兼容:未经维护者明确讨论,不得引入处于不兼容许可证下(例如 GPL)的代码。
这一条对 AI 辅助场景尤其重要:模型可能从训练语料中"复现"出带有其他许可证风格的代码片段,人类提交者必须确认引入代码的许可兼容性,而非默认模型输出天然干净。
Signed-off-by 与开发者原创证书(DCO)
政策的核心禁令只有一条,但表述极为强硬:AI 代理不得(MUST NOT)添加 Signed-off-by 尾注。理由在于开发者原创证书(Developer Certificate of Origin, DCO)在法律上只能由人类作出认证。
由此,人类提交者承担以下四项责任:
- 审查(review)全部 AI 生成的代码;
- 确认代码符合许可证要求;
- 当项目要求 DCO 时,添加自己的
Signed-off-by尾注以认证该贡献; - 对该贡献承担全部责任。
与之配套的第二条禁令是:AI 代理也不得(MUST NOT)为自己添加 Co-Authored-By 尾注。政策对此的解释是:人类审查者拥有该贡献,AI 的参与通过下文的 Assisted-by 尾注来记录。从源码结构看,这一点在仓库的提交历史中得到体现——实际的提交信息中确实普遍携带 Signed-off-by(以及人类维护者之间的 Co-authored-by)尾注,署名主体始终是真实的人或维护者操作的自动化身份。
例外:维护者操作的自动化
上述规则针对的是最常见情形——AI 助手帮一位人类贡献者写码,再由该贡献者签署。但它并不适配维护者自行运行、并由维护者本人发起 Pull Request 的自动化场景:这种 PR 没有"人类提交者"可供签署,若机械执行禁令,DCO 检查将永久卡死该 PR。
因此政策给出一个窄例外:由维护者操作的机器人(bot)必须(MUST)添加一条 Signed-off-by 尾注,署名对象是操作该自动化的维护者本人,而不是机器人、更不是模型。原文给出的示例:
Assisted-by: Codex:gpt-5
Signed-off-by: Ettore Di Giacinto <mudler@localai.io>
政策强调,这不是 AI 在认证 DCO——恰恰相反,是维护者在认证:正如对手敲的提交一样,他配置了这套自动化、拥有其产出,并在合并时为其承担责任。Assisted-by 尾注依旧记录"模型生成了这段代码",因此出处(provenance)链条不受影响。
这个例外被严格限定为窄口径,并且不扩大规则对任何其他人的适用范围,边界有四条:
- 仅适用于 LocalAI 维护者操作、且其在合并前审查产出的自动化;
- 签署者必须是一个承担 DCO 责任的真实个人;
- AI 助手帮助外部贡献者时,仍然不得(MUST NOT)代签——该贡献者添加自己的尾注;
- 机器人**不得(MUST NOT)**代表除操作者以外的任何人签署,也不得为其推送到的贡献者分支添加尾注。如果自动化贡献进了别人的分支,签署工作留给那位贡献者。
Assisted-by 署名格式
当 AI 工具参与 LocalAI 开发时,恰当的署名有助于追踪 AI 在开发过程中的角色演变。所有 AI 辅助的贡献都应在提交信息的尾注区(trailer)包含一条 Assisted-by 标签,格式为:
Assisted-by: AGENT_NAME:MODEL_VERSION [TOOL1] [TOOL2]
各字段含义:
AGENT_NAME—— AI 工具或框架的名称(例如Claude、Copilot、Cursor);MODEL_VERSION—— 实际使用的具体模型版本(例如claude-opus-4-7、gpt-5);[TOOL1] [TOOL2]—— 可选的、由 Agent 调用的专用分析工具(例如golangci-lint、staticcheck、go vet)。
注意一条排除规则:基础开发工具(git、go、make、编辑器)不应列入该字段——它们不构成"AI 参与的专有证据",列出只会稀释信息的价值。
完整提交信息示例
原文给出的完整示例,展示了 conventional commits 风格的主题行、正文与尾注区的组合:
fix(llama-cpp): handle empty tool call arguments
Previously the parser panicked when the model returned a tool call with
an empty arguments object. Fall back to an empty JSON object in that
case so downstream consumers receive a valid payload.
Assisted-by: Claude:claude-opus-4-7 golangci-lint
Signed-off-by: Jane Developer <jane@example.com>
注意示例中的分工:Assisted-by 记录"由哪个 Agent 的哪个模型、借助哪个静态分析工具产出了代码",Signed-off-by 则属于人类提交者本人。两条尾注各司其职,互不替代。
责任范围:AI 参与不降低人类提交者的义务
政策最后一条主题是"Scope and Responsibility",其立场明确:使用 AI 助手不降低贡献者的任何责任。人类提交者必须做到:
- 理解 PR 中落地的每一行代码;
- 验证生成代码可以编译、通过测试、并符合项目风格;
- 确认所引用的 API、flag 或文件路径在当前代码树中真实存在——AI 模型可能幻觉出并不存在的标识符;
- 不未经审查地原样提交 AI 输出。
对于审查环节,政策还预设了审查者可能的质疑,并给出标准答案的边界:"无论变更如何产生,审查者都可以就任何变更要求澄清。'是一个 AI 写的'不是设计问题的可接受答案。"
这一条与仓库的工程实践形成闭环。以 .agents/building-and-testing.md 为例,项目为"验证代码通过测试"提供了具体可执行的门槛:核心 Go 测试套件(./pkg、./core 及进程内集成套件 ./tests/e2e)受**严格且单调递增的覆盖率棘轮(coverage ratchet)**约束——make test-coverage 以 covermode=atomic 采集覆盖率并写入合并 profile,make test-coverage-check 对照提交的基线文件 coverage-baseline.txt,低于基线即构建失败;React UI 一侧则由 Playwright e2e 规格加上带容忍度的覆盖率门槛把关。规则同时明确:绝不允许为把红色门槛变绿而手工下调基线或放宽容忍度,棘轮只能向上走——若变更导致覆盖率下降,应通过补测试(例如 render-smoke 规格)把覆盖率抬回去。对 AI 生成的代码而言,这意味着"通过测试"不是一个可以靠调整门槛绕过去的说法,而是有脚本化判据的硬约束。
风格验证同样有工具化抓手:.agents/coding-style.md 规定 Go 测试统一使用 Ginkgo v2 与 Gomega 匹配器(由 golangci-lint 的 forbidigo 检查器强制,禁止 t.Run/t.Errorf 等 stdlib 风格混用),日志统一走 github.com/mudler/xlog,且遵循"docs-with-code"规则——用户可见行为的变更必须在同一变更中更新 docs/content/ 下对应文档,否则视为不完整。这正是 Assisted-by 字段中允许列出 golangci-lint 等分析工具的原因:静态分析在 AI 辅助流程中被视为验证环节的一部分,其参与值得被记录。
小结:三条规则与一份责任清单
把 .agents/ai-coding-assistants.md 的政策压缩成可执行清单,即:
| 规则 | 约束对象 | 依据 |
|---|---|---|
不得添加 Signed-off-by |
AI 代理 | DCO 只能由人类法律上认证;维护者操作的自动化以其维护者身份签署为唯一窄例外 |
不得添加 Co-Authored-By 自署 |
AI 代理 | 贡献归人类审查者所有,AI 参与由 Assisted-by 记录 |
必须添加 Assisted-by: AGENT_NAME:MODEL_VERSION [TOOL...] |
AI 辅助的贡献 | 保留 AI 参与的出处链;基础工具(git、go、make、编辑器)不列入 |
| MIT 许可证兼容 | 所有引入的代码 | 新文件适用处标注 SPDX MIT;不兼容许可证(如 GPL)须先与维护者讨论 |
| 逐行理解、验证编译与测试、核实引用标识符真实存在、不原样提交 | 人类提交者 | AI 参与不降低责任;"AI 写的"不构成设计问题的答案 |
对维护 LocalAI 的开发者而言,这套政策的实际收益在于:DCO 链条始终由可追责的人类闭合,AI 的参与以机器可读的尾注形式留在提交历史中,而验证责任通过覆盖率棘轮、golangci-lint 强制项与 docs-with-code 规则被具体化为可检查的门槛——署名规范与工程验证因此成为同一套合规体系的两个侧面。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0623
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00