changeset-validation:OpenAI 把 PR 的版本审核外包给了 AI

你给 openai-agents-js 提了一个 PR,改了 packages/core 里几个函数签名。CI 全绿,你点了合并。五分钟后 release manager 在下面留言:“changeset bump level 不对,这个改的是 public API,应该 minor 不是 patch。”

这种对话在 monorepo 维护中每天都在发生。判断 bump level 本身不难,但当一个仓库每天合并十几个 PR、每个都可能跨多个包时,靠人眼审核就成了纯粹的时间黑洞。

OpenAI 的 Agents SDK 团队也深受其苦。他们的解法不是多招几个 release manager,而是写了一个 Codex Skill 让 LLM 来干这件事。这个 Skill 叫 changeset-validation,存放在仓库的 .agents/skills/ 目录下,核心规则文件不到 300 行。

说真的,看完这个 Skill 的设计逻辑之后,我意识到一个问题。我们用了很多 AI 来写代码、跑测试、修 bug,但很少用它来审核代码的“元数据”。changeset 本质上是代码变更的摘要信息,让 LLM 来校验摘要和正文是否匹配,其实比让人做更靠谱,机器不会疲劳,也不会在审到第十个 PR 时随手点 approve。

环境准备

changeset-validation 不是一个独立安装的工具。它是 openai-agents-js monorepo 内建的 Codex Skill,存在 .agents/skills/changeset-validation/ 目录里。如果你有自己的 monorepo 想复用,核心依赖只有两个:一个跑 Changesets 的仓库,以及一个能读 Skill 的 Codex 环境。

仓库这边,项目根目录需要有 .changeset/ 目录,package.json 里配置了 @changesets/cli。OpenAI 的 JS 仓库用 pnpm workspace 管理多包结构,但 Skill 本身不绑定包管理器,你用 npm workspaces 或者 yarn 也一样能跑。

安装就是把仓库 clone 下来。核心文件就两个:SKILL.md 是 Skill 的入口描述,references/validation-prompt.md 才是真正干活的东西。这个文件里用自然语言写了所有变更验证规则,LLM 读取后对照 git diff 判断 changeset 是否正确。配套脚本 pnpm changeset:validate-prompt 只做一件事:收集上下文(git diff 的内容 + 已有的 changeset 文件),拼接成一个 prompt 交给 LLM。

验证命令的用法很简单:

# 本地模式:prompt 输出到终端,Codex 当场判断
pnpm changeset:validate-prompt

# CI 模式:prompt 写入文件,由 Codex GitHub Action 消费
pnpm changeset:validate-prompt -- --ci --output .github/codex/prompts/changeset-validation.generated.md

changeset-validation:OpenAI 把 PR 的版本审核外包给了 AI

两种模式共享同一份 validation-prompt.md,彻底消灭了“本地跑得过、CI 炸了”的经典问题。CI 模式多了一个 --output 参数,把 prompt 写到指定路径,后续由 openai/codex-action 在 GitHub Actions 工作流中消费。

操作流程

整个验证链路分三步,但每一步都有值得展开的细节。

第一步,脚本收集两个关键输入。一个是当前分支相对于 main 的完整 git diff,另一个是 .changeset/ 目录下所有已有的 changeset 文件。diff 告诉你“实际改了什么”,changeset 告诉你“声称改了什么”。两个一对齐,矛盾的地方就浮出来了。

第二步,LLM 读取 references/validation-prompt.md 中的规则,逐条对照 diff 和 changeset 的内容做判断。规则用自然语言写的好处在这里体现得很明显。比如有一条规则是这样表述的:“如果变更被明确标记为 experimental 或 preview-only,且不改变现有行为,bump level 可以保持 patch。”这种带语义判断的条件,用正则表达式去匹配几乎不可能写对,但 LLM 处理起来毫不费力。

第三步是 bump level 校验,也是最容易出问题的环节。LLM 需要判断实际代码变更的幅度是否和 changeset 里声明的版本升级级别一致。这里有一条硬规则:在 1.0 正式版发布之前,禁止使用 major bump。很多开发者的直觉是“我加了个大功能,应该升 major”,但 pre-1.0 的语义版本规则不是这么玩的。Skill 把这条写死了,直接拦截。

changeset-validation:OpenAI 把 PR 的版本审核外包给了 AI

还有一个容易被忽略但很重要的分支级规则:如果当前分支已经存在 changeset 文件,Skill 不会新建,而是更新已有的那份。摘要要求压缩到一行,风格遵循 Conventional Commit 规范。这个约束看着小,解决了一个高频痛点。你改了三版代码,每次都 changeset add,最后 .changeset/ 里躺了五六个 markdown 文件,没人知道哪个是最终版。

最终输出是一个结构化的 JSON 判定:

{
  "ok"false,
  "errors": ["Bump level should be minor (was patch) due to function signature change in packages/core"],
  "warnings": ["Summary could be more specific about which APIs changed"],
  "required_bump""minor"
}

ok 决定 CI 是否放行,errors 列出必须修的硬伤,warnings 是建议性提示。required_bump 是 LLM 根据 diff 判断出的正确 bump level,直接告诉开发者该改什么,不用自己猜。

关键设计

changeset-validation 最值得聊的,不是它做了什么,而是它有意不做什么。

第一个设计决策:规则用自然语言写,不写代码。validation-prompt.md 是唯一的真相源,脚本只负责收集上下文和生成 prompt。这意味着改一条验证规则不需要动任何脚本代码,直接编辑 markdown 文件就行。对比很多项目把规则硬编码在 CI 配置和 shell 脚本里、改一行要改三个文件的做法,这种“Prompt as Policy”的思路对快速迭代的开源项目友好太多了。

第二个决策:errors 和 warnings 的分层设计。JSON 输出里的这两层不是随便分的。errors 是硬伤,比如 bump level 选错了、changeset 文件缺失,CI 必须 block。warnings 是建议,比如摘要可以更精确、命名不符合惯例,CI 可以配置为只 warn 不 block。这给了维护者灵活调整的空间,不会因为规则太严导致所有 PR 都被卡住。

分支级去重规则的设计动机也值得细品。要求“已有 changeset 则更新而不是新增”,并且“摘要只能一行”,相当于每次 push 都在强制维护者重新审视自己的 changeset 是否还准确。初看像是增加工作量,但想想 changeset 不准确导致的 changelog 混乱有多难修,这个约束是划算的。

changeset-validation:OpenAI 把 PR 的版本审核外包给了 AI

不足的地方也很明显。这个 Skill 深度绑定 openai-agents-js 的仓库结构,虽然核心逻辑能移植,但没有抽象成通用工具。另外它完全依赖 LLM 的判断,在语义版本的边界情况上,比如“改了内部函数的参数名,但对外暴露的 API 没变”。LLM 的判断可能不够稳定。这个问题不是工具能解决的,它根植于语义版本规范本身的模糊地带。

使用场景

最高频的场景是 PR 提交前的本地自检。开发者在 push 之前跑一遍 pnpm changeset:validate-prompt,Codex 对照 diff 当场判断,有问题立刻改。不用等 CI 红了再回来修,也不用让 reviewer 手动指出 bump level 的问题。几秒钟的事情,省掉了 PR 评论链上来回两三趟的沟通。

CI 门禁是第二个核心场景。openai-agents-js 把 changeset-validation 挂在了 PR 的 GitHub Actions 工作流里,作为合并前的必过检查项。效果直接:不合规的 changeset 进不了 main 分支。因为 validation-prompt.md 在本地和 CI 共享,两种模式下 LLM 的判断逻辑完全一致,消除了“在本地好好的、推到 CI 就炸”的环境差异。

如果没有 Codex GitHub Action,这个 Skill 的思路仍然能复用。本质上它做的是“用 LLM 判断 git diff 和 changeset 是否匹配”,你完全可以在本地用 Claude Code 或者任何支持自定义 system prompt 的工具实现类似效果。核心价值不在特定的工具链,而在于把审核规则从“人脑里的默契”变成了“可版本控制的文档”。

从 OpenAI 官方博客披露的数据来看,引入这套 Skill 体系后,JS 仓库三个月内的 PR 合并量从 134 跳到了 231,增幅超过 70%。虽然这不是 changeset-validation 一家的功劳,但 release metadata 的错误率下降确实减少了 PR 的反复沟通成本。每一个被 changeset 审核卡住的 PR,至少浪费两个人各十分钟。

洞察与反思

这个 Skill 让我重新想了一个问题:在开源维护中,什么样的工作应该自动化,什么样的不应该

代码格式化、lint、类型检查,这些早就自动化了,因为它们有明确的对错标准。但 changeset 审核不一样,涉及语义判断,边界模糊。传统思路是“模糊的事情让人来做”。问题在于,人处理模糊的事情时也经常犯错,尤其是连续审了十几个 PR 之后,认知疲劳会让判断质量直线下降。

changeset-validation 的做法是取一个折中方案。让 LLM 做初筛,框出明显的问题,人只需要处理 LLM 标记为不确定的边界情况。这不是用 AI 替代人,是用 AI 把人的精力集中在真正需要专业判断的地方。审 changeset 这件事,90% 的情况判断标准非常明确,LLM 完全可以胜任。

从更大的视角看,OpenAI 两个 SDK 仓库的 Skill 化实践,其实给出了一套可复用的开源维护自动化模型。每个 Skill 职责窄而清晰,有明确的触发条件,输出结构化结果。Python 仓库 8 个 Skills,JS 仓库加 3 个专属的,总共 11 个,覆盖了从代码验证、文档同步、覆盖率检查到发布前审查的完整维护链路。

如果你在维护一个活跃的 monorepo,不一定要全套照搬这套体系。但至少可以学一个思路:把团队里“每次 PR 都要做一遍”的重复判断工作,写成规则文档,让 LLM 来执行初筛。changeset-validation 证明这件事可行,而且门槛比你想象的低,核心就是一个不到 300 行的规则文件加上一个收集上下文的脚本。

资源地址

资源 地址
Smithery smithery.ai/skills/openai/changeset-validation
GitHub 仓库 github.com/openai/openai-agents-js
OpenAI 博客 developers.openai.com/blog/skills-agents-sdk

总结

changeset-validation 解决的其实不是一个技术难题,是一个流程效率问题。它做的事情任何一个有经验的维护者都能做:看 diff、判断 bump level、检查 changeset 格式。但当这件事每天要重复十几次时,把它自动化掉就很值了。

这个 Skill 给我们的启发也不仅限于 changeset。任何高频重复、有明确判断标准但带一定模糊性的审核工作,都可以用同样的思路来解决。把规则写成文档,让 LLM 对照执行,人只处理边界情况和 LLM 不确定的灰色地带。

如果你正在维护一个用 Changesets 管理版本的 monorepo,clone 这个仓库,看 .agents/skills/changeset-validation/ 里的两个文件就够。不到 300 行的规则文档,可能帮你省掉 PR 审核中最无聊也最容易出错的那部分工作。

skills资源

PyTorch 构建 building 深度拆解:从环境准备到跨端编译

2026-7-16 10:42:00

开源项目

Superpowers:AI 编程 Agent 的工程化操作系统

2026-7-1 15:48:30

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧