“为啥应用慢”是性能问题里最糟的提问,得到的答案也最差。一个好的回归 Prompt 会点明指标(p50 / p99 / TTFB / LCP)、diff 窗口,并禁止猜测——只要 file:line 证据和 benchmark 数字,其他都不要。
一句话总结
- 永远别让 AI”把它变快”。喂给它一个指标、一个 diff 窗口(
oldSha…newSha)、一个交付物。下面 12 个模板就是按这个形状预设好的。 - 贴真实信号,不要贴感觉:导出成 JSON / Markdown 的 Chrome trace、一份
EXPLAIN ANALYZEplan、一段git diff,或 bundle-analyzer 报告。模型读文本 trace 很在行,但看不了图形火焰图,除非先走一步 vision。 - trace 大的时候用 1M token 上下文的模型(Claude Opus 4.7 / Sonnet 4.6、Gemini 3.1 Pro、GPT-5.5)——一份完整的 Chrome
.jsontrace 轻松超过 10 万 token。 - 给 LCP / INP / CLS 类 Prompt 锚定的 Core Web Vitals 目标(2026 年 6 月):LCP 低于 2.5 秒、INP 低于 200 毫秒、CLS 低于 0.1,全部按真实用户的第 75 百分位衡量。
适合哪些人
处理性能告警的值班、追慢 PR 的 lead、上线前要过 Core Web Vitals 的独立开发。只要你手里有一个变差的数字和一段可能解释它的 diff,这些 Prompt 就能把它变成一份排好序的假设清单,而不是一场瞎猜。
什么时候别用这些 Prompt
没有 baseline 指标就别用。“慢”没有数字会浪费所有人的时间,而且模型会很乐意为一个可能根本不存在的回归编出一堆听起来很合理的原因。也别拿 dev 环境的耗时来跑——要测生产,那里的热路径、数据量、缓存状态都不一样。
先选对模型和工具
Prompt 只是一半的活;你贴进去的东西更关键。
| 你手里的信号 | 该贴什么 | 合适的模型 |
|---|---|---|
| 前端 LCP / INP 回归 | 导出成 JSON 或 Markdown 的 Chrome trace | 1M 上下文模型(Opus 4.7、Sonnet 4.6、Gemini 3.1 Pro) |
| 慢接口 / N+1 | handler 代码 + 一份 EXPLAIN ANALYZE plan | Sonnet 4.6 或 GPT-5.5 |
| PR 引起的 bundle 增长 | webpack-bundle-analyzer / vite build --report 输出 + diff | 任意前沿模型 |
| 线上页面,还没 trace | 让 agent 通过 Chrome DevTools MCP 自己录一份 | 接了 MCP 的 Claude Code / Cursor |
2026 年 6 月的两个实用提醒:
- Chrome DevTools MCP(v0.19,2026 年 3 月发布)给 Claude Code、Cursor 这类 AI agent 提供了 29 个实时浏览器工具。它的
performance_start_trace会录制一份 trace,返回 LCP、CLS、FCP,并带 render-blocking 分析和网络依赖树——也就是 agent 自己去取证据,不用你手动导文件。详见 Chrome DevTools MCP 仓库。 - 原始 Chrome trace 体积很大。 一份真实的
.jsontrace 动辄几十万 token。先用转换工具(chperf、chrome-trace-analyzer)把它压成 Markdown,或者直接喂进 1M token 模型,每次只问一个窄问题。
Prompt 结构
每个性能回归 Prompt 都要带这六个要素:
- 角色:AI 扮演谁(SRE / Release Captain / staff 工程师 / QA Lead)。
- 上下文:技术栈、分支、失败日志、diff、dashboard URL。
- 目标:一个具体可交付物——根因、checklist、计划、ticket 列表、runbook。
- 限制:AI 不能做什么(别自动修、别瞎造文件路径)。
- 输出格式:编号清单、Markdown 表格、JSON、unified diff、可运行代码。
- 信号:真实的 trace、plan 或 diff,不是它的转述。
12 个可直接复制的 Prompt 模板
变量用 [方括号],方便你查找替换。2026 年 6 月的模型(Opus 4.7、Sonnet 4.6、GPT-5.5、Gemini 3.1 Pro)都能处理;trace 较重的几个建议用 1M 上下文模型。
1. p99 diff triage
p99 latency on `[endpoint]` jumped [fromMs]ms to [toMs]ms between `[oldSha]` and `[newSha]`. List 5 likely causes in priority order. For each: (a) suspicion strength, (b) one file:line or query to inspect, (c) one cheap check. Do not propose fixes yet. Cite only paths that appear in the diff I pasted.
可替换: endpoint, fromMs, toMs, oldSha, newSha
2. PR 性能风险扫描
Scan this PR diff for perf risks: (1) new synchronous I/O in a hot path, (2) loops calling DB/fetch inside, (3) a new large dep imported eagerly, (4) React re-render expansion (new context, unstable deps), (5) a missing index for a new query. Output file:line + severity. Ignore anything outside the diff.
3. N+1 猎人
In the function `[functionName]` at `[filePath]`, identify N+1 patterns: (a) loops calling DB/fetch, (b) Promise.all over single-item fetches, (c) recursive accessors hitting ORM lazy fields. For each, rewrite as a single batched call, with code.
可替换: functionName, filePath
4. bundle size 回归
Bundle grew from [oldKb] to [newKb] KB. Identify the top 3 contributors: (1) new direct deps and their gzipped size, (2) tree-shake failures (default import from a CJS-only library), (3) polyfill bloat (browserslist target changed?). Output one concrete fix per item.
可替换: oldKb, newKb
5. React render storm 诊断
Component `[component]` re-renders [nRenders] times per interaction. Diagnose: (1) unstable prop identity (objects/arrays created in render), (2) context provider value not memoized, (3) parent state too coarse, (4) a useEffect dep that changes every render. Output cause + the minimal fix.
可替换: component, nRenders
6. DB query plan 回归
The plan for `[query]` changed: it was an index scan + nested loop, now a sequential scan + hash join. Diagnose: (1) stale statistics (ANALYZE overdue?), (2) cardinality estimate off, (3) new column or index mismatch, (4) parameter sniffing. Output the most likely cause + the exact ANALYZE / pg_stat_user_indexes command to confirm it.
可替换: query
7. 冷启动回归
Serverless function `[fnName]` cold start went [fromMs] to [toMs] ms. Diagnose: (1) bundle size grew, (2) new top-level imports, (3) a new connection opened at boot, (4) a new env/secret fetch at module load. Output the top 3 by likelihood + a 5-minute experiment for each.
可替换: fnName, fromMs, toMs
8. TTFB / LCP 回归
LCP on `[pagePath]` went [fromMs] to [toMs] ms (target: under 2500ms at p75). Walk the waterfall: (1) server response time / TTFB, (2) render-blocking CSS/JS, (3) image or font payload, (4) layout shift forcing a re-render. Pick the single dominant cause and the one change that recovers the most.
可替换: pagePath, fromMs, toMs
9. 内存增长回归
Service RSS grew from [oldMb] to [newMb] MB. Diagnose: (1) a new cache without eviction, (2) closures retaining large objects, (3) listener leaks (no removeListener on unmount/restart), (4) buffer pools sized too large. Give file:line for each suspect.
可替换: oldMb, newMb
10. 慢测试回归
The test suite went from [fromMin] to [toMin] min. Identify: (1) specific test files that grew, (2) setup/teardown bloat, (3) a real timer or sleep introduced, (4) reduced parallelism. Output 3 specific cleanups ranked by time saved.
可替换: fromMin, toMin
11. 性能修复 benchmark 计划
Before fixing, design a benchmark: (1) a minimal reproducible scenario, (2) the metric (report median AND p99), (3) sample size and warmup, (4) the exact baseline run command. After the fix, re-run the identical benchmark 3 times. Do not declare a win without before/after numbers.
12. “慢但能接受”决策
A regression is real but small ([deltaMs]ms). Decide: (1) is the absolute p99 now above target/SLO? (2) is user impact measurable (conversion / bounce)? (3) is the fix more expensive than the regression? Output SHIP / FIX / REVERT + a one-line rationale.
可替换: deltaMs
容易踩的坑
- 没 baseline 就开始优化,结果证明不了修复有没有用。
- p50 / p99 不分——尾部尖峰和中位数漂移修法完全不同。
- 相信 dev 环境 profile——线上热路径、数据量、缓存都不一样。
- 底层 N+1 没修就先加缓存。
- bundle split 之前不量哪些是 preload、哪些是 lazy。
- React 一切都 memo——比较开销反而上来,还容易踩 unstable dep 的坑。
- 读 deploy diff 之前就开查——回归多半是代码,不是基建。
进一步提升结果
- 每个 Prompt 都锚定到 指标 + 样本数 + diff 窗口。
- p99 的活和 p50 的活分开,两者很少同一个根因。
- React 用 Profiler trace 取证,别让模型靠 log 猜。
- DB 用
EXPLAIN (ANALYZE, BUFFERS)抓修改前后的 plan。 - benchmark 至少跑 3 次——方差既能藏住回归,也能伪造回归。
- 缓存是最后手段,先把真正的工作量去掉。
- 回归和修复都写进复盘,下个人才不会再踩。
FAQ
- 回归多大才值得管? 推到 p99 超过 SLO 目标就要管。低于 SLO 就用第 12 个模板,对照修复成本权衡。
- 该往哪个 Core Web Vitals 目标优化? 2026 年 6 月现状:LCP 低于 2.5 秒、INP 低于 200 毫秒、CLS 低于 0.1,都按真实用户第 75 百分位算。Google 2026 年 3 月的 core update 在把 LCP 往 2.0 秒收紧,所以更稳妥的目标是 2.0 秒。
- 上线前要彻底优化吗? 达到 Core Web Vitals 目标就发。在上线前继续往目标以下抠,通常是你拿不回来的时间。
- React.memo 总是安全的吗? 不是。
memo配上不稳定的 props(对象、数组、内联回调)会多做比较,可能比不 memo 还慢。 - 怎么找 DB 索引缺口? 用
pg_stat_user_indexes找无用索引,用pg_stat_user_tables找顺序扫描多的表,再用EXPLAIN ANALYZE确认。 - AI 能读火焰图吗? 文本 trace 和 Profiler JSON 读得很好;图形火焰图图片需要 vision 模型,或者先把 trace 转成 Markdown(chperf、chrome-trace-analyzer)再贴。