现在关于 AI 写代码的内容很多,但我不太喜欢其中两种倾向:一种是用 AI 做炫酷但不实用的花瓶,另一种是夸大 AI 能力来博眼球、贩卖焦虑。

我更关心的是:AI 到底能在哪些真实工程场景里,稳定地产生价值。关键不只是 AI 能不能写代码,而是场景是不是真实、反馈是不是可验证、失败是不是能被及时发现和回滚。离开这些前提,再漂亮的生成结果也很容易停留在演示层面。

过去一段时间,我在 Knife4j Next 上尝试的就是这样一个场景:不用 AI 从零写一个新项目,而是让它参与复活一个已经停止维护、但仍然有人需要的开源项目。

Knife4j NextKnife4j 的一个社区维护 fork。Knife4j 本身是很多 Java 项目用过的 API 文档工具,官网在 doc.xiaominfo.com/knife4j。当一个有历史用户的项目维护节奏变慢后,需求不会自动消失:文档页面要保持可用,调试链路不能莫名断掉,发布说明和发布产物也需要对得上。

这类项目很有代表性:它不是一个需要每天重新定义方向的新产品,也不是一个改错一次就会造成巨大损失的核心系统;它有真实用户、有明确问题、有可验证的结果,也有很多适合被拆成小 PR 的维护工作。

这篇文章想聊的就是这件事:从 Knife4j Next 这个引子出发,为什么“AI 复活开源项目”是一个务实场景,什么样的项目适合这么做,以及我是怎么把任务、边界、验证和审查体系搭起来的。

什么项目适合 AI 维护

先说项目类型。

我现在比较看好的,不是那种方向还很模糊、每天都要做产品判断的新项目,而是另一类更朴素的项目:

  • 原维护者已经停止维护,或者维护频率很低;
  • 真实用户还在,issue 里仍然有明确需求;
  • 项目规模不算太大,代码结构还能读懂;
  • 需求大多是 bug 修复、兼容性补丁、文档补齐、发布流程修复;
  • 每个任务都能用测试、构建、截图、日志或 CI 来验证;
  • 改动失败的风险可控,回滚路径比较简单。

这类项目不一定性感,但很适合 AI。

因为 AI 最擅长的不是替你拍板“产品下一步该往哪里走”,而是在边界清楚、反馈明确的范围内推进具体任务。比如修一个已知 bug、补一个测试、更新一段文档、对齐 release note、把一个重复流程脚本化。

反过来,有些项目我会很谨慎:

  • 核心金融、交易、权限、安全相关系统;
  • 需求本身还没想清楚,需要大量产品判断;
  • 没有测试、没有构建、没有可重复验证方式;
  • 改错一次影响面很大,或者很难回滚;
  • issue 都是“感觉不好用”“能不能做成某某产品那样”这类开放问题。

AI 不是不能参与这些项目,但不能让它自治推进。它最多适合做探索、对比、整理和局部实现。

所以我的第一个判断是:AI 维护开源项目,最适合从低风险、需求明确、容易验证的小型项目开始。

这是项目层面的选择:先选一个不需要每天重新定义方向、也不会因为一次小改动带来巨大损失的维护场景。

不要直接让 AI 接管项目

刚开始用 Coding Agent 时,很容易有一种冲动:直接把 issue 扔给它,让它自己读代码、自己改、自己提交。

偶尔这样确实能成功,但不稳定。

原因很简单:真实项目里有太多隐性规则。哪些模块可以改,哪些模块只是兼容维护;什么算完成,什么只是本地看起来过了;什么时候要开 PR,什么时候要等 CI;哪些改动需要人工确认,哪些可以让 AI 自己推进。

这些规则如果只存在于维护者脑子里,AI 就只能猜。

我后来做的第一件事,不是继续优化 prompt,而是把这些隐性规则写进仓库。项目里逐渐有了这些文件:

  • AGENTS.md:给所有 Agent 的总规则;
  • .agent/PROJECT.md:项目目标、边界和非目标;
  • .agent/AUTONOMY_POLICY.md:AI 可以自治做什么,什么必须停下来问人;
  • .agent/COORDINATION.md:多 Agent 如何分工,什么时候需要 worker 和 reviewer;
  • .agent/RUNBOOK.md:不同类型改动要跑什么验证;
  • .agent/KNOWN_PITFALLS.md:历史踩坑和反例;
  • .agent/REVIEW_POLICY.md:审查重点和合并前门槛。

这些文件看起来像文档,但我更愿意把它们理解成“项目给 AI 的操作系统”。

AI 每次进来,不需要从聊天记录里猜这个项目的性格,也不需要靠我临时提醒“别顺手扩大范围”“先跑这个脚本”“这个状态要写回 issue”。它可以先读规则,再按规则工作。

这一步非常关键。

因为 AI 协作真正怕的,不是它写不出代码,而是它在不知道边界的情况下写出一堆看起来合理、实际很难维护的代码。

任务状态要有唯一来源

另一个很快暴露的问题是:聊天窗口不能当任务管理器。

今天我在一个对话里说“继续处理这个 issue”,AI 还能靠上下文接上;明天换一个会话、换一个工具、换一个模型,它就不知道现在到底做到哪一步了。

某个任务是刚准备做,还是已经开了分支?PR 是等 CI,还是已经有人 review 过?某个问题是暂时不推进,还是技术上已经确认不存在?如果这些状态只散落在聊天里,迟早会乱。

所以我把任务状态放到了 GitHub Issues + Labels 上。

核心状态很简单:

  • status:ready:任务已经细化,可以开始;
  • status:in-progress:正在处理;
  • status:review:本地验证、独立审查、PR CI 都通过,等待最终 review 或 merge;
  • status:blocked:被信息、环境或决策阻塞。

这套状态不复杂,但好处很明显:不管是我手动和 AI 对话,还是让定时任务自动唤醒 AI,它都可以从 GitHub 读取当前队列,而不是依赖某段聊天历史。

它的工作方式也变得更像一个状态机:

  1. status:ready 里挑一个小任务;
  2. 切到 status:in-progress
  3. 创建独立分支;
  4. 做最小改动;
  5. 跑对应验证;
  6. 开 PR,等待 CI 和 review;
  7. 全部通过后再进入 status:review

这一步让我意识到:AI 不怕任务多,怕的是任务状态没有唯一来源。

只要状态清楚,AI 就能接力;状态不清楚,它就只能猜。而 AI 一旦开始猜任务状态,后面的努力很可能都是在把错误推进得更远。

多 Agent 不是虚拟公司

我以前也研究过多 Agent,最不看好的一种模式,就是把它们包装成一个“虚拟公司”:一个当产品经理,一个当架构师,一个当开发,一个当测试,然后像公司部门一样交接文档。

这个模式演示起来很好看,但工程上经常不稳。因为模型之间没有真实的职业经验差异,所谓角色分工很容易变成表演;更麻烦的是,信息在一轮轮交接中不断被压缩,最后每个节点看起来都合理,整体却偏了。

我现在更认可一种浅层模式:coordinator / worker / reviewer。

这三个名字不是职位,而是上下文边界:

  • coordinator 负责读规则、选任务、维护 issue 状态、整合 PR 叙事;
  • worker 只做一个窄范围实现或探索;
  • reviewer 只审查 diff、回归风险、范围漂移和验证质量。

这样拆分的目的,不是为了模拟一个更复杂的组织结构,而是为了控制每个 agent 的上下文长度。worker 只拿到当前任务需要的信息,就更容易专注在本职工作上,不至于在一堆历史背景、产品想法和无关文件里注意力涣散。

worker 完成后,不是把一大堆过程都塞回来,而是给一个简短 handoff:改了哪些文件,解决了什么问题,跑了什么验证,还有什么风险。

reviewer 也不是再实现一遍,而是带着独立上下文专门挑问题:有没有改过头,有没有缺测试,有没有把未验证的假设写成事实。这个角色很重要,因为实现者很容易相信自己的解释;独立 reviewer 至少有机会发现 worker 的幻觉,避免整套流程变成“自卖自夸”。

所以这套模式的重点不是交接仪式,而是让不同 agent 在更小、更专注的上下文里完成各自工作。长任务里,AI 很容易越做越细,最后忘了最初的任务边界。把实现和审查拆成短命任务,可以减少这种漂移。

适合 AI 的任务要能验证

如果上一节说的是项目类型,这一节说的就是任务粒度。

在一个适合 AI 维护的项目里,也不是所有事情都应该直接交给 AI 自治推进。我现在判断一个任务适不适合交给 AI,最核心的问题不是“它难不难”,而是“它能不能验证”。

比如这些任务就很适合:

  • 复现一个明确 bug,然后补回归测试;
  • 修一个前端显示问题,并能用构建或截图验证;
  • 更新文档,让 README、文档站和实际代码保持一致;
  • 修 CI 或发布脚本,让失败条件变成明确报错;
  • 清理小范围过期说明;
  • 给已有功能补单元测试;
  • 把手动发布检查变成脚本。

这些任务有一个共同点:完成标准比较客观。命令过不过、截图对不对、CI 是否绿、发布产物是否存在,都能检查。

不适合 AI 自治推进的任务也很明显:

  • “我们要不要转型成另一个产品”;
  • “这个功能应该怎么设计才最好”;
  • “顺便把架构现代化一下”;
  • “把这个历史模块重写掉”;
  • “看着优化一下体验”。

这些任务不是不能做,而是必须有人先把边界收窄。AI 可以参与调研和方案对比,但不能直接拿着这种开放题去改代码。

所以我后来给自己的规则是:凡是交给 AI 自治处理的任务,都必须有目标文件或模块、预期行为变化、验证命令和完成条件。

缺一项,就先细化任务,不要急着写代码。

不可复现,就不要急着修

维护开源项目时,很多 issue 来自上游项目或者历史用户反馈。

这类问题很容易误导 AI。标题里一句“某某报错”,截图里一个异常片段,看起来方向很明显。但真实原因可能藏在评论、版本组合、配置方式或者调用链里。

我后来给 AI 定了一条很硬的规则:上游 issue 或历史 bug,修复前先复现。

如果复现不到,就不要写“防御性代码”。

因为没有复现的修复,本质上无法证明它修的是同一个问题。AI 很擅长写一个看起来更稳的 iftry-catch 或 fallback,但这类代码如果没有测试约束,反而可能吞掉真正的错误。

正确流程应该是:

  1. 读完整 issue 正文、堆栈和评论;
  2. 找到当前项目里对应的代码路径;
  3. 用最小工程或测试先复现;
  4. 复现成功,再修;
  5. 修完后,同一个测试从失败变成通过。

如果复现不到,也要把尝试过的条件写回 issue,而不是假装修了。

这件事对 AI 特别重要。因为 AI 的默认倾向是“给出一个解决方案”,但维护项目时,更重要的是先证明你理解的是同一个问题。

发布也要变成可验证流程

很多小型开源项目真正麻烦的地方,不在写代码,而在发布。

一次发布到底算不算完成?是 tag 推了就算?CI 绿了就算?包发到仓库就算?用户能在 Release 页面看到说明算不算也必须检查?

如果这些都靠人记,迟早会漏。

所以我把发布也当成一组可验证条件来设计:

  • tag 是否存在;
  • workflow 是否成功;
  • 构件是否能从公开仓库访问;
  • GitHub Release 是否存在;
  • Release body 是否来自项目里的 release note;
  • 文档站是否同步更新。

这里的关键不是某个具体脚本,而是思路:不要让发布完成条件只存在于人的记忆里。

发布是最适合流程化的环节之一。只要把“什么叫完成”写成脚本和 CI,AI 就可以帮你监控、补齐和汇报,而不是靠一句“应该发好了”糊弄过去。

Knife4j Next 现在怎么维护

上面说的是原则,落到 Knife4j Next 里,实际维护方式更像一条很短的流水线。

首先,GitHub Issue 就是任务列表。一个适合 AI 处理的任务,会打上 agent-task,再用 status:readystatus:in-progressstatus:reviewstatus:blocked 表示状态。模块归属则用 area:ui-reactarea:javaarea:docs 这类标签标出来。

然后是角色分工:coordinator 负责选任务、维护 issue 状态、创建分支和整理 PR 叙事;worker 负责一个窄范围实现;reviewer 负责检查 diff、回归风险、验证质量和范围漂移。它不是“虚拟公司”式表演,而是通过控制上下文长度,让 worker 专注做好本职工作,再让带着独立上下文的 reviewer 去发现 worker 可能存在的幻觉和自我合理化。

一个典型例子是 issue #379。用户反馈在 doc.html 里进入右上角设置,添加全局参数时按钮 loading 不消失,控制台报 TypeError: crypto.randomUUID is not a function。这个 issue 被标成 agent-taskstatus:in-progressarea:ui-react,任务边界就很清楚:这是 React UI 的兼容性 bug,不是一次产品重设计。

处理过程大致是这样:

  1. coordinator 先确认复现路径:进入全局参数配置,添加 Accept-Language 这类 header 参数。
  2. worker 顺着报错定位到 GlobalParamContext.tsx,发现添加参数时直接依赖 crypto.randomUUID()
  3. 修复没有扩大成“重做全局参数功能”,而是新增一个 createClientId():优先使用 crypto.randomUUID(),缺失时退到 crypto.getRandomValues(),再不行才使用本地临时 ID。
  4. 为这个 ID 生成逻辑补了测试,覆盖 randomUUID 存在、只有 getRandomValues、完全没有 crypto 三种场景。
  5. 本地验证跑了 bun run test./scripts/test-front-core.shgit diff --check
  6. 最后通过 PR #382 合并。

这个例子本身不复杂,但它正好说明了 AI 适合做什么:从一个真实用户问题出发,限定模块,复现现象,做小修复,补测试,跑项目认可的验证命令,然后把结论写回 issue 和 PR。

真正重要的不是 AI 一次写了多少代码,而是它有没有沿着这条链路把事情闭环。

最后得到的一套体系

折腾下来,我觉得 AI 维护开源项目需要的不是神奇 prompt,而是一套很具体的工程体系:

  • 项目边界:写清楚什么能做,什么不能做;
  • 任务队列:用 GitHub Issue 管理状态;
  • 分支纪律:一个分支只处理一个小任务;
  • 验证入口:不同类型改动有明确命令;
  • 复现规则:bug 修复先证明问题存在;
  • 审查门禁:实现和 review 尽量拆开;
  • 发布闭环:发布结果必须能被脚本验证;
  • 状态写回:重要结论回到 issue、PR 或仓库文档里。

这些东西看起来不像“AI 能力”,但它们决定了 AI 能不能稳定工作。没有规则时,AI 越积极,越容易扩大伤害;规则清楚时,它才有机会变成可控的维护协作者。

结语

现在很多人讨论 AI 写代码,喜欢聊它能不能从零做一个完整产品。

但我反而觉得,AI 在开源维护里有一个更现实的切入点:那些停止维护、需求仍在、风险不高、验证路径清楚的小型项目。

这类项目通常不缺宏大愿景,缺的是持续处理 issue、补测试、修文档、打 release、收尾 PR 的耐心。AI 在这里的价值,不是替维护者宣布方向,而是把这些具体、可验证、可回滚的工作稳定往前推。

我的结论很简单:

别急着让 AI 接管项目。先搭好任务、边界、验证、审查和发布流程。

流程搭起来之后,AI 才不是偶尔写出一段代码的工具,而是可以长期参与维护的小型工程力量。