[{"data":1,"prerenderedAt":564},["ShallowReactive",2],{"header-counts":3,"playbook-review\u002Fai-code-review-workflow":6,"footer-counts":561},{"tools":4,"reviews":5},65,7,{"id":7,"title":8,"body":9,"category":541,"cover":542,"description":543,"extension":544,"meta":545,"navigation":546,"path":547,"published":548,"relatedTools":549,"seo":553,"stem":554,"tags":555,"updated":559,"__hash__":560},"playbook\u002Fplaybook\u002Freview\u002Fai-code-review-workflow.md","AI 做 PR Review：开发者的 5 倍速 review 工作流",{"type":10,"value":11,"toc":517},"minimark",[12,16,29,41,44,64,68,73,149,152,156,164,170,174,177,182,188,192,198,207,211,217,221,227,231,237,243,246,249,329,340,343,370,373,377,384,388,395,399,409,413,420,422,426,429,495,498,500,513],[13,14,15],"h2",{"id":15},"谁需要这套流程",[17,18,19,23,26],"ul",{},[20,21,22],"li",{},"团队 leader \u002F staff engineer，每天 review 5-10 个 PR",[20,24,25],{},"独立维护者，开源项目 PR 多但人手少",[20,27,28],{},"想给自己的 PR 自查的开发者",[30,31,32,36,37,40],"p",{},[33,34,35],"strong",{},"核心承诺","：让 AI 做\"第一道筛\"——把明显问题 + 一致性问题先过一遍，",[33,38,39],{},"人脑只看 AI 标出来的高价值地方","。",[13,42,43],{"id":43},"不要做什么",[17,45,46,54,61],{},[20,47,48,49,53],{},"❌ 让 AI 写 ",[50,51,52],"code",{},"LGTM"," 然后 merge——AI 会把烂代码 review 通过",[20,55,56,57,60],{},"❌ 让 AI ",[33,58,59],{},"决定","合不合并——AI 只做建议，决策权在人",[20,62,63],{},"❌ 把 PR 全文丢给 ChatGPT 网页版让它\"看看\"——上下文不够，结论不可信",[13,65,67],{"id":66},"工作流4-步法","工作流：4 步法",[69,70,72],"h3",{"id":71},"step-1-准备-review-上下文2-min","Step 1 — 准备 review 上下文（2 min）",[74,75,80],"pre",{"className":76,"code":77,"language":78,"meta":79,"style":79},"language-bash shiki shiki-themes github-light github-dark","# 在 PR 分支\ngit fetch origin main\ngit diff main...HEAD > \u002Ftmp\u002Fpr.diff\ngit log main..HEAD --pretty=format:'%h %s%n%b' > \u002Ftmp\u002Fpr.commits\n","bash","",[50,81,82,91,108,126],{"__ignoreMap":79},[83,84,87],"span",{"class":85,"line":86},"line",1,[83,88,90],{"class":89},"sJ8bj","# 在 PR 分支\n",[83,92,94,98,102,105],{"class":85,"line":93},2,[83,95,97],{"class":96},"sScJk","git",[83,99,101],{"class":100},"sZZnC"," fetch",[83,103,104],{"class":100}," origin",[83,106,107],{"class":100}," main\n",[83,109,111,113,116,119,123],{"class":85,"line":110},3,[83,112,97],{"class":96},[83,114,115],{"class":100}," diff",[83,117,118],{"class":100}," main...HEAD",[83,120,122],{"class":121},"szBVR"," >",[83,124,125],{"class":100}," \u002Ftmp\u002Fpr.diff\n",[83,127,129,131,134,137,141,144,146],{"class":85,"line":128},4,[83,130,97],{"class":96},[83,132,133],{"class":100}," log",[83,135,136],{"class":100}," main..HEAD",[83,138,140],{"class":139},"sj4cs"," --pretty=format:",[83,142,143],{"class":100},"'%h %s%n%b'",[83,145,122],{"class":121},[83,147,148],{"class":100}," \u002Ftmp\u002Fpr.commits\n",[30,150,151],{},"进入项目根，开 Claude Code 或 Cursor。",[69,153,155],{"id":154},"step-2-让-ai-分类改动5-min","Step 2 — 让 AI 分类改动（5 min）",[74,157,162],{"className":158,"code":160,"language":161,"meta":79},[159],"language-text","请分析本分支相对 main 的改动（git diff main...HEAD），按类型归类：\n\nA. 业务逻辑改动（新功能 \u002F bug 修复 \u002F 行为变更）\nB. 重构（不改行为）\nC. 测试改动\nD. 配置 \u002F 依赖\nE. 文档\n\n输出 markdown 表格：类型 | 文件 | 改动摘要（1 句）\n\n特别标出：\n- 是否有\"业务逻辑改动\"但没有对应测试\n- 是否有\"重构\"但行为可能被无意改变\n- 是否有任何 secret \u002F API key 出现在 diff 里\n","text",[50,163,160],{"__ignoreMap":79},[30,165,166,169],{},[33,167,168],{},"这一步的产出物极其有价值","——你瞬间知道这个 PR 的盘子有多大、风险点在哪。",[69,171,173],{"id":172},"step-3-深度审视10-30-min","Step 3 — 深度审视（10-30 min）",[30,175,176],{},"针对 Step 2 标出的高风险项，挨个深问：",[178,179,181],"h4",{"id":180},"_31-业务逻辑深查","3.1 业务逻辑深查",[74,183,186],{"className":184,"code":185,"language":161,"meta":79},[159],"对于改动【文件 X 第 Y-Z 行】，请回答：\n\n1. 改动前的行为是什么？（读 git blame \u002F git show HEAD~1）\n2. 改动后的行为是什么？\n3. 这两个行为的差异是否符合 commit message \u002F PR description 的承诺？\n4. 有没有 edge case 没考虑？（null \u002F 空数组 \u002F 极大值 \u002F 并发）\n5. 有没有可能影响其他调用方？\n\n每条都要给确凿依据，不要\"我觉得\"。\n",[50,187,185],{"__ignoreMap":79},[178,189,191],{"id":190},"_32-一致性扫描","3.2 一致性扫描",[74,193,196],{"className":194,"code":195,"language":161,"meta":79},[159],"请扫描整个项目，看本 PR 的改动有没有\"漏改\"：\n\n- 如果 PR 改了某个函数的签名，所有调用方都改了吗？\n- 如果 PR 加了新的常量，类似的常量定义是否同步更新？\n- 如果 PR 改了某个文件的 pattern，类似文件是否需要同样改？\n\n逐条列出\"可能漏改但 PR 里没改\"的地方，给文件:行号。\n",[50,197,195],{"__ignoreMap":79},[30,199,200,203,204,40],{},[33,201,202],{},"这是 AI 比人类强的地方","——人类做 PR review 容易盯着 diff 看，",[33,205,206],{},"AI 会去看 diff 之外的地方",[178,208,210],{"id":209},"_33-测试-review","3.3 测试 review",[74,212,215],{"className":213,"code":214,"language":161,"meta":79},[159],"对于本 PR 中的测试改动 + 新增测试，请评估：\n\n1. 测试是否真的覆盖了\"业务逻辑改动\"？还是只覆盖了 happy path？\n2. 测试的断言是否够强？（不要只 assert 不抛异常）\n3. 有没有\"修测试让它通过\"的痕迹（注释掉的 assert \u002F 改宽容的 matcher）？\n4. 哪些 edge case 没被测到？\n\n输出：测试覆盖度评估 + 建议补的测试用例（伪代码）\n",[50,216,214],{"__ignoreMap":79},[178,218,220],{"id":219},"_34-风险与回滚","3.4 风险与回滚",[74,222,225],{"className":223,"code":224,"language":161,"meta":79},[159],"假设这个 PR 合并到生产后出了严重问题，回滚成本如何？\n\n- 单纯 revert 这个 commit 能恢复吗？\n- 有没有不可逆的改动（DB 迁移 \u002F 数据格式变更 \u002F 删了字段）？\n- 有没有\"客户端已经发了新版本，服务端不能简单回滚\"的耦合？\n\n如果回滚成本高，建议拆 PR 或加 feature flag。\n",[50,226,224],{"__ignoreMap":79},[69,228,230],{"id":229},"step-4-整合-review-反馈5-min","Step 4 — 整合 review 反馈（5 min）",[74,232,235],{"className":233,"code":234,"language":161,"meta":79},[159],"请整合前面 3.1-3.4 的所有发现，输出一份最终 review 评论，格式：\n\n## ✅ 看起来没问题的部分\n（简短列出）\n\n## ⚠️ 需要 PR author 回应的问题\n（每条带文件:行号 + 具体问题）\n\n## 🛑 阻塞合并的问题\n（如有，必须解决才能合）\n\n## 💡 建议（非阻塞）\n（可选优化）\n\n语气专业、具体，不要客套话。\n",[50,236,234],{"__ignoreMap":79},[30,238,239,242],{},[33,240,241],{},"人工 review 这份 markdown","——70% 的内容你直接 copy 到 PR 评论区。剩下 30% 自己再补充判断和上下文。",[244,245],"hr",{},[13,247,248],{"id":248},"实战时间分配",[250,251,252,268],"table",{},[253,254,255],"thead",{},[256,257,258,262,265],"tr",{},[259,260,261],"th",{},"步骤",[259,263,264],{},"耗时",[259,266,267],{},"谁做",[269,270,271,283,294,305,315],"tbody",{},[256,272,273,277,280],{},[274,275,276],"td",{},"1 准备",[274,278,279],{},"2 min",[274,281,282],{},"人",[256,284,285,288,291],{},[274,286,287],{},"2 分类",[274,289,290],{},"5 min",[274,292,293],{},"AI",[256,295,296,299,302],{},[274,297,298],{},"3 深查",[274,300,301],{},"10-30 min",[274,303,304],{},"AI 主导，人 review",[256,306,307,310,312],{},[274,308,309],{},"4 整合",[274,311,290],{},[274,313,314],{},"AI 输出，人调整",[256,316,317,322,327],{},[274,318,319],{},[33,320,321],{},"合计",[274,323,324],{},[33,325,326],{},"~30 min \u002F PR",[274,328],{},[30,330,331,332,335,336,339],{},"对比纯人工 review 一个中型 PR（~500 行 diff）通常 60-90 min，",[33,333,334],{},"省一半时间","，且",[33,337,338],{},"漏掉问题更少","（AI 看的范围比人广）。",[13,341,342],{"id":342},"工具选择",[17,344,345,351,357,363],{},[20,346,347,350],{},[33,348,349],{},"Claude Code"," ← 首选。能跑命令读 git history，做\"全局一致性扫描\"最强",[20,352,353,356],{},[33,354,355],{},"Cursor + @codebase"," ← 中型项目够用，便宜",[20,358,359,362],{},[33,360,361],{},"Augment"," ← 团队场景，原生集成 PR 流程",[20,364,365,366,369],{},"ChatGPT 网页版 ← ",[33,367,368],{},"不推荐","，上下文不够",[13,371,372],{"id":372},"踩坑",[69,374,376],{"id":375},"_1-不要给-ai-pr-description作为唯一上下文","1. 不要给 AI \"PR description\"作为唯一上下文",[30,378,379,380,383],{},"PR description 是作者自己写的，",[33,381,382],{},"不一定准","。让 AI 自己读 diff，不要被 description 带偏。",[69,385,387],{"id":386},"_2-警惕-ai-的看起来-lgtm","2. 警惕 AI 的\"看起来 LGTM\"",[30,389,390,391,394],{},"AI 倾向于温和。如果它说\"看起来没问题\"，",[33,392,393],{},"强制让它给出 3 条具体担忧","——总能挖出来。",[69,396,398],{"id":397},"_3-别完全替代人脑","3. 别完全替代人脑",[30,400,401,402,405,406,40],{},"AI 的 review 是",[33,403,404],{},"第一道筛","，不是终审。",[33,407,408],{},"关键判断（架构是否合理 \u002F 是否符合产品方向）只能人做",[69,410,412],{"id":411},"_4-注意-token-预算","4. 注意 token 预算",[30,414,415,416,419],{},"大 PR review 容易烧 $1-5。",[33,417,418],{},"对小 PR（\u003C 50 行）直接人脑 review","，不值得开 AI。",[244,421],{},[13,423,425],{"id":424},"bonus把这套做成-git-hook","Bonus：把这套做成 git hook",[30,427,428],{},"把 Step 2-3 写成一个 shell 脚本 + Claude Code prompt 文件，挂在 PR 创建\u002F更新时自动跑：",[74,430,432],{"className":76,"code":431,"language":78,"meta":79,"style":79},"# .github\u002Fhooks\u002Fpr-review.sh （示意）\n#!\u002Fbin\u002Fbash\ngit diff main...HEAD > \u002Ftmp\u002Fpr.diff\nclaude-code --prompt-file=.github\u002Fhooks\u002Freview-prompt.md \\\n            --output-file=\u002Ftmp\u002Freview.md\ngh pr comment $PR_NUMBER --body-file \u002Ftmp\u002Freview.md\n",[50,433,434,439,444,456,467,473],{"__ignoreMap":79},[83,435,436],{"class":85,"line":86},[83,437,438],{"class":89},"# .github\u002Fhooks\u002Fpr-review.sh （示意）\n",[83,440,441],{"class":85,"line":93},[83,442,443],{"class":89},"#!\u002Fbin\u002Fbash\n",[83,445,446,448,450,452,454],{"class":85,"line":110},[83,447,97],{"class":96},[83,449,115],{"class":100},[83,451,118],{"class":100},[83,453,122],{"class":121},[83,455,125],{"class":100},[83,457,458,461,464],{"class":85,"line":128},[83,459,460],{"class":96},"claude-code",[83,462,463],{"class":139}," --prompt-file=.github\u002Fhooks\u002Freview-prompt.md",[83,465,466],{"class":139}," \\\n",[83,468,470],{"class":85,"line":469},5,[83,471,472],{"class":139},"            --output-file=\u002Ftmp\u002Freview.md\n",[83,474,476,479,482,485,489,492],{"class":85,"line":475},6,[83,477,478],{"class":96},"gh",[83,480,481],{"class":100}," pr",[83,483,484],{"class":100}," comment",[83,486,488],{"class":487},"sVt8B"," $PR_NUMBER ",[83,490,491],{"class":139},"--body-file",[83,493,494],{"class":100}," \u002Ftmp\u002Freview.md\n",[30,496,497],{},"完整 GitHub Actions 工作流即将整理上线。",[244,499],{},[30,501,502,503,508,509,40],{},"继续阅读：",[504,505,507],"a",{"href":506},"\u002Fplaybook\u002Fonboarding\u002Flegacy-codebase-onboarding","陌生项目 onboarding 工作流","、",[504,510,512],{"href":511},"\u002Fplaybook\u002Frefactor\u002Flarge-refactor-with-ai-agent","大型重构工作流",[514,515,516],"style",{},"html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}",{"title":79,"searchDepth":110,"depth":110,"links":518},[519,520,521,532,533,534,540],{"id":15,"depth":93,"text":15},{"id":43,"depth":93,"text":43},{"id":66,"depth":93,"text":67,"children":522},[523,524,525,531],{"id":71,"depth":110,"text":72},{"id":154,"depth":110,"text":155},{"id":172,"depth":110,"text":173,"children":526},[527,528,529,530],{"id":180,"depth":128,"text":181},{"id":190,"depth":128,"text":191},{"id":209,"depth":128,"text":210},{"id":219,"depth":128,"text":220},{"id":229,"depth":110,"text":230},{"id":248,"depth":93,"text":248},{"id":342,"depth":93,"text":342},{"id":372,"depth":93,"text":372,"children":535},[536,537,538,539],{"id":375,"depth":110,"text":376},{"id":386,"depth":110,"text":387},{"id":397,"depth":110,"text":398},{"id":411,"depth":110,"text":412},{"id":424,"depth":93,"text":425},"review","\u002Fog\u002Fplaybook\u002Fai-code-review.png","用 Claude Code \u002F Cursor 给 PR 做第一道 review 的标准化工作流：风险扫描、命名一致性、测试覆盖、文档同步。","md",{},true,"\u002Fplaybook\u002Freview\u002Fai-code-review-workflow","2026-06-01",[550,551,552],"coding\u002Fcli\u002Fclaude-code","coding\u002Fide\u002Fcursor","coding\u002Fagent\u002Faugment",{"title":8,"description":543},"playbook\u002Freview\u002Fai-code-review-workflow",[556,557,349,558],"code review","PR","工作流","2026-06-15","t09WfO0oBlGLWe6k_9Q9vCP5UiVK2HxMSQqK1Ipa43Q",{"tools":4,"reviews":5,"playbooks":562,"news":563},10,8,1782316489337]