Legora 如何使持续集成维护成本减半
Legora 是面向法律工作的 agentic 操作系统,帮助律师在复杂案件中完成研究、审查和起草。目前已有 50 多个市场、1800 多家顶尖律所和企业法务团队的超过 10 万名法律专业人士在使用它。工程规模也在同步扩张:monorepo 一年内几乎翻倍,项目数超过 600 个,月度 CI 运行次数增长了六倍——而支撑这一切的平台团队只有三个人。他们的 monorepo 基于 Nx,主要使用 TypeScript,同时包含 43 个 Python 项目、一个 Rust crate、一个 Java 服务和 protobuf 校验,全部在一条 Nx Agents 流水线中运行。
挑战
Legora 的发展速度超出了原有 CI 架构的承载能力。当时的检查任务通过 GitHub Actions 矩阵在 Blacksmith 上运行,每个检查使用固定的 runner 规格,分片靠手工配置(功能测试 2x、验收测试 6x)。这套方案在团队规模较小时还很合适,但工作流代码在 2026 年 3 月到 5 月间从 94 行膨胀到了 621 行。仅 6 月,独立 PR 数量就增长了 35%,静态矩阵模式不仅用起来麻烦,随着公司扩张还越来越难维护。对三人的平台团队来说,手动调优成了日益沉重的负担——因为新增项目后没有任何机制自动重新平衡。团队的首要目标是稳定性:先确保快速扩张的工程组织能信任自己的流水线,再去优化其他东西。
此外,对缓存的信任也是一大障碍。到春季,团队已经禁用了生产构建的缓存,还自己写了一个校验工具——绕过缓存重新构建并对比输出校验和,因为缓存构建和全新构建的结果偶尔会不一致。
解决方案
Nx Cloud 的 task sandboxing 用每个任务实际读写文件的追踪记录取代了这种猜测。第一次完整运行就标记出 968 个任务中的 811 个存在沙箱违规。大约六周后,团队把沙箱违规清零,并首次启用了严格模式。到 6 月中旬,缓存命中率在两周内从约 50% 提升到了 73%。
我的目标就是把沙箱违规降到 0,这样才能真正信任缓存。没想到的是,这个过程还暴露出了许多其他问题:配置在悄悄互相覆盖、inputs 存在隐蔽的错误。整个仓库在这之后都变得更健康、更快了。
Sofie Thorsen,Legora 技术团队成员
随后,Legora 将核心代码检查迁移到 Nx Agents:构建、类型检查、Lint、单元测试、功能测试和验收测试这些受影响任务的扩展分布,全部运行在团队已作为远程缓存使用的 Nx Cloud 租户上。随之消失的,是那个曾经需要手工维护的、将每项检查绑定到特定 Runner 的矩阵。
需要维护的工作流配置减少了一半,而且对于分布式检查,省去了 Blacksmith 所需的手动分片、按检查项设定 Runner 规格以及必选检查的配置。随着项目的增加,系统会自动重新平衡,而 Blacksmith 则需要持续人工调优。
Sofie Thorsen,Legora 技术团队成员
Nx Agents 的 分布式任务执行 (DTE) 是一个任务分发编排器,而非 Runner。它不会预先将特定检查分配给特定 Runner,而是持续地、按任务粒度决定由哪个 Agent 处理哪部分工作。Agent 池随时待命,每当有一个释放,它就立即领取队列中的下一个任务。没有预先确定的分片边界,也不需要手动将特定检查映射到特定规格的 Runner。
这种持续模型自带了几项好处。快速完成的任务不会等待较慢的关联任务,工作持续流向空闲的 Agent。分配规则会将高 CPU 或高内存的异常任务路由到合适的节点,避免在规格不足的 Agent 上引发内存溢出失败。当检测到任务不稳定(flaky)时,Nx 会在全新的机器上自动重试,而不是让整轮运行失败。任务沙箱机制强制隔离执行:追踪任务读写的所有文件,未声明的访问会导致任务失败,从而确保缓存结果与新构建不会悄悄产生差异。由于由 Nx Cloud 编排运行,它还会 捕获任务级利用率数据(每个任务的 CPU 和内存),用于调优和可视化,这是固定矩阵模型无法提供的。
随着代码库增长,上述机制无需重新调优:新项目和新测试直接汇入同一条持续流水线,无需人工调整分片数量或 Agent 规格。
| 能力 | 编排 | 仅 Runner |
|---|---|---|
| 任务分配 | 通过编排,当 Agent 空闲时自动持续分配任务 | 静态的 GitHub Actions 矩阵,每个检查任务固定分配 |
| 机器分配 | 根据变更规模动态调整机器资源 | 每个检查任务使用固定大小的 Runner,需手动选择 |
效果
对于迁移到 Nx Agents 的检查项,CI 配置篇幅减少了一半,原本需要手动分片、手动为每个检查项指定 Runner 大小以及配置必需检查项的繁琐工作也彻底取消了。
我们的 Dx 团队只有三个人,因此 DTE 的动态持续分配机制比静态矩阵更适配我们这个规模的 monorepo,同时也消除了慢速分片导致其他节点空闲的问题。
Sofie ThorsenLegora 技术团队成员
DTE 工作流现在运行 16 个目标,涵盖 TypeScript、Python、Rust 和 Java,此外还包括 7 项全仓库级的护栏检查,而这些在 5 月份之前并不存在,包括:lockfile 漂移、生成文件同步、合规性规则、认证权限控制、翻译键检查、protobuf 兼容性验证以及 Temporal 代码包检查。所有这些功能所需的配置代码行数,比之前的矩阵模式更少。
联系我们的团队!正在寻找精简平台团队来扩展 monorepo 规模的解决方案?联系我们,了解更多关于 Nx Cloud 的信息。