圣堂之魂
博客随笔

代码审查 Prompt


一、通用底层结构(所有任务适用)

你是[角色]。

任务:[做什么]

要求:
- 引用具体内容时,标注来源(文件名/行号/原文)
- 你不确定的地方,明确说"我不确定"
- 不要编造不存在的名称、函数、引用
- 完成后,列出你在这个回答里"推断"了什么、"直接读到"了什么

二、验证 AI 输出的五个方法

核心思路:不靠“看懂代码”,靠“设计验证方法”。初级程序员的优势不是审查能力,而是可以让工具和 AI 替你审查。关键是知道该问什么问题


三、模块分析(读懂代码)

适用场景:在审查或重构之前,先彻底搞清楚一个模块做了什么、谁在调用它、它依赖什么

你是一个代码分析师。

任务:分析 [文件名] 中 [模块] 的工作原理和调用方式。

输出结构:

### 1. 模块职责(一句话)
这个模块在整个系统中负责什么。

### 2. 对外接口清单
列出所有对外暴露的函数/方法/变量,每个包含:
- 接口名称
- 参数(名称、类型、是否必需)
- 返回值(类型、含义)
- 副作用(修改了什么外部状态?触发了什么事件?)
- 引用原代码中的函数签名

### 3. 内部工作流程
用编号步骤描述核心逻辑,每步引用关键代码行。
不要写伪代码,直接引用实际代码片段。

### 4. 调用方分析
在以下文件中找出所有调用 A模块 的地方:
- 调用位置(文件名 + 函数名 + 行号)
- 调用时机(初始化?事件触发?条件分支?)
- 传入的参数是什么
- 对返回值做了什么处理
- 引用调用处的原代码

### 5. 依赖关系
- 该 [模块] 依赖了哪些其他模块/函数/全局变量
- 哪些模块依赖该 [模块]
- 画出依赖链:[调用方] → [模块] → [A模块的依赖]

### 6. 边界条件处理
- 参数为空/undefined 时会怎样
- 异步操作失败时会怎样
- DOM 元素不存在时会怎样
- 引用具体的防护代码,或标注"无防护"

### 7. 看不清的部分
列出因代码截断、注释不清、逻辑复杂等原因,你无法确定的部分。

---

规则:
- 所有描述必须引用原代码,不能只用自然语言概括
- 不要评价代码好坏,只描述它做了什么
- 如果某个调用方的意图你看不懂,标注"意图不明"
- 不要推断未来可能的用途,只分析当前实际的调用
- 整理成 markdown 文本并存储到 [路径]

四、代码健壮性审查

适用场景:审查某页面中某模块的潜在问题

你是一个代码审查员。

任务:审查 [文件名] 中 [模块名] 的健壮性问题。

审查维度:
- 空值/undefined 未防护
- 错误未捕获或静默失败
- DOM 操作前无存在性检查
- 异步操作无 reject 处理
- 状态标记与实际行为不一致

输出格式,每个问题必须包含:
1. 问题编号和级别(致命/中等/低)
2. 问题描述(一句话)
3. 直接引用原代码片段(原文,不要改写)
4. 为什么有问题(一句话)
5. 修复建议(给出修改后的代码)
6. 修复状态:未修复

规则:
- 只报告你在代码里直接看到的问题,不推断
- 如果代码被截断或看不清,明确说明哪里看不到
- 不允许出现"已修复",所有问题默认未修复
- 完成后,额外列一行:本次未能审查的部分
- 整理成 markdown 文本并存储到 [路径]

三个设计要点

  • 禁止“已修复”:堵死文档说已改但代码没改的情况。修复确认是你的工作,不是 AI 的工作。
  • 强制引用原文:AI 如果必须引原文,就没法编造。引不出来的问题就不存在。
  • 本次未能审查的部分:代码太长被截断时,AI 常常假装没事。这一行强迫它交代盲区。

五、模块重构(保留交互与视觉)

适用场景:重构某模块,但不能改变用户可见的任何行为

你是一个重构工程师。

任务:重构 [文件名] 中的 [模块名],要求代码结构更清晰、健壮性更好。

【硬性约束,违反即重来】
- 所有对外暴露的函数名、参数名、返回值结构不变
- 所有用户可见的交互行为不变(触发时机、动画、状态切换)
- 所有视觉输出不变(DOM结构、class名、样式逻辑)
- 不引入当前代码里没有的第三方依赖

重构目标(可以动的部分):
- 消除重复代码
- 补充空值防护
- 统一错误处理
- 改善内部命名和注释

输出格式:
1. 重构后的完整代码
2. 变更清单:每一处改动,说明改了什么、为什么改、原代码是什么
3. 【未动的部分】:列出你刻意保留的关键逻辑,引用原代码确认

规则:
- 变更清单必须引用原代码片段,不能只描述
- 如果某处你不确定能不能动,先不动,在变更清单里标注"存疑,未处理"
- 不允许在变更清单里出现"优化了逻辑"这种模糊表述,必须说具体改了什么
- 将所有的步骤和修改点整理成 markdown 文本并存储到 [路径]

关键设计点

  • “硬性约束”单独成块:写在最前面、加警告语,让 AI 在生成每一行时都会回头对照。
  • 变更清单要引用原代码:重构后拿到的是新代码,没有对照表根本不知道哪里变了。
  • “存疑,未处理”:遇到模糊地带,AI 交出来给你决策,而不是悄悄做一个你不知道的决定。

六、跨页面逻辑比对(A/B 双页面)

适用场景:A 为全量页面,B 为降级页面,同一逻辑两边实现不一致,需找出最优并统一

你是一个跨页面逻辑审查员。

背景:
- A页面([文件名]):全量页面,面向横屏用户
- B页面([文件名]):降级页面,面向竖屏用户
- 两者调用相同数据接口,但各自实现,存在逻辑分化

任务:逐一比对以下模块在A和B中的实现差异,找出哪边处理得更好,并给出统一方案建议。

需要比对的模块:[列出模块名,例如:图片加载、错误处理、标签筛选]

输出格式,每个模块一节:

### 模块名

**A的实现**(直接引用代码):
[代码]

**B的实现**(直接引用代码):
[代码]

**差异说明**:具体哪里不同(不能模糊说"逻辑类似")

**优劣判断**
- A更好的点:[具体说明,或"无"]
- B更好的点:[具体说明,或"无"]
- 判断依据:[健壮性/性能/可读性/边界处理,选一个主因]

**统一方案建议**
- 建议采用哪边的逻辑作为基础
- 需要从另一边补充的内容
- 给出合并后的参考代码

**风险提示**:如果统一这个逻辑,对A或B的现有行为有没有副作用

---

规则:
- 必须引用两边的实际代码,不能凭记忆描述
- 如果某个模块只有一边有、另一边没有,明确标注"A独有"或"B独有"
- 如果两边逻辑你判断不出优劣,直接说"需要产品确认业务意图",不要强行下判断
- 完成后列出:【需要产品/业务确认的问题】——纯技术无法决定的,不要替业务做决定
  • 很多差异不是技术问题,是业务决策。给它一个合法的“我不知道”出口,比让它乱猜好。
  • 统一逻辑可能破坏现有用户体验,强迫 AI 在给建议之前先想副作用。

七、幽灵代码排查

适用场景:排查空调用、死代码、找不到定义的接口调用、以及“别删这个/删了会崩”类恐吓注释

你是一个代码考古员,专门找"看起来没问题但实际有问题"的代码。

任务:在 [文件名] 中找出以下四类幽灵代码,逐一列出。

【第一类:空调用】
定义:函数被调用,但调用结果没有被使用,也没有副作用
找法:调用后既没有赋值、也没有 return、也没有修改外部状态
输出:引用调用行 + 说明为什么这次调用没有意义

【第二类:死代码】
定义:永远不会被执行到的代码
找法:return/throw 之后的语句、条件永远为 false 的分支、从未被调用的函数
输出:引用代码 + 说明为什么执行不到

【第三类:幽灵接口调用】
定义:代码里调用了某个函数/方法/属性,但在整个代码库里找不到它的定义
找法:所有 xxx.yyy() 或 yyy() 的调用,对照文件里有没有对应定义
输出:引用调用行 + 说明在哪些文件里搜不到定义 + 可能来源(外部库?拼写错误?已删除?)
注意:只报告你确认找不到的,不确定的标注"需人工确认来源"

【第四类:恐吓注释】
定义:注释里有"别删""不要动""删了会崩"等警告,但没有解释原因
找法:扫描所有注释,找包含"别删/不要动/删了/don't remove/keep this"等关键词的
输出:引用注释原文 + 引用被保护的代码 + 问三个问题:
  - 这段代码现在还有调用方吗?
  - 如果删掉,实际影响是什么?
  - 这个警告有没有可能已经过期?

---

输出格式:
每类问题单独成节,每个问题编号。
没有发现的类别写:【本文件未发现此类问题】

最后列一节:
【需要跨文件确认的项目】
——凡是你在单文件内判断不了的(比如函数在其他文件定义),列在这里,说明需要提供哪个文件才能确认

规则:
- 所有输出必须引用原代码,不能只描述
- 不确定就说不确定,不要强行下结论
- 恐吓注释不等于可以删,你只负责揭示,不负责决策

关于“恐吓注释”:这是最难处理的,因为它可能是:

  • 是真的:历史上确实踩过坑,注释是经验沉淀
  • 已过期:当时依赖的模块早就重构了,现在删掉完全没事
  • 是谎言:原作者自己也不确定,写了个注释吓退后人

AI 的正确姿态是揭示而不决策,而是告诉你这段代码现在还有没有调用方、删掉的实际影响链条是什么,但“删不删”是你的决定。


八、处理技术债

搞清楚为什么不能删

常见的依赖机制:

情况说明
框架查方法名是否存在插件系统/生命周期钩子会扫描对象上有没有特定方法名,“这个名字存在”本身就是信号
继承或接口约定调用方不在乎它做了什么,只在乎调用不报错
历史事故遗留保险原因可能已经不存在了,只是没人验证过

修复

第一阶段:确认能不能动

你是一个技术债清理工程师。

任务:帮我处理 [文件名] 中以下这个疑似技术债的空函数:

[引用函数原文和注释]

第一步:调用方追踪
在以下所有文件中找出所有引用这个函数的地方,包括:
- 直接调用
- typeof / ?. 存在性检查
- 字符串形式的方法名引用
- 动态调用(apply/call/bind)
每处引用原代码,说明它对这个函数有什么期待(返回值?副作用?仅检查存在性?)

第二步:依赖性判断
根据调用方分析,这个函数的"存在"和"被调用"分别有没有意义?
- 如果有意义:说明是哪种机制在依赖它
- 如果没有意义:说明可以安全删除的理由

第三步:给出处理建议,三选一:
A. 可以安全删除,删除步骤是……
B. 不能删除,但可以替换成更明确的实现,替换方案是……
C. 无法在单文件内判断,需要额外提供的文件是……

规则:
- 不允许直接给出"建议删除"而不经过第一步和第二步
- 如果调用方代码被截断看不全,明确说明,不要推断

[所有相关文件贴这里]

第二阶段:如果需要保留,重写注释

这个函数需要保留,但原注释只有警告没有原因。

根据以下调用方分析结果,帮我重写这个函数的注释,要求:
- 说明为什么不能删(具体机制)
- 说明调用方在哪个文件的哪一行
- 说明函数体为空是否是预期行为
- 注释里不允许出现"别删"这种恐吓语气,改成解释性语言

[把第一阶段的调用方分析结果贴这里]
[把函数原文贴这里]

核心原则:空函数加恐吓注释,本质是一笔没有还清的技术债。债是真实的,但没有对账单。你要做的不是还债,是把对账单补上,让下一个人不用再猜。


九、完整模块重写(连根重构)

适用场景:不是小修小补,是把整个模块完全重写

核心风险:不再是“会不会改坏”,而是**“重构完之后,原来依赖这个模块的代码还能正常工作吗”**。

你是一个模块重构工程师。

任务:彻底重构 [模块],用更清晰、健壮的方式重新实现相同的功能。
这不是小修小补,是完全重写。

【第一步:摸清现状,不急着动】

1.1 列出 [模块] 目前对外暴露的所有接口:
- 函数名、参数、返回值
- 对外暴露的变量或状态
- 触发的事件或回调

1.2 列出 [模块] 的所有调用方(在以下文件中搜索):
- 谁在调用 D 模块的哪个接口
- 调用时机(初始化?事件触发?周期性?)
- 调用方对返回值或副作用有什么依赖

1.3 列出 [模块] 内部的所有技术债:
- 空函数(函数体为空但有注释说不能删的)
- 死代码
- 重复逻辑
- 没有防护的危险操作

完成第一步后暂停,等我确认再继续。
【第二步:设计新模块,先不写代码】

根据第一步的分析,设计重构后的 [模块] 结构:

2.1 对外接口设计:
- 哪些接口保留原签名(调用方不需要改动)
- 哪些接口需要修改(说明修改原因和调用方需要同步修改的地方)
- 哪些接口可以删除(说明为什么安全)

2.2 内部结构设计:
- 模块划分(每块负责什么)
- 错误处理策略
- 空值防护策略

2.3 迁移风险评估:
- 哪些调用方需要同步改动
- 哪些行为变化可能影响用户体验
- 建议的上线策略(一次性替换?还是分阶段?)

完成第二步后暂停,等我确认设计再继续。
【第三步:写代码】

根据确认后的设计,输出:
- 重构后的完整 [模块] 代码
- 每个需要同步修改的调用方,给出修改后的代码片段
- 迁移检查清单:上线前需要人工验证的每一项

规则:
- 第一步和第二步必须完整完成,不允许跳过直接写代码
- 所有分析必须引用原代码,不能凭记忆描述
- 如果某个调用方的意图你看不懂,标注"需业务确认",不要猜
- 空函数等技术债,在第一步列出,在第二步决定是否保留,不允许默默带入新代码

为什么分三步暂停:整个重构里最贵的错误是设计阶段就走错了方向。三步暂停让你在每个关键决策点介入:

任何一步有问题,代价都比写完再返工小得多。


十、文档交叉审查(两份文档对比代码)

适用场景:有两份关于同一模块的分析文档(可能来自不同 AI 对话、不同人写的、或不同时期生成的),需要找出哪些对、哪些错、哪些互相矛盾

核心思路:不是文档 A 和文档 B 互相辩论,是两份文档都要接受代码的审判

你是一个文档审查员。

任务:对比以下两份关于 [A模块] 的分析文档,找出差异、错误、遗漏,给出最终版本建议。

背景:
- 文档A:[AI生成 / 你写的 / 其他来源]
- 文档B:[AI生成 / 你写的 / 其他来源]
- 原始代码:[文件名]

输出结构:

### 1. 一致的部分
列出两份文档描述一致且与代码相符的内容,引用文档原文 + 代码验证。
这部分可以直接采纳。

### 2. 冲突的部分
列出两份文档描述不一致的地方,每项包含:
- 冲突点:具体在描述什么
- 文档A的说法:[引用原文]
- 文档B的说法:[引用原文]
- 代码实际情况:[引用代码]
- 判断:哪个文档正确,或两个都错

### 3. 单方遗漏
- 文档A有但文档B没有的内容 → 核对代码,判断是否应该补充到最终版
- 文档B有但文档A没有的内容 → 核对代码,判断是否应该补充到最终版

### 4. 共同遗漏
两份文档都没提到,但代码里实际存在的重要内容:
- 未记录的函数/接口
- 未记录的调用方
- 未记录的边界处理
- 未记录的依赖关系

### 5. 虚假内容
两份文档中任何一方提到但代码里不存在的内容:
- 不存在的函数名
- 不存在的参数
- 不存在的调用关系
- 引用文档原文 + 说明在代码中搜索不到

### 6. 最终版本建议
基于以上分析,给出合并后的文档框架:
- 采纳文档A的哪些部分
- 采纳文档B的哪些部分
- 需要补充的内容
- 需要删除的内容

不需要输出完整文档,只需要给出结构和关键修改点。

---

规则:
- 所有判断必须以代码为准,文档只是待验证的材料
- 不允许出现"两份文档都有道理"这种和稀泥的说法,必须明确对错
- 如果代码被截断导致无法判断,明确标注"需补充代码片段"
- 虚假内容是最严重的问题,单独列出,不要混在其他部分

设计要点

  • “虚假内容”单独成节:这是最危险的错误——不是描述不准确,是凭空编造。必须单独揪出来。
  • 不输出完整文档:让 AI 直接合并两份文档容易出新错误。你只要它给出“采纳清单”,最终文档你自己组装,或拿着清单让它按指令重新生成。
  • 禁止和稀泥:强迫 AI 明确对错,以代码为唯一裁判。

变体:如果需要直接输出合并版,在第 6 节后面追加:

### 7. 合并后的完整文档

根据第6节的建议,输出最终版本的完整文档。

要求:
- 每一段内容后面标注来源:[采纳自文档A] / [采纳自文档B] / [补充自代码] / [新增说明]
- 所有描述必须引用代码验证
- 不允许出现任何一方文档中被判定为"虚假"的内容

合并版:

你是一个文档审查员。

任务:对比以下两份关于 [A模块] 的分析文档,找出差异、错误、遗漏,给出最终版本建议。

背景:
- 文档A:[AI生成 / 你写的 / 其他来源]
- 文档B:[AI生成 / 你写的 / 其他来源]
- 原始代码:[文件名]

输出结构:

### 1. 一致的部分
列出两份文档描述一致且与代码相符的内容,引用文档原文 + 代码验证。
这部分可以直接采纳。

### 2. 冲突的部分
列出两份文档描述不一致的地方,每项包含:
- 冲突点:具体在描述什么
- 文档A的说法:[引用原文]
- 文档B的说法:[引用原文]
- 代码实际情况:[引用代码]
- 判断:哪个文档正确,或两个都错

### 3. 单方遗漏
- 文档A有但文档B没有的内容 → 核对代码,判断是否应该补充到最终版
- 文档B有但文档A没有的内容 → 核对代码,判断是否应该补充到最终版

### 4. 共同遗漏
两份文档都没提到,但代码里实际存在的重要内容:
- 未记录的函数/接口
- 未记录的调用方
- 未记录的边界处理
- 未记录的依赖关系

### 5. 虚假内容
两份文档中任何一方提到但代码里不存在的内容:
- 不存在的函数名
- 不存在的参数
- 不存在的调用关系
- 引用文档原文 + 说明在代码中搜索不到

### 6. 最终版本建议
基于以上分析,给出合并后的文档框架:
- 采纳文档A的哪些部分
- 采纳文档B的哪些部分
- 需要补充的内容
- 需要删除的内容

### 7. 输出文档
要求:
- 每一段内容后面标注来源:[采纳自文档A] / [采纳自文档B] / [补充自代码] / [新增说明]
- 所有描述必须引用代码验证
- 不允许出现任何一方文档中被判定为"虚假"的内容

---

规则:
- 所有判断必须以代码为准,文档只是待验证的材料
- 不允许出现"两份文档都有道理"这种和稀泥的说法,必须明确对错
- 如果代码被截断导致无法判断,明确标注"需补充代码片段"
- 虚假内容是最严重的问题,单独列出,不要混在其他部分

建议:分两次对话——第一次对比分析,第二次拿着分析结果让它生成。一次性做完容易在合并时又引入新错误。


十一、锚点注释(代码即文档)

适用场景:多模块项目,需要一种可维护、可追踪、可被工具扫描的方式记录模块间的依赖和接口关系

核心思路:在代码中插入固定格式的锚点注释,让代码本身成为可被解析的文档。不需要单独维护映射表,Git 可追踪变更历史,grep 就能提取。

锚点标签定义

标签含义使用位置
@module:模块名 @interface:函数名对外暴露的接口接口函数前
@module:模块名 @internal:函数名内部函数内部函数前
@module:模块名 @depends:模块名依赖的外部模块调用外部模块处
@module:模块名 @entry:场景描述被外部触发的入口外部调用的入口处

分级原则:只标记跨模块边界@interface@entry@depends),模块内部私有函数不加锚点,减少维护成本。

实际示例

// @module:Portfolio @interface:openModal
// @depends:ImageLoaderAPI
// @entry:用户点击作品卡片
function openModal(workId) {
    const work = portfolioData.find(item => item.id === workId);
    if (!work) return; // @guard:空值防护
    
    // @module:Portfolio @depends:ImageLoaderAPI.load
    ImageLoaderAPI.load(modalImg, work.image, {
        onSuccess: () => showModal(),
        onError: () => showPlaceholder()
    });
}

// @module:Portfolio @internal:showModal
function showModal() {
    modal.classList.add('active');
}

这些锚点:人类可读、机器可解析、Git 可追踪、失效可检测(代码删了锚点还在,grep 能发现)。

锚点的三个优势

  1. 代码即文档:锚点直接写在代码里,代码改了锚点就在旁边,改起来心理负担小
  2. 可以被 Git 追踪:Git 会记录锚点的变更历史,可以看到"这个接口是什么时候被标记为对外暴露的"
  3. 可以被工具扫描:写个简单脚本就能提取所有标签生成依赖图,不需要 AI,grep 就能干

三步操作 Prompt

第一步:插入锚点

你是一个代码分析师。

任务:分析 [文件名] 中的 [A模块],并在关键位置插入锚点注释。

锚点规则:
- 每个对外接口函数前插入:// @module:A @interface:函数名
- 每个内部关键函数前插入:// @module:A @internal:函数名
- 每个调用外部模块的地方插入:// @module:A @depends:模块名
- 每个被外部调用的入口插入:// @module:A @entry:场景描述

锚点格式固定,不要自由发挥。

输出:
1. 插入锚点后的完整代码
2. 锚点索引表(所有锚点的清单 + 说明)

第二步:基于锚点生成索引

你是一个索引生成器。

任务:扫描以下代码中的所有锚点注释,生成结构化索引。

索引格式:
【模块名】:从 @module 标签提取
【对外接口】:所有 @interface 标签
  - 函数签名
  - 锚点:// @module:A @interface:openModal
【内部函数】:所有 @internal 标签
【依赖关系】:所有 @depends 标签
【调用入口】:所有 @entry 标签

规则:
- 只提取锚点标签,不要解读代码逻辑
- 如果某个函数有锚点但没有实现,标注【锚点孤立】
- 如果某个函数有实现但没有锚点,标注【未标记】

第三步:合并多个模块的索引

你是一个索引合并员。

任务:合并以下多个模块的锚点索引,检查一致性。

检查项:
- A模块标记 @depends:B.foo,B模块是否有 @interface:foo
- A模块标记 @entry:初始化,是否有其他模块调用这个入口
- 是否存在循环依赖(A depends B, B depends A)

输出:
1. 全局依赖图(基于 @depends 和 @interface)
2. 调用链路图(基于 @entry 和实际调用)
3. 不一致清单(锚点声明和实际代码不匹配的地方)

快速选择指南

你想做的事用哪个 Prompt
先读懂一个模块再动手Prompt 0:模块分析
找问题,不改代码Prompt 1:健壮性审查
改代码,不改行为Prompt 2:模块重构
两个页面同一逻辑不一致Prompt 3:跨页面比对
代码里有可疑的注释和僵尸代码Prompt 4:幽灵代码排查
处理"别删会崩"的空函数第八章:技术债清理(两阶段)
把整个模块连根重写Prompt 5:完整模块重写(三步暂停)
两份文档互相矛盾,不知道信哪个Prompt 6:文档交叉审查
多模块项目需要记录接口和依赖关系第十一章:锚点注释方案(三步)
验证 AI 生成的文档是否准确通用底层结构 + 方法一到五


本页目录