CrashSight在进行异常问题分组时,经常会由于一些特殊case导致无法聚合在一起,如堆栈里面包含uuid,玩家姓名等,从而产生大量重复issue,给用户带来不必要的干扰,同时海量的issue也影响了页面查询性能。另外,崩溃issue分组场景下,由于一些通用堆栈行的干扰,传统的分组算法有时会将实际不同的issue识别成相同issue,影响问题追踪精准度。因此,CrashSight团队引入用LLM大模型驱动的问题分组方法,带来更智能化的问题分组体验。
CrashSight提出的基于LLM大模型的堆栈分类优化方案系统架构如下。主流程仍然保留现有的Hash值精准匹配过程,如果精确匹配到已有分组,则不会进入堆栈相似度判定流程。如果检测到新的hash值,则会生成向量嵌入,并将其与数据库中现有的向量值进行相似度判定。判定核心模块主要为:生成文本嵌入向量、动态阈值获取、近似最近邻检索(ANN)、重排序(Re-ranking)、向量区分和存储。

基于异常上报的堆栈,调用 self._generate_embedding(stacktrace) 将堆栈文本转换为高维向量,如通过BERT、Sentence-BERT等模型。将向量转换为字符串格式(如 "[0.1,0.2,...]"),用于后续SQL查询。
核心步骤为:
完成文本嵌入向量生成后,我们基于pgVector 核心功能实现近似最近邻搜索(ANN)。
pgVector 是一个开源的 PostgreSQL 扩展插件,它使得 PostgreSQL 数据库能够高效地存储、查询和处理高维向量数据。同时pgVector 可以支持多种索引技术,如 HNSW(Hierarchical Navigable Small World)和 IVFFlat(Inverted File Index)等,支持在亿级数据中快速找到与目标向量最相似的条目,同时平衡精度与速度。
我们通过pgVector 从项目存储的错误向量表中快速找出Config.RERANK_CANDIDATES个最接近的候选组(如100个),按原始向量距离排序。
最终过滤和输出准确和相关的聚类结果需要设定一个阈值。我们通过动态阈值,可以实现更加适配不同项目、不同数据分布的“最佳聚类阈值”。动态阈值的设定可以基于规则的方法或者自适应的算法,如Isolation Forest,SVM。目前CrashSight采用基于规则的方法来设定动态阈值,通过计算历史数据的均值(µ)和标准差(σ),动态设定阈值为t=μ+kσ(k为常数),因此动态阈值获取主要分为以下两个步骤:
收集历史相似度
每次聚类时,把本次“新样本与已存在组的最大相似度”记录下来,形成一个滑动窗口(最多1000个)。
动态阈值计算
如果样本太少(<50),直接用初始阈值(如0.95),否则,计算历史相似度的均值 mean 和标准差 std。
取mean- 2 * std作为"动态阈值”,但不低于初始阈值。
最终阈值做一次平滑:
final threshold = decay * dynamic + (1 - decay) * initial
其中 decay = 0.9,起到平滑作用,避免阈值剧烈波动。
动态阈值主要起到如下作用,如果历史相似度都很高,说明组内样本很相似,可以适当降低阈值,允许更宽松的聚类。如果历史相似度波动大,std 大,阈值会自动提高,避免误聚类。考虑到更期望保障匹配的准确性,一般初始阈值设定的比较严格。
粗排获得候选集后,需要进行重排序(Re-ranking)。重排序的核心思想是对候选集应用更复杂的模型或规则,进行二次排序,通过更精细的算法或业务规则提升最终结果的准确性和相关性,确定与语义更符合的结果,生成最终的Top-K(如5条)结果。
具体步骤如下:
对候选组进行精确相似度计算,综合两个维度的特征:
权重m:错误组的聚合向量(error_groups.embedding_vector)与当前错误堆栈的相似度
权重n:原始错误向量(error_vectors.embedding)与当前错误堆栈的相似度
最终相似度 = m*(1-组向量距离) + n*(1-原始向量距离)
阈值过滤:
仅保留相似度 >= 项目动态阈值(通过_threshold_optimizer获取)的组。
择优取Top:
将达标组按综合相似度从高到低排序,选取Top-K的group_id。
最近邻检索(ANN)和重排序(Re-ranking)可参考查询示例如下:
WITH ann_candidates AS (
SELECT
eg.group_id,
ev.embedding AS vector
FROM error_vectors ev
JOIN error_groups eg ON ev.group_id = eg.group_id
WHERE ev.project_id = %s
ORDER BY ev.embedding <=> %s::vector
LIMIT {Config.RERANK_CANDIDATES}
),
reranked AS (
SELECT
ac.group_id,
(m * (1 - (eg.embedding_vector <=> %s::vector)) +
n * (1 - (ac.vector <=> %s::vector))) AS similarity
FROM ann_candidates ac
JOIN error_groups eg USING (group_id)
WHERE eg.project_id = %s
)
SELECT group_id
FROM reranked
WHERE similarity >= %s
ORDER BY similarity DESC
LIMIT 5
在错误堆栈分类场景,我们取Top1相似度的分组进行issue合并,如下是部分分组处理日志。

为了提高查询性能,我们应用了基于哈希分区的方法,按 project_id hash 分区所有表结构和索引自动初始化,每个分区表独立建主键索引和 HNSW 向量索引(Hierarchical Navigable Small World),提升检索和写入效率,易于维护和扩展每个分区表,可以支持多项目高并发,整体改善了查询延迟并提高了召回率。
我们将该方案应用到部分游戏项目数据中,数据表现如下

崩溃issue 的原始分组由于游戏引擎和业务逻辑的不同同时存在重复分类和错误分类的情况,所以在优化后,部分项目的分组数相比原来有所增加,部分项目有所降低,上下浮动范围在30%以内,但是经过人工校验核对,分类的精准度都明显提高。
错误issue的原始分组的重复分类问题更为突出,所以优化后项目A、B、D优化后的分组数降低了30%-70%不等,效果显著。
基于规则的问题分类(Rule-Based Clustering)和基于AI的问题分类(AI-Based Clustering)关系如下所示。

为确保新的分组没有“矫枉过正”从而产生大量分组错误,我们人工排查了新分组包含的堆栈情况,发现新分组相比旧分组主要新增了如下几类情况致:

以上合并分类和新增分类的情况整体符合正确合并要求,当前测试每条数据可以在毫秒级别响应,完全可以满足线上要求,已在部分数据量较大的项目中试点开放生效。如图所示,错误issue直接应用基于AI的分类模型进行分类。

崩溃issue在issue详情页中已添加“AI问题分类”tab,支持查看AI子分类和相似问题。