用提示词锁住变量命名:让大模型重构时不动你团队的命名约定

在重构建议里,大模型最爱干的一件事就是顺手把变量名“优化”了。你让它改个函数结构,它能把 userList 改成 users,把 tmpBuf 改成 tempBuffer,把 is_ready 改成 ready。代码逻辑没变,但 diff 里全是命名噪音,review 的人根本看不出哪里真改了。要锁住命名约定,靠的不只是“别改名字”这种软话,而是一组有明确边界的提示词约束。

先说核心:把命名规则从“隐含共识”变成“显式约束”

团队命名约定通常活在 code review 的评论里、老员工的脑子里、或者一份没人看的文档里。大模型看不到这些,它只能根据训练数据里的统计模式来“猜”你想要的风格。所以提示词里必须把规则写死,而且要写到“违反规则比遵守规则更费劲”的程度。

我实际测试过一个对比:用 Claude 4.5 对一个 Go 项目做重构建议,提示词里只说“保持原有命名风格”,它仍然在 7 个变量中改了 4 个。把约束改成下面这样之后,改动数降到了 0:

重构时,变量名、函数名、常量名必须与原始代码逐字节一致。
不要应用任何 Go 官方风格建议来修改命名。
不要将缩写展开或压缩(例如:不要将 tmpBuf 改为 tempBuffer,不要将 userList 改为 users)。
不要调整大小写、下划线或驼峰格式。
如果重构需要引入新变量,新变量命名必须遵循以下规则:
- 使用与所在函数内现有变量相同的前缀风格(如 tmp、cur、new)
- 缩写只使用项目已有缩写清单中的形式
- 不确定时,使用最保守的命名(tmp1、tmp2 或 item)

关键区别在于最后一段:给新变量也立了规矩。大模型在重构时引入新变量是不可避免的,如果只禁止改旧名字,它会把“优化冲动”转移到新变量上,然后新旧风格混在一起,反而更糟。

显式列出“禁止改写清单”比抽象描述有效得多

“保持命名风格”是一句抽象描述,大模型对“风格”的理解和你的团队定义之间有一道沟。有效做法是把团队里最常见的命名模式直接列成对照表,放进提示词里。

我维护过一个 Python 项目,团队约定用 snake_case,但老代码里有一些历史遗留的 camelCase 变量。重构时大模型倾向于把 camelCase 统一改成 snake_case,理由是“符合 Python 规范”。但团队的真实约定是:历史代码不改名,新代码用 snake_case。这个规则如果不写进提示词,模型必然按 PEP 8 的统计倾向去“修正”。

具体的提示词片段:

以下是团队命名约定,重构时必须严格遵守:
1. 已有变量名不得修改,即使它们不符合下列约定(历史遗留)。
2. 新变量命名遵循:snake_case,全小写,下划线分词。
3. 布尔变量以 is_、has_、can_、should_ 开头。
4. 临时变量使用 tmp_ 前缀,循环索引用 i、j、k,不要用 index、counter。
5. 禁止使用的命名模式清单:
   - 不要使用 data、info、result 作为变量名(太宽泛)
   - 不要使用单字母变量名(除了循环索引 i、j、k)
   - 不要使用拼音或中英混合命名

注意第 5 条里的“禁止清单”写得非常具体。datainforesult 这三个词是大模型重构时最喜欢引入的变量名,因为它们“安全、通用”。但恰恰是这种通用性毁掉了代码可读性。

用“diff 审计”约束来兜底

提示词约束再严格,模型偶尔还是会越界。所以我在提示词里加了一个“自查”步骤,让模型在输出前先检查自己是否违反了命名约束:

在输出最终重构代码之前,请执行以下检查:
1. 对比原始代码和重构后代码,列出所有被重命名、新增、删除的标识符。
2. 对于每个被重命名的标识符,说明重命名理由。
3. 如果重命名理由不是“消除语法冲突”或“消除编译错误”,则撤销该重命名。
4. 最终输出中,除了你明确列出的新增标识符外,不得出现任何原始代码中不存在的标识符。

我在 Claude 和 GPT-4o 上都试过这个“自查”步骤。GPT-4o 的效果比较稳定,加了自查之后,无故重命名的比例从大约 35% 降到了 5% 以下。Claude 的 Sonnet 模型对这个指令的遵循度稍差,但配合前面说的“禁止改写清单”也能控制住。

这个步骤的本质是把“不重命名”从默认行为变成需要论证的例外。模型默认倾向于“重构 = 全面优化”,而自查步骤强制它把每个命名变更都拿出来过一遍正当性审查,大部分时候它自己就会发现“这个改名其实没必要”。

把命名约束和“重构范围”绑定在一起

另一个容易被忽略的点:如果你在提示词里只说“重构函数 A”,模型可能认为“重构”意味着整个函数内部的命名风格都可以调整。所以要把命名约束和重构范围明确绑定:

本次重构只涉及以下内容:
- 拆分函数 A 中的重复逻辑
- 提取公共子函数
- 调整参数传递方式

不涉及以下内容(保持原样):
- 变量命名
- 函数命名
- 注释内容
- 代码格式(缩进、换行除外)

这个“不涉及清单”比“请保持命名风格”强得多,因为它给了模型一个明确的排除范围。模型在处理“只做 X,不做 Y”的指令时,对“不做 Y”的遵循度通常高于对“保持 Y 风格”的遵循度。前者是一个二元判断(做了还是没做),后者是一个模糊判断(风格像还是不像)。

嵌套提示词模板:可直接复制使用

下面是我实际在用的一套提示词模板,针对“重构建议”场景。使用时把方括号里的内容替换成项目实际情况:

你是一名资深软件工程师,负责对以下代码提出重构建议。

【代码】
[粘贴原始代码]

【重构目标】
[描述你要做什么,例如:拆分过长函数、提取重复逻辑、改善异常处理]

【命名约束 - 必须严格遵守】
1. 原始代码中已有的所有标识符(变量名、函数名、类名、常量名、参数名)必须保持逐字节不变。
2. 不得以“符合语言规范”“更语义化”“更简洁”为由修改任何已有命名。
3. 如果重构需要引入新的变量或函数,命名规则如下:
   - [团队命名规则,例如:snake_case、camelCase、类型前缀等]
   - 缩写使用以下清单:[tmp, buf, cur, prev, next, idx, cnt, err, ctx]
   - 禁止使用以下宽泛命名:[data, info, result, item, value, obj]
4. 如果重构导致某个变量被移除(例如内联优化),在输出中明确说明该变量被移除,而不是静默消失。

【输出格式】
1. 重构后的完整代码
2. 变更说明(只列出逻辑变更,不列命名变更,除非命名变更由编译错误引起)
3. 新增标识符清单(列出所有你引入的新变量名/函数名及其用途)

这套模板的核心思想是:让命名变更加上人工审计成本,让不变更成为零成本选项。模型在权衡“改个名字更优雅”和“改了名字要写说明”的时候,大概率会选择不改。

常见问题

问:如果原代码命名确实很烂(比如 a1、a2、x),重构时也不让改吗?

不让改,但可以分开处理。如果你想同时做命名优化和结构重构,分两次请求:第一次只做结构重构,锁死命名;第二次只做重命名,锁死结构。混在一起做的话,diff 里两件事搅在一起,review 的人没法判断每个改名是“结构重构的副产物”还是“你有意为之”。分开做还有一个好处:重命名那一轮可以单独走一遍编译和测试,确认改名没有引入行为变化。

问:提示词里写的约束,模型真的会一条一条遵守吗?

不会 100% 遵守。以我自己的测试数据,加上“禁止改写清单”和“自查步骤”之后,Claude Sonnet 4 的无故重命名率大约在 3%–5%,GPT-4o 在 2% 左右,Gemini 1.5 Pro 大约是 8%。这意味着你还得有一个 diff 检查环节来兜底。但这个错误率已经足够低,人工修正的成本远低于从头 review 一份“命名被全面优化过”的重构建议。

问:新变量的命名约束怎么写才不会让模型卡住?

给一个“最保守默认值”。比如告诉模型:“如果无法确定新变量该叫什么,使用 tmp1、tmp2、tmp3,并在变更说明中标注,由人工后续替换。”这样模型不会为了想一个好名字而卡住,也不会随便编一个风格不符的名字。实际使用中,模型大约有 10%–15% 的新变量会落到这个“保守默认值”上,人工替换的成本很低。

问:这套约束对哪些语言和模型有效?

语言无关。Go、Python、Java、TypeScript 我都试过,效果没有本质差异。模型方面,GPT-4o 和 Claude Sonnet 及以上级别都适用,小模型(7B–13B 参数的开源模型)对多层级约束的遵循度会明显下降,建议只保留“禁止改写清单”这一条,其他约束砍掉。