让AI只改注释不动代码:注释微重构Prompt调优全记录
2026/9/19 10:08:17 网站建设 项目流程

接手一个三年没人维护的 Python 项目,我干的第一件事有点反常规:把所有注释从头到尾读了一遍。不是读代码,是读注释。原因很简单,代码如果跑不动,测试和报错会告诉我;可注释一旦开始撒谎,没有人会主动报错。我翻到一个函数,注释写着“获取当前用户”,函数体里查的却是订单表;另一个配置文件里,YAML 注释和字段名逐字重复,真正重要的“为什么这个值不能小于 30”反而没人写。这种状态,我称之为注释债务。

当时我正好在系统性练习提示词工程,就顺手做了一个“注释微重构 prompt”,专门干这件事。所谓注释微重构,就是只对注释层做局部修正:改错字、补上下文、统一格式、删除明显过时信息,但绝不改动代码行为。这篇文章是我自己调优这份 prompt 的完整记录,包括设计思路、三个能直接套用的模板、四次翻车现场,以及最终的稳定版本。

如果你也在清理老项目里的中文注释,想把 YAML 配置里的冗余说明统一掉,或者只是想找到一个能让 AI“只碰注释、不碰代码行”的用法,这篇内容应该对你有用。

1. 注释会腐烂,但代码不会主动告诉你

1.1 注释腐烂的真实过程

代码是会被测试逼着成长的。行为变了、接口变了,通常有编译错误或测试失败来提醒。但注释不同,它从写下来的那一刻起就开始慢慢过期。最常见的腐烂路径是:需求调整后,程序员改了实现逻辑,却忘了同步改动旁边那段注释;或者重构时抽出了公共方法,原本解释“为什么这样设计”的注释被随手删掉;再或者,团队换了一批人,新成员按自己的习惯补充注释,格式和语言越来越散。

我见过最典型的一段代码是这样的:

def get_user(uid, db): # 获取用户信息,根据 id result = db.query("select * from user where id = ?", uid) # 如果不存在 if not result: # 返回空 return None return result[0]

这段注释的问题很典型:第一行注释和代码内容重复,“根据 id”也说得含糊;后面两句“如果不存在”和“返回空”完全是在翻译代码,属于“读注释等于读代码”的低信息量注释。真正应该写清楚的是:为什么用db.query而不是ORMuid是字符串还是整数?查不到用户时为什么要返回None而不是抛出异常?这些决策背景一个都没写。

注释不会导致测试失败,所以它会安静地烂在那里。等下一次重构时,新人看到“获取当前用户”的注释,就会真的以为这个函数返回的是当前用户,然后在一个错误的前提上继续叠加新代码。到这一步,注释就不再是资产,而是负债。

1.2 为什么我不等“以后重写”,而是现在做微重构

很多团队对待烂注释的策略是“等这次大重构一起收拾”。但大重构永远遥遥无期,风险也高。注释微重构则像给老房子重新贴标签:你不用拆承重墙,只需要把墙上错误的门牌号换掉,把模糊的提示条写清楚,把重复的贴纸撕下来。单次成本低,风险小,收益却立刻能体现。

我做微重构时给自己定了几条原则:

  • 不改变代码逻辑,不调整函数结构,不重命名变量。
  • 不翻译注释,除非客户或团队明确要求。
  • 不删除那些看起来“没用”但包含历史决策的信息。
  • 每一条改动都要能说清楚原因,最好能逐条 review。

有了这些边界,才有资格谈“用 AI 批量做”。否则让模型自由发挥,它很可能把注释和代码一起重构掉,最后你拿到一份看起来更优雅、但没人敢合并的 diff。

1.3 脚本和 IDE 为什么搞不定这个活

如果你只是想统一注释前缀、检查 docstring 是否缺失,工具已经做得不错了,比如ruff的 pydocstyle 规则、Javadoc 的校验插件、各种格式化工具。但注释的语义问题,工具完全无能为力。一个脚本可以检测出一行注释与上一行代码完全相同,但它判断不了“注释写的是获取当前用户,代码查的却是订单表”这种语境错位。

这时候大模型就有天然优势:它能理解代码语义,能分辨注释是在解释“为什么”还是在复述“是什么”,还能按照你给定的规范统一输出。但前提是,你的 prompt 必须足够精确。这就引出了下一部分:一个合格的注释微重构 prompt,到底要包含哪些要素。

2. 注释微重构 prompt 的五个关键要素

2.1 角色设定:告诉模型它是“注释医生”,不是“代码架构师”

很多人写 prompt 喜欢用“你是一个 AI 助手”,这太模糊了。我会把角色定义成“注释维护工程师”,并且加一句“你只负责注释质量,无权修改代码”。角色的意义在于,模型后续生成的文本风格和决策倾向会跟着角色走。当你强调“医生”而不是“外科医生”时,模型会更倾向于保守治疗,而不是给你动大手术。

我常用的角色描述是:

你是注释维护工程师,负责代码可读性治理。你的使命是让注释准确、简洁、可追溯,同时绝不改变代码行为。

这行字放在 prompt 最前面,后面接任务要求,比“帮我改一下注释”稳定得多。

2.2 目标拆解:把“微重构”变成五个可检查的动作

“请优化注释”这种指令,模型不知道该做到什么程度。我会拆成明确动作:

  1. 修正错别字、错误参数名和过时描述。
  2. 统一注释位置和注释符号。
  3. 补充缺失的关键上下文,例如配置项的取值含义。
  4. 删除与代码明显重复的“弱注释”。
  5. 保留表达业务规则或历史决策的“强注释”。

这些动作都是二元的,模型容易执行,你 review 时也有明确标准。微重构不是自由创作,每一步都要有据可依。

2.3 规范说明:语言、格式、标签,一个都不能少

注释规范需要写清楚三件事:语言、格式、标签风格。

语言方面,我默认要求“保留原注释语言”。如果你直接让模型“优化注释”,它很可能把中文注释翻译成英文,理由是“英文更专业”。这是模型默认倾向,必须在 prompt 里强制纠正。

格式方面,要指定行内注释还是独立行注释、注释与代码之间留几个空格、是否有最大行长。例如 Python 的#注释和 docstring 风格,YAML 的#注释统一放在键上方。这些规则要写具体,模型才能稳定输出。

标签方面,最常见的是 TODO 和 FIXME。我会让模型把杂乱的“后面改”“这里可能要优化”统一成TODO(负责人): 事项,然后把无法确认负责人的条目放到修订说明,而不是直接在代码里捏造一个负责人。

2.4 硬边界:把“不许改代码”写进死规则

这句话说几遍都不过分。模型对“优化”这件事有很强的冲动,如果你只说“修改注释”,它往往会顺手把变量名改了、把函数体简化了,甚至调整空行。所以 prompt 里必须有单独的“禁止”段落,明确列出:

  • 禁止修改任何非注释的代码行。
  • 禁止重命名函数、变量、类、文件。
  • 禁止改变代码缩进、空行、换行。
  • 禁止删除无法确认意义的注释,哪怕它看起来很啰嗦。
  • 禁止编造函数签名中不存在的参数或异常。

这些约束不是为了让模型“不敢动”,而是为了让你拿到结果后,能用git diff快速确认代码部分没有任何改动。

2.5 输出格式:只有结构化,才方便批量审查

如果模型只输出“修改后的完整代码”,你还需要逐行对比才知道它动了什么。但如果它输出“重构后的代码 + 变更列表 + 修订说明”,你的 review 成本会指数级下降。

我要求的输出格式固定为三段:

  • 第一段:处理后的完整代码,要求“没有省略,没有省略号”。
  • 第二段:逐条变更列表,写成位置 -> 原注释 -> 新注释 -> 理由
  • 第三段:修订说明,专门放那些“我拿不准,但原文保留了”的内容,并统一标记[存疑]

这个输出格式最大的好处是:即使模型判断错了,它也会把存疑内容暴露出来,而不是偷偷摸摸写进代码里。

3. 三个能直接套用的注释微重构 prompt 模板

3.1 模板一:Python 包和函数的 docstring 规范化

场景:你有一个老 Python 模块,顶部没有模块 docstring,函数注释散乱,有的写在函数体外,有的写在函数体内,还有的干脆没有参数说明。你想把它整合成规范的 Google docstring。

我用的 prompt 如下:

你是注释维护工程师。请对下面的 Python 代码做注释微重构。 任务: 1. 为模块顶部补充一个 docstring,概括模块用途。 2. 为每个函数补充或修正 docstring,采用 Google docstring 风格。 3. docstring 中必须写清楚函数作用、参数、返回值;如果代码中能看出可能抛出的异常,也要写。 4. 函数内部的普通 `#` 注释,只保留解释“为什么”的条目;删除复述代码的弱注释。 5. 保留原注释语言,默认不翻译。 禁止: 1. 修改任何代码行,包括函数名、变量名、空行、缩进、标点。 2. 编造代码中不存在的参数、类型或异常。 3. 输出时使用省略号,必须给出完整代码。 输出: 第一段:重构后的完整代码。 第二段:逐条变更列表。 第三段:修订说明,无法从代码确认的内容全部放在这里,并标记[存疑]。

配合的输入示例可以是:

# 获取用户 def get_user(uid, db): # 根据uid查用户表 result = db.query("select * from user where id = ?", uid) # 如果没有结果 if not result: # 返回空 return None return result[0]

期望输出应该能生成类似这样的 docstring:

"""用户查询模块。 提供按 ID 获取用户信息的工具函数。 """ def get_user(uid, db): """根据用户 ID 查询用户记录。 Args: uid: 用户 ID。 db: 数据库连接对象。 Returns: 用户记录;如果不存在则返回 None。 """ result = db.query("select * from user where id = ?", uid) if not result: return None return result[0]

注意:我特意没有要求模型补函数签名类型注解,因为它无法可靠推断。如果团队用的是 NumPy docstring 风格,把第一条里的“Google docstring 风格”替换掉即可,其余逻辑不变。

3.2 模板二:老项目中文注释清洗与 TODO 标签统一

场景:老项目里中文注释风格混乱,错别字多,夹杂编码乱码,还有大量“以后要改”“不知道为啥这里会这样”这类模糊句子。你希望保留中文,修正表达,并把 TODO 统一。

这一版 prompt 我会加一个针对“历史信息”的保留条款:

你是注释维护工程师。请对下面的代码片段做注释微重构。 任务: 1. 修正中文错别字和不通顺的句子,保留原注释的中文表达。 2. 保留所有与业务规则、历史 Bug、决策原因相关的说明,不要为了简洁而删除。 3. 将 `TODO`、`FIXME`、`以后优化`、`这里可能要改` 统一转换为 `TODO(负责人): 说明` 的格式。无法确定负责人的条目,在修订说明中列出,不写入代码。 4. 编码乱码如 `??`、`\ufffd`,如果上下文能推断出含义就修正;不能推断则保留原样并标记[存疑]。 5. 删除明显的“读代码如读注释”的弱注释,但删除行为必须写进变更列表。 禁止: 1. 修改代码逻辑。 2. 将中文翻译成英文。 3. 删除带有“因为”“注意”“不要”“临时”等关键词的强注释。 输出: 第一段:重构后的完整代码。 第二段:逐条变更列表。 第三段:修订说明。

输入示例:

def query_order(order_id, db): # 这里不能直接用 qryMap,因为历史订单状态为 0 时 qryMap 查不到,先按 uid 过滤 conditions = {"order_id": order_id} if order_id.startswith("H"): conditions["status"] = 0 # TODO 后面优化成联合查询 # 获取??? rows = db.find("order", conditions) return rows

最终版会把“获取???”修成“获取订单记录”,把 TODO 行转换为TODO: 之后优化成联合查询(因为你没指定负责人,模型会把它留在修订说明),同时保留第一行那个长长的“为什么”注释,因为它才是整个函数真正的灵魂。

3.3 模板三:YAML/配置文件的注释去重与补位

场景:配置文件的注释质量往往更差。很多人喜欢在字段旁边写行尾注释,但行尾注释一旦多起来,对齐就是灾难。还有些注释只是把字段名翻译了一遍,比如port: 8080 # 端口,没有任何信息增量。你希望统一为“键上方注释”,删除重复注释,并补充必要的取值范围或单位说明。

我用的 YAML prompt:

你是配置文件注释编辑。请对下面的 YAML 内容做注释微重构。 任务: 1. 不修改任何键名、键值、嵌套结构。 2. 将所有注释统一放在键的正上方一行,不使用行尾注释。 3. 删除只是重复字段名的注释,例如 `port: 8080 # 端口`。 4. 如果某个键明显是数值、布尔或枚举类型,在注释里补充合法值或单位;如果无法从当前内容推断,不要编造,在修订说明中标记[待确认]。 5. 保留所有与业务规则相关的注释,例如“不能小于 30”“生产环境不要打开”等。 禁止: 1. 改动 YAML 的缩进和引号。 2. 给布尔值编造默认值。 3. 在注释中出现任何疑似密钥或密码的信息。 输出: 第一段:重构后的完整 YAML。 第二段:逐条变更列表。 第三段:修订说明。

输入示例:

server: # 端口 port: 8080 timeout: 30 # 超时时间 debug: false # 日志级别 log_level: info

期望输出:

server: # 服务监听端口 port: 8080 # 请求超时时间(秒) timeout: 30 # 是否开启调试输出;合法值:true/false debug: false # 日志级别;合法值:debug/info/warn/error log_level: info

这个模板里,timeout: 30 # 超时时间被移到了键上方并补了“(秒)”,因为 30 这个数值从上下文看大概率是秒。但如果模型不确定,它必须标记[待确认],不能直接写“秒”。这是防止幻觉的关键。

三种模板覆盖了最常见的内联代码注释、历史注释和配置注释。下面进入我最想分享的部分:这些 prompt 是怎么从“翻车”一步步调出来的。

4. 实测调优:从“AI 乱改代码”到“只动注释”

4.1 第一次翻车:它把代码也重写了

最早一版 prompt 很简单,我就写了句“请优化这两个函数的注释”。结果模型不仅整理了注释,还把get_user改名成了fetch_user,用列表推导式重写了db.query的返回处理,甚至帮我加了个Optional类型标注。看起来确实更“现代”了,但 git diff 里红绿一片,代码行为虽然测试能过,可我根本没法快速确认它对所有边界情况的处理没变。

这次教训让我明白:对于注释微重构,模型的“积极性”必须被约束。光说“不要改代码”还不够,要具体列出禁止重命名、禁止改缩进、禁止改空行、禁止改标点。因为模型对“优化”的理解是全面的,它认为缩进和命名也是可优化对象。从那以后,我把“禁止段”提到角色设定后面,优先级仅次于任务。

4.2 第二次翻车:中文注释被翻译成了英文

我第二次测试用了一个全中文注释的老模块。任务说明里写了“修正注释”,结果模型把“获取用户信息”翻译成 “Fetch user info”,把“如果不存在”翻译成 “Return None if not exists”。它认为这样更专业。但我所在团队的中文技术文档生态很稳定,全切成英文既不必要,也增加 review 成本。

修复方式是加了一条显式规则:保留原注释语言,默认不翻译;只有用户指令中出现“翻译”时才翻译。为什么必须这句话?因为模型的默认行为是“应尽量使用英文技术写作”,你不反向纠正,它就会自由发挥。现在我把“默认保留原语言”作为所有注释类 prompt 的默认条款。

4.3 第三次翻车:注释里出现了签名里没有的参数

有一次,模型给get_user(uid, db)补 docstring,写出了Raises: TypeError: 如果 uid 不是整数。函数体里根本没有类型判断,这完全是它从常见编程经验里“脑补”出来的。对一个严格要求注释与代码一致的团队来说,这比没有注释更危险,因为假注释会误导后来者。

解决办法有二。第一,在禁止段里加“禁止编造代码中不存在的参数、类型和异常”。第二,增加一个“修订说明”出口,允许模型把不确定信息写在那里,并标记[存疑],但不进入最终代码。这样既保留了模型的分析能力,又守住了代码的干净程度。

4.4 第四次翻车:输出被省略,没法 review

文件一大,模型就开始偷懒。我拿一个 500 行的模块去跑,结果它输出到第 300 行附近给我写了一句“中间部分与原始代码一致,省略”,后面接最后几行。这种输出完全没法用,因为我不可能再手动对一遍中间几百行是否有改动。

我后来调整为两个方案。方案一是把大文件切成 80~150 行的小片段,逐段跑,每次都能拿到完整输出。方案二是让模型只输出git diff格式,这样即使它处理长文件,我也能通过 diff 一眼看出改了哪些行。但对很多不擅长生成精确 diff 的模型,方案一更稳妥。我最终采用“分段输入 + 完整输出 + 变更列表”的组合。

4.5 我最终在用的完整 prompt

经过四轮翻车后,我现在固定使用的版本是这样:

你是注释维护工程师,负责代码可读性治理。你只修改注释与 docstring,绝不修改任何代码。 任务: 1. 修正注释中的错别字、错误参数名和过时描述。 2. 统一注释的位置、符号和风格,具体规范由用户给定。 3. 删除与代码明显重复的弱注释。 4. 保留所有与业务规则、历史决策、风险提示相关的强注释。 5. 默认保留原注释语言,不翻译,除非用户明确要求。 6. 将 TODO/FIXME 统一为 `TODO(负责人): 说明`,无法确认负责人时写入修订说明。 禁止: 1. 修改任何代码,包括函数名、变量名、缩进、空行、标点。 2. 删除无法确认意义的注释。 3. 编造不存在的参数、类型、异常或配置项。 4. 输出时省略代码,必须逐字输出完整代码片段。 输出: 第一段:处理后的完整代码。 第二段:逐条变更列表,格式为 `位置 -> 原注释 -> 新注释 -> 理由`。 第三段:修订说明,包含所有 [存疑] 或 [待确认] 的内容,以及被删除弱注释的清单。

这个版本的稳定度已经高了很多。我用它处理过 Python、Java、YAML、SQL 文件,只要输入片段控制在合理长度,返回结果基本可以做到“代码行零改动,只动注释”。但这不意味着可以直接闭眼合并,下一节要说的就是边界。

5. 注释微重构的边界和人工复核清单

5.1 prompt 无法判断“注释对不对”,只能判断“注释和代码当不当”

即使是最稳定的 prompt,也只是让注释和代码在文本语义上尽量一致。它根本无法理解你的业务逻辑。比如有这么一行:

# 这里返回打折后的价格 return price * 1.2

模型看不出“打折”和“乘以 1.2”哪个才是业务上的正确描述,它只会觉得注释通顺、格式没问题。它甚至可能帮你把注释改成更通顺的“这里返回价格乘以 1.2”,然后你以为原注释没问题,实际上这个 bug 还是没被发现。所以注释微重构解决的是“注释可信度”问题,不是“业务正确性”问题。业务校验必须靠代码审查和测试覆盖。

5.2 哪些信息绝不能让它删掉

模型为了追求简洁,会倾向于删掉看起来“啰嗦”的注释。有几种注释在 prompt 里明文保护了,我也会在人工复核时特别检查:

  • 决策型注释:例如“不能直接用 qryMap,因为历史订单状态为 0 时查不到”。这类是灵魂,删了代码就变成不可维护的黑盒。
  • 风险提示型注释:例如“生产环境不要打开 debug”。这类关系到线上安全,丢了会出事。
  • 历史 Bug 记录:例如“修复 #123,用户删除后 session 残留”。这类对后续排查问题极其重要。

在每次合并前,我会先看修订说明中被标记为“删除”的项目,逐条确认是不是弱注释。如果发现有决策型注释被删,我会手动把它补回去,并调整 prompt,让“保留强注释”的优先级更高。

5.3 把团队规范写进 prompt,而不是让 AI 自由发挥

不同团队对注释的审美完全不同。有的要求函数必须有 docstring,有的只要求复杂函数写;有的喜欢行尾注释,有的禁止行尾注释。不要拿通用 prompt 直接跑,最好把你的团队注释规范压缩成十行以内,粘贴到 prompt 的“规范说明”里。

我自己的做法是维护了一份comment-style-guide.md,每次用模板时把里面的关键词挑出来替换。比如团队规定行尾注释统一用两个空格分隔、独立注释必须有空行,这些我都会写进 prompt 的规范段。点评时也更容易:如果输出不符合团队规范,不是模型问题,是 prompt 没有把规范讲清楚。

5.4 私有代码的脱敏与安全

如果你用的是云端大模型,在粘贴代码前要注意脱敏。密钥、数据库连接串、内网域名、真实手机号身份证号,这些都要替换成 mock 值。尤其 YAML 配置文件,经常藏着密码或 token,我见过有人直接把password: xxxxxx发给模型,这是非常危险的习惯。安全起见的做法包括:移除安全字段。你也可以用本地模型处理敏感仓库,速度和效果稍差,但对隐私要求高的团队值得。

脱敏的代码示例:

# 原始内容:password: "my_real_password" # 替换为:password: "<REDACTED>"

等模型返回结果后再把占位符替换回真实值。

5.5 一条长期有效的操作习惯

最后分享一个我这半年坚持下来的习惯:每次调优 prompt 后,我会把“好用的版本”存成一个 Markdown 文件,文件名就叫这个任务的名字,里面包含 prompt、示例输入、期望输出和失败案例。时间久了,注释微重构的 prompt 就变成了团队内部的规范类资产。新人接手老项目时直接拷走就能用,不需要重新踩我踩过的坑。

我自己再遇到烂注释,从复制 prompt 到 review 完 diff,通常不会超过十五分钟。这就是微重构的收益:它不解决所有问题,却能把最碍眼的注释债务一点点还掉。如果你也有一个注释烂到不想打开的项目,不妨试试用这份 prompt 先跑一个小模块,你可能会重新找回看代码的耐心。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询