在ProgressAwareContentAggregator中,我们做了RAG中引用材料的持久化,我们有以下代码:
List<ChatMessage.RagReference> ragReferenceChunks = results.stream()
.collect(Collectors.toMap(
content -> content.textSegment().metadata().getString(CHUNK_ID),
content -> content,
(existing, replacement) -> existing,
LinkedHashMap::new
)).values().stream()
.map(content -> ReferenceUtil.getRagReference(content, RetrievalSource.HYBRID))
.collect(Collectors.toList());
但是,这么做引入了一个bug。 ProgressAwareContentAggregator#aggregate 在 Reranker 完成后,需要按 chunkId 对 results 做一次去重,原实现使用了 Collectors.toMap 的三参重载。 Collectors.toMap 三参重载默认返回的是 HashMap。HashMap 基于哈希桶存储,不保证迭代顺序与插入顺序一致。一旦 chunkId 哈希分布跨桶,.values() 输出的顺序就会偏离 Reranker 给出的相关度顺序,最终持久化引用顺序与 LLM 上下文顺序脱节。 因为ragas在评测上下文准确率指标的时候,参考资料的顺序非常重要。因为以上操作导致了相关度分数高的可能排在了后面,导致最终评测结果分数很低(评测时实际是在0.5左右)。
修复方案
使用 Collectors.toMap 的四参重载,显式传入 LinkedHashMap::new 作为 Map 工厂:
List
content
content
LinkedHashMap 在哈希桶之外维护了一条双向链表,迭代顺序严格等于插入顺序。这样去重后的 values() 顺序就保持了 Reranker 输出的相关度排序,前端 [REFERENCE] 列表与持久化记录均与 LLM 实际依赖的上下文顺序对齐。