为什么选该Embedding?通用语义相似是否等于漏洞推理相关?

第118题:为什么选该Embedding?通用语义相似是否等于漏洞推理相关?

在这里插入图片描述

1. 核心结论

通用语义相似:

Similarity(q,d) Similarity(q,d) Similarity(q,d)

不能直接等价于漏洞推理相关:

Relevancesecurity(q,d) Relevance_{\text{security}}(q,d) Relevancesecurity(q,d)

因为两个代码片段可以在:

  • API;
  • 函数名;
  • 自然语言描述;
  • CWE主题;

上高度相似,但它们对当前漏洞结论的作用完全不同。

所以我不会用:

“这个 Embedding 在通用榜单上效果好”

作为选择依据。

我会先定义:

什么文档才算对当前漏洞判断真正相关。

然后在相同数据、相同切分和相同计算预算下比较多个 Embedding,在:

  • Recall@K;
  • MRR;
  • nDCG;
  • 跨项目泛化;
  • 延迟;
  • 索引大小;
  • 最终漏洞检测效果;

上选择最合适的模型。

如果当前材料没有这些实验,我会把:

“为什么选这个 Embedding”

明确列为待补实验,而不会声称它已经被证明是最优选择。


2. 为什么“语义相似”和“漏洞相关”不是同一个概念

通用 Embedding 通常希望满足:

$$
SemanticSimilarity(q,d_1)

SemanticSimilarity(q,d_2)
$$

意味着:

d1d_1d1 在自然语言或代码语义上与 qqq 更接近。

但漏洞分析真正需要的问题是:

这个候选证据能不能帮助判断当前代码为什么存在或不存在漏洞?

可以定义:

R(q,d)=1 R(q,d)=1 R(q,d)=1

表示文档 ddd 对查询 qqq 的安全结论提供有效证据。

这里的“有效证据”可能是:

  • 相同漏洞机理;
  • 相同危险 API 的正确/错误用法;
  • 对应 Source;
  • 对应 Sink;
  • Sanitizer;
  • 数据流传播关系;
  • 调用链;
  • 补丁模式;
  • 攻击前置条件;
  • 反例代码。

因此:

SemanticSimilarity≠SecurityReasoningRelevance SemanticSimilarity \neq SecurityReasoningRelevance SemanticSimilarity=SecurityReasoningRelevance

这是本题最重要的结论。


3. 一个最简单的反例

假设待分析代码是:

char buf[8];
strcpy(buf, input);

查询目标是判断:

是否存在 Buffer Overflow?

检索系统可能找到两个候选。

候选 A:

char dst[8];
strcpy(dst, src);

与查询代码非常相似。

候选 B:

if (strlen(input) >= sizeof(buf)) {
    return ERROR;
}
memcpy(buf, input, strlen(input));

从表面 Token 来看,候选 A 可能更相似。

但漏洞推理真正需要比较的是:

是否检查输入长度
是否可能越界
目标buffer大小
危险函数调用条件

因此一个“表面不像”的安全反例可能比一个“代码很像”的样本更有判别价值。


4. 同API也不等于同漏洞

例如下面两段代码都调用:

memcpy()

第一段:

memcpy(dst, src, user_len);

第二段:

if (user_len <= sizeof(dst)) {
    memcpy(dst, src, user_len);
}

它们具有:

相同API
相似Token
相似局部结构

但漏洞标签可能相反。

因此,如果 Embedding 主要学习:

SameAPI→HighSimilarity SameAPI \rightarrow HighSimilarity SameAPIHighSimilarity

可能会把:

安全实现

和:

漏洞实现

都聚在一起。

对普通代码搜索这可能合理。

对漏洞判别却未必足够。


5. 同CWE也不一定是最相关文档

假设两个样本都属于:

CWE-78 OS Command Injection

一个漏洞来自:

shell=True

另一个来自:

system(user_input)

从分类层面:

CWEA=CWEB CWE_A=CWE_B CWEA=CWEB

但具体:

  • Source;
  • Propagation;
  • Sanitization;
  • Sink;
  • Exploit Condition;

可能完全不同。

所以“同 CWE”可以作为弱相关信号,但不能自动作为最终 Ground Truth。

真正的 Retrieval Label 必须根据任务定义。


6. 第一步应该先定义Retrieval Relevance

我会先把任务定义成一句可以判断真假的话。

例如:

给定待分析函数 qqq,检索出的代码或文档 ddd 是否包含能够支持当前漏洞存在性判断的证据?

然后定义:

R(q,d)∈{0,1} R(q,d)\in\{0,1\} R(q,d){0,1}

或者使用多级相关性:

R(q,d)∈{0,1,2,3} R(q,d)\in\{0,1,2,3\} R(q,d){0,1,2,3}

例如:

等级含义
0无关
1同主题/同API,但不能支持判断
2同漏洞机理,具有参考价值
3直接包含当前判断所需证据

这样训练和评测的 Embedding 才是在学习:

Task Relevance

而不只是:

Semantic Similarity

7. “相关文档”的标注单位也必须明确

不同任务下,相关文档可能完全不同。

7.1 CWE定义

适合回答:

这个漏洞类型的标准定义是什么?

7.2 历史漏洞代码

适合回答:

是否存在相似的漏洞实现模式?

7.3 修复Commit

适合回答:

类似问题历史上是如何修复的?

7.4 Source-Sink路径

适合回答:

不可信数据能否真正到达危险操作?

7.5 安全代码反例

适合回答:

什么情况下同一个API的使用是安全的?

所以不能把:

CWE
Patch
Code
Commit
Attack Path

全部混成一种“相关文档”。

它们承担不同推理角色。


8. 为什么通用Embedding只能作为候选基线

例如 Sentence-BERT 的目标是产生可以通过 Cosine Similarity 比较的语义向量。

CodeBERT 则学习 Programming Language 和 Natural Language 的通用代码表示,并在 Code Search 等任务上验证。

这些结果能够说明模型具备一定:

Semantic Representation

或:

Code Retrieval

能力。

但不能直接推出:

对漏洞推理任务也是最优Embedding。

因为训练目标不同。

可以形式化成:

Ppretrain(q,d)≠Psecurity(q,d) P_{\text{pretrain}}(q,d) \neq P_{\text{security}}(q,d) Ppretrain(q,d)=Psecurity(q,d)

存在 Domain Shift 和 Task Shift。

所以必须重新做安全任务内评测。


9. Code Search能力也不能直接等同于Security Retrieval能力

普通 Code Search 常见查询可能是:

find function that parses JSON

目标是找到功能语义相近代码。

而安全检索查询可能是:

这个user-controlled value是否未经净化进入SQL sink?

后一问题可能需要理解:

Data Flow
Control Flow
Call Relation
Sanitization

因此相关性函数不同。

可以表示成:

Rcode-search≠Rvulnerability R_{\text{code-search}} \neq R_{\text{vulnerability}} Rcode-search=Rvulnerability

即使使用同一个 Embedding,也需要针对新的相关性定义重新验证。


10. 程序结构信息可能比文本相似更重要

代码中的真实关系包括:

Definition
Use
Call
Import
Data Flow
Control Flow
Source
Sink

因此一个候选代码片段可能:

Token相似度很低

但通过 Call Graph 与当前函数直接关联。

例如:

controller.py
    ↓
service.py
    ↓
validator.py
    ↓
database.py

真正的安全证据可能位于:

validator.py

或者:

database.py

而不是文本最像的文件。

DraCo 在 Repository-Level Code Completion 中也观察到,单纯基于文本相似度或简单 import 关系得到的跨文件上下文可能不够相关,因此引入 Data-Flow-Guided Retrieval。

这不能直接证明漏洞检索必须使用 Data Flow,但说明:

代码任务相关性可能由程序关系决定,而非只由文本语义决定。


11. 为什么通常使用Bi-encoder做第一阶段召回

大规模检索库可能包含:

N=105∼108 N=10^5\sim10^8 N=105108

个代码 Chunk。

如果使用 Bi-encoder,可以分别计算:

eq=f(q) e_q=f(q) eq=f(q)

ed=g(d) e_d=g(d) ed=g(d)

文档向量:

ed e_d ed

可以提前离线计算并建立向量索引。

查询时只需要计算:

Similarity(eq,ed) Similarity(e_q,e_d) Similarity(eq,ed)

例如:

cos⁡(eq,ed) \cos(e_q,e_d) cos(eq,ed)

或:

eq⊤ed e_q^\top e_d eqed

所以适合:

Large-Scale Candidate Retrieval。


12. 为什么可以再加Cross-encoder Reranker

Bi-encoder 的问题是:

Query

和:

Document

在编码阶段基本独立。

它很难像 Cross-Encoder 那样进行细粒度 Token-Level Interaction。

因此可以采用两阶段结构:

Bi-encoder
↓
Top-100
↓
Cross-encoder
↓
Top-10

第一阶段负责:

Recall Recall Recall

第二阶段负责:

Precision Precision Precision

即:

Retrieve
→
Rerank

对于漏洞任务,Cross-Encoder 可以进一步判断:

  • API 是否真的起相同作用;
  • Sanitizer 是否存在;
  • Source-Sink关系是否一致;
  • 候选是否只是表面相似。

13. Embedding应该比较哪些候选

至少可以加入几类模型。

13.1 Sparse Baseline

例如:

BM25

它对:

  • API名称;
  • 函数名;
  • CVE;
  • CWE;
  • Identifier;

等精确词匹配可能很强。

因此必须保留。

13.2 通用Embedding

测试通用语义能力是否足够。

13.3 Code-specific Embedding

例如从代码语料训练的模型。

测试:

Programming Language Representation 是否改善检索?

13.4 Security-adapted Embedding

如果有足够漏洞相关性标签,可以进行任务微调。

比较:

Egeneral E_{\text{general}} Egeneral

Ecode E_{\text{code}} Ecode

Esecurity E_{\text{security}} Esecurity

才能回答:

为什么最终选择某一个Embedding?


14. Embedding选择首先看Recall@K

对于第一阶段召回,我最关注:

Recall@K Recall@K Recall@K

定义为:

$$
Recall@K

\frac{
\text{Top-K中命中的相关证据}
}{
\text{全部应召回证据}
}
$$

因为如果真正证据没有进入候选集:

Retriever Miss

后面的:

Reranker
LLM
Agent

都无法恢复。

所以第一阶段目标通常是:

先保证 Evidence Coverage。


15. 还要看MRR和nDCG

如果每个 Query 有一个关键证据,可以用:

$$
MRR

\frac{1}{|Q|}
\sum_q
\frac{1}{rank_q}
$$

它衡量关键证据出现得有多靠前。

如果一个 Query 有多个相关程度不同的证据,可以使用:

nDCG@K nDCG@K nDCG@K

因为它能够考虑:

不同相关等级
+
排序位置

例如:

直接Source-Sink Path

应该排在:

只是同CWE的历史代码

之前。


16. 不能只测离线Retrieval指标

最终目标是漏洞分析。

所以还需要检查:

Retriever→Generator Retriever \rightarrow Generator RetrieverGenerator

之后到底有没有真实收益。

可以比较:

No Retrieval
Random Retrieval
BM25
Embedding Retrieval
Embedding + Reranker
Oracle Retrieval

然后记录:

F1vuln F1_{\text{vuln}} F1vuln

LocalizationAccuracy LocalizationAccuracy LocalizationAccuracy

EvidenceAccuracy EvidenceAccuracy EvidenceAccuracy

如果:

Recall@10↑ Recall@10\uparrow Recall@10

但最终:

F1vuln F1_{\text{vuln}} F1vuln

完全不变,那么可能说明:

检索指标改善没有转化成实际任务价值。


17. Oracle Retrieval是非常重要的上界实验

人工给出正确证据:

Doracle D_{\text{oracle}} Doracle

然后让同一个 Generator 推理。

得到:

Qoracle Q_{\text{oracle}} Qoracle

当前检索器得到:

Qretrieval Q_{\text{retrieval}} Qretrieval

如果:

Qoracle≫Qretrieval Q_{\text{oracle}} \gg Q_{\text{retrieval}} QoracleQretrieval

说明:

Retriever仍然是主要瓶颈。

如果:

Qoracle≈Qretrieval Q_{\text{oracle}} \approx Q_{\text{retrieval}} QoracleQretrieval

但最终效果仍不高,则问题更可能出现在:

Generator / Reasoning

而非 Embedding。


18. Exact Search可以区分Embedding和ANN问题

向量索引通常使用:

Approximate Nearest Neighbor

即 ANN。

但检索失败可能有两种原因。

第一种:

Embedding空间本身排错了

第二种:

Embedding排序正确
但ANN近似搜索没有找到真正近邻

因此可以比较:

Recall@KExact Recall@K_{\text{Exact}} Recall@KExact

和:

Recall@KANN Recall@K_{\text{ANN}} Recall@KANN

如果:

RecallExact≫RecallANN Recall_{\text{Exact}} \gg Recall_{\text{ANN}} RecallExactRecallANN

说明主要问题在索引参数或 ANN。

如果两者都低,则更可能是:

RepresentationProblem RepresentationProblem RepresentationProblem

这可以避免把向量索引问题误判成 Embedding 模型问题。


19. Hard Negative为什么重要

假设正样本:

unsafe strcpy usage

负样本只是随机找:

matrix multiplication

这种负样本太容易。

模型只需要学会:

字符串处理
vs
数学计算

就可以区分。

它没有学会真正的漏洞边界。

因此 Hard Negative 应该满足:

Similaritysurface↑ Similarity_{\text{surface}}\uparrow Similaritysurface

但:

Relevancesecurity=0 Relevance_{\text{security}}=0 Relevancesecurity=0

也就是:

看起来很像,但安全结论不同。

稠密检索研究如 ANCE 也指出,过于简单、无信息量的负样本会限制表示学习,Hard Negative 能够为 Retriever 提供更有效的判别信号。


20. 漏洞任务中的Hard Negative可以怎么构造

例如 Query 是:

某个SQL Injection漏洞代码

Hard Negative 可以是:

20.1 同API但安全

execute(parameterized_query)

20.2 同项目但安全

避免模型只学习:

repository identity

20.3 同CWE主题但机制不同

避免模型只看到:

CWE关键词

20.4 修复后的代码

例如:

Codevulnerable Code_{\text{vulnerable}} Codevulnerable

和:

Codepatched Code_{\text{patched}} Codepatched

局部结构高度接近,但标签相反。

这种样本特别有利于学习真正的安全决策边界。


21. Hard Negative也有False Negative风险

一个被当成负样本的代码:

unlabeled

不一定真的:

benign

如果它实际存在漏洞:

y=1 y=1 y=1

但训练标签写成:

y~=0 \tilde y=0 y~=0

那么 Contrastive Learning 会强迫模型:

sim(q,d)↓ sim(q,d)\downarrow sim(q,d)

这实际上是错误监督。

所以困难负样本需要做:

  • 标签来源记录;
  • 人工抽检;
  • 补丁验证;
  • 静态/动态证据复核。

越 Hard 的 Negative,越应该关注 False Negative。


22. 还需要做跨项目切分

如果同一个 Repository 同时出现在 Train 和 Test:

函数名
API组合
编码风格
目录结构

都可能形成 Shortcut。

因此安全检索应重点报告:

Recall@Kcross-repo Recall@K_{\text{cross-repo}} Recall@Kcross-repo

而不只看:

Recall@Krandom-split Recall@K_{\text{random-split}} Recall@Krandom-split

更严格时还可以做:

  • Cross-project;
  • Cross-time;
  • Cross-CWE;
  • Cross-language;

评测。

如果一个 Embedding 只在同项目随机切分有效,泛化证据较弱。


23. 为什么不能只根据Embedding维度选择

例如:

Model A: 384 dimensions
Model B: 768 dimensions
Model C: 1024 dimensions

更高维:

d↑ d\uparrow d

不代表:

RetrievalQuality↑ RetrievalQuality\uparrow RetrievalQuality

同时索引存储近似与:

N×d N\times d N×d

相关。

维度越大通常意味着更高:

  • Index Memory;
  • Network Cost;
  • Similarity Computation Cost。

因此模型选择需要比较:

Quality Quality Quality

和:

Efficiency Efficiency Efficiency

两部分。


24. 一个合理的Embedding选择表

最终可以得到:

模型Recall@10MRRCross-Repo RecallP95延迟Index SizeEnd-to-End
BM25
General Embedding
Code Embedding
Security-tuned Embedding
Hybrid + Reranker

然后选择:

$$
E^*

\arg\max_E
Utility(E)
$$

其中:

$$
Utility

f(
Recall,
Ranking,
Generalization,
Latency,
Memory,
EndToEnd
)
$$

这才是“为什么选该 Embedding”的实验依据。


25. 可以进一步加入Hybrid Retrieval

代码安全任务既需要:

Semantic Similarity

又可能依赖:

Exact Identifier Match

例如:

  • API 名称;
  • CVE;
  • CWE;
  • 函数名;
  • 类名;
  • 配置项。

因此可以同时使用:

BM25
+
Dense Embedding

生成候选。

再进行:

Fusion
↓
Rerank

这样可以避免 Dense Retriever 丢失重要的稀有标识符。

是否需要 Hybrid Retrieval 仍然必须通过消融实验确定。


26. 如何判断Embedding真正学到了漏洞相关性

我会设计成对反事实。

给定 Anchor:

危险API + 未校验输入

Positive:

不同变量名、不同项目
但具有相同漏洞机理

Hard Negative:

相同API、相似结构
但进行了正确校验

理想 Embedding 应满足:

$$
sim(A,P)

sim(A,N)
$$

即使:

$$
LexicalSimilarity(A,N)

LexicalSimilarity(A,P)
$$

如果模型能够稳定做到这一点,才更能支持:

Embedding 捕获的是漏洞机理,而不只是表面代码相似度。


27. 最关键的消融实验

至少比较:

BM25
General Semantic Embedding
Code Embedding
Task-tuned Embedding
Task-tuned Embedding + Hard Negatives
Task-tuned Embedding + Reranker
Oracle Retrieval

然后分别观察:

27.1 Retrieval

Recall@K, MRR, nDCG Recall@K,\ MRR,\ nDCG Recall@K, MRR, nDCG

27.2 End-to-End

Precision, Recall, F1 Precision,\ Recall,\ F1 Precision, Recall, F1

27.3 Efficiency

Latency, IndexSize, Cost Latency,\ IndexSize,\ Cost Latency, IndexSize, Cost

如果任务微调只改善:

Recall@K Recall@K Recall@K

但不改善最终任务,则不能宣称它提高了漏洞检测能力。


28. 什么结果会推翻“这个Embedding更合适”的主张

需要提前定义 Falsification Condition。

例如:

如果在相同:

  • Retrieval Corpus;
  • Chunk;
  • Query;
  • Split;
  • ANN配置;
  • Top-K;
  • Generator;

条件下:

Recall@Kchosen≤Recall@Kbaseline Recall@K_{chosen} \le Recall@K_{baseline} Recall@KchosenRecall@Kbaseline

且:

EndToEndchosen≤EndToEndbaseline EndToEnd_{chosen} \le EndToEnd_{baseline} EndToEndchosenEndToEndbaseline

同时:

Costchosen≥Costbaseline Cost_{chosen} \ge Cost_{baseline} CostchosenCostbaseline

那么:

“该 Embedding 更适合漏洞检索”

没有被实验支持。

此时应该换模型,或者降低主张。


29. 如果所有Embedding效果都差怎么办

这可能说明问题本身不适合单纯单向量检索。

例如安全相关性主要依赖:

Call Graph
Data Flow
Source-Sink

那么可以将:

SemanticRetriever SemanticRetriever SemanticRetriever

与:

ProgramStructureRetriever ProgramStructureRetriever ProgramStructureRetriever

结合。

例如:

Dense Retrieval
+
Call Graph
+
Data Flow

这时研究问题从:

哪个Embedding最好?

变成:

单纯语义表示是否足以建模安全相关性?

这通常是更有价值的问题。


30. 面试时可以压缩成下面这段

我不会因为某个 Embedding 在通用语义检索或 Code Search 榜单上表现好,就直接认为它适合漏洞检索。首先要定义“相关”:是同主题、同 API、同 CWE,还是能够真正支持当前漏洞结论。我更倾向最后一种,因为漏洞推理可能依赖 Source、Sink、Sanitizer、调用链和数据流,而这些信息不一定具有最高的文本语义相似度。

选择 Embedding 时,我会固定同一个 Retrieval Corpus 和数据切分,对 BM25、通用 Embedding、代码 Embedding 和任务微调 Embedding 比较 Recall@K、MRR、nDCG、跨项目泛化、P95延迟和索引大小。Bi-encoder负责大规模召回,必要时再用 Cross-Encoder 精排。

训练时 Hard Negative 应该尽量是表面相似但漏洞结论不同的样本,例如同 API 的安全代码,而不是随机无关代码,同时要复核 False Negative。

实验上我还会加入 Exact Search、ANN Search 和 Oracle Retrieval。这样可以区分问题到底来自 Embedding 表示、ANN索引还是 Generator。如果某个 Embedding 只提高离线 Recall@K,却没有改善最终漏洞检测结果,我不会把它称为有效的端到端贡献。

所以我的结论是:

通用语义相似不等于漏洞推理相关;Embedding 的选择必须由安全任务定义和任务内实验决定。


31. 当前资料的事实边界

原面经没有提供:

  • 实际使用的 Embedding 名称;
  • Embedding 维度;
  • 是否经过安全领域微调;
  • Retrieval Corpus;
  • 相关性标注规则;
  • Hard Negative 构造方法;
  • Recall@K / MRR / nDCG;
  • Cross-Repository结果;
  • ANN参数;
  • Reranker;
  • End-to-End消融结果。

因此目前无法可靠回答:

为什么候选人的某个具体Embedding一定是最佳选择

当前能够可靠给出的结论是:

必须先定义漏洞推理相关性,再以任务内检索指标、跨项目泛化、系统成本和端到端效果比较候选Embedding。若尚未完成这些实验,应明确列为待补工作。


32. 来源

  1. Reimers & Gurevych, Sentence-BERT: Sentence Embeddings using Siamese BERT-Networks, EMNLP-IJCNLP 2019:说明Bi-encoder式Sentence Embedding可以通过Cosine Similarity进行高效语义相似检索。
  2. Feng et al., CodeBERT: A Pre-Trained Model for Programming and Natural Languages, Findings of EMNLP 2020:提出面向Programming Language和Natural Language的通用预训练表示,并在Code Search等任务上评测。
  3. Thakur et al., BEIR: A Heterogeneous Benchmark for Zero-shot Evaluation of Information Retrieval Models, NeurIPS Datasets and Benchmarks 2021:说明检索模型在不同任务与领域中的Zero-shot泛化差异明显,因此通用检索性能不能直接代表目标领域性能。
  4. Xiong et al., Approximate Nearest Neighbor Negative Contrastive Learning for Dense Text Retrieval, ICLR 2021:说明无信息量负样本会限制Dense Retrieval训练,并提出基于全局ANN检索的Hard Negative训练。
  5. Liu et al., RepoBench: Benchmarking Repository-Level Code Auto-Completion Systems, ICLR 2024:将Repository-Level系统拆分为Retrieval、Completion和完整Pipeline评测,说明检索质量和最终任务质量需要分别度量。
  6. Cheng et al., Dataflow-Guided Retrieval Augmentation for Repository-Level Code Completion, ACL 2024:指出基于文本相似度或简单Import关系得到的跨文件上下文可能与真实代码任务不够相关,并通过Data-Flow-Guided Retrieval引入程序结构相关性。
  7. Khattab & Zaharia, ColBERT: Efficient and Effective Passage Search via Contextualized Late Interaction over BERT, SIGIR 2020:展示Late Interaction在检索效率和细粒度Query-Document交互之间的另一种架构取舍。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小白羊丨

开始面试题与解析

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值