从“数据拼凑”到“精准断案”:深度剖析 RAG 系统中信息完整性的关键作用

本文详细探讨了在构建智能缺陷查重系统时,基于 RAG 架构遇到的“数据拼凑”难题。作者最初怀疑是 Prompt 工程设计不当,但经过深入排查,最终定位到问题的根源在于 RAG 知识库在索引和检索阶段出现了“信息断层”。具体而言,结构化元数据(如缺陷 ID、模块、版本)在向量化过程中与其所属的文本块逻辑解耦,导致 LLM 在接收上下文时无法获取完整的原始记录。当 LLM 被要求返回这些缺失信息时,便会基于内部知识或零星上下文进行“幻觉”或“创造性拼凑”。解决方案是确保在整个 RAG 工作流中,每一份信息都保持其原始记录的原子性,即在索引时将所有结构化字段作为字典完整附加到每个文本块上。通过此改造,LLM 能够接收到结构完整的数据合集,从而准确生成查重报告。文章强调,RAG 的成功基石是数据工程而非单纯的 Prompt 工程,并呼吁以系统性思维进行 AI 调试。




最近在做智能缺陷查重的项目过程中,遇到一个有意思的问题,尽管采用了精心设计的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系统检索到的历史缺陷,执行一个严格的、两阶段的查重流程:
        第一阶段:识别唯一最佳匹配
        1.  **深度分析**:仔细分析新缺陷的每一个细节。
        2.  **精准比对**:将新缺陷与RAG检索出的 每一条 历史缺陷记录 作为一个不可分割的整体 进行综合比对。
        3.  **确定冠军**:在所有历史缺陷中,找出与新缺陷 整体相似度最高的 那唯一一条 记录。你的所有后续操作都将只围绕这一条“冠军”记录展开。


        第二阶段:基于最佳匹配生成返回结果
        1.  **判断与评分**: 基于你在第一阶段找到的“冠军”记录,判断新缺陷是否为重复缺陷,并为其计算一个0-100的相似度分数。
        2.  **提供依据**: 简要说明你做出判断的核心理由。
        2.  **提取数据**:严格地、完整地 从那条“冠军”记录中提取其对应的 ID, 标题, 描述, 模块, 归属项目, 版本, 状态 字段,并填充到输出结果中。


        # 分析与比对规则
        在进行比对时,请遵循以下权重和逻辑:
        - **核心依据(高权重)**:  描述、标题和评论。这是判断问题的根本。你需要理解其深层语义,而不仅仅是关键词匹配。例如,"用户无法登录" 和 "点击登录按钮无响应" 很可能描述的是同一个问题。
        - **重要上下文(中权重)**:  模块, 归属项目, 版本。这些字段帮助确定问题发生的具体环境。一个在“xx[tianji]模块”的缺陷和一个在“yy[tianji]模块”的缺陷,即使描述相似,也可能是两个不同的问题。
        - **辅助信息(低权重)**: 严重程度, 标签。这些可以作为佐证,但不作为主要判断依据。
        - **忽略字段**: 在计算相似度时,请忽略 ID, 创建时间, 创建者, 指派给, 验证者等具有唯一性或主观性的字段,因为它们与缺陷内容的重复性无关。


        # 核心约束
        至关重要:most_similar_defect 对象中的所有字段值(缺陷ID, 标题, 描述等)必须全部来源于你在第一阶段所选定的那 唯一一条 最相似的历史缺陷记录。严禁从不同的历史缺陷记录中摘取或拼凑字段。输出必须是一个真实存在的、完整的历史记录的快照。




        # 输出要求
        请基于分析与比对规则返回一条与输入缺陷数据最为相似的的历史缺陷,并将该缺陷对应的ID、标题、描述、模块、归属项目、版本、状态返回输出,严格按照以下JSON格式返回你的分析结果。


        ```json
        {
          "is_duplicate": <true_or_false>,
          "similarity_score": <一个0-100的整数,表示与最相似缺陷的相似度百分比>,
          "justification""<简明扼要的中文说明,解释你判断的核心理由,例如:'新缺陷的描述和标题与历史缺陷#XXXX在核心问题、复现步骤和报错信息上高度一致,且发生在同一模块。'>",
          "most_similar_defect": {
            "缺陷ID""<最相似缺陷的ID>",
            "标题""<最相似缺陷的标题>",
            "描述""<最相似缺陷的描述>",
            "模块""<最相似缺陷的模块>",
            "归属项目""<最相似缺陷的归属项目>",
            "版本""<最相似缺陷的版本>",
            "状态""<最相似缺陷的状态>"
          }
        }
          
        ## 限制
        - 仅针对缺陷分类与查重任务进行讨论和分析。
        - 确保比对过程中的字段权重和逻辑一致。
        - 输出结果必须符合指定的JSON格式,不得添加额外的解释性文字。
        - 如果分析结果similarity_score小于90,则不返回


        # 知识库
        请记住以下材料,他们可能对回答问题有帮助。
        ${documents}

        然而,即使用了这份堪称“天衣无缝”的Prompt,问题依旧存在。并且更换了另一款以逻辑推理见长的模型 (DeepSeek),虽然它给出了不同的相似度判断,但其返回的most_similar_defect对象,其内部字段依旧存在来源不一、逻辑矛盾的问题。

        • 排查升级:问题根源并非LLM或Prompt

        当一个经过强力约束的Prompt,在不同模型上都无法解决一个结构性问题时,这强烈暗示了问题的根源不在于生成环节,而在于其上游——即LLM在生成答案时所能观测到的上下文(@documents@)本身存在结构性缺陷。

        我对整个RAG流程进行了深度剖析,定位到了一个致命的“信息断层”。

        1.根源诊断:索引与检索阶段的信息断层

        回到我刚开始建立的知识库,参考下图,为了提高检索效率,我只设置了标题描述, 评论为检索字段。而且我的RAG数据库是一个结构化的数据结构,每行代表一条缺陷,每列代表一个字段,那么基于标题、描述进行检索后,应该将检索最相关的缺陷的这行数据都返回才对。然而效果不及预期,这就不得不重新温习RAG的三个重要阶段。

        从“数据拼凑”到“精准断案”:深度剖析 RAG 系统中信息完整性的关键作用

        • 索引阶段的“有损压缩”:在构建知识库时,为了进行有效的语义检索,标准做法是仅对标题描述等非结构化文本进行分块和向量化。在这个过程中,与这些文本块关联的结构化数据(如缺陷ID模块)往往被当作元数据处理。如果处理不当,这些元数据会与其所属的文本块在逻辑上或物理上“解耦”。向量数据库中存储的,实质上是去除了身份信息的、匿名的文本片段。

        • 检索阶段的“碎片化召回”:检索器根据语义相似度,从数据库中召回了几个最相关的文本块。但它传递给下游LLM的,仅仅是这些文本块的纯文本内容,而丢失了它们各自的元数据“身份证”。

        • 生成阶段的“必然幻觉”:LLM收到的上下文${documents}本质上是一段由多个匿名文本片段拼接而成的长文本。面对一个要求返回缺陷ID模块等具体结构化字段的指令,而上下文中又不存在这些信息时,模型唯一的选择就是基于其内部知识或上下文中的零星词汇进行“幻觉”或“创造性拼凑”。因此,数据拼凑不是模型的“故障”,而是其在信息不完整环境下的合理反应。

        • 解决方案的核心就是确保在整个RAG工作流中,每一份信息都保持其原始记录的原子性(Atomicity)

        • 在配置索引时,也需要勾选上该缺陷的其他结构化字段(ID模块归属项目版本状态等),使其作为一个字典,完整地附加到每个生成的文本块上。那么在检索返回最相似的文本块时,就会附带上完整的元数据包。

        从“数据拼凑”到“精准断案”:深度剖析 RAG 系统中信息完整性的关键作用

        通过此番改造,LLM接收到的上下文不再是无序的文本碎片,而是由多个结构完整、字段明确的历史缺陷记录组成的数据合集。在此基础上,我们最初设计的Prompt便能准确无误地发挥作用,最终输出了数据完全一致的查重报告。

        优化后输出:

          {
          "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"
          }
          }

          四、思考与总结

          本次深度调试过程为构建企业级RAG应用提供了一些参考:


          • RAG的成功基石是数据工程,而非单纯的Prompt工程:在处理包含结构化信息的复杂任务时,RAG系统的瓶颈往往出现在如何设计高效且信息无损的索引与检索策略,其重要性甚至超过了对Prompt的精雕细琢。

          • 信息原子性是系统可靠性的前提:必须确保数据记录的完整性贯穿整个RAG流程。任何导致信息在索引、检索环节解耦的操作,都将直接导致生成环节的不可靠。

          • 建立系统性思维进行AI调试:当遇到模型“幻觉”或逻辑错误时,应避免将其简单归因于模型本身。需要将RAG视为一个端到端的系统,审查从数据源到最终输出的每一个环节,通过逻辑推理和实验来定位真正的故障点。

          最终,我们的智能缺陷查重系统成功地从一个“数据拼凑者”蜕变为一个“精准断案者”,这不仅解决了业务落地过程中的一个痛点,也为我们团队在AI工程化落地方面积累了宝贵的实战经验。


          AI 前线

          OpenAI 董事长:太多 AI 应用是在表演!AI 泡沫远比想象更严重,会有人赔大本;应用不应追求 AGI;微调或不再重要;支持抽成模式

          2025-12-23 22:16:12

          AI 前线

          0 融资、10 亿美元营收,数据标注领域真正的巨头,不认为合成数据是未来

          2025-12-23 22:16:26

          0 条回复 A文章作者 M管理员
            暂无讨论,说说你的看法吧
          个人中心
          购物车
          优惠劵
          今日签到
          有新私信 私信列表
          搜索