为什么不能让大模型直接用正则或纯文本覆写代码?
大模型在输出超长修改时,很容易发生缩进错位、漏闭合花括号,或者在替换公共函数签名时漏改了某个边缘调用方。
编译器驱动的“AI 提议 + 语法树执行”架构
- 意图提议阶段:大模型只输出结构化的重构方案描述(如:“将函数
calculateFee重命名为computeServiceFee,并将第二个参数提取为对象参数”); - AST 精确执行阶段:由确定的代码编译器工具(如 Babel / ts-morph / jscodeshift)解析语法树,执行原子级节点增删改;
- 类型安全检查阶段:自动运行 TypeScript 编译器(
tsc --noEmit)获取完整类型错误列表,若有未适配项再反馈给模型增量修复。
实操:一次安全重命名的完整流水线
以"重命名一个被几十个文件引用的导出函数"为例:
- 模型产出结构化意图:源符号、目标名称、作用范围,不产出任何代码文本;
- 编排器先在代码索引中解析出符号定义与全部引用点(定位思路与 混合搜索与 AST 代码索引架构:打造万级文件代码库的高精度定位引擎 一致),确认无同名冲突;
- 交给 codemod 执行:jscodeshift 或 ts-morph 按语法节点逐个改写,字符串字面量、注释与同名局部变量天然不受影响;
- 运行
tsc --noEmit收集残余错误,把错误列表回传模型生成增量修复意图,循环上限设为 3–5 轮(经验值),超限即人工介入; - 通过后运行全量测试,输出变更摘要供评审。
文本覆写与 AST 改写对比
| 维度 | 纯文本 / 正则覆写 | AST 引导改写 |
|---|---|---|
| 语法正确性 | 无保证,靠模型自觉 | 结构上不可能破坏语法 |
| 跨文件引用更新 | 极易漏改 | 由符号解析统一覆盖 |
| 失败模式 | 静默出错,难察觉 | 显式报错,易定位 |
| 性能开销 | 极低 | 全量解析,中到大 |
| 适用规模 | 单文件小改动 | 跨模块、公共 API 变更 |
验证方法
除了跑测试,加两道专门检查:差异审查,用 AST 对比工具确认变更只落在预期节点类型上,出现计划外节点即打回;对照组实验,同一重构任务分别用文本覆写与本架构各跑数次,统计引入的类型错误数与漏改引用数,两者差距就是架构的价值证明。更多防退化手段见 AI 生成代码的质量评测指标与防退化策略:从语法检查到变异测试。
常见故障速查
| 现象 | 原因 | 处理 |
|---|---|---|
| 重构后出现大量同名误改 | 意图未限定符号作用域 | 改写前先做符号解析而非按名字匹配 |
| codemod 对个别文件静默跳过 | 该文件解析失败(方言/新语法) | 收集解析失败清单,单独降级处理 |
| 修复循环多轮不收敛 | 错误列表未去重导致模型打转 | 每轮只回传新增错误并限制轮数 |
| 测试通过但行为变了 | 重构触及语义(如参数求值顺序) | 对高风险操作强制人工评审关口 |
小结
验收标准很直接:一次批量重构之后,tsc --noEmit 与全量测试均为零错误,且差异审查未发现任何计划外节点变更。做到这三点,才可以说模型被限制在了"提议者"位置;只要还有一次改动绕过了 AST 执行层直接落盘,架构就不成立,应先堵住旁路再扩大重构范围。