pr-draft-summary :OpenAI 是怎么让 Codex 写 PR 描述的

改完两百行代码,你跟 AI 说帮我写个 PR 描述。它回你三段话,第一段复述你刚做的事,第二段写这次改动提升了代码质量与可维护性,第三段列了一串你根本没跑过的测试。你想改,又不知道从哪一句改起。

问题不在模型。你给的是一句话的意图,它只能靠猜去补上下文,猜不出来就用最安全最空洞的模板填满。openai/openai-agents-python 这个仓库里有个叫 pr-draft-summary 的 Skill 专门治这个毛病,思路很朴素,一句话能说完:把写 PR 描述这件事拆成四个环节,每个环节都写死约束,最后压进一个 5.6KB 的 SKILL.md。

pr-draft-summary :OpenAI 是怎么让 Codex 写 PR 描述的

这四个环节分别是:

  • 什么情况下才该触发
  • 触发后先去采集哪些输入
  • 怎么给这次改动定性
  • 最终输出长什么样

我一开始以为这只是个格式化脚本,看完才意识到它真正的价值在另一处。它把本来属于模型自由发挥的整段区间,硬切成了一条有门禁的流水线,每个环节都有明确答案:

  • 哪些情况才该跑
  • 跑之前先执行哪几条 git 命令
  • 描述开头必须是哪个动词
  • 引用必须归一成什么形态

模型只负责最后一公里的措辞。

这也是它值得拆的原因。它不是社区里那种写着玩的 Prompt 玩具,是 OpenAI 放在自己生产仓库 .agents/skills/ 目录下、跟着代码一起进版本库的工程约束。你拿到的是一份被真实交付流程打磨过的样本。

我准备从四个维度拆它:

  • 触发判定是怎么写的
  • 输入采集凭什么敢写 do not ask the user
  • 十步工作流里哪些步是真正的防呆设计
  • 输出规范化为什么要用一整条指令去描述重扫

拆完再聊它的局限和我自己的改法。

架构分析

整份 SKILL.md 是标准五段式:

  • Purpose
  • When to Trigger
  • Inputs to Collect Automatically
  • Workflow
  • Output Format

这五段不是并列的说明文档,是一条自上而下收紧的链路,越往下约束越硬。

pr-draft-summary :OpenAI 是怎么让 Codex 写 PR 描述的

最上面那层 Purpose 只有两句话,但锁死了整份文档的硬约束:产物必须包含一个可以直接粘进 PR 的块,描述必须以 This pull request 开头。这两句看着不起眼,实际是把输出的自由度在最开始就砍掉一半。很多人写 Prompt 喜欢在结尾加一句请输出得专业一些,那种话等于没说,模型根本不知道专业指什么。这里给的是可判定的字面条件。

第二层 When to Trigger 用的是负向清单优先的写法。它先把不该跑的情况列全:

  • 纯拼写、注释、格式改动
  • 纯对话任务
  • 仓库元信息或文档改动且无行为影响
  • 用户明确说不要
  • $release-candidate-prep 交接这类已有专门产物的场景

列完之后才说该跑什么。这个顺序很关键,因为排除项才是模型最容易踩坑的地方,正向描述写得再漂亮也拦不住它在改一行 typo 时给你输出一个 PR 草稿。

第三层 Inputs to Collect Automatically 是全篇信息密度最高的部分,一共七条 git 命令,标题里那句 do not ask the user 是核心。它不允许模型反问用户你的分支名是什么、你改了哪些文件,而是要求它自己去壳里执行。这一条把 Skill 从对话提示词升级成了带工具调用约定的程序。

git rev-parse --abbrev-ref HEAD
git status -sb
git ls-files --others --exclude-standard
git diff --name-only && git diff --name-only --cached
LATEST_RELEASE_TAG=$(.agents/skills/final-release-review/scripts/find_latest_release_tag.sh origin 'v*' 2>/dev/null || git tag -l 'v*' --sort=-v:refname | head -n1)
BASE_REF=$(git rev-parse --abbrev-ref --symbolic-full-name @{upstream} 2>/dev/null || echo origin/main)
BASE_COMMIT=$(git merge-base --fork-point "$BASE_REF" HEAD || git merge-base "$BASE_REF" HEAD || echo "$BASE_REF")

还有个容易忽略的细节:这份文档在 Smithery 上的版本比 skills.sh 收录的旧版多了两条,也就是第 08 步和第 09 步,专门处理 GitHub 引用的规范化。旧版只说引用 issue 时用 #123,新版加了一整段禁止清单,明确不许出现 PR #123 这种 Markdown 链接形态,并要求输出前 rescan 全文。能看出这是被真实事故逼出来的补丁,模型太喜欢把引用包成链接,粘到 GitHub 上就成了噪音。

工作流分析

Workflow 段编号从 01 到 10,读下来像一份被反复修过的检查单,几乎每一条都能对应到某个具体的翻车现场。

pr-draft-summary :OpenAI 是怎么让 Codex 写 PR 描述的

第 02 步要求先算 BASE_REF 和 BASE_COMMIT 再跑后面的命令,理由是后面的 diff 都要复用这两个值。这种顺序依赖写出来很琐碎,但不写模型就会每条命令各算一次,算出来的 base 还不一定一致,最后摘要张冠李戴。

第 03 步是分类与兼容性风险判定,这里有个我觉得很狠的设计。它要求风险判定必须对照 LATEST_RELEASE_TAG 做,而不是对照当前分支。意思是判断这次改动会不会破坏公开 API,基准是已经发出去的那个版本,不是你本地那堆还没合的提交。少了这句话,模型会拿工作区里的最新代码当基准,从而把所有 breaking change 都判成内部调整。

第 04 步点名了一个非常具体的坑:git diff --stat 不包含 untracked 文件,所以必须用 git status -sb 加 git ls-files --others --exclude-standard 补。新手写 Skill 最常漏的就是这个,结果新增的文件在摘要里凭空消失,PR 描述里只字不提真正的核心改动。

第 05 步给了一张动词映射表,feature 对应 adds,bug fix 对应 fixes,重构或性能对应 improves 或 updates,纯文档对应 updates。看起来是小事,作用是把描述的开头语气统一掉,避免同一个仓库里一半 PR 写 This PR adds,另一半写 This PR introduces。

第 06 到 07 步处理分支名和 issue 关联。已经在 main 之外的分支就保留,否则按主改动区域建议 feat/ fix/ docs/ 前缀;分支名如果匹配 issue-<数字>,保留原名并自动补一行 This pull request resolves #<number>.。第 09 步再兜一次底,把所有同仓库的 URL 归一成 #123,跨仓库的归一成 owner/repo#123,然后要求重扫全文确认没有遗漏。这两步加起来,本质是在做一个输出前的 lint。

使用场景

判断一个 Skill 好不好用,得看它在边界场景下的表现。这份文档对边界的处理比我预期细,我挑四个典型场景说。

pr-draft-summary :OpenAI 是怎么让 Codex 写 PR 描述的

第一个场景是本地改了一堆还没提交,用户压根没提 PR 两个字。文档明确说这种情况要跑,并且加了一句 Producing this text does not authorize creating a branch, committing, pushing, or opening a pull request。这句是给 Agent 的权限划界,防止它自作主张把代码推上去。很多人写这类 Skill 时会漏掉权限声明,结果 Agent 一边生成描述一边顺手 commit 了。

第二个场景是改动只在注释、拼写、格式上,即便路径落在 runtime 或测试目录里。文档把这类判为 editorial,要求跳过。判定标准是是否改变行为或契约,不是文件在哪个目录。这个区分很值钱,因为按路径判断是最省事的写法,也是最容易误触发的写法。

第三个场景是用户明确说不要。文档把显式用户指令的优先级放在自动触发规则之上,包括自动触发的排除项。这条看着理所当然,但在 Prompt 里经常会被一堆规则淹没,模型容易记住规则忘了人话。

第四个场景是 release 流程。文档说当 $release-candidate-prep 被显式调用并且要用 $final-release-review 的完整报告作为 release 专用描述时,跳过本 Skill,同时补了一句这条例外只适用于准备 release candidate 本身,不适用于修改 release 准备流程的 Skill。这种补丁式的补充说明,一看就是踩过坑才写出来的。

洞察与反思

拆完之后,我觉得这份文档最值得抄走的设计有三个,也各有各的代价。

设计 做法 代价
输入采集脚本化 七条 git 命令 + do not ask the user 强依赖 shell 环境,无 git 的场景直接失效
排除项优先 先列 5 类 skip 场景再讲触发 判定仍需模型理解行为影响,非机械匹配
输出前 lint 第 09 步引用归一化 + rescan 全文 占用输出 token,长 PR 描述成本上升

第一个亮点是把输入采集从对话搬进了脚本。Prompt 工程里最容易被低估的一件事是:模型输出质量的下限,取决于它拿到的上下文是不是确定性的。你让它问用户改了哪些文件,用户可能随口说个大概;你让它执行 git diff --name-only,它拿到的一定是真的。

第二个亮点是输出规范化那条 rescan 指令。它不只说要用 #123,还列举了所有禁止形态,并要求输出前重扫一遍。这是在承认一件事:单次约束对模型不够用,得给它一个自检动作。这个思路可以直接搬到任何要求格式稳定的 Prompt 里。

不足也很明显。最要命的是强绑定 openai-agents-python,category signals 里把路径写死了:

  • runtime → src/agents/
  • tests → tests/
  • examples → examples/
  • docs → docs/、mkdocs.yml
  • 构建配置 → pyproject.toml、uv.lock、Makefile、.github/

换仓库不改这些路径,分类推理会全部失准。它是一份仓库内置规范,不是通用工具,你照搬之前得先做适配。

另一个不足是全篇零 few-shot。所有要求都用规则描述,没有给一个合格输出和不合格输出的对照样例。规则能约束格式,约束不了语气和详略程度。真要我改,我会补一组正反例,再给描述加一个硬上限,比如正文不超过 150 词。现在这版只说 Keep it tight,tight 是多少全靠模型自己领会。

资源地址

资源 链接
Smithery 页面 https://smithery.ai/skills/openai/pr-draft-summary
来源仓库 https://github.com/openai/openai-agents-python
安装命令 npx skills add https://github.com/openai/openai-agents-python –skill pr-draft-summary

总结

值不值得用,取决于你在哪个仓库。如果你就在 openai-agents-python 里干活,或者你的仓库结构跟它接近,这份 Skill 基本是开箱即用,改几个路径就能跑。如果你指望拿它当通用的 PR 描述生成器,那得先做一轮适配,而且适配完你会发现它的价值主要在分类信号那一层,不在生成那一层。

对我自己写 Prompt 的启发有两条。一条是排除项比正向描述重要,先写清楚什么时候不要跑,再写什么时候跑。另一条是能脚本化的输入就不要用对话问,确定性上下文比任何措辞技巧都管用。

还有个更大的问题留在这:这类收口型 Skill 到底该不该默认自动触发?它规定每次最终回复前都要检查一遍,代价是每次对话都多一轮判断。我倾向于在小仓库里值得,在大仓库里会拖慢节奏。你怎么看,评论区聊。

skills资源开源项目

nuget-manager:凭什么管住 AI 改 NuGet 包

2026-10-6 23:07:14

AI工具

GPT-5.6 评测:三档模型同台,OpenAI 的效率牌打对了吗?

2026-7-10 11:03:33

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