What · 是什么
五级回退:hunk 新侧→hunk 旧侧→全文件滑动窗口→跨文件重定位→LLM 重定位,保证评论落在真实行
行号定位回退链解决『审查评论最终必须落在哪个文件的哪几行』的定位问题,是评论回填 Collector 前的最后一步精确对齐
采用五级回退策略,优先级从同文件精确匹配逐步降级到跨文件匹配,最终由 LLM 兜底
第一级:同文件 hunk 新侧(context+added 行→新行号)精确连续匹配
第二级:hunk 旧侧(context+deleted 行→旧行号)匹配
第三级:NewFileContent 全文件滑动窗口匹配,窗口可跳空行容忍格式噪音
第四级:跨文件 RelocateAcrossFiles 纯字符串匹配;第五级:LLM ReLocateComment 生成目标代码块定位
配套 normalizeLine 清洗(去 +/- 前缀与首尾空白)与 matchConsecutive 精确连续匹配保证匹配严格性
Why · 为什么
原理 · Principle
单一匹配策略在真实 diff 中常失效(行号漂移、文件改名、上下文被截断),需要多级回退链逐级降级兜底
新侧优先因为评论目标是『改动后的新代码』,新行号对用户可点击跳转最有效
全文件滑动窗口解决 diff 上下文不足以唯一匹配的模糊场景,跳空行容忍格式噪音
LLM 兜底保证极端场景(跨文件、语义等价但文本不同)下仍能给出定位结果,避免评论无处安放
How · 怎么做
一级:在目标文件各 hunk 的新侧(context+added 行集合)按行顺序做精确连续匹配(matchConsecutive),命中返回新行号区间
二级:一级失败后转向 hunk 旧侧(context+deleted 行→旧行号)执行同样的连续匹配
三级:两级 hunk 匹配失败后,以 NewFileContent 全文件为文本,用滑动窗口匹配目标行片段(可跳过空行)
四级:仍失败则调用 RelocateAcrossFiles 在其他文件 diff 中做纯字符串匹配迁移
五级:最终由 LLM ReLocateComment 推理定位,返回代码块后 resolve 评论行号
全程先 normalizeLine 清洗行内容(去 +/- 前缀、首尾空白),再交给 matchConsecutive 严格精确匹配,杜绝模糊子串误命中
案例 · Cases
| 代表性案例 |
|---|
| 开发者把被注释的代码块上下移动了 20 行,一级新侧匹配失败,二级旧侧按旧行号定位成功 |
| diff 仅含少量上下文行导致片段被截断,三级全文件滑动窗口找到唯一匹配位置 |
| 评论针对的函数被抽到另一个文件,四级跨文件 RelocateAcrossFiles 纯字符串匹配命中新文件 |
| 重构后文本面目全非,四级 0/多命中被拒绝,最终五级 LLM 推理出目标位置 |
反模式 · Anti-patterns
- 跳过 normalizeLine 直接匹配带 +/- 前缀的行,导致全链路匹配失败
- 用子串/模糊匹配代替 matchConsecutive 精确连续匹配,误命中行号污染评论落点
- 五级链路不逐级降级、直接跳级,导致本可用旧侧定位的评论被 LLM 高成本兜底
- 忽略滑动窗口的跳空行能力,把格式噪音当失败原因,过早进入跨文件/LLM 兜底
正反实例论证 · Evidence
正例 · Pro
先 normalizeLine 再 matchConsecutive 精确连续匹配
line := normalizeLine(raw) // 去掉 + - 前缀与首尾空白if matchConsecutive(hunk.NewLines, lines) { return hunk.NewStartLine + offset // 新行号命中}逐行清洗后再按行序做精确连续匹配,避免 +/空格等 diff 噪音干扰,命中即返回新行号区间,是第一级定位的正确实现。
反例 · Con
跳过 normalizeLine 直接匹配带 +/- 前缀的行
# 错误:直接用 diff 原始行匹配if rawLine == targetLine { // "+foo()" 永远匹配不上 "foo()" ...}不先去除 +/- 前缀与首尾空白,文本恒不相等,全链路匹配失败,评论被迫降级到成本更高的跨文件/LLM 定位。
正例 · Pro
hunk 匹配失败后按级降级:旧侧→全文件滑动窗口→跨文件→LLM
1) hunk 新侧(context+added) 精确连续匹配 -> 新行号2) hunk 旧侧(context+deleted) -> 旧行号3) NewFileContent 滑动窗口(可跳空行)4) RelocateAcrossFiles 跨文件纯字符串匹配5) LLM ReLocateComment 推理兜底五级回退逐级降级,能用机械匹配解决的绝不提前动用 LLM;滑动窗口跳空行容忍格式噪音,保证定位结果稳定且低成本。
反例 · Con
用子串模糊匹配代替精确连续匹配
# 错误:strings.Contains 模糊匹配if strings.Contains(fileText, target) { // 可能命中多个位置 line = guessLine // 行号是猜的}模糊匹配可能命中多处或错位,行号污染评论落点,用户点击跳到错误代码,破坏审查可信度。