Cohere · 官方

用AI agent自动化fork维护 | Cohere

Automating fork maintenance with AI agents | Cohere

二〇二六年六月二十六日 · 英文原文

Cohere 团队提出一种基于 AI agent 的通用方法,将维护软件 fork 与上游同步的反馈循环自动化。该方法将循环分解为扰动注入、测量收集和控制器三个组件,每个组件由 agent skill 自动化。应用于 vLLM fork 的案例中,agent 自动将自定义提交 rebase 到新上游版本 v0.19.1,通过运行 Cohere 的 ASR 模型正确性测试检测回归(WER 从 11.92 升至 100),诊断出 transformers 版本升级导致的 tokenizer 行为变化并自动修复,最终将吸收新版本所需时间从数周压缩至数天。相关 skill 已在 cohere-ai/vllm-skills 开源。

你维护着一个 fork。上游在演进。你同步代码,然后出问题,你修复,验证,发布。几周后,上游又变了。这个循环周而复始。

这篇文章描述了一种使用 AI 编码 agent 来自动化这个循环的通用方法。我们将其应用于 vLLM 的 fork,通过一个具体案例来演示:一次常规的上游发布静默地破坏了我们 fork 中 Cohere 的 cohere-transcribe-03-2026 ASR 模型,而修复方案最终以 vLLM PR 的形式回流到了上游。

在实践中,这种方法将吸收新上游版本所需的时间从数周压缩到了数天,人类只需审查最终结果。驱动此工作流的技能已在 cohere-ai/vllm-skills 开源。

问题所在

维护一个活跃开发项目的长期 fork 是一项持续的成本。但上游版本也带来了你想要的特性、性能改进和 bug 修复。保持同步不仅仅是维护,更是让 fork 持续变得更好的方式。问题在于,每个上游版本也都会引入一个扰动:合并冲突、API 变更、函数移除、新依赖或测试失败。fork 维护者的工作就是吸收这个扰动,并恢复到一个可工作的状态。

这项工作的结构始终如一:

  1. 同步:将新的上游版本合并到 fork 中。
  2. 测量:通过运行测试、基准测试、评估来查看哪些地方出了问题。
  3. 修复:解决冲突,适配 API 变更,更新测试。
  4. 重复:重复步骤 2 和 3,直到所有测试通过。
  5. 发布:更新后的 fork。

这是一个反馈循环。每个维护 fork 的团队都存在这个循环;只是它缓慢且手动。对于我们的 vLLM fork,吸收一个典型的上游版本过去需要开发人员断断续续投入数周时间,而下面描述的工作目标是将其缩短到数天,主要由 agent 自主运行。

反馈系统

在控制理论中,闭环系统会持续比较其输出与参考值,并进行调整以缩小差距。但真实系统也面临扰动:将系统推离期望状态的外部输入。

Image 1

控制器利用误差来调整系统;反馈使输出更接近目标。一个设计良好的反馈循环不仅仅是跟踪参考值;它通过检测扰动对输出的影响,并在无需人工干预的情况下将误差驱回零,从而抑制扰动

巡航控制是教科书式的例子。你设定一个期望速度(参考值),汽车维持这个速度(系统),但遇到上坡或逆风(扰动)。一个好的控制器会注意到速度下降并自动调整油门。

Image 2: Cruise control flow Fork 维护具有完全相同的结构。

Image 3: Fork maintenance flow

r(t), 参考值

自定义更改在最新上游上正确工作

d(t), 扰动

新的上游版本:冲突、API 变更、破坏性更改

控制器

解决冲突、更新补丁、修复测试

系统

Fork 本身(代码、测试、CI)

y(t), 输出

同步后 fork 的运行时行为

测量

测试套件、基准测试、评估

目标是自动化整个循环——同步、测量、修复、重复——这样我们就能以最少的人工干预吸收上游的改进。

我们之前的流程

有几种方法可以将 fork 与上游同步:mergecherry-pickrebase 是最常见的。Merge 保留了双方的历史,但会产生混乱的提交图,难以区分自定义更改和上游更改。Cherry-pick 提供了精确的控制,但当上游每个版本移动数百个提交时,它无法扩展;你最终会维护一个不断增长且容易不同步的 pick 列表。Rebase 将你的自定义提交在新的上游标签之上重放,产生一个干净、线性的历史,你的补丁清晰地位于顶部。权衡之处在于 rebase 会重写历史并强制 force-push,但对于一个在快速演进的上游之上只有少量自定义提交的 fork 来说,这种清晰性是值得的。

在 Cohere,我们很早就确定了使用 rebase。在下面描述的基于 agent 的工作流之前,我们的流水线已经混合了脚本化自动化和手动工作。

  1. Rebase: 一个 GitHub Actions 工作流尝试 rebase 到目标上游标签,从共享的 git rerere 缓存中重放之前解决过的冲突。
  2. 解决冲突: 当工作流的自动 rebase 失败时,开发人员在本地接手,手动解决剩余的冲突(通常借助 LLM 助手),验证 CI,并上传更新后的 rerere 缓存。
  3. 验证并发布: 一旦 rebase 后的分支在 CI 上通过,它就成为 fork 的新基础。

这个流程已经结合了多种自动化:git rerere 重放已知的解决方案,GitHub Actions 运行 rebase 尝试和 CI,LLM 协助处理单个编码和调试任务。但人类仍然是控制器的一部分,负责拼接各个部分,选择应用哪些修复,并决定何时重新运行。反馈循环是有效的;只是转得慢。下面描述的基于 agent 的工作流保持了相同的结构,但让 agent 扮演控制器的角色,因此迭代以机器速度进行,人类只在边缘进行干预。

自动化每个组件

该方法将循环分解为三个可由 agent 自动化的组件。每个组件都对应控制图的一部分。

1. 扰动注入

一个 agent skill 检测并应用新的上游版本。它将 fork rebase 到新标签上,并自动解决合并冲突。这就是进入系统的扰动:一个故意的、自动化的操作,我们知道它会暂时破坏一些东西,但我们希望尽可能快地吸收它。

该 skill 需要:

2. 测量收集

Rebase 之后,fork 处于未知状态。测量告诉你离目标有多远:一个所有自定义行为都完好的工作 fork。没有它,agent 就是在盲目飞行。

测量本身(测试、基准测试、评估)由项目定义,并且在任何自动化之前就已经存在。Agent 自动化的是收集它们:一个测试运行器 skill,知道如何设置环境、执行验证套件并报告结果。

输出是误差信号:哪些测试失败,哪些基准测试回归,哪些评估指标下降。测量越丰富、越可靠,控制器收敛得越快。测试套件薄弱的 fork 给出的信号很弱;agent 不知道哪里出了问题,也不知道离完成还有多远。

3. 控制器

一个 agent skill 负责闭环。在 rebase 完成且测量结果返回后,该 skill:

  1. 读取测试和基准测试结果
  2. 识别失败和回归
  3. 应用修复(解决构建错误、更新损坏的测试、适配 API 变更)
  4. 重新运行测量
  5. 重复直到所有测量通过,或升级给人类处理

这就是将误差驱向零的控制器。关键洞察在于,agent 不需要在第一次尝试时就正确完成 rebase,它只需要迭代——就像开发人员一样。

案例研究:vLLM

vLLM 是一个开源的 LLM 服务引擎。在 Cohere,我们在推理栈的各个层面使用它,从模型开发期间的 RL rollout 和评估,到生产环境中服务用户请求。我们维护一个 fork 来承载自定义提交——额外的模型支持、自定义 kernel 和优化、修改的入口点、额外的测试——其中一些正在向上游提交,另一些则是我们特有的需求。挑战在于将这些提交重放到每个新的上游版本上而不破坏任何东西。上游大约每隔几周发布一个版本,每个版本都很大:标签之间的 diff 通常涉及数百个文件。

Skill 栈

我们构建了五个 skill,已在 cohere-ai/vllm-skills 开源,它们实例化了这个通用模式。每个 skill 都是一个 markdown 文档,编码 agent 可以读取并交互式执行,并可以访问终端、文件系统和所需的工具。

install-vllm

环境设置

创建一个 uv virtualenv,以可编辑模式安装 vLLM,并附带正确的预编译 CUDA wheel

local-test-runner

测量

在本地 NVIDIA GPU 上运行等效于 Buildkite CI 的测试;解析 .buildkite/test_areas/*.yaml,管理 HuggingFace token,捕获日志

detect-upstream-base

扰动检测

通过 git merge-base + git describe 找到 fork 当前基于的上游标签 (v1)

rebase-assistant

控制器

将自定义提交从 v1 rebase 到 v2,使用上游 diff 作为上下文解决冲突,通过 test-runner 验证结果

Rebase 如何运行

在本节中:v1 / v2 是旧的和新的上游标签,b1 / b2 是 rebase 前后的 fork 分支。

一个典型的调用:"/auto-rebase sync 当前分支与最新的上游版本,并确保 <test> 通过。"

  1. auto-rebase 检查先决条件(gh auth status),然后调用 detect-upstream-base 找到 v1(例如 v0.19.0)。

  2. 它获取上游标签并发现 v2(v0.19.1)。它向用户展示版本并等待确认。

  3. 它从用户那里收集验证检查(例如 pytest tests/entrypoints/openai/correctness/test_transcription_api_correctness.py)。

  4. 它调用 rebase-assistant,该 assistant:

    • 分析 b1 上的自定义提交(git log v1..HEAD
    • 首先验证测试在 b1 上通过(使用 local-test-runner 和 v1 wheel),这是确保我们有一个已知良好基线的门控
    • 备份 b1,创建 b2,可选地压缩自定义提交
    • 运行 git rebase --onto upstream/v0.19.1 <fork-point> HEAD
    • 通过比较 upstream/v1..upstream/v2 的 diff 来理解发生了什么变化,从而解决冲突
    • 在 b2 上运行测试(使用 local-test-runner 和 v2 wheel)
    • 如果测试失败:检查失败原因,与 v1 基线比较,应用修复,并重新运行(内部反馈循环)
  5. 一旦所有检查通过,auto-rebase 呈现一个摘要(重放的提交、解决的冲突、测试结果)并提供推送选项。

作为一系列 skill 交互:

Image 4: Sequence of skill interactions 内部循环是控制器在 b2 上迭代:local-test-runner 报告失败,rebase-assistant 应用修复并重新运行,直到测试通过。

工作示例:v0.19.1 上的 Cohere Transcribe

以下是这个循环的一次真实调用,端到端。

设置: 我们的 fork 位于 cohere-transcribe-v0.19.0,在上游 v0.19.0 之上有一个自定义提交,该提交启用了 Cohere 的 cohere-transcribe-03-2026 ASR 模型的正确性测试。vLLM 在 v0.19.0 中添加了对该模型架构的支持,但上游测试被注释掉了,因为权重尚未发布。我们的自定义提交只是取消注释了一行。

# TODO (ekagra): turn on after asr release
        # CohereASR is used to test the variable encoder length code paths
        ("CohereLabs/cohere-transcribe-03-2026", 11.92),

该测试在 earnings-22 验证集的一个过滤切片上运行模型,并断言 WER ≤ 11.92。这个单一数字就是我们的测量信号 y(t)。当 fork 健康时,该数字接近 11.92;当出现问题时,它会飙升。

扰动: 上游发布了 v0.19.1。这是一个增量版本,但并不小:它包括一个 transformers 版本升级和相关的重构。我们用一个 prompt 运行 auto-rebase。

/auto-rebase let's sync current branch with latest upstream release,
make sure the test CohereLabs/cohere-transcribe-03-2026 passes
@tests/entrypoints/openai/correctness/test_transcription_api_correctness.py:172-173

结果:

  1. 将自定义提交 rebase 到 v0.19.1 并在 b2 上重新运行测试后,结果返回 WER = 100——完全失败,模型输出垃圾内容。
  2. 控制器循环诊断了回归:rebase-assistant 比较了 upstream/v0.19.0..upstream/v0.19.1 的 diff,将失败追溯到升级的 transformers 版本,该版本改变了模型 tokenizer 处理其 prompt 前缀的方式,并应用了一个快速修复来绕过它。WER 恢复到 ~11.92,fork 在 v0.19.1 上通过,整个过程在一个交互式会话内完成。

循环端到端地工作:扰动到来,控制器吸收它,fork 自动恢复到健康状态。

后续: 由于该 bug 影响了该模型的每个下游用户,我们提交了 vllm-project/vllm#40582 将变通方案转化为一个合适的上游修复。一旦合并,下一个版本将不再需要为此模型打 fork 补丁;扰动对所有人都消失了。

超越 vLLM

每当一个代码库吸收外部变更并需要收敛回工作状态时,同样的闭环结构都适用。

另一个最近的例子是我们内部维护的 HuggingFace transformers fork,我们在其公开发布之前维护着 command-a-plus-05-2026。当 transformers v5 发布,移除了废弃参数、引入了新的必需签名、改变了 tokenizer 行为时,所有这些就是扰动。应用了相同的循环:升级到 v5,运行模型的正确性评估和生成测试,让 agent 在失败上迭代。在导入路径、API 调用和 tokenizer 默认值方面出现了几个问题;有些被自主修复,另一些需要人类介入解决。循环持续进行,直到模型在公开发布前在 v5 上正确生成。

Skill 不同,但结构相同:引入变更,测量差距,闭环。

结论

Fork 维护的结构不会改变:同步、测量、修复、重复。改变的是循环转动的速度。

在基于 agent 的工作流之前,将我们的 vLLM fork 与新的上游版本同步需要数周:等待某人切换上下文、手动分类冲突、重新运行 CI、一次一个地调试失败。通过 auto-rebase 驱动控制器循环,这个时间线已经压缩到了数天。而且由于预期的测量已预先设置在仓库中,整个流水线无需人工输入即可运行;只需要一个人审查最终结果。

该方法适用于任何具有可测量“工作”定义的 fork:检测扰动,收集测量,让 agent 在误差上迭代。这些 skill 是可组合的,控制理论的框架使其易于适应新的代码库。

本文中描述的 skill 已在 cohere-ai/vllm-skills 开源。如果你维护一个 fork 并想尝试这种方法,首先编写一个测量(测试、基准测试、评估)来捕获对你 fork 而言“健康”的含义。循环的其余部分由此展开。

致谢

感谢 Ekagra Ranjan 协助 Cohere Transcribe 实验,感谢 Zhoujie Zhao 和 Walter Beller-Morales 帮助塑造 agent skill,感谢 Bharat Venkitesh 支持这项工作。

译自 Cohere · 官方 · 录于 二〇二六年六月二十六日