[{"data":1,"prerenderedAt":13001},["ShallowReactive",2],{"header-counts":3,"playbook-onboarding\u002Fasync-coding-agent-workflow":6,"footer-counts":734,"playbook-tools-onboarding\u002Fasync-coding-agent-workflow":735,"pb-all":3699},{"tools":4,"reviews":5},67,7,{"id":7,"title":8,"body":9,"category":717,"cover":718,"description":719,"extension":104,"meta":720,"navigation":130,"path":721,"published":722,"relatedTools":723,"seo":728,"stem":729,"tags":730,"updated":722,"__hash__":733},"playbook\u002Fplaybook\u002Fonboarding\u002Fasync-coding-agent-workflow.md","异步 Coding Agent 工作流：把 issue 交给 Jules \u002F Devin \u002F Copilot Coding Agent",{"type":10,"value":11,"toc":703},"minimark",[12,16,20,36,44,47,50,70,73,90,93,96,99,271,274,277,285,292,296,404,407,411,414,432,435,439,505,509,512,538,541,544,547,596,600,603,649,652,655,693,696,699],[13,14,15],"h2",{"id":15},"适用场景",[17,18,19],"p",{},"异步 Coding Agent 指的是这类工具：你把 GitHub issue \u002F repo \u002F prompt 交给它，它在云端或隔离环境中完成任务，最后返回 diff 或 PR。典型代表：",[21,22,23,27,30,33],"ul",{},[24,25,26],"li",{},"Google Jules",[24,28,29],{},"Devin",[24,31,32],{},"GitHub Copilot Coding Agent",[24,34,35],{},"OpenHands Cloud \u002F 自托管",[17,37,38,39,43],{},"它们和 Claude Code \u002F Codex CLI \u002F Cursor 最大区别：",[40,41,42],"strong",{},"不是实时结对，而是任务委派","。",[13,45,46],{"id":46},"先判断任务适不适合异步委派",[17,48,49],{},"适合：",[21,51,52,55,58,61,64,67],{},[24,53,54],{},"补测试",[24,56,57],{},"依赖升级",[24,59,60],{},"小 bug fix",[24,62,63],{},"文档更新",[24,65,66],{},"codemod \u002F 机械迁移",[24,68,69],{},"有明确复现步骤和验收标准的 issue",[17,71,72],{},"不适合：",[21,74,75,78,81,84,87],{},[24,76,77],{},"产品方向不明确的新功能",[24,79,80],{},"需要大量口头沟通的需求",[24,82,83],{},"涉及生产凭据 \u002F 内网数据库 \u002F 隐私数据",[24,85,86],{},"紧急线上事故",[24,88,89],{},"大规模架构重构的第一步",[17,91,92],{},"**判断标准：**如果你不能在 10 行内写清楚「做什么、不能做什么、如何验收」，就先别交给异步 Agent。",[13,94,95],{"id":95},"任务模板",[17,97,98],{},"把 issue 写成下面这种结构，成功率会明显高：",[100,101,106],"pre",{"className":102,"code":103,"language":104,"meta":105,"style":105},"language-md shiki shiki-themes github-light github-dark","## Goal\nFix duplicate toast after saving settings.\n\n## Scope\n- Only edit settings page and related toast utility.\n- Do not change the global notification API.\n\n## Reproduction\n1. Open \u002Fsettings\n2. Change display name\n3. Click Save once\n4. Two success toasts appear\n\n## Expected\nOnly one success toast appears.\n\n## Verification\n- pnpm test settings\n- pnpm run typecheck\n- Manual: save settings once and confirm one toast\n\n## Notes\nPrefer removing duplicate caller over adding debounce.\n","md","",[107,108,109,118,125,132,138,148,156,160,166,175,184,193,202,207,213,219,224,230,238,246,254,259,265],"code",{"__ignoreMap":105},[110,111,114],"span",{"class":112,"line":113},"line",1,[110,115,117],{"class":116},"sq-ep","## Goal\n",[110,119,121],{"class":112,"line":120},2,[110,122,124],{"class":123},"sVt8B","Fix duplicate toast after saving settings.\n",[110,126,128],{"class":112,"line":127},3,[110,129,131],{"emptyLinePlaceholder":130},true,"\n",[110,133,135],{"class":112,"line":134},4,[110,136,137],{"class":116},"## Scope\n",[110,139,141,145],{"class":112,"line":140},5,[110,142,144],{"class":143},"s4XuR","-",[110,146,147],{"class":123}," Only edit settings page and related toast utility.\n",[110,149,151,153],{"class":112,"line":150},6,[110,152,144],{"class":143},[110,154,155],{"class":123}," Do not change the global notification API.\n",[110,157,158],{"class":112,"line":5},[110,159,131],{"emptyLinePlaceholder":130},[110,161,163],{"class":112,"line":162},8,[110,164,165],{"class":116},"## Reproduction\n",[110,167,169,172],{"class":112,"line":168},9,[110,170,171],{"class":143},"1.",[110,173,174],{"class":123}," Open \u002Fsettings\n",[110,176,178,181],{"class":112,"line":177},10,[110,179,180],{"class":143},"2.",[110,182,183],{"class":123}," Change display name\n",[110,185,187,190],{"class":112,"line":186},11,[110,188,189],{"class":143},"3.",[110,191,192],{"class":123}," Click Save once\n",[110,194,196,199],{"class":112,"line":195},12,[110,197,198],{"class":143},"4.",[110,200,201],{"class":123}," Two success toasts appear\n",[110,203,205],{"class":112,"line":204},13,[110,206,131],{"emptyLinePlaceholder":130},[110,208,210],{"class":112,"line":209},14,[110,211,212],{"class":116},"## Expected\n",[110,214,216],{"class":112,"line":215},15,[110,217,218],{"class":123},"Only one success toast appears.\n",[110,220,222],{"class":112,"line":221},16,[110,223,131],{"emptyLinePlaceholder":130},[110,225,227],{"class":112,"line":226},17,[110,228,229],{"class":116},"## Verification\n",[110,231,233,235],{"class":112,"line":232},18,[110,234,144],{"class":143},[110,236,237],{"class":123}," pnpm test settings\n",[110,239,241,243],{"class":112,"line":240},19,[110,242,144],{"class":143},[110,244,245],{"class":123}," pnpm run typecheck\n",[110,247,249,251],{"class":112,"line":248},20,[110,250,144],{"class":143},[110,252,253],{"class":123}," Manual: save settings once and confirm one toast\n",[110,255,257],{"class":112,"line":256},21,[110,258,131],{"emptyLinePlaceholder":130},[110,260,262],{"class":112,"line":261},22,[110,263,264],{"class":116},"## Notes\n",[110,266,268],{"class":112,"line":267},23,[110,269,270],{"class":123},"Prefer removing duplicate caller over adding debounce.\n",[17,272,273],{},"异步 Agent 最怕「帮我优化一下」。它需要像 junior developer 一样拿到清楚的 ticket。",[13,275,276],{"id":276},"推荐流程",[100,278,283],{"className":279,"code":281,"language":282,"meta":105},[280],"language-text","Backlog issue\n  ↓\n人工筛选：是否边界清楚 \u002F 风险低\n  ↓\nAgent 生成 plan\n  ↓\n人工确认 plan\n  ↓\nAgent 在云端 \u002F VM 改代码 + 跑测试\n  ↓\n生成 PR\n  ↓\nAI Review + 人工 Review\n  ↓\nCI 通过后 merge\n","text",[107,284,281],{"__ignoreMap":105},[17,286,287,288,291],{},"关键点：",[40,289,290],{},"不要跳过 plan review 和 PR review","。异步 Agent 是执行者，不是合并权限的拥有者。",[13,293,295],{"id":294},"jules-工作流示例","Jules 工作流示例",[100,297,301],{"className":298,"code":299,"language":300,"meta":105,"style":105},"language-bash shiki shiki-themes github-light github-dark","npm install -g @google\u002Fjules\njules login\n\n# 当前目录对应 GitHub repo 时可用 .\njules remote new --repo . --session \"Fix duplicate toast after saving settings. Run pnpm test settings and pnpm run typecheck.\"\n\n# 查看任务\njules remote list --session\n\n# 拉取完成结果\njules remote pull --session 123456\n","bash",[107,302,303,320,328,332,338,360,364,369,381,385,390],{"__ignoreMap":105},[110,304,305,309,313,317],{"class":112,"line":113},[110,306,308],{"class":307},"sScJk","npm",[110,310,312],{"class":311},"sZZnC"," install",[110,314,316],{"class":315},"sj4cs"," -g",[110,318,319],{"class":311}," @google\u002Fjules\n",[110,321,322,325],{"class":112,"line":120},[110,323,324],{"class":307},"jules",[110,326,327],{"class":311}," login\n",[110,329,330],{"class":112,"line":127},[110,331,131],{"emptyLinePlaceholder":130},[110,333,334],{"class":112,"line":134},[110,335,337],{"class":336},"sJ8bj","# 当前目录对应 GitHub repo 时可用 .\n",[110,339,340,342,345,348,351,354,357],{"class":112,"line":140},[110,341,324],{"class":307},[110,343,344],{"class":311}," remote",[110,346,347],{"class":311}," new",[110,349,350],{"class":315}," --repo",[110,352,353],{"class":311}," .",[110,355,356],{"class":315}," --session",[110,358,359],{"class":311}," \"Fix duplicate toast after saving settings. Run pnpm test settings and pnpm run typecheck.\"\n",[110,361,362],{"class":112,"line":150},[110,363,131],{"emptyLinePlaceholder":130},[110,365,366],{"class":112,"line":5},[110,367,368],{"class":336},"# 查看任务\n",[110,370,371,373,375,378],{"class":112,"line":162},[110,372,324],{"class":307},[110,374,344],{"class":311},[110,376,377],{"class":311}," list",[110,379,380],{"class":315}," --session\n",[110,382,383],{"class":112,"line":168},[110,384,131],{"emptyLinePlaceholder":130},[110,386,387],{"class":112,"line":177},[110,388,389],{"class":336},"# 拉取完成结果\n",[110,391,392,394,396,399,401],{"class":112,"line":186},[110,393,324],{"class":307},[110,395,344],{"class":311},[110,397,398],{"class":311}," pull",[110,400,356],{"class":315},[110,402,403],{"class":315}," 123456\n",[17,405,406],{},"Jules 会在 Google Cloud VM 中 clone repo、制定计划、修改代码、跑测试并返回 diff。适合一次派发多个低风险任务。",[13,408,410],{"id":409},"copilot-coding-agent-工作流示例","Copilot Coding Agent 工作流示例",[17,412,413],{},"适合已经用 GitHub Issues 管理任务的团队：",[415,416,417,420,423,426,429],"ol",{},[24,418,419],{},"在 issue 中写好 Goal \u002F Scope \u002F Verification。",[24,421,422],{},"将 issue assign 给 Copilot 或在 GitHub UI 中触发 Coding Agent。",[24,424,425],{},"Copilot 在 GitHub Actions 环境中工作。",[24,427,428],{},"完成后开 PR。",[24,430,431],{},"团队按普通 PR 流程 review。",[17,433,434],{},"Copilot 的优势是和 GitHub 权限、Actions、PR review 链路集成最深；缺点是 Actions minutes、仓库权限和企业策略要提前配置。",[13,436,438],{"id":437},"devin-openhands-工作流","Devin \u002F OpenHands 工作流",[440,441,442,458],"table",{},[443,444,445],"thead",{},[446,447,448,452,455],"tr",{},[449,450,451],"th",{},"工具",[449,453,454],{},"适合",[449,456,457],{},"注意",[459,460,461,472,483,494],"tbody",{},[446,462,463,466,469],{},[464,465,29],"td",{},[464,467,468],{},"企业团队、复杂云端执行",[464,470,471],{},"成本较高，仍需严格 review",[446,473,474,477,480],{},[464,475,476],{},"OpenHands",[464,478,479],{},"想自托管、代码不能出境",[464,481,482],{},"需要自己维护运行环境和模型接入",[446,484,485,488,491],{},[464,486,487],{},"Jules",[464,489,490],{},"Google\u002FGemini 用户、低成本试水",[464,492,493],{},"代码进入 Google Cloud VM，中文友好一般",[446,495,496,499,502],{},[464,497,498],{},"Copilot Coding Agent",[464,500,501],{},"GitHub-first 团队",[464,503,504],{},"依赖 Actions 与 GitHub 权限体系",[13,506,508],{"id":507},"review-agent-pr-的检查清单","Review Agent PR 的检查清单",[17,510,511],{},"收到异步 Agent PR 后，不要只看「测试通过」。至少检查：",[21,513,514,517,520,523,526,529,532,535],{},[24,515,516],{},"是否改了 scope 外的文件？",[24,518,519],{},"是否删掉了测试而不是修复测试？",[24,521,522],{},"是否引入了新的依赖？依赖是否必要？",[24,524,525],{},"是否硬编码 token \u002F URL \u002F 环境变量？",[24,527,528],{},"是否只修了表面现象，没有覆盖根因？",[24,530,531],{},"是否有回归测试？",[24,533,534],{},"CI 日志是否真的跑了目标命令？",[24,536,537],{},"PR 描述是否解释了 trade-off？",[17,539,540],{},"推荐再加一层 AI review：CodeRabbit \u002F Copilot review \u002F Claude Code 读 diff。一个 Agent 写，另一个 Agent 审，能抓到不少低级问题。",[13,542,543],{"id":543},"权限与安全",[17,545,546],{},"异步 Agent 通常需要访问 repo、issue、CI、包管理器甚至部署环境。建议：",[415,548,549,555,561,567,573,579],{},[24,550,551,554],{},[40,552,553],{},"单独 service account","：不要用个人 GitHub token。",[24,556,557,560],{},[40,558,559],{},"最小权限","：只给目标 repo，不给 org admin。",[24,562,563,566],{},[40,564,565],{},"禁止生产 secret","：Agent 环境不注入生产数据库、支付、云厂商 root key。",[24,568,569,572],{},[40,570,571],{},"分支保护","：Agent PR 必须走 CI + 人工 review。",[24,574,575,578],{},[40,576,577],{},"日志留存","：保留 Agent plan、命令输出、测试结果。",[24,580,581,584,585,588,589,588,592,595],{},[40,582,583],{},"敏感目录排除","：如 ",[107,586,587],{},"infra\u002Fprod","、",[107,590,591],{},"secrets",[107,593,594],{},"billing"," 需要更高门槛。",[13,597,599],{"id":598},"指标怎么判断值不值","指标：怎么判断值不值",[17,601,602],{},"看四个数：",[440,604,605,615],{},[443,606,607],{},[446,608,609,612],{},[449,610,611],{},"指标",[449,613,614],{},"目标",[459,616,617,625,633,641],{},[446,618,619,622],{},[464,620,621],{},"PR 接受率",[464,623,624],{},"> 50% 才值得扩大使用",[446,626,627,630],{},[464,628,629],{},"平均人工 review 时间",[464,631,632],{},"应该下降，而不是变成「帮 Agent 擦屁股」",[446,634,635,638],{},[464,636,637],{},"回滚率",[464,639,640],{},"不应高于人工 PR",[446,642,643,646],{},[464,644,645],{},"单任务成本",[464,647,648],{},"包括订阅费、CI minutes、review 人力",[17,650,651],{},"开始阶段建议只拿 10-20 个低风险 issue 做试点，不要一口气把 backlog 全派出去。",[13,653,654],{"id":654},"常见失败模式",[415,656,657,663,669,675,681,687],{},[24,658,659,662],{},[40,660,661],{},"任务太大","：Agent 生成 2,000 行 PR，没人敢 merge。",[24,664,665,668],{},[40,666,667],{},"没有测试","：Agent 无法判断是否完成，只能猜。",[24,670,671,674],{},[40,672,673],{},"权限太小","：跑不了依赖安装 \u002F 测试，反复失败。",[24,676,677,680],{},[40,678,679],{},"权限太大","：能改不该改的文件，安全风险上升。",[24,682,683,686],{},[40,684,685],{},"review 不及时","：Agent PR 堆积，merge 冲突越来越多。",[24,688,689,692],{},[40,690,691],{},"把 Agent 当 owner","：没有人类 owner，需求判断和质量兜底会失控。",[13,694,695],{"id":695},"一句话总结",[17,697,698],{},"异步 Coding Agent 最适合做「边界清晰、能自动验证、风险可控」的工程杂活。正确姿势不是让它替代开发者，而是把它纳入现有 issue → PR → CI → review 流程，让人类只处理真正需要判断的部分。",[700,701,702],"style",{},"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 .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}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 .sq-ep, html code.shiki .sq-ep{--shiki-default:#005CC5;--shiki-default-font-weight:bold;--shiki-dark:#79B8FF;--shiki-dark-font-weight:bold}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}",{"title":105,"searchDepth":127,"depth":127,"links":704},[705,706,707,708,709,710,711,712,713,714,715,716],{"id":15,"depth":120,"text":15},{"id":46,"depth":120,"text":46},{"id":95,"depth":120,"text":95},{"id":276,"depth":120,"text":276},{"id":294,"depth":120,"text":295},{"id":409,"depth":120,"text":410},{"id":437,"depth":120,"text":438},{"id":507,"depth":120,"text":508},{"id":543,"depth":120,"text":543},{"id":598,"depth":120,"text":599},{"id":654,"depth":120,"text":654},{"id":695,"depth":120,"text":695},"onboarding","\u002Fog\u002Fplaybook\u002Fasync-coding-agent-workflow.png","面向 Google Jules、Devin、GitHub Copilot Coding Agent 等异步 AI 编程工具的落地指南：如何拆任务、写验收标准、控制权限、review Agent 生成的 PR。",{},"\u002Fplaybook\u002Fonboarding\u002Fasync-coding-agent-workflow","2026-06-25",[724,725,726,727],"coding\u002Fagent\u002Fjules","coding\u002Fagent\u002Fdevin","coding\u002Fcopilot\u002Fgithub-copilot","coding\u002Fagent\u002Fopenhands",{"title":8,"description":719},"playbook\u002Fonboarding\u002Fasync-coding-agent-workflow",[731,487,29,498,732],"Async Agent","GitHub","L3d_nP-4U5NMhHFqR_SMb1JnpsXSS-QvEpot54K_lkc",{"tools":4,"reviews":5,"playbooks":195,"news":177},[736,1310,2061,2571],{"id":737,"title":29,"alternatives":738,"api_compatible":748,"body":749,"category":1243,"chinese_friendly":120,"cover":1244,"description":1245,"domestic":1246,"extension":104,"faq":1247,"free":1246,"github":748,"languages":1260,"meta":1262,"models":748,"navigation":130,"notSuitable":748,"opensource":1246,"path":1263,"pillar":1264,"platforms":1265,"priceTable":1268,"pricing":1280,"published":1281,"relatedPlaybooks":1282,"relatedReviews":748,"score":1289,"self_host":1246,"seo":1290,"slug":725,"sources":1291,"stem":1301,"suitable":748,"tagline":1302,"tags":1303,"updated":1294,"verdict":1307,"website":1308,"__hash__":1309},"tools\u002Ftools\u002Fcoding\u002Fagent\u002Fdevin.md",[739,742,745],{"name":740,"url":741},"openhands","\u002Ftools\u002Fcoding\u002Fagent\u002Fopenhands",{"name":743,"url":744},"manus","\u002Ftools\u002Fagent\u002Fgeneral\u002Fmanus",{"name":746,"url":747},"claude-code","\u002Ftools\u002Fcoding\u002Fcli\u002Fclaude-code",null,{"type":10,"value":750,"toc":1231},[751,755,758,761,764,767,791,794,798,803,877,882,942,945,948,954,968,973,990,993,1010,1013,1117,1120,1152,1156,1173,1176,1197,1200],[13,752,754],{"id":753},"tldr","TL;DR",[17,756,757],{},"Devin 是 Cognition Labs 推出的「自主 AI 软件工程师」。2024-03 首发时 $500\u002F月 + 引爆全网，2025-04 Devin 2.0 把入门价砍到 $20\u002F月（按 ACU 计费），2026 年又通过收购 Windsurf 扩张到桌面端。它的核心定位不是 copilot，而是「异步 agent」——把任务扔进去，它在云沙箱里独立 plan → code → test → PR，你第二天来看结果。",[17,759,760],{},"适合：有明确边界的工程任务（重构、bug fix、新 feature），不需要全程盯着的团队。不适合：交互式探索、紧急 hotfix、中文项目、超预算敏感的个人。",[13,762,763],{"id":763},"它是什么",[17,765,766],{},"Devin 不在你电脑上跑——它有自己的云端 IDE + shell + 浏览器，等于一台 7×24 在线的远程开发机。给它一个 issue（GitHub \u002F Linear \u002F Slack 都行），它会：",[415,768,769,776,782,785,788],{},[24,770,771,772,775],{},"进 sandbox、",[107,773,774],{},"git clone"," 仓库、看 README、构建 Devin Wiki",[24,777,778,781],{},[40,779,780],{},"Interactive Planning","：跟你确认实现方案",[24,783,784],{},"写代码、跑测试、调浏览器看结果",[24,786,787],{},"失败自己排查、改、再试（带 citations 引用代码行）",[24,789,790],{},"提 PR、回 Slack「搞定」",[17,792,793],{},"主打 Cloud + Async + 多并发：Core 最多 10 个 Devin 同时跑不同任务，Team 起无限并发。",[13,795,797],{"id":796},"价格2026-06-综合官方-第三方追踪","价格（2026-06 综合官方 + 第三方追踪）",[17,799,800],{},[40,801,802],{},"Cloud Devin（按 ACU 计费）",[440,804,805,824],{},[443,806,807],{},[446,808,809,812,815,818,821],{},[449,810,811],{},"Plan",[449,813,814],{},"月费",[449,816,817],{},"ACU 价",[449,819,820],{},"并发",[449,822,823],{},"关键能力",[459,825,826,845,862],{},[446,827,828,833,836,839,842],{},[464,829,830],{},[40,831,832],{},"Core",[464,834,835],{},"$20 起步（PAYG）",[464,837,838],{},"$2.25\u002FACU",[464,840,841],{},"10",[464,843,844],{},"Devin IDE、Ask Devin、Wiki",[446,846,847,850,853,856,859],{},[464,848,849],{},"Team",[464,851,852],{},"$500 含 250 ACU",[464,854,855],{},"$2\u002FACU（含内）",[464,857,858],{},"∞",[464,860,861],{},"API、专属 Slack 频道、early access",[446,863,864,867,870,872,874],{},[464,865,866],{},"Enterprise",[464,868,869],{},"Custom",[464,871,869],{},[464,873,858],{},[464,875,876],{},"VPC、SSO、Custom Devins",[17,878,879],{},[40,880,881],{},"Devin Desktop（2026-06 Windsurf 改名后）",[440,883,884,896],{},[443,885,886],{},[446,887,888,890,893],{},[449,889,811],{},[449,891,892],{},"价格",[449,894,895],{},"适用",[459,897,898,909,920,931],{},[446,899,900,903,906],{},[464,901,902],{},"Free",[464,904,905],{},"$0",[464,907,908],{},"轻量配额",[446,910,911,914,917],{},[464,912,913],{},"Pro",[464,915,916],{},"$20\u002F月",[464,918,919],{},"个人开发者",[446,921,922,925,928],{},[464,923,924],{},"Max",[464,926,927],{},"$200\u002F月",[464,929,930],{},"重度用户",[446,932,933,936,939],{},[464,934,935],{},"Teams",[464,937,938],{},"$80\u002F月 + $40\u002F席",[464,940,941],{},"团队",[17,943,944],{},"ACU 经济账：1 ACU = 15 分钟 Devin 主动工作。一个中等任务（小 feature\u002F简单 bug）约消耗 0.5–1.5 ACU ≈ $1.13–$3.38。一个复杂 task（跨文件重构 + 测试）2–4 ACU ≈ $5–$10。",[13,946,947],{"id":947},"实测",[17,949,950,953],{},[40,951,952],{},"好的地方","：",[21,955,956,959,962,965],{},[24,957,958],{},"单次任务交付质量稳定——比早期 demo 时代靠谱多了",[24,960,961],{},"Devin Wiki 自动生成的代码库地图很有用",[24,963,964],{},"多并发：开 5 个 Devin 同时干 5 个独立 bug，效率拉满",[24,966,967],{},"Interactive Planning 让你能纠偏，不会写到一半发现方向错",[17,969,970,953],{},[40,971,972],{},"踩坑",[21,974,975,978,981,984,987],{},[24,976,977],{},"ACU 烧得快——一次 Devin 跑歪 + 自我修复循环可能 2-3 ACU 没了",[24,979,980],{},"中文几乎不能用——Cognition 没做本地化，prompt 中文也回英文",[24,982,983],{},"国内开发者用：网络 + 价格 + 中文三重劝退，建议看 OpenHands \u002F Manus",[24,985,986],{},"复杂上下文（10w 行老代码）依然容易迷失，需要人辅助拆任务",[24,988,989],{},"Free trial 没有，最低要先付 $20 才能试",[13,991,992],{"id":992},"上手",[415,994,995,998,1001,1004,1007],{},[24,996,997],{},"devin.ai 注册（GitHub OAuth），充值 $20 拿到 9 ACU",[24,999,1000],{},"连接 GitHub repo + 选触发方式（Linear\u002FSlack\u002FWeb）",[24,1002,1003],{},"给一个 issue + 验收标准（越具体越省 ACU）",[24,1005,1006],{},"Interactive Planning：审一遍方案",[24,1008,1009],{},"Devin 自动跑、PR 自动开、等 review",[13,1011,1012],{"id":1012},"对比一览",[440,1014,1015,1032],{},[443,1016,1017],{},[446,1018,1019,1022,1024,1026,1029],{},[449,1020,1021],{},"维度",[449,1023,29],{},[449,1025,476],{},[449,1027,1028],{},"Manus",[449,1030,1031],{},"Claude Code",[459,1033,1034,1051,1068,1084,1101],{},[446,1035,1036,1039,1042,1045,1048],{},[464,1037,1038],{},"模式",[464,1040,1041],{},"异步 Cloud Agent",[464,1043,1044],{},"自托管 \u002F Cloud",[464,1046,1047],{},"异步 Cloud",[464,1049,1050],{},"同步 CLI",[446,1052,1053,1056,1059,1062,1065],{},[464,1054,1055],{},"起步价",[464,1057,1058],{},"$20 + ACU",[464,1060,1061],{},"免费（开源）",[464,1063,1064],{},"$39\u002F月",[464,1066,1067],{},"Pro $20\u002F月",[446,1069,1070,1072,1075,1078,1081],{},[464,1071,820],{},[464,1073,1074],{},"10–∞",[464,1076,1077],{},"自托管无限",[464,1079,1080],{},"5+",[464,1082,1083],{},"1",[446,1085,1086,1089,1092,1095,1098],{},[464,1087,1088],{},"中文",[464,1090,1091],{},"弱",[464,1093,1094],{},"强（社区维护）",[464,1096,1097],{},"强（国产）",[464,1099,1100],{},"中",[446,1102,1103,1106,1109,1112,1114],{},[464,1104,1105],{},"沙箱",[464,1107,1108],{},"内置云端",[464,1110,1111],{},"Docker \u002F Cloud",[464,1113,1108],{},[464,1115,1116],{},"本地",[13,1118,1119],{"id":1119},"避坑",[21,1121,1122,1128,1134,1140,1146],{},[24,1123,1124,1127],{},[40,1125,1126],{},"不要不写验收标准就丢任务","：Devin 会尽职跑，但跑到哪里算「完成」很主观，写明「跑通这个测试」「PR 必须含 changelog」",[24,1129,1130,1133],{},[40,1131,1132],{},"新项目 \u002F 老项目都要先 Wiki","：让它先生成 Devin Wiki，后续任务上下文准很多",[24,1135,1136,1139],{},[40,1137,1138],{},"ACU 监控要开","：仪表盘里设单任务 ACU 上限，避免 runaway",[24,1141,1142,1145],{},[40,1143,1144],{},"PR 必须 review","：Devin 偶尔会引入安全问题（hardcode key、删测试）",[24,1147,1148,1151],{},[40,1149,1150],{},"国内团队三思","：网络、定价、语言成本叠加后，单位产出 ROI 不一定胜过 Cursor + Claude",[13,1153,1155],{"id":1154},"适合-不适合","适合 \u002F 不适合",[21,1157,1158,1161,1164,1167,1170],{},[24,1159,1160],{},"✅ 海外团队、英文项目、批量化的中小 task",[24,1162,1163],{},"✅ 想做「夜跑 agent」流水线的工程团队",[24,1165,1166],{},"❌ 中文项目、国内个人开发者",[24,1168,1169],{},"❌ 预算敏感（同样钱可以买 4 个 Cursor 席位）",[24,1171,1172],{},"❌ 需要实时协作 \u002F 紧急 hotfix",[13,1174,1175],{"id":1175},"相关阅读",[21,1177,1178,1185,1191],{},[24,1179,1180,1184],{},[1181,1182,1183],"a",{"href":741},"OpenHands 评测","（Devin 的开源平替）",[24,1186,1187,1190],{},[1181,1188,1189],{"href":744},"Manus 评测","（国产 cloud agent）",[24,1192,1193,1196],{},[1181,1194,1195],{"href":747},"Claude Code 评测","（同步替代方案）",[13,1198,1199],{"id":1199},"来源",[415,1201,1202,1210,1217,1224],{},[24,1203,1204,1205],{},"SiliconAngle — Devin 2.0 with lower starting price（2025-04-03）",[1181,1206,1207],{"href":1207,"rel":1208},"https:\u002F\u002Fsiliconangle.com\u002F2025\u002F04\u002F03\u002Fcognition-ai-launches-revamped-coding-assistant-devin-2-0-much-lower-starting-price",[1209],"nofollow",[24,1211,1212,1213],{},"CostBench — Devin AI Pricing 2026（2026-05-04）",[1181,1214,1215],{"href":1215,"rel":1216},"https:\u002F\u002Fcostbench.com\u002Fsoftware\u002Fai-coding-assistants\u002Fdevin-ai\u002F",[1209],[24,1218,1219,1220],{},"eesel — Cognition AI Pricing Explained ",[1181,1221,1222],{"href":1222,"rel":1223},"https:\u002F\u002Fwww.eesel.ai\u002Fblog\u002Fcognition-ai-pricing",[1209],[24,1225,1226,1227],{},"Vibe Coding — Devin Review 2026 \u002F Windsurf rebrand ",[1181,1228,1229],{"href":1229,"rel":1230},"https:\u002F\u002Fvibecoding.app\u002Fblog\u002Fdevin-review",[1209],{"title":105,"searchDepth":127,"depth":127,"links":1232},[1233,1234,1235,1236,1237,1238,1239,1240,1241,1242],{"id":753,"depth":120,"text":754},{"id":763,"depth":120,"text":763},{"id":796,"depth":120,"text":797},{"id":947,"depth":120,"text":947},{"id":992,"depth":120,"text":992},{"id":1012,"depth":120,"text":1012},{"id":1119,"depth":120,"text":1119},{"id":1154,"depth":120,"text":1155},{"id":1175,"depth":120,"text":1175},{"id":1199,"depth":120,"text":1199},"agent","\u002Fimg\u002Ftools\u002Fdevin.webp","Devin 真实评测：Cognition Labs 的自主编程 Agent。Core $20\u002F月 + $2.25\u002FACU（1 ACU ≈ 15 分钟），Team $500\u002F月含 250 ACUs。2026 收购 Windsurf 后产品线扩张到 Desktop Free\u002FPro\u002FMax。",false,[1248,1251,1254,1257],{"q":1249,"a":1250},"1 ACU 等于多少？","1 ACU ≈ Devin 主动工作 15 分钟。Core 单价 $2.25\u002FACU，Team 单价 $2\u002FACU。换算下来 Devin 主动小时成本约 $8–$9，确实接近 Upwork 入门级海外开发者，但能 7×24 工作。",{"q":1252,"a":1253},"Devin 和 Cursor \u002F Claude Code 区别？","Cursor \u002F Claude Code 是『陪你写』的 copilot，Devin 是『代你写』的 async agent——你给任务、它在云沙箱里独立完成、返回 PR。前者实时同步，后者异步交付。",{"q":1255,"a":1256},"2026 年 Devin \u002F Windsurf 关系？","Cognition 收购了 Windsurf 资产（前 Codeium），2026-06 后 Devin Desktop 取代 Windsurf IDE，新增 Free \u002F Pro $20\u002FMax $200 桌面端订阅，Cloud 版（Core\u002FTeam\u002FEnterprise）保留 ACU 计费。",{"q":1258,"a":1259},"Devin 能跑国内项目吗？","技术上可以——它在云沙箱跑 Linux 命令、git、浏览器。但默认走美国节点，访问国内 git\u002Fnpm 镜像慢，且不支持中文 prompt（会回英文）。国内团队建议看 OpenHands 自托管或 Manus。",[1261],"en",{},"\u002Ftools\u002Fcoding\u002Fagent\u002Fdevin","coding",[1266,1267],"cloud","desktop",[1269,1273,1277],{"plan":1270,"price":1271,"seats":1083,"notes":1272},"Core (PAYG)","$20\u002F月起","Pay-as-you-go，$2.25\u002FACU，最多 10 并发会话",{"plan":849,"price":1274,"seats":1275,"notes":1276},"$500\u002F月","≥1","含 250 ACUs（$2\u002FACU 实际单价）、无限并发、Slack 专属频道",{"plan":866,"price":869,"seats":1278,"notes":1279},"—","VPC 部署、SAML\u002FOIDC SSO、Custom Devins","Core $20·月 起按 ACU \u002F Team $500·月含 250 ACU \u002F Enterprise 定制","2026-06-19",[1283,1286],{"name":1284,"url":1285},"AI PR Review Pipeline","\u002Fplaybook\u002Freview\u002Fai-pr-review-pipeline",{"name":1287,"url":1288},"AI Agent 概念入门 Wiki","\u002Fwiki\u002Fai-agent",{"power":140,"ux":134,"price":120,"cn_support":120,"stability":134},{"title":29,"description":1245},[1292,1295,1297,1299],{"name":1293,"url":1207,"accessed":1294},"SiliconAngle — Devin 2.0 launch","2026-06-24",{"name":1296,"url":1215,"accessed":1294},"CostBench — Devin AI Pricing 2026",{"name":1298,"url":1222,"accessed":1294},"eesel — Cognition AI Pricing",{"name":1300,"url":1229,"accessed":1294},"Vibe Coding — Devin Review 2026 (Windsurf rebrand)","tools\u002Fcoding\u002Fagent\u002Fdevin","Cognition 出品的自主 AI 软件工程师，ACU 计费，2026 已并入 Windsurf 阵营",[1243,1304,1266,1305,1306],"autonomous","ACU","async","AI 自主编程的开山旗手，2026 价格从 $500 起跳降到 $20 起步。ACU 计费让成本可预算化，但单 ACU $2.25 仍是同类最贵，适合『把任务扔进去、明天看 PR』的异步开发模式。","https:\u002F\u002Fdevin.ai","68AhwdBz_aUeyATlc897dupjP5HNLfAacT6xRyKuEOE",{"id":1311,"title":487,"alternatives":1312,"api_compatible":748,"body":1315,"category":1243,"chinese_friendly":120,"cover":1999,"description":2000,"domestic":1246,"extension":104,"faq":2001,"free":1246,"github":748,"languages":2014,"meta":2015,"models":748,"navigation":130,"notSuitable":2016,"opensource":1246,"path":2020,"pillar":1264,"platforms":2021,"priceTable":2023,"pricing":2034,"published":722,"relatedPlaybooks":2035,"relatedReviews":748,"score":2038,"self_host":1246,"seo":2039,"slug":724,"sources":2040,"stem":2047,"suitable":2048,"tagline":2053,"tags":2054,"updated":722,"verdict":2059,"website":1958,"__hash__":2060},"tools\u002Ftools\u002Fcoding\u002Fagent\u002Fjules.md",[725,727,1313,1314],"coding\u002Fcli\u002Fclaude-code","coding\u002Fcli\u002Fgemini-cli",{"type":10,"value":1316,"toc":1983},[1317,1319,1335,1337,1344,1364,1367,1387,1390,1438,1441,1445,1448,1554,1557,1703,1707,1814,1819,1830,1833,1838,1844,1847,1851,1857,1860,1864,1870,1873,1876,1892,1895,1898,1936,1940,1946,1949,1951,1974,1980],[13,1318,754],{"id":753},[1320,1321,1326,1332],"div",{"className":1322},[1323,1324,1325],"card","p-5","my-4",[17,1327,1328,1331],{},[40,1329,1330],{},"一句话："," Jules 是 Google 的异步 Coding Agent：你把 GitHub repo + 任务描述交给它，它在 Google Cloud VM 里 clone 代码、制定计划、改文件、跑测试，最后给你 diff \u002F PR。",[17,1333,1334],{},"它不是 Cursor \u002F Claude Code 那种实时结对工具，而是「把不想做的工程任务派出去」的云端队友。",[13,1336,763],{"id":763},[17,1338,1339,1340,1343],{},"Jules 的定位很清晰：",[40,1341,1342],{},"async coding agent","。它连接 GitHub 仓库后，可以处理：",[21,1345,1346,1349,1352,1355,1358,1361],{},[24,1347,1348],{},"bug fix",[24,1350,1351],{},"写 \u002F 补测试",[24,1353,1354],{},"feature building",[24,1356,1357],{},"version bump \u002F dependency upgrade",[24,1359,1360],{},"生成 changelog \u002F audio changelog",[24,1362,1363],{},"GitHub issue 任务委派",[17,1365,1366],{},"典型流程：",[415,1368,1369,1372,1375,1378,1381,1384],{},[24,1370,1371],{},"选择 GitHub repo 和 branch。",[24,1373,1374],{},"写明确任务和验收标准。",[24,1376,1377],{},"Jules 在 Cloud VM 中 clone 仓库并给出计划。",[24,1379,1380],{},"你确认计划。",[24,1382,1383],{},"Jules 修改代码、跑测试、展示 diff。",[24,1385,1386],{},"你 review 后发布分支 \u002F 创建 PR。",[13,1388,1389],{"id":1389},"价格与额度",[440,1391,1392,1404],{},[443,1393,1394],{},[446,1395,1396,1398,1402],{},[449,1397,811],{},[449,1399,1401],{"align":1400},"right","额度",[449,1403,454],{},[459,1405,1406,1416,1427],{},[446,1407,1408,1410,1413],{},[464,1409,487],{},[464,1411,1412],{"align":1400},"15 tasks\u002Fday，3 并发",[464,1414,1415],{},"个人试用、轻量任务",[446,1417,1418,1421,1424],{},[464,1419,1420],{},"Jules in Pro",[464,1422,1423],{"align":1400},"100 tasks\u002Fday，15 并发",[464,1425,1426],{},"每天都要委派任务的开发者",[446,1428,1429,1432,1435],{},[464,1430,1431],{},"Jules in Ultra",[464,1433,1434],{"align":1400},"300 tasks\u002Fday，60 并发",[464,1436,1437],{},"大规模并行 Agent 工作流",[17,1439,1440],{},"免费档已经足够验证「补测试、修小 bug、依赖升级」这类任务的 ROI。",[13,1442,1444],{"id":1443},"jules-toolscli-入口","Jules Tools：CLI 入口",[17,1446,1447],{},"Jules 早期主要是 Web UI，后来 Google 推出 Jules Tools，让它可以在终端中被脚本化。",[100,1449,1451],{"className":298,"code":1450,"language":300,"meta":105,"style":105},"npm install -g @google\u002Fjules\njules login\n\n# 查看连接过的仓库\njules remote list --repo\n\n# 创建云端任务\njules remote new --repo . --session \"write unit tests for auth module\"\n\n# 查看任务\njules remote list --session\n\n# 拉取完成任务的结果\njules remote pull --session 123456\n",[107,1452,1453,1463,1469,1473,1478,1489,1493,1498,1515,1519,1523,1533,1537,1542],{"__ignoreMap":105},[110,1454,1455,1457,1459,1461],{"class":112,"line":113},[110,1456,308],{"class":307},[110,1458,312],{"class":311},[110,1460,316],{"class":315},[110,1462,319],{"class":311},[110,1464,1465,1467],{"class":112,"line":120},[110,1466,324],{"class":307},[110,1468,327],{"class":311},[110,1470,1471],{"class":112,"line":127},[110,1472,131],{"emptyLinePlaceholder":130},[110,1474,1475],{"class":112,"line":134},[110,1476,1477],{"class":336},"# 查看连接过的仓库\n",[110,1479,1480,1482,1484,1486],{"class":112,"line":140},[110,1481,324],{"class":307},[110,1483,344],{"class":311},[110,1485,377],{"class":311},[110,1487,1488],{"class":315}," --repo\n",[110,1490,1491],{"class":112,"line":150},[110,1492,131],{"emptyLinePlaceholder":130},[110,1494,1495],{"class":112,"line":5},[110,1496,1497],{"class":336},"# 创建云端任务\n",[110,1499,1500,1502,1504,1506,1508,1510,1512],{"class":112,"line":162},[110,1501,324],{"class":307},[110,1503,344],{"class":311},[110,1505,347],{"class":311},[110,1507,350],{"class":315},[110,1509,353],{"class":311},[110,1511,356],{"class":315},[110,1513,1514],{"class":311}," \"write unit tests for auth module\"\n",[110,1516,1517],{"class":112,"line":168},[110,1518,131],{"emptyLinePlaceholder":130},[110,1520,1521],{"class":112,"line":177},[110,1522,368],{"class":336},[110,1524,1525,1527,1529,1531],{"class":112,"line":186},[110,1526,324],{"class":307},[110,1528,344],{"class":311},[110,1530,377],{"class":311},[110,1532,380],{"class":315},[110,1534,1535],{"class":112,"line":195},[110,1536,131],{"emptyLinePlaceholder":130},[110,1538,1539],{"class":112,"line":204},[110,1540,1541],{"class":336},"# 拉取完成任务的结果\n",[110,1543,1544,1546,1548,1550,1552],{"class":112,"line":209},[110,1545,324],{"class":307},[110,1547,344],{"class":311},[110,1549,398],{"class":311},[110,1551,356],{"class":315},[110,1553,403],{"class":315},[17,1555,1556],{},"CLI 的意义不只是少打开一个网页，而是能接入现有开发流水线：",[100,1558,1560],{"className":298,"code":1559,"language":300,"meta":105,"style":105},"# 把 TODO.md 每一行都派给 Jules\ncat TODO.md | while IFS= read -r line; do\n  jules remote new --repo . --session \"$line\"\ndone\n\n# 把 GitHub issue 标题直接交给 Jules\ngh issue list --assignee @me --limit 1 --json title \\\n  | jq -r '.[0].title' \\\n  | jules remote new --repo .\n",[107,1561,1562,1567,1603,1627,1632,1636,1641,1672,1687],{"__ignoreMap":105},[110,1563,1564],{"class":112,"line":113},[110,1565,1566],{"class":336},"# 把 TODO.md 每一行都派给 Jules\n",[110,1568,1569,1572,1575,1579,1582,1585,1588,1591,1594,1597,1600],{"class":112,"line":120},[110,1570,1571],{"class":307},"cat",[110,1573,1574],{"class":311}," TODO.md",[110,1576,1578],{"class":1577},"szBVR"," |",[110,1580,1581],{"class":1577}," while",[110,1583,1584],{"class":123}," IFS",[110,1586,1587],{"class":1577},"=",[110,1589,1590],{"class":315}," read",[110,1592,1593],{"class":315}," -r",[110,1595,1596],{"class":311}," line",[110,1598,1599],{"class":123},"; ",[110,1601,1602],{"class":1577},"do\n",[110,1604,1605,1608,1610,1612,1614,1616,1618,1621,1624],{"class":112,"line":127},[110,1606,1607],{"class":307},"  jules",[110,1609,344],{"class":311},[110,1611,347],{"class":311},[110,1613,350],{"class":315},[110,1615,353],{"class":311},[110,1617,356],{"class":315},[110,1619,1620],{"class":311}," \"",[110,1622,1623],{"class":123},"$line",[110,1625,1626],{"class":311},"\"\n",[110,1628,1629],{"class":112,"line":134},[110,1630,1631],{"class":1577},"done\n",[110,1633,1634],{"class":112,"line":140},[110,1635,131],{"emptyLinePlaceholder":130},[110,1637,1638],{"class":112,"line":150},[110,1639,1640],{"class":336},"# 把 GitHub issue 标题直接交给 Jules\n",[110,1642,1643,1646,1649,1651,1654,1657,1660,1663,1666,1669],{"class":112,"line":5},[110,1644,1645],{"class":307},"gh",[110,1647,1648],{"class":311}," issue",[110,1650,377],{"class":311},[110,1652,1653],{"class":315}," --assignee",[110,1655,1656],{"class":311}," @me",[110,1658,1659],{"class":315}," --limit",[110,1661,1662],{"class":315}," 1",[110,1664,1665],{"class":315}," --json",[110,1667,1668],{"class":311}," title",[110,1670,1671],{"class":315}," \\\n",[110,1673,1674,1677,1680,1682,1685],{"class":112,"line":162},[110,1675,1676],{"class":1577},"  |",[110,1678,1679],{"class":307}," jq",[110,1681,1593],{"class":315},[110,1683,1684],{"class":311}," '.[0].title'",[110,1686,1671],{"class":315},[110,1688,1689,1691,1694,1696,1698,1700],{"class":112,"line":168},[110,1690,1676],{"class":1577},[110,1692,1693],{"class":307}," jules",[110,1695,344],{"class":311},[110,1697,347],{"class":311},[110,1699,350],{"class":315},[110,1701,1702],{"class":311}," .\n",[13,1704,1706],{"id":1705},"和-devin-openhands-的差异","和 Devin \u002F OpenHands 的差异",[440,1708,1709,1721],{},[443,1710,1711],{},[446,1712,1713,1715,1717,1719],{},[449,1714,1021],{},[449,1716,487],{},[449,1718,29],{},[449,1720,476],{},[459,1722,1723,1737,1750,1764,1777,1790,1802],{},[446,1724,1725,1728,1731,1734],{},[464,1726,1727],{},"运行位置",[464,1729,1730],{},"Google Cloud VM",[464,1732,1733],{},"Devin Cloud",[464,1735,1736],{},"本地 Docker \u002F Cloud",[446,1738,1739,1742,1745,1747],{},[464,1740,1741],{},"开源",[464,1743,1744],{},"❌",[464,1746,1744],{},[464,1748,1749],{},"✅ MIT",[446,1751,1752,1755,1758,1761],{},[464,1753,1754],{},"免费入口",[464,1756,1757],{},"✅ 15 tasks\u002Fday",[464,1759,1760],{},"通常需付费",[464,1762,1763],{},"✅ OSS \u002F Cloud 免费档",[446,1765,1766,1769,1772,1774],{},[464,1767,1768],{},"GitHub PR",[464,1770,1771],{},"✅",[464,1773,1771],{},[464,1775,1776],{},"可配置",[446,1778,1779,1782,1784,1787],{},[464,1780,1781],{},"CLI \u002F API",[464,1783,1771],{},[464,1785,1786],{},"有 API",[464,1788,1789],{},"✅ CLI\u002FSDK",[446,1791,1792,1795,1797,1799],{},[464,1793,1794],{},"中文友好",[464,1796,1091],{},[464,1798,1091],{},[464,1800,1801],{},"较好",[446,1803,1804,1807,1809,1811],{},[464,1805,1806],{},"隐私可控",[464,1808,1100],{},[464,1810,1100],{},[464,1812,1813],{},"强（自托管）",[17,1815,1816],{},[40,1817,1818],{},"AIHO 建议：",[21,1820,1821,1824,1827],{},[24,1822,1823],{},"想最低门槛试 async agent：Jules",[24,1825,1826],{},"企业买成熟云端体验：Devin",[24,1828,1829],{},"代码不能出境 \u002F 要自托管：OpenHands",[13,1831,1832],{"id":1832},"最适合的任务",[1834,1835,1837],"h3",{"id":1836},"_1-补测试","1. 补测试",[100,1839,1842],{"className":1840,"code":1841,"language":282,"meta":105},[280],"为 src\u002Fbilling 里的 invoice parser 补单元测试，覆盖金额为 0、负数、缺失 tax 字段和 malformed JSON。跑通现有 test suite。\n",[107,1843,1841],{"__ignoreMap":105},[17,1845,1846],{},"边界清楚、可验证，最适合 Jules。",[1834,1848,1850],{"id":1849},"_2-依赖升级","2. 依赖升级",[100,1852,1855],{"className":1853,"code":1854,"language":282,"meta":105},[280],"把 Next.js 从 14 升级到 15，修复 breaking changes，跑 build 和现有 e2e，最后给出变更摘要。\n",[107,1856,1854],{"__ignoreMap":105},[17,1858,1859],{},"Jules 的 Cloud VM 能自己装包、跑测试、返回 diff。",[1834,1861,1863],{"id":1862},"_3-低风险-bug-fix","3. 低风险 bug fix",[100,1865,1868],{"className":1866,"code":1867,"language":282,"meta":105},[280],"修复设置页保存后 toast 重复出现的问题。验收：保存一次只出现一个 toast，补回归测试。\n",[107,1869,1867],{"__ignoreMap":105},[17,1871,1872],{},"有明确复现和验收标准，成功率更高。",[13,1874,1875],{"id":1875},"不适合的任务",[21,1877,1878,1881,1884,1887,1889],{},[24,1879,1880],{},"架构方向还没定的大重构",[24,1882,1883],{},"没有测试、没有验收标准的「帮我优化一下」",[24,1885,1886],{},"需要访问内网服务 \u002F 私有数据库的任务",[24,1888,86],{},[24,1890,1891],{},"高度中文上下文项目",[17,1893,1894],{},"Jules 是「异步执行者」，不是「替你想清楚产品需求的人」。",[13,1896,1897],{"id":1897},"避坑清单",[415,1899,1900,1906,1912,1918,1924,1930],{},[24,1901,1902,1905],{},[40,1903,1904],{},"任务要小","：一个 session 只做一个目标，不要把 5 个需求塞一起。",[24,1907,1908,1911],{},[40,1909,1910],{},"验收标准写清","：告诉它必须跑哪些测试、改完看哪些页面。",[24,1913,1914,1917],{},[40,1915,1916],{},"先让它给 plan","：计划不对就别批准执行。",[24,1919,1920,1923],{},[40,1921,1922],{},"敏感 repo 谨慎连接","：Jules 会把代码 clone 到 Cloud VM。",[24,1925,1926,1929],{},[40,1927,1928],{},"PR 必须人工 review","：Agent 可能修掉表面 bug、引入隐蔽边界问题。",[24,1931,1932,1935],{},[40,1933,1934],{},"不要无限并发","：并发越高 review 压力越大，先从 2-3 个低风险任务开始。",[13,1937,1939],{"id":1938},"aiho-工作流建议","AIHO 工作流建议",[100,1941,1944],{"className":1942,"code":1943,"language":282,"meta":105},[280],"issue backlog → Gemini CLI 低成本分拣 → Jules 处理低风险任务 → Copilot\u002FCodeRabbit\u002F人工 review → merge\n",[107,1945,1943],{"__ignoreMap":105},[17,1947,1948],{},"Jules 的价值不在「一次写出完美代码」，而在把低风险工程杂活从你的连续工作流里剥离出去。",[13,1950,1199],{"id":1199},[21,1952,1953,1960,1967],{},[24,1954,1955,1956],{},"Jules 官网：",[1181,1957,1958],{"href":1958,"rel":1959},"https:\u002F\u002Fjules.google\u002F",[1209],[24,1961,1962,1963],{},"Jules Tools CLI Reference：",[1181,1964,1965],{"href":1965,"rel":1966},"https:\u002F\u002Fjules.google\u002Fdocs\u002Fcli\u002Freference",[1209],[24,1968,1969,1970],{},"Google Developers Blog — Meet Jules Tools：",[1181,1971,1972],{"href":1972,"rel":1973},"https:\u002F\u002Fdevelopers.googleblog.com\u002Fen\u002Fmeet-jules-tools-a-command-line-companion-for-googles-async-coding-agent\u002F",[1209],[1975,1976,1977],"blockquote",{},[17,1978,1979],{},"本卡片由 AIHO 编辑部根据公开资料整理，非厂商付费内容；额度和功能以官网为准。",[700,1981,1982],{},"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 .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}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 .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}",{"title":105,"searchDepth":127,"depth":127,"links":1984},[1985,1986,1987,1988,1989,1990,1995,1996,1997,1998],{"id":753,"depth":120,"text":754},{"id":763,"depth":120,"text":763},{"id":1389,"depth":120,"text":1389},{"id":1443,"depth":120,"text":1444},{"id":1705,"depth":120,"text":1706},{"id":1832,"depth":120,"text":1832,"children":1991},[1992,1993,1994],{"id":1836,"depth":127,"text":1837},{"id":1849,"depth":127,"text":1850},{"id":1862,"depth":127,"text":1863},{"id":1875,"depth":120,"text":1875},{"id":1897,"depth":120,"text":1897},{"id":1938,"depth":120,"text":1939},{"id":1199,"depth":120,"text":1199},"\u002Fimg\u002Ftools\u002Fjules.webp","Jules 真实评测：Google Labs 出品的异步 Coding Agent，连接 GitHub 仓库后在 Cloud VM 中计划、修改、运行测试并生成 PR；支持 Web、CLI（@google\u002Fjules）、REST API、GitHub issue 标签触发。免费档 15 tasks\u002Fday、3 并发，Pro\u002FUltra 提供更高任务和并发额度。",[2002,2005,2008,2011],{"q":2003,"a":2004},"Jules 和 Gemini CLI 有什么区别？","Gemini CLI 是本地终端 Agent，读写当前目录；Jules 是异步云端 Agent，会把 GitHub 仓库 clone 到 Cloud VM，执行任务后返回 diff\u002FPR。前者适合你边写边问，后者适合把任务丢出去等结果。",{"q":2006,"a":2007},"Jules 和 Devin 怎么选？","两者都是 async coding agent。Devin 更早、产品链路更企业化；Jules 绑定 Google\u002FGemini 生态，免费档更容易试，CLI\u002FAPI 和 GitHub 标签触发更适合做脚本化委派。",{"q":2009,"a":2010},"Jules Tools 是什么？","`@google\u002Fjules` 命令行工具。它可以 `jules remote new` 创建云端任务、`jules remote list` 查看任务、`jules remote pull` 拉取结果，也可以打开 TUI 看 diff。",{"q":2012,"a":2013},"代码会不会在本地跑？","Jules 的核心执行在 Google Cloud VM。它会 clone 仓库、安装依赖、运行测试、生成 diff；这也是隐私\u002F合规敏感项目要谨慎的原因。",[1261],{},[2017,2018,2019],"不能把代码 clone 到 Google Cloud VM 的项目","需要中文深度交互和国内网络友好的团队","紧急 hotfix \u002F 强实时结对编程","\u002Ftools\u002Fcoding\u002Fagent\u002Fjules",[1266,2022],"cli",[2024,2027,2031],{"plan":487,"price":905,"limit":2025,"note":2026},"15 tasks\u002Fday，3 concurrent tasks","入门免费档，Gemini 2.5 Pro",{"plan":1420,"price":2028,"limit":2029,"note":2030},"随 Google AI Pro","100 tasks\u002Fday，15 concurrent tasks","更高模型访问，起步 Gemini 3 Pro",{"plan":1431,"price":2032,"limit":2033,"note":1437},"随 Google AI Ultra","300 tasks\u002Fday，60 concurrent tasks","免费 15 tasks\u002Fday \u002F Pro 100 tasks\u002Fday \u002F Ultra 300 tasks\u002Fday",[2036,2037],"onboarding\u002Fasync-coding-agent-workflow","review\u002Fai-pr-review-pipeline",{"power":134,"ux":134,"price":134,"cn_support":120,"stability":134},{"title":487,"description":2000},[2041,2043,2045],{"title":2042,"url":1958},"Jules 官网",{"title":2044,"url":1965},"Jules Tools CLI Reference",{"title":2046,"url":1972},"Google Developers Blog — Meet Jules Tools","tools\u002Fcoding\u002Fagent\u002Fjules",[2049,2050,2051,2052],"GitHub issue 边界清晰的 bug fix \u002F test \u002F version bump","想异步委派任务、稍后 review PR 的团队","需要多个云端 Agent 并发处理低风险任务","已经在 Google AI Pro \u002F Ultra 生态里的开发者","Google 异步 Coding Agent，在 Cloud VM 中完成任务并返回 PR",[1243,1304,1306,2055,2056,2057,2058,2022],"google","gemini","cloud-vm","github","Google 版 Devin：把 issue 丢给云端 Agent，等它在 VM 里跑完测试、给你 diff \u002F PR。适合依赖升级、补测试、低风险 bug fix；不适合中文项目、强隐私代码和需要实时结对的任务。","0ylazVOOHRNn95TTd41NpitkwTqCj-ZsMS8qOsYQRdo",{"id":2062,"title":476,"alternatives":2063,"api_compatible":748,"body":2073,"category":1243,"chinese_friendly":134,"cover":2515,"description":2516,"domestic":1246,"extension":104,"faq":2517,"free":1246,"github":2530,"languages":2531,"meta":2533,"models":748,"navigation":130,"notSuitable":748,"opensource":130,"path":741,"pillar":1264,"platforms":2534,"priceTable":2536,"pricing":2543,"published":1281,"relatedPlaybooks":2544,"relatedReviews":748,"score":2549,"self_host":130,"seo":2550,"slug":727,"sources":2551,"stem":2560,"suitable":748,"tagline":2561,"tags":2562,"updated":1294,"verdict":2568,"website":2569,"__hash__":2570},"tools\u002Ftools\u002Fcoding\u002Fagent\u002Fopenhands.md",[2064,2066,2069,2072],{"name":2065,"url":1263},"devin",{"name":2067,"url":2068},"aider","\u002Ftools\u002Fcoding\u002Fcli\u002Faider",{"name":2070,"url":2071},"cline","\u002Ftools\u002Fcoding\u002Fcli\u002Fcline",{"name":743,"url":744},{"type":10,"value":2074,"toc":2503},[2075,2077,2084,2087,2089,2092,2115,2118,2146,2150,2196,2199,2203,2207,2228,2232,2252,2254,2283,2285,2385,2387,2427,2429,2446,2448,2471,2473],[13,2076,754],{"id":753},[17,2078,2079,2080,2083],{},"OpenHands（前 OpenDevin）是 MIT 开源的自主编程 Agent 平台，由 All Hands AI 主导，GitHub 40k+ stars。它的目标和 Devin 一致——给 AI 一个完整的开发者工具集（编辑器、shell、浏览器、API），让它能像人一样完成端到端开发任务。差异在于：",[40,2081,2082],{},"OpenHands 完全开源 + 多入口 + BYOK","，可以本地 docker 起一个、可以走免费 Cloud、可以企业自托管。",[17,2085,2086],{},"适合：合规 \u002F 隐私敏感场景、想用 Claude \u002F GPT \u002F 本地 Ollama 的人、嫌 Devin 贵且不能落地的人。不适合：想要开箱即用 SaaS 体验、不想碰 Docker \u002F yaml 的非技术用户。",[13,2088,763],{"id":763},[17,2090,2091],{},"OpenHands 的核心是「Agent + 工具集」，工具集包括：",[21,2093,2094,2097,2100,2103,2106,2109],{},[24,2095,2096],{},"文件编辑（多文件 diff\u002Fedit）",[24,2098,2099],{},"shell command 执行（Docker sandbox 隔离）",[24,2101,2102],{},"浏览器自动化（点击、表单、截图）",[24,2104,2105],{},"API 调用 \u002F HTTP 请求",[24,2107,2108],{},"Git 仓库操作（clone、commit、PR）",[24,2110,2111,2114],{},[40,2112,2113],{},"MCP 协议","：可挂载任意第三方 tool",[17,2116,2117],{},"四种使用入口：",[415,2119,2120,2129,2135,2140],{},[24,2121,2122,953,2125,2128],{},[40,2123,2124],{},"OSS 自托管",[107,2126,2127],{},"docker run"," 一行起，本地 Web GUI + CLI",[24,2130,2131,2134],{},[40,2132,2133],{},"Individual Cloud","：openhands.dev 注册免费用，每天 10 会话",[24,2136,2137,2139],{},[40,2138,866],{},"：私有云 + 多用户 + RBAC + 集中 billing",[24,2141,2142,2145],{},[40,2143,2144],{},"Cloud Agent SDK","：把 OpenHands 当 lib 嵌入自家产品",[13,2147,2149],{"id":2148},"价格2026-06","价格（2026-06）",[440,2151,2152,2163],{},[443,2153,2154],{},[446,2155,2156,2158,2160],{},[449,2157,811],{},[449,2159,892],{},[449,2161,2162],{},"限制",[459,2164,2165,2176,2187],{},[446,2166,2167,2171,2173],{},[464,2168,2169],{},[40,2170,2124],{},[464,2172,905],{},[464,2174,2175],{},"BYOK，单用户，自己付 LLM 费",[446,2177,2178,2182,2184],{},[464,2179,2180],{},[40,2181,2133],{},[464,2183,905],{},[464,2185,2186],{},"每天 10 会话，BYOK 或 OpenHands at-cost LLM",[446,2188,2189,2191,2193],{},[464,2190,866],{},[464,2192,869],{},[464,2194,2195],{},"多用户、SAML\u002FSSO、专属支持、Slack 频道",[17,2197,2198],{},"至今没有「Cloud Pro $X\u002F月」中间档——要么免费 BYOK，要么直接谈 Enterprise。BYOK 路线下，实际 LLM 成本主导：跑一个中等任务（5–10 步）约 $0.5–$2 Claude Sonnet token。",[13,2200,2202],{"id":2201},"实测本地-docker-一周高强度试用","实测（本地 docker 一周高强度试用）",[17,2204,2205,953],{},[40,2206,952],{},[21,2208,2209,2216,2219,2222,2225],{},[24,2210,2211,2212,2215],{},"起步快：",[107,2213,2214],{},"docker run -p 3000:3000 allhandsai\u002Fopenhands"," 三分钟到 Web UI",[24,2217,2218],{},"中文支持比 Devin 好——社区贡献了不少中文 prompt 案例",[24,2220,2221],{},"浏览器 use 能力扎实——能去 stackoverflow 搜错误后修代码",[24,2223,2224],{},"任务可视化：sandbox 里跑的每条命令、改的每个文件都有回放",[24,2226,2227],{},"BYOK 灵活：白天 Claude Sonnet 4，晚上 DeepSeek R1，省钱",[17,2229,2230,953],{},[40,2231,972],{},[21,2233,2234,2240,2243,2246,2249],{},[24,2235,2236,2239],{},[40,2237,2238],{},"自主性偶尔失控","：会陷入「装包失败 → 改 requirements → 再装 → 再失败」死循环，需要人工打断",[24,2241,2242],{},"长任务（>30 分钟）context window 会爆，需要把任务拆小",[24,2244,2245],{},"Windows 用户必走 WSL2 + Docker Desktop，原生 docker 不稳",[24,2247,2248],{},"GUI 体验不如 Cursor \u002F Devin 精致——是工程师工具，不是 PM 工具",[24,2250,2251],{},"沙箱占资源——idle 时也吃 1–2GB 内存",[13,2253,992],{"id":992},[415,2255,2256,2259,2264,2270,2273,2276],{},[24,2257,2258],{},"装 Docker（含 docker-in-docker 支持）",[24,2260,2261],{},[107,2262,2263],{},"docker pull docker.all-hands.dev\u002Fall-hands-ai\u002Fopenhands:latest",[24,2265,2266,2267],{},"一行启动（官方推荐命令在 docs），打开 ",[107,2268,2269],{},"localhost:3000",[24,2271,2272],{},"选 LLM provider（Anthropic \u002F OpenAI \u002F Ollama \u002F 任意 OpenAI 兼容 endpoint）+ 填 API key",[24,2274,2275],{},"描述任务（中文 OK），Agent 在 sandbox 里跑给你看",[24,2277,2278,2279,2282],{},"进阶：编辑 ",[107,2280,2281],{},"config.toml"," 加 MCP server，或 fork 仓库改 microagent prompt",[13,2284,1012],{"id":1012},[440,2286,2287,2302],{},[443,2288,2289],{},[446,2290,2291,2293,2295,2297,2300],{},[449,2292,1021],{},[449,2294,476],{},[449,2296,29],{},[449,2298,2299],{},"Aider",[449,2301,1028],{},[459,2303,2304,2316,2329,2341,2357,2370],{},[446,2305,2306,2308,2310,2312,2314],{},[464,2307,1741],{},[464,2309,1749],{},[464,2311,1744],{},[464,2313,1771],{},[464,2315,1744],{},[446,2317,2318,2321,2323,2325,2327],{},[464,2319,2320],{},"自托管",[464,2322,1771],{},[464,2324,1744],{},[464,2326,1771],{},[464,2328,1744],{},[446,2330,2331,2333,2335,2337,2339],{},[464,2332,1055],{},[464,2334,905],{},[464,2336,1058],{},[464,2338,905],{},[464,2340,1064],{},[446,2342,2343,2345,2348,2351,2354],{},[464,2344,1088],{},[464,2346,2347],{},"4\u002F5",[464,2349,2350],{},"1\u002F5",[464,2352,2353],{},"3\u002F5",[464,2355,2356],{},"5\u002F5",[446,2358,2359,2362,2364,2366,2368],{},[464,2360,2361],{},"Browser use",[464,2363,1771],{},[464,2365,1771],{},[464,2367,1744],{},[464,2369,1771],{},[446,2371,2372,2375,2378,2381,2383],{},[464,2373,2374],{},"上手成本",[464,2376,2377],{},"中（需 Docker）",[464,2379,2380],{},"低",[464,2382,2380],{},[464,2384,2380],{},[13,2386,1119],{"id":1119},[21,2388,2389,2395,2401,2415,2421],{},[24,2390,2391,2394],{},[40,2392,2393],{},"沙箱必启用","：直接给 OpenHands 你的家目录权限 = 自杀，永远走 docker-in-docker 隔离",[24,2396,2397,2400],{},[40,2398,2399],{},"API key 限额要设","：BYOK 没有月度上限，Agent 一旦循环可能一夜烧掉 $100+，在 Anthropic \u002F OpenAI 控制台配 budget alert",[24,2402,2403,2406,2407,2410,2411,2414],{},[40,2404,2405],{},"大仓库先 wiki","：让 OpenHands 跑一遍 ",[107,2408,2409],{},"summarize the repo","，把结果存到 ",[107,2412,2413],{},"microagents\u002F","，后续任务上下文更准",[24,2416,2417,2420],{},[40,2418,2419],{},"MCP 来源审计","：开 MCP server 等于给 Agent 一把外部钥匙，第三方 server 先审代码",[24,2422,2423,2426],{},[40,2424,2425],{},"不要给 production repo 直接权限","：先 fork \u002F 分支隔离，让 Agent 提 PR 而不是直接 push",[13,2428,1155],{"id":1154},[21,2430,2431,2434,2437,2440,2443],{},[24,2432,2433],{},"✅ 中文 \u002F 国内场景（速度 + 隐私 + 成本三优）",[24,2435,2436],{},"✅ 合规 \u002F 私有云部署",[24,2438,2439],{},"✅ 想做企业内部 AI 开发平台的底座",[24,2441,2442],{},"❌ 不会 Docker \u002F 不愿读 yaml 的 PM \u002F 设计师",[24,2444,2445],{},"❌ 要 Devin 那种端到端体验（PR \u002F Slack \u002F Wiki 全自动）",[13,2447,1175],{"id":1175},[21,2449,2450,2456,2461,2466],{},[24,2451,2452,2455],{},[1181,2453,2454],{"href":1263},"Devin 评测","（闭源同类）",[24,2457,2458],{},[1181,2459,2460],{"href":2068},"Aider 评测",[24,2462,2463],{},[1181,2464,2465],{"href":2071},"Cline 评测",[24,2467,2468,2470],{},[1181,2469,1189],{"href":744},"（国产 Cloud 替代）",[13,2472,1199],{"id":1199},[415,2474,2475,2482,2489,2496],{},[24,2476,2477,2478],{},"OpenHands 官方 Pricing ",[1181,2479,2480],{"href":2480,"rel":2481},"https:\u002F\u002Fwww.openhands.dev\u002Fpricing",[1209],[24,2483,2484,2485],{},"AISO Tools — OpenHands Pricing 2026（2026-06-21）",[1181,2486,2487],{"href":2487,"rel":2488},"https:\u002F\u002Faisotools.com\u002Fpricing\u002Fopenhands",[1209],[24,2490,2491,2492],{},"AI Tool Finder — OpenHands Review 2026（2026-05-14）",[1181,2493,2494],{"href":2494,"rel":2495},"https:\u002F\u002Faitoolfinder.org\u002Ftools\u002Fopenhands",[1209],[24,2497,2498,2499],{},"OSS-AI-SWE 项目目录 ",[1181,2500,2501],{"href":2501,"rel":2502},"https:\u002F\u002Foss-ai-swe.org\u002Fopen-hands",[1209],{"title":105,"searchDepth":127,"depth":127,"links":2504},[2505,2506,2507,2508,2509,2510,2511,2512,2513,2514],{"id":753,"depth":120,"text":754},{"id":763,"depth":120,"text":763},{"id":2148,"depth":120,"text":2149},{"id":2201,"depth":120,"text":2202},{"id":992,"depth":120,"text":992},{"id":1012,"depth":120,"text":1012},{"id":1119,"depth":120,"text":1119},{"id":1154,"depth":120,"text":1155},{"id":1175,"depth":120,"text":1175},{"id":1199,"depth":120,"text":1199},"\u002Fimg\u002Ftools\u002Fopenhands.webp","OpenHands 真实评测：MIT 开源自主编程 Agent，前身 OpenDevin。可云端、本地 GUI、CLI、SDK 多种方式跑，BYOK 任意 LLM。Individual 免费、Enterprise 自托管多用户。40k+ GitHub stars。",[2518,2521,2524,2527],{"q":2519,"a":2520},"OpenHands 和 OpenDevin 什么关系？","同一个项目。2024 年底从 OpenDevin 改名 OpenHands，由 All Hands AI 主导维护，社区贡献者来自学术界和工业界。",{"q":2522,"a":2523},"和 Devin 比能力差多少？","核心能力覆盖：plan、code、run command、browser use、MCP tool use 都有。差距主要在『一体化体验』——Devin 自带 Wiki\u002FSlack\u002FIDE，OpenHands 需要自己拼 Docker + GUI\u002FCLI；任务成功率两者接近，特定 benchmark（SWE-Bench）OpenHands 还领先过。",{"q":2525,"a":2526},"本地跑要什么配置？","Docker 必备（Linux\u002FmacOS\u002FWSL2），16GB 内存以上推荐，API key 可走 Anthropic Claude \u002F OpenAI GPT \u002F 本地 Ollama。沙箱用 docker-in-docker，CPU 占用偶发尖峰。",{"q":2528,"a":2529},"Individual Cloud 真的免费？","免费，但限制每天 10 会话；BYOK 自付模型 token，或用『OpenHands LLM provider』按 at-cost 转售价 PAYG（无加价）。","https:\u002F\u002Fgithub.com\u002FAll-Hands-AI\u002FOpenHands",[2532,1261],"zh",{},[2535,1266,2022],"docker",[2537,2539,2541],{"plan":2124,"price":905,"seats":1083,"notes":2538},"MIT，Docker 起，BYOK，单用户",{"plan":2133,"price":905,"seats":1083,"notes":2540},"每日 10 会话上限，BYOK 或用 OpenHands LLM at-cost",{"plan":866,"price":869,"seats":858,"notes":2542},"自托管多用户、RBAC、SAML\u002FSSO、SLA、专属支持","OSS MIT 免费 \u002F Individual Cloud 免费 BYOK \u002F Enterprise 定制",[2545,2548],{"name":2546,"url":2547},"Legacy 代码库 AI Onboarding","\u002Fplaybook\u002Fonboarding\u002Flegacy-codebase-onboarding",{"name":1287,"url":1288},{"power":134,"ux":127,"price":140,"cn_support":134,"stability":127},{"title":476,"description":2516},[2552,2554,2556,2558],{"name":2553,"url":2480,"accessed":1294},"OpenHands 官方 pricing",{"name":2555,"url":2487,"accessed":1294},"AISO Tools — OpenHands Pricing 2026",{"name":2557,"url":2494,"accessed":1294},"AI Tool Finder — OpenHands Review 2026",{"name":2559,"url":2501,"accessed":1294},"OSS-AI-SWE — OpenHands intro","tools\u002Fcoding\u002Fagent\u002Fopenhands","开源自主编程 Agent（前 OpenDevin），MIT 许可，多入口（Cloud\u002FCLI\u002FLocal\u002FSDK）",[1243,1304,2563,2564,2565,2566,2567],"opensource","mit","sandbox","mcp","byok","想要 Devin 能力又不想为 ACU 付费 + 担心代码出境的人选 OpenHands。MIT 开源 + Docker 自托管 + BYOK 任意 LLM，是企业级自主 Agent 的开源旗手。","https:\u002F\u002Fwww.openhands.dev","DFosd9OUmpxRhhrEU4jOSPPl0BQrhgA_xvkxn5fJjpM",{"id":2572,"title":2573,"alternatives":2574,"api_compatible":2579,"body":2580,"category":2815,"chinese_friendly":127,"cover":3619,"description":3620,"domestic":1246,"extension":104,"faq":748,"free":1246,"github":3569,"languages":3621,"meta":3622,"models":3623,"navigation":130,"notSuitable":3629,"opensource":1246,"path":3633,"pillar":1264,"platforms":3634,"priceTable":3638,"pricing":3658,"published":1281,"relatedPlaybooks":748,"relatedReviews":748,"score":3659,"self_host":1246,"seo":3660,"slug":726,"sources":3661,"stem":3684,"suitable":3685,"tagline":3691,"tags":3692,"updated":722,"verdict":3697,"website":3569,"__hash__":3698},"tools\u002Ftools\u002Fcoding\u002Fcopilot\u002Fgithub-copilot.md","GitHub Copilot",[2575,2576,2577,2578],"coding\u002Fide\u002Fcursor","coding\u002Fide\u002Fwindsurf","coding\u002Fextension\u002Fcline","coding\u002Fextension\u002Fcontinue",[],{"type":10,"value":2581,"toc":3600},[2582,2584,2612,2617,2620,2624,2674,2678,2686,2700,2707,2712,2716,2724,2742,2745,2749,2759,2762,2806,2824,2828,2831,2834,2848,2855,2859,2867,2891,2894,2901,2980,2985,3010,3014,3121,3124,3127,3167,3170,3332,3337,3371,3373,3442,3444,3447,3464,3467,3495,3497,3560,3562,3590,3597],[13,2583,754],{"id":753},[1320,2585,2587,2601],{"className":2586},[1323,1324,1325],[17,2588,2589,2591,2592,2596,2597,2600],{},[40,2590,1330],{}," AI 编程的\"出厂选项\"。2021 年随 VS Code 首发，2025-02 Agent Mode GA、2025-09 Coding Agent GA、2025 全年支持 ",[1181,2593,2595],{"href":2594},"\u002Fwiki\u002Fmcp.html","MCP","，到 2026 Q2 已经从\"补全工具\"演化成 ",[40,2598,2599],{},"完整 Agent 平台","——补全、对话、Agent Mode、后台 Coding Agent 一站全有。",[17,2602,2603,2604,2607,2608,2611],{},"最大优势是 ",[40,2605,2606],{},"生态最稳 + 免费档大方（2000 次补全\u002F月）+ 学生\u002F开源免费 Pro","。代价是 ",[40,2609,2610],{},"国内门槛","：账号 + 网络 + 支付。",[1975,2613,2614],{},[17,2615,2616],{},"来源说明：本文基于 github.com 官方页面、docs.github.com 企业版文档、github.blog 公告、第三方评测（augmentcode \u002F tossitt \u002F 4geeks）综合整理。Copilot 定价 2026 多次调整（社区报告 2026-04 起新增 credit 制），请以最新官方页面为准。",[13,2618,2619],{"id":2619},"核心特性",[1834,2621,2623],{"id":2622},"三大形态completion-chat-agent","三大形态：Completion \u002F Chat \u002F Agent",[21,2625,2626,2632,2638,2644,2650,2668],{},[24,2627,2628,2631],{},[40,2629,2630],{},"Code Completion","：开山立派的能力，AI 在你写代码时给 inline 建议",[24,2633,2634,2637],{},[40,2635,2636],{},"Copilot Chat","：侧边栏对话，问\"这段代码什么意思\"、\"帮我写个 SQL\"",[24,2639,2640,2643],{},[40,2641,2642],{},"Agent Mode","（2025-02 在 VS Code GA）：自主多文件编辑，可调工具、跑测试、看结果调整",[24,2645,2646,2649],{},[40,2647,2648],{},"Coding Agent","（2025-09 GA）：在 GitHub 网页 \u002F 移动端把 issue 派给 Copilot，它在云端 Actions 环境里改代码、开 PR 等你 review",[24,2651,2652,2655,2656,588,2659,588,2662,588,2665],{},[40,2653,2654],{},"Copilot CLI 新终端界面","（2026-06-23 GA）：Tabbed TUI、Issues\u002FPRs\u002FGists 标签页、内置 ",[107,2657,2658],{},"\u002Fmcp add",[107,2660,2661],{},"\u002Fskills",[107,2663,2664],{},"\u002Fplugin",[107,2666,2667],{},"\u002Fsettings",[24,2669,2670,2673],{},[40,2671,2672],{},"Agent Finder","（2026-06-17 发布）：基于开放 ARD（Agentic Resource Discovery）规范，按任务动态发现可用资源 \u002F MCP \u002F 私有 registry，避免一开始把所有工具塞进上下文",[1834,2675,2677],{"id":2676},"agent-mode-详解","Agent Mode 详解",[17,2679,2680,2685],{},[1181,2681,2684],{"href":2682,"rel":2683},"https:\u002F\u002Fgithub.blog\u002Fnews-insights\u002Fproduct-news\u002Fgithub-copilot-coding-agent-is-now-generally-available\u002F",[1209],"GitHub Blog 公告"," 描述的 Agent Mode 能力：",[21,2687,2688,2691,2694,2697],{},[24,2689,2690],{},"跨文件自主编辑（不需要你一个个 @ 文件）",[24,2692,2693],{},"调用 terminal 跑测试 \u002F linter",[24,2695,2696],{},"MCP 服务集成（2025-04 起 public preview，VS Code \u002F JetBrains \u002F Xcode 都支持）",[24,2698,2699],{},"支持 Claude Opus 4.6 \u002F Sonnet 4.6 \u002F GPT-5 \u002F Gemini 2.5 Pro 等多模型按需切",[17,2701,2702,953],{},[1181,2703,2706],{"href":2704,"rel":2705},"https:\u002F\u002Fagents.4geeks.com\u002Fagent\u002Fgithub-copilot",[1209],"4geeks.com 2025 评测",[1975,2708,2709],{},[17,2710,2711],{},"\"GitHub Copilot supports MCP (Model Context Protocol) servers in VS Code, JetBrains, and Xcode, available in Agent Mode. Users can connect MCP tools directly from the Copilot panel.\"",[1834,2713,2715],{"id":2714},"coding-agent云端后台-pr-生成","Coding Agent（云端后台 PR 生成）",[17,2717,2718,2723],{},[1181,2719,2722],{"href":2720,"rel":2721},"https:\u002F\u002Fdocs.github.com\u002F",[1209],"GitHub 官方文档"," 描述的 Coding Agent：",[21,2725,2726,2729,2736,2739],{},[24,2727,2728],{},"从 GitHub Issues、VS Code、GitHub.com agent 界面、PR 评论、安全告警任一入口指派",[24,2730,2731,2732,2735],{},"在 ",[40,2733,2734],{},"GitHub Actions 临时开发环境","里跑（不占你本地）",[24,2737,2738],{},"完成后开 PR，附完整 commit \u002F 测试输出 \u002F 工作日志",[24,2740,2741],{},"你只 review + merge",[17,2743,2744],{},"支持版本：Pro \u002F Pro+ \u002F Business \u002F Enterprise（Free 不含）",[1834,2746,2748],{"id":2747},"copilot-cli2026-新终端界面-ga","Copilot CLI（2026 新终端界面 GA）",[17,2750,2751,2752,588,2755,2758],{},"2026-06-23，GitHub 将新版 Copilot CLI terminal interface 推到 GA。它已经不只是 ",[107,2753,2754],{},"gh copilot suggest",[107,2756,2757],{},"gh copilot explain"," 这种「自然语言 → shell 命令」工具，而是更接近一个终端里的 Copilot 工作台。",[17,2760,2761],{},"关键变化：",[21,2763,2764,2770,2780,2797],{},[24,2765,2766,2769],{},[40,2767,2768],{},"Tabbed TUI","：Session \u002F Gists \u002F Issues \u002F Pull Requests 标签页，当前目录是 GitHub repo 时自动显示 issue \u002F PR。",[24,2771,2772,2775,2776,2779],{},[40,2773,2774],{},"引用工作项","：在 Issues \u002F PRs tab 高亮条目后按 ",[107,2777,2778],{},"c","，可以把该 issue \u002F PR 直接塞进 prompt，让 Copilot 调查、修复或 review。",[24,2781,2782,953,2785,588,2787,588,2790,588,2792,588,2794,2796],{},[40,2783,2784],{},"内置配置",[107,2786,2658],{},[107,2788,2789],{},"\u002Fmcp search",[107,2791,2661],{},[107,2793,2664],{},[107,2795,2667],{}," 都可以在会话中完成，不再手写配置文件。",[24,2798,2799,953,2802,2805],{},[40,2800,2801],{},"无障碍主题",[107,2803,2804],{},"\u002Ftheme"," 支持 default \u002F dim \u002F high-contrast \u002F colorblind，并自动检测 screen reader。",[100,2807,2809],{"className":298,"code":2808,"language":300,"meta":105,"style":105},"copilot update\ncopilot\n",[107,2810,2811,2819],{"__ignoreMap":105},[110,2812,2813,2816],{"class":112,"line":113},[110,2814,2815],{"class":307},"copilot",[110,2817,2818],{"class":311}," update\n",[110,2820,2821],{"class":112,"line":120},[110,2822,2823],{"class":307},"copilot\n",[1834,2825,2827],{"id":2826},"agent-finder资源发现开始标准化","Agent Finder：资源发现开始标准化",[17,2829,2830],{},"2026-06-17，GitHub 推出 Agent Finder。它解决的是 2026 年 Agent 工具链的新问题：工具、MCP、skills、私有 registry 越来越多，如果每次都预加载，context 会爆；如果都手动接，开发者又会被配置淹没。",[17,2832,2833],{},"Agent Finder 的思路是：",[415,2835,2836,2839,2842,2845],{},[24,2837,2838],{},"用户用自然语言描述任务。",[24,2840,2841],{},"Copilot 到公开 catalog 或企业私有 registry 里搜索资源。",[24,2843,2844],{},"返回 ranked matches。",[24,2846,2847],{},"用户确认后，Copilot 再按需加载对应工具 \u002F skill。",[17,2849,2850,2851,2854],{},"GitHub 表示它实现了开放的 ",[40,2852,2853],{},"ARD（Agentic Resource Discovery）spec","，并与 Google、GoDaddy、Hugging Face、Microsoft 协作制定。这个方向值得关注：MCP 解决「连工具」，ARD 解决「怎么发现该连哪个工具」。",[1834,2856,2858],{"id":2857},"模型选择-credit-制2026-新变化","模型选择 + Credit 制（2026 新变化）",[17,2860,2861,2866],{},[1181,2862,2865],{"href":2863,"rel":2864},"https:\u002F\u002Fgithub.com\u002Ffeatures\u002Fcopilot\u002Fplans",[1209],"Copilot 官方 Plans 页"," 2026 Q2 价格表关键变化：",[21,2868,2869,2876,2879,2882],{},[24,2870,2871,2872,2875],{},"各档位除 seat 费外，",[40,2873,2874],{},"附赠 AI credits","（Pro $15 \u002F Pro+ $70 \u002F Max $200 \u002F Business $? \u002F Enterprise 更多）",[24,2877,2878],{},"Credits 用于调用 premium 模型（Opus \u002F GPT-5 等）",[24,2880,2881],{},"普通 Sonnet \u002F Haiku \u002F GPT-5 mini 不消耗 credits 或低消耗",[24,2883,2884,2885,2890],{},"2026-04-20 起一度暂停 Pro \u002F Pro+ \u002F Student 新签，6-1 切到 credit 制（",[1181,2886,2889],{"href":2887,"rel":2888},"https:\u002F\u002Ftossitt.com\u002Fgithub-copilot-guide-2026",[1209],"tossitt 2026-04 指南","）",[13,2892,2893],{"id":2893},"价格与运行成本",[17,2895,2896,2900],{},[1181,2897,2899],{"href":2863,"rel":2898},[1209],"官方 Plans 页"," 2026 Q2 公开数据：",[440,2902,2903,2915],{},[443,2904,2905],{},[446,2906,2907,2910,2912],{},[449,2908,2909],{},"档位",[449,2911,892],{},[449,2913,2914],{},"关键点",[459,2916,2917,2929,2939,2949,2959,2970],{},[446,2918,2919,2921,2923],{},[464,2920,902],{},[464,2922,905],{},[464,2924,2925,2926],{},"2000 补全\u002F月，Haiku 4.5 + GPT-5 mini，含 Copilot CLI，",[40,2927,2928],{},"无需信用卡",[446,2930,2931,2933,2936],{},[464,2932,913],{},[464,2934,2935],{},"$10\u002F月",[464,2937,2938],{},"无限补全 + Cloud agent + Code review + 第三方 agent（Claude Code \u002F Codex）+ $15 credits",[446,2940,2941,2944,2946],{},[464,2942,2943],{},"Pro+",[464,2945,1064],{},[464,2947,2948],{},"Pro + Opus 等 premium 模型 + 4x usage + $70 credits",[446,2950,2951,2953,2956],{},[464,2952,924],{},[464,2954,2955],{},"$100\u002F月",[464,2957,2958],{},"Pro+ 2.9x + 优先新模型 + $200 credits",[446,2960,2961,2964,2967],{},[464,2962,2963],{},"Business",[464,2965,2966],{},"$19\u002Fseat\u002F月",[464,2968,2969],{},"组织管理 + Copilot 策略 + 全代码库语义索引",[446,2971,2972,2974,2977],{},[464,2973,866],{},[464,2975,2976],{},"$39\u002Fseat\u002F月",[464,2978,2979],{},"Business + Enterprise 索引 + 优先模型",[17,2981,2982,953],{},[40,2983,2984],{},"重要福利",[21,2986,2987,2998,3004],{},[24,2988,2989,953,2992,2997],{},[40,2990,2991],{},"学生免费",[1181,2993,2996],{"href":2994,"rel":2995},"https:\u002F\u002Feducation.github.com\u002Fpack",[1209],"GitHub Student Developer Pack"," 认证后直接拿 Pro",[24,2999,3000,3003],{},[40,3001,3002],{},"开源维护者免费","：维护流行开源项目（star 数 + 活跃度门槛）可申请免费 Pro",[24,3005,3006,3009],{},[40,3007,3008],{},"教师免费","：通过 GitHub Education 认证",[13,3011,3013],{"id":3012},"上手-3-分钟","上手 3 分钟",[100,3015,3017],{"className":298,"code":3016,"language":300,"meta":105,"style":105},"# VS Code：扩展市场搜 \"GitHub Copilot\" 装上即可\n# JetBrains：Plugin Marketplace 搜 Copilot\n# Neovim：装 github\u002Fcopilot.vim 仓库\n# Xcode：装 github\u002FCopilotForXcode\n\n# 命令行\nbrew install gh                  # macOS\nwinget install GitHub.cli        # Windows\n# Linux：参考 cli.github.com\n\ngh auth login                    # 登录 GitHub\ngh extension install github\u002Fgh-copilot\ngh copilot suggest \"重启 docker 并清理缓存\"\n",[107,3018,3019,3024,3029,3034,3039,3043,3048,3061,3074,3079,3083,3096,3108],{"__ignoreMap":105},[110,3020,3021],{"class":112,"line":113},[110,3022,3023],{"class":336},"# VS Code：扩展市场搜 \"GitHub Copilot\" 装上即可\n",[110,3025,3026],{"class":112,"line":120},[110,3027,3028],{"class":336},"# JetBrains：Plugin Marketplace 搜 Copilot\n",[110,3030,3031],{"class":112,"line":127},[110,3032,3033],{"class":336},"# Neovim：装 github\u002Fcopilot.vim 仓库\n",[110,3035,3036],{"class":112,"line":134},[110,3037,3038],{"class":336},"# Xcode：装 github\u002FCopilotForXcode\n",[110,3040,3041],{"class":112,"line":140},[110,3042,131],{"emptyLinePlaceholder":130},[110,3044,3045],{"class":112,"line":150},[110,3046,3047],{"class":336},"# 命令行\n",[110,3049,3050,3053,3055,3058],{"class":112,"line":5},[110,3051,3052],{"class":307},"brew",[110,3054,312],{"class":311},[110,3056,3057],{"class":311}," gh",[110,3059,3060],{"class":336},"                  # macOS\n",[110,3062,3063,3066,3068,3071],{"class":112,"line":162},[110,3064,3065],{"class":307},"winget",[110,3067,312],{"class":311},[110,3069,3070],{"class":311}," GitHub.cli",[110,3072,3073],{"class":336},"        # Windows\n",[110,3075,3076],{"class":112,"line":168},[110,3077,3078],{"class":336},"# Linux：参考 cli.github.com\n",[110,3080,3081],{"class":112,"line":177},[110,3082,131],{"emptyLinePlaceholder":130},[110,3084,3085,3087,3090,3093],{"class":112,"line":186},[110,3086,1645],{"class":307},[110,3088,3089],{"class":311}," auth",[110,3091,3092],{"class":311}," login",[110,3094,3095],{"class":336},"                    # 登录 GitHub\n",[110,3097,3098,3100,3103,3105],{"class":112,"line":195},[110,3099,1645],{"class":307},[110,3101,3102],{"class":311}," extension",[110,3104,312],{"class":311},[110,3106,3107],{"class":311}," github\u002Fgh-copilot\n",[110,3109,3110,3112,3115,3118],{"class":112,"line":204},[110,3111,1645],{"class":307},[110,3113,3114],{"class":311}," copilot",[110,3116,3117],{"class":311}," suggest",[110,3119,3120],{"class":311}," \"重启 docker 并清理缓存\"\n",[17,3122,3123],{},"IDE 中：登录 GitHub 账号 → 同意订阅 → 直接用。Free 档不需要任何信用卡。",[13,3125,3126],{"id":3126},"国内使用注意事项",[415,3128,3129,3135,3145,3151],{},[24,3130,3131,3134],{},[40,3132,3133],{},"账号","：注册 GitHub 即可，国内号 ok，但偶发要海外手机验证",[24,3136,3137,3140,3141,3144],{},[40,3138,3139],{},"网络","：插件 push \u002F pull 走 api.github.com 和 copilot-proxy.githubusercontent.com，国内",[40,3142,3143],{},"必须有稳定代理","，否则补全卡顿到不可用",[24,3146,3147,3150],{},[40,3148,3149],{},"支付","：Pro 付款渠道有限——Apple 礼品卡（macOS）、Google Play（Android）、海外卡。第三方代付方案少",[24,3152,3153,3156,3157,3161,3162,3166],{},[40,3154,3155],{},"替代路径","：用 ",[1181,3158,3160],{"href":3159},"\u002Fcoding\u002Fcli\u002Fcline.html","Cline"," \u002F ",[1181,3163,3165],{"href":3164},"\u002Fcoding\u002Fagent\u002Fcontinue.html","Continue"," + 国产模型，国内体验更顺畅",[13,3168,3169],{"id":3169},"与同类怎么选",[440,3171,3172,3196],{},[443,3173,3174],{},[446,3175,3176,3178,3180,3186,3192],{},[449,3177,1021],{},[449,3179,2573],{},[449,3181,3182],{},[1181,3183,3185],{"href":3184},"\u002Fcoding\u002Fide\u002Fcursor.html","Cursor",[449,3187,3188],{},[1181,3189,3191],{"href":3190},"\u002Fcoding\u002Fide\u002Fwindsurf.html","Windsurf",[449,3193,3194],{},[1181,3195,3160],{"href":3159},[459,3197,3198,3214,3230,3244,3260,3275,3290,3304,3319],{},[446,3199,3200,3203,3206,3209,3211],{},[464,3201,3202],{},"形态",[464,3204,3205],{},"插件（VS Code\u002FJetBrains 等）",[464,3207,3208],{},"AI-first IDE",[464,3210,3208],{},[464,3212,3213],{},"VS Code 扩展",[446,3215,3216,3219,3222,3225,3227],{},[464,3217,3218],{},"多 IDE 覆盖",[464,3220,3221],{},"★★★★★",[464,3223,3224],{},"★★☆☆☆ 仅自家",[464,3226,3224],{},[464,3228,3229],{},"★★★★☆",[446,3231,3232,3235,3237,3239,3241],{},[464,3233,3234],{},"补全速度",[464,3236,3229],{},[464,3238,3229],{},[464,3240,3221],{},[464,3242,3243],{},"★★★☆☆",[446,3245,3246,3249,3252,3255,3258],{},[464,3247,3248],{},"Agent 模式",[464,3250,3251],{},"★★★★☆ Agent Mode",[464,3253,3254],{},"★★★★★ Composer",[464,3256,3257],{},"★★★★★ Cascade",[464,3259,3229],{},[446,3261,3262,3265,3268,3271,3273],{},[464,3263,3264],{},"云端后台 Agent",[464,3266,3267],{},"★★★★★ Coding Agent",[464,3269,3270],{},"⚠️ Bug bot",[464,3272,1744],{},[464,3274,1744],{},[446,3276,3277,3280,3283,3285,3287],{},[464,3278,3279],{},"模型选择",[464,3281,3282],{},"★★★★★ 多家",[464,3284,3229],{},[464,3286,3229],{},[464,3288,3289],{},"★★★★★ BYOK",[446,3291,3292,3295,3298,3300,3302],{},[464,3293,3294],{},"企业合规",[464,3296,3297],{},"★★★★★ SOC2\u002FISO",[464,3299,3229],{},[464,3301,3243],{},[464,3303,3243],{},[446,3305,3306,3309,3312,3314,3316],{},[464,3307,3308],{},"免费档",[464,3310,3311],{},"★★★★☆ 2000\u002F月",[464,3313,3243],{},[464,3315,3229],{},[464,3317,3318],{},"完全免费（自带 API）",[446,3320,3321,3323,3326,3328,3330],{},[464,3322,2610],{},[464,3324,3325],{},"高",[464,3327,3325],{},[464,3329,3325],{},[464,3331,2380],{},[17,3333,3334,953],{},[40,3335,3336],{},"怎么选",[21,3338,3339,3345,3351,3361],{},[24,3340,3341,3344],{},[40,3342,3343],{},"公司发账号 \u002F 团队"," → GitHub Copilot Business",[24,3346,3347,3350],{},[40,3348,3349],{},"个人海外 + 想要稳定生态"," → Pro $10\u002F月",[24,3352,3353,3356,3357,3161,3359],{},[40,3354,3355],{},"追求 IDE 级 Agent 激进度"," → ",[1181,3358,3185],{"href":3184},[1181,3360,3191],{"href":3190},[24,3362,3363,3356,3366,3161,3368,3370],{},[40,3364,3365],{},"国内 \u002F 完全自主可控",[1181,3367,3160],{"href":3159},[1181,3369,3165],{"href":3164}," + 国产模型",[13,3372,1897],{"id":1897},[21,3374,3375,3386,3392,3398,3408,3418,3424,3430,3436],{},[24,3376,3377,3380,3381,3385],{},[40,3378,3379],{},"2026-04 起 Pro \u002F Pro+ \u002F Student 新签曾被暂停","：6-1 起 credit 制 GA，老用户不受影响，新签前最好去 ",[1181,3382,3384],{"href":2863,"rel":3383},[1209],"github.com\u002Ffeatures\u002Fcopilot\u002Fplans"," 确认当前是否可注册",[24,3387,3388,3391],{},[40,3389,3390],{},"Credit 制下 Premium 模型烧得快","：Opus 4.6 一次复杂 agent 任务可能耗 5-10 个 credits（社区报告，非官方明示），重度使用算账要仔细",[24,3393,3394,3397],{},[40,3395,3396],{},"Coding Agent 跑在 Actions 上","：你的 Actions minutes 会被消耗，免费仓库够用，私有仓库要注意账单",[24,3399,3400,3403,3404,3407],{},[40,3401,3402],{},"Agent Mode 默认权限要 review","：第一次跑会让你授权\"能改文件 \u002F 能跑命令\"，团队建议设置 ",[107,3405,3406],{},".github\u002Fcopilot-instructions.md"," 把规则成文",[24,3409,3410,3417],{},[40,3411,3412,3413,3416],{},"不要把 ",[107,3414,3415],{},"OPENAI_API_KEY"," 暴露","：Copilot 自带模型供给，不需要你的 API key",[24,3419,3420,3423],{},[40,3421,3422],{},"国内首次激活有\"需要海外手机\"的概率事件","：失败时换网络环境或换手机号",[24,3425,3426,3429],{},[40,3427,3428],{},"JetBrains 插件偶发崩溃","：IDE 端体验略落后 VS Code，遇到崩溃先升 plugin 版本",[24,3431,3432,3435],{},[40,3433,3434],{},"Agent Finder 不等于自动装工具","：它只负责发现和推荐，企业管理员仍应控制允许的 registry；不要把未知 MCP server 直接接进生产仓库",[24,3437,3438,3441],{},[40,3439,3440],{},"Pro+ \u002F Max 是个人订阅，不能给团队共享","：要团队就上 Business",[13,3443,1155],{"id":1154},[17,3445,3446],{},"✅ 适合：",[21,3448,3449,3452,3455,3458,3461],{},[24,3450,3451],{},"已经全员在 GitHub 的团队（开 Business 最省事）",[24,3453,3454],{},"个人海外开发者，重视生态稳定",[24,3456,3457],{},"学生 \u002F 开源维护者（薅免费 Pro）",[24,3459,3460],{},"多 IDE 切换的开发者（VS Code + JetBrains + Neovim）",[24,3462,3463],{},"需要\"issue → PR\"自动化流程",[17,3465,3466],{},"❌ 不适合：",[21,3468,3469,3479,3486,3492],{},[24,3470,3471,3472,3161,3476,2890],{},"国内首选 IDE 体验（去 ",[1181,3473,3475],{"href":3474},"\u002Fcoding\u002Fide\u002Ftrae.html","Trae",[1181,3477,3478],{"href":3184},"Cursor 国内代付",[24,3480,3481,3482,3161,3484,2890],{},"想要最激进的多文件 Agent（去 ",[1181,3483,3185],{"href":3184},[1181,3485,3191],{"href":3190},[24,3487,3488,3489,3491],{},"私有部署 \u002F 数据不出网（",[1181,3490,3165],{"href":3164}," + 自建模型）",[24,3493,3494],{},"反对一切 credit 制",[13,3496,1175],{"id":1175},[21,3498,3499,3517,3530,3549],{},[24,3500,3501,3502,3161,3504,3161,3506,3161,3508,3161,3511,3161,3513],{},"同类对比：",[1181,3503,3185],{"href":3184},[1181,3505,3191],{"href":3190},[1181,3507,3475],{"href":3474},[1181,3509,1031],{"href":3510},"\u002Fcoding\u002Fcli\u002Fclaude-code.html",[1181,3512,3160],{"href":3159},[1181,3514,3516],{"href":3515},"\u002Fcoding\u002Fcli\u002Fcodex.html","Codex CLI",[24,3518,3519,3520,3161,3524,3161,3526],{},"概念：",[1181,3521,3523],{"href":3522},"\u002Fwiki\u002Fai-agent.html","AI Agent",[1181,3525,2595],{"href":2594},[1181,3527,3529],{"href":3528},"\u002Fwiki\u002Ffunction-calling.html","Function Calling",[24,3531,3532,3533,3161,3537,3161,3541,3161,3545],{},"模型：",[1181,3534,3536],{"href":3535},"\u002Fmodels\u002Fgpt-5.html","GPT-5",[1181,3538,3540],{"href":3539},"\u002Fmodels\u002Fclaude-sonnet-4.html","Claude Sonnet 4",[1181,3542,3544],{"href":3543},"\u002Fmodels\u002Fclaude-opus-4.html","Claude Opus 4",[1181,3546,3548],{"href":3547},"\u002Fmodels\u002Fgemini-2.5-pro.html","Gemini 2.5 Pro",[24,3550,3551,3552,3161,3556],{},"进阶：",[1181,3553,3555],{"href":3554},"\u002Fwiki\u002Fvibe-coding.html","Vibe Coding",[1181,3557,3559],{"href":3558},"\u002Fwiki\u002Fprompt-engineering.html","Prompt Engineering",[13,3561,1199],{"id":1199},[21,3563,3564,3571,3577,3584,3587],{},[24,3565,3566,3567],{},"官网：",[1181,3568,3569],{"href":3569,"rel":3570},"https:\u002F\u002Fgithub.com\u002Ffeatures\u002Fcopilot",[1209],[24,3572,3573,3574],{},"定价：",[1181,3575,2863],{"href":2863,"rel":3576},[1209],[24,3578,3579,3580],{},"企业文档：",[1181,3581,3582],{"href":3582,"rel":3583},"https:\u002F\u002Fdocs.github.com\u002Fen\u002Fenterprise-cloud@latest\u002Fcopilot\u002Fget-started\u002Fplans",[1209],[24,3585,3586],{},"公告：github.blog",[24,3588,3589],{},"第三方评测：augmentcode.com \u002F tossitt.com \u002F 4geeks.com",[17,3591,3592,3593,3596],{},"本卡片由 AIHO 编辑部根据官方公开资料与第三方评测整理。所有事实点均标注来源；如发现价格 \u002F 模型 \u002F 功能与最新官方信息不一致，请通过 ",[1181,3594,3595],{"href":3595},"\u002Fsubmit"," 反馈。",[700,3598,3599],{},"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 .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 .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}",{"title":105,"searchDepth":127,"depth":127,"links":3601},[3602,3603,3611,3612,3613,3614,3615,3616,3617,3618],{"id":753,"depth":120,"text":754},{"id":2619,"depth":120,"text":2619,"children":3604},[3605,3606,3607,3608,3609,3610],{"id":2622,"depth":127,"text":2623},{"id":2676,"depth":127,"text":2677},{"id":2714,"depth":127,"text":2715},{"id":2747,"depth":127,"text":2748},{"id":2826,"depth":127,"text":2827},{"id":2857,"depth":127,"text":2858},{"id":2893,"depth":120,"text":2893},{"id":3012,"depth":120,"text":3013},{"id":3126,"depth":120,"text":3126},{"id":3169,"depth":120,"text":3169},{"id":1897,"depth":120,"text":1897},{"id":1154,"depth":120,"text":1155},{"id":1175,"depth":120,"text":1175},{"id":1199,"depth":120,"text":1199},"\u002Fimg\u002Ftools\u002Fgithub-copilot.webp","GitHub Copilot 真实评测：微软+OpenAI 出品的 IDE 插件鼻祖，覆盖 VS Code \u002F JetBrains \u002F Neovim \u002F Visual Studio。Copilot Chat、Agent Mode、Coding Agent、Copilot CLI 新终端界面、Agent Finder 多模型资源发现一应俱全。AIHO 编辑部基于官方文档与多份评测整理。",[2532,1261],{},[3624,3625,3626,3627,3628],"claude-opus-4.6","claude-sonnet-4.6","gpt-5","gemini-2.5-pro","haiku-4.5",[3630,3631,3632],"完全无网络代理的国内开发者","追求最激进的多文件 Agent（去 Cursor \u002F Windsurf）","想私有部署 \u002F 数据不出网（去 Continue.dev）","\u002Ftools\u002Fcoding\u002Fcopilot\u002Fgithub-copilot",[3635,3636,3637],"windows","macos","linux",[3639,3642,3646,3649,3651,3655],{"plan":902,"price":905,"limit":3640,"cn_pay":1278,"note":3641},"2,000 completions\u002F月 + Haiku\u002FGPT-5 mini + Copilot CLI","学生免费升级 Pro",{"plan":913,"price":2935,"limit":3643,"cn_pay":3644,"note":3645},"无限补全 + Cloud agent + Code review + $15 credits","⚠️ 需海外卡 \u002F Apple 礼品卡","个人主力档",{"plan":2943,"price":1064,"limit":3647,"cn_pay":3648,"note":930},"Pro + Opus 等 premium 模型 + 4x credits ($70)","⚠️",{"plan":924,"price":2955,"limit":2958,"cn_pay":3648,"note":3650},"高并发 agent",{"plan":2963,"price":2966,"limit":3652,"cn_pay":3653,"note":3654},"组织管理 + 策略控制 + 代码库索引","✅ 企业发票","团队首选",{"plan":866,"price":2976,"limit":3656,"cn_pay":1771,"note":3657},"Business + 优先模型 + 更大 AI credits","大企业","Free \u002F Pro $10\u002Fmo \u002F Pro+ $39\u002Fmo \u002F Max $100\u002Fmo \u002F Business $19 seat \u002F Enterprise $39 seat",{"power":134,"ux":140,"price":134,"cn_support":127,"stability":140},{"title":2573,"description":3620},[3662,3664,3666,3668,3670,3673,3676,3678,3681],{"title":3663,"url":3569},"GitHub Copilot 官方",{"title":3665,"url":2863},"Copilot Plans & Pricing",{"title":3667,"url":3582},"Copilot Enterprise Docs",{"title":3669,"url":2682},"Agent Mode GA Blog",{"title":3671,"url":3672},"MCP Support Public Preview","https:\u002F\u002Fgithub.blog\u002Fchangelog\u002F2025\u002F04\u002F04\u002Fgithub-copilot-now-supports-mcp-servers-in-public-preview-in-vs-code\u002F",{"title":3674,"url":3675},"Copilot vs Intent 2026 评测","https:\u002F\u002Fwww.augmentcode.com\u002Ftools\u002Fintent-vs-github-copilot",{"title":3677,"url":2887},"Copilot 2026 完整指南",{"title":3679,"url":3680},"Copilot CLI 新终端界面 GA","https:\u002F\u002Fgithub.blog\u002Fchangelog\u002F2026-06-23-copilot-cli-new-terminal-interface-is-generally-available\u002F",{"title":3682,"url":3683},"Agent Finder for GitHub Copilot","https:\u002F\u002Fgithub.blog\u002Fchangelog\u002F2026-06-17-agent-finder-for-github-copilot-now-available\u002F","tools\u002Fcoding\u002Fcopilot\u002Fgithub-copilot",[3686,3687,3688,3689,3690],"已经在用 GitHub 的所有人（最低成本）","团队 \u002F 企业（合规、SOC2、ISO 27001）","JetBrains 用户 \u002F Neovim \u002F Visual Studio \u002F Xcode","学生 \u002F 开源维护者（免费 Pro 资格）","需要 Coding Agent 自动从 issue 生成 PR","AI Copilot 鼻祖，VS Code \u002F JetBrains \u002F Neovim 全家桶覆盖",[2815,3693,3694,2058,3695,3696],"vscode","jetbrains","agent-mode","coding-agent","插件生态最稳的选择，免费档大方，国内用稳定代理 + GitHub 账号即可。Agent Mode 已经能跟 Cursor 掰手腕，Coding Agent 能直接在 GitHub 上跑后台 PR。","jtnG539AZV3xKfaMgXyVo9ktxOawbNsCriRbbiZcvrk",[3700,4192,4868,5746,6845,7550,8274,9253,10795,11415,11917,12548],{"id":7,"title":8,"body":3701,"category":717,"cover":718,"description":719,"extension":104,"meta":4188,"navigation":130,"path":721,"published":722,"relatedTools":4189,"seo":4190,"stem":729,"tags":4191,"updated":722,"__hash__":733},{"type":10,"value":3702,"toc":4174},[3703,3705,3707,3717,3721,3723,3725,3739,3741,3753,3755,3757,3759,3873,3875,3877,3882,3886,3888,3970,3972,3974,3976,3988,3990,3992,4038,4040,4042,4060,4062,4064,4066,4098,4100,4102,4138,4140,4142,4168,4170,4172],[13,3704,15],{"id":15},[17,3706,19],{},[21,3708,3709,3711,3713,3715],{},[24,3710,26],{},[24,3712,29],{},[24,3714,32],{},[24,3716,35],{},[17,3718,38,3719,43],{},[40,3720,42],{},[13,3722,46],{"id":46},[17,3724,49],{},[21,3726,3727,3729,3731,3733,3735,3737],{},[24,3728,54],{},[24,3730,57],{},[24,3732,60],{},[24,3734,63],{},[24,3736,66],{},[24,3738,69],{},[17,3740,72],{},[21,3742,3743,3745,3747,3749,3751],{},[24,3744,77],{},[24,3746,80],{},[24,3748,83],{},[24,3750,86],{},[24,3752,89],{},[17,3754,92],{},[13,3756,95],{"id":95},[17,3758,98],{},[100,3760,3761],{"className":102,"code":103,"language":104,"meta":105,"style":105},[107,3762,3763,3767,3771,3775,3779,3785,3791,3795,3799,3805,3811,3817,3823,3827,3831,3835,3839,3843,3849,3855,3861,3865,3869],{"__ignoreMap":105},[110,3764,3765],{"class":112,"line":113},[110,3766,117],{"class":116},[110,3768,3769],{"class":112,"line":120},[110,3770,124],{"class":123},[110,3772,3773],{"class":112,"line":127},[110,3774,131],{"emptyLinePlaceholder":130},[110,3776,3777],{"class":112,"line":134},[110,3778,137],{"class":116},[110,3780,3781,3783],{"class":112,"line":140},[110,3782,144],{"class":143},[110,3784,147],{"class":123},[110,3786,3787,3789],{"class":112,"line":150},[110,3788,144],{"class":143},[110,3790,155],{"class":123},[110,3792,3793],{"class":112,"line":5},[110,3794,131],{"emptyLinePlaceholder":130},[110,3796,3797],{"class":112,"line":162},[110,3798,165],{"class":116},[110,3800,3801,3803],{"class":112,"line":168},[110,3802,171],{"class":143},[110,3804,174],{"class":123},[110,3806,3807,3809],{"class":112,"line":177},[110,3808,180],{"class":143},[110,3810,183],{"class":123},[110,3812,3813,3815],{"class":112,"line":186},[110,3814,189],{"class":143},[110,3816,192],{"class":123},[110,3818,3819,3821],{"class":112,"line":195},[110,3820,198],{"class":143},[110,3822,201],{"class":123},[110,3824,3825],{"class":112,"line":204},[110,3826,131],{"emptyLinePlaceholder":130},[110,3828,3829],{"class":112,"line":209},[110,3830,212],{"class":116},[110,3832,3833],{"class":112,"line":215},[110,3834,218],{"class":123},[110,3836,3837],{"class":112,"line":221},[110,3838,131],{"emptyLinePlaceholder":130},[110,3840,3841],{"class":112,"line":226},[110,3842,229],{"class":116},[110,3844,3845,3847],{"class":112,"line":232},[110,3846,144],{"class":143},[110,3848,237],{"class":123},[110,3850,3851,3853],{"class":112,"line":240},[110,3852,144],{"class":143},[110,3854,245],{"class":123},[110,3856,3857,3859],{"class":112,"line":248},[110,3858,144],{"class":143},[110,3860,253],{"class":123},[110,3862,3863],{"class":112,"line":256},[110,3864,131],{"emptyLinePlaceholder":130},[110,3866,3867],{"class":112,"line":261},[110,3868,264],{"class":116},[110,3870,3871],{"class":112,"line":267},[110,3872,270],{"class":123},[17,3874,273],{},[13,3876,276],{"id":276},[100,3878,3880],{"className":3879,"code":281,"language":282,"meta":105},[280],[107,3881,281],{"__ignoreMap":105},[17,3883,287,3884,291],{},[40,3885,290],{},[13,3887,295],{"id":294},[100,3889,3890],{"className":298,"code":299,"language":300,"meta":105,"style":105},[107,3891,3892,3902,3908,3912,3916,3932,3936,3940,3950,3954,3958],{"__ignoreMap":105},[110,3893,3894,3896,3898,3900],{"class":112,"line":113},[110,3895,308],{"class":307},[110,3897,312],{"class":311},[110,3899,316],{"class":315},[110,3901,319],{"class":311},[110,3903,3904,3906],{"class":112,"line":120},[110,3905,324],{"class":307},[110,3907,327],{"class":311},[110,3909,3910],{"class":112,"line":127},[110,3911,131],{"emptyLinePlaceholder":130},[110,3913,3914],{"class":112,"line":134},[110,3915,337],{"class":336},[110,3917,3918,3920,3922,3924,3926,3928,3930],{"class":112,"line":140},[110,3919,324],{"class":307},[110,3921,344],{"class":311},[110,3923,347],{"class":311},[110,3925,350],{"class":315},[110,3927,353],{"class":311},[110,3929,356],{"class":315},[110,3931,359],{"class":311},[110,3933,3934],{"class":112,"line":150},[110,3935,131],{"emptyLinePlaceholder":130},[110,3937,3938],{"class":112,"line":5},[110,3939,368],{"class":336},[110,3941,3942,3944,3946,3948],{"class":112,"line":162},[110,3943,324],{"class":307},[110,3945,344],{"class":311},[110,3947,377],{"class":311},[110,3949,380],{"class":315},[110,3951,3952],{"class":112,"line":168},[110,3953,131],{"emptyLinePlaceholder":130},[110,3955,3956],{"class":112,"line":177},[110,3957,389],{"class":336},[110,3959,3960,3962,3964,3966,3968],{"class":112,"line":186},[110,3961,324],{"class":307},[110,3963,344],{"class":311},[110,3965,398],{"class":311},[110,3967,356],{"class":315},[110,3969,403],{"class":315},[17,3971,406],{},[13,3973,410],{"id":409},[17,3975,413],{},[415,3977,3978,3980,3982,3984,3986],{},[24,3979,419],{},[24,3981,422],{},[24,3983,425],{},[24,3985,428],{},[24,3987,431],{},[17,3989,434],{},[13,3991,438],{"id":437},[440,3993,3994,4004],{},[443,3995,3996],{},[446,3997,3998,4000,4002],{},[449,3999,451],{},[449,4001,454],{},[449,4003,457],{},[459,4005,4006,4014,4022,4030],{},[446,4007,4008,4010,4012],{},[464,4009,29],{},[464,4011,468],{},[464,4013,471],{},[446,4015,4016,4018,4020],{},[464,4017,476],{},[464,4019,479],{},[464,4021,482],{},[446,4023,4024,4026,4028],{},[464,4025,487],{},[464,4027,490],{},[464,4029,493],{},[446,4031,4032,4034,4036],{},[464,4033,498],{},[464,4035,501],{},[464,4037,504],{},[13,4039,508],{"id":507},[17,4041,511],{},[21,4043,4044,4046,4048,4050,4052,4054,4056,4058],{},[24,4045,516],{},[24,4047,519],{},[24,4049,522],{},[24,4051,525],{},[24,4053,528],{},[24,4055,531],{},[24,4057,534],{},[24,4059,537],{},[17,4061,540],{},[13,4063,543],{"id":543},[17,4065,546],{},[415,4067,4068,4072,4076,4080,4084,4088],{},[24,4069,4070,554],{},[40,4071,553],{},[24,4073,4074,560],{},[40,4075,559],{},[24,4077,4078,566],{},[40,4079,565],{},[24,4081,4082,572],{},[40,4083,571],{},[24,4085,4086,578],{},[40,4087,577],{},[24,4089,4090,584,4092,588,4094,588,4096,595],{},[40,4091,583],{},[107,4093,587],{},[107,4095,591],{},[107,4097,594],{},[13,4099,599],{"id":598},[17,4101,602],{},[440,4103,4104,4112],{},[443,4105,4106],{},[446,4107,4108,4110],{},[449,4109,611],{},[449,4111,614],{},[459,4113,4114,4120,4126,4132],{},[446,4115,4116,4118],{},[464,4117,621],{},[464,4119,624],{},[446,4121,4122,4124],{},[464,4123,629],{},[464,4125,632],{},[446,4127,4128,4130],{},[464,4129,637],{},[464,4131,640],{},[446,4133,4134,4136],{},[464,4135,645],{},[464,4137,648],{},[17,4139,651],{},[13,4141,654],{"id":654},[415,4143,4144,4148,4152,4156,4160,4164],{},[24,4145,4146,662],{},[40,4147,661],{},[24,4149,4150,668],{},[40,4151,667],{},[24,4153,4154,674],{},[40,4155,673],{},[24,4157,4158,680],{},[40,4159,679],{},[24,4161,4162,686],{},[40,4163,685],{},[24,4165,4166,692],{},[40,4167,691],{},[13,4169,695],{"id":695},[17,4171,698],{},[700,4173,702],{},{"title":105,"searchDepth":127,"depth":127,"links":4175},[4176,4177,4178,4179,4180,4181,4182,4183,4184,4185,4186,4187],{"id":15,"depth":120,"text":15},{"id":46,"depth":120,"text":46},{"id":95,"depth":120,"text":95},{"id":276,"depth":120,"text":276},{"id":294,"depth":120,"text":295},{"id":409,"depth":120,"text":410},{"id":437,"depth":120,"text":438},{"id":507,"depth":120,"text":508},{"id":543,"depth":120,"text":543},{"id":598,"depth":120,"text":599},{"id":654,"depth":120,"text":654},{"id":695,"depth":120,"text":695},{},[724,725,726,727],{"title":8,"description":719},[731,487,29,498,732],{"id":4193,"title":4194,"body":4195,"category":717,"cover":4856,"description":4857,"extension":104,"meta":4858,"navigation":130,"path":4859,"published":722,"relatedTools":4860,"seo":4863,"stem":4864,"tags":4865,"updated":722,"__hash__":4867},"playbook\u002Fplaybook\u002Fonboarding\u002Fterminal-agent-stack-2026.md","2026 终端 AI Agent 怎么选：Claude Code \u002F Codex \u002F Gemini CLI \u002F Aider 工作流",{"type":10,"value":4196,"toc":4840},[4197,4199,4202,4216,4219,4315,4320,4326,4330,4333,4395,4398,4528,4531,4535,4539,4542,4557,4560,4564,4567,4573,4576,4580,4583,4589,4592,4596,4599,4643,4646,4650,4653,4673,4676,4690,4694,4697,4703,4706,4710,4716,4719,4775,4778,4781,4823,4825,4828,4834,4837],[13,4198,15],{"id":15},[17,4200,4201],{},"这篇不是「哪个 Agent 最强」的排行榜，而是一套现实可用的终端 AI Agent 工作流。适合：",[21,4203,4204,4207,4210,4213],{},[24,4205,4206],{},"已经会用 Cursor \u002F Copilot，但想把 AI 编程搬到终端的人",[24,4208,4209],{},"需要在服务器、SSH、容器、Windows 原生环境里跑 Agent 的开发者",[24,4211,4212],{},"团队想把 AI Agent 接入 repo 规范、MCP 工具、测试闭环",[24,4214,4215],{},"预算有限，想混用免费额度、订阅额度和 BYOK 模型的人",[13,4217,4218],{"id":4218},"结论先行",[440,4220,4221,4237],{},[443,4222,4223],{},[446,4224,4225,4228,4231,4234],{},[449,4226,4227],{},"任务",[449,4229,4230],{},"首选",[449,4232,4233],{},"备选",[449,4235,4236],{},"原因",[459,4238,4239,4251,4263,4276,4289,4302],{},[446,4240,4241,4244,4246,4248],{},[464,4242,4243],{},"长时间重构 \u002F 多文件改造",[464,4245,1031],{},[464,4247,3516],{},[464,4249,4250],{},"长任务规划和上下文连续性强",[446,4252,4253,4256,4258,4260],{},[464,4254,4255],{},"已订阅 ChatGPT Plus\u002FPro",[464,4257,3516],{},[464,4259,1031],{},[464,4261,4262],{},"额度打包，Windows 原生体验好",[446,4264,4265,4268,4271,4273],{},[464,4266,4267],{},"大仓库阅读 \u002F 查新资料",[464,4269,4270],{},"Gemini CLI",[464,4272,2299],{},[464,4274,4275],{},"1M 上下文 + Google Search grounding",[446,4277,4278,4281,4283,4286],{},[464,4279,4280],{},"接国产模型 \u002F 私有 endpoint",[464,4282,2299],{},[464,4284,4285],{},"Cline \u002F Continue",[464,4287,4288],{},"OpenAI-compatible endpoint 最灵活",[446,4290,4291,4294,4296,4299],{},[464,4292,4293],{},"低成本 issue triage",[464,4295,4270],{},[464,4297,4298],{},"Codex mini",[464,4300,4301],{},"免费额度大，headless 脚本友好",[446,4303,4304,4307,4310,4312],{},[464,4305,4306],{},"生产仓库改代码",[464,4308,4309],{},"Claude Code \u002F Codex",[464,4311,2299],{},[464,4313,4314],{},"沙箱、权限、工具链更完整",[17,4316,4317],{},[40,4318,4319],{},"AIHO 推荐默认组合：",[100,4321,4324],{"className":4322,"code":4323,"language":282,"meta":105},[280],"Claude Code \u002F Codex CLI：主力改代码\nGemini CLI：查新资料 + 大上下文阅读 + 第二意见\nAider：接国内模型 \u002F 私有模型 \u002F 成本兜底\nMCP：统一接 GitHub、数据库、内部工具\n",[107,4325,4323],{"__ignoreMap":105},[13,4327,4329],{"id":4328},"第一步先给项目写-agent-记忆","第一步：先给项目写 Agent 记忆",[17,4331,4332],{},"不同工具的项目记忆文件不同，但内容应该一致：",[440,4334,4335,4344],{},[443,4336,4337],{},[446,4338,4339,4341],{},[449,4340,451],{},[449,4342,4343],{},"项目记忆文件",[459,4345,4346,4355,4364,4375,4385],{},[446,4347,4348,4350],{},[464,4349,1031],{},[464,4351,4352],{},[107,4353,4354],{},"CLAUDE.md",[446,4356,4357,4359],{},[464,4358,4270],{},[464,4360,4361],{},[107,4362,4363],{},"GEMINI.md",[446,4365,4366,4368],{},[464,4367,2573],{},[464,4369,4370,3161,4373],{},[107,4371,4372],{},"AGENTS.md",[107,4374,3406],{},[446,4376,4377,4379],{},[464,4378,3516],{},[464,4380,4381,4384],{},[107,4382,4383],{},".codex\u002F"," \u002F team config",[446,4386,4387,4389],{},[464,4388,3185],{},[464,4390,4391,4394],{},[107,4392,4393],{},".cursorrules"," \u002F project rules",[17,4396,4397],{},"建议模板：",[100,4399,4401],{"className":102,"code":4400,"language":104,"meta":105,"style":105},"# Project Guide for AI Agents\n\n## Tech stack\n- Nuxt 4 + Vue 3 + TypeScript\n- pnpm workspace\n- @nuxt\u002Fcontent for markdown content\n\n## Commands\n- Install: pnpm install\n- Typecheck: pnpm run typecheck\n- Build: pnpm run build\n\n## Conventions\n- Do not commit automatically.\n- Keep frontmatter schema consistent with content.config.ts.\n- Before changing many files, explain the plan first.\n- After editing, run the smallest relevant verification command.\n\n## Pitfalls\n- Do not run build while dev server is running on Windows.\n- Do not edit generated .output or .nuxt files.\n",[107,4402,4403,4408,4412,4417,4424,4431,4438,4442,4447,4454,4461,4468,4472,4477,4484,4491,4498,4505,4509,4514,4521],{"__ignoreMap":105},[110,4404,4405],{"class":112,"line":113},[110,4406,4407],{"class":116},"# Project Guide for AI Agents\n",[110,4409,4410],{"class":112,"line":120},[110,4411,131],{"emptyLinePlaceholder":130},[110,4413,4414],{"class":112,"line":127},[110,4415,4416],{"class":116},"## Tech stack\n",[110,4418,4419,4421],{"class":112,"line":134},[110,4420,144],{"class":143},[110,4422,4423],{"class":123}," Nuxt 4 + Vue 3 + TypeScript\n",[110,4425,4426,4428],{"class":112,"line":140},[110,4427,144],{"class":143},[110,4429,4430],{"class":123}," pnpm workspace\n",[110,4432,4433,4435],{"class":112,"line":150},[110,4434,144],{"class":143},[110,4436,4437],{"class":123}," @nuxt\u002Fcontent for markdown content\n",[110,4439,4440],{"class":112,"line":5},[110,4441,131],{"emptyLinePlaceholder":130},[110,4443,4444],{"class":112,"line":162},[110,4445,4446],{"class":116},"## Commands\n",[110,4448,4449,4451],{"class":112,"line":168},[110,4450,144],{"class":143},[110,4452,4453],{"class":123}," Install: pnpm install\n",[110,4455,4456,4458],{"class":112,"line":177},[110,4457,144],{"class":143},[110,4459,4460],{"class":123}," Typecheck: pnpm run typecheck\n",[110,4462,4463,4465],{"class":112,"line":186},[110,4464,144],{"class":143},[110,4466,4467],{"class":123}," Build: pnpm run build\n",[110,4469,4470],{"class":112,"line":195},[110,4471,131],{"emptyLinePlaceholder":130},[110,4473,4474],{"class":112,"line":204},[110,4475,4476],{"class":116},"## Conventions\n",[110,4478,4479,4481],{"class":112,"line":209},[110,4480,144],{"class":143},[110,4482,4483],{"class":123}," Do not commit automatically.\n",[110,4485,4486,4488],{"class":112,"line":215},[110,4487,144],{"class":143},[110,4489,4490],{"class":123}," Keep frontmatter schema consistent with content.config.ts.\n",[110,4492,4493,4495],{"class":112,"line":221},[110,4494,144],{"class":143},[110,4496,4497],{"class":123}," Before changing many files, explain the plan first.\n",[110,4499,4500,4502],{"class":112,"line":226},[110,4501,144],{"class":143},[110,4503,4504],{"class":123}," After editing, run the smallest relevant verification command.\n",[110,4506,4507],{"class":112,"line":232},[110,4508,131],{"emptyLinePlaceholder":130},[110,4510,4511],{"class":112,"line":240},[110,4512,4513],{"class":116},"## Pitfalls\n",[110,4515,4516,4518],{"class":112,"line":248},[110,4517,144],{"class":143},[110,4519,4520],{"class":123}," Do not run build while dev server is running on Windows.\n",[110,4522,4523,4525],{"class":112,"line":256},[110,4524,144],{"class":143},[110,4526,4527],{"class":123}," Do not edit generated .output or .nuxt files.\n",[17,4529,4530],{},"别把临时需求写进这些文件。项目记忆应该只放稳定事实：技术栈、命令、目录约定、不可踩的坑。",[13,4532,4534],{"id":4533},"第二步按风险分级使用-agent","第二步：按风险分级使用 Agent",[1834,4536,4538],{"id":4537},"level-1只读分析","Level 1：只读分析",[17,4540,4541],{},"适合 Gemini CLI \u002F Aider \u002F 任意模型：",[100,4543,4545],{"className":298,"code":4544,"language":300,"meta":105,"style":105},"gemini -p \"读 README、package.json 和 src 目录，解释这个项目架构，不要改文件\"\n",[107,4546,4547],{"__ignoreMap":105},[110,4548,4549,4551,4554],{"class":112,"line":113},[110,4550,2056],{"class":307},[110,4552,4553],{"class":315}," -p",[110,4555,4556],{"class":311}," \"读 README、package.json 和 src 目录，解释这个项目架构，不要改文件\"\n",[17,4558,4559],{},"用于：接手新项目、审计依赖、理解错误日志、生成迁移计划。",[1834,4561,4563],{"id":4562},"level-2小范围修改","Level 2：小范围修改",[17,4565,4566],{},"适合 Claude Code \u002F Codex CLI：",[100,4568,4571],{"className":4569,"code":4570,"language":282,"meta":105},[280],"只修改 src\u002Fauth 目录，修复 refresh token 过期判断。先列计划，我确认后再动手。改完跑 pnpm test auth。\n",[107,4572,4570],{"__ignoreMap":105},[17,4574,4575],{},"关键是限制范围、写清验收命令。",[1834,4577,4579],{"id":4578},"level-3多文件重构","Level 3：多文件重构",[17,4581,4582],{},"只建议用 Claude Code \u002F Codex CLI，且必须分阶段：",[100,4584,4587],{"className":4585,"code":4586,"language":282,"meta":105},[280],"目标：把旧的 REST client 迁移到 typed SDK。\n阶段 1：只做调用点清单，不改代码。\n阶段 2：先迁移一个模块，跑测试。\n阶段 3：确认模式后批量迁移。\n",[107,4588,4586],{"__ignoreMap":105},[17,4590,4591],{},"不要一上来就说「帮我重构整个项目」。Agent 会为了完成任务而扩大改动面。",[1834,4593,4595],{"id":4594},"level-4自动化-ci","Level 4：自动化 \u002F CI",[17,4597,4598],{},"用 headless 模式：",[100,4600,4602],{"className":298,"code":4601,"language":300,"meta":105,"style":105},"gemini -p \"根据这些 issue 标题，按复杂度和风险排序，输出 JSON\" --output-format json\ncodex exec \"review this diff for security issues\"\naider --yes --message \"fix lint errors in changed files only\"\n",[107,4603,4604,4619,4630],{"__ignoreMap":105},[110,4605,4606,4608,4610,4613,4616],{"class":112,"line":113},[110,4607,2056],{"class":307},[110,4609,4553],{"class":315},[110,4611,4612],{"class":311}," \"根据这些 issue 标题，按复杂度和风险排序，输出 JSON\"",[110,4614,4615],{"class":315}," --output-format",[110,4617,4618],{"class":311}," json\n",[110,4620,4621,4624,4627],{"class":112,"line":120},[110,4622,4623],{"class":307},"codex",[110,4625,4626],{"class":311}," exec",[110,4628,4629],{"class":311}," \"review this diff for security issues\"\n",[110,4631,4632,4634,4637,4640],{"class":112,"line":127},[110,4633,2067],{"class":307},[110,4635,4636],{"class":315}," --yes",[110,4638,4639],{"class":315}," --message",[110,4641,4642],{"class":311}," \"fix lint errors in changed files only\"\n",[17,4644,4645],{},"CI 中要注意：只读审查可以自动跑；自动改代码应该进入 PR，不要直接 push 到 main。",[13,4647,4649],{"id":4648},"第三步mcp-只接必要工具","第三步：MCP 只接必要工具",[17,4651,4652],{},"MCP 很强，但也最容易失控。推荐从低风险工具开始：",[415,4654,4655,4658,4661,4664,4667,4670],{},[24,4656,4657],{},"Filesystem（限定目录）",[24,4659,4660],{},"GitHub（限定 repo 权限）",[24,4662,4663],{},"Search \u002F docs",[24,4665,4666],{},"Database read-only",[24,4668,4669],{},"Slack \u002F Linear \u002F Jira",[24,4671,4672],{},"Production write tools（最后再考虑）",[17,4674,4675],{},"原则：",[21,4677,4678,4681,4684,4687],{},[24,4679,4680],{},"能只读就不要给写权限。",[24,4682,4683],{},"能限定 repo \u002F schema \u002F directory 就不要给全局权限。",[24,4685,4686],{},"第三方 MCP server 先看源码和权限，再接入团队环境。",[24,4688,4689],{},"生产数据库必须 read-only replica，不能让 Agent 直连主库写入。",[13,4691,4693],{"id":4692},"第四步每次任务都要有验证闭环","第四步：每次任务都要有验证闭环",[17,4695,4696],{},"好 prompt 不是「请帮我修好」，而是包含验证命令：",[100,4698,4701],{"className":4699,"code":4700,"language":282,"meta":105},[280],"修复这个 bug。限制：不要改 public API。完成后运行：\n1. pnpm run typecheck\n2. pnpm test auth\n3. pnpm run build\n如果任一失败，继续修到通过；如果是环境问题，说明具体报错。\n",[107,4702,4700],{"__ignoreMap":105},[17,4704,4705],{},"Agent 质量差距的一半来自模型，另一半来自你有没有给它可执行的验收标准。",[13,4707,4709],{"id":4708},"推荐工作流双-agent-交叉检查","推荐工作流：双 Agent 交叉检查",[100,4711,4714],{"className":4712,"code":4713,"language":282,"meta":105},[280],"Claude Code \u002F Codex CLI 负责改代码\nGemini CLI 负责读 diff + 查新资料 + 第二意见\n人工负责最终 review 和 merge\n",[107,4715,4713],{"__ignoreMap":105},[17,4717,4718],{},"示例：",[100,4720,4722],{"className":298,"code":4721,"language":300,"meta":105,"style":105},"# 1. 主 Agent 改代码后生成 diff\ngit diff > \u002Ftmp\u002Fchange.diff\n\n# 2. 第二 Agent 审查\ngemini -p \"Review this diff for hidden risk and missing tests:\\n$(cat \u002Ftmp\u002Fchange.diff)\"\n\n# 3. 人看两个结果再决定是否合并\n",[107,4723,4724,4729,4743,4747,4752,4766,4770],{"__ignoreMap":105},[110,4725,4726],{"class":112,"line":113},[110,4727,4728],{"class":336},"# 1. 主 Agent 改代码后生成 diff\n",[110,4730,4731,4734,4737,4740],{"class":112,"line":120},[110,4732,4733],{"class":307},"git",[110,4735,4736],{"class":311}," diff",[110,4738,4739],{"class":1577}," >",[110,4741,4742],{"class":311}," \u002Ftmp\u002Fchange.diff\n",[110,4744,4745],{"class":112,"line":127},[110,4746,131],{"emptyLinePlaceholder":130},[110,4748,4749],{"class":112,"line":134},[110,4750,4751],{"class":336},"# 2. 第二 Agent 审查\n",[110,4753,4754,4756,4758,4761,4763],{"class":112,"line":140},[110,4755,2056],{"class":307},[110,4757,4553],{"class":315},[110,4759,4760],{"class":311}," \"Review this diff for hidden risk and missing tests:\\n$(",[110,4762,1571],{"class":307},[110,4764,4765],{"class":311}," \u002Ftmp\u002Fchange.diff)\"\n",[110,4767,4768],{"class":112,"line":150},[110,4769,131],{"emptyLinePlaceholder":130},[110,4771,4772],{"class":112,"line":5},[110,4773,4774],{"class":336},"# 3. 人看两个结果再决定是否合并\n",[17,4776,4777],{},"这种「一个写、一个审」比让同一个 Agent 自夸自审更可靠。",[13,4779,4780],{"id":4780},"常见踩坑",[415,4782,4783,4789,4795,4801,4807,4817],{},[24,4784,4785,4788],{},[40,4786,4787],{},"不给边界","：让 Agent 改「整个项目」，它就真的会碰一堆文件。",[24,4790,4791,4794],{},[40,4792,4793],{},"不给验证命令","：Agent 会用自然语言说完成，但没跑过测试。",[24,4796,4797,4800],{},[40,4798,4799],{},"项目记忆太长","：几千行规则会稀释重点，保留最关键 20 条。",[24,4802,4803,4806],{},[40,4804,4805],{},"MCP 权限过大","：一开始就接生产数据库、Slack 写权限、GitHub admin token。",[24,4808,4809,4812,4813,4816],{},[40,4810,4811],{},"长会话不清理","：任务切换时 ",[107,4814,4815],{},"\u002Fclear"," 或新开会话，避免旧上下文污染。",[24,4818,4819,4822],{},[40,4820,4821],{},"把 Agent 当 CI","：CI 是确定性验证，Agent 是概率性执行，两者不能互相替代。",[13,4824,695],{"id":695},[17,4826,4827],{},"2026 年终端 Agent 的正确姿势不是押注一个工具，而是建立一套可验证的流水线：",[100,4829,4832],{"className":4830,"code":4831,"language":282,"meta":105},[280],"项目记忆 → 小任务边界 → MCP 最小权限 → 自动验证 → 第二 Agent 审查 → 人工 merge\n",[107,4833,4831],{"__ignoreMap":105},[17,4835,4836],{},"工具会换，但这套工作流不会过时。",[700,4838,4839],{},"html pre.shiki code .sq-ep, html code.shiki .sq-ep{--shiki-default:#005CC5;--shiki-default-font-weight:bold;--shiki-dark:#79B8FF;--shiki-dark-font-weight:bold}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}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 .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}",{"title":105,"searchDepth":127,"depth":127,"links":4841},[4842,4843,4844,4845,4851,4852,4853,4854,4855],{"id":15,"depth":120,"text":15},{"id":4218,"depth":120,"text":4218},{"id":4328,"depth":120,"text":4329},{"id":4533,"depth":120,"text":4534,"children":4846},[4847,4848,4849,4850],{"id":4537,"depth":127,"text":4538},{"id":4562,"depth":127,"text":4563},{"id":4578,"depth":127,"text":4579},{"id":4594,"depth":127,"text":4595},{"id":4648,"depth":120,"text":4649},{"id":4692,"depth":120,"text":4693},{"id":4708,"depth":120,"text":4709},{"id":4780,"depth":120,"text":4780},{"id":695,"depth":120,"text":695},"\u002Fog\u002Fplaybook\u002Fterminal-agent-stack-2026.png","一套面向 2026 年的终端 AI Agent 选型与落地指南：Claude Code、Codex CLI、Gemini CLI、Aider 各自适合什么任务，如何配置项目记忆、MCP、权限与验证闭环。",{},"\u002Fplaybook\u002Fonboarding\u002Fterminal-agent-stack-2026",[1313,4861,1314,4862],"coding\u002Fcli\u002Fcodex","coding\u002Fcli\u002Faider",{"title":4194,"description":4857},"playbook\u002Fonboarding\u002Fterminal-agent-stack-2026",[4866,1031,3516,4270,2299,2595],"CLI Agent","G9emZG5RHrZptWZrdwHuEDlxgV3g1Re9AgNyx5umrZA",{"id":4869,"title":4870,"body":4871,"category":5729,"cover":5730,"description":5731,"extension":104,"meta":5732,"navigation":130,"path":5733,"published":5734,"relatedTools":5735,"seo":5738,"stem":5739,"tags":5740,"updated":5734,"__hash__":5745},"playbook\u002Fplaybook\u002Fdeploy\u002Fai-auto-deploy.md","用 AI Agent 全自动部署：从 Git Push 到生产环境零手工",{"type":10,"value":4872,"toc":5718},[4873,4875,4886,4889,4895,4899,4904,5189,5193,5196,5287,5291,5392,5396,5512,5515,5604,5607,5610,5670,5673,5715],[13,4874,15],{"id":15},[21,4876,4877,4880,4883],{},[24,4878,4879],{},"个人项目 \u002F 小团队，不想手动部署",[24,4881,4882],{},"想让 AI 做部署决策（是否回滚、是否发公告）",[24,4884,4885],{},"需要部署后自动验证的",[13,4887,4888],{"id":4888},"架构",[100,4890,4893],{"className":4891,"code":4892,"language":282},[280],"git push main\n  → GitHub Actions 触发\n    → Step 1: 跑测试（pnpm test）\n    → Step 2: Claude Code 审查改动\n    → Step 3: 构建（pnpm build）\n    → Step 4: 部署到 Vercel\n    → Step 5: Claude Code 验证生产环境\n    → Step 6: 失败则自动回滚 + 通知\n",[107,4894,4892],{"__ignoreMap":105},[13,4896,4898],{"id":4897},"第一步基础-ci","第一步：基础 CI",[17,4900,4901,953],{},[107,4902,4903],{},".github\u002Fworkflows\u002Fdeploy.yml",[100,4905,4909],{"className":4906,"code":4907,"language":4908,"meta":105,"style":105},"language-yaml shiki shiki-themes github-light github-dark","name: Deploy\non:\n  push:\n    branches: [main]\n\njobs:\n  deploy:\n    runs-on: ubuntu-latest\n    permissions:\n      contents: write\n      deployments: write\n    steps:\n      - uses: actions\u002Fcheckout@v4\n      - uses: pnpm\u002Faction-setup@v2\n        with: { version: 9 }\n      - uses: actions\u002Fsetup-node@v4\n        with: { node-version: 22, cache: pnpm }\n\n      - name: Install\n        run: pnpm install --frozen-lockfile\n\n      - name: Test\n        run: pnpm test\n\n      - name: Build\n        run: pnpm build\n        env:\n          VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }}\n","yaml",[107,4910,4911,4923,4931,4938,4952,4956,4963,4970,4980,4987,4997,5006,5013,5026,5037,5056,5067,5094,5098,5109,5119,5123,5134,5143,5148,5160,5170,5178],{"__ignoreMap":105},[110,4912,4913,4917,4920],{"class":112,"line":113},[110,4914,4916],{"class":4915},"s9eBZ","name",[110,4918,4919],{"class":123},": ",[110,4921,4922],{"class":311},"Deploy\n",[110,4924,4925,4928],{"class":112,"line":120},[110,4926,4927],{"class":315},"on",[110,4929,4930],{"class":123},":\n",[110,4932,4933,4936],{"class":112,"line":127},[110,4934,4935],{"class":4915},"  push",[110,4937,4930],{"class":123},[110,4939,4940,4943,4946,4949],{"class":112,"line":134},[110,4941,4942],{"class":4915},"    branches",[110,4944,4945],{"class":123},": [",[110,4947,4948],{"class":311},"main",[110,4950,4951],{"class":123},"]\n",[110,4953,4954],{"class":112,"line":140},[110,4955,131],{"emptyLinePlaceholder":130},[110,4957,4958,4961],{"class":112,"line":150},[110,4959,4960],{"class":4915},"jobs",[110,4962,4930],{"class":123},[110,4964,4965,4968],{"class":112,"line":5},[110,4966,4967],{"class":4915},"  deploy",[110,4969,4930],{"class":123},[110,4971,4972,4975,4977],{"class":112,"line":162},[110,4973,4974],{"class":4915},"    runs-on",[110,4976,4919],{"class":123},[110,4978,4979],{"class":311},"ubuntu-latest\n",[110,4981,4982,4985],{"class":112,"line":168},[110,4983,4984],{"class":4915},"    permissions",[110,4986,4930],{"class":123},[110,4988,4989,4992,4994],{"class":112,"line":177},[110,4990,4991],{"class":4915},"      contents",[110,4993,4919],{"class":123},[110,4995,4996],{"class":311},"write\n",[110,4998,4999,5002,5004],{"class":112,"line":186},[110,5000,5001],{"class":4915},"      deployments",[110,5003,4919],{"class":123},[110,5005,4996],{"class":311},[110,5007,5008,5011],{"class":112,"line":195},[110,5009,5010],{"class":4915},"    steps",[110,5012,4930],{"class":123},[110,5014,5015,5018,5021,5023],{"class":112,"line":204},[110,5016,5017],{"class":123},"      - ",[110,5019,5020],{"class":4915},"uses",[110,5022,4919],{"class":123},[110,5024,5025],{"class":311},"actions\u002Fcheckout@v4\n",[110,5027,5028,5030,5032,5034],{"class":112,"line":209},[110,5029,5017],{"class":123},[110,5031,5020],{"class":4915},[110,5033,4919],{"class":123},[110,5035,5036],{"class":311},"pnpm\u002Faction-setup@v2\n",[110,5038,5039,5042,5045,5048,5050,5053],{"class":112,"line":215},[110,5040,5041],{"class":4915},"        with",[110,5043,5044],{"class":123},": { ",[110,5046,5047],{"class":4915},"version",[110,5049,4919],{"class":123},[110,5051,5052],{"class":315},"9",[110,5054,5055],{"class":123}," }\n",[110,5057,5058,5060,5062,5064],{"class":112,"line":221},[110,5059,5017],{"class":123},[110,5061,5020],{"class":4915},[110,5063,4919],{"class":123},[110,5065,5066],{"class":311},"actions\u002Fsetup-node@v4\n",[110,5068,5069,5071,5073,5076,5078,5081,5084,5087,5089,5092],{"class":112,"line":226},[110,5070,5041],{"class":4915},[110,5072,5044],{"class":123},[110,5074,5075],{"class":4915},"node-version",[110,5077,4919],{"class":123},[110,5079,5080],{"class":315},"22",[110,5082,5083],{"class":123},", ",[110,5085,5086],{"class":4915},"cache",[110,5088,4919],{"class":123},[110,5090,5091],{"class":311},"pnpm",[110,5093,5055],{"class":123},[110,5095,5096],{"class":112,"line":232},[110,5097,131],{"emptyLinePlaceholder":130},[110,5099,5100,5102,5104,5106],{"class":112,"line":240},[110,5101,5017],{"class":123},[110,5103,4916],{"class":4915},[110,5105,4919],{"class":123},[110,5107,5108],{"class":311},"Install\n",[110,5110,5111,5114,5116],{"class":112,"line":248},[110,5112,5113],{"class":4915},"        run",[110,5115,4919],{"class":123},[110,5117,5118],{"class":311},"pnpm install --frozen-lockfile\n",[110,5120,5121],{"class":112,"line":256},[110,5122,131],{"emptyLinePlaceholder":130},[110,5124,5125,5127,5129,5131],{"class":112,"line":261},[110,5126,5017],{"class":123},[110,5128,4916],{"class":4915},[110,5130,4919],{"class":123},[110,5132,5133],{"class":311},"Test\n",[110,5135,5136,5138,5140],{"class":112,"line":267},[110,5137,5113],{"class":4915},[110,5139,4919],{"class":123},[110,5141,5142],{"class":311},"pnpm test\n",[110,5144,5146],{"class":112,"line":5145},24,[110,5147,131],{"emptyLinePlaceholder":130},[110,5149,5151,5153,5155,5157],{"class":112,"line":5150},25,[110,5152,5017],{"class":123},[110,5154,4916],{"class":4915},[110,5156,4919],{"class":123},[110,5158,5159],{"class":311},"Build\n",[110,5161,5163,5165,5167],{"class":112,"line":5162},26,[110,5164,5113],{"class":4915},[110,5166,4919],{"class":123},[110,5168,5169],{"class":311},"pnpm build\n",[110,5171,5173,5176],{"class":112,"line":5172},27,[110,5174,5175],{"class":4915},"        env",[110,5177,4930],{"class":123},[110,5179,5181,5184,5186],{"class":112,"line":5180},28,[110,5182,5183],{"class":4915},"          VERCEL_TOKEN",[110,5185,4919],{"class":123},[110,5187,5188],{"class":311},"${{ secrets.VERCEL_TOKEN }}\n",[13,5190,5192],{"id":5191},"第二步ai-审查改动","第二步：AI 审查改动",[17,5194,5195],{},"在 build 前加 Claude Code 审查：",[100,5197,5199],{"className":4906,"code":5198,"language":4908,"meta":105,"style":105},"      - name: AI Review Changes\n        uses: anthropics\u002Fclaude-code-action@v1\n        with:\n          anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}\n          prompt: |\n            检查这次改动是否有部署风险：\n            1. 是否修改了环境变量配置\n            2. 是否修改了数据库 schema\n            3. 是否有 breaking change\n            4. 是否需要发迁移公告\n\n            如果有风险，输出 \"BLOCK_DEPLOY: \u003C原因>\"\n            如果没风险，输出 \"DEPLOY_OK\"\n",[107,5200,5201,5212,5222,5228,5238,5248,5253,5258,5263,5268,5273,5277,5282],{"__ignoreMap":105},[110,5202,5203,5205,5207,5209],{"class":112,"line":113},[110,5204,5017],{"class":123},[110,5206,4916],{"class":4915},[110,5208,4919],{"class":123},[110,5210,5211],{"class":311},"AI Review Changes\n",[110,5213,5214,5217,5219],{"class":112,"line":120},[110,5215,5216],{"class":4915},"        uses",[110,5218,4919],{"class":123},[110,5220,5221],{"class":311},"anthropics\u002Fclaude-code-action@v1\n",[110,5223,5224,5226],{"class":112,"line":127},[110,5225,5041],{"class":4915},[110,5227,4930],{"class":123},[110,5229,5230,5233,5235],{"class":112,"line":134},[110,5231,5232],{"class":4915},"          anthropic_api_key",[110,5234,4919],{"class":123},[110,5236,5237],{"class":311},"${{ secrets.ANTHROPIC_API_KEY }}\n",[110,5239,5240,5243,5245],{"class":112,"line":140},[110,5241,5242],{"class":4915},"          prompt",[110,5244,4919],{"class":123},[110,5246,5247],{"class":1577},"|\n",[110,5249,5250],{"class":112,"line":150},[110,5251,5252],{"class":311},"            检查这次改动是否有部署风险：\n",[110,5254,5255],{"class":112,"line":5},[110,5256,5257],{"class":311},"            1. 是否修改了环境变量配置\n",[110,5259,5260],{"class":112,"line":162},[110,5261,5262],{"class":311},"            2. 是否修改了数据库 schema\n",[110,5264,5265],{"class":112,"line":168},[110,5266,5267],{"class":311},"            3. 是否有 breaking change\n",[110,5269,5270],{"class":112,"line":177},[110,5271,5272],{"class":311},"            4. 是否需要发迁移公告\n",[110,5274,5275],{"class":112,"line":186},[110,5276,131],{"emptyLinePlaceholder":130},[110,5278,5279],{"class":112,"line":195},[110,5280,5281],{"class":311},"            如果有风险，输出 \"BLOCK_DEPLOY: \u003C原因>\"\n",[110,5283,5284],{"class":112,"line":204},[110,5285,5286],{"class":311},"            如果没风险，输出 \"DEPLOY_OK\"\n",[13,5288,5290],{"id":5289},"第三步ai-部署","第三步：AI 部署",[100,5292,5294],{"className":4906,"code":5293,"language":4908,"meta":105,"style":105},"      - name: Deploy with Claude\n        if: success()\n        uses: anthropics\u002Fclaude-code-action@v1\n        with:\n          anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}\n          prompt: |\n            执行部署：\n            1. 运行 vercel --prod --yes\n            2. 等待部署完成，获取 URL\n            3. curl 测试首页是否 200\n            4. curl 测试 \u002Fapi\u002Fhealth 是否返回 ok\n            5. 如果验证失败，运行 vercel rollback\n            6. 输出部署结果\n          allowed_tools: \"Bash\"\n",[107,5295,5296,5307,5317,5325,5331,5339,5347,5352,5357,5362,5367,5372,5377,5382],{"__ignoreMap":105},[110,5297,5298,5300,5302,5304],{"class":112,"line":113},[110,5299,5017],{"class":123},[110,5301,4916],{"class":4915},[110,5303,4919],{"class":123},[110,5305,5306],{"class":311},"Deploy with Claude\n",[110,5308,5309,5312,5314],{"class":112,"line":120},[110,5310,5311],{"class":4915},"        if",[110,5313,4919],{"class":123},[110,5315,5316],{"class":311},"success()\n",[110,5318,5319,5321,5323],{"class":112,"line":127},[110,5320,5216],{"class":4915},[110,5322,4919],{"class":123},[110,5324,5221],{"class":311},[110,5326,5327,5329],{"class":112,"line":134},[110,5328,5041],{"class":4915},[110,5330,4930],{"class":123},[110,5332,5333,5335,5337],{"class":112,"line":140},[110,5334,5232],{"class":4915},[110,5336,4919],{"class":123},[110,5338,5237],{"class":311},[110,5340,5341,5343,5345],{"class":112,"line":150},[110,5342,5242],{"class":4915},[110,5344,4919],{"class":123},[110,5346,5247],{"class":1577},[110,5348,5349],{"class":112,"line":5},[110,5350,5351],{"class":311},"            执行部署：\n",[110,5353,5354],{"class":112,"line":162},[110,5355,5356],{"class":311},"            1. 运行 vercel --prod --yes\n",[110,5358,5359],{"class":112,"line":168},[110,5360,5361],{"class":311},"            2. 等待部署完成，获取 URL\n",[110,5363,5364],{"class":112,"line":177},[110,5365,5366],{"class":311},"            3. curl 测试首页是否 200\n",[110,5368,5369],{"class":112,"line":186},[110,5370,5371],{"class":311},"            4. curl 测试 \u002Fapi\u002Fhealth 是否返回 ok\n",[110,5373,5374],{"class":112,"line":195},[110,5375,5376],{"class":311},"            5. 如果验证失败，运行 vercel rollback\n",[110,5378,5379],{"class":112,"line":204},[110,5380,5381],{"class":311},"            6. 输出部署结果\n",[110,5383,5384,5387,5389],{"class":112,"line":209},[110,5385,5386],{"class":4915},"          allowed_tools",[110,5388,4919],{"class":123},[110,5390,5391],{"class":311},"\"Bash\"\n",[13,5393,5395],{"id":5394},"第四步自动回滚","第四步：自动回滚",[100,5397,5399],{"className":4906,"code":5398,"language":4908,"meta":105,"style":105},"      - name: Rollback on failure\n        if: failure()\n        run: |\n          # 获取上一个稳定部署\n          PREV=$(vercel ls --yes | head -5 | tail -1 | awk '{print $1}')\n          echo \"Rolling back to $PREV\"\n          vercel promote $PREV --yes\n\n      - name: Notify\n        if: always()\n        uses: slackapi\u002Fslack-github-action@v1\n        with:\n          slack-message: |\n            ${{ job.status == 'success' && '✅' || '❌' }} 部署 ${{ job.status }}\n            仓库: ${{ github.repository }}\n            提交: ${{ github.event.head_commit.message }}\n",[107,5400,5401,5412,5421,5429,5434,5439,5444,5449,5453,5464,5473,5482,5488,5497,5502,5507],{"__ignoreMap":105},[110,5402,5403,5405,5407,5409],{"class":112,"line":113},[110,5404,5017],{"class":123},[110,5406,4916],{"class":4915},[110,5408,4919],{"class":123},[110,5410,5411],{"class":311},"Rollback on failure\n",[110,5413,5414,5416,5418],{"class":112,"line":120},[110,5415,5311],{"class":4915},[110,5417,4919],{"class":123},[110,5419,5420],{"class":311},"failure()\n",[110,5422,5423,5425,5427],{"class":112,"line":127},[110,5424,5113],{"class":4915},[110,5426,4919],{"class":123},[110,5428,5247],{"class":1577},[110,5430,5431],{"class":112,"line":134},[110,5432,5433],{"class":311},"          # 获取上一个稳定部署\n",[110,5435,5436],{"class":112,"line":140},[110,5437,5438],{"class":311},"          PREV=$(vercel ls --yes | head -5 | tail -1 | awk '{print $1}')\n",[110,5440,5441],{"class":112,"line":150},[110,5442,5443],{"class":311},"          echo \"Rolling back to $PREV\"\n",[110,5445,5446],{"class":112,"line":5},[110,5447,5448],{"class":311},"          vercel promote $PREV --yes\n",[110,5450,5451],{"class":112,"line":162},[110,5452,131],{"emptyLinePlaceholder":130},[110,5454,5455,5457,5459,5461],{"class":112,"line":168},[110,5456,5017],{"class":123},[110,5458,4916],{"class":4915},[110,5460,4919],{"class":123},[110,5462,5463],{"class":311},"Notify\n",[110,5465,5466,5468,5470],{"class":112,"line":177},[110,5467,5311],{"class":4915},[110,5469,4919],{"class":123},[110,5471,5472],{"class":311},"always()\n",[110,5474,5475,5477,5479],{"class":112,"line":186},[110,5476,5216],{"class":4915},[110,5478,4919],{"class":123},[110,5480,5481],{"class":311},"slackapi\u002Fslack-github-action@v1\n",[110,5483,5484,5486],{"class":112,"line":195},[110,5485,5041],{"class":4915},[110,5487,4930],{"class":123},[110,5489,5490,5493,5495],{"class":112,"line":204},[110,5491,5492],{"class":4915},"          slack-message",[110,5494,4919],{"class":123},[110,5496,5247],{"class":1577},[110,5498,5499],{"class":112,"line":209},[110,5500,5501],{"class":311},"            ${{ job.status == 'success' && '✅' || '❌' }} 部署 ${{ job.status }}\n",[110,5503,5504],{"class":112,"line":215},[110,5505,5506],{"class":311},"            仓库: ${{ github.repository }}\n",[110,5508,5509],{"class":112,"line":221},[110,5510,5511],{"class":311},"            提交: ${{ github.event.head_commit.message }}\n",[13,5513,5514],{"id":5514},"安全边界",[440,5516,5517,5530],{},[443,5518,5519],{},[446,5520,5521,5524,5527],{},[449,5522,5523],{},"操作",[449,5525,5526],{},"AI 可执行",[449,5528,5529],{},"需人工确认",[459,5531,5532,5541,5550,5559,5568,5577,5586,5595],{},[446,5533,5534,5537,5539],{},[464,5535,5536],{},"跑测试",[464,5538,1771],{},[464,5540],{},[446,5542,5543,5546,5548],{},[464,5544,5545],{},"构建项目",[464,5547,1771],{},[464,5549],{},[446,5551,5552,5555,5557],{},[464,5553,5554],{},"部署到 preview",[464,5556,1771],{},[464,5558],{},[446,5560,5561,5564,5566],{},[464,5562,5563],{},"部署到 production",[464,5565,1771],{},[464,5567],{},[446,5569,5570,5573,5575],{},[464,5571,5572],{},"回滚",[464,5574,1771],{},[464,5576],{},[446,5578,5579,5582,5584],{},[464,5580,5581],{},"修改环境变量",[464,5583],{},[464,5585,1771],{},[446,5587,5588,5591,5593],{},[464,5589,5590],{},"数据库迁移",[464,5592],{},[464,5594,1771],{},[446,5596,5597,5600,5602],{},[464,5598,5599],{},"删除资源",[464,5601],{},[464,5603,1771],{},[13,5605,5606],{"id":5606},"效果",[17,5608,5609],{},"上线 1 个月后：",[440,5611,5612,5624],{},[443,5613,5614],{},[446,5615,5616,5618,5621],{},[449,5617,611],{},[449,5619,5620],{},"之前（手动）",[449,5622,5623],{},"之后（AI 自动）",[459,5625,5626,5637,5648,5659],{},[446,5627,5628,5631,5634],{},[464,5629,5630],{},"部署频率",[464,5632,5633],{},"2 次\u002F周",[464,5635,5636],{},"5 次\u002F天",[446,5638,5639,5642,5645],{},[464,5640,5641],{},"部署耗时",[464,5643,5644],{},"15 分钟",[464,5646,5647],{},"3 分钟",[446,5649,5650,5653,5656],{},[464,5651,5652],{},"部署失败率",[464,5654,5655],{},"10%",[464,5657,5658],{},"3%（自动回滚）",[446,5660,5661,5664,5667],{},[464,5662,5663],{},"人工介入",[464,5665,5666],{},"每次",[464,5668,5669],{},"5% 的部署",[13,5671,5672],{"id":5672},"踩坑记录",[415,5674,5675,5688,5694,5700,5706],{},[24,5676,5677,5683,5684,5687],{},[40,5678,5679,5680],{},"Claude Code Action 的 ",[107,5681,5682],{},"allowed_tools","——只给 ",[107,5685,5686],{},"Bash","，别给文件编辑权限，否则 AI 可能改代码。",[24,5689,5690,5693],{},[40,5691,5692],{},"Vercel rollback 需要 production deployment 历史","——首次部署没有回滚目标，先手动部署一次。",[24,5695,5696,5699],{},[40,5697,5698],{},"Claude API 成本","——每次部署约 $0.2-0.5（审查 + 部署 + 验证），月费 $30-50。",[24,5701,5702,5705],{},[40,5703,5704],{},"preview 环境先验证","——加一步部署到 preview 验证通过再 promote 到 production。",[24,5707,5708,5711,5712,43],{},[40,5709,5710],{},"GitHub Actions 超时","——Claude Code 调用有时慢，设置 ",[107,5713,5714],{},"timeout-minutes: 15",[700,5716,5717],{},"html pre.shiki code .s9eBZ, html code.shiki .s9eBZ{--shiki-default:#22863A;--shiki-dark:#85E89D}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}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 .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}",{"title":105,"searchDepth":127,"depth":127,"links":5719},[5720,5721,5722,5723,5724,5725,5726,5727,5728],{"id":15,"depth":120,"text":15},{"id":4888,"depth":120,"text":4888},{"id":4897,"depth":120,"text":4898},{"id":5191,"depth":120,"text":5192},{"id":5289,"depth":120,"text":5290},{"id":5394,"depth":120,"text":5395},{"id":5514,"depth":120,"text":5514},{"id":5606,"depth":120,"text":5606},{"id":5672,"depth":120,"text":5672},"deploy","\u002Fog\u002Fplaybook\u002Fai-auto-deploy.png","用 Claude Code + GitHub Actions + Vercel\u002FCfly 搭一条全自动部署流水线——push 到 main → AI 跑测试 → AI 审查 → AI 部署 → 验证 → 通知。零手工操作，含回滚机制。",{},"\u002Fplaybook\u002Fdeploy\u002Fai-auto-deploy","2026-06-21",[1313,5736,5737],"coding\u002Fbuilder\u002Fv0","agent\u002Fskills\u002Fclaude-skills",{"title":4870,"description":5731},"playbook\u002Fdeploy\u002Fai-auto-deploy",[5741,5742,1031,5743,5744],"部署","CI\u002FCD","GitHub Actions","自动化","0C0tbe1lwERKuzXgnhYWUeLJ7FFDITUdnTFvc0MVs-E",{"id":5747,"title":5748,"body":5749,"category":6831,"cover":6832,"description":6833,"extension":104,"meta":6834,"navigation":130,"path":6835,"published":5734,"relatedTools":6836,"seo":6837,"stem":6838,"tags":6839,"updated":5734,"__hash__":6844},"playbook\u002Fplaybook\u002Fmigration\u002Fai-db-migration.md","用 AI 做数据库迁移：零停机 schema 变更工作流",{"type":10,"value":5750,"toc":6817},[5751,5753,5767,5770,5796,5799,5805,5809,5812,5818,5821,5846,5849,5975,5979,5985,5988,5992,5996,6315,6318,6542,6545,6600,6604,6701,6705,6708,6744,6808,6814],[13,5752,15],{"id":15},[21,5754,5755,5758,5761,5764],{},[24,5756,5757],{},"生产数据库需要 schema 变更",[24,5759,5760],{},"大表（千万行+）加列 \u002F 改类型 \u002F 加索引",[24,5762,5763],{},"需要零停机迁移",[24,5765,5766],{},"想让 AI 生成迁移文件 + 回滚方案",[13,5768,5769],{"id":5769},"迁移原则",[415,5771,5772,5778,5784,5790],{},[24,5773,5774,5777],{},[40,5775,5776],{},"永远可回滚","——每个迁移文件都有对应的 down migration",[24,5779,5780,5783],{},[40,5781,5782],{},"分阶段执行","——大变更拆成多步，每步都可独立回滚",[24,5785,5786,5789],{},[40,5787,5788],{},"先兼容后破坏","——先让代码兼容新 schema，再删旧字段",[24,5791,5792,5795],{},[40,5793,5794],{},"AI 生成 + 人工审查","——AI 写迁移，人审 SQL",[13,5797,5798],{"id":5798},"工作流",[100,5800,5803],{"className":5801,"code":5802,"language":282},[280],"需求：给 users 表加 phone 字段\n  → Step 1: Claude 生成迁移文件（含 up + down）\n  → Step 2: Claude 检查兼容性（是否破坏现有代码）\n  → Step 3: 在 shadow DB 测试迁移\n  → Step 4: 生产分阶段执行\n  → Step 5: 验证 + 清理\n",[107,5804,5802],{"__ignoreMap":105},[13,5806,5808],{"id":5807},"step-1-ai-生成迁移","Step 1: AI 生成迁移",[17,5810,5811],{},"用 Claude Code 连数据库（通过 MCP），描述需求：",[100,5813,5816],{"className":5814,"code":5815,"language":282},[280],"给 users 表加一个 phone 字段，varchar(20)，可空，加唯一索引。\n用 Drizzle migration 格式生成，含 up 和 down。\n检查现有代码是否有依赖。\n",[107,5817,5815],{"__ignoreMap":105},[17,5819,5820],{},"Claude 会：",[415,5822,5823,5826,5829,5832,5835],{},[24,5824,5825],{},"查当前 users 表结构",[24,5827,5828],{},"生成 Drizzle schema 改动",[24,5830,5831],{},"生成 SQL migration 文件",[24,5833,5834],{},"生成回滚 SQL",[24,5836,5837,5838,5841,5842,5845],{},"检查代码里的 ",[107,5839,5840],{},"select *"," 和 ",[107,5843,5844],{},"insert"," 是否受影响",[17,5847,5848],{},"生成的文件：",[100,5850,5854],{"className":5851,"code":5852,"language":5853,"meta":105,"style":105},"language-sql shiki shiki-themes github-light github-dark","-- migrations\u002F0024_add_user_phone.sql\n\n-- UP\nALTER TABLE users ADD COLUMN phone VARCHAR(20);\nCREATE UNIQUE INDEX idx_users_phone ON users(phone) WHERE phone IS NOT NULL;\n\n-- DOWN\nDROP INDEX IF EXISTS idx_users_phone;\nALTER TABLE users DROP COLUMN IF EXISTS phone;\n","sql",[107,5855,5856,5861,5865,5870,5899,5928,5932,5937,5954],{"__ignoreMap":105},[110,5857,5858],{"class":112,"line":113},[110,5859,5860],{"class":336},"-- migrations\u002F0024_add_user_phone.sql\n",[110,5862,5863],{"class":112,"line":120},[110,5864,131],{"emptyLinePlaceholder":130},[110,5866,5867],{"class":112,"line":127},[110,5868,5869],{"class":336},"-- UP\n",[110,5871,5872,5875,5878,5881,5884,5887,5890,5893,5896],{"class":112,"line":134},[110,5873,5874],{"class":1577},"ALTER",[110,5876,5877],{"class":1577}," TABLE",[110,5879,5880],{"class":123}," users ",[110,5882,5883],{"class":1577},"ADD",[110,5885,5886],{"class":123}," COLUMN phone ",[110,5888,5889],{"class":1577},"VARCHAR",[110,5891,5892],{"class":123},"(",[110,5894,5895],{"class":315},"20",[110,5897,5898],{"class":123},");\n",[110,5900,5901,5904,5907,5910,5913,5916,5919,5922,5925],{"class":112,"line":140},[110,5902,5903],{"class":1577},"CREATE",[110,5905,5906],{"class":1577}," UNIQUE INDEX",[110,5908,5909],{"class":307}," idx_users_phone",[110,5911,5912],{"class":1577}," ON",[110,5914,5915],{"class":123}," users(phone) ",[110,5917,5918],{"class":1577},"WHERE",[110,5920,5921],{"class":123}," phone ",[110,5923,5924],{"class":1577},"IS NOT NULL",[110,5926,5927],{"class":123},";\n",[110,5929,5930],{"class":112,"line":150},[110,5931,131],{"emptyLinePlaceholder":130},[110,5933,5934],{"class":112,"line":5},[110,5935,5936],{"class":336},"-- DOWN\n",[110,5938,5939,5942,5945,5948,5951],{"class":112,"line":162},[110,5940,5941],{"class":1577},"DROP",[110,5943,5944],{"class":1577}," INDEX",[110,5946,5947],{"class":1577}," IF",[110,5949,5950],{"class":1577}," EXISTS",[110,5952,5953],{"class":123}," idx_users_phone;\n",[110,5955,5956,5958,5960,5962,5964,5967,5970,5972],{"class":112,"line":168},[110,5957,5874],{"class":1577},[110,5959,5877],{"class":1577},[110,5961,5880],{"class":123},[110,5963,5941],{"class":1577},[110,5965,5966],{"class":123}," COLUMN ",[110,5968,5969],{"class":1577},"IF",[110,5971,5950],{"class":1577},[110,5973,5974],{"class":123}," phone;\n",[13,5976,5978],{"id":5977},"step-2-兼容性检查","Step 2: 兼容性检查",[100,5980,5983],{"className":5981,"code":5982,"language":282},[280],"检查这次迁移会影响哪些代码：\n1. 哪些 INSERT 语句需要加 phone 字段\n2. 哪些 SELECT * 会导致返回字段变化\n3. 哪些 API 响应 schema 会变\n",[107,5984,5982],{"__ignoreMap":105},[17,5986,5987],{},"Claude 输出影响清单，你确认后再执行。",[13,5989,5991],{"id":5990},"step-3-高危操作安全模式","Step 3: 高危操作安全模式",[1834,5993,5995],{"id":5994},"大表加列千万行","大表加列（千万行+）",[100,5997,5999],{"className":5851,"code":5998,"language":5853,"meta":105,"style":105},"-- ❌ 错误：直接加（锁表）\nALTER TABLE users ADD COLUMN phone VARCHAR(20);\n\n-- ✅ 正确：分阶段\n-- Phase 1: 加可空字段（不锁表，PostgreSQL 11+）\nALTER TABLE users ADD COLUMN phone VARCHAR(20);\n\n-- Phase 2: 回填数据（分批，不锁表）\n-- Claude 生成批处理脚本\nDO $$\nDECLARE\n  batch_size INT := 10000;\n  offset_val INT := 0;\nBEGIN\n  LOOP\n    UPDATE users SET phone = '' WHERE id IN (\n      SELECT id FROM users WHERE phone IS NULL LIMIT batch_size\n    );\n    GET DIAGNOSTICS batch_size = ROW_COUNT;\n    EXIT WHEN batch_size = 0;\n    PERFORM pg_sleep(0.1);  -- 给主从复制留时间\n  END LOOP;\nEND $$;\n\n-- Phase 3: 加约束（先检查再加）\nALTER TABLE users ADD CONSTRAINT chk_phone CHECK (phone ~ '^\\+?[0-9]{6,20}$') NOT VALID;\nALTER TABLE users VALIDATE CONSTRAINT chk_phone;\n",[107,6000,6001,6006,6026,6030,6035,6040,6060,6064,6069,6074,6079,6084,6102,6118,6123,6128,6157,6185,6190,6203,6220,6239,6249,6257,6261,6266,6300],{"__ignoreMap":105},[110,6002,6003],{"class":112,"line":113},[110,6004,6005],{"class":336},"-- ❌ 错误：直接加（锁表）\n",[110,6007,6008,6010,6012,6014,6016,6018,6020,6022,6024],{"class":112,"line":120},[110,6009,5874],{"class":1577},[110,6011,5877],{"class":1577},[110,6013,5880],{"class":123},[110,6015,5883],{"class":1577},[110,6017,5886],{"class":123},[110,6019,5889],{"class":1577},[110,6021,5892],{"class":123},[110,6023,5895],{"class":315},[110,6025,5898],{"class":123},[110,6027,6028],{"class":112,"line":127},[110,6029,131],{"emptyLinePlaceholder":130},[110,6031,6032],{"class":112,"line":134},[110,6033,6034],{"class":336},"-- ✅ 正确：分阶段\n",[110,6036,6037],{"class":112,"line":140},[110,6038,6039],{"class":336},"-- Phase 1: 加可空字段（不锁表，PostgreSQL 11+）\n",[110,6041,6042,6044,6046,6048,6050,6052,6054,6056,6058],{"class":112,"line":150},[110,6043,5874],{"class":1577},[110,6045,5877],{"class":1577},[110,6047,5880],{"class":123},[110,6049,5883],{"class":1577},[110,6051,5886],{"class":123},[110,6053,5889],{"class":1577},[110,6055,5892],{"class":123},[110,6057,5895],{"class":315},[110,6059,5898],{"class":123},[110,6061,6062],{"class":112,"line":5},[110,6063,131],{"emptyLinePlaceholder":130},[110,6065,6066],{"class":112,"line":162},[110,6067,6068],{"class":336},"-- Phase 2: 回填数据（分批，不锁表）\n",[110,6070,6071],{"class":112,"line":168},[110,6072,6073],{"class":336},"-- Claude 生成批处理脚本\n",[110,6075,6076],{"class":112,"line":177},[110,6077,6078],{"class":123},"DO $$\n",[110,6080,6081],{"class":112,"line":186},[110,6082,6083],{"class":1577},"DECLARE\n",[110,6085,6086,6089,6092,6095,6097,6100],{"class":112,"line":195},[110,6087,6088],{"class":123},"  batch_size ",[110,6090,6091],{"class":1577},"INT",[110,6093,6094],{"class":123}," :",[110,6096,1587],{"class":1577},[110,6098,6099],{"class":315}," 10000",[110,6101,5927],{"class":123},[110,6103,6104,6107,6109,6111,6113,6116],{"class":112,"line":204},[110,6105,6106],{"class":123},"  offset_val ",[110,6108,6091],{"class":1577},[110,6110,6094],{"class":123},[110,6112,1587],{"class":1577},[110,6114,6115],{"class":315}," 0",[110,6117,5927],{"class":123},[110,6119,6120],{"class":112,"line":209},[110,6121,6122],{"class":1577},"BEGIN\n",[110,6124,6125],{"class":112,"line":215},[110,6126,6127],{"class":1577},"  LOOP\n",[110,6129,6130,6133,6135,6138,6140,6142,6145,6148,6151,6154],{"class":112,"line":221},[110,6131,6132],{"class":1577},"    UPDATE",[110,6134,5880],{"class":123},[110,6136,6137],{"class":1577},"SET",[110,6139,5921],{"class":123},[110,6141,1587],{"class":1577},[110,6143,6144],{"class":311}," ''",[110,6146,6147],{"class":1577}," WHERE",[110,6149,6150],{"class":123}," id ",[110,6152,6153],{"class":1577},"IN",[110,6155,6156],{"class":123}," (\n",[110,6158,6159,6162,6164,6167,6169,6171,6173,6176,6179,6182],{"class":112,"line":226},[110,6160,6161],{"class":1577},"      SELECT",[110,6163,6150],{"class":123},[110,6165,6166],{"class":1577},"FROM",[110,6168,5880],{"class":123},[110,6170,5918],{"class":1577},[110,6172,5921],{"class":123},[110,6174,6175],{"class":1577},"IS",[110,6177,6178],{"class":1577}," NULL",[110,6180,6181],{"class":1577}," LIMIT",[110,6183,6184],{"class":123}," batch_size\n",[110,6186,6187],{"class":112,"line":232},[110,6188,6189],{"class":123},"    );\n",[110,6191,6192,6195,6198,6200],{"class":112,"line":240},[110,6193,6194],{"class":1577},"    GET",[110,6196,6197],{"class":123}," DIAGNOSTICS batch_size ",[110,6199,1587],{"class":1577},[110,6201,6202],{"class":123}," ROW_COUNT;\n",[110,6204,6205,6208,6211,6214,6216,6218],{"class":112,"line":248},[110,6206,6207],{"class":123},"    EXIT ",[110,6209,6210],{"class":1577},"WHEN",[110,6212,6213],{"class":123}," batch_size ",[110,6215,1587],{"class":1577},[110,6217,6115],{"class":315},[110,6219,5927],{"class":123},[110,6221,6222,6225,6228,6231,6233,6236],{"class":112,"line":256},[110,6223,6224],{"class":123},"    PERFORM pg_sleep(",[110,6226,6227],{"class":315},"0",[110,6229,6230],{"class":123},".",[110,6232,1083],{"class":315},[110,6234,6235],{"class":123},");  ",[110,6237,6238],{"class":336},"-- 给主从复制留时间\n",[110,6240,6241,6244,6247],{"class":112,"line":261},[110,6242,6243],{"class":1577},"  END",[110,6245,6246],{"class":1577}," LOOP",[110,6248,5927],{"class":123},[110,6250,6251,6254],{"class":112,"line":267},[110,6252,6253],{"class":1577},"END",[110,6255,6256],{"class":123}," $$;\n",[110,6258,6259],{"class":112,"line":5145},[110,6260,131],{"emptyLinePlaceholder":130},[110,6262,6263],{"class":112,"line":5150},[110,6264,6265],{"class":336},"-- Phase 3: 加约束（先检查再加）\n",[110,6267,6268,6270,6272,6274,6276,6279,6282,6285,6288,6291,6294,6297],{"class":112,"line":5162},[110,6269,5874],{"class":1577},[110,6271,5877],{"class":1577},[110,6273,5880],{"class":123},[110,6275,5883],{"class":1577},[110,6277,6278],{"class":1577}," CONSTRAINT",[110,6280,6281],{"class":123}," chk_phone ",[110,6283,6284],{"class":1577},"CHECK",[110,6286,6287],{"class":123}," (phone ~ ",[110,6289,6290],{"class":311},"'^\\+?[0-9]{6,20}$'",[110,6292,6293],{"class":123},") ",[110,6295,6296],{"class":1577},"NOT",[110,6298,6299],{"class":123}," VALID;\n",[110,6301,6302,6304,6306,6309,6312],{"class":112,"line":5172},[110,6303,5874],{"class":1577},[110,6305,5877],{"class":1577},[110,6307,6308],{"class":123}," users VALIDATE ",[110,6310,6311],{"class":1577},"CONSTRAINT",[110,6313,6314],{"class":123}," chk_phone;\n",[1834,6316,6317],{"id":6317},"改字段类型",[100,6319,6321],{"className":5851,"code":6320,"language":5853,"meta":105,"style":105},"-- ❌ 错误：直接改（锁表 + 重写全表）\nALTER TABLE users ALTER COLUMN phone TYPE BIGINT USING phone::BIGINT;\n\n-- ✅ 正确：新字段 + 回填 + 切换 + 删旧\n-- Phase 1: 加新字段\nALTER TABLE users ADD COLUMN phone_int BIGINT;\n\n-- Phase 2: 双写（代码同时写旧和新）\n-- Claude 生成代码改动：INSERT\u002FUPDATE 同时写 phone 和 phone_int\n\n-- Phase 3: 回填\nUPDATE users SET phone_int = phone::BIGINT WHERE phone_int IS NULL AND phone ~ '^[0-9]+$';\n\n-- Phase 4: 验证数据一致\nSELECT COUNT(*) FROM users WHERE phone IS NOT NULL AND phone_int IS NULL;\n-- 必须为 0\n\n-- Phase 5: 代码切到读 phone_int\n\n-- Phase 6: 删旧字段（等一个发布周期后）\nALTER TABLE users DROP COLUMN phone;\nALTER TABLE users RENAME COLUMN phone_int TO phone;\n",[107,6322,6323,6328,6357,6361,6366,6371,6388,6392,6397,6402,6406,6411,6448,6452,6457,6492,6497,6501,6506,6510,6515,6528],{"__ignoreMap":105},[110,6324,6325],{"class":112,"line":113},[110,6326,6327],{"class":336},"-- ❌ 错误：直接改（锁表 + 重写全表）\n",[110,6329,6330,6332,6334,6336,6338,6340,6343,6346,6349,6352,6355],{"class":112,"line":120},[110,6331,5874],{"class":1577},[110,6333,5877],{"class":1577},[110,6335,5880],{"class":123},[110,6337,5874],{"class":1577},[110,6339,5886],{"class":123},[110,6341,6342],{"class":1577},"TYPE",[110,6344,6345],{"class":1577}," BIGINT",[110,6347,6348],{"class":1577}," USING",[110,6350,6351],{"class":123}," phone::",[110,6353,6354],{"class":1577},"BIGINT",[110,6356,5927],{"class":123},[110,6358,6359],{"class":112,"line":127},[110,6360,131],{"emptyLinePlaceholder":130},[110,6362,6363],{"class":112,"line":134},[110,6364,6365],{"class":336},"-- ✅ 正确：新字段 + 回填 + 切换 + 删旧\n",[110,6367,6368],{"class":112,"line":140},[110,6369,6370],{"class":336},"-- Phase 1: 加新字段\n",[110,6372,6373,6375,6377,6379,6381,6384,6386],{"class":112,"line":150},[110,6374,5874],{"class":1577},[110,6376,5877],{"class":1577},[110,6378,5880],{"class":123},[110,6380,5883],{"class":1577},[110,6382,6383],{"class":123}," COLUMN phone_int ",[110,6385,6354],{"class":1577},[110,6387,5927],{"class":123},[110,6389,6390],{"class":112,"line":5},[110,6391,131],{"emptyLinePlaceholder":130},[110,6393,6394],{"class":112,"line":162},[110,6395,6396],{"class":336},"-- Phase 2: 双写（代码同时写旧和新）\n",[110,6398,6399],{"class":112,"line":168},[110,6400,6401],{"class":336},"-- Claude 生成代码改动：INSERT\u002FUPDATE 同时写 phone 和 phone_int\n",[110,6403,6404],{"class":112,"line":177},[110,6405,131],{"emptyLinePlaceholder":130},[110,6407,6408],{"class":112,"line":186},[110,6409,6410],{"class":336},"-- Phase 3: 回填\n",[110,6412,6413,6416,6418,6420,6423,6425,6427,6429,6431,6433,6435,6437,6440,6443,6446],{"class":112,"line":195},[110,6414,6415],{"class":1577},"UPDATE",[110,6417,5880],{"class":123},[110,6419,6137],{"class":1577},[110,6421,6422],{"class":123}," phone_int ",[110,6424,1587],{"class":1577},[110,6426,6351],{"class":123},[110,6428,6354],{"class":1577},[110,6430,6147],{"class":1577},[110,6432,6422],{"class":123},[110,6434,6175],{"class":1577},[110,6436,6178],{"class":1577},[110,6438,6439],{"class":1577}," AND",[110,6441,6442],{"class":123}," phone ~ ",[110,6444,6445],{"class":311},"'^[0-9]+$'",[110,6447,5927],{"class":123},[110,6449,6450],{"class":112,"line":204},[110,6451,131],{"emptyLinePlaceholder":130},[110,6453,6454],{"class":112,"line":209},[110,6455,6456],{"class":336},"-- Phase 4: 验证数据一致\n",[110,6458,6459,6462,6465,6467,6470,6472,6474,6476,6478,6480,6482,6484,6486,6488,6490],{"class":112,"line":215},[110,6460,6461],{"class":1577},"SELECT",[110,6463,6464],{"class":315}," COUNT",[110,6466,5892],{"class":123},[110,6468,6469],{"class":1577},"*",[110,6471,6293],{"class":123},[110,6473,6166],{"class":1577},[110,6475,5880],{"class":123},[110,6477,5918],{"class":1577},[110,6479,5921],{"class":123},[110,6481,5924],{"class":1577},[110,6483,6439],{"class":1577},[110,6485,6422],{"class":123},[110,6487,6175],{"class":1577},[110,6489,6178],{"class":1577},[110,6491,5927],{"class":123},[110,6493,6494],{"class":112,"line":221},[110,6495,6496],{"class":336},"-- 必须为 0\n",[110,6498,6499],{"class":112,"line":226},[110,6500,131],{"emptyLinePlaceholder":130},[110,6502,6503],{"class":112,"line":232},[110,6504,6505],{"class":336},"-- Phase 5: 代码切到读 phone_int\n",[110,6507,6508],{"class":112,"line":240},[110,6509,131],{"emptyLinePlaceholder":130},[110,6511,6512],{"class":112,"line":248},[110,6513,6514],{"class":336},"-- Phase 6: 删旧字段（等一个发布周期后）\n",[110,6516,6517,6519,6521,6523,6525],{"class":112,"line":256},[110,6518,5874],{"class":1577},[110,6520,5877],{"class":1577},[110,6522,5880],{"class":123},[110,6524,5941],{"class":1577},[110,6526,6527],{"class":123}," COLUMN phone;\n",[110,6529,6530,6532,6534,6537,6540],{"class":112,"line":261},[110,6531,5874],{"class":1577},[110,6533,5877],{"class":1577},[110,6535,6536],{"class":123}," users RENAME COLUMN phone_int ",[110,6538,6539],{"class":1577},"TO",[110,6541,5974],{"class":123},[1834,6543,6544],{"id":6544},"加索引",[100,6546,6548],{"className":5851,"code":6547,"language":5853,"meta":105,"style":105},"-- ❌ 错误：直接加（锁表写操作）\nCREATE INDEX idx_users_email ON users(email);\n\n-- ✅ 正确：CONCURRENTLY（不锁表，但慢）\nCREATE INDEX CONCURRENTLY idx_users_email ON users(email);\n-- 注意：CONCURRENTLY 不能在事务里跑\n",[107,6549,6550,6555,6569,6573,6578,6595],{"__ignoreMap":105},[110,6551,6552],{"class":112,"line":113},[110,6553,6554],{"class":336},"-- ❌ 错误：直接加（锁表写操作）\n",[110,6556,6557,6559,6561,6564,6566],{"class":112,"line":120},[110,6558,5903],{"class":1577},[110,6560,5944],{"class":1577},[110,6562,6563],{"class":307}," idx_users_email",[110,6565,5912],{"class":1577},[110,6567,6568],{"class":123}," users(email);\n",[110,6570,6571],{"class":112,"line":127},[110,6572,131],{"emptyLinePlaceholder":130},[110,6574,6575],{"class":112,"line":134},[110,6576,6577],{"class":336},"-- ✅ 正确：CONCURRENTLY（不锁表，但慢）\n",[110,6579,6580,6582,6584,6587,6590,6593],{"class":112,"line":140},[110,6581,5903],{"class":1577},[110,6583,5944],{"class":1577},[110,6585,6586],{"class":307}," CONCURRENTLY",[110,6588,6589],{"class":123}," idx_users_email ",[110,6591,6592],{"class":1577},"ON",[110,6594,6568],{"class":123},[110,6596,6597],{"class":112,"line":150},[110,6598,6599],{"class":336},"-- 注意：CONCURRENTLY 不能在事务里跑\n",[13,6601,6603],{"id":6602},"step-4-执行-监控","Step 4: 执行 + 监控",[100,6605,6607],{"className":298,"code":6606,"language":300,"meta":105,"style":105},"# 1. 在 shadow DB 测试\npsql $SHADOW_DB -f migrations\u002F0024_add_user_phone.sql\n\n# 2. 生产执行（维护窗口）\npsql $PROD_DB -f migrations\u002F0024_add_user_phone.sql\n\n# 3. 监控（Claude 帮你写监控脚本）\nwatch -n 5 'psql $PROD_DB -c \"\n  SELECT\n    count(*) AS total,\n    count(phone) AS with_phone,\n    count(*) - count(phone) AS without_phone\n  FROM users\n\"'\n",[107,6608,6609,6614,6628,6632,6637,6648,6652,6657,6671,6676,6681,6686,6691,6696],{"__ignoreMap":105},[110,6610,6611],{"class":112,"line":113},[110,6612,6613],{"class":336},"# 1. 在 shadow DB 测试\n",[110,6615,6616,6619,6622,6625],{"class":112,"line":120},[110,6617,6618],{"class":307},"psql",[110,6620,6621],{"class":123}," $SHADOW_DB ",[110,6623,6624],{"class":315},"-f",[110,6626,6627],{"class":311}," migrations\u002F0024_add_user_phone.sql\n",[110,6629,6630],{"class":112,"line":127},[110,6631,131],{"emptyLinePlaceholder":130},[110,6633,6634],{"class":112,"line":134},[110,6635,6636],{"class":336},"# 2. 生产执行（维护窗口）\n",[110,6638,6639,6641,6644,6646],{"class":112,"line":140},[110,6640,6618],{"class":307},[110,6642,6643],{"class":123}," $PROD_DB ",[110,6645,6624],{"class":315},[110,6647,6627],{"class":311},[110,6649,6650],{"class":112,"line":150},[110,6651,131],{"emptyLinePlaceholder":130},[110,6653,6654],{"class":112,"line":5},[110,6655,6656],{"class":336},"# 3. 监控（Claude 帮你写监控脚本）\n",[110,6658,6659,6662,6665,6668],{"class":112,"line":162},[110,6660,6661],{"class":307},"watch",[110,6663,6664],{"class":315}," -n",[110,6666,6667],{"class":315}," 5",[110,6669,6670],{"class":311}," 'psql $PROD_DB -c \"\n",[110,6672,6673],{"class":112,"line":168},[110,6674,6675],{"class":311},"  SELECT\n",[110,6677,6678],{"class":112,"line":177},[110,6679,6680],{"class":311},"    count(*) AS total,\n",[110,6682,6683],{"class":112,"line":186},[110,6684,6685],{"class":311},"    count(phone) AS with_phone,\n",[110,6687,6688],{"class":112,"line":195},[110,6689,6690],{"class":311},"    count(*) - count(phone) AS without_phone\n",[110,6692,6693],{"class":112,"line":204},[110,6694,6695],{"class":311},"  FROM users\n",[110,6697,6698],{"class":112,"line":209},[110,6699,6700],{"class":311},"\"'\n",[13,6702,6704],{"id":6703},"step-5-回滚方案","Step 5: 回滚方案",[17,6706,6707],{},"每个迁移执行前，Claude 生成回滚 checklist：",[100,6709,6713],{"className":6710,"code":6711,"language":6712,"meta":105,"style":105},"language-markdown shiki shiki-themes github-light github-dark","## 回滚步骤（如需）\n\n1. 确认 down migration 安全：\n   ```sql\n   SELECT count(*) FROM users WHERE phone IS NOT NULL;\n   -- 如果 > 0，回滚会丢数据，确认是否可接受\n","markdown",[107,6714,6715,6720,6724,6729,6734,6739],{"__ignoreMap":105},[110,6716,6717],{"class":112,"line":113},[110,6718,6719],{},"## 回滚步骤（如需）\n",[110,6721,6722],{"class":112,"line":120},[110,6723,131],{"emptyLinePlaceholder":130},[110,6725,6726],{"class":112,"line":127},[110,6727,6728],{},"1. 确认 down migration 安全：\n",[110,6730,6731],{"class":112,"line":134},[110,6732,6733],{},"   ```sql\n",[110,6735,6736],{"class":112,"line":140},[110,6737,6738],{},"   SELECT count(*) FROM users WHERE phone IS NOT NULL;\n",[110,6740,6741],{"class":112,"line":150},[110,6742,6743],{},"   -- 如果 > 0，回滚会丢数据，确认是否可接受\n",[415,6745,6746,6765,6792],{"start":120},[24,6747,6748,6749],{},"执行回滚：",[100,6750,6752],{"className":298,"code":6751,"language":300,"meta":105,"style":105},"psql $PROD_DB -f migrations\u002F0024_add_user_phone_down.sql\n",[107,6753,6754],{"__ignoreMap":105},[110,6755,6756,6758,6760,6762],{"class":112,"line":113},[110,6757,6618],{"class":307},[110,6759,6643],{"class":123},[110,6761,6624],{"class":315},[110,6763,6764],{"class":311}," migrations\u002F0024_add_user_phone_down.sql\n",[24,6766,6767,6768],{},"代码回滚到上一个版本：",[100,6769,6771],{"className":298,"code":6770,"language":300,"meta":105,"style":105},"git revert \u003Cmerge-commit>\n",[107,6772,6773],{"__ignoreMap":105},[110,6774,6775,6777,6780,6783,6786,6789],{"class":112,"line":113},[110,6776,4733],{"class":307},[110,6778,6779],{"class":311}," revert",[110,6781,6782],{"class":1577}," \u003C",[110,6784,6785],{"class":311},"merge-commi",[110,6787,6788],{"class":123},"t",[110,6790,6791],{"class":1577},">\n",[24,6793,6794,6795],{},"验证：",[100,6796,6798],{"className":5851,"code":6797,"language":5853,"meta":105,"style":105},"\\d users  -- 确认 phone 字段已删\n",[107,6799,6800],{"__ignoreMap":105},[110,6801,6802,6805],{"class":112,"line":113},[110,6803,6804],{"class":123},"\\d users  ",[110,6806,6807],{"class":336},"-- 确认 phone 字段已删\n",[100,6809,6812],{"className":6810,"code":6811,"language":282},[280],"\n## 踩坑记录\n\n1. **PostgreSQL 11+ 加可空字段才是即时**——低版本加字段仍会锁表，先升级。\n2. **CONCURRENTLY 索引失败要手动清理**——失败后留 invalid index，`DROP INDEX` 后重建。\n3. **回填脚本要分批 + sleep**——大批量 UPDATE 会撑爆 WAL 和主从延迟。\n4. **NOT VALID + VALIDATE 两步走**——直接加 CHECK 会全表扫描锁表。\n5. **Claude 生成 SQL 必须 review**——AI 偶尔会忘加 WHERE 条件，删数据操作尤其要审。\n",[107,6813,6811],{"__ignoreMap":105},[700,6815,6816],{},"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 .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}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 .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}",{"title":105,"searchDepth":127,"depth":127,"links":6818},[6819,6820,6821,6822,6823,6824,6829,6830],{"id":15,"depth":120,"text":15},{"id":5769,"depth":120,"text":5769},{"id":5798,"depth":120,"text":5798},{"id":5807,"depth":120,"text":5808},{"id":5977,"depth":120,"text":5978},{"id":5990,"depth":120,"text":5991,"children":6825},[6826,6827,6828],{"id":5994,"depth":127,"text":5995},{"id":6317,"depth":127,"text":6317},{"id":6544,"depth":127,"text":6544},{"id":6602,"depth":120,"text":6603},{"id":6703,"depth":120,"text":6704},"migration","\u002Fog\u002Fplaybook\u002Fai-db-migration.png","数据库 schema 迁移最怕搞挂生产。用 Claude Code + Drizzle migrations 搭一套安全迁移流程——AI 生成迁移文件 → 自动检查兼容性 → 分阶段执行 → 验证 → 回滚方案。含大表加列、改类型等高危操作。",{},"\u002Fplaybook\u002Fmigration\u002Fai-db-migration",[1313,2575],{"title":5748,"description":6833},"playbook\u002Fmigration\u002Fai-db-migration",[6840,6841,6842,6843,1031],"数据库","迁移","Drizzle","零停机","tzaBre4cpBUCVMaO1qaWEjIwBDWReTAlQ9UMCOMI54A",{"id":6846,"title":6847,"body":6848,"category":717,"cover":7539,"description":7540,"extension":104,"meta":7541,"navigation":130,"path":7542,"published":5734,"relatedTools":7543,"seo":7544,"stem":7545,"tags":7546,"updated":5734,"__hash__":7549},"playbook\u002Fplaybook\u002Fonboarding\u002Fclaude-code-getting-started.md","Claude Code 从零上手：CLI AI 编程实战指南",{"type":10,"value":6849,"toc":7516},[6850,6852,6866,6870,6985,6991,6995,7033,7036,7079,7082,7103,7107,7110,7127,7130,7136,7139,7153,7157,7160,7166,7169,7173,7176,7182,7185,7202,7208,7212,7215,7221,7224,7230,7234,7237,7246,7398,7401,7404,7408,7413,7452,7455,7459,7466,7470,7473,7479,7481,7485,7488,7492,7499,7503,7506,7510,7513],[13,6851,15],{"id":15},[21,6853,6854,6857,6860,6863],{},[24,6855,6856],{},"想用 CLI 方式做 AI 编程（不依赖 IDE）",[24,6858,6859],{},"已有 Cursor \u002F Copilot，想试试 Claude 原生体验",[24,6861,6862],{},"需要在服务器 \u002F SSH 环境用 AI 编程",[24,6864,6865],{},"想用 Claude Sonnet 4 \u002F Opus 4 的完整能力",[13,6867,6869],{"id":6868},"claude-code-vs-cursor-vs-copilot","Claude Code vs Cursor vs Copilot",[440,6871,6872,6884],{},[443,6873,6874],{},[446,6875,6876,6878,6880,6882],{},[449,6877,1021],{},[449,6879,1031],{},[449,6881,3185],{},[449,6883,2573],{},[459,6885,6886,6899,6913,6926,6939,6952,6963,6974],{},[446,6887,6888,6890,6893,6896],{},[464,6889,3202],{},[464,6891,6892],{},"CLI",[464,6894,6895],{},"IDE",[464,6897,6898],{},"IDE 插件",[446,6900,6901,6904,6907,6910],{},[464,6902,6903],{},"模型",[464,6905,6906],{},"Claude 全系",[464,6908,6909],{},"多模型",[464,6911,6912],{},"GPT\u002FClaude",[446,6914,6915,6918,6921,6923],{},[464,6916,6917],{},"多文件修改",[464,6919,6920],{},"✅ 原生",[464,6922,1771],{},[464,6924,6925],{},"❌ 单文件",[446,6927,6928,6931,6934,6936],{},[464,6929,6930],{},"项目理解",[464,6932,6933],{},"✅ 自动索引",[464,6935,1771],{},[464,6937,6938],{},"部分",[446,6940,6941,6944,6947,6950],{},[464,6942,6943],{},"终端操作",[464,6945,6946],{},"✅ 直接执行",[464,6948,6949],{},"需切换",[464,6951,1744],{},[446,6953,6954,6957,6959,6961],{},[464,6955,6956],{},"Git 集成",[464,6958,6920],{},[464,6960,6938],{},[464,6962,6938],{},[446,6964,6965,6968,6970,6972],{},[464,6966,6967],{},"SSH\u002F服务器",[464,6969,1771],{},[464,6971,1744],{},[464,6973,1744],{},[446,6975,6976,6978,6981,6983],{},[464,6977,892],{},[464,6979,6980],{},"$20\u002F月（Max）",[464,6982,916],{},[464,6984,2935],{},[17,6986,6987,6990],{},[40,6988,6989],{},"Claude Code 的独特优势","：CLI 原生 + 终端操作 + SSH 可用。",[13,6992,6994],{"id":6993},"第一步安装","第一步：安装",[100,6996,6998],{"className":298,"code":6997,"language":300,"meta":105,"style":105},"# 需要 Node.js 18+\nnpm install -g @anthropic-ai\u002Fclaude-code\n\n# 验证\nclaude --version\n",[107,6999,7000,7005,7016,7020,7025],{"__ignoreMap":105},[110,7001,7002],{"class":112,"line":113},[110,7003,7004],{"class":336},"# 需要 Node.js 18+\n",[110,7006,7007,7009,7011,7013],{"class":112,"line":120},[110,7008,308],{"class":307},[110,7010,312],{"class":311},[110,7012,316],{"class":315},[110,7014,7015],{"class":311}," @anthropic-ai\u002Fclaude-code\n",[110,7017,7018],{"class":112,"line":127},[110,7019,131],{"emptyLinePlaceholder":130},[110,7021,7022],{"class":112,"line":134},[110,7023,7024],{"class":336},"# 验证\n",[110,7026,7027,7030],{"class":112,"line":140},[110,7028,7029],{"class":307},"claude",[110,7031,7032],{"class":315}," --version\n",[1834,7034,7035],{"id":7035},"认证",[100,7037,7039],{"className":298,"code":7038,"language":300,"meta":105,"style":105},"# 方式 1：用 Anthropic 账号（推荐，含 Max 订阅）\nclaude login\n\n# 方式 2：用 API Key（按量付费）\nexport ANTHROPIC_API_KEY=\"sk-ant-xxx\"\nclaude\n",[107,7040,7041,7046,7052,7056,7061,7074],{"__ignoreMap":105},[110,7042,7043],{"class":112,"line":113},[110,7044,7045],{"class":336},"# 方式 1：用 Anthropic 账号（推荐，含 Max 订阅）\n",[110,7047,7048,7050],{"class":112,"line":120},[110,7049,7029],{"class":307},[110,7051,327],{"class":311},[110,7053,7054],{"class":112,"line":127},[110,7055,131],{"emptyLinePlaceholder":130},[110,7057,7058],{"class":112,"line":134},[110,7059,7060],{"class":336},"# 方式 2：用 API Key（按量付费）\n",[110,7062,7063,7066,7069,7071],{"class":112,"line":140},[110,7064,7065],{"class":1577},"export",[110,7067,7068],{"class":123}," ANTHROPIC_API_KEY",[110,7070,1587],{"class":1577},[110,7072,7073],{"class":311},"\"sk-ant-xxx\"\n",[110,7075,7076],{"class":112,"line":150},[110,7077,7078],{"class":307},"claude\n",[17,7080,7081],{},"国内用户如果直连慢，可以配代理：",[100,7083,7085],{"className":298,"code":7084,"language":300,"meta":105,"style":105},"export HTTPS_PROXY=\"http:\u002F\u002F127.0.0.1:7890\"\nclaude\n",[107,7086,7087,7099],{"__ignoreMap":105},[110,7088,7089,7091,7094,7096],{"class":112,"line":113},[110,7090,7065],{"class":1577},[110,7092,7093],{"class":123}," HTTPS_PROXY",[110,7095,1587],{"class":1577},[110,7097,7098],{"class":311},"\"http:\u002F\u002F127.0.0.1:7890\"\n",[110,7100,7101],{"class":112,"line":120},[110,7102,7078],{"class":307},[13,7104,7106],{"id":7105},"第二步第一次使用","第二步：第一次使用",[17,7108,7109],{},"进入项目目录，启动 Claude Code：",[100,7111,7113],{"className":298,"code":7112,"language":300,"meta":105,"style":105},"cd my-project\nclaude\n",[107,7114,7115,7123],{"__ignoreMap":105},[110,7116,7117,7120],{"class":112,"line":113},[110,7118,7119],{"class":315},"cd",[110,7121,7122],{"class":311}," my-project\n",[110,7124,7125],{"class":112,"line":120},[110,7126,7078],{"class":307},[17,7128,7129],{},"进入交互式 REPL。几个基本操作：",[100,7131,7134],{"className":7132,"code":7133,"language":282,"meta":105},[280],"> 帮我理解这个项目的结构          # 项目理解\n> 找到处理用户登录的代码          # 代码定位\n> 把这个函数改成支持异步          # 代码修改\n> 跑一下测试看看有没有 break      # 执行命令\n",[107,7135,7133],{"__ignoreMap":105},[17,7137,7138],{},"Claude Code 会自动：",[415,7140,7141,7144,7147,7150],{},[24,7142,7143],{},"扫描项目文件结构",[24,7145,7146],{},"读 package.json \u002F README 理解技术栈",[24,7148,7149],{},"找到相关文件",[24,7151,7152],{},"提出修改方案（需你确认后执行）",[13,7154,7156],{"id":7155},"第三步项目理解工作流","第三步：项目理解工作流",[17,7158,7159],{},"新接手一个项目时的标准操作：",[100,7161,7164],{"className":7162,"code":7163,"language":282,"meta":105},[280],"> 先读 README 和 package.json，告诉我这个项目是做什么的、用了什么技术栈\n\n> 画出项目的目录结构，标注每个目录的职责\n\n> 找到项目的入口文件，解释启动流程\n\n> 这个项目的数据流是怎样的？从 API 请求到数据库的完整路径\n\n> 找到所有 TODO 和 FIXME，按优先级排序\n",[107,7165,7163],{"__ignoreMap":105},[17,7167,7168],{},"Claude Code 会实际读取文件并分析，不是瞎猜。",[13,7170,7172],{"id":7171},"第四步多文件修改","第四步：多文件修改",[17,7174,7175],{},"这是 Claude Code 最强的能力。举个例子：",[100,7177,7180],{"className":7178,"code":7179,"language":282,"meta":105},[280],"> 我需要加一个\"用户头像上传\"功能。需要：\n> 1. 后端 API（上传到 S3）\n> 2. 前端组件（拖拽上传 + 预览）\n> 3. 数据库加 avatar_url 字段\n> 4. 用户 profile 页面显示头像\n> 先看一下现有代码结构，告诉我你的计划，我确认后再动手\n",[107,7181,7179],{"__ignoreMap":105},[17,7183,7184],{},"Claude Code 会：",[415,7186,7187,7190,7193,7196,7199],{},[24,7188,7189],{},"扫描相关文件（后端路由、前端组件、数据库 schema）",[24,7191,7192],{},"给出修改计划（改哪些文件、每个文件改什么）",[24,7194,7195],{},"等你确认",[24,7197,7198],{},"一次性修改多个文件",[24,7200,7201],{},"跑测试验证",[17,7203,7204,7207],{},[40,7205,7206],{},"关键","：先说\"告诉我计划\"，确认后再让它动手。避免改出一堆你不想要的东西。",[13,7209,7211],{"id":7210},"第五步git-工作流","第五步：Git 工作流",[17,7213,7214],{},"Claude Code 原生支持 git 操作：",[100,7216,7219],{"className":7217,"code":7218,"language":282,"meta":105},[280],"> 看一下当前的 git diff，帮我写 commit message\n\n> 帮我把这个改动拆成 3 个独立的 commit（按逻辑分组）\n\n> 创建一个分支 feature\u002Favatar-upload，把改动提交上去\n",[107,7220,7218],{"__ignoreMap":105},[17,7222,7223],{},"推荐工作流：",[100,7225,7228],{"className":7226,"code":7227,"language":282,"meta":105},[280],"1. claude  # 启动\n2. \"在 feature 分支上实现 XXX 功能\"  # 让它创建分支 + 改代码\n3. \"跑测试\"  # 验证\n4. \"看一下 diff，写 commit message\"  # 提交\n5. 退出后自己 git push + 开 PR\n",[107,7229,7227],{"__ignoreMap":105},[13,7231,7233],{"id":7232},"第六步mcp-集成","第六步：MCP 集成",[17,7235,7236],{},"Claude Code 支持连接 MCP Server，扩展能力：",[100,7238,7240],{"className":298,"code":7239,"language":300,"meta":105,"style":105},"# 配置文件位置：~\u002F.claude\u002Fmcp_servers.json\n",[107,7241,7242],{"__ignoreMap":105},[110,7243,7244],{"class":112,"line":113},[110,7245,7239],{"class":336},[100,7247,7251],{"className":7248,"code":7249,"language":7250,"meta":105,"style":105},"language-json shiki shiki-themes github-light github-dark","{\n  \"mcpServers\": {\n    \"postgres\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@modelcontextprotocol\u002Fserver-postgres\"],\n      \"env\": {\n        \"DATABASE_URL\": \"postgresql:\u002F\u002F...\"\n      }\n    },\n    \"github\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@modelcontextprotocol\u002Fserver-github\"],\n      \"env\": {\n        \"GITHUB_TOKEN\": \"ghp_xxx\"\n      }\n    }\n  }\n}\n","json",[107,7252,7253,7258,7266,7273,7286,7304,7311,7321,7326,7331,7338,7348,7363,7369,7379,7383,7388,7393],{"__ignoreMap":105},[110,7254,7255],{"class":112,"line":113},[110,7256,7257],{"class":123},"{\n",[110,7259,7260,7263],{"class":112,"line":120},[110,7261,7262],{"class":315},"  \"mcpServers\"",[110,7264,7265],{"class":123},": {\n",[110,7267,7268,7271],{"class":112,"line":127},[110,7269,7270],{"class":315},"    \"postgres\"",[110,7272,7265],{"class":123},[110,7274,7275,7278,7280,7283],{"class":112,"line":134},[110,7276,7277],{"class":315},"      \"command\"",[110,7279,4919],{"class":123},[110,7281,7282],{"class":311},"\"npx\"",[110,7284,7285],{"class":123},",\n",[110,7287,7288,7291,7293,7296,7298,7301],{"class":112,"line":140},[110,7289,7290],{"class":315},"      \"args\"",[110,7292,4945],{"class":123},[110,7294,7295],{"class":311},"\"-y\"",[110,7297,5083],{"class":123},[110,7299,7300],{"class":311},"\"@modelcontextprotocol\u002Fserver-postgres\"",[110,7302,7303],{"class":123},"],\n",[110,7305,7306,7309],{"class":112,"line":150},[110,7307,7308],{"class":315},"      \"env\"",[110,7310,7265],{"class":123},[110,7312,7313,7316,7318],{"class":112,"line":5},[110,7314,7315],{"class":315},"        \"DATABASE_URL\"",[110,7317,4919],{"class":123},[110,7319,7320],{"class":311},"\"postgresql:\u002F\u002F...\"\n",[110,7322,7323],{"class":112,"line":162},[110,7324,7325],{"class":123},"      }\n",[110,7327,7328],{"class":112,"line":168},[110,7329,7330],{"class":123},"    },\n",[110,7332,7333,7336],{"class":112,"line":177},[110,7334,7335],{"class":315},"    \"github\"",[110,7337,7265],{"class":123},[110,7339,7340,7342,7344,7346],{"class":112,"line":186},[110,7341,7277],{"class":315},[110,7343,4919],{"class":123},[110,7345,7282],{"class":311},[110,7347,7285],{"class":123},[110,7349,7350,7352,7354,7356,7358,7361],{"class":112,"line":195},[110,7351,7290],{"class":315},[110,7353,4945],{"class":123},[110,7355,7295],{"class":311},[110,7357,5083],{"class":123},[110,7359,7360],{"class":311},"\"@modelcontextprotocol\u002Fserver-github\"",[110,7362,7303],{"class":123},[110,7364,7365,7367],{"class":112,"line":204},[110,7366,7308],{"class":315},[110,7368,7265],{"class":123},[110,7370,7371,7374,7376],{"class":112,"line":209},[110,7372,7373],{"class":315},"        \"GITHUB_TOKEN\"",[110,7375,4919],{"class":123},[110,7377,7378],{"class":311},"\"ghp_xxx\"\n",[110,7380,7381],{"class":112,"line":215},[110,7382,7325],{"class":123},[110,7384,7385],{"class":112,"line":221},[110,7386,7387],{"class":123},"    }\n",[110,7389,7390],{"class":112,"line":226},[110,7391,7392],{"class":123},"  }\n",[110,7394,7395],{"class":112,"line":232},[110,7396,7397],{"class":123},"}\n",[17,7399,7400],{},"配置后，Claude Code 可以直接查数据库、操作 GitHub。",[13,7402,7403],{"id":7403},"常用技巧",[1834,7405,7407],{"id":7406},"_1-用-claudemd-固化项目约定","1. 用 CLAUDE.md 固化项目约定",[17,7409,7410,7411,953],{},"在项目根目录创建 ",[107,7412,4354],{},[100,7414,7416],{"className":6710,"code":7415,"language":6712,"meta":105,"style":105},"# 项目约定\n\n- 用 pnpm 不用 npm\n- 测试用 vitest，跑 `pnpm test`\n- 提交前跑 `pnpm lint`\n- Vue 组件用 \u003Cscript setup>\n- 不要用 any，所有变量都要有类型\n",[107,7417,7418,7423,7427,7432,7437,7442,7447],{"__ignoreMap":105},[110,7419,7420],{"class":112,"line":113},[110,7421,7422],{},"# 项目约定\n",[110,7424,7425],{"class":112,"line":120},[110,7426,131],{"emptyLinePlaceholder":130},[110,7428,7429],{"class":112,"line":127},[110,7430,7431],{},"- 用 pnpm 不用 npm\n",[110,7433,7434],{"class":112,"line":134},[110,7435,7436],{},"- 测试用 vitest，跑 `pnpm test`\n",[110,7438,7439],{"class":112,"line":140},[110,7440,7441],{},"- 提交前跑 `pnpm lint`\n",[110,7443,7444],{"class":112,"line":150},[110,7445,7446],{},"- Vue 组件用 \u003Cscript setup>\n",[110,7448,7449],{"class":112,"line":5},[110,7450,7451],{},"- 不要用 any，所有变量都要有类型\n",[17,7453,7454],{},"Claude Code 每次启动会自动读取，不用每次重复说。",[1834,7456,7458],{"id":7457},"_2-用-compact-压缩上下文","2. 用 \u002Fcompact 压缩上下文",[17,7460,7461,7462,7465],{},"聊了很久后上下文会满，用 ",[107,7463,7464],{},"\u002Fcompact"," 压缩历史对话，保留关键信息。",[1834,7467,7469],{"id":7468},"_3-子-agent-并发","3. 子 Agent 并发",[17,7471,7472],{},"复杂任务可以让 Claude Code 开子 Agent 并行处理：",[100,7474,7477],{"className":7475,"code":7476,"language":282,"meta":105},[280],"> 用 3 个并行子任务：\n> 1. 修复 auth 模块的 bug\n> 2. 给 API 模块加测试\n> 3. 重构 utils 模块\n> 分别完成后汇总给我\n",[107,7478,7476],{"__ignoreMap":105},[13,7480,5672],{"id":5672},[1834,7482,7484],{"id":7483},"坑-1大项目首次索引慢","坑 1：大项目首次索引慢",[17,7486,7487],{},"10 万行以上的项目，首次启动会花 1-2 分钟扫描。后续有缓存会快。",[1834,7489,7491],{"id":7490},"坑-2会主动改你不想改的文件","坑 2：会主动改你不想改的文件",[17,7493,7494,7495,7498],{},"Claude Code 有时会\"顺手\"改一些你没要求的文件（比如格式化）。用 ",[107,7496,7497],{},"--allowedTools"," 限制它只能用特定工具。",[1834,7500,7502],{"id":7501},"坑-3国内网络","坑 3：国内网络",[17,7504,7505],{},"Anthropic API 在国内不稳定。必须配代理，否则会频繁超时。",[1834,7507,7509],{"id":7508},"坑-4token-消耗快","坑 4：Token 消耗快",[17,7511,7512],{},"Sonnet 4 做大型重构时，一次任务可能消耗 50 万+ token。用 Max 订阅（$200\u002F月）比 API 按量付费划算。",[700,7514,7515],{},"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 .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 .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}",{"title":105,"searchDepth":127,"depth":127,"links":7517},[7518,7519,7520,7523,7524,7525,7526,7527,7528,7533],{"id":15,"depth":120,"text":15},{"id":6868,"depth":120,"text":6869},{"id":6993,"depth":120,"text":6994,"children":7521},[7522],{"id":7035,"depth":127,"text":7035},{"id":7105,"depth":120,"text":7106},{"id":7155,"depth":120,"text":7156},{"id":7171,"depth":120,"text":7172},{"id":7210,"depth":120,"text":7211},{"id":7232,"depth":120,"text":7233},{"id":7403,"depth":120,"text":7403,"children":7529},[7530,7531,7532],{"id":7406,"depth":127,"text":7407},{"id":7457,"depth":127,"text":7458},{"id":7468,"depth":127,"text":7469},{"id":5672,"depth":120,"text":5672,"children":7534},[7535,7536,7537,7538],{"id":7483,"depth":127,"text":7484},{"id":7490,"depth":127,"text":7491},{"id":7501,"depth":127,"text":7502},{"id":7508,"depth":127,"text":7509},"\u002Fog\u002Fplaybook\u002Fclaude-code-getting-started.png","Anthropic 官方 CLI 工具 Claude Code 30 分钟上手——安装配置、项目理解、多文件修改、git 工作流、MCP 集成、子 Agent 并发，含真实项目踩坑记录。",{},"\u002Fplaybook\u002Fonboarding\u002Fclaude-code-getting-started",[1313,2575,4862],{"title":6847,"description":7540},"playbook\u002Fonboarding\u002Fclaude-code-getting-started",[1031,6892,7547,7548],"AI 编程","Anthropic","iY5IsM7_Dx24z0nrqr2srrkmMB01rtDVKpKWe9B0Fz0",{"id":7551,"title":7552,"body":7553,"category":717,"cover":8261,"description":8262,"extension":104,"meta":8263,"navigation":130,"path":8264,"published":5734,"relatedTools":8265,"seo":8269,"stem":8270,"tags":8271,"updated":5734,"__hash__":8273},"playbook\u002Fplaybook\u002Fonboarding\u002Fcursor-mcp-database.md","Cursor + MCP 让 AI 直接操作数据库：从零到生产",{"type":10,"value":7554,"toc":8244},[7555,7557,7568,7572,7579,7582,7589,7593,7596,7620,7623,7699,7702,7706,7709,7715,7816,7820,7897,7903,7906,7909,7994,7998,8002,8005,8011,8014,8032,8036,8042,8044,8062,8066,8072,8074,8091,8094,8164,8170,8172,8241],[13,7556,15],{"id":15},[21,7558,7559,7562,7565],{},[24,7560,7561],{},"开发时频繁需要查表结构、跑 SQL 验证",[24,7563,7564],{},"AI 生成代码时需要知道数据库 schema",[24,7566,7567],{},"想让 AI 帮写数据库迁移文件",[13,7569,7571],{"id":7570},"为什么用-mcp-而不是复制粘贴","为什么用 MCP 而不是复制粘贴",[17,7573,7574,7575,7578],{},"传统做法：手动跑 ",[107,7576,7577],{},"\\d table_name"," → 复制结果 → 粘给 Cursor → AI 生成 SQL → 手动执行验证。",[17,7580,7581],{},"MCP 做法：Cursor 直接连数据库 → AI 自己查 schema → 生成 SQL → 自己执行验证 → 返回结果。",[17,7583,7584,7585,7588],{},"省的是",[40,7586,7587],{},"中间的复制粘贴往返","。在复杂查询调试时，这个往返可能 5-10 次。",[13,7590,7592],{"id":7591},"第一步装-mcp-postgresql-server","第一步：装 MCP PostgreSQL Server",[17,7594,7595],{},"用 Smithery 一行装好：",[100,7597,7599],{"className":298,"code":7598,"language":300,"meta":105,"style":105},"npx @smithery\u002Fcli install @modelcontextprotocol\u002Fserver-postgres --client cursor\n",[107,7600,7601],{"__ignoreMap":105},[110,7602,7603,7606,7609,7611,7614,7617],{"class":112,"line":113},[110,7604,7605],{"class":307},"npx",[110,7607,7608],{"class":311}," @smithery\u002Fcli",[110,7610,312],{"class":311},[110,7612,7613],{"class":311}," @modelcontextprotocol\u002Fserver-postgres",[110,7615,7616],{"class":315}," --client",[110,7618,7619],{"class":311}," cursor\n",[17,7621,7622],{},"或手动配 Cursor Settings → MCP → Add Server：",[100,7624,7626],{"className":7248,"code":7625,"language":7250,"meta":105,"style":105},"{\n  \"mcpServers\": {\n    \"postgres\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@modelcontextprotocol\u002Fserver-postgres\"],\n      \"env\": {\n        \"DATABASE_URL\": \"postgresql:\u002F\u002Fuser:pass@localhost:5432\u002Fmydb\"\n      }\n    }\n  }\n}\n",[107,7627,7628,7632,7638,7644,7654,7668,7674,7683,7687,7691,7695],{"__ignoreMap":105},[110,7629,7630],{"class":112,"line":113},[110,7631,7257],{"class":123},[110,7633,7634,7636],{"class":112,"line":120},[110,7635,7262],{"class":315},[110,7637,7265],{"class":123},[110,7639,7640,7642],{"class":112,"line":127},[110,7641,7270],{"class":315},[110,7643,7265],{"class":123},[110,7645,7646,7648,7650,7652],{"class":112,"line":134},[110,7647,7277],{"class":315},[110,7649,4919],{"class":123},[110,7651,7282],{"class":311},[110,7653,7285],{"class":123},[110,7655,7656,7658,7660,7662,7664,7666],{"class":112,"line":140},[110,7657,7290],{"class":315},[110,7659,4945],{"class":123},[110,7661,7295],{"class":311},[110,7663,5083],{"class":123},[110,7665,7300],{"class":311},[110,7667,7303],{"class":123},[110,7669,7670,7672],{"class":112,"line":150},[110,7671,7308],{"class":315},[110,7673,7265],{"class":123},[110,7675,7676,7678,7680],{"class":112,"line":5},[110,7677,7315],{"class":315},[110,7679,4919],{"class":123},[110,7681,7682],{"class":311},"\"postgresql:\u002F\u002Fuser:pass@localhost:5432\u002Fmydb\"\n",[110,7684,7685],{"class":112,"line":162},[110,7686,7325],{"class":123},[110,7688,7689],{"class":112,"line":168},[110,7690,7387],{"class":123},[110,7692,7693],{"class":112,"line":177},[110,7694,7392],{"class":123},[110,7696,7697],{"class":112,"line":186},[110,7698,7397],{"class":123},[17,7700,7701],{},"重启 Cursor，Agent 模式现在能查数据库了。",[13,7703,7705],{"id":7704},"第二步安全配置重要","第二步：安全配置（重要）",[1834,7707,7708],{"id":7708},"用只读账号",[17,7710,7711,7714],{},[40,7712,7713],{},"绝对不要用超级用户账号连 MCP。"," 创建只读账号：",[100,7716,7718],{"className":5851,"code":7717,"language":5853,"meta":105,"style":105},"CREATE ROLE mcp_readonly WITH LOGIN PASSWORD 'xxx';\nGRANT USAGE ON SCHEMA public TO mcp_readonly;\nGRANT SELECT ON ALL TABLES IN SCHEMA public TO mcp_readonly;\nALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO mcp_readonly;\n",[107,7719,7720,7744,7765,7787],{"__ignoreMap":105},[110,7721,7722,7724,7727,7730,7733,7736,7739,7742],{"class":112,"line":113},[110,7723,5903],{"class":1577},[110,7725,7726],{"class":1577}," ROLE",[110,7728,7729],{"class":123}," mcp_readonly ",[110,7731,7732],{"class":1577},"WITH",[110,7734,7735],{"class":1577}," LOGIN",[110,7737,7738],{"class":1577}," PASSWORD",[110,7740,7741],{"class":311}," 'xxx'",[110,7743,5927],{"class":123},[110,7745,7746,7749,7752,7754,7757,7760,7762],{"class":112,"line":120},[110,7747,7748],{"class":1577},"GRANT",[110,7750,7751],{"class":123}," USAGE ",[110,7753,6592],{"class":1577},[110,7755,7756],{"class":1577}," SCHEMA",[110,7758,7759],{"class":123}," public ",[110,7761,6539],{"class":1577},[110,7763,7764],{"class":123}," mcp_readonly;\n",[110,7766,7767,7769,7772,7774,7777,7779,7781,7783,7785],{"class":112,"line":127},[110,7768,7748],{"class":1577},[110,7770,7771],{"class":1577}," SELECT",[110,7773,5912],{"class":1577},[110,7775,7776],{"class":123}," ALL TABLES ",[110,7778,6153],{"class":1577},[110,7780,7756],{"class":1577},[110,7782,7759],{"class":123},[110,7784,6539],{"class":1577},[110,7786,7764],{"class":123},[110,7788,7789,7791,7794,7797,7799,7801,7803,7805,7807,7809,7812,7814],{"class":112,"line":134},[110,7790,5874],{"class":1577},[110,7792,7793],{"class":1577}," DEFAULT",[110,7795,7796],{"class":123}," PRIVILEGES ",[110,7798,6153],{"class":1577},[110,7800,7756],{"class":1577},[110,7802,7759],{"class":123},[110,7804,7748],{"class":1577},[110,7806,7771],{"class":1577},[110,7808,5912],{"class":1577},[110,7810,7811],{"class":123}," TABLES ",[110,7813,6539],{"class":1577},[110,7815,7764],{"class":123},[1834,7817,7819],{"id":7818},"开发生产隔离","开发\u002F生产隔离",[100,7821,7823],{"className":7248,"code":7822,"language":7250,"meta":105,"style":105},"{\n  \"mcpServers\": {\n    \"postgres-dev\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@modelcontextprotocol\u002Fserver-postgres\"],\n      \"env\": {\n        \"DATABASE_URL\": \"postgresql:\u002F\u002Fmcp_readonly:xxx@localhost:5432\u002Fmydb_dev\"\n      }\n    }\n  }\n}\n",[107,7824,7825,7829,7835,7842,7852,7866,7872,7881,7885,7889,7893],{"__ignoreMap":105},[110,7826,7827],{"class":112,"line":113},[110,7828,7257],{"class":123},[110,7830,7831,7833],{"class":112,"line":120},[110,7832,7262],{"class":315},[110,7834,7265],{"class":123},[110,7836,7837,7840],{"class":112,"line":127},[110,7838,7839],{"class":315},"    \"postgres-dev\"",[110,7841,7265],{"class":123},[110,7843,7844,7846,7848,7850],{"class":112,"line":134},[110,7845,7277],{"class":315},[110,7847,4919],{"class":123},[110,7849,7282],{"class":311},[110,7851,7285],{"class":123},[110,7853,7854,7856,7858,7860,7862,7864],{"class":112,"line":140},[110,7855,7290],{"class":315},[110,7857,4945],{"class":123},[110,7859,7295],{"class":311},[110,7861,5083],{"class":123},[110,7863,7300],{"class":311},[110,7865,7303],{"class":123},[110,7867,7868,7870],{"class":112,"line":150},[110,7869,7308],{"class":315},[110,7871,7265],{"class":123},[110,7873,7874,7876,7878],{"class":112,"line":5},[110,7875,7315],{"class":315},[110,7877,4919],{"class":123},[110,7879,7880],{"class":311},"\"postgresql:\u002F\u002Fmcp_readonly:xxx@localhost:5432\u002Fmydb_dev\"\n",[110,7882,7883],{"class":112,"line":162},[110,7884,7325],{"class":123},[110,7886,7887],{"class":112,"line":168},[110,7888,7387],{"class":123},[110,7890,7891],{"class":112,"line":177},[110,7892,7392],{"class":123},[110,7894,7895],{"class":112,"line":186},[110,7896,7397],{"class":123},[17,7898,7899,7902],{},[40,7900,7901],{},"只在 dev 环境配 MCP","。生产数据库永远不连 MCP。",[1834,7904,7905],{"id":7905},"限制可查的表",[17,7907,7908],{},"如果有些表（用户密码、token）不想让 AI 看到，用视图：",[100,7910,7912],{"className":5851,"code":7911,"language":5853,"meta":105,"style":105},"CREATE VIEW public_safe.users_safe AS\n  SELECT id, username, created_at FROM public.users;\n\nREVOKE SELECT ON public.users FROM mcp_readonly;\nGRANT SELECT ON public_safe.users_safe TO mcp_readonly;\n",[107,7913,7914,7930,7950,7954,7974],{"__ignoreMap":105},[110,7915,7916,7918,7921,7924,7927],{"class":112,"line":113},[110,7917,5903],{"class":1577},[110,7919,7920],{"class":1577}," VIEW",[110,7922,7923],{"class":307}," public_safe",[110,7925,7926],{"class":123},".users_safe ",[110,7928,7929],{"class":1577},"AS\n",[110,7931,7932,7935,7938,7940,7943,7945,7948],{"class":112,"line":120},[110,7933,7934],{"class":1577},"  SELECT",[110,7936,7937],{"class":123}," id, username, created_at ",[110,7939,6166],{"class":1577},[110,7941,7942],{"class":315}," public",[110,7944,6230],{"class":123},[110,7946,7947],{"class":315},"users",[110,7949,5927],{"class":123},[110,7951,7952],{"class":112,"line":127},[110,7953,131],{"emptyLinePlaceholder":130},[110,7955,7956,7959,7961,7963,7965,7967,7969,7972],{"class":112,"line":134},[110,7957,7958],{"class":1577},"REVOKE",[110,7960,7771],{"class":1577},[110,7962,5912],{"class":1577},[110,7964,7942],{"class":315},[110,7966,6230],{"class":123},[110,7968,7947],{"class":315},[110,7970,7971],{"class":1577}," FROM",[110,7973,7764],{"class":123},[110,7975,7976,7978,7980,7982,7984,7986,7989,7992],{"class":112,"line":140},[110,7977,7748],{"class":1577},[110,7979,7771],{"class":1577},[110,7981,5912],{"class":1577},[110,7983,7923],{"class":315},[110,7985,6230],{"class":123},[110,7987,7988],{"class":315},"users_safe",[110,7990,7991],{"class":1577}," TO",[110,7993,7764],{"class":123},[13,7995,7997],{"id":7996},"第三步实战用法","第三步：实战用法",[1834,7999,8001],{"id":8000},"场景一查-schema-生成代码","场景一：查 schema 生成代码",[17,8003,8004],{},"在 Cursor Agent 模式输入：",[100,8006,8009],{"className":8007,"code":8008,"language":282},[280],"帮我写一个查询用户订单的 API，需要分页\n",[107,8010,8008],{"__ignoreMap":105},[17,8012,8013],{},"Cursor 会：",[415,8015,8016,8023,8029],{},[24,8017,8018,8019,8022],{},"调 MCP ",[107,8020,8021],{},"list_tables"," 看有哪些表",[24,8024,8018,8025,8028],{},[107,8026,8027],{},"describe_table"," 看 orders 和 users 表结构",[24,8030,8031],{},"生成 JOIN 查询 + 分页代码",[1834,8033,8035],{"id":8034},"场景二调试-sql","场景二：调试 SQL",[100,8037,8040],{"className":8038,"code":8039,"language":282},[280],"这个查询很慢，帮我优化\nSELECT * FROM orders o JOIN users u ON o.user_id = u.id WHERE o.status = 'pending'\n",[107,8041,8039],{"__ignoreMap":105},[17,8043,8013],{},[415,8045,8046,8053,8056,8059],{},[24,8047,8048,8049,8052],{},"跑 ",[107,8050,8051],{},"EXPLAIN ANALYZE"," 看执行计划",[24,8054,8055],{},"发现全表扫描",[24,8057,8058],{},"建议加索引",[24,8060,8061],{},"生成 migration 文件",[1834,8063,8065],{"id":8064},"场景三生成迁移","场景三：生成迁移",[100,8067,8070],{"className":8068,"code":8069,"language":282},[280],"给 orders 表加一个 shipping_address 字段，类型 jsonb，可空\n",[107,8071,8069],{"__ignoreMap":105},[17,8073,8013],{},[415,8075,8076,8079,8086,8089],{},[24,8077,8078],{},"查当前 orders 表结构",[24,8080,8081,8082,8085],{},"生成 ",[107,8083,8084],{},"ALTER TABLE"," SQL",[24,8087,8088],{},"生成 Drizzle\u002FPrisma migration 文件",[24,8090,5834],{},[13,8092,8093],{"id":8093},"权限边界",[440,8095,8096,8108],{},[443,8097,8098],{},[446,8099,8100,8102,8105],{},[449,8101,5523],{},[449,8103,8104],{},"只读 MCP",[449,8106,8107],{},"可写 MCP",[459,8109,8110,8119,8128,8137,8146,8156],{},[446,8111,8112,8115,8117],{},[464,8113,8114],{},"查表结构",[464,8116,1771],{},[464,8118,1771],{},[446,8120,8121,8124,8126],{},[464,8122,8123],{},"SELECT 查询",[464,8125,1771],{},[464,8127,1771],{},[446,8129,8130,8133,8135],{},[464,8131,8132],{},"EXPLAIN",[464,8134,1771],{},[464,8136,1771],{},[446,8138,8139,8142,8144],{},[464,8140,8141],{},"INSERT\u002FUPDATE\u002FDELETE",[464,8143,1744],{},[464,8145,1771],{},[446,8147,8148,8151,8153],{},[464,8149,8150],{},"CREATE\u002FDROP TABLE",[464,8152,1744],{},[464,8154,8155],{},"⚠️ 需额外授权",[446,8157,8158,8160,8162],{},[464,8159,8084],{},[464,8161,1744],{},[464,8163,8155],{},[17,8165,8166,8169],{},[40,8167,8168],{},"建议","：日常用只读 MCP，需要写操作时切到可写 MCP 并加确认步骤。",[13,8171,5672],{"id":5672},[415,8173,8174,8180,8219,8225],{},[24,8175,8176,8179],{},[40,8177,8178],{},"MCP Server 连接池","：默认无连接池，大量查询会打满 PG 连接。用 PgBouncer 做连接池。",[24,8181,8182,8185,8186,8189,8190,8193,8194],{},[40,8183,8184],{},"大表 SELECT","：AI 可能跑 ",[107,8187,8188],{},"SELECT * FROM huge_table","。设 ",[107,8191,8192],{},"statement_timeout"," 防止卡死：\n",[100,8195,8197],{"className":5851,"code":8196,"language":5853,"meta":105,"style":105},"ALTER ROLE mcp_readonly SET statement_timeout = '10s';\n",[107,8198,8199],{"__ignoreMap":105},[110,8200,8201,8203,8205,8207,8209,8212,8214,8217],{"class":112,"line":113},[110,8202,5874],{"class":1577},[110,8204,7726],{"class":1577},[110,8206,7729],{"class":123},[110,8208,6137],{"class":1577},[110,8210,8211],{"class":123}," statement_timeout ",[110,8213,1587],{"class":1577},[110,8215,8216],{"class":311}," '10s'",[110,8218,5927],{"class":123},[24,8220,8221,8224],{},[40,8222,8223],{},"Cursor MCP 不支持事务","：每个 SQL 是独立执行，不能 BEGIN\u002FCOMMIT。多步操作用存储过程。",[24,8226,8227,953,8230,8233,8234,8237,8238,43],{},[40,8228,8229],{},"DATABASE_URL 泄露",[107,8231,8232],{},".cursor\u002Fmcp.json"," 可能被 git 提交。加到 ",[107,8235,8236],{},".gitignore","，用 ",[107,8239,8240],{},".cursor\u002Fmcp.local.json",[700,8242,8243],{},"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 .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}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}",{"title":105,"searchDepth":127,"depth":127,"links":8245},[8246,8247,8248,8249,8254,8259,8260],{"id":15,"depth":120,"text":15},{"id":7570,"depth":120,"text":7571},{"id":7591,"depth":120,"text":7592},{"id":7704,"depth":120,"text":7705,"children":8250},[8251,8252,8253],{"id":7708,"depth":127,"text":7708},{"id":7818,"depth":127,"text":7819},{"id":7905,"depth":127,"text":7905},{"id":7996,"depth":120,"text":7997,"children":8255},[8256,8257,8258],{"id":8000,"depth":127,"text":8001},{"id":8034,"depth":127,"text":8035},{"id":8064,"depth":127,"text":8065},{"id":8093,"depth":120,"text":8093},{"id":5672,"depth":120,"text":5672},"\u002Fog\u002Fplaybook\u002Fcursor-mcp-database.png","用 MCP 协议让 Cursor \u002F Claude Code 直接读写 PostgreSQL——AI 能查表结构、跑 SQL、生成迁移文件。含安全配置、权限边界和踩坑记录。",{},"\u002Fplaybook\u002Fonboarding\u002Fcursor-mcp-database",[8266,8267,8268,2575],"agent\u002Fprotocol\u002Fsmithery","agent\u002Fprotocol\u002Fcomposio","agent\u002Fprotocol\u002Fmcp-toolbox",{"title":7552,"description":8262},"playbook\u002Fonboarding\u002Fcursor-mcp-database",[2595,3185,8272,6840],"PostgreSQL","Xz0aDqhIFWiE0v5sBvsHZqBKQn_S_xNSzHCeNesIXxA",{"id":8275,"title":8276,"body":8277,"category":717,"cover":9243,"description":9244,"extension":104,"meta":9245,"navigation":130,"path":9246,"published":5734,"relatedTools":9247,"seo":9248,"stem":9249,"tags":9250,"updated":5734,"__hash__":9252},"playbook\u002Fplaybook\u002Fonboarding\u002Fcursor-mcp-deep-integration.md","Cursor + MCP 深度集成：让 AI IDE 连接一切",{"type":10,"value":8278,"toc":9214},[8279,8281,8292,8296,8299,8310,8316,8320,8330,8409,8412,8416,8420,8423,8485,8488,8504,8508,8511,8587,8589,8603,8607,8610,8674,8678,8681,8760,8763,8767,8770,8829,8832,8836,8839,8898,8901,8905,8909,8915,8918,8937,8941,8947,8949,8969,8973,8979,8981,9001,9004,9007,9010,9014,9029,9032,9053,9087,9091,9099,9102,9106,9109,9121,9124,9127,9135,9139,9206,9211],[13,8280,15],{"id":15},[21,8282,8283,8286,8289],{},[24,8284,8285],{},"已在用 Cursor，想让 AI 能直接查数据库 \u002F 操作 GitHub",[24,8287,8288],{},"想让 AI 在写代码时能访问外部 API（Slack、Jira、Linear）",[24,8290,8291],{},"想构建\"AI 能看能做\"的开发环境，不只是\"AI 建议、人执行\"",[13,8293,8295],{"id":8294},"mcp-在-cursor-中的定位","MCP 在 Cursor 中的定位",[17,8297,8298],{},"Cursor 0.42+ 原生支持 MCP。配置 MCP Server 后：",[21,8300,8301,8304,8307],{},[24,8302,8303],{},"AI Agent 模式下可以调用 MCP 工具",[24,8305,8306],{},"AI 能看到工具的返回结果，基于结果继续推理",[24,8308,8309],{},"不需要离开 IDE 去查数据库 \u002F 看 GitHub Issue",[17,8311,8312,8315],{},[40,8313,8314],{},"本质","：把\"复制粘贴往返\"变成\"AI 直接操作\"。",[13,8317,8319],{"id":8318},"第一步理解-mcp-配置","第一步：理解 MCP 配置",[17,8321,8322,8323,8326,8327,8329],{},"Cursor 的 MCP 配置在 ",[107,8324,8325],{},"~\u002F.cursor\u002Fmcp.json","（全局）或项目根目录 ",[107,8328,8232],{},"（项目级）。",[100,8331,8333],{"className":7248,"code":8332,"language":7250,"meta":105,"style":105},"{\n  \"mcpServers\": {\n    \"server-name\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@mcp\u002Fserver-package\"],\n      \"env\": {\n        \"API_KEY\": \"xxx\"\n      }\n    }\n  }\n}\n",[107,8334,8335,8339,8345,8352,8362,8377,8383,8393,8397,8401,8405],{"__ignoreMap":105},[110,8336,8337],{"class":112,"line":113},[110,8338,7257],{"class":123},[110,8340,8341,8343],{"class":112,"line":120},[110,8342,7262],{"class":315},[110,8344,7265],{"class":123},[110,8346,8347,8350],{"class":112,"line":127},[110,8348,8349],{"class":315},"    \"server-name\"",[110,8351,7265],{"class":123},[110,8353,8354,8356,8358,8360],{"class":112,"line":134},[110,8355,7277],{"class":315},[110,8357,4919],{"class":123},[110,8359,7282],{"class":311},[110,8361,7285],{"class":123},[110,8363,8364,8366,8368,8370,8372,8375],{"class":112,"line":140},[110,8365,7290],{"class":315},[110,8367,4945],{"class":123},[110,8369,7295],{"class":311},[110,8371,5083],{"class":123},[110,8373,8374],{"class":311},"\"@mcp\u002Fserver-package\"",[110,8376,7303],{"class":123},[110,8378,8379,8381],{"class":112,"line":150},[110,8380,7308],{"class":315},[110,8382,7265],{"class":123},[110,8384,8385,8388,8390],{"class":112,"line":5},[110,8386,8387],{"class":315},"        \"API_KEY\"",[110,8389,4919],{"class":123},[110,8391,8392],{"class":311},"\"xxx\"\n",[110,8394,8395],{"class":112,"line":162},[110,8396,7325],{"class":123},[110,8398,8399],{"class":112,"line":168},[110,8400,7387],{"class":123},[110,8402,8403],{"class":112,"line":177},[110,8404,7392],{"class":123},[110,8406,8407],{"class":112,"line":186},[110,8408,7397],{"class":123},[17,8410,8411],{},"配置后重启 Cursor，在 Agent 模式下 AI 自动可用这些工具。",[13,8413,8415],{"id":8414},"第二步6-个常用-mcp-server-配置","第二步：6 个常用 MCP Server 配置",[1834,8417,8419],{"id":8418},"_1-postgresql最常用","1. PostgreSQL（最常用）",[17,8421,8422],{},"让 AI 能查表结构、跑 SQL、分析数据。",[100,8424,8426],{"className":7248,"code":8425,"language":7250,"meta":105,"style":105},"{\n  \"mcpServers\": {\n    \"postgres\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@modelcontextprotocol\u002Fserver-postgres\", \"postgresql:\u002F\u002Fuser:pass@localhost:5432\u002Fmydb\"]\n    }\n  }\n}\n",[107,8427,8428,8432,8438,8444,8454,8473,8477,8481],{"__ignoreMap":105},[110,8429,8430],{"class":112,"line":113},[110,8431,7257],{"class":123},[110,8433,8434,8436],{"class":112,"line":120},[110,8435,7262],{"class":315},[110,8437,7265],{"class":123},[110,8439,8440,8442],{"class":112,"line":127},[110,8441,7270],{"class":315},[110,8443,7265],{"class":123},[110,8445,8446,8448,8450,8452],{"class":112,"line":134},[110,8447,7277],{"class":315},[110,8449,4919],{"class":123},[110,8451,7282],{"class":311},[110,8453,7285],{"class":123},[110,8455,8456,8458,8460,8462,8464,8466,8468,8471],{"class":112,"line":140},[110,8457,7290],{"class":315},[110,8459,4945],{"class":123},[110,8461,7295],{"class":311},[110,8463,5083],{"class":123},[110,8465,7300],{"class":311},[110,8467,5083],{"class":123},[110,8469,8470],{"class":311},"\"postgresql:\u002F\u002Fuser:pass@localhost:5432\u002Fmydb\"",[110,8472,4951],{"class":123},[110,8474,8475],{"class":112,"line":150},[110,8476,7387],{"class":123},[110,8478,8479],{"class":112,"line":5},[110,8480,7392],{"class":123},[110,8482,8483],{"class":112,"line":162},[110,8484,7397],{"class":123},[17,8486,8487],{},"AI 能力：",[21,8489,8490,8495,8498,8501],{},[24,8491,8492,8494],{},[107,8493,7577],{}," 查表结构",[24,8496,8497],{},"跑 SELECT 查询（只读）",[24,8499,8500],{},"分析数据分布",[24,8502,8503],{},"生成数据库迁移建议",[1834,8505,8507],{"id":8506},"_2-github","2. GitHub",[17,8509,8510],{},"让 AI 能看 Issue \u002F PR \u002F 代码评论。",[100,8512,8514],{"className":7248,"code":8513,"language":7250,"meta":105,"style":105},"{\n  \"mcpServers\": {\n    \"github\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@modelcontextprotocol\u002Fserver-github\"],\n      \"env\": {\n        \"GITHUB_PERSONAL_ACCESS_TOKEN\": \"ghp_xxx\"\n      }\n    }\n  }\n}\n",[107,8515,8516,8520,8526,8532,8542,8556,8562,8571,8575,8579,8583],{"__ignoreMap":105},[110,8517,8518],{"class":112,"line":113},[110,8519,7257],{"class":123},[110,8521,8522,8524],{"class":112,"line":120},[110,8523,7262],{"class":315},[110,8525,7265],{"class":123},[110,8527,8528,8530],{"class":112,"line":127},[110,8529,7335],{"class":315},[110,8531,7265],{"class":123},[110,8533,8534,8536,8538,8540],{"class":112,"line":134},[110,8535,7277],{"class":315},[110,8537,4919],{"class":123},[110,8539,7282],{"class":311},[110,8541,7285],{"class":123},[110,8543,8544,8546,8548,8550,8552,8554],{"class":112,"line":140},[110,8545,7290],{"class":315},[110,8547,4945],{"class":123},[110,8549,7295],{"class":311},[110,8551,5083],{"class":123},[110,8553,7360],{"class":311},[110,8555,7303],{"class":123},[110,8557,8558,8560],{"class":112,"line":150},[110,8559,7308],{"class":315},[110,8561,7265],{"class":123},[110,8563,8564,8567,8569],{"class":112,"line":5},[110,8565,8566],{"class":315},"        \"GITHUB_PERSONAL_ACCESS_TOKEN\"",[110,8568,4919],{"class":123},[110,8570,7378],{"class":311},[110,8572,8573],{"class":112,"line":162},[110,8574,7325],{"class":123},[110,8576,8577],{"class":112,"line":168},[110,8578,7387],{"class":123},[110,8580,8581],{"class":112,"line":177},[110,8582,7392],{"class":123},[110,8584,8585],{"class":112,"line":186},[110,8586,7397],{"class":123},[17,8588,8487],{},[21,8590,8591,8594,8597,8600],{},[24,8592,8593],{},"查看某个 Issue 的讨论",[24,8595,8596],{},"列出分配给你的 PR",[24,8598,8599],{},"根据 Issue 描述直接开始修 bug",[24,8601,8602],{},"创建 PR 描述",[1834,8604,8606],{"id":8605},"_3-文件系统增强版","3. 文件系统（增强版）",[17,8608,8609],{},"Cursor 自带文件读写，但 MCP 文件系统 Server 支持更复杂的操作（搜索、批量重命名）。",[100,8611,8613],{"className":7248,"code":8612,"language":7250,"meta":105,"style":105},"{\n  \"mcpServers\": {\n    \"filesystem\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@modelcontextprotocol\u002Fserver-filesystem\", \"\u002FUsers\u002Fme\u002Fprojects\"]\n    }\n  }\n}\n",[107,8614,8615,8619,8625,8632,8642,8662,8666,8670],{"__ignoreMap":105},[110,8616,8617],{"class":112,"line":113},[110,8618,7257],{"class":123},[110,8620,8621,8623],{"class":112,"line":120},[110,8622,7262],{"class":315},[110,8624,7265],{"class":123},[110,8626,8627,8630],{"class":112,"line":127},[110,8628,8629],{"class":315},"    \"filesystem\"",[110,8631,7265],{"class":123},[110,8633,8634,8636,8638,8640],{"class":112,"line":134},[110,8635,7277],{"class":315},[110,8637,4919],{"class":123},[110,8639,7282],{"class":311},[110,8641,7285],{"class":123},[110,8643,8644,8646,8648,8650,8652,8655,8657,8660],{"class":112,"line":140},[110,8645,7290],{"class":315},[110,8647,4945],{"class":123},[110,8649,7295],{"class":311},[110,8651,5083],{"class":123},[110,8653,8654],{"class":311},"\"@modelcontextprotocol\u002Fserver-filesystem\"",[110,8656,5083],{"class":123},[110,8658,8659],{"class":311},"\"\u002FUsers\u002Fme\u002Fprojects\"",[110,8661,4951],{"class":123},[110,8663,8664],{"class":112,"line":150},[110,8665,7387],{"class":123},[110,8667,8668],{"class":112,"line":5},[110,8669,7392],{"class":123},[110,8671,8672],{"class":112,"line":162},[110,8673,7397],{"class":123},[1834,8675,8677],{"id":8676},"_4-slack","4. Slack",[17,8679,8680],{},"让 AI 能看频道消息、搜索历史讨论。",[100,8682,8684],{"className":7248,"code":8683,"language":7250,"meta":105,"style":105},"{\n  \"mcpServers\": {\n    \"slack\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@modelcontextprotocol\u002Fserver-slack\"],\n      \"env\": {\n        \"SLACK_BOT_TOKEN\": \"xoxb-xxx\"\n      }\n    }\n  }\n}\n",[107,8685,8686,8690,8696,8703,8713,8728,8734,8744,8748,8752,8756],{"__ignoreMap":105},[110,8687,8688],{"class":112,"line":113},[110,8689,7257],{"class":123},[110,8691,8692,8694],{"class":112,"line":120},[110,8693,7262],{"class":315},[110,8695,7265],{"class":123},[110,8697,8698,8701],{"class":112,"line":127},[110,8699,8700],{"class":315},"    \"slack\"",[110,8702,7265],{"class":123},[110,8704,8705,8707,8709,8711],{"class":112,"line":134},[110,8706,7277],{"class":315},[110,8708,4919],{"class":123},[110,8710,7282],{"class":311},[110,8712,7285],{"class":123},[110,8714,8715,8717,8719,8721,8723,8726],{"class":112,"line":140},[110,8716,7290],{"class":315},[110,8718,4945],{"class":123},[110,8720,7295],{"class":311},[110,8722,5083],{"class":123},[110,8724,8725],{"class":311},"\"@modelcontextprotocol\u002Fserver-slack\"",[110,8727,7303],{"class":123},[110,8729,8730,8732],{"class":112,"line":150},[110,8731,7308],{"class":315},[110,8733,7265],{"class":123},[110,8735,8736,8739,8741],{"class":112,"line":5},[110,8737,8738],{"class":315},"        \"SLACK_BOT_TOKEN\"",[110,8740,4919],{"class":123},[110,8742,8743],{"class":311},"\"xoxb-xxx\"\n",[110,8745,8746],{"class":112,"line":162},[110,8747,7325],{"class":123},[110,8749,8750],{"class":112,"line":168},[110,8751,7387],{"class":123},[110,8753,8754],{"class":112,"line":177},[110,8755,7392],{"class":123},[110,8757,8758],{"class":112,"line":186},[110,8759,7397],{"class":123},[17,8761,8762],{},"场景：开发时遇到问题，AI 可以搜 Slack 历史看团队之前是否讨论过。",[1834,8764,8766],{"id":8765},"_5-puppeteer浏览器","5. Puppeteer（浏览器）",[17,8768,8769],{},"让 AI 能打开网页、截图、提取内容。",[100,8771,8773],{"className":7248,"code":8772,"language":7250,"meta":105,"style":105},"{\n  \"mcpServers\": {\n    \"puppeteer\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@modelcontextprotocol\u002Fserver-puppeteer\"]\n    }\n  }\n}\n",[107,8774,8775,8779,8785,8792,8802,8817,8821,8825],{"__ignoreMap":105},[110,8776,8777],{"class":112,"line":113},[110,8778,7257],{"class":123},[110,8780,8781,8783],{"class":112,"line":120},[110,8782,7262],{"class":315},[110,8784,7265],{"class":123},[110,8786,8787,8790],{"class":112,"line":127},[110,8788,8789],{"class":315},"    \"puppeteer\"",[110,8791,7265],{"class":123},[110,8793,8794,8796,8798,8800],{"class":112,"line":134},[110,8795,7277],{"class":315},[110,8797,4919],{"class":123},[110,8799,7282],{"class":311},[110,8801,7285],{"class":123},[110,8803,8804,8806,8808,8810,8812,8815],{"class":112,"line":140},[110,8805,7290],{"class":315},[110,8807,4945],{"class":123},[110,8809,7295],{"class":311},[110,8811,5083],{"class":123},[110,8813,8814],{"class":311},"\"@modelcontextprotocol\u002Fserver-puppeteer\"",[110,8816,4951],{"class":123},[110,8818,8819],{"class":112,"line":150},[110,8820,7387],{"class":123},[110,8822,8823],{"class":112,"line":5},[110,8824,7392],{"class":123},[110,8826,8827],{"class":112,"line":162},[110,8828,7397],{"class":123},[17,8830,8831],{},"场景：调试前端时让 AI 打开 localhost:3000 截图，对比设计稿。",[1834,8833,8835],{"id":8834},"_6-memory持久记忆","6. Memory（持久记忆）",[17,8837,8838],{},"让 AI 跨会话记住信息。",[100,8840,8842],{"className":7248,"code":8841,"language":7250,"meta":105,"style":105},"{\n  \"mcpServers\": {\n    \"memory\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@modelcontextprotocol\u002Fserver-memory\"]\n    }\n  }\n}\n",[107,8843,8844,8848,8854,8861,8871,8886,8890,8894],{"__ignoreMap":105},[110,8845,8846],{"class":112,"line":113},[110,8847,7257],{"class":123},[110,8849,8850,8852],{"class":112,"line":120},[110,8851,7262],{"class":315},[110,8853,7265],{"class":123},[110,8855,8856,8859],{"class":112,"line":127},[110,8857,8858],{"class":315},"    \"memory\"",[110,8860,7265],{"class":123},[110,8862,8863,8865,8867,8869],{"class":112,"line":134},[110,8864,7277],{"class":315},[110,8866,4919],{"class":123},[110,8868,7282],{"class":311},[110,8870,7285],{"class":123},[110,8872,8873,8875,8877,8879,8881,8884],{"class":112,"line":140},[110,8874,7290],{"class":315},[110,8876,4945],{"class":123},[110,8878,7295],{"class":311},[110,8880,5083],{"class":123},[110,8882,8883],{"class":311},"\"@modelcontextprotocol\u002Fserver-memory\"",[110,8885,4951],{"class":123},[110,8887,8888],{"class":112,"line":150},[110,8889,7387],{"class":123},[110,8891,8892],{"class":112,"line":5},[110,8893,7392],{"class":123},[110,8895,8896],{"class":112,"line":162},[110,8897,7397],{"class":123},[17,8899,8900],{},"场景：让 AI 记住\"这个项目用 pnpm 不用 npm\"，下次启动自动加载。",[13,8902,8904],{"id":8903},"第三步实战场景","第三步：实战场景",[1834,8906,8908],{"id":8907},"场景-1根据-github-issue-修-bug","场景 1：根据 GitHub Issue 修 Bug",[100,8910,8913],{"className":8911,"code":8912,"language":282,"meta":105},[280],"@agent 看一下 github issue #142，理解问题，然后修复它\n",[107,8914,8912],{"__ignoreMap":105},[17,8916,8917],{},"AI 流程：",[415,8919,8920,8923,8926,8929,8932,8934],{},[24,8921,8922],{},"调 GitHub MCP 读 Issue 内容",[24,8924,8925],{},"分析问题原因",[24,8927,8928],{},"找到相关代码",[24,8930,8931],{},"修改",[24,8933,5536],{},[24,8935,8936],{},"生成 PR 描述（可让它直接创建 PR）",[1834,8938,8940],{"id":8939},"场景-2数据驱动的功能开发","场景 2：数据驱动的功能开发",[100,8942,8945],{"className":8943,"code":8944,"language":282,"meta":105},[280],"@agent 我要加用户积分功能。先查一下 users 表结构和现有数据量，然后设计 schema 和 API\n",[107,8946,8944],{"__ignoreMap":105},[17,8948,8917],{},[415,8950,8951,8954,8957,8960,8963,8966],{},[24,8952,8953],{},"调 PostgreSQL MCP 查 users 表结构",[24,8955,8956],{},"查现有数据量（SELECT COUNT(*)）",[24,8958,8959],{},"设计 points 字段和积分日志表",[24,8961,8962],{},"生成迁移 SQL",[24,8964,8965],{},"设计 API 接口",[24,8967,8968],{},"写代码实现",[1834,8970,8972],{"id":8971},"场景-3前端调试","场景 3：前端调试",[100,8974,8977],{"className":8975,"code":8976,"language":282,"meta":105},[280],"@agent 打开 localhost:3000\u002Fprofile，截图看看头像上传组件的样式问题\n",[107,8978,8976],{"__ignoreMap":105},[17,8980,8917],{},[415,8982,8983,8986,8989,8992,8995,8998],{},[24,8984,8985],{},"调 Puppeteer MCP 打开页面",[24,8987,8988],{},"截图",[24,8990,8991],{},"分析样式问题",[24,8993,8994],{},"找到对应组件代码",[24,8996,8997],{},"修改 CSS",[24,8999,9000],{},"重新截图验证",[13,9002,9003],{"id":9003},"权限边界与安全",[1834,9005,9006],{"id":9006},"数据库只读",[17,9008,9009],{},"PostgreSQL MCP Server 默认只允许 SELECT。不要给它写权限，除非你完全信任 AI 的判断。",[1834,9011,9013],{"id":9012},"token-最小权限","Token 最小权限",[17,9015,9016,9017,9020,9021,9024,9025,9028],{},"GitHub Token 只给 ",[107,9018,9019],{},"repo:read"," + ",[107,9022,9023],{},"issues:read","，不要给 ",[107,9026,9027],{},"repo:write","（除非你想让 AI 直接 push 代码）。",[1834,9030,9031],{"id":9031},"敏感信息不进配置文件",[100,9033,9035],{"className":298,"code":9034,"language":300,"meta":105,"style":105},"# 不要把 token 写死在 mcp.json，用环境变量\nexport GITHUB_TOKEN=\"ghp_xxx\"\n",[107,9036,9037,9042],{"__ignoreMap":105},[110,9038,9039],{"class":112,"line":113},[110,9040,9041],{"class":336},"# 不要把 token 写死在 mcp.json，用环境变量\n",[110,9043,9044,9046,9049,9051],{"class":112,"line":120},[110,9045,7065],{"class":1577},[110,9047,9048],{"class":123}," GITHUB_TOKEN",[110,9050,1587],{"class":1577},[110,9052,7378],{"class":311},[100,9054,9056],{"className":7248,"code":9055,"language":7250,"meta":105,"style":105},"{\n  \"env\": {\n    \"GITHUB_PERSONAL_ACCESS_TOKEN\": \"${GITHUB_TOKEN}\"\n  }\n}\n",[107,9057,9058,9062,9069,9079,9083],{"__ignoreMap":105},[110,9059,9060],{"class":112,"line":113},[110,9061,7257],{"class":123},[110,9063,9064,9067],{"class":112,"line":120},[110,9065,9066],{"class":315},"  \"env\"",[110,9068,7265],{"class":123},[110,9070,9071,9074,9076],{"class":112,"line":127},[110,9072,9073],{"class":315},"    \"GITHUB_PERSONAL_ACCESS_TOKEN\"",[110,9075,4919],{"class":123},[110,9077,9078],{"class":311},"\"${GITHUB_TOKEN}\"\n",[110,9080,9081],{"class":112,"line":134},[110,9082,7392],{"class":123},[110,9084,9085],{"class":112,"line":140},[110,9086,7397],{"class":123},[1834,9088,9090],{"id":9089},"gitignore-掉-mcpjson",".gitignore 掉 mcp.json",[17,9092,9093,9094,9096,9097,43],{},"项目级 ",[107,9095,8232],{}," 可能含 token，务必加到 ",[107,9098,8236],{},[13,9100,9101],{"id":9101},"性能注意事项",[1834,9103,9105],{"id":9104},"mcp-server-启动慢","MCP Server 启动慢",[17,9107,9108],{},"每个 MCP Server 是一个独立进程。配 6 个就是 6 个 npx 进程。建议：",[21,9110,9111,9114],{},[24,9112,9113],{},"只配当前任务需要的",[24,9115,9116,9117,9120],{},"用 ",[107,9118,9119],{},"npx --prefer-offline"," 加速",[1834,9122,9123],{"id":9123},"上下文膨胀",[17,9125,9126],{},"MCP 工具的返回结果会进入 AI 上下文。数据库返回 1000 行结果会吃掉大量 token。建议：",[21,9128,9129,9132],{},[24,9130,9131],{},"让 AI 用 LIMIT 限制查询行数",[24,9133,9134],{},"只查需要的字段",[13,9136,9138],{"id":9137},"与-claude-code-mcp-的区别","与 Claude Code MCP 的区别",[440,9140,9141,9153],{},[443,9142,9143],{},[446,9144,9145,9147,9150],{},[449,9146,1021],{},[449,9148,9149],{},"Cursor MCP",[449,9151,9152],{},"Claude Code MCP",[459,9154,9155,9165,9176,9187,9196],{},[446,9156,9157,9160,9162],{},[464,9158,9159],{},"配置位置",[464,9161,8232],{},[464,9163,9164],{},"~\u002F.claude\u002Fmcp_servers.json",[446,9166,9167,9170,9173],{},[464,9168,9169],{},"UI 可视化",[464,9171,9172],{},"✅ 有 MCP 面板",[464,9174,9175],{},"❌ 纯命令行",[446,9177,9178,9181,9184],{},[464,9179,9180],{},"工具调用可见性",[464,9182,9183],{},"✅ 在 chat 里显示",[464,9185,9186],{},"✅ 在终端显示",[446,9188,9189,9192,9194],{},[464,9190,9191],{},"多 Server 同时",[464,9193,1771],{},[464,9195,1771],{},[446,9197,9198,9201,9203],{},[464,9199,9200],{},"项目级配置",[464,9202,1771],{},[464,9204,9205],{},"❌ 全局",[17,9207,9208,9210],{},[40,9209,8168],{},"：两个工具配同样的 MCP Server，根据场景切换用。",[700,9212,9213],{},"html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}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 .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}",{"title":105,"searchDepth":127,"depth":127,"links":9215},[9216,9217,9218,9219,9227,9232,9238,9242],{"id":15,"depth":120,"text":15},{"id":8294,"depth":120,"text":8295},{"id":8318,"depth":120,"text":8319},{"id":8414,"depth":120,"text":8415,"children":9220},[9221,9222,9223,9224,9225,9226],{"id":8418,"depth":127,"text":8419},{"id":8506,"depth":127,"text":8507},{"id":8605,"depth":127,"text":8606},{"id":8676,"depth":127,"text":8677},{"id":8765,"depth":127,"text":8766},{"id":8834,"depth":127,"text":8835},{"id":8903,"depth":120,"text":8904,"children":9228},[9229,9230,9231],{"id":8907,"depth":127,"text":8908},{"id":8939,"depth":127,"text":8940},{"id":8971,"depth":127,"text":8972},{"id":9003,"depth":120,"text":9003,"children":9233},[9234,9235,9236,9237],{"id":9006,"depth":127,"text":9006},{"id":9012,"depth":127,"text":9013},{"id":9031,"depth":127,"text":9031},{"id":9089,"depth":127,"text":9090},{"id":9101,"depth":120,"text":9101,"children":9239},[9240,9241],{"id":9104,"depth":127,"text":9105},{"id":9123,"depth":127,"text":9123},{"id":9137,"depth":120,"text":9138},"\u002Fog\u002Fplaybook\u002Fcursor-mcp-deep-integration.png","Cursor 已支持 MCP——连接数据库、GitHub、Slack、文件系统、浏览器，让 AI 在 IDE 里直接操作外部服务。含 6 个常用 MCP Server 配置 + 权限边界 + 真实场景。",{},"\u002Fplaybook\u002Fonboarding\u002Fcursor-mcp-deep-integration",[2575,8266,8267,8268],{"title":8276,"description":9244},"playbook\u002Fonboarding\u002Fcursor-mcp-deep-integration",[3185,2595,9251,5798],"集成","7qzEiYO3w5v5Fw3TTNc64WmPJaxqOD2eo9lXwr7Yv1c",{"id":9254,"title":9255,"body":9256,"category":717,"cover":10781,"description":10782,"extension":104,"meta":10783,"navigation":130,"path":10784,"published":5734,"relatedTools":10785,"seo":10789,"stem":10790,"tags":10791,"updated":5734,"__hash__":10794},"playbook\u002Fplaybook\u002Fonboarding\u002Frag-pipeline-build.md","RAG 管道从零搭建：文档问答系统实战",{"type":10,"value":9257,"toc":10754},[9258,9260,9274,9278,9284,9287,9370,9374,9398,9402,9405,9529,9532,9591,9596,9600,9808,9812,9954,9957,9960,9964,10115,10119,10122,10222,10226,10229,10490,10493,10496,10581,10584,10588,10593,10598,10609,10613,10617,10628,10632,10636,10647,10651,10655,10669,10672,10751],[13,9259,15],{"id":15},[21,9261,9262,9265,9268,9271],{},[24,9263,9264],{},"公司内部知识库问答（HR 政策、技术文档、FAQ）",[24,9266,9267],{},"法律\u002F医疗文档检索 + 问答",[24,9269,9270],{},"产品手册智能客服",[24,9272,9273],{},"个人笔记\u002F文献智能检索",[13,9275,9277],{"id":9276},"rag-架构总览","RAG 架构总览",[100,9279,9282],{"className":9280,"code":9281,"language":282,"meta":105},[280],"文档 → 切分 → Embedding → 存入向量数据库\n                                    ↓\n用户提问 → Embedding → 检索 Top-K → 重排序 → LLM 生成回答\n",[107,9283,9281],{"__ignoreMap":105},[13,9285,9286],{"id":9286},"技术选型",[440,9288,9289,9302],{},[443,9290,9291],{},[446,9292,9293,9296,9299],{},[449,9294,9295],{},"组件",[449,9297,9298],{},"选型",[449,9300,9301],{},"理由",[459,9303,9304,9315,9326,9337,9348,9359],{},[446,9305,9306,9309,9312],{},[464,9307,9308],{},"框架",[464,9310,9311],{},"LlamaIndex",[464,9313,9314],{},"比 LangChain 更专注 RAG",[446,9316,9317,9320,9323],{},[464,9318,9319],{},"Embedding",[464,9321,9322],{},"BGE-large-zh-v1.5",[464,9324,9325],{},"中文效果最佳，开源免费",[446,9327,9328,9331,9334],{},[464,9329,9330],{},"向量数据库",[464,9332,9333],{},"ChromaDB",[464,9335,9336],{},"轻量，原型够用",[446,9338,9339,9342,9345],{},[464,9340,9341],{},"重排序",[464,9343,9344],{},"bge-reranker-large",[464,9346,9347],{},"显著提升准确率",[446,9349,9350,9353,9356],{},[464,9351,9352],{},"LLM",[464,9354,9355],{},"GPT-4o",[464,9357,9358],{},"性价比好，支持国内中转",[446,9360,9361,9364,9367],{},[464,9362,9363],{},"文档解析",[464,9365,9366],{},"Unstructured",[464,9368,9369],{},"支持 PDF\u002FWord\u002FHTML",[13,9371,9373],{"id":9372},"第一步环境准备","第一步：环境准备",[100,9375,9377],{"className":298,"code":9376,"language":300,"meta":105,"style":105},"pip install llama-index chromadb sentence-transformers unstructured\n",[107,9378,9379],{"__ignoreMap":105},[110,9380,9381,9384,9386,9389,9392,9395],{"class":112,"line":113},[110,9382,9383],{"class":307},"pip",[110,9385,312],{"class":311},[110,9387,9388],{"class":311}," llama-index",[110,9390,9391],{"class":311}," chromadb",[110,9393,9394],{"class":311}," sentence-transformers",[110,9396,9397],{"class":311}," unstructured\n",[13,9399,9401],{"id":9400},"第二步文档加载与切分","第二步：文档加载与切分",[17,9403,9404],{},"切分是 RAG 效果的决定性因素。",[100,9406,9410],{"className":9407,"code":9408,"language":9409,"meta":105,"style":105},"language-python shiki shiki-themes github-light github-dark","from llama_index.core import SimpleDirectoryReader\nfrom llama_index.core.node_parser import SentenceSplitter\n\n# 1. 加载文档\ndocuments = SimpleDirectoryReader(\".\u002Fdocs\").load_data()\n\n# 2. 切分\nsplitter = SentenceSplitter(\n    chunk_size=512,      # 每块 512 token\n    chunk_overlap=50,    # 重叠 50 token，保证上下文连贯\n)\nnodes = splitter.get_nodes_from_documents(documents)\n","python",[107,9411,9412,9426,9438,9442,9447,9463,9467,9472,9482,9498,9514,9519],{"__ignoreMap":105},[110,9413,9414,9417,9420,9423],{"class":112,"line":113},[110,9415,9416],{"class":1577},"from",[110,9418,9419],{"class":123}," llama_index.core ",[110,9421,9422],{"class":1577},"import",[110,9424,9425],{"class":123}," SimpleDirectoryReader\n",[110,9427,9428,9430,9433,9435],{"class":112,"line":120},[110,9429,9416],{"class":1577},[110,9431,9432],{"class":123}," llama_index.core.node_parser ",[110,9434,9422],{"class":1577},[110,9436,9437],{"class":123}," SentenceSplitter\n",[110,9439,9440],{"class":112,"line":127},[110,9441,131],{"emptyLinePlaceholder":130},[110,9443,9444],{"class":112,"line":134},[110,9445,9446],{"class":336},"# 1. 加载文档\n",[110,9448,9449,9452,9454,9457,9460],{"class":112,"line":140},[110,9450,9451],{"class":123},"documents ",[110,9453,1587],{"class":1577},[110,9455,9456],{"class":123}," SimpleDirectoryReader(",[110,9458,9459],{"class":311},"\".\u002Fdocs\"",[110,9461,9462],{"class":123},").load_data()\n",[110,9464,9465],{"class":112,"line":150},[110,9466,131],{"emptyLinePlaceholder":130},[110,9468,9469],{"class":112,"line":5},[110,9470,9471],{"class":336},"# 2. 切分\n",[110,9473,9474,9477,9479],{"class":112,"line":162},[110,9475,9476],{"class":123},"splitter ",[110,9478,1587],{"class":1577},[110,9480,9481],{"class":123}," SentenceSplitter(\n",[110,9483,9484,9487,9489,9492,9495],{"class":112,"line":168},[110,9485,9486],{"class":143},"    chunk_size",[110,9488,1587],{"class":1577},[110,9490,9491],{"class":315},"512",[110,9493,9494],{"class":123},",      ",[110,9496,9497],{"class":336},"# 每块 512 token\n",[110,9499,9500,9503,9505,9508,9511],{"class":112,"line":177},[110,9501,9502],{"class":143},"    chunk_overlap",[110,9504,1587],{"class":1577},[110,9506,9507],{"class":315},"50",[110,9509,9510],{"class":123},",    ",[110,9512,9513],{"class":336},"# 重叠 50 token，保证上下文连贯\n",[110,9515,9516],{"class":112,"line":186},[110,9517,9518],{"class":123},")\n",[110,9520,9521,9524,9526],{"class":112,"line":195},[110,9522,9523],{"class":123},"nodes ",[110,9525,1587],{"class":1577},[110,9527,9528],{"class":123}," splitter.get_nodes_from_documents(documents)\n",[1834,9530,9531],{"id":9531},"切分策略选择",[440,9533,9534,9546],{},[443,9535,9536],{},[446,9537,9538,9541,9544],{},[449,9539,9540],{},"策略",[449,9542,9543],{},"chunk_size",[449,9545,15],{},[459,9547,9548,9559,9569,9580],{},[446,9549,9550,9553,9556],{},[464,9551,9552],{},"小块",[464,9554,9555],{},"256",[464,9557,9558],{},"FAQ、短问答",[446,9560,9561,9564,9566],{},[464,9562,9563],{},"中块",[464,9565,9491],{},[464,9567,9568],{},"通用文档（推荐起步值）",[446,9570,9571,9574,9577],{},[464,9572,9573],{},"大块",[464,9575,9576],{},"1024",[464,9578,9579],{},"长文档、技术手册",[446,9581,9582,9585,9588],{},[464,9583,9584],{},"按段落",[464,9586,9587],{},"不固定",[464,9589,9590],{},"保持语义完整",[17,9592,9593,9595],{},[40,9594,7206],{},"：chunk_overlap 设 chunk_size 的 10%，避免切断语义。",[13,9597,9599],{"id":9598},"第三步embedding-与入库","第三步：Embedding 与入库",[100,9601,9603],{"className":9407,"code":9602,"language":9409,"meta":105,"style":105},"from llama_index.embeddings.huggingface import HuggingFaceEmbedding\nfrom llama_index.vector_stores.chroma import ChromaVectorStore\nimport chromadb\n\n# 1. 用 BGE 中文模型\nembed_model = HuggingFaceEmbedding(\n    model_name=\"BAAI\u002Fbge-large-zh-v1.5\",\n    max_length=512,\n)\n\n# 2. 创建向量数据库\ndb = chromadb.PersistentClient(path=\".\u002Fchroma_db\")\nchroma_collection = db.get_or_create_collection(\"docs\")\nvector_store = ChromaVectorStore(chroma_collection=chroma_collection)\n\n# 3. 构建索引\nfrom llama_index.core import StorageContext, VectorStoreIndex\nstorage_context = StorageContext.from_defaults(vector_store=vector_store)\nindex = VectorStoreIndex(nodes, embed_model=embed_model, storage_context=storage_context)\n",[107,9604,9605,9617,9629,9636,9640,9645,9655,9667,9678,9682,9686,9691,9711,9726,9744,9748,9753,9764,9782],{"__ignoreMap":105},[110,9606,9607,9609,9612,9614],{"class":112,"line":113},[110,9608,9416],{"class":1577},[110,9610,9611],{"class":123}," llama_index.embeddings.huggingface ",[110,9613,9422],{"class":1577},[110,9615,9616],{"class":123}," HuggingFaceEmbedding\n",[110,9618,9619,9621,9624,9626],{"class":112,"line":120},[110,9620,9416],{"class":1577},[110,9622,9623],{"class":123}," llama_index.vector_stores.chroma ",[110,9625,9422],{"class":1577},[110,9627,9628],{"class":123}," ChromaVectorStore\n",[110,9630,9631,9633],{"class":112,"line":127},[110,9632,9422],{"class":1577},[110,9634,9635],{"class":123}," chromadb\n",[110,9637,9638],{"class":112,"line":134},[110,9639,131],{"emptyLinePlaceholder":130},[110,9641,9642],{"class":112,"line":140},[110,9643,9644],{"class":336},"# 1. 用 BGE 中文模型\n",[110,9646,9647,9650,9652],{"class":112,"line":150},[110,9648,9649],{"class":123},"embed_model ",[110,9651,1587],{"class":1577},[110,9653,9654],{"class":123}," HuggingFaceEmbedding(\n",[110,9656,9657,9660,9662,9665],{"class":112,"line":5},[110,9658,9659],{"class":143},"    model_name",[110,9661,1587],{"class":1577},[110,9663,9664],{"class":311},"\"BAAI\u002Fbge-large-zh-v1.5\"",[110,9666,7285],{"class":123},[110,9668,9669,9672,9674,9676],{"class":112,"line":162},[110,9670,9671],{"class":143},"    max_length",[110,9673,1587],{"class":1577},[110,9675,9491],{"class":315},[110,9677,7285],{"class":123},[110,9679,9680],{"class":112,"line":168},[110,9681,9518],{"class":123},[110,9683,9684],{"class":112,"line":177},[110,9685,131],{"emptyLinePlaceholder":130},[110,9687,9688],{"class":112,"line":186},[110,9689,9690],{"class":336},"# 2. 创建向量数据库\n",[110,9692,9693,9696,9698,9701,9704,9706,9709],{"class":112,"line":195},[110,9694,9695],{"class":123},"db ",[110,9697,1587],{"class":1577},[110,9699,9700],{"class":123}," chromadb.PersistentClient(",[110,9702,9703],{"class":143},"path",[110,9705,1587],{"class":1577},[110,9707,9708],{"class":311},"\".\u002Fchroma_db\"",[110,9710,9518],{"class":123},[110,9712,9713,9716,9718,9721,9724],{"class":112,"line":204},[110,9714,9715],{"class":123},"chroma_collection ",[110,9717,1587],{"class":1577},[110,9719,9720],{"class":123}," db.get_or_create_collection(",[110,9722,9723],{"class":311},"\"docs\"",[110,9725,9518],{"class":123},[110,9727,9728,9731,9733,9736,9739,9741],{"class":112,"line":209},[110,9729,9730],{"class":123},"vector_store ",[110,9732,1587],{"class":1577},[110,9734,9735],{"class":123}," ChromaVectorStore(",[110,9737,9738],{"class":143},"chroma_collection",[110,9740,1587],{"class":1577},[110,9742,9743],{"class":123},"chroma_collection)\n",[110,9745,9746],{"class":112,"line":215},[110,9747,131],{"emptyLinePlaceholder":130},[110,9749,9750],{"class":112,"line":221},[110,9751,9752],{"class":336},"# 3. 构建索引\n",[110,9754,9755,9757,9759,9761],{"class":112,"line":226},[110,9756,9416],{"class":1577},[110,9758,9419],{"class":123},[110,9760,9422],{"class":1577},[110,9762,9763],{"class":123}," StorageContext, VectorStoreIndex\n",[110,9765,9766,9769,9771,9774,9777,9779],{"class":112,"line":232},[110,9767,9768],{"class":123},"storage_context ",[110,9770,1587],{"class":1577},[110,9772,9773],{"class":123}," StorageContext.from_defaults(",[110,9775,9776],{"class":143},"vector_store",[110,9778,1587],{"class":1577},[110,9780,9781],{"class":123},"vector_store)\n",[110,9783,9784,9787,9789,9792,9795,9797,9800,9803,9805],{"class":112,"line":240},[110,9785,9786],{"class":123},"index ",[110,9788,1587],{"class":1577},[110,9790,9791],{"class":123}," VectorStoreIndex(nodes, ",[110,9793,9794],{"class":143},"embed_model",[110,9796,1587],{"class":1577},[110,9798,9799],{"class":123},"embed_model, ",[110,9801,9802],{"class":143},"storage_context",[110,9804,1587],{"class":1577},[110,9806,9807],{"class":123},"storage_context)\n",[13,9809,9811],{"id":9810},"第四步检索-重排序","第四步：检索 + 重排序",[100,9813,9815],{"className":9407,"code":9814,"language":9409,"meta":105,"style":105},"from llama_index.core.postprocessor import SentenceTransformerRerank\n\n# 重排序模型——显著提升检索质量\nreranker = SentenceTransformerRerank(\n    model=\"BAAI\u002Fbge-reranker-large\",\n    top_n=3,  # 重排序后取前 3\n)\n\n# 检索器\nretriever = index.as_retriever(similarity_top_k=10)  # 先粗检索 10 条\n\n# 检索 + 重排序\nnodes = retriever.retrieve(\"年假怎么请？\")\nreranked = reranker.postprocess_nodes(nodes, query_str=\"年假怎么请？\")\n",[107,9816,9817,9829,9833,9838,9848,9860,9876,9880,9884,9889,9912,9916,9921,9935],{"__ignoreMap":105},[110,9818,9819,9821,9824,9826],{"class":112,"line":113},[110,9820,9416],{"class":1577},[110,9822,9823],{"class":123}," llama_index.core.postprocessor ",[110,9825,9422],{"class":1577},[110,9827,9828],{"class":123}," SentenceTransformerRerank\n",[110,9830,9831],{"class":112,"line":120},[110,9832,131],{"emptyLinePlaceholder":130},[110,9834,9835],{"class":112,"line":127},[110,9836,9837],{"class":336},"# 重排序模型——显著提升检索质量\n",[110,9839,9840,9843,9845],{"class":112,"line":134},[110,9841,9842],{"class":123},"reranker ",[110,9844,1587],{"class":1577},[110,9846,9847],{"class":123}," SentenceTransformerRerank(\n",[110,9849,9850,9853,9855,9858],{"class":112,"line":140},[110,9851,9852],{"class":143},"    model",[110,9854,1587],{"class":1577},[110,9856,9857],{"class":311},"\"BAAI\u002Fbge-reranker-large\"",[110,9859,7285],{"class":123},[110,9861,9862,9865,9867,9870,9873],{"class":112,"line":150},[110,9863,9864],{"class":143},"    top_n",[110,9866,1587],{"class":1577},[110,9868,9869],{"class":315},"3",[110,9871,9872],{"class":123},",  ",[110,9874,9875],{"class":336},"# 重排序后取前 3\n",[110,9877,9878],{"class":112,"line":5},[110,9879,9518],{"class":123},[110,9881,9882],{"class":112,"line":162},[110,9883,131],{"emptyLinePlaceholder":130},[110,9885,9886],{"class":112,"line":168},[110,9887,9888],{"class":336},"# 检索器\n",[110,9890,9891,9894,9896,9899,9902,9904,9906,9909],{"class":112,"line":177},[110,9892,9893],{"class":123},"retriever ",[110,9895,1587],{"class":1577},[110,9897,9898],{"class":123}," index.as_retriever(",[110,9900,9901],{"class":143},"similarity_top_k",[110,9903,1587],{"class":1577},[110,9905,841],{"class":315},[110,9907,9908],{"class":123},")  ",[110,9910,9911],{"class":336},"# 先粗检索 10 条\n",[110,9913,9914],{"class":112,"line":186},[110,9915,131],{"emptyLinePlaceholder":130},[110,9917,9918],{"class":112,"line":195},[110,9919,9920],{"class":336},"# 检索 + 重排序\n",[110,9922,9923,9925,9927,9930,9933],{"class":112,"line":204},[110,9924,9523],{"class":123},[110,9926,1587],{"class":1577},[110,9928,9929],{"class":123}," retriever.retrieve(",[110,9931,9932],{"class":311},"\"年假怎么请？\"",[110,9934,9518],{"class":123},[110,9936,9937,9940,9942,9945,9948,9950,9952],{"class":112,"line":209},[110,9938,9939],{"class":123},"reranked ",[110,9941,1587],{"class":1577},[110,9943,9944],{"class":123}," reranker.postprocess_nodes(nodes, ",[110,9946,9947],{"class":143},"query_str",[110,9949,1587],{"class":1577},[110,9951,9932],{"class":311},[110,9953,9518],{"class":123},[1834,9955,9956],{"id":9956},"为什么要重排序",[17,9958,9959],{},"Embedding 检索快但不够精准。先粗检索 10 条，再用重排序模型精选 3 条，准确率提升 20-30%。",[13,9961,9963],{"id":9962},"第五步生成回答","第五步：生成回答",[100,9965,9967],{"className":9407,"code":9966,"language":9409,"meta":105,"style":105},"from llama_index.llms.openai import OpenAI\n\nllm = OpenAI(model=\"gpt-4o\", temperature=0)\n\n# 构建 query engine\nquery_engine = index.as_query_engine(\n    llm=llm,\n    similarity_top_k=10,\n    node_postprocessors=[reranker],\n    response_mode=\"compact\",  # 紧凑模式，省 token\n)\n\n# 提问\nresponse = query_engine.query(\"年假怎么请？需要提前多久申请？\")\nprint(response.response)\n",[107,9968,9969,9981,9985,10014,10018,10023,10033,10043,10054,10064,10079,10083,10087,10092,10107],{"__ignoreMap":105},[110,9970,9971,9973,9976,9978],{"class":112,"line":113},[110,9972,9416],{"class":1577},[110,9974,9975],{"class":123}," llama_index.llms.openai ",[110,9977,9422],{"class":1577},[110,9979,9980],{"class":123}," OpenAI\n",[110,9982,9983],{"class":112,"line":120},[110,9984,131],{"emptyLinePlaceholder":130},[110,9986,9987,9990,9992,9995,9998,10000,10003,10005,10008,10010,10012],{"class":112,"line":127},[110,9988,9989],{"class":123},"llm ",[110,9991,1587],{"class":1577},[110,9993,9994],{"class":123}," OpenAI(",[110,9996,9997],{"class":143},"model",[110,9999,1587],{"class":1577},[110,10001,10002],{"class":311},"\"gpt-4o\"",[110,10004,5083],{"class":123},[110,10006,10007],{"class":143},"temperature",[110,10009,1587],{"class":1577},[110,10011,6227],{"class":315},[110,10013,9518],{"class":123},[110,10015,10016],{"class":112,"line":134},[110,10017,131],{"emptyLinePlaceholder":130},[110,10019,10020],{"class":112,"line":140},[110,10021,10022],{"class":336},"# 构建 query engine\n",[110,10024,10025,10028,10030],{"class":112,"line":150},[110,10026,10027],{"class":123},"query_engine ",[110,10029,1587],{"class":1577},[110,10031,10032],{"class":123}," index.as_query_engine(\n",[110,10034,10035,10038,10040],{"class":112,"line":5},[110,10036,10037],{"class":143},"    llm",[110,10039,1587],{"class":1577},[110,10041,10042],{"class":123},"llm,\n",[110,10044,10045,10048,10050,10052],{"class":112,"line":162},[110,10046,10047],{"class":143},"    similarity_top_k",[110,10049,1587],{"class":1577},[110,10051,841],{"class":315},[110,10053,7285],{"class":123},[110,10055,10056,10059,10061],{"class":112,"line":168},[110,10057,10058],{"class":143},"    node_postprocessors",[110,10060,1587],{"class":1577},[110,10062,10063],{"class":123},"[reranker],\n",[110,10065,10066,10069,10071,10074,10076],{"class":112,"line":177},[110,10067,10068],{"class":143},"    response_mode",[110,10070,1587],{"class":1577},[110,10072,10073],{"class":311},"\"compact\"",[110,10075,9872],{"class":123},[110,10077,10078],{"class":336},"# 紧凑模式，省 token\n",[110,10080,10081],{"class":112,"line":186},[110,10082,9518],{"class":123},[110,10084,10085],{"class":112,"line":195},[110,10086,131],{"emptyLinePlaceholder":130},[110,10088,10089],{"class":112,"line":204},[110,10090,10091],{"class":336},"# 提问\n",[110,10093,10094,10097,10099,10102,10105],{"class":112,"line":209},[110,10095,10096],{"class":123},"response ",[110,10098,1587],{"class":1577},[110,10100,10101],{"class":123}," query_engine.query(",[110,10103,10104],{"class":311},"\"年假怎么请？需要提前多久申请？\"",[110,10106,9518],{"class":123},[110,10108,10109,10112],{"class":112,"line":215},[110,10110,10111],{"class":315},"print",[110,10113,10114],{"class":123},"(response.response)\n",[1834,10116,10118],{"id":10117},"prompt-优化","Prompt 优化",[17,10120,10121],{},"默认 prompt 是英文的，中文场景建议自定义：",[100,10123,10125],{"className":9407,"code":10124,"language":9409,"meta":105,"style":105},"from llama_index.core import PromptTemplate\n\nqa_prompt = PromptTemplate(\"\"\"\n你是一个文档问答助手。请根据以下检索到的文档片段回答问题。\n如果文档中没有相关信息，明确说\"文档中未找到相关信息\"，不要编造。\n\n文档片段：\n{context_str}\n\n问题：{query_str}\n\n回答：\n\"\"\")\n\nquery_engine.update_prompts({\"response_synthesis_prompt\": qa_prompt})\n",[107,10126,10127,10138,10142,10155,10160,10165,10169,10174,10179,10183,10191,10195,10200,10207,10211],{"__ignoreMap":105},[110,10128,10129,10131,10133,10135],{"class":112,"line":113},[110,10130,9416],{"class":1577},[110,10132,9419],{"class":123},[110,10134,9422],{"class":1577},[110,10136,10137],{"class":123}," PromptTemplate\n",[110,10139,10140],{"class":112,"line":120},[110,10141,131],{"emptyLinePlaceholder":130},[110,10143,10144,10147,10149,10152],{"class":112,"line":127},[110,10145,10146],{"class":123},"qa_prompt ",[110,10148,1587],{"class":1577},[110,10150,10151],{"class":123}," PromptTemplate(",[110,10153,10154],{"class":311},"\"\"\"\n",[110,10156,10157],{"class":112,"line":134},[110,10158,10159],{"class":311},"你是一个文档问答助手。请根据以下检索到的文档片段回答问题。\n",[110,10161,10162],{"class":112,"line":140},[110,10163,10164],{"class":311},"如果文档中没有相关信息，明确说\"文档中未找到相关信息\"，不要编造。\n",[110,10166,10167],{"class":112,"line":150},[110,10168,131],{"emptyLinePlaceholder":130},[110,10170,10171],{"class":112,"line":5},[110,10172,10173],{"class":311},"文档片段：\n",[110,10175,10176],{"class":112,"line":162},[110,10177,10178],{"class":315},"{context_str}\n",[110,10180,10181],{"class":112,"line":168},[110,10182,131],{"emptyLinePlaceholder":130},[110,10184,10185,10188],{"class":112,"line":177},[110,10186,10187],{"class":311},"问题：",[110,10189,10190],{"class":315},"{query_str}\n",[110,10192,10193],{"class":112,"line":186},[110,10194,131],{"emptyLinePlaceholder":130},[110,10196,10197],{"class":112,"line":195},[110,10198,10199],{"class":311},"回答：\n",[110,10201,10202,10205],{"class":112,"line":204},[110,10203,10204],{"class":311},"\"\"\"",[110,10206,9518],{"class":123},[110,10208,10209],{"class":112,"line":209},[110,10210,131],{"emptyLinePlaceholder":130},[110,10212,10213,10216,10219],{"class":112,"line":215},[110,10214,10215],{"class":123},"query_engine.update_prompts({",[110,10217,10218],{"class":311},"\"response_synthesis_prompt\"",[110,10220,10221],{"class":123},": qa_prompt})\n",[13,10223,10225],{"id":10224},"第六步评估","第六步：评估",[1834,10227,10228],{"id":10228},"检索质量评估",[100,10230,10232],{"className":9407,"code":10231,"language":9409,"meta":105,"style":105},"# 准备测试集：问题 + 正确答案所在文档\ntest_cases = [\n    {\"question\": \"年假怎么请？\", \"relevant_doc_id\": \"hr_policy_003\"},\n    {\"question\": \"报销流程是什么？\", \"relevant_doc_id\": \"finance_007\"},\n]\n\n# 计算 Recall@K\ndef eval_retrieval(query_engine, test_cases, k=5):\n    hits = 0\n    for tc in test_cases:\n        nodes = query_engine.retrieve(tc[\"question\"])\n        retrieved_ids = [n.node.metadata[\"doc_id\"] for n in nodes[:k]]\n        if tc[\"relevant_doc_id\"] in retrieved_ids:\n            hits += 1\n    return hits \u002F len(test_cases)\n\nrecall = eval_retrieval(query_engine, test_cases, k=5)\nprint(f\"Recall@5: {recall:.1%}\")\n",[107,10233,10234,10239,10249,10274,10296,10300,10304,10309,10328,10338,10352,10367,10394,10410,10421,10438,10442,10461],{"__ignoreMap":105},[110,10235,10236],{"class":112,"line":113},[110,10237,10238],{"class":336},"# 准备测试集：问题 + 正确答案所在文档\n",[110,10240,10241,10244,10246],{"class":112,"line":120},[110,10242,10243],{"class":123},"test_cases ",[110,10245,1587],{"class":1577},[110,10247,10248],{"class":123}," [\n",[110,10250,10251,10254,10257,10259,10261,10263,10266,10268,10271],{"class":112,"line":127},[110,10252,10253],{"class":123},"    {",[110,10255,10256],{"class":311},"\"question\"",[110,10258,4919],{"class":123},[110,10260,9932],{"class":311},[110,10262,5083],{"class":123},[110,10264,10265],{"class":311},"\"relevant_doc_id\"",[110,10267,4919],{"class":123},[110,10269,10270],{"class":311},"\"hr_policy_003\"",[110,10272,10273],{"class":123},"},\n",[110,10275,10276,10278,10280,10282,10285,10287,10289,10291,10294],{"class":112,"line":134},[110,10277,10253],{"class":123},[110,10279,10256],{"class":311},[110,10281,4919],{"class":123},[110,10283,10284],{"class":311},"\"报销流程是什么？\"",[110,10286,5083],{"class":123},[110,10288,10265],{"class":311},[110,10290,4919],{"class":123},[110,10292,10293],{"class":311},"\"finance_007\"",[110,10295,10273],{"class":123},[110,10297,10298],{"class":112,"line":140},[110,10299,4951],{"class":123},[110,10301,10302],{"class":112,"line":150},[110,10303,131],{"emptyLinePlaceholder":130},[110,10305,10306],{"class":112,"line":5},[110,10307,10308],{"class":336},"# 计算 Recall@K\n",[110,10310,10311,10314,10317,10320,10322,10325],{"class":112,"line":162},[110,10312,10313],{"class":1577},"def",[110,10315,10316],{"class":307}," eval_retrieval",[110,10318,10319],{"class":123},"(query_engine, test_cases, k",[110,10321,1587],{"class":1577},[110,10323,10324],{"class":315},"5",[110,10326,10327],{"class":123},"):\n",[110,10329,10330,10333,10335],{"class":112,"line":168},[110,10331,10332],{"class":123},"    hits ",[110,10334,1587],{"class":1577},[110,10336,10337],{"class":315}," 0\n",[110,10339,10340,10343,10346,10349],{"class":112,"line":177},[110,10341,10342],{"class":1577},"    for",[110,10344,10345],{"class":123}," tc ",[110,10347,10348],{"class":1577},"in",[110,10350,10351],{"class":123}," test_cases:\n",[110,10353,10354,10357,10359,10362,10364],{"class":112,"line":186},[110,10355,10356],{"class":123},"        nodes ",[110,10358,1587],{"class":1577},[110,10360,10361],{"class":123}," query_engine.retrieve(tc[",[110,10363,10256],{"class":311},[110,10365,10366],{"class":123},"])\n",[110,10368,10369,10372,10374,10377,10380,10383,10386,10389,10391],{"class":112,"line":195},[110,10370,10371],{"class":123},"        retrieved_ids ",[110,10373,1587],{"class":1577},[110,10375,10376],{"class":123}," [n.node.metadata[",[110,10378,10379],{"class":311},"\"doc_id\"",[110,10381,10382],{"class":123},"] ",[110,10384,10385],{"class":1577},"for",[110,10387,10388],{"class":123}," n ",[110,10390,10348],{"class":1577},[110,10392,10393],{"class":123}," nodes[:k]]\n",[110,10395,10396,10398,10401,10403,10405,10407],{"class":112,"line":204},[110,10397,5311],{"class":1577},[110,10399,10400],{"class":123}," tc[",[110,10402,10265],{"class":311},[110,10404,10382],{"class":123},[110,10406,10348],{"class":1577},[110,10408,10409],{"class":123}," retrieved_ids:\n",[110,10411,10412,10415,10418],{"class":112,"line":209},[110,10413,10414],{"class":123},"            hits ",[110,10416,10417],{"class":1577},"+=",[110,10419,10420],{"class":315}," 1\n",[110,10422,10423,10426,10429,10432,10435],{"class":112,"line":215},[110,10424,10425],{"class":1577},"    return",[110,10427,10428],{"class":123}," hits ",[110,10430,10431],{"class":1577},"\u002F",[110,10433,10434],{"class":315}," len",[110,10436,10437],{"class":123},"(test_cases)\n",[110,10439,10440],{"class":112,"line":221},[110,10441,131],{"emptyLinePlaceholder":130},[110,10443,10444,10447,10449,10452,10455,10457,10459],{"class":112,"line":226},[110,10445,10446],{"class":123},"recall ",[110,10448,1587],{"class":1577},[110,10450,10451],{"class":123}," eval_retrieval(query_engine, test_cases, ",[110,10453,10454],{"class":143},"k",[110,10456,1587],{"class":1577},[110,10458,10324],{"class":315},[110,10460,9518],{"class":123},[110,10462,10463,10465,10467,10470,10473,10476,10479,10482,10485,10488],{"class":112,"line":232},[110,10464,10111],{"class":315},[110,10466,5892],{"class":123},[110,10468,10469],{"class":1577},"f",[110,10471,10472],{"class":311},"\"Recall@5: ",[110,10474,10475],{"class":315},"{",[110,10477,10478],{"class":123},"recall",[110,10480,10481],{"class":1577},":.1%",[110,10483,10484],{"class":315},"}",[110,10486,10487],{"class":311},"\"",[110,10489,9518],{"class":123},[1834,10491,10492],{"id":10492},"回答质量评估",[17,10494,10495],{},"用 LLM 自动评估回答质量：",[100,10497,10499],{"className":9407,"code":10498,"language":9409,"meta":105,"style":105},"eval_prompt = f\"\"\"\n请评估以下回答的质量，打分 1-5：\n问题：{question}\n检索到的文档：{retrieved_docs}\n回答：{answer}\n\n评分标准：\n5 — 完全正确，基于文档\n3 — 部分正确，有遗漏\n1 — 错误或编造\n\"\"\"\n",[107,10500,10501,10513,10518,10529,10541,10553,10557,10562,10567,10572,10577],{"__ignoreMap":105},[110,10502,10503,10506,10508,10511],{"class":112,"line":113},[110,10504,10505],{"class":123},"eval_prompt ",[110,10507,1587],{"class":1577},[110,10509,10510],{"class":1577}," f",[110,10512,10154],{"class":311},[110,10514,10515],{"class":112,"line":120},[110,10516,10517],{"class":311},"请评估以下回答的质量，打分 1-5：\n",[110,10519,10520,10522,10524,10527],{"class":112,"line":127},[110,10521,10187],{"class":311},[110,10523,10475],{"class":315},[110,10525,10526],{"class":123},"question",[110,10528,7397],{"class":315},[110,10530,10531,10534,10536,10539],{"class":112,"line":134},[110,10532,10533],{"class":311},"检索到的文档：",[110,10535,10475],{"class":315},[110,10537,10538],{"class":123},"retrieved_docs",[110,10540,7397],{"class":315},[110,10542,10543,10546,10548,10551],{"class":112,"line":140},[110,10544,10545],{"class":311},"回答：",[110,10547,10475],{"class":315},[110,10549,10550],{"class":123},"answer",[110,10552,7397],{"class":315},[110,10554,10555],{"class":112,"line":150},[110,10556,131],{"emptyLinePlaceholder":130},[110,10558,10559],{"class":112,"line":5},[110,10560,10561],{"class":311},"评分标准：\n",[110,10563,10564],{"class":112,"line":162},[110,10565,10566],{"class":311},"5 — 完全正确，基于文档\n",[110,10568,10569],{"class":112,"line":168},[110,10570,10571],{"class":311},"3 — 部分正确，有遗漏\n",[110,10573,10574],{"class":112,"line":177},[110,10575,10576],{"class":311},"1 — 错误或编造\n",[110,10578,10579],{"class":112,"line":186},[110,10580,10154],{"class":311},[13,10582,10583],{"id":10583},"常见问题与优化",[1834,10585,10587],{"id":10586},"问题-1检索不到相关文档","问题 1：检索不到相关文档",[17,10589,10590,10592],{},[40,10591,4236],{},"：切分太碎，语义丢失。",[17,10594,10595,953],{},[40,10596,10597],{},"解决",[21,10599,10600,10603,10606],{},[24,10601,10602],{},"增大 chunk_size（512 → 1024）",[24,10604,10605],{},"加 chunk_overlap",[24,10607,10608],{},"用 parent-child 切分（检索小块，返回大块）",[1834,10610,10612],{"id":10611},"问题-2回答不基于文档幻觉","问题 2：回答不基于文档（幻觉）",[17,10614,10615,953],{},[40,10616,10597],{},[21,10618,10619,10622,10625],{},[24,10620,10621],{},"prompt 强制要求\"只基于文档回答\"",[24,10623,10624],{},"temperature 设 0",[24,10626,10627],{},"检查检索结果是否相关（不相关就回答\"未找到\"）",[1834,10629,10631],{"id":10630},"问题-3中文检索效果差","问题 3：中文检索效果差",[17,10633,10634,953],{},[40,10635,10597],{},[21,10637,10638,10641,10644],{},[24,10639,10640],{},"用 BGE 系列中文 Embedding 模型",[24,10642,10643],{},"不要用 OpenAI 的 Embedding（中文效果一般）",[24,10645,10646],{},"加重排序模型",[1834,10648,10650],{"id":10649},"问题-4速度慢","问题 4：速度慢",[17,10652,10653,953],{},[40,10654,10597],{},[21,10656,10657,10660,10663,10666],{},[24,10658,10659],{},"Embedding 用 GPU",[24,10661,10662],{},"向量数据库加 HNSW 索引",[24,10664,10665],{},"减少 similarity_top_k（10 → 5）",[24,10667,10668],{},"LLM 用流式输出",[13,10670,10671],{"id":10671},"生产部署清单",[21,10673,10676,10685,10691,10697,10703,10709,10715,10721,10727,10733,10739,10745],{"className":10674},[10675],"contains-task-list",[24,10677,10680,10684],{"className":10678},[10679],"task-list-item",[10681,10682],"input",{"disabled":130,"type":10683},"checkbox"," 文档解析支持 PDF\u002FWord\u002FHTML\u002FMarkdown",[24,10686,10688,10690],{"className":10687},[10679],[10681,10689],{"disabled":130,"type":10683}," 切分策略测试过（chunk_size 调优）",[24,10692,10694,10696],{"className":10693},[10679],[10681,10695],{"disabled":130,"type":10683}," Embedding 模型选定并部署",[24,10698,10700,10702],{"className":10699},[10679],[10681,10701],{"disabled":130,"type":10683}," 向量数据库持久化",[24,10704,10706,10708],{"className":10705},[10679],[10681,10707],{"disabled":130,"type":10683}," 重排序模型集成",[24,10710,10712,10714],{"className":10711},[10679],[10681,10713],{"disabled":130,"type":10683}," LLM prompt 优化（中文 + 防幻觉）",[24,10716,10718,10720],{"className":10717},[10679],[10681,10719],{"disabled":130,"type":10683}," 检索质量评估（Recall@K > 80%）",[24,10722,10724,10726],{"className":10723},[10679],[10681,10725],{"disabled":130,"type":10683}," 回答质量评估（人工抽检）",[24,10728,10730,10732],{"className":10729},[10679],[10681,10731],{"disabled":130,"type":10683}," 流式输出（用户体验）",[24,10734,10736,10738],{"className":10735},[10679],[10681,10737],{"disabled":130,"type":10683}," 缓存层（常见问题缓存回答）",[24,10740,10742,10744],{"className":10741},[10679],[10681,10743],{"disabled":130,"type":10683}," 日志记录（问题 + 检索结果 + 回答）",[24,10746,10748,10750],{"className":10747},[10679],[10681,10749],{"disabled":130,"type":10683}," 限流 + 鉴权",[700,10752,10753],{},"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 .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 .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}",{"title":105,"searchDepth":127,"depth":127,"links":10755},[10756,10757,10758,10759,10760,10763,10764,10767,10770,10774,10780],{"id":15,"depth":120,"text":15},{"id":9276,"depth":120,"text":9277},{"id":9286,"depth":120,"text":9286},{"id":9372,"depth":120,"text":9373},{"id":9400,"depth":120,"text":9401,"children":10761},[10762],{"id":9531,"depth":127,"text":9531},{"id":9598,"depth":120,"text":9599},{"id":9810,"depth":120,"text":9811,"children":10765},[10766],{"id":9956,"depth":127,"text":9956},{"id":9962,"depth":120,"text":9963,"children":10768},[10769],{"id":10117,"depth":127,"text":10118},{"id":10224,"depth":120,"text":10225,"children":10771},[10772,10773],{"id":10228,"depth":127,"text":10228},{"id":10492,"depth":127,"text":10492},{"id":10583,"depth":120,"text":10583,"children":10775},[10776,10777,10778,10779],{"id":10586,"depth":127,"text":10587},{"id":10611,"depth":127,"text":10612},{"id":10630,"depth":127,"text":10631},{"id":10649,"depth":127,"text":10650},{"id":10671,"depth":120,"text":10671},"\u002Fog\u002Fplaybook\u002Frag-pipeline-build.png","用 LlamaIndex + ChromaDB + GPT-4o 搭一个生产级 RAG 系统——文档切分策略、Embedding 选型、检索优化、重排序、回答生成、评估指标，含完整代码和踩坑记录。",{},"\u002Fplaybook\u002Fonboarding\u002Frag-pipeline-build",[10786,10787,10788],"agent\u002Fplatform\u002Fdify","agent\u002Fplatform\u002Ffastgpt","coding\u002Flocal\u002Follama",{"title":9255,"description":10782},"playbook\u002Fonboarding\u002Frag-pipeline-build",[10792,9311,9330,10793],"RAG","文档问答","iDBgSssiFFBzdFhaAXgu0ePo29Ov3xLYoHWpnnCPo04",{"id":10796,"title":10797,"body":10798,"category":11402,"cover":11403,"description":11404,"extension":104,"meta":11405,"navigation":130,"path":1285,"published":5734,"relatedTools":11406,"seo":11409,"stem":11410,"tags":11411,"updated":5734,"__hash__":11414},"playbook\u002Fplaybook\u002Freview\u002Fai-pr-review-pipeline.md","用 AI Agent 搭一个自动化 PR Review 流水线",{"type":10,"value":10799,"toc":11393},[10800,10802,10813,10815,10821,10825,10828,10848,10938,10943,10947,10950,10956,11217,11221,11224,11282,11288,11290,11293,11353,11355,11390],[13,10801,15],{"id":15},[21,10803,10804,10807,10810],{},[24,10805,10806],{},"团队 5-20 人，PR review 是瓶颈",[24,10808,10809],{},"想让 AI 做第一轮审查，人只看 AI 标记的问题",[24,10811,10812],{},"需要 CI 阻断有严重问题的 PR（而非只评论）",[13,10814,4888],{"id":4888},[100,10816,10819],{"className":10817,"code":10818,"language":282},[280],"PR 提交 → GitHub Actions 触发\n  ├─ CodeRabbit Bot 自动评论（逐行 + 摘要）\n  ├─ Claude Code 自定义规则审查（安全 \u002F 性能 \u002F 规范）\n  └─ 严重问题 → 设置 commit status = failed → 阻断合并\n",[107,10820,10818],{"__ignoreMap":105},[13,10822,10824],{"id":10823},"第一步coderabbit-接入","第一步：CodeRabbit 接入",[17,10826,10827],{},"CodeRabbit 是开箱即用的 GitHub App，装上就自动 review。",[415,10829,10830,10839,10842],{},[24,10831,10832,10833,10838],{},"去 ",[1181,10834,10837],{"href":10835,"rel":10836},"https:\u002F\u002Fcoderabbit.ai",[1209],"coderabbit.ai"," 安装 GitHub App",[24,10840,10841],{},"选择要 review 的仓库",[24,10843,10844,10845,953],{},"在仓库根目录加 ",[107,10846,10847],{},".coderabbit.yml",[100,10849,10851],{"className":4906,"code":10850,"language":4908,"meta":105,"style":105},"reviews:\n  auto_review:\n    enabled: true\n    drafts: false\n  path_filters:\n    - \"!**\u002F*.lock\"\n    - \"!**\u002Fdist\u002F**\"\n  instructions: |\n    - 用中文评论\n    - 重点关注 SQL 注入、XSS、敏感信息泄露\n    - 不要评论代码风格（用 ESLint 管）\n    - 性能问题只在 O(n²) 以上才报\n",[107,10852,10853,10860,10867,10877,10887,10894,10902,10909,10918,10923,10928,10933],{"__ignoreMap":105},[110,10854,10855,10858],{"class":112,"line":113},[110,10856,10857],{"class":4915},"reviews",[110,10859,4930],{"class":123},[110,10861,10862,10865],{"class":112,"line":120},[110,10863,10864],{"class":4915},"  auto_review",[110,10866,4930],{"class":123},[110,10868,10869,10872,10874],{"class":112,"line":127},[110,10870,10871],{"class":4915},"    enabled",[110,10873,4919],{"class":123},[110,10875,10876],{"class":315},"true\n",[110,10878,10879,10882,10884],{"class":112,"line":134},[110,10880,10881],{"class":4915},"    drafts",[110,10883,4919],{"class":123},[110,10885,10886],{"class":315},"false\n",[110,10888,10889,10892],{"class":112,"line":140},[110,10890,10891],{"class":4915},"  path_filters",[110,10893,4930],{"class":123},[110,10895,10896,10899],{"class":112,"line":150},[110,10897,10898],{"class":123},"    - ",[110,10900,10901],{"class":311},"\"!**\u002F*.lock\"\n",[110,10903,10904,10906],{"class":112,"line":5},[110,10905,10898],{"class":123},[110,10907,10908],{"class":311},"\"!**\u002Fdist\u002F**\"\n",[110,10910,10911,10914,10916],{"class":112,"line":162},[110,10912,10913],{"class":4915},"  instructions",[110,10915,4919],{"class":123},[110,10917,5247],{"class":1577},[110,10919,10920],{"class":112,"line":168},[110,10921,10922],{"class":311},"    - 用中文评论\n",[110,10924,10925],{"class":112,"line":177},[110,10926,10927],{"class":311},"    - 重点关注 SQL 注入、XSS、敏感信息泄露\n",[110,10929,10930],{"class":112,"line":186},[110,10931,10932],{"class":311},"    - 不要评论代码风格（用 ESLint 管）\n",[110,10934,10935],{"class":112,"line":195},[110,10936,10937],{"class":311},"    - 性能问题只在 O(n²) 以上才报\n",[415,10939,10940],{"start":134},[24,10941,10942],{},"提交一个 PR 测试，CodeRabbit 会在 30 秒内出评论",[13,10944,10946],{"id":10945},"第二步claude-code-自定义规则","第二步：Claude Code 自定义规则",[17,10948,10949],{},"CodeRabbit 是通用审查，团队特定规范用 Claude Code 补。",[17,10951,10952,10953,953],{},"创建 ",[107,10954,10955],{},".github\u002Fworkflows\u002Fai-review.yml",[100,10957,10959],{"className":4906,"code":10958,"language":4908,"meta":105,"style":105},"name: AI Review\non:\n  pull_request:\n    types: [opened, synchronize]\n\njobs:\n  claude-review:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions\u002Fcheckout@v4\n        with:\n          fetch-depth: 0\n\n      - name: Get changed files\n        id: changed\n        run: |\n          files=$(git diff --name-only ${{ github.event.pull_request.base.sha }}..${{ github.event.pull_request.head.sha }})\n          echo \"files=$files\" >> $GITHUB_OUTPUT\n\n      - name: Claude Code Review\n        uses: anthropics\u002Fclaude-code-action@v1\n        with:\n          anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}\n          prompt: |\n            审查以下文件的改动，重点关注：\n            1. 是否有未处理的 Promise rejection\n            2. 是否有 SQL 拼接（而非参数化查询）\n            3. 是否有 console.log 遗留在生产代码中\n            4. 是否有 hardcoded 密钥 \u002F token\n\n            输出格式：\n            - 🔴 严重问题（必须修复）：文件:行号 + 原因\n            - 🟡 建议（可选）：文件:行号 + 建议\n            - ✅ 没问题的文件不用提\n\n            改动的文件：\n            ${{ steps.changed.outputs.files }}\n",[107,10960,10961,10970,10976,10983,11000,11004,11010,11017,11025,11031,11041,11047,11057,11061,11072,11082,11090,11095,11100,11104,11115,11123,11129,11137,11145,11150,11155,11160,11165,11171,11176,11182,11188,11194,11200,11205,11211],{"__ignoreMap":105},[110,10962,10963,10965,10967],{"class":112,"line":113},[110,10964,4916],{"class":4915},[110,10966,4919],{"class":123},[110,10968,10969],{"class":311},"AI Review\n",[110,10971,10972,10974],{"class":112,"line":120},[110,10973,4927],{"class":315},[110,10975,4930],{"class":123},[110,10977,10978,10981],{"class":112,"line":127},[110,10979,10980],{"class":4915},"  pull_request",[110,10982,4930],{"class":123},[110,10984,10985,10988,10990,10993,10995,10998],{"class":112,"line":134},[110,10986,10987],{"class":4915},"    types",[110,10989,4945],{"class":123},[110,10991,10992],{"class":311},"opened",[110,10994,5083],{"class":123},[110,10996,10997],{"class":311},"synchronize",[110,10999,4951],{"class":123},[110,11001,11002],{"class":112,"line":140},[110,11003,131],{"emptyLinePlaceholder":130},[110,11005,11006,11008],{"class":112,"line":150},[110,11007,4960],{"class":4915},[110,11009,4930],{"class":123},[110,11011,11012,11015],{"class":112,"line":5},[110,11013,11014],{"class":4915},"  claude-review",[110,11016,4930],{"class":123},[110,11018,11019,11021,11023],{"class":112,"line":162},[110,11020,4974],{"class":4915},[110,11022,4919],{"class":123},[110,11024,4979],{"class":311},[110,11026,11027,11029],{"class":112,"line":168},[110,11028,5010],{"class":4915},[110,11030,4930],{"class":123},[110,11032,11033,11035,11037,11039],{"class":112,"line":177},[110,11034,5017],{"class":123},[110,11036,5020],{"class":4915},[110,11038,4919],{"class":123},[110,11040,5025],{"class":311},[110,11042,11043,11045],{"class":112,"line":186},[110,11044,5041],{"class":4915},[110,11046,4930],{"class":123},[110,11048,11049,11052,11054],{"class":112,"line":195},[110,11050,11051],{"class":4915},"          fetch-depth",[110,11053,4919],{"class":123},[110,11055,11056],{"class":315},"0\n",[110,11058,11059],{"class":112,"line":204},[110,11060,131],{"emptyLinePlaceholder":130},[110,11062,11063,11065,11067,11069],{"class":112,"line":209},[110,11064,5017],{"class":123},[110,11066,4916],{"class":4915},[110,11068,4919],{"class":123},[110,11070,11071],{"class":311},"Get changed files\n",[110,11073,11074,11077,11079],{"class":112,"line":215},[110,11075,11076],{"class":4915},"        id",[110,11078,4919],{"class":123},[110,11080,11081],{"class":311},"changed\n",[110,11083,11084,11086,11088],{"class":112,"line":221},[110,11085,5113],{"class":4915},[110,11087,4919],{"class":123},[110,11089,5247],{"class":1577},[110,11091,11092],{"class":112,"line":226},[110,11093,11094],{"class":311},"          files=$(git diff --name-only ${{ github.event.pull_request.base.sha }}..${{ github.event.pull_request.head.sha }})\n",[110,11096,11097],{"class":112,"line":232},[110,11098,11099],{"class":311},"          echo \"files=$files\" >> $GITHUB_OUTPUT\n",[110,11101,11102],{"class":112,"line":240},[110,11103,131],{"emptyLinePlaceholder":130},[110,11105,11106,11108,11110,11112],{"class":112,"line":248},[110,11107,5017],{"class":123},[110,11109,4916],{"class":4915},[110,11111,4919],{"class":123},[110,11113,11114],{"class":311},"Claude Code Review\n",[110,11116,11117,11119,11121],{"class":112,"line":256},[110,11118,5216],{"class":4915},[110,11120,4919],{"class":123},[110,11122,5221],{"class":311},[110,11124,11125,11127],{"class":112,"line":261},[110,11126,5041],{"class":4915},[110,11128,4930],{"class":123},[110,11130,11131,11133,11135],{"class":112,"line":267},[110,11132,5232],{"class":4915},[110,11134,4919],{"class":123},[110,11136,5237],{"class":311},[110,11138,11139,11141,11143],{"class":112,"line":5145},[110,11140,5242],{"class":4915},[110,11142,4919],{"class":123},[110,11144,5247],{"class":1577},[110,11146,11147],{"class":112,"line":5150},[110,11148,11149],{"class":311},"            审查以下文件的改动，重点关注：\n",[110,11151,11152],{"class":112,"line":5162},[110,11153,11154],{"class":311},"            1. 是否有未处理的 Promise rejection\n",[110,11156,11157],{"class":112,"line":5172},[110,11158,11159],{"class":311},"            2. 是否有 SQL 拼接（而非参数化查询）\n",[110,11161,11162],{"class":112,"line":5180},[110,11163,11164],{"class":311},"            3. 是否有 console.log 遗留在生产代码中\n",[110,11166,11168],{"class":112,"line":11167},29,[110,11169,11170],{"class":311},"            4. 是否有 hardcoded 密钥 \u002F token\n",[110,11172,11174],{"class":112,"line":11173},30,[110,11175,131],{"emptyLinePlaceholder":130},[110,11177,11179],{"class":112,"line":11178},31,[110,11180,11181],{"class":311},"            输出格式：\n",[110,11183,11185],{"class":112,"line":11184},32,[110,11186,11187],{"class":311},"            - 🔴 严重问题（必须修复）：文件:行号 + 原因\n",[110,11189,11191],{"class":112,"line":11190},33,[110,11192,11193],{"class":311},"            - 🟡 建议（可选）：文件:行号 + 建议\n",[110,11195,11197],{"class":112,"line":11196},34,[110,11198,11199],{"class":311},"            - ✅ 没问题的文件不用提\n",[110,11201,11203],{"class":112,"line":11202},35,[110,11204,131],{"emptyLinePlaceholder":130},[110,11206,11208],{"class":112,"line":11207},36,[110,11209,11210],{"class":311},"            改动的文件：\n",[110,11212,11214],{"class":112,"line":11213},37,[110,11215,11216],{"class":311},"            ${{ steps.changed.outputs.files }}\n",[13,11218,11220],{"id":11219},"第三步严重问题阻断合并","第三步：严重问题阻断合并",[17,11222,11223],{},"在 review workflow 末尾加 commit status：",[100,11225,11227],{"className":4906,"code":11226,"language":4908,"meta":105,"style":105},"      - name: Set check status\n        if: steps.claude-review.outputs.severity == 'critical'\n        run: |\n          curl -X POST \\\n            -H \"Authorization: token ${{ secrets.GITHUB_TOKEN }}\" \\\n            -H \"Accept: application\u002Fvnd.github.v3+json\" \\\n            https:\u002F\u002Fapi.github.com\u002Frepos\u002F${{ github.repository }}\u002Fstatuses\u002F${{ github.event.pull_request.head.sha }} \\\n            -d '{\"state\": \"failure\", \"context\": \"AI Review \u002F Critical Issues\", \"description\": \"发现严重问题，请修复后重新提交\"}'\n",[107,11228,11229,11240,11249,11257,11262,11267,11272,11277],{"__ignoreMap":105},[110,11230,11231,11233,11235,11237],{"class":112,"line":113},[110,11232,5017],{"class":123},[110,11234,4916],{"class":4915},[110,11236,4919],{"class":123},[110,11238,11239],{"class":311},"Set check status\n",[110,11241,11242,11244,11246],{"class":112,"line":120},[110,11243,5311],{"class":4915},[110,11245,4919],{"class":123},[110,11247,11248],{"class":311},"steps.claude-review.outputs.severity == 'critical'\n",[110,11250,11251,11253,11255],{"class":112,"line":127},[110,11252,5113],{"class":4915},[110,11254,4919],{"class":123},[110,11256,5247],{"class":1577},[110,11258,11259],{"class":112,"line":134},[110,11260,11261],{"class":311},"          curl -X POST \\\n",[110,11263,11264],{"class":112,"line":140},[110,11265,11266],{"class":311},"            -H \"Authorization: token ${{ secrets.GITHUB_TOKEN }}\" \\\n",[110,11268,11269],{"class":112,"line":150},[110,11270,11271],{"class":311},"            -H \"Accept: application\u002Fvnd.github.v3+json\" \\\n",[110,11273,11274],{"class":112,"line":5},[110,11275,11276],{"class":311},"            https:\u002F\u002Fapi.github.com\u002Frepos\u002F${{ github.repository }}\u002Fstatuses\u002F${{ github.event.pull_request.head.sha }} \\\n",[110,11278,11279],{"class":112,"line":162},[110,11280,11281],{"class":311},"            -d '{\"state\": \"failure\", \"context\": \"AI Review \u002F Critical Issues\", \"description\": \"发现严重问题，请修复后重新提交\"}'\n",[17,11283,11284,11285,43],{},"在 GitHub 仓库设置 → Branch protection → Require status checks → 添加 ",[107,11286,11287],{},"AI Review \u002F Critical Issues",[13,11289,5606],{"id":5606},[17,11291,11292],{},"上线一个月后：",[440,11294,11295,11307],{},[443,11296,11297],{},[446,11298,11299,11301,11304],{},[449,11300,611],{},[449,11302,11303],{},"之前",[449,11305,11306],{},"之后",[459,11308,11309,11320,11331,11342],{},[446,11310,11311,11314,11317],{},[464,11312,11313],{},"PR 平均 review 时间",[464,11315,11316],{},"8 小时",[464,11318,11319],{},"2 小时",[446,11321,11322,11325,11328],{},[464,11323,11324],{},"人工 review 评论数",[464,11326,11327],{},"15 条\u002FPR",[464,11329,11330],{},"5 条\u002FPR",[446,11332,11333,11336,11339],{},[464,11334,11335],{},"合并后发现的 bug",[464,11337,11338],{},"3 个\u002F周",[464,11340,11341],{},"1 个\u002F周",[446,11343,11344,11347,11350],{},[464,11345,11346],{},"开发者满意度",[464,11348,11349],{},"6\u002F10",[464,11351,11352],{},"8\u002F10",[13,11354,5672],{"id":5672},[415,11356,11357,11363,11369,11375,11381],{},[24,11358,11359,11362],{},[40,11360,11361],{},"CodeRabbit 免费版限制","：开源仓库免费，私有仓库 $24\u002Fseat\u002Fmo。小团队可只给核心仓库开。",[24,11364,11365,11368],{},[40,11366,11367],{},"Claude Code API 成本","：每个 PR 约 $0.1-0.5（取决于改动量），月费 $50 以内可控。",[24,11370,11371,11374],{},[40,11372,11373],{},"不要让 AI 阻断全部问题","——只阻断安全类严重问题（SQL 注入、密钥泄露），否则开发者会绕过。",[24,11376,11377,11380],{},[40,11378,11379],{},"path_filters 很重要","——不加的话会 review lock 文件、dist 目录，浪费 API 调用。",[24,11382,11383,11389],{},[40,11384,11385,11386],{},"Claude Code Action 需要 ",[107,11387,11388],{},"fetch-depth: 0","——否则 git diff 拿不到完整历史。",[700,11391,11392],{},"html pre.shiki code .s9eBZ, html code.shiki .s9eBZ{--shiki-default:#22863A;--shiki-dark:#85E89D}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}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 .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);}",{"title":105,"searchDepth":127,"depth":127,"links":11394},[11395,11396,11397,11398,11399,11400,11401],{"id":15,"depth":120,"text":15},{"id":4888,"depth":120,"text":4888},{"id":10823,"depth":120,"text":10824},{"id":10945,"depth":120,"text":10946},{"id":11219,"depth":120,"text":11220},{"id":5606,"depth":120,"text":5606},{"id":5672,"depth":120,"text":5672},"review","\u002Fog\u002Fplaybook\u002Fai-pr-review.png","从零用 CodeRabbit + Claude Code + GitHub Actions 搭一条自动化 PR Review 流水线：提交 PR → AI 审查代码 → 评论区出报告 → 严重问题阻断合并。含完整配置和踩坑记录。",{},[11407,1313,11408],"coding\u002Freview\u002Fcoderabbit","coding\u002Freview\u002Fgreptile",{"title":10797,"description":11404},"playbook\u002Freview\u002Fai-pr-review-pipeline",[11412,5743,11413,5744],"PR Review","CodeRabbit","SsbL8A6w0qdO6rgCdogrJAPlq2NrJdkxw6n5D6zV5is",{"id":11416,"title":11417,"body":11418,"category":11402,"cover":11903,"description":11904,"extension":104,"meta":11905,"navigation":130,"path":11906,"published":11907,"relatedTools":11908,"seo":11910,"stem":11911,"tags":11912,"updated":11915,"__hash__":11916},"playbook\u002Fplaybook\u002Freview\u002Fai-code-review-workflow.md","AI 做 PR Review：开发者的 5 倍速 review 工作流",{"type":10,"value":11419,"toc":11879},[11420,11423,11434,11443,11446,11465,11469,11473,11531,11534,11538,11544,11550,11554,11557,11562,11568,11572,11578,11587,11591,11597,11601,11607,11611,11617,11623,11626,11629,11703,11714,11717,11743,11745,11749,11756,11760,11767,11771,11781,11785,11792,11794,11798,11801,11861,11864,11866,11876],[13,11421,11422],{"id":11422},"谁需要这套流程",[21,11424,11425,11428,11431],{},[24,11426,11427],{},"团队 leader \u002F staff engineer，每天 review 5-10 个 PR",[24,11429,11430],{},"独立维护者，开源项目 PR 多但人手少",[24,11432,11433],{},"想给自己的 PR 自查的开发者",[17,11435,11436,11439,11440,43],{},[40,11437,11438],{},"核心承诺","：让 AI 做\"第一道筛\"——把明显问题 + 一致性问题先过一遍，",[40,11441,11442],{},"人脑只看 AI 标出来的高价值地方",[13,11444,11445],{"id":11445},"不要做什么",[21,11447,11448,11455,11462],{},[24,11449,11450,11451,11454],{},"❌ 让 AI 写 ",[107,11452,11453],{},"LGTM"," 然后 merge——AI 会把烂代码 review 通过",[24,11456,11457,11458,11461],{},"❌ 让 AI ",[40,11459,11460],{},"决定","合不合并——AI 只做建议，决策权在人",[24,11463,11464],{},"❌ 把 PR 全文丢给 ChatGPT 网页版让它\"看看\"——上下文不够，结论不可信",[13,11466,11468],{"id":11467},"工作流4-步法","工作流：4 步法",[1834,11470,11472],{"id":11471},"step-1-准备-review-上下文2-min","Step 1 — 准备 review 上下文（2 min）",[100,11474,11476],{"className":298,"code":11475,"language":300,"meta":105,"style":105},"# 在 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",[107,11477,11478,11483,11496,11510],{"__ignoreMap":105},[110,11479,11480],{"class":112,"line":113},[110,11481,11482],{"class":336},"# 在 PR 分支\n",[110,11484,11485,11487,11490,11493],{"class":112,"line":120},[110,11486,4733],{"class":307},[110,11488,11489],{"class":311}," fetch",[110,11491,11492],{"class":311}," origin",[110,11494,11495],{"class":311}," main\n",[110,11497,11498,11500,11502,11505,11507],{"class":112,"line":127},[110,11499,4733],{"class":307},[110,11501,4736],{"class":311},[110,11503,11504],{"class":311}," main...HEAD",[110,11506,4739],{"class":1577},[110,11508,11509],{"class":311}," \u002Ftmp\u002Fpr.diff\n",[110,11511,11512,11514,11517,11520,11523,11526,11528],{"class":112,"line":134},[110,11513,4733],{"class":307},[110,11515,11516],{"class":311}," log",[110,11518,11519],{"class":311}," main..HEAD",[110,11521,11522],{"class":315}," --pretty=format:",[110,11524,11525],{"class":311},"'%h %s%n%b'",[110,11527,4739],{"class":1577},[110,11529,11530],{"class":311}," \u002Ftmp\u002Fpr.commits\n",[17,11532,11533],{},"进入项目根，开 Claude Code 或 Cursor。",[1834,11535,11537],{"id":11536},"step-2-让-ai-分类改动5-min","Step 2 — 让 AI 分类改动（5 min）",[100,11539,11542],{"className":11540,"code":11541,"language":282,"meta":105},[280],"请分析本分支相对 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",[107,11543,11541],{"__ignoreMap":105},[17,11545,11546,11549],{},[40,11547,11548],{},"这一步的产出物极其有价值","——你瞬间知道这个 PR 的盘子有多大、风险点在哪。",[1834,11551,11553],{"id":11552},"step-3-深度审视10-30-min","Step 3 — 深度审视（10-30 min）",[17,11555,11556],{},"针对 Step 2 标出的高风险项，挨个深问：",[11558,11559,11561],"h4",{"id":11560},"_31-业务逻辑深查","3.1 业务逻辑深查",[100,11563,11566],{"className":11564,"code":11565,"language":282,"meta":105},[280],"对于改动【文件 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",[107,11567,11565],{"__ignoreMap":105},[11558,11569,11571],{"id":11570},"_32-一致性扫描","3.2 一致性扫描",[100,11573,11576],{"className":11574,"code":11575,"language":282,"meta":105},[280],"请扫描整个项目，看本 PR 的改动有没有\"漏改\"：\n\n- 如果 PR 改了某个函数的签名，所有调用方都改了吗？\n- 如果 PR 加了新的常量，类似的常量定义是否同步更新？\n- 如果 PR 改了某个文件的 pattern，类似文件是否需要同样改？\n\n逐条列出\"可能漏改但 PR 里没改\"的地方，给文件:行号。\n",[107,11577,11575],{"__ignoreMap":105},[17,11579,11580,11583,11584,43],{},[40,11581,11582],{},"这是 AI 比人类强的地方","——人类做 PR review 容易盯着 diff 看，",[40,11585,11586],{},"AI 会去看 diff 之外的地方",[11558,11588,11590],{"id":11589},"_33-测试-review","3.3 测试 review",[100,11592,11595],{"className":11593,"code":11594,"language":282,"meta":105},[280],"对于本 PR 中的测试改动 + 新增测试，请评估：\n\n1. 测试是否真的覆盖了\"业务逻辑改动\"？还是只覆盖了 happy path？\n2. 测试的断言是否够强？（不要只 assert 不抛异常）\n3. 有没有\"修测试让它通过\"的痕迹（注释掉的 assert \u002F 改宽容的 matcher）？\n4. 哪些 edge case 没被测到？\n\n输出：测试覆盖度评估 + 建议补的测试用例（伪代码）\n",[107,11596,11594],{"__ignoreMap":105},[11558,11598,11600],{"id":11599},"_34-风险与回滚","3.4 风险与回滚",[100,11602,11605],{"className":11603,"code":11604,"language":282,"meta":105},[280],"假设这个 PR 合并到生产后出了严重问题，回滚成本如何？\n\n- 单纯 revert 这个 commit 能恢复吗？\n- 有没有不可逆的改动（DB 迁移 \u002F 数据格式变更 \u002F 删了字段）？\n- 有没有\"客户端已经发了新版本，服务端不能简单回滚\"的耦合？\n\n如果回滚成本高，建议拆 PR 或加 feature flag。\n",[107,11606,11604],{"__ignoreMap":105},[1834,11608,11610],{"id":11609},"step-4-整合-review-反馈5-min","Step 4 — 整合 review 反馈（5 min）",[100,11612,11615],{"className":11613,"code":11614,"language":282,"meta":105},[280],"请整合前面 3.1-3.4 的所有发现，输出一份最终 review 评论，格式：\n\n## ✅ 看起来没问题的部分\n（简短列出）\n\n## ⚠️ 需要 PR author 回应的问题\n（每条带文件:行号 + 具体问题）\n\n## 🛑 阻塞合并的问题\n（如有，必须解决才能合）\n\n## 💡 建议（非阻塞）\n（可选优化）\n\n语气专业、具体，不要客套话。\n",[107,11616,11614],{"__ignoreMap":105},[17,11618,11619,11622],{},[40,11620,11621],{},"人工 review 这份 markdown","——70% 的内容你直接 copy 到 PR 评论区。剩下 30% 自己再补充判断和上下文。",[11624,11625],"hr",{},[13,11627,11628],{"id":11628},"实战时间分配",[440,11630,11631,11644],{},[443,11632,11633],{},[446,11634,11635,11638,11641],{},[449,11636,11637],{},"步骤",[449,11639,11640],{},"耗时",[449,11642,11643],{},"谁做",[459,11645,11646,11657,11668,11679,11689],{},[446,11647,11648,11651,11654],{},[464,11649,11650],{},"1 准备",[464,11652,11653],{},"2 min",[464,11655,11656],{},"人",[446,11658,11659,11662,11665],{},[464,11660,11661],{},"2 分类",[464,11663,11664],{},"5 min",[464,11666,11667],{},"AI",[446,11669,11670,11673,11676],{},[464,11671,11672],{},"3 深查",[464,11674,11675],{},"10-30 min",[464,11677,11678],{},"AI 主导，人 review",[446,11680,11681,11684,11686],{},[464,11682,11683],{},"4 整合",[464,11685,11664],{},[464,11687,11688],{},"AI 输出，人调整",[446,11690,11691,11696,11701],{},[464,11692,11693],{},[40,11694,11695],{},"合计",[464,11697,11698],{},[40,11699,11700],{},"~30 min \u002F PR",[464,11702],{},[17,11704,11705,11706,11709,11710,11713],{},"对比纯人工 review 一个中型 PR（~500 行 diff）通常 60-90 min，",[40,11707,11708],{},"省一半时间","，且",[40,11711,11712],{},"漏掉问题更少","（AI 看的范围比人广）。",[13,11715,11716],{"id":11716},"工具选择",[21,11718,11719,11724,11730,11736],{},[24,11720,11721,11723],{},[40,11722,1031],{}," ← 首选。能跑命令读 git history，做\"全局一致性扫描\"最强",[24,11725,11726,11729],{},[40,11727,11728],{},"Cursor + @codebase"," ← 中型项目够用，便宜",[24,11731,11732,11735],{},[40,11733,11734],{},"Augment"," ← 团队场景，原生集成 PR 流程",[24,11737,11738,11739,11742],{},"ChatGPT 网页版 ← ",[40,11740,11741],{},"不推荐","，上下文不够",[13,11744,972],{"id":972},[1834,11746,11748],{"id":11747},"_1-不要给-ai-pr-description作为唯一上下文","1. 不要给 AI \"PR description\"作为唯一上下文",[17,11750,11751,11752,11755],{},"PR description 是作者自己写的，",[40,11753,11754],{},"不一定准","。让 AI 自己读 diff，不要被 description 带偏。",[1834,11757,11759],{"id":11758},"_2-警惕-ai-的看起来-lgtm","2. 警惕 AI 的\"看起来 LGTM\"",[17,11761,11762,11763,11766],{},"AI 倾向于温和。如果它说\"看起来没问题\"，",[40,11764,11765],{},"强制让它给出 3 条具体担忧","——总能挖出来。",[1834,11768,11770],{"id":11769},"_3-别完全替代人脑","3. 别完全替代人脑",[17,11772,11773,11774,11777,11778,43],{},"AI 的 review 是",[40,11775,11776],{},"第一道筛","，不是终审。",[40,11779,11780],{},"关键判断（架构是否合理 \u002F 是否符合产品方向）只能人做",[1834,11782,11784],{"id":11783},"_4-注意-token-预算","4. 注意 token 预算",[17,11786,11787,11788,11791],{},"大 PR review 容易烧 $1-5。",[40,11789,11790],{},"对小 PR（\u003C 50 行）直接人脑 review","，不值得开 AI。",[11624,11793],{},[13,11795,11797],{"id":11796},"bonus把这套做成-git-hook","Bonus：把这套做成 git hook",[17,11799,11800],{},"把 Step 2-3 写成一个 shell 脚本 + Claude Code prompt 文件，挂在 PR 创建\u002F更新时自动跑：",[100,11802,11804],{"className":298,"code":11803,"language":300,"meta":105,"style":105},"# .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",[107,11805,11806,11811,11816,11828,11837,11842],{"__ignoreMap":105},[110,11807,11808],{"class":112,"line":113},[110,11809,11810],{"class":336},"# .github\u002Fhooks\u002Fpr-review.sh （示意）\n",[110,11812,11813],{"class":112,"line":120},[110,11814,11815],{"class":336},"#!\u002Fbin\u002Fbash\n",[110,11817,11818,11820,11822,11824,11826],{"class":112,"line":127},[110,11819,4733],{"class":307},[110,11821,4736],{"class":311},[110,11823,11504],{"class":311},[110,11825,4739],{"class":1577},[110,11827,11509],{"class":311},[110,11829,11830,11832,11835],{"class":112,"line":134},[110,11831,746],{"class":307},[110,11833,11834],{"class":315}," --prompt-file=.github\u002Fhooks\u002Freview-prompt.md",[110,11836,1671],{"class":315},[110,11838,11839],{"class":112,"line":140},[110,11840,11841],{"class":315},"            --output-file=\u002Ftmp\u002Freview.md\n",[110,11843,11844,11846,11849,11852,11855,11858],{"class":112,"line":150},[110,11845,1645],{"class":307},[110,11847,11848],{"class":311}," pr",[110,11850,11851],{"class":311}," comment",[110,11853,11854],{"class":123}," $PR_NUMBER ",[110,11856,11857],{"class":315},"--body-file",[110,11859,11860],{"class":311}," \u002Ftmp\u002Freview.md\n",[17,11862,11863],{},"完整 GitHub Actions 工作流即将整理上线。",[11624,11865],{},[17,11867,11868,11869,588,11872,43],{},"继续阅读：",[1181,11870,11871],{"href":2547},"陌生项目 onboarding 工作流",[1181,11873,11875],{"href":11874},"\u002Fplaybook\u002Frefactor\u002Flarge-refactor-with-ai-agent","大型重构工作流",[700,11877,11878],{},"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":105,"searchDepth":127,"depth":127,"links":11880},[11881,11882,11883,11894,11895,11896,11902],{"id":11422,"depth":120,"text":11422},{"id":11445,"depth":120,"text":11445},{"id":11467,"depth":120,"text":11468,"children":11884},[11885,11886,11887,11893],{"id":11471,"depth":127,"text":11472},{"id":11536,"depth":127,"text":11537},{"id":11552,"depth":127,"text":11553,"children":11888},[11889,11890,11891,11892],{"id":11560,"depth":134,"text":11561},{"id":11570,"depth":134,"text":11571},{"id":11589,"depth":134,"text":11590},{"id":11599,"depth":134,"text":11600},{"id":11609,"depth":127,"text":11610},{"id":11628,"depth":120,"text":11628},{"id":11716,"depth":120,"text":11716},{"id":972,"depth":120,"text":972,"children":11897},[11898,11899,11900,11901],{"id":11747,"depth":127,"text":11748},{"id":11758,"depth":127,"text":11759},{"id":11769,"depth":127,"text":11770},{"id":11783,"depth":127,"text":11784},{"id":11796,"depth":120,"text":11797},"\u002Fog\u002Fplaybook\u002Fai-code-review.png","用 Claude Code \u002F Cursor 给 PR 做第一道 review 的标准化工作流：风险扫描、命名一致性、测试覆盖、文档同步。",{},"\u002Fplaybook\u002Freview\u002Fai-code-review-workflow","2026-06-01",[1313,2575,11909],"coding\u002Fagent\u002Faugment",{"title":11417,"description":11904},"playbook\u002Freview\u002Fai-code-review-workflow",[11913,11914,1031,5798],"code review","PR","2026-06-15","t09WfO0oBlGLWe6k_9Q9vCP5UiVK2HxMSQqK1Ipa43Q",{"id":11918,"title":11919,"body":11920,"category":12535,"cover":12536,"description":12537,"extension":104,"meta":12538,"navigation":130,"path":11874,"published":12539,"relatedTools":12540,"seo":12541,"stem":12542,"tags":12543,"updated":12546,"__hash__":12547},"playbook\u002Fplaybook\u002Frefactor\u002Flarge-refactor-with-ai-agent.md","用 AI Agent 跑大型重构：不翻车工作流",{"type":10,"value":11921,"toc":12508},[11922,11924,11931,11948,11954,11956,11959,11966,11969,11972,11989,11992,11999,12006,12026,12032,12039,12046,12048,12052,12056,12059,12065,12075,12079,12085,12091,12095,12128,12136,12199,12204,12208,12211,12217,12222,12242,12246,12249,12298,12304,12307,12311,12335,12337,12339,12401,12403,12407,12414,12418,12424,12427,12436,12440,12447,12451,12457,12459,12463,12470,12489,12498,12500,12505],[13,11923,15],{"id":15},[17,11925,11926,11927,11930],{},"任何",[40,11928,11929],{},"符合下列任意一条","的重构都属于\"大型重构\"：",[21,11932,11933,11936,11939,11942,11945],{},[24,11934,11935],{},"影响超过 30 个文件",[24,11937,11938],{},"涉及 API 签名变更（调用方需要同步改）",[24,11940,11941],{},"涉及数据格式变更（DB schema \u002F 序列化协议）",[24,11943,11944],{},"跨模块、跨进程",[24,11946,11947],{},"需要保留向后兼容",[17,11949,11950,11953],{},[40,11951,11952],{},"这类任务用 IDE 手改太慢，让 AI 一次性跑完又容易翻车。"," 本工作流的目标是：让 AI 跑大头，但每一步可验证、可回滚。",[11624,11955],{},[13,11957,11958],{"id":11958},"核心原则",[1834,11960,11962,11963],{"id":11961},"_1-任务必须拆","1. ",[40,11964,11965],{},"任务必须拆",[17,11967,11968],{},"不要给 AI：\"把整个项目从 Pinia 1 迁到 Pinia 2\"。",[17,11970,11971],{},"要给 AI：",[21,11973,11974,11977,11980,11983,11986],{},[24,11975,11976],{},"Step A: 找出所有用 Pinia 1 API 的文件，输出清单",[24,11978,11979],{},"Step B: 改第 1-10 个文件，跑测试",[24,11981,11982],{},"Step C: 改第 11-20 个，跑测试",[24,11984,11985],{},"...",[24,11987,11988],{},"Step Z: 全跑通后删 Pinia 1 依赖",[17,11990,11991],{},"每步独立 commit。",[1834,11993,11995,11996],{"id":11994},"_2-每步都有-checkpoint","2. ",[40,11997,11998],{},"每步都有 checkpoint",[17,12000,12001,12002,12005],{},"checkpoint = 一个",[40,12003,12004],{},"可机器验证","的状态。比如：",[21,12007,12008,12014,12019],{},[24,12009,12010,12013],{},[107,12011,12012],{},"pnpm typecheck"," 通过",[24,12015,12016,12013],{},[107,12017,12018],{},"pnpm test",[24,12020,12021,12022,12025],{},"启动 dev server 后 ",[107,12023,12024],{},"curl \u002Fhealth"," 返 200",[17,12027,12028,12031],{},[40,12029,12030],{},"没有 checkpoint 的步骤不要放进工作流","——因为你没法知道它对不对。",[1834,12033,12035,12036],{"id":12034},"_3-git-隔离","3. ",[40,12037,12038],{},"git 隔离",[17,12040,12041,12042,12045],{},"每个大任务开独立分支。每个 step 一个 commit。\n",[40,12043,12044],{},"不要让 AI 直接 push 到主干","，永远先 PR。",[11624,12047],{},[13,12049,12051],{"id":12050},"完整工作流6-阶段","完整工作流：6 阶段",[1834,12053,12055],{"id":12054},"阶段-1调研人工-ai30-min","阶段 1：调研（人工 + AI，30 min）",[17,12057,12058],{},"让 AI 帮你回答 4 个问题：",[100,12060,12063],{"className":12061,"code":12062,"language":282,"meta":105},[280],"针对【重构目标】，请回答：\n\n1. 影响面：哪些文件会被修改？给出完整列表 + 行数估算\n2. 阻塞依赖：有没有外部库 \u002F API 升级也需要做？\n3. 不可逆操作：有没有数据迁移 \u002F 二进制格式变更？\n4. 测试覆盖：现有测试能 cover 多少？哪些路径无测试？\n\n不要开始改代码，只产出调研报告。\n",[107,12064,12062],{"__ignoreMap":105},[17,12066,12067,12070,12071,12074],{},[40,12068,12069],{},"输出物","：一份 markdown 报告。",[40,12072,12073],{},"人工 review 这份报告再决定是否继续","——很多时候你会发现\"这个重构不该做\"或\"该用别的方案\"。",[1834,12076,12078],{"id":12077},"阶段-2拆任务人工-ai20-min","阶段 2：拆任务（人工 + AI，20 min）",[100,12080,12083],{"className":12081,"code":12082,"language":282,"meta":105},[280],"基于调研报告，请把整个重构拆成 N 个 step。每个 step 满足：\n\n- 影响 ≤ 5 个文件\n- 有明确的 checkpoint（typecheck \u002F 测试 \u002F 编译）\n- 每步独立可 commit、可回滚\n- step 之间有依赖时显式标出\n\n输出 markdown 表格：step 编号 | 描述 | 影响文件 | checkpoint | 依赖 step\n",[107,12084,12082],{"__ignoreMap":105},[17,12086,12087,12090],{},[40,12088,12089],{},"人工 review 这份拆解","——如果某 step 影响超过 5 文件，强制再拆。",[1834,12092,12094],{"id":12093},"阶段-3建脚手架ai10-min","阶段 3：建脚手架（AI，10 min）",[100,12096,12098],{"className":298,"code":12097,"language":300,"meta":105,"style":105},"git checkout -b refactor\u002Fpinia-2-migration\nmkdir -p .refactor\n# 把拆解后的 task list 存进去\n",[107,12099,12100,12113,12123],{"__ignoreMap":105},[110,12101,12102,12104,12107,12110],{"class":112,"line":113},[110,12103,4733],{"class":307},[110,12105,12106],{"class":311}," checkout",[110,12108,12109],{"class":315}," -b",[110,12111,12112],{"class":311}," refactor\u002Fpinia-2-migration\n",[110,12114,12115,12118,12120],{"class":112,"line":120},[110,12116,12117],{"class":307},"mkdir",[110,12119,4553],{"class":315},[110,12121,12122],{"class":311}," .refactor\n",[110,12124,12125],{"class":112,"line":127},[110,12126,12127],{"class":336},"# 把拆解后的 task list 存进去\n",[17,12129,12130,953,12133],{},[40,12131,12132],{},"关键文件",[107,12134,12135],{},".refactor\u002FSTATUS.md",[100,12137,12139],{"className":6710,"code":12138,"language":6712,"meta":105,"style":105},"# Pinia 2 Migration Status\n\n- [ ] step-01: 列出所有 Pinia 1 调用点\n- [ ] step-02: 改 stores\u002Fuser.ts + 调用方\n- [ ] step-03: 改 stores\u002Fcart.ts + 调用方\n...\n\n## Checkpoints\n- [ ] all `pnpm typecheck` passes\n- [ ] all `pnpm test` passes\n- [ ] dev server boots\n- [ ] e2e smoke test passes\n",[107,12140,12141,12146,12150,12155,12160,12165,12170,12174,12179,12184,12189,12194],{"__ignoreMap":105},[110,12142,12143],{"class":112,"line":113},[110,12144,12145],{},"# Pinia 2 Migration Status\n",[110,12147,12148],{"class":112,"line":120},[110,12149,131],{"emptyLinePlaceholder":130},[110,12151,12152],{"class":112,"line":127},[110,12153,12154],{},"- [ ] step-01: 列出所有 Pinia 1 调用点\n",[110,12156,12157],{"class":112,"line":134},[110,12158,12159],{},"- [ ] step-02: 改 stores\u002Fuser.ts + 调用方\n",[110,12161,12162],{"class":112,"line":140},[110,12163,12164],{},"- [ ] step-03: 改 stores\u002Fcart.ts + 调用方\n",[110,12166,12167],{"class":112,"line":150},[110,12168,12169],{},"...\n",[110,12171,12172],{"class":112,"line":5},[110,12173,131],{"emptyLinePlaceholder":130},[110,12175,12176],{"class":112,"line":162},[110,12177,12178],{},"## Checkpoints\n",[110,12180,12181],{"class":112,"line":168},[110,12182,12183],{},"- [ ] all `pnpm typecheck` passes\n",[110,12185,12186],{"class":112,"line":177},[110,12187,12188],{},"- [ ] all `pnpm test` passes\n",[110,12190,12191],{"class":112,"line":186},[110,12192,12193],{},"- [ ] dev server boots\n",[110,12195,12196],{"class":112,"line":195},[110,12197,12198],{},"- [ ] e2e smoke test passes\n",[17,12200,12201,43],{},[40,12202,12203],{},"让 AI 每完成一步就更新这份文件",[1834,12205,12207],{"id":12206},"阶段-4执行ai-主导1-n-小时","阶段 4：执行（AI 主导，1-N 小时）",[17,12209,12210],{},"每个 step 用同一个 prompt 模板：",[100,12212,12215],{"className":12213,"code":12214,"language":282,"meta":105},[280],"现在执行 step-{N}：{描述}。\n\n要求：\n1. 只改清单内的文件，不要碰其他文件\n2. 改完后跑 checkpoint：{checkpoint 命令}\n3. 如果 checkpoint 失败，先 debug 失败原因，再决定是修改还是回滚\n4. 成功后：\n   a. 在 .refactor\u002FSTATUS.md 把这一项打勾\n   b. git add 改动 + git commit -m \"refactor(step-{N}): {描述}\"\n5. 不要继续下一步，等我确认\n",[107,12216,12214],{"__ignoreMap":105},[17,12218,12219],{},[40,12220,12221],{},"关键纪律：",[21,12223,12224,12230,12236],{},[24,12225,12226,12229],{},[40,12227,12228],{},"每步 commit","，不要憋一个大 commit",[24,12231,12232,12235],{},[40,12233,12234],{},"每步等人确认","，AI 不要连续跑 5 步——很容易在第 3 步偏轨道但你没发现",[24,12237,12238,12239],{},"如果 step 失败 2 次，",[40,12240,12241],{},"停下来人工介入",[1834,12243,12245],{"id":12244},"阶段-5合并验证人工-ai30-min","阶段 5：合并验证（人工 + AI，30 min）",[17,12247,12248],{},"所有 step 完成后：",[100,12250,12252],{"className":298,"code":12251,"language":300,"meta":105,"style":105},"# 1. 跑全套测试\npnpm test\npnpm e2e\n\n# 2. 启动 dev server，手测核心路径\npnpm dev\n\n# 3. 让 AI 做\"自我代码审查\"\n",[107,12253,12254,12259,12266,12273,12277,12282,12289,12293],{"__ignoreMap":105},[110,12255,12256],{"class":112,"line":113},[110,12257,12258],{"class":336},"# 1. 跑全套测试\n",[110,12260,12261,12263],{"class":112,"line":120},[110,12262,5091],{"class":307},[110,12264,12265],{"class":311}," test\n",[110,12267,12268,12270],{"class":112,"line":127},[110,12269,5091],{"class":307},[110,12271,12272],{"class":311}," e2e\n",[110,12274,12275],{"class":112,"line":134},[110,12276,131],{"emptyLinePlaceholder":130},[110,12278,12279],{"class":112,"line":140},[110,12280,12281],{"class":336},"# 2. 启动 dev server，手测核心路径\n",[110,12283,12284,12286],{"class":112,"line":150},[110,12285,5091],{"class":307},[110,12287,12288],{"class":311}," dev\n",[110,12290,12291],{"class":112,"line":5},[110,12292,131],{"emptyLinePlaceholder":130},[110,12294,12295],{"class":112,"line":162},[110,12296,12297],{"class":336},"# 3. 让 AI 做\"自我代码审查\"\n",[100,12299,12302],{"className":12300,"code":12301,"language":282,"meta":105},[280],"请审视本分支相对 main 的所有改动，找出：\n- 不一致：相同模式有没有漏改的地方\n- 风险：有没有可能的运行时错误（null deref、type 转换失败）\n- 兼容：旧代码调用新代码会不会出问题\n- 性能：有没有 N+1 查询、不必要的循环\n\n输出 markdown 报告，每条带文件路径和行号。\n",[107,12303,12301],{"__ignoreMap":105},[17,12305,12306],{},"人工 review 报告，必要时再开新 step 修补。",[1834,12308,12310],{"id":12309},"阶段-6发布人工时间不定","阶段 6：发布（人工，时间不定）",[21,12312,12313,12316,12321,12324],{},[24,12314,12315],{},"发 PR，标题写清楚 \"Refactor: ...\" + 影响面摘要",[24,12317,12318],{},[40,12319,12320],{},"PR description 直接贴 .refactor\u002FSTATUS.md 内容",[24,12322,12323],{},"至少一个 reviewer 看",[24,12325,12326,12327,12330,12331,12334],{},"合并后保留 ",[107,12328,12329],{},".refactor\u002F"," 目录在 git 里",[40,12332,12333],{},"作为历史记录","——下次类似重构可参考",[11624,12336],{},[13,12338,11716],{"id":11716},[440,12340,12341,12353],{},[443,12342,12343],{},[446,12344,12345,12348,12351],{},[449,12346,12347],{},"阶段",[449,12349,12350],{},"推荐工具",[449,12352,4236],{},[459,12354,12355,12365,12379,12390],{},[446,12356,12357,12360,12362],{},[464,12358,12359],{},"调研 \u002F 拆任务",[464,12361,1031],{},[464,12363,12364],{},"自由探索能力强",[446,12366,12367,12370,12376],{},[464,12368,12369],{},"执行 step",[464,12371,12372,12375],{},[40,12373,12374],{},"Windsurf Cascade"," 或 Claude Code",[464,12377,12378],{},"长任务能力",[446,12380,12381,12384,12387],{},[464,12382,12383],{},"单步快速改",[464,12385,12386],{},"Cursor Composer",[464,12388,12389],{},"Tab 流畅",[446,12391,12392,12395,12398],{},[464,12393,12394],{},"自我代码审查",[464,12396,12397],{},"Claude Code（独立 session）",[464,12399,12400],{},"切换 context 更客观",[13,12402,972],{"id":972},[1834,12404,12406],{"id":12405},"_1-不要相信-ai-说我已完成","1. 不要相信 AI 说\"我已完成\"",[17,12408,12409,12410,12413],{},"每步都要",[40,12411,12412],{},"自己跑 checkpoint"," 确认，不能信 AI 的口头报告。",[1834,12415,12417],{"id":12416},"_2-别让-ai-改测试","2. 别让 AI 改测试",[17,12419,12420,12421,43],{},"如果跑测试失败，AI 倾向于\"修测试让它通过\"——这是",[40,12422,12423],{},"最危险的反模式",[17,12425,12426],{},"明确禁止：",[1975,12428,12429],{},[17,12430,12431,12432,12435],{},"\"如果测试失败，分析为什么失败。",[40,12433,12434],{},"不允许修改测试文件","——除非测试本身有 bug 且你能在改之前向我证明。\"",[1834,12437,12439],{"id":12438},"_3-不要跨大版本改依赖","3. 不要跨大版本改依赖",[17,12441,12442,12443,12446],{},"step 中遇到\"顺便升一下这个库\"的诱惑——",[40,12444,12445],{},"说不","。把依赖升级单独开 PR。",[1834,12448,12450],{"id":12449},"_4-注意-token-成本","4. 注意 token 成本",[17,12452,12453,12454,43],{},"跨 50 文件的重构容易烧掉 $10-50 的 token（Claude Sonnet 4.5）。",[40,12455,12456],{},"先估预算再开始",[11624,12458],{},[13,12460,12462],{"id":12461},"实战案例本站项目从-src-改根级","实战案例：本站项目从 src\u002F 改根级",[17,12464,12465,12466,12469],{},"我们自己用这套工作流把姊妹站 oltools.net 从 ",[107,12467,12468],{},"src\u002F"," 根布局改成 Nuxt 4 标准布局，影响 200+ 文件。",[21,12471,12472,12475,12478,12481,12484],{},[24,12473,12474],{},"调研：30 min",[24,12476,12477],{},"拆任务：拆成 14 个 step",[24,12479,12480],{},"执行：4 小时（Windsurf Cascade，重度人工 review）",[24,12482,12483],{},"合并验证：1 小时",[24,12485,12486],{},[40,12487,12488],{},"零线上事故",[17,12490,12491,12492,12497],{},"完整 commit 历史可看 ",[1181,12493,12496],{"href":12494,"rel":12495},"https:\u002F\u002Fgithub.com\u002Faiho\u002Foltools",[1209],"oltools.net 仓库","（即将开放）。",[11624,12499],{},[17,12501,11868,12502,43],{},[1181,12503,12504],{"href":11906},"AI 做 PR review 工作流",[700,12506,12507],{},"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 .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}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);}",{"title":105,"searchDepth":127,"depth":127,"links":12509},[12510,12511,12519,12527,12528,12534],{"id":15,"depth":120,"text":15},{"id":11958,"depth":120,"text":11958,"children":12512},[12513,12515,12517],{"id":11961,"depth":127,"text":12514},"1. 任务必须拆",{"id":11994,"depth":127,"text":12516},"2. 每步都有 checkpoint",{"id":12034,"depth":127,"text":12518},"3. git 隔离",{"id":12050,"depth":120,"text":12051,"children":12520},[12521,12522,12523,12524,12525,12526],{"id":12054,"depth":127,"text":12055},{"id":12077,"depth":127,"text":12078},{"id":12093,"depth":127,"text":12094},{"id":12206,"depth":127,"text":12207},{"id":12244,"depth":127,"text":12245},{"id":12309,"depth":127,"text":12310},{"id":11716,"depth":120,"text":11716},{"id":972,"depth":120,"text":972,"children":12529},[12530,12531,12532,12533],{"id":12405,"depth":127,"text":12406},{"id":12416,"depth":127,"text":12417},{"id":12438,"depth":127,"text":12439},{"id":12449,"depth":127,"text":12450},{"id":12461,"depth":120,"text":12462},"refactor","\u002Fog\u002Fplaybook\u002Flarge-refactor.png","跨 50+ 文件的重构任务如何让 AI Agent 安全完成？任务拆解、checkpoint、git 隔离、验证策略与回滚预案的完整 playbook。",{},"2026-05-15",[1313,2576,11909],{"title":11919,"description":12537},"playbook\u002Frefactor\u002Flarge-refactor-with-ai-agent",[12544,12545,1031,3191,5798],"重构","Agent","2026-06-12","wtg_idmRZ3PBBQlCMTaD7GBi9U74mmV8uBlvN5dIArQ",{"id":12549,"title":12550,"body":12551,"category":717,"cover":12989,"description":12990,"extension":104,"meta":12991,"navigation":130,"path":2547,"published":12992,"relatedTools":12993,"seo":12994,"stem":12995,"tags":12996,"updated":12999,"__hash__":13000},"playbook\u002Fplaybook\u002Fonboarding\u002Flegacy-codebase-onboarding.md","用 AI 接手老代码：陌生项目 onboarding 工作流",{"type":10,"value":12552,"toc":12976},[12553,12555,12569,12574,12578,12584,12590,12592,12596,12660,12663,12668,12677,12683,12685,12689,12692,12698,12714,12716,12720,12726,12736,12745,12747,12751,12758,12764,12774,12776,12780,12786,12792,12794,12798,12801,12807,12813,12815,12818,12899,12906,12908,12910,12942,12944,12968,12973],[13,12554,15],{"id":15},[21,12556,12557,12560,12563,12566],{},[24,12558,12559],{},"新人入职，被丢给一个 5 年老项目",[24,12561,12562],{},"接手前同事跑路留下的代码",[24,12564,12565],{},"评估一个开源项目能否用作技术选型",[24,12567,12568],{},"给客户做代码 audit \u002F 接手报价",[17,12570,12571],{},[40,12572,12573],{},"用人脑读两周做的事，AI 协助下 2-4 小时完成 80%。",[13,12575,12577],{"id":12576},"总览六步法","总览：六步法",[100,12579,12582],{"className":12580,"code":12581,"language":282,"meta":105},[280],"1. clone & 准备 → 2. 项目体检 → 3. 架构图 → 4. 核心路径 →\n5. 风险与债务 → 6. 关键问题清单\n",[107,12583,12581],{"__ignoreMap":105},[17,12585,12586,12587,43],{},"每一步都有",[40,12588,12589],{},"具体 Prompt + 验收标准",[11624,12591],{},[13,12593,12595],{"id":12594},"step-1-clone-与环境准备10-分钟","Step 1 — clone 与环境准备（10 分钟）",[100,12597,12599],{"className":298,"code":12598,"language":300,"meta":105,"style":105},"git clone \u003Crepo>\ncd \u003Crepo>\n# 关键：先让 AI 看 git 历史活跃度\ngit log --since='1 year ago' --pretty=format:'%h %s' | wc -l\n",[107,12600,12601,12618,12630,12635],{"__ignoreMap":105},[110,12602,12603,12605,12608,12610,12613,12616],{"class":112,"line":113},[110,12604,4733],{"class":307},[110,12606,12607],{"class":311}," clone",[110,12609,6782],{"class":1577},[110,12611,12612],{"class":311},"rep",[110,12614,12615],{"class":123},"o",[110,12617,6791],{"class":1577},[110,12619,12620,12622,12624,12626,12628],{"class":112,"line":120},[110,12621,7119],{"class":315},[110,12623,6782],{"class":1577},[110,12625,12612],{"class":311},[110,12627,12615],{"class":123},[110,12629,6791],{"class":1577},[110,12631,12632],{"class":112,"line":127},[110,12633,12634],{"class":336},"# 关键：先让 AI 看 git 历史活跃度\n",[110,12636,12637,12639,12641,12644,12647,12649,12652,12654,12657],{"class":112,"line":134},[110,12638,4733],{"class":307},[110,12640,11516],{"class":311},[110,12642,12643],{"class":315}," --since=",[110,12645,12646],{"class":311},"'1 year ago'",[110,12648,11522],{"class":315},[110,12650,12651],{"class":311},"'%h %s'",[110,12653,1578],{"class":1577},[110,12655,12656],{"class":307}," wc",[110,12658,12659],{"class":315}," -l\n",[17,12661,12662],{},"打开 Claude Code 或 Cursor，进入项目目录。",[17,12664,12665,953],{},[40,12666,12667],{},"第一条 Prompt",[1975,12669,12670],{},[17,12671,12672,12673,12676],{},"\"请扫描当前目录，告诉我：(1) 这是什么类型的项目；(2) 主要技术栈；(3) 入口文件在哪；(4) 有没有 README \u002F docs。",[40,12674,12675],{},"先不要读源码","，只看 package.json \u002F pyproject.toml \u002F Cargo.toml \u002F go.mod 这类元文件。\"",[17,12678,12679,12682],{},[40,12680,12681],{},"为什么","：先让 AI 建立宏观认知，避免它一上来就被某个文件带偏。",[11624,12684],{},[13,12686,12688],{"id":12687},"step-2-项目体检20-分钟","Step 2 — 项目体检（20 分钟）",[17,12690,12691],{},"让 AI 出一份\"健康报告\"：",[100,12693,12696],{"className":12694,"code":12695,"language":282,"meta":105},[280],"请生成一份项目体检报告，包含：\n\n1. 代码量：按语言\u002F目录分布\n2. 测试覆盖：有没有测试，跑得起来吗，覆盖率多少\n3. 依赖健康：有几个依赖、最旧的几个分别多久没更新\n4. 文档完整度：README \u002F CHANGELOG \u002F CONTRIBUTING \u002F docs\u002F\n5. CI 状态：有 CI 吗，最近一次跑成功了吗\n6. 死代码迹象：明显未使用的文件 \u002F 函数\n\n不要猜测，只报告确凿能看到的事实。每条结论给出依据。\n",[107,12697,12695],{"__ignoreMap":105},[17,12699,12700,12703,12704,588,12707,588,12710,12713],{},[40,12701,12702],{},"Claude Code 做这事最强","——它会自己跑 ",[107,12705,12706],{},"find",[107,12708,12709],{},"git log",[107,12711,12712],{},"npm outdated"," 这类命令，给出真凭实据。",[11624,12715],{},[13,12717,12719],{"id":12718},"step-3-架构图30-分钟","Step 3 — 架构图（30 分钟）",[100,12721,12724],{"className":12722,"code":12723,"language":282,"meta":105},[280],"基于刚才的体检，画一张项目架构图（Mermaid 格式）。\n要求：\n- 顶层模块用方框\n- 数据流向用箭头\n- 外部依赖（DB \u002F 第三方 API \u002F 队列）单独标出\n- **如果某个边界你不确定，标 \"?\" 而不是猜**\n\n画完后，用 5-10 句话解释这个架构的核心思路。\n",[107,12725,12723],{"__ignoreMap":105},[17,12727,12728,12731,12732,12735],{},[40,12729,12730],{},"关键技巧","：明确告诉 AI ",[40,12733,12734],{},"\"不确定就标 ?\"","，否则它会编。",[17,12737,12738,12739,12744],{},"把生成的 Mermaid 复制到 ",[1181,12740,12743],{"href":12741,"rel":12742},"https:\u002F\u002Fmermaid.live",[1209],"mermaid.live"," 验证可视化效果。",[11624,12746],{},[13,12748,12750],{"id":12749},"step-4-找到核心路径30-分钟","Step 4 — 找到\"核心路径\"（30 分钟）",[17,12752,12753,12754,12757],{},"这是 onboarding 最关键的一步。每个项目都有 1-3 条",[40,12755,12756],{},"核心业务路径","——用户最常用的功能链路。把它走通，整个项目就懂一半了。",[100,12759,12762],{"className":12760,"code":12761,"language":282,"meta":105},[280],"请找出本项目的 3 条核心业务路径（按重要性排序）：\n\n每条路径需要回答：\n1. 用户从哪触发（URL \u002F API endpoint \u002F CLI 命令）\n2. 经过哪些关键文件 \u002F 函数\n3. 数据如何流动（DB 读什么、写什么）\n4. 在哪里返回结果\n\n用编号列表给出，每个文件名 + 行号都要确凿。\n",[107,12763,12761],{"__ignoreMap":105},[17,12765,12766,12769,12770,12773],{},[40,12767,12768],{},"验收标准","：你能照着这份路径，",[40,12771,12772],{},"自己手动 trace 一遍而不卡壳","。如果哪一步看不懂，回去问 AI 那一段具体是什么。",[11624,12775],{},[13,12777,12779],{"id":12778},"step-5-风险-技术债清单30-分钟","Step 5 — 风险 + 技术债清单（30 分钟）",[100,12781,12784],{"className":12782,"code":12783,"language":282,"meta":105},[280],"请审视代码库，列出：\n\nA. 高风险代码（运行时容易出问题）\n   - 没有错误处理的 IO \u002F 网络调用\n   - 明显的 race condition \u002F 并发问题\n   - 写死的 secret \u002F API key\n   - SQL 注入 \u002F XSS 风险\n\nB. 技术债（影响开发效率）\n   - 重复的代码 (DRY 违反)\n   - 函数过长（>200 行）\n   - 圈复杂度过高的函数\n   - 循环依赖\n\nC. 维护性差的部分\n   - 完全没注释的关键算法\n   - \"magic number\"\n   - 命名混乱的模块\n\n每条给出文件路径 + 行号，并用 1 句话解释为什么是问题。\n",[107,12785,12783],{"__ignoreMap":105},[17,12787,12788,12791],{},[40,12789,12790],{},"这一步的输出可以直接交给客户\u002F老板","——如果你是接外包、做 audit，这就是付费报告的核心内容。",[11624,12793],{},[13,12795,12797],{"id":12796},"step-6-关键问题清单20-分钟","Step 6 — 关键问题清单（20 分钟）",[17,12799,12800],{},"最后一步，让 AI 列出\"作为新人接手，你最该问原作者的 10 个问题\"：",[100,12802,12805],{"className":12803,"code":12804,"language":282,"meta":105},[280],"假设你即将接手这个项目，原作者今天最后一天上班，\n你只能问他 10 个问题。请列出这 10 个问题，按重要性排序。\n\n每个问题要：\n- 具体（不能是\"这个项目怎么部署\"这种宽泛问题）\n- 可被一句话回答\n- 解决之后你能独立运行\u002F修改这个项目\n",[107,12806,12804],{"__ignoreMap":105},[17,12808,12809,12812],{},[40,12810,12811],{},"这份清单极其有价值","——它把\"未知的未知\"转化成\"已知的未知\"。你可以拿着它去问前同事 \u002F 客户 \u002F 文档 \u002F 社区。",[11624,12814],{},[13,12816,12817],{"id":12817},"总耗时与产出",[440,12819,12820,12831],{},[443,12821,12822],{},[446,12823,12824,12826,12828],{},[449,12825,12347],{},[449,12827,11640],{},[449,12829,12830],{},"产出物",[459,12832,12833,12844,12853,12863,12872,12883],{},[446,12834,12835,12838,12841],{},[464,12836,12837],{},"1-2",[464,12839,12840],{},"30 min",[464,12842,12843],{},"项目体检报告",[446,12845,12846,12848,12850],{},[464,12847,9869],{},[464,12849,12840],{},[464,12851,12852],{},"Mermaid 架构图",[446,12854,12855,12858,12860],{},[464,12856,12857],{},"4",[464,12859,12840],{},[464,12861,12862],{},"核心业务路径文档",[446,12864,12865,12867,12869],{},[464,12866,10324],{},[464,12868,12840],{},[464,12870,12871],{},"风险 + 技术债清单",[446,12873,12874,12877,12880],{},[464,12875,12876],{},"6",[464,12878,12879],{},"20 min",[464,12881,12882],{},"关键问题清单",[446,12884,12885,12889,12894],{},[464,12886,12887],{},[40,12888,11695],{},[464,12890,12891],{},[40,12892,12893],{},"~2.5 小时",[464,12895,12896],{},[40,12897,12898],{},"5 份可交付文档",[17,12900,12901,12902,12905],{},"把这 5 份文档存进项目 ",[107,12903,12904],{},"docs\u002Fonboarding\u002F","，下一个新人来直接读，再省 2 小时。",[11624,12907],{},[13,12909,11716],{"id":11716},[21,12911,12912,12919,12928,12937],{},[24,12913,12914,12916,12917,43],{},[40,12915,1031],{},"：最适合这种\"广撒网\"任务，自己跑命令、读文件。",[40,12918,4230],{},[24,12920,12921,12927],{},[40,12922,12923,12924],{},"Cursor + ",[107,12925,12926],{},"@codebase","：体验也很好，胜在便宜。中型项目（\u003C 5 万行）够用。",[24,12929,12930,12932,12933,12936],{},[40,12931,2299],{},"：可以，但要手动 ",[107,12934,12935],{},"add"," 文件，节奏更慢。",[24,12938,12939,12941],{},[40,12940,3475],{},"：国内项目首选，中文 prompt 体验最佳。",[13,12943,972],{"id":972},[21,12945,12946,12956,12962],{},[24,12947,12948,12951,12952,12955],{},[40,12949,12950],{},"不要让 AI 一次读完整个项目","——它会丢上下文。",[40,12953,12954],{},"分模块"," + 每模块独立提问。",[24,12957,12958,12961],{},[40,12959,12960],{},"关键结论要让它给出文件:行号"," 作为依据，否则容易编。",[24,12963,12964,12967],{},[40,12965,12966],{},"不要过度依赖 AI 的\"我觉得\"","——遇到不确定的地方，强制让它标记不确定，然后人工 verify。",[17,12969,12970,12971,43],{},"下一篇：",[1181,12972,11875],{"href":11874},[700,12974,12975],{},"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 .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}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);}",{"title":105,"searchDepth":127,"depth":127,"links":12977},[12978,12979,12980,12981,12982,12983,12984,12985,12986,12987,12988],{"id":15,"depth":120,"text":15},{"id":12576,"depth":120,"text":12577},{"id":12594,"depth":120,"text":12595},{"id":12687,"depth":120,"text":12688},{"id":12718,"depth":120,"text":12719},{"id":12749,"depth":120,"text":12750},{"id":12778,"depth":120,"text":12779},{"id":12796,"depth":120,"text":12797},{"id":12817,"depth":120,"text":12817},{"id":11716,"depth":120,"text":11716},{"id":972,"depth":120,"text":972},"\u002Fog\u002Fplaybook\u002Flegacy-onboarding.png","新人面对几十万行老代码不知从何下手？用 Claude Code \u002F Cursor 在 2 小时内画出项目架构、找到核心入口、定位关键风险点的标准化工作流。",{},"2026-04-25",[1313,2575,4862],{"title":12550,"description":12990},"playbook\u002Fonboarding\u002Flegacy-codebase-onboarding",[717,12997,12998,1031],"代码理解","架构图","2026-06-08","0F1OVuaSvo8nT4EWBpyuDs7C5ypSOig0svKHVsTriyM",1782480894085]