你打开 Codex 的 PR:title 是 “Update components”,body 是 “Refactored several components for better readability”——完。12 个文件、400 行 diff,没说改了什么、为什么、怎么测的。Reviewer 现在只能冷读全部 diff,没有作者意图作为参照。
这不是 Codex 能力问题。让它写一份好 PR 描述完全办得到,默认糟糕是因为大多数 repo 没有 PR template、AGENTS.md 没写描述格式,model 就用最泛的语气填空。
修法:.github/PULL_REQUEST_TEMPLATE.md + AGENTS.md 里告诉 Codex 必须用它,每节怎么从自己的 commit log 抽内容。
常见原因
1. Repo 没有 PR template
GitHub “New pull request” 弹出来是空的。Codex 没锚点,写一句话就发了。
如何判断:ls .github/PULL_REQUEST_TEMPLATE.md 没东西。PR 描述直接从 model 的散文开始。
2. AGENTS.md 没写 PR 描述格式
Codex 听 AGENTS.md。这个文件一句都没写 PR 格式,agent 就用训练数据里的 default,通常很泛。
如何判断:grep -i 'pull request\|pr description\|pr body' AGENTS.md 没结果。
3. 任务 prompt 本身就一行
你说 “修一下 date picker 的 bug”。Codex 写的 PR body 详细度大约等于你的 prompt。短输入短输出。
如何判断:对比 Codex 任务描述和 PR body。都是一句话——瓶颈在 prompt。
4. Harness 把 PR body 截断了
有些 Codex CLI/wrapper 走 CLI flag 传 body,有长度上限;或者中间经过 script 把换行抹掉。Model 写得很详细,上传那一步被截了。
如何判断:对比 git log(或 agent transcript)里看到的 body 和 GitHub 上的 body。GitHub 上短,就是 harness 吃了。
5. Codex 把第一个 commit message 当成了 body
没有其他指引时 agent 会复制第一个 commit subject 同时当 title 和 body。结果 PR body 和 commit subject 完全一样,没有展开。
如何判断:看 PR body 是不是等于第一个 commit message。是的话,prompt 或 harness 没要求更丰富的 body。
最短修复路径
Step 1:写 PR template
新建 .github/PULL_REQUEST_TEMPLATE.md:
## 改了什么
<一段总结>
## 为什么
<问题、动机、或关联的 issue>
## Before / After
<行为变化的话:写清楚或贴图 before 和 after>
## 怎么测的
- [ ] `npm test` 本地通过
- [ ] 手动检查:<步骤>
- [ ] 新增测试覆盖:<场景>
## 风险
<什么可能坏,谁依赖被改的代码>
## 相关
<关联 issue、关联 PR>
GitHub 会自动把这份 template 填到 PR body。Codex 看到空的 section 会填。
Step 2:AGENTS.md 写要求
追加到 AGENTS.md:
## PR 描述
你开的每个 PR 都必须严格遵循 `.github/PULL_REQUEST_TEMPLATE.md`。每节都填。具体:
- **改了什么**:列出对用户可见的行为变化,或者按 file path 列结构性变化。
不要写 "重构组件"——要写 "把 `useSession` 从 `Header.tsx` 抽出来,
dashboard 可以复用了"。
- **为什么**:有 issue 就链,没有就描述 bug / 需求。
- **Before / After**:UI 或行为变化要展示两个状态。
- **怎么测的**:列具体跑过的命令,不要写 "本地测过了"。
- **风险**:至少指出一个可能坏的地方。
某节不适用时写 "N/A — <原因>",不许留空。
这样把 template 变成强制结构。
Step 3:用 commit log 起草 body
AGENTS.md 里加:
起草 PR body 时,"改了什么" 一节基于 commit log:
git log --reverse origin/main..HEAD --pretty=format:'- %s'
每个 commit 变成一条 bullet。然后每条 bullet 用一句话扩展 context。
这样 PR body 和真实改动对得上。
agent 写描述就有具体素材了,不是 vibes。
Step 4:CI 验证描述长度
加 workflow 拦短 body:
# .github/workflows/pr-description.yml
name: PR description check
on:
pull_request:
types: [opened, edited, synchronize]
jobs:
check:
runs-on: ubuntu-latest
steps:
- name: Require non-trivial description
env:
BODY: ${{ github.event.pull_request.body }}
run: |
if [ -z "$BODY" ] || [ ${#BODY} -lt 200 ]; then
echo "PR body 太短(需要 200+ 字符)。用 template。"
exit 1
fi
for section in "改了什么" "为什么" "怎么测的"; do
if ! echo "$BODY" | grep -q "$section"; then
echo "缺少节:$section"
exit 1
fi
done
这个 workflow 设为 required status check,Codex 一句话 body 就 merge 不了。
Step 5:写更好的任务 prompt
agent 镜像你的 prompt 详细度。用 prompt template:
TITLE: <一句话,祈使句>
CONTEXT: <为什么重要,链 issue>
SCOPE: <文件 / glob>
ACCEPTANCE:
- <具体测试或行为 1>
- <具体测试或行为 2>
NOTES FOR PR BODY:
- "Before / After" 一节提到 <X>
- 链 issue #<N>
Codex 把这些 note 翻译成 PR section。
预防
- 把
.github/PULL_REQUEST_TEMPLATE.md提交进 repo,节就是你真正想要的那些 AGENTS.md要求填每一节,不许无理由的 “N/A”- 让 agent 用
git log起草 “改了什么”,不要新写一份总结 - CI 检查 PR body 长度和节标题,required status check
- 任务 prompt 也用结构化模板,agent 才有 PR body 素材
- 看 GitHub 上的真实 body,不只是 transcript——harness 可能截断