RAG系统遇“数据拼凑”难题?本文揭示了LLM信息幻觉的根源在于数据工程中的“信息断层”,强调通过确保信息“原子性”来保障RAG应用的数据完整与输出准确。
原文标题:从“数据拼凑”到“精准断案”:深度剖析RAG系统中信息完整性的关键作用
原文作者:阿里云开发者
冷月清谈:
具体来说,在知识库构建的索引阶段,为了提高检索效率,仅对标题、描述等非结构化文本进行分块和向量化,而缺陷ID、模块、版本等结构化元数据在处理过程中被当作元数据,与文本块在逻辑上或物理上“解耦”。随后在检索阶段,检索器只向LLM传递了这些匿名的文本片段,导致了它们各自的元数据“身份证”丢失。当LLM在生成阶段接收到由多个匿名文本片段拼接而成的长文本,却被指令要求返回包含缺陷ID、模块等具体结构化字段的信息时,由于上下文缺乏这些信息,模型便只能基于内部知识或上下文中的零星词汇进行“幻觉”或“创造性拼凑”。因此,这种数据拼凑并非模型的“故障”,而是其在信息不完整环境下的合理反应。
解决此问题的核心在于确保在整个RAG工作流中,每一份信息都保持其原始记录的**原子性与完整性**。具体方案是:在配置索引时,将缺陷的其他结构化字段(如ID、模块、归属项目、版本、状态)作为一个字典,完整地附加到每个生成的文本块上。这样,在检索返回最相似的文本块时,便会附带上完整的元数据包。经过此番改造,LLM接收到的上下文不再是无序的文本碎片,而是由多个结构完整、字段明确的历史缺陷记录组成的数据合集,从而实现了精准无误的查重报告。
文章最终总结,RAG的成功基石在于数据工程,而非单纯的Prompt工程;信息原子性是系统可靠性的前提;以及在AI调试过程中,建立端到端的系统性思维至关重要。
怜星夜思:
2、RAG调试的系统性思维:作者提到“建立系统性思维进行AI调试,避免简单归因于模型本身”。在咱们实际工作中,有多少次是吭哧吭哧改Prompt,结果发现问题根本不在Prompt上?大家有没有碰到过什么“坑”,让你认识到调试RAG真的需要从头到尾仔细审视整个流程的?分享一些经验呗!
3、Prompt复杂性和幻觉问题:文章里面一开始的Prompt已经很复杂,各种约束和两阶段任务流程都上了,但还是没解决问题。这说明啥?是不是意味着,当基础数据上下文有问题的时候,再复杂的Prompt也救不了场?大家觉得在什么情况下,Prompt工程才是“银弹”?
原文内容
最近在做智能缺陷查重的项目过程中,遇到一个有意思的问题,尽管采用了精心设计的Prompt和强大的LLM,模型在返回重复缺陷时,仍产生数据不一致的“拼凑”结果。通过层层递进的分析,发现问题的根源并非出在Prompt工程或模型本身,而在于RAG数据库中的“信息断层”。这里将问题分析与调试过程记录下来,与大家共享。
一、背景:软件工程中“重复缺陷”的治理困境
在专有云产品版本演进过程中,重复缺陷的识别与管理是一项长期存在且成本高昂的挑战。测试人员或开发人员在提交新缺陷时,往往难以高效检索并确认其是否已存在于庞大的历史缺陷库中。这不仅导致了大量重复劳动,也分散了问题跟进的焦点,降低了整体研发效能。为解决此痛点,我们立项开发一套“智能缺陷查重系统”,旨在利用AI技术自动识别新提交的缺陷是否为重复项。当然,今天的重点,是在开发这个查重系统中遇到的一个细节问题,下面听我娓娓道来。
二、目标:构建基于RAG的自动化缺陷分析专家
我们的技术选型为当前主流的检索增强生成(RAG)架构,其核心设计思路如下:
-
知识库构建:将海量的历史缺陷数据(包含
标题
,描述
,模块
,版本
等字段)处理后,存入向量数据库,形成一个可供语义检索的知识库。 -
智能检索:当接收到新的缺陷数据时,系统提取其核心语义信息(如
标题
和描述
),在知识库中进行向量相似度检索,召回最相关的一组历史缺陷。 -
LLM分析与生成:将新缺陷与检索到的历史缺陷一并作为上下文,交由大语言模型(LLM)。通过精密的Prompt设计,将LLM设定为一名“经验丰富的QA专家”,要求其执行深度分析、精准比对,并最终以严格的JSON格式输出查重结论,包括是否重复、相似度评分,以及最相似缺陷的完整、准确信息。
我们为这位“AI专家”制定了详尽的工作指南(即初始Prompt),明确了不同字段(如描述
vs 模块
)在判断中的权重,并期望它能输出一个逻辑自洽且数据准确的分析报告。
三、遇到的核心难题:无法根治的“数据拼凑”现象
Promt设计完后,就找了一条缺陷数据测试,很快就暴露出一个令人困惑的严重问题:模型返回的“最相似缺陷”是一个数据不一致的“拼凑体”(Composite Entity)。
初步现象:
输入:
{
"标题":"xxxxxx_@_adb实例中断任务",
"描述":"【专有云xxx单号】000xxxxxx
【底座及版本】v3.xx.x
*【产品版本】ADBx.0
*【问题描述】
1,现场升级到v3.xx.x-ADBx.0 版本后 新建ADB实例任务在创建xx的时候会失败,通过报错看是端口被占用,但是实际到机器上看对应的端口 也没有进程占用,通过docker logs 查看发现 启动时还在检查influxdb 。 ",
"模块":"yy",
"版本":"v3.xx.x",
}
模型输出:
{
"is_duplicate": true,
"similarity_score": 93,
"justification": "新缺陷的标题和描述与历史缺陷#bug1在核心问题、环境配置及任务流中断表现上高度一致,且发生在同一类模块中。两者均涉及实例创建过程中任务流中断的问题,虽然具体产品版本不同,但根本原因均指向任务流执行时的关键组件异常。",
"most_similar_defect": {
"缺陷ID": "bug1",
"标题": "创建xx实例会有中断任务,报错为Cgrou_E2503066U2ZN4F",
"描述": "【问题描述】(截图或者错误信息,发生时间及相关变更)\n所有的实例创建任务流都中断在do_config_resource\n*【初步分析定位结果】(尽量详细,初步已排查步骤,截图,是否可复现)xxx........系统时间",
"模块": "yy",
"归属项目": "318x",
"版本": "v3.xx.x",
"状态": "Closed"
}
}
不难发现,上面的prompt返回的重复缺陷,其缺陷ID、标题、描述、模块等信息竟然不是来自RAG同一条缺陷数据,而是来自不同历史缺陷的数据对应字段,而且缺陷ID竟然是一个不存在的信息。
-
第一轮排查与假设:Prompt工程失效
我最初的假设是LLM未能完全理解Prompt的“原子性操作”意图。即,它将上下文中的所有信息视为一个扁平的“信息池”,并为了满足JSON输出格式,为每个字段在池中寻找“最佳”匹配项,从而导致了跨记录的数据拼凑。
基于此假设,我们对Prompt进行了大幅优化:
-
引入两阶段任务流程:强制模型先“识别唯一最佳匹配”,再“基于该匹配提取数据”。
-
强调记录的不可分割性:使用“作为一个不可分割的整体”、“那唯一一条记录”等措辞。
-
设立“核心约束”:用最严厉的措辞明确禁止拼凑行为。
优化后的Prompt:
# 角色
你是一位经验丰富的AI软件质量保证(QA)专家,你的核心任务是“缺陷分类与查重(Defect Triage and Deduplication)”。
上下文
你正在使用一个基于历史缺陷数据的RAG(Retrieval-Augmented Generation)知识库(@documents@)。当接收到一个新的缺陷数据时,RAG系统根据语义相似性从知识库中检索出了一组最相关的历史缺陷数据。每条缺陷数据都包含以下字段:标题, 指派给, 标签, 状态, 创建者, 模块, 创建时间, 验证者, 评论, 描述, 归属项目, 版本, ID,严重程度 。
任务
你的任务是基于提供的新缺陷数据和RAG系统检索到的历史缺陷,执行一个严格的、两阶段的查重流程:
第一阶段:识别唯一最佳匹配
- 深度分析:仔细分析新缺陷的每一个细节。
- 精准比对:将新缺陷与RAG检索出的 每一条 历史缺陷记录 作为一个不可分割的整体 进行综合比对。
- 确定冠军:在所有历史缺陷中,找出与新缺陷 整体相似度最高的 那唯一一条 记录。你的所有后续操作都将只围绕这一条“冠军”记录展开。
第二阶段:基于最佳匹配生成返回结果
- 判断与评分: 基于你在第一阶段找到的“冠军”记录,判断新缺陷是否为重复缺陷,并为其计算一个0-100的相似度分数。
- 提供依据: 简要说明你做出判断的核心理由。
- 提取数据:严格地、完整地 从那条“冠军”记录中提取其对应的 ID, 标题, 描述, 模块, 归属项目, 版本, 状态 字段,并填充到输出结果中。
分析与比对规则
在进行比对时,请遵循以下权重和逻辑:
- 核心依据(高权重): 描述、标题和评论。这是判断问题的根本。你需要理解其深层语义,而不仅仅是关键词匹配。例如,“用户无法登录” 和 “点击登录按钮无响应” 很可能描述的是同一个问题。
- 重要上下文(中权重): 模块, 归属项目, 版本。这些字段帮助确定问题发生的具体环境。一个在“xx[tianji]模块”的缺陷和一个在“yy[tianji]模块”的缺陷,即使描述相似,也可能是两个不同的问题。
- 辅助信息(低权重): 严重程度, 标签。这些可以作为佐证,但不作为主要判断依据。
- 忽略字段: 在计算相似度时,请忽略 ID, 创建时间, 创建者, 指派给, 验证者等具有唯一性或主观性的字段,因为它们与缺陷内容的重复性无关。
核心约束
至关重要:most_similar_defect 对象中的所有字段值(缺陷ID, 标题, 描述等)必须全部来源于你在第一阶段所选定的那 唯一一条 最相似的历史缺陷记录。严禁从不同的历史缺陷记录中摘取或拼凑字段。输出必须是一个真实存在的、完整的历史记录的快照。
输出要求
请基于分析与比对规则返回一条与输入缺陷数据最为相似的的历史缺陷,并将该缺陷对应的ID、标题、描述、模块、归属项目、版本、状态返回输出,严格按照以下JSON格式返回你的分析结果。
{
"is_duplicate": <true_or_false>,
"similarity_score": <一个0-100的整数,表示与最相似缺陷的相似度百分比>,
"justification": "<简明扼要的中文说明,解释你判断的核心理由,例如:'新缺陷的描述和标题与历史缺陷#XXXX在核心问题、复现步骤和报错信息上高度一致,且发生在同一模块。'>",
"most_similar_defect": {
"缺陷ID": "<最相似缺陷的ID>",
"标题": "<最相似缺陷的标题>",
"描述": "<最相似缺陷的描述>",
"模块": "<最相似缺陷的模块>",
"归属项目": "<最相似缺陷的归属项目>",
"版本": "<最相似缺陷的版本>",
"状态": "<最相似缺陷的状态>"
}
}
## 限制
- 仅针对缺陷分类与查重任务进行讨论和分析。
- 确保比对过程中的字段权重和逻辑一致。
- 输出结果必须符合指定的JSON格式,不得添加额外的解释性文字。
- 如果分析结果similarity_score小于90,则不返回
# 知识库
请记住以下材料,他们可能对回答问题有帮助。
${documents}
</code></pre>
</div>
</div>
<p data-wct-cr-11><span><span data-wct-cr-12><span data-wct-cr-13>然而,即使用了这份堪称“天衣无缝”的Prompt,问题依旧存在。并且更换了另一款以逻辑推理见长的模型 (DeepSeek),虽然它给出了不同的相似度判断,但其返回的</span></span></span><code><span><span data-wct-cr-12><span data-wct-cr-14>most_similar_defect</span></span></span></code><span><span data-wct-cr-12><span data-wct-cr-13>对象,其内部字段依旧存在来源不一、逻辑矛盾的问题。</span></span></span></p>
<ul>
<li>
<p data-wct-cr-16><span><span data-wct-cr-12><span data-wct-cr-17>排查升级:问题根源并非LLM或Prompt</span></span></span></p></li>
</ul>
<p data-wct-cr-16><span><span data-wct-cr-12><span data-wct-cr-13>当一个经过强力约束的Prompt,在不同模型上都无法解决一个结构性问题时,这强烈暗示了问题的根源不在于生成环节,而在于其上游——即LLM在生成答案时所能观测到的上下文(</span></span></span><code><span><span data-wct-cr-12><span data-wct-cr-14>@documents@</span></span></span></code><span><span data-wct-cr-12><span data-wct-cr-13>)本身存在结构性缺陷。</span></span></span></p>
<p data-wct-cr-16><span><span data-wct-cr-12><span data-wct-cr-13>我对整个RAG流程进行了深度剖析,定位到了一个致命的“信息断层”。</span></span></span></p>
<p data-wct-cr-16><span><span data-wct-cr-12><span data-wct-cr-13>1.根源诊断:索引与检索阶段的信息断层</span></span></span></p>
<p data-wct-cr-16><span><span data-wct-cr-12><span data-wct-cr-13>回到我刚开始建立的知识库,参考下图,为了提高检索效率,我只设置了</span></span></span><code><span><span data-wct-cr-12><span data-wct-cr-14>标题</span></span></span></code><span><span data-wct-cr-12><span data-wct-cr-13>, </span></span></span><code><span><span data-wct-cr-12><span data-wct-cr-14>描述</span></span></span></code><span><span data-wct-cr-12><span data-wct-cr-13>,</span></span></span><span data-wct-cr-15><span data-wct-cr-15><span data-wct-cr-14> </span></span></span><code><span><span data-wct-cr-15><span data-wct-cr-14>评论</span></span><span data-wct-cr-15><span data-wct-cr-13>作</span></span><span data-wct-cr-15><span data-wct-cr-13>为检索字段。而且我的RAG数据库是一个结构化的数据结构,每行代表一条缺陷,每列代表一个字段,那么基于标题、描述进行检索后,应该将检索最相关的缺陷的这行数据都返回才对。然而效果不及预期,这就不得不重新温习RAG的三个重要阶段。</span></span></span></code></p>
<p data-wct-cr-20><span data-wct-cr-21></span><span data-wct-cr-12><img src="https://raw.xinfinite.net/wct-cr-img/04490011862a00dbdbd0435cda71d469.jpg" alt="图片" data-wct-cr-22></span><span data-wct-cr-21></span></p>
<ul>
<li>
<p data-wct-cr-16><span><span data-wct-cr-12><span data-wct-cr-13>索引阶段的“有损压缩”:在构建知识库时,为了进行有效的语义检索,标准做法是仅对</span></span></span><code><span><span data-wct-cr-12><span data-wct-cr-14>标题</span></span></span></code><span><span data-wct-cr-12><span data-wct-cr-13>、</span></span></span><code><span><span data-wct-cr-12><span data-wct-cr-14>描述</span></span></span></code><span><span data-wct-cr-12><span data-wct-cr-13>等非结构化文本进行分块和向量化。在这个过程中,与这些文本块关联的结构化数据(如</span></span></span><code><span><span data-wct-cr-15><span data-wct-cr-14>缺陷ID</span></span></span></code><span><span data-wct-cr-12><span data-wct-cr-13>, </span></span></span><code><span><span data-wct-cr-15><span data-wct-cr-14>模块</span></span></span></code><span><span data-wct-cr-12><span data-wct-cr-13>, </span></span></span><code><span><span data-wct-cr-15><span data-wct-cr-14>版</span></span><span data-wct-cr-15><span data-wct-cr-14>本</span></span></span></code><span><span data-wct-cr-12><span data-wct-cr-13>)往往被当作元数据处理。如果处理不当,这些元数据会与其所属的文本块在逻辑上或物理上“解耦”。向量数据库中存储的,实质上是去除了身份信息的、匿名的文本片段。</span></span></span></p></li>
<li>
<p data-wct-cr-16><span><span data-wct-cr-12><span data-wct-cr-13>检索阶段的“碎片化召回”:检索器根据语义相似度,从数据库中召回了几个最相关的文本块。但它传递给下游LLM的,仅仅是这些文本块的纯文本内容,而丢失了它们各自的元数据“身份证”。</span></span></span></p></li>
<li>
<p data-wct-cr-16><span><span data-wct-cr-12><span data-wct-cr-13>生成阶段的“必然幻觉”:LLM收到的上下文</span></span></span><code><span><span data-wct-cr-12><span data-wct-cr-14>${documents}</span></span></span></code><span><span data-wct-cr-12><span data-wct-cr-13>本质上是一段由多个匿名文本片段拼接而成的长文本。面对一个要求返回</span></span></span><code><span><span data-wct-cr-12><span data-wct-cr-14>缺陷ID</span></span></span></code><span><span data-wct-cr-12><span data-wct-cr-13>、</span></span></span><code><span><span data-wct-cr-12><span data-wct-cr-14>模块</span></span></span></code><span><span data-wct-cr-12><span data-wct-cr-13>等具体结构化字段的指令,而上下文中又不存在这些信息时,模型唯一的选择就是基于其内部知识或上下文中的零星词汇进行“幻觉”或“创造性拼凑”。因此,数据拼凑不是模型的“故障”,而是其在信息不完整环境下的合理反应。</span></span></span></p></li>
<li>
<p data-wct-cr-16><span><span data-wct-cr-12><span data-wct-cr-17>解决方案的核心就是确保在整个RAG工作流中,每一份信息都保持其原始记录的原子性(Atomicity)</span></span></span></p></li>
</ul>
<ul>
<li>
<p data-wct-cr-16><span><span data-wct-cr-12><span data-wct-cr-13>在配置索引时,也需要勾选上该缺陷的其他结构化字段(</span></span></span><code><span><span data-wct-cr-12><span data-wct-cr-14>ID</span></span></span></code><span><span data-wct-cr-12><span data-wct-cr-13>, </span></span></span><code><span><span data-wct-cr-15><span data-wct-cr-14>模块</span></span></span></code><span><span data-wct-cr-12><span data-wct-cr-13>, </span></span></span><code><span><span data-wct-cr-15><span data-wct-cr-14>归属项目</span></span></span></code><span><span data-wct-cr-12><span data-wct-cr-13>, </span></span></span><code><span><span data-wct-cr-15><span data-wct-cr-14>版本</span></span></span></code><span><span data-wct-cr-12><span data-wct-cr-13>, </span></span></span><code><span><span data-wct-cr-15><span data-wct-cr-14>状态</span></span></span></code><span><span data-wct-cr-12><span data-wct-cr-13>等),使其作为一个字典,完整地附加到每个生成的文本块上。那么在检索返回最相似的文本块时,就会附带上完整的元数据包。</span></span></span></p></li>
</ul>
<p data-wct-cr-20><span data-wct-cr-21></span><span data-wct-cr-12><img src="https://raw.xinfinite.net/wct-cr-img/2cb4c39dd4a3d411e59a5a93c7775f49.jpg" alt="图片" data-wct-cr-23></span><span data-wct-cr-21></span><span data-wct-cr-24></span></p>
<p data-wct-cr-16><span><span data-wct-cr-12><span data-wct-cr-13>通过此番改造,LLM接收到的上下文不再是无序的文本碎片,而是由多个结构完整、字段明确的历史缺陷记录组成的数据合集。在此基础上,我们最初设计的Prompt便能准确无误地发挥作用,最终输出了数据完全一致的查重报告。</span></span></span></p>
<p data-wct-cr-16><span><span data-wct-cr-12><span data-wct-cr-13>优化后输出:</span></span></span></p>
<div data-wct-cr-7>
<div>
<pre><code>{
"is_duplicate": true,
"similarity_score": 95,
"justification": "新缺陷的描述和标题与历史缺陷#bug2在核心问题、复现步骤和环境信息上高度一致,且发生在同一模块zz,均涉及ADBx.0实例创建中断问题,且均提到了环境相关问题导致任务中断。",
"most_similar_defect": {
"缺陷ID": "bug2",
"标题": "【adbx.0】mm环境创建adbx.0的实例会异常中断",
"描述": "[缺陷描述]:xxxxxxxxxxxx描述",
"模块": "zz",
"归属项目": "318x",
"版本": "v3.yy.y",
"状态": "Open"
}
}
</code></pre>
</div>
</div>
<p data-wct-cr-16><span><span data-wct-cr-12><br></span></span></p>
<div data-wct-cr-7>
<div data-wct-cr-8>
<div data-wct-cr-9>
<p data-wct-cr-10><span>四、思考与总结</span></p>
</div>
</div>
</div>
<p data-wct-cr-11><span><span data-wct-cr-12><span data-wct-cr-13>本次深度调试过程为构建企业级RAG应用提供了一些参考:</span></span></span><span><span data-wct-cr-12><br></span></span></p>
<ul>
<li>
<p data-wct-cr-11><span><span data-wct-cr-12><span data-wct-cr-13>RAG的成功基石是数据工程,而非单纯的Prompt工程:在处理包含结构化信息的复杂任务时,RAG系统的瓶颈往往出现在如何设计高效且信息无损的索引与检索策略,其重要性甚至超过了对Prompt的精雕细琢。</span></span></span></p></li>
<li>
<p data-wct-cr-11><span><span data-wct-cr-12><span data-wct-cr-13>信息原子性是系统可靠性的前提:必须确保数据记录的完整性贯穿整个RAG流程。任何导致信息在索引、检索环节解耦的操作,都将直接导致生成环节的不可靠。</span></span></span></p></li>
<li>
<p data-wct-cr-16><span><span data-wct-cr-12><span data-wct-cr-13>建立系统性思维进行AI调试:当遇到模型“幻觉”或逻辑错误时,应避免将其简单归因于模型本身。需要将RAG视为一个端到端的系统,审查从数据源到最终输出的每一个环节,通过逻辑推理和实验来定位真正的故障点。</span></span></span></p></li>
</ul>
<p data-wct-cr-16><span><span data-wct-cr-12><span data-wct-cr-13>最终,我们的智能缺陷查重系统成功地从一个“数据拼凑者”蜕变为一个“精准断案者”,这不仅解决了业务落地过程中的一个痛点,也为我们团队在AI工程化落地方面积累了宝贵的实战经验。</span></span></span></p>
</div>
<div data-wct-cr-7>
<div data-wct-cr-25>
<div data-wct-cr-26>
<div data-wct-cr-27>
<div data-wct-cr-28>
<div data-wct-cr-29>
<div data-wct-cr-30>
<div data-wct-cr-31>
</div>
</div>
</div>
</div>
<div data-wct-cr-28>
<div data-wct-cr-32>
<p data-wct-cr-33><strong></strong></p>
<p data-wct-cr-33><strong><span data-wct-cr-34><span>颠覆传统 BI,用自然语言与数据对话</span></span></strong></p>
</div>
</div>
</div>
<div data-wct-cr-35>
<p data-wct-cr-33><span><br></span></p>
</div>
<div data-wct-cr-36>
<p data-wct-cr-33><span>针对企业在数据分析过程中面临的取数难、报表效率低和数据割裂等问题,Quick BI 作为企业级分析 Agent,支持通过自然语言完成看板搭建与数据获取,借助 AI 发现异常并归因,真正实现“ChatBI,对话即分析”,显著提升数据使用效率与用户体验,助力企业高效运营、科学决策。</span></p>
<p data-wct-cr-33><span><br></span></p>
<p data-wct-cr-33><span>点击阅读原文查看详情。</span></p>
</div>
<div data-wct-cr-37>
<div data-wct-cr-38>
<div data-wct-cr-39>
<div data-wct-cr-40>
</div>
</div>
</div>
<div data-wct-cr-41>
</div>
</div>
</div>
</div>
</div>
<div data-wct-cr-16>
<span data-wct-cr-12><br></span>
</div>
<p data-wct-cr-42></p>
</div>
</div>
</div>