跳到主要内容

余弦相似度说你们俩很像,板子说不

画唠
画唠

· 阅读约 4 分钟

前几天翻到一篇八月初挂上 arXiv 的论文,做嵌入式 C 代码的函数复用检测。我本来以为是又一篇“用 embedding 找相似代码”的流水线文章——这个方向我绕过弯路,之前画 RAG 那张图的时候就想画“代码相似度”这个口,一直没动手。

结果被一个数字钉在椅子上了:SonarQube 当复用过滤器用,假阳性率 93.6%。

先别急着说“SonarQube 本来就不是干这个的”。对,它确实不是干这个的,但有意思的恰恰在这——论文里那些被误判为“可以复用”的函数对,余弦相似度超过 0.90。0.90!按我们平时做 embedding 检索的习惯,这已经是“基本同一个东西”的分数了。

打个比方:两个函数长得像双胞胎,说话像、走路像、连口头禅都像。但一个是给这块单片机写的,一个是给那块写的——寄存器映射不一样,外设接口不一样,HAL 层依赖不一样。你把“双胞胎”里这一位直接搬到另一位的位置上,板子不亮。

画张图:

  传统判断"能不能复用":
  代码相似度高 + 质量检查通过 ──► 复用 ✓

  实际情况:
  代码相似度高 + 质量检查通过 ──► ?硬件域兼容吗?
                                   │
                    外设 / 寄存器 / HAL 依赖 ──► 大概率 ✗

论文统计了那 83.5% 的失败对,全折在硬件环境不匹配上。而这玩意儿静态分析工具根本看不见——不是工具烂,是它的世界里压根没有“这块板子的寄存器长什么样”这个概念。它检查的是代码质量,质量满分和能不能跑在另一块芯片上,是两个正交的轴。

这个认知落差我嚼了很久。我们做检索做 RAG 的人,太习惯把“embedding 距离近”当成“语义相同”的代理了。在自然语言的世界里这个代理大体成立——两段话说的事情接近,坐标就接近。但代码的“语义”里有一半根本不在文本里,在板子上。文本相似度有个天花板,天花板外面那一大块,模型看不见。

得老实标一下这个比喻哪里漏风:不能说 embedding 在这里“错了”。它确实把“逻辑上干同一件事的函数”聚到一起了,聚类本身没毛病——毛病在我们拿聚类结果直接当复用结论,中间跳过了“硬件域”这一整层。是流水线的锅,不是向量的锅。

论文的解法倒是挺工程直觉的:领域感知的 RAG 流水线,把函数的内联注释、调用图上下文、项目 README 都揉进函数表示里——等于逼着“文本”把硬件上下文带进来一点。然后是我觉得全文最值得抄的一步:在检索栈里直接串了四个硬件兼容性验证器——外设令牌重叠、参数数量一致性、调用图依赖重叠、结构分支模式。

  检索(embedding 粗筛)
        │
        ▼
  四个验证器过滤 ──► 候选函数
        │
        ▼
  过不了硬件这关的,相似度再高也扔掉

八种骨干模型都试了一遍,从 MiniLM 到 StarCoder2 3B 都在列。人工验证了 40 个被拒的函数对,验证器准确率 97.5%。

等等等等,先别急——我知道你想说什么:六个项目、184 个函数,这规模也太小了。是的,小。但这次我反而不想拿规模说事,因为这篇文章真正画开的东西不是“这个方法多好”,而是“相似度和可复用性之间裂了条多大的缝”。93.6% 这个数字本身就是那条缝的宽度。缝是真实存在的,用多大规模量出来,它都还在。

我之前对“相似度检索找可复用代码”的默认信任,这次算是被敲掉一角。以后再看到"cosine 0.9,拿去用吧",脑子里会多弹一个问题:这个域里,有多少语义根本没进文本?

这条缝不止在嵌入式。配置文件、部署脚本、平台相关的胶水代码——凡是“能不能用”取决于文本之外某个环境的地方,纯文本 embedding 都在超纲作答。哪些地方超纲,得一个域一个域画。

这玩意儿真的太酷了——不是那篇论文酷,是“我以为向量看见的就是全部,结果它只看见了桌面上的那一半”这件事酷。下期我可能去画“embedding 到底看不见什么”,候选还有 KV cache。哪个你想看?

画唠
画唠

把被讲玄的概念用图 + 比喻 + 动手实验拆到咔哒扣明白,错的也保留。

查看主页 →