《拆解全球最火 AI 开源项目》第一季 · REA

不是教你用 REA,而是借 REA,看懂现代 AI 开源项目为什么能高速进化。


REA

GitHub 全球 Star 第 4

2026 年增长最快的 AI 开源项目


过去几个月我的排名

Merged PR Top Contributors
37 第 10

(真人 PR Contributor 中排 第 8)


这是我第一次,以 Contributor 身份,而不是使用者身份,讲这个项目。


第一章 我错得很彻底

我第一次给 REA 提 PR,觉得自己写得挺好。

改动很小,逻辑清楚,测试也跑了,门禁也过了,描述里还写了一张对照表。我提交完就放在那里,等着被合并。

几分钟后,机器人来了。

它说 P1。

csharp 复制代码
Reject truncated wide caches before accepting 28-byte headers

If a valid 32-byte cache is truncated by exactly four bytes at EOF,
bytes.length - declaredPayload becomes 28 and this allow-list accepts
it as the narrow layout.

我盯着这段话看了很久。

我的第一个念头是:它错了。

因为我的 PR 里有一份"证据"。我跑了真实的 Node,把一个 64 位的 V8 code cache 取出来,把它末尾的四个填充字节删掉,然后交给 V8 自己判断。

php 复制代码
new vm.Script(src, { cachedData: narrow }).cachedDataRejected
→ false

V8 接受了。 所以这份字节是合法的。所以我的实现是对的。

这套推理看起来无懈可击。

然后我决定"证明它错了",于是我把三种情况都跑了一遍。

V8 连被截断的坏文件都接受。

我拿着一个什么都不证明的实验,当成了关键证据,还写进了 PR 描述。

那一刻的感觉不是"我被冤枉了",而是 "我做的事,比我想象的要浅。"


后面我又花了几个小时,才找到真正的判据。我跑了六个不同的源码,量出两个常量:

复制代码
x64 的填充字,偏移 28   恒为 0x00000000
payload 的第一个字,偏移 32  恒为 0x03542401

只有那个 0 能区分「真的 28 字节头」和「被截断的 32 字节头」。

因为这个 0 是 V8 的对齐填充,而一个真正的 28 字节头,在那个位置放的是 payload 的第一个字。

这个 PR 最后是这么写的:

| container | before | after | | 真 32 字节头 | accept | accept | | 真 28 字节头 | accept | accept | | 32 字节头截 4 字节 | accept | malformed |

两行没有变化的行,和一行变化了的行,同等重要。


那天我学到的东西,比我过去一年自己写代码学到的都多。

所以这个系列的第一句话,我想这么写:

我不是来教你怎么用 REA 的。 我是来告诉你,在一个几十万 Star 的项目里,一个人的判断能错到什么程度,以及它怎么把你掰回来。


第二章 为什么全世界都在讨论它

先回答一个最朴素的问题:这到底是个什么量级的项目?

2.1 全球第 4

bash 复制代码
1  codecrafters-io/build-your-own-x          562,490
2  sindresorhus/awesome                      536,805
3  public-apis/public-apis                    498,972
4  morluto/rea                                459,260   ←
5  freeCodeCamp/freeCodeCamp                  459,128
6  EbookFoundation/free-programming-books     401,586

第 4 和第 5 只差 132 星。

这个位置随时会换。所以"全球第 4"是一个动态快照,并非既成事实。我可能下周就得改这句话。

2.2 但它只存在了 7 个月

这才是真正离谱的部分。

我把 2026 年创建的所有仓库按星数拉了一遍:

yaml 复制代码
1  morluto/rea                     459,260   created 2026-04-14
2  mattpocock/skills                324,301   created 2026-02-03
3  affaan-m/ECC                     302,782   created 2026-01-18

它是唯一突破 40 万的 2026 年新仓库。

而且注意那个时间差:第二名比它早创建两个月,星数还少 13 万。

所以这句话可以写得更硬:

按"创建后 7 个月的星数"算,REA 是目前全球第一。

2.3 一个反直觉的比例

yaml 复制代码
459,260 stars
112,585 forks
──────────────
≈ 4.1 : 1

大多数"网红项目"的 star/fork 比是 20:1 甚至 50:1,因为大量人只是点星收藏,不会额外做事。

1:4 意味着每四个点星的人里,就有一个真的把它 fork 下来动手了。

这是"看热闹"和"真在用"的分界线。

2.4 但它同时也是拥堵的

arduino 复制代码
885 个 open PR
837 个 open Issue

这其实是一个瓶颈信号,未必代表健康。


第三章 我为什么选它,而不是别的

2026 年的 AI Coding 赛道不缺水项目。Continue、OpenHands、Roo Code、Aider,还有每周冒出来的新 Agent 框架。

我评估过其中几个。最后把时间投在 REA 上,理由不是"它最火"。

我的判据

它在这五个维度上的实际表现

工程质量:极高,而且可验证。

我每次提交要过的是这些:

bash 复制代码
npm ci                    # 锁定依赖
npx tsc --noEmit -p .     # 全量类型检查
npm run lint              # 0 error
npm run knip              # 死代码 / 未用导出
npm run format:check      # oxfmt
npm run docs:check        # 文档一致性

CI 还分 lane。我动 hopper 代码时触发的那个:

yaml 复制代码
apple-artifacts:
  name: Real Apple artifact CLI/MCP E2E
  runs-on: macos-15
  timeout-minutes: 15

我真实踩过一次坑:那个 job 跑了 15 分 23 秒 ,被自己的 timeout 砍掉,GitHub 记成 cancelled 而不是 failure。

我一开始判断是"并发取消",写了半天,最后对着时间戳才发现:started 10:24:57,completed 10:40:20,正好 15 分 23 秒。

这种细节,只有里面提交过几十次 PR 的人才知道。

Review 严格度:这是我留下来的头号原因。

这个项目的 Review Bot 在你 push 之后几分钟内就会贴意见,而且经常一次贴好几条 P1/P2。我一开始觉得是噪音。

后来我数了一下:我有 21 条未清的评论线程,分布在 7 个 PR 上。其中有一个 PR 累计 54 条。

它从来不写"你错了"。它写的是:

When a crafted link has no LinkInfo and records https://example.test/app.exe. in RelativePath, targetPaths makes that raw value the first target and this fallback strips the terminal dot, publishing .exe; an HTTP target preserves that dot and can address a different resource.

它构造一个具体输入 → 顺着我的代码路径走一遍 → 给我一个具体输出 → 指出这个输出和现实不符。

它不先做立场判断,只把证据摆出来。

Maintainer 响应:慢,但真实。

我 37 个 PR 的中位合并耗时是 18.7 小时。而且带 issue 链接的明显更快:

复制代码
带 issue 链接的 PR    中位 5.8h
不带 issue 链接的 PR  中位 8.2h

为什么不是别的项目

只说一个可验证的判据:去看外部贡献者的实际合并率。

REA 的外部占比是 5%。

这是个真实问题,我必须承认。 从纯投入产出的角度看,它不是理想的标的。

但我还是留下来了,原因很具体:

在那 5% 里,每一个都是因为代码本身正确而被合并的。没有一个是靠关系。

有个叫 Plastic-time 的人,和我一样是 CONTRIBUTOR、push = false。他 36 个 PR 全部由仓库所有者手动合并,自己一个都没合过。

在那个 5% 的通道里,规则是干净的。

这就是我判断的依据。


第四章 四轮

第三章我说 Review 严格。第四章我把这件事讲完。

4.1 一个改动的四种死法

我有个 Windows 快捷方式解析的 PR。改的是:Win32 会裁掉路径末尾的句点和空格。

起因很简单:一个 .lnk 文件的图标路径,是目标路径加了一个尾句点。REA 逐字符比较,判成"不相等",然后输出:

ini 复制代码
icon_location_differs_from_target = true

下游看到这个字段会怎么理解?"这个快捷方式在伪装自己的图标。"

这是一个安全信号。

而事实是:它们指向同一个文件。

我在本机验了:

python 复制代码
Test-Path 'C:\Windows\System32\shell32.dll'      → True
Test-Path 'C:\Windows\System32\shell32.dll.'     → True    ← 同一个文件
Test-Path 'C:\Windows\System32\shell32.dll '     → True    ← 同一个文件
Test-Path 'C:\Windows.\System32\shell32.dll'     → True    ← 同一个文件
Test-Path '\\?\C:\Windows\System32\shell32.dll.' → False   ← 设备路径跳过规范化

代码没算错------两个字符串确实不相等。但结论错了,它报出了一个不存在的安全威胁。

4.2 然后我被连续打回四轮

四轮之后我才明白一件事:

我一直在按"文本内容"打补丁,而正确的判据是"书写形式"。

Win32 会打开的文件系统路径,用反斜杠写 (C:\... 或 \\server\...)。URL 保留正斜杠。而 //example.test/... 折叠之后,和 UNC 路径一模一样------只有原始写法能区分它们。

4.3 但我第一版还是写错了

我第一版的规则是:"用反斜杠写的才算文件系统路径。"

它立刻被一个既有测试抓住:

ts 复制代码
expect(await iconFor("C:/Tools/bin/../\\app.exe", "c:/tools//app.exe"))
  .toBe(false);

c:/tools//app.exe 是正斜杠,但它是文件系统路径------Windows 两者都接受。

所以规则必须拆成两条:

六个约束,最后压成两行判断。

这就是这个项目里"小改动"的真实成本结构:行数小,约束密度大。


第五章 我走进这个代码库,被三件事砸了一下

震撼一:它不复杂,它啰嗦

我原以为,这种几十万 Star 的项目,代码应该像 Linux 内核一样------模板元编程、几百层抽象、我读不懂的"黑魔法"。

结果打开第一份源码,我愣住了。

没有。全都没有。

真正让我震惊的,是注释。

比如这个函数,干了 6 行的事:

ts 复制代码
// In `u` mode a well-formed surrogate pair is one code point outside this
// range, so the class matches only unpaired surrogates.
const UNPAIRED_SURROGATE_PATTERN = /[\uD800-\uDFFF]/u;

/**
 * Reject unpaired UTF-16 surrogates without advertising a pattern.
 *
 * ECMA-262 spells the surrogate block only as `\uD800-\uDFFF`. RE2 has no `\u`
 * escape and Rust's `regex` and `jsonschema` crates refuse non-scalar code
 * points, and a client that cannot compile one advertised pattern refuses the
 * complete tools request rather than the affected call. The issue keeps the
 * `invalid_format` regex shape an advertised `.regex` raises, so input issue
 * projection still reports `message`.
 */
export const rejectUnpairedSurrogates = <Schema extends z.ZodString>(
  schema: Schema,
  message: string,
): Schema =>
  schema.superRefine((value, context) => {
    if (UNPAIRED_SURROGATE_PATTERN.test(value))
      context.addIssue({
        code: "invalid_format",
        format: "regex",
        message,
        input: value,
      });
  });

上面那段注释,解释的是:

  • 为什么不能直接用 .regex()
  • 为什么是 RE2 的限制
  • 为什么是 Rust 的 regex / jsonschema crate 不肯接受非标量码点
  • 为什么一个人编译不了,会导致整个 tools 请求被拒,而不是单个调用失败
  • 为什么还要保留 invalid_format 的错误形状

一段 6 行的实现,配 15 行"为什么不能是别的写法"。

复杂不在算法,复杂在约束的密度。

震撼二:Schema 就是产品

这一条彻底改变了我对"写 AI 工具"的理解。

我原以为 Prompt 是 Prompt,代码是代码。

在 REA 里不是。工具的 JSON Schema,就是你交付给模型的全部语义。没有别的。

有一条数据我记到现在:

ts 复制代码
// Moonshot's function-calling API rejects requests while any single tool
// parameters schema exceeds its literal serialized size cap. Community
// measurements bound the cap between ~13.7 KB (accepted) and ~15 KB
// (rejected); 13 KiB leaves margin under the lower bound.
export const COMPACT_INPUT_SCHEMA_BUDGET_BYTES = 13 * 1024;

一个第三方 API 的 13.7KB 上限,直接决定了这个项目的 schema 设计。

而且它是个开关:

ts 复制代码
export const resolveMcpInputSchemaProfile = (
  profile: McpInputSchemaProfile | undefined,
): McpInputSchemaProfile => profile ?? "compact";

compact 从 10 月 22 日起就是服务器默认值。

然后这条链条就开始了:

一个默认值改动,一路传到"用户的配置文件被判为过时"。

我修的那个 PR,就是把那个函数和它的两个消费者删掉:

省略一个等于默认值的设置,是"一致",不是"过时"。

震撼三:大部分 Bug 不是代码 Bug

这是最颠覆我认知的一条。

传统软件里,Bug 是"这段代码算错了"。

在 REA 里,大量 Bug 是:代码算得完全正确,但它对世界的建模错了。

回到那个快捷方式的例子:

所以这个项目的 PR 描述里,你看到的不是"我改了什么",而是:

  • 实测数据表
  • 权威文档引用
  • 修复前后对照
  • 哪些情况保持不变

"哪些情况不变"和"哪些情况变了"同等重要。 这是我在这个项目里学到的第一条工程纪律。


第六章 一个 Contributor 的一天

真实的循环

三个真实体感

体感一:CI lane 是分区的,你的 diff 决定你等多久

体感二:最大的坑不是代码,是"分支落后于已修复的 main"

我有两个 PR 连续几天 Source tests 红。我以为是自己代码有问题,查了半天。

结果:失败的那 3 个用例在 JavaScriptAnalysisWorkerServer.test.ts,我一行都没碰过那个文件。

再查------main 自己在同一时间是红的。上游在 14:17 修好了,我的分支落后 41 个 commit,还带着旧的失败。

rebase 到最新 main 之后,同一个测试本机 6 passed。

这条我记进了笔记:CI 红有三类原因------代码问题、flake、以及"分支落后于已修复的 main"。第三类最容易被误判成第一类。

体感三:和人共享分支,比开新 PR 危险得多

我有个 PR 是和仓库所有者共享分支 的。他 13 个 commit,我 13 个 commit,26 个 commit 全部只存在于那个分支上------一个都没进 main。

现在这个分支 rebase 不动了------第一个 commit 就冲突,因为那个文件后来被另一个 44 文件的 PR 重写了(+2084/−603)。

这是我在这个项目里学到的最贵的一课。


第七章 为什么一个小改动要讨论四轮

这一章是我最想写的,也是别人写不了的。

一处路径比较,需要几个约束

我那个 +184/−6、两个文件的 PR,修复的是"Win32 会裁掉路径末尾的句点和空格"这件事。

看起来是 path.replaceAll("/", "\\") 之后加个 .replace(/[. ]+$/, "")。

实际上它需要的约束是:

我从中学到的三条

第一条:先证伪自己。

在说"这是 bug"之前,先构造一个能让自己的解释失败的反例。我那个 V8 的 PR 就是没做这一步,被机器抓了。
第二条:区分"错误计算"和"错误输出"。

代码算对了但结论错了,比代码算错了更危险------因为它看起来是对的。这个项目里大量 bug 属于这一类。
第三条:把"哪些情况不变"写进 PR。

只写"修了什么"的 PR,读者无法判断你有没有引入回归。写了"下表保持不变"的 PR,读者一眼就能看出你的边界。

还有第四条,关于 AI 时代的代码

在这个项目里,我把"我验证过了"和"我验证的方式是对的"彻底分开了。

我原来的证据是 cachedDataRejected === false。实测发现:V8 连被截断的损坏文件都返回 false。

也就是说------我的验证方式本身是无效的,而我完全不知道。

那一刻我理解了为什么这个仓库的代码里全是那种注释。

"我这样做可以工作"和"我这样做是因为别的都不可行",是两种完全不同的知识。 前者会被时间淘汰,后者不会。

这就是 REA 给我的最大冲击:在一个所有人都急着交付结论的领域里,它坚持证明自己的结论方式。


结语

37 个 PR、第 10 名、全球第 4 的项目------这些全都是动态快照。

rea 现在离第 5 名只差 132 星。我和一个自动化账号并列 37 次提交。下周这些数字就都不一样了。

能被时间留下的只有三样东西:

  1. 它验证问题的方式------先构造反例,再下结论
  2. 它把约束写进注释的习惯------解释"为什么不能是别的写法"
  3. 它对"没解决的问题不许集成"的坚持------哪怕代价是 885 个 open PR

如果这一季最后只让你记住一句话,我希望是这句:

在一个所有人都急着交付结论的领域里,一个坚持证明自己结论方式的代码库,是最值得花时间读的。

第二期,我们从 885 个 open PR 开始。


数据截至 2026-11-14。Star 数、排名、PR 合并数均为实时快照,会随时间变化。

相关推荐
AllData公司负责人4 小时前
AI大模型数据开发底座系列说明书,AllData集成Chat2DB开源项目建设AI 数据库分析底座,涵盖AI 洞察/对话SQL/智能视图!
数据库·人工智能·sql·开源·ai 洞察·对话sql
泯泷6 小时前
让 Agent 分清“马上办、等一等、顺手办”
人工智能·llm·agent
鲜于言悠9056 小时前
Claude Fable 5.2 登场,专治复杂推理与长任务
人工智能
联犀7 小时前
如何工程化降低语音交互AI设备的延迟(小智ai,芙崽这样的ai设备)
人工智能
杉岩数据7 小时前
杉岩数据董事长陈坚:从数据存储到行业智能——杉岩的AI时代战略布局
人工智能
冬奇Lab7 小时前
Loop 工程到底是高深的新技术,还是炒冷饭?用训练一个识别狗的模型讲明白
人工智能
冬奇Lab7 小时前
一天一个开源项目(第260篇):Plannotator —— 给 AI 编码 Agent 配一块「可批注的审阅台」,计划和代码改动都能在浏览器里逐条批示
人工智能·开源·claude
泯泷7 小时前
语音,正在成为 AI Agent 最自然的接口
人工智能·llm·agent
杨凯凡9 小时前
IT日报|2026-11-13:GitHub 大规模凭据攻击、Signal 形式化验证、Claude 新模型与 AI 安全诉讼
人工智能·安全·github