2619 字
约 8 分钟
16
S24-A18 · AI 与代码搜索:为什么它找不到你的类

让助手"找一下处理退款的地方",它给出了三个文件名,全是猜的——因为它没有读过你的仓库,只是从"退款"这个词联想到常见的命名习惯。而真实的退款逻辑在一个叫 reverse_settlement.py 的文件里,名字里没有"退款"两个字。

这个问题的本质不是模型能力,而是搜索方式:模型的"知识"来自训练数据,而你的代码不在里面。这个分工可以写得很明确:定位靠检索(确定性),理解靠模型(生成性)。而多数失败是把两件事都交给了模型——于是它既定位不准,又在此基础上解释。
所以"让它找代码"必须变成"先检索、再让它读",而这中间的关键是检索能否命中。


1. 三种"找代码"的方式

方式 依据
模型凭常识猜 命名惯例(不可靠)
关键词/正则搜索 字面匹配(可靠但需知道词)
语义/向量检索 语义相似(覆盖同义)
符号索引(调用图) 结构关系(最准)

第一项是"直接问助手"的默认行为,它的问题不在能力而在没有数据:你的私有命名它不知道。第二项(关键词)的隐含前提是"你知道该搜什么词",而"不知道业务词与代码词的对应"恰恰是搜索困难的来源。所以关键词可靠但需要先建立词汇映射。

第四项最准:"谁调用了这个方法""这个接口的实现在哪"是结构问题,而结构与语义都无关。

2. 为什么关键词会漏

原因 例子
命名不含业务词 reverse_settlement
多语言混用 中文注释、英文标识
缩写与简称 rfnd、tx
逻辑分散 退款在三个模块里各一半

第三项在"老代码"里很常见:缩写只有原作者懂,而搜索的人不知道要试哪些缩写。

第四项还有个"时间"版本:同一个逻辑在不同时期被重写过,旧版本仍在某处被调用。于是"找到三处实现"之后,还要判断"哪一处是活的"——这靠调用链,不靠文本。
第四项最麻烦:"退款"这个业务动作可能由"状态机 + 补偿任务 + 手工脚本"三处共同完成,任何单点搜索都只能找到一部分。

// 一次"找退款逻辑"的完整检索路径(多方式组合)
1 关键词:refund / 退款 / reverse / 冲正 / 撤销
2 符号:找到入口接口(/api/refund)→ 看调用链
3 数据:grep 状态枚举 REFUNDING / REFUNDED
4 配置:搜 refund 相关的开关与定时任务
// 单一方式都会漏;四种组合才接近完整

3. 让助手找得准的三种做法

做法 效果
先给它"正确的文件名/类名" 最有效
给它搜索工具(grep/符号检索) 让它自己找
给它仓库地图(目录 + 职责) 缩小范围

第二项是"工具化"的正解:让 Agent 有 grep、find、go to definition 这类工具第二项的成本在"工具质量":一个只会全文 grep 的工具,会返回几百条噪声,而模型在噪声里选错的概率很高。所以工具的"过滤与排序"比"能不能搜"更重要。
,它就能从"猜"变成"查"。而"猜"与"查"的差别,在私有代码上就是"对不对"。

第一项还有个"复用"价值:你自己搜的过程会形成"这个词对应这个文件"的知识,而它下次还能用。把定位完全交给模型,等于放弃积累这份映射。
第一项最便宜:你自己先搜到文件,再把文件贴给它。这时它的作用从"定位"变成"解释",而这是它擅长的部分。

// 两种提示的差别(同一任务)
差:"帮我找退款逻辑在哪" → 得到猜测
好:"退款逻辑主要在 src/settle/reverse.py,
    这里有入口函数和状态机,读一下并说明调用顺序"
// 关键:定位由人/工具完成,理解由模型完成

4. 检索工具的三个要求

要求 原因
能搜"定义"而非只搜"文本" 区分调用与定义
能返回上下文(前后若干行) 模型需要语境
能说明"没找到" 避免编造

第二项很实际:只给一行匹配,模型无法判断那行在做什么。所以检索结果要带上下文(如 ±5 行)。

第三项最容易被忽略:工具"没找到"时必须明确返回空第三项的反面例子很典型:工具返回"未找到匹配"时,模型仍会给出一个文件名,因为"什么都不说"在训练里是较差的回答。所以"没找到"要显式、且要重复强调。
,否则模型会"基于没找到"编造一个答案。

// 检索返回的最小结构(三字段)
{"file": "src/settle/reverse.py", "line": 42,
 "context": "def reverse_settlement(order_id):\n    # 冲正:调用支付网关撤销\n    ..."}
// 缺 context → 模型只能猜语义;缺 file/line → 无法验证

代码检索还有一个"识别符拆分"的技术点值得知道:把 reverseSettlement 拆成 reverse/settlement 建索引,否则"搜 settlement"永远搜不到驼峰命名的标识符。

// 三种索引策略的命中差异(搜"settlement")
原文索引:reverseSettlement        → 不命中(大小写+连写)
分词索引:reverse / settlement      → 命中
语义索引:向量(需注释或文档)      → 可能命中
// 结论:至少要做"标识符拆分 + 大小写归一"

5. 语义检索在代码上的边界

场景 效果
找"类似的实现" 好
找"具体调用点" 差(该用符号)
找"业务概念在哪" 中
跨语言/跨命名 好

第三项(业务概念)能不能搜到,取决于注释质量:写"反转结算"的注释比写"处理"有用得多。这也是"注释质量决定 AI 可用性"的一个具体体现。
第二项是语义检索的硬伤:"谁调用了 X"是结构问题,而向量相似度对结构不敏感。

第三项要看语料的注释质量:如果代码没有注释、命名又很抽象,语义检索也找不到。

评估"代码检索是否够用"有个便宜的办法:拿 10 个你已知答案的问题去测。比如"退款入口在哪""哪个类负责重试",看它能否定位到正确文件。这个测试集只需半小时建立,却能长期使用。

// 检索能力的自测集(10 题,每题一个已知答案)
1 退款入口 → src/settle/reverse.py:42
2 重试策略 → src/common/retry.py
3 订单状态机 → src/order/state.py
// 指标:Top-1 准确率、Top-5 命中率、是否编造(给出不存在的路径)

6. 排错:五种"AI 找不到代码"

现象 成因 处理方向
给的文件不存在 凭常识猜 先自己搜
找到的是测试代码 无"定义优先" 检索加过滤
只找到一半 逻辑分散 多方式组合
说"找到了"但内容不符 没有上下文 返回带 context
说"没找到"却没搜 无工具 给它检索工具

第一项最危险:"不存在的文件名"看起来像真的,而验证成本由人承担。第四项(说找到了但内容不符)的排查方式是"让它引用行号与原文"。要求"贴出你看到的 3 行",就能立刻判断它是真读了还是编的。

最后一条与"上下文成本"有关的边界:检索到的片段越多,模型越容易"抓错重点"。所以"给 20 个相关文件"往往不如"给 3 个最相关的"。检索的目标不是"找回全部",而是"找回那一个"。

// 片段数量的经验值
1–3 个片段:模型聚焦,适合"解释这段逻辑"
5–8 个片段:适合"比较几种实现"
>10 个片段:注意力分散,容易得出"综合了多处"的错误结论

7. 边界:什么情况不必检索

场景 为什么 做法
单文件脚本 全在眼前 直接贴
标准框架用法 属于公共知识 直接问
已给出文件路径 无需定位 直接读
探索性提问("一般怎么做") 不需要具体代码 直接问

最后一条与"工具"有关的边界:给 Agent 的检索工具应当"窄而准"(限定目录、限定文件类型),而不是"整个磁盘"。范围越大,噪声越多,而噪声会直接变成错误结论。
判断口径一句话:这个任务需要"你的代码里的事实"还是"一般做法"。需要事实,就必须先检索(人或工具);只需要一般做法,直接问模型更快。


8. 自测

  1. "让它找代码"为什么会失败?问题的本质是能力还是数据?
  2. 四种找代码的方式里,哪一种最准?为什么"谁调用了这个方法"是结构问题?
  3. 关键词搜索会漏的四种原因是什么?为什么"逻辑分散"最难处理?
  4. 为什么"给它检索工具"能从"猜"变成"查"?你自己先搜到文件有什么好处?
  5. 检索工具的"返回上下文"与"说明没找到"分别防什么?
  6. 判断"是否需要检索"的那个问题是什么?
S24-A18 · AI 与代码搜索:为什么它找不到你的类
https://www.clxhxhhr.top/posts/6527/
作者
clxstart
发布于
2024-12-31
许可协议
CC BY-NC-SA 4.0
评论
0 条
还没有评论,先写一条吧。