AI 如何在不重新生成整个程序的情况下编辑代码?
一份关于局部代码再生成的实用研究指南:哪些内容必须保持不变、哪些内容可以修改, 以及在把一次变换称为“保持结构”之前需要什么证据。
问题究竟是什么
代码编辑并不是提示词更短的代码生成。编辑器接收一个已有软件制品、预期改动和一个隐含的保持契约。 因此核心问题具有两个方向:允许改变哪个区域,其余部分的哪些属性必须保持稳定?
本指南面向正在进入 AI 辅助软件编辑领域的技术读者。它把“局部改动”的直观概念, 与语法保持、结构保持、语义等价和功能正确这些更强的主张区分开来。
核心思想
有边界的编辑器需要显式的保持边界,而不只是一个生成目标。
什么必须保持不变
它可以是文本片段、语法、API 签名、AST 区域、测试行为、依赖契约, 或学习得到的粗粒度表示。每一种选择保护的稳定性含义都不同。
什么可以改变
可编辑区域必须拥有足够自由度来完成任务。复制所有内容的方法很稳定但没有用; 重写所有内容的方法有自由度,却没有局部性。
直观模型:只装修一个房间,同时保留整栋建筑
想象只装修一个房间,同时保持承重结构、管线接口和相邻房间不变。 完整再生成更像是根据口头描述重新盖一栋房子;局部编辑则先标出受保护结构, 打开一个有边界的工作区,执行改动,并在接受结果前检查它。
这个类比在哪里失效。学习得到的潜码并不是经过认证的建筑图纸。固定粗粒度潜码可以提高测得的结构稳定性, 但不能保证某个 AST 节点、行为或接口一定保持不变。
更精确地理解部分再生成
设编码器把程序 x 映射到结构化潜表示 z。 保持掩码选择必须固定的位置集合 L。生成器只采样其余位置, 并对每个锁定位置强制满足 z'ₗ = zₗ。 最后,解码器把补全后的表示 z' 映射回源代码。
这一机制在 token 之上创建了可检查的控制面。但其含义仍需通过实验建立: 必须测试锁定位置在解码后究竟保持了什么,以及可编辑位置是否还保留足够自由度。
四阶段编辑流程
指定边界
确定受保护的区域或属性,并定义预期改动。
表示软件制品
使用文本、语法、检索上下文,或者学习得到的粗粒度与细粒度潜码。
选择性再生成
只采样可编辑位置,同时保留选定约束。
接受之前先验证
测量局部性、语法、结构、行为和非预期副作用。
代码编辑、程序修复和受约束生成不是同一个任务
| 方法 | 主要目标 | 典型保持机制 | 仍需验证什么 |
|---|---|---|---|
| 完整代码生成 | 生成完整制品 | 提示词和上下文 | 预期改动之外的所有内容 |
| 自动程序修复 | 消除已诊断故障 | 故障定位、测试、模板或补丁 | 测试覆盖之外的正确性和补丁最小性 |
| 填空或编辑模型 | 修改选定文本区域 | 可见前缀、后缀、diff 或编辑上下文 | 非预期的结构和行为变化 |
| 语法约束解码 | 让输出保持在形式语言内 | 语法有效的解码状态 | 程序含义、任务正确性和局部性 |
| 分层潜变量控制 | 再生成选定的学习型位置 | 锁定粗粒度或细粒度潜码 | 这些潜码在解码后保持了什么 |
如何测量局部性和结构保持
- 目标区域之外的变化
- 测量预期编辑之外的 diff。较低值支持局部性,但单纯复制并不等于成功。
- 可编辑区域的自由度
- 测量未锁定区域是否真的改变,以及是否仍能生成多个有效候选。
- 语法和文法
- 解析率或语法有效性能够发现格式错误,却不能单独说明程序行为。
- 结构不变量
- 比较任务要求保持稳定的签名、AST 片段、控制流、数据流、导入或 API。
- 功能证据
- 只要相应制品存在,就运行测试、静态检查、编译和任务特定的行为评估。
- 多样性和不确定性
- 报告候选唯一性和重复运行变异,避免把模式坍缩误认为稳定性。
哪一种控制面适合当前编辑任务?
“不要重写整个函数”是一个要求,而不是完整的方法。
| 所需保证 | 更匹配的控制面 | 应要求的证据 |
|---|---|---|
| 保持行为的重构 | 让 LLM 识别或提出变换,并尽可能交给可信重构引擎执行。参见RefactoringMirror。 | 编译、测试、静态检查和重构检测。SWE-Refactor在仓库级基准中显式要求这些检查。 |
| 不完整重写的局部修改 | 复用未改变的源代码片段,只生成候选编辑区域,如EfficientEdit。 | 区域外 diff、任务成功率、已接受 token 的复用程度,以及省略上下文是否导致跨文件变化漏检。 |
| 从静态生成错误中恢复 | 为有效前缀建立检查点,只回滚到责任区域,如Hydra。 | 编译器或类型检查成功、功能测试、修复延迟,以及重新生成的有效代码量。 |
| 可检查的稳定性—自由度权衡 | 锁定选定的粗粒度或细粒度潜位置,只采样其余位置。 | 解码后的局部性、语法、结构不变量、编辑自由度、多样性和不确定性。 仅锁定潜变量并不能保证重构正确。 |
当前实验说明了什么,又没有说明什么
在中文论文页面Inspectable Control for Structure-Preserving Software Regeneration所总结的实验中,分层 VQ-VAE 把 64-token Python 函数映射为 16 个顶层和 32 个底层离散位置。 锁定四个顶层潜码后,解析率从 0.453 提高到 0.591; 未锁定位置仍以 0.936 的比例发生变化,条件样本保持 0.998 的唯一率。
这证明了一个小规模设置中的可测稳定性—自由度权衡。它不保证精确保持 AST、 语义等价、功能正确、修复成功或仓库级行为。
配套研究Where Quality Breaks in Compressed Short-Text Generation还给出一个重要评估结论:潜空间代理指标的改善不一定传递到解码输出。 表示、生成和解码后行为应当作为不同阶段分别检查。
可复用的分阶段判断流程见区分编解码器损失与生成器损失的方法指南。
常见误解
“可以解析,所以就是正确的。”
成功解析只证明语法形式正确;程序仍可能违反测试、契约或用户意图。
“粗粒度潜码就是 AST 节点。”
除非已经证明显式对齐,否则不是。学习型潜码可能混合多个表面和结构因素。
“锁定潜变量就意味着源文本不变。”
解码是全局且学习得到的。固定潜位置能够提高稳定性,却不能保证某段文本完全相同。
“变化越少总是越好。”
只复制输入的编辑器具有完美稳定性,却没有任何任务进展。局部性和编辑成功必须同时测量。
下一步阅读
相邻工作使用不同控制面;在任务没有对齐时,不能把它们视为可互换的基线。
- Self-Edit: Fault-Aware Code Editor for Code Generation
把生成视为可编辑过程,并使用检测到的故障引导修正。
- Coeditor: Leveraging Contextual Changes for Multi-round Code Auto-editing
在多轮编辑中建模上下文代码变化,而不是每次都从头再生成。
- PAFT: Preservation Aware Fine-Tuning for Minimal-Edit Program Repair
在程序修复训练中显式建模保持性和最小改动。
- Constrained Decoding of Diffusion LLMs with Context-Free Grammars
展示如何在扩散解码期间通过形式约束提供语法保证。
- Neural Discrete Representation Learning
提出 VQ-VAE,为学习型离散潜表示提供基础机制。
- Simple and Effective Masked Diffusion Language Models
给出配套诊断研究中潜变量生成器采用的掩码离散扩散框架。
- An Empirical Study on the Potential of LLMs in Automated Software Refactoring
发现由 LLM 提议的不安全重构,并评估通过可信重构引擎重新应用已识别变换的效果。
- SWE-Refactor: A Repository-Level Benchmark for Real-World LLM-Based Code Refactoring
使用编译、测试和重构检测,评估仓库级、保持行为的真实代码重构。
- EfficientEdit: Accelerating Code Editing via Edit-Oriented Speculative Decoding
复用未改变的源代码片段并预测编辑位置,而不是把一次编辑当作完整的自回归再生成。
- Hydra: Efficient, Correct Code Generation via Checkpoint-and-Rollback Support
结合静态检查、检查点和定向回滚,避免在错误后重新生成已经有效的前缀。
简短总结
局部代码再生成是改动与保持之间的契约。 分层离散潜变量提供了一种可检查的表达方式,但只有在解码程序同时接受局部性、语法、结构、 行为、多样性和不确定性评估时,这种表示才有意义。