RAG的上下文断裂问题
2026/6/3 17:00:00 网站建设 项目流程

什么是“RAG的上下文断裂问题”?

举个典型的例子:

  • 文档 A 部分(第 3 页)“在系统处于‘开发环境’时,可以直接使用 root 密码登录,无需配置安全证书。”(前提:开发环境)

  • 文档 B 部分(第 80 页)“严禁在没有安全证书的情况下暴露端口,否则会导致严重的生产事故!”

如果用户提问:“可以不配置安全证书直接用 root 登录吗?”

ES 极有可能因为相似度计算,把 A 部分那句话(第 3 页)捞出来喂给大模型,而把第 80 页的警告漏掉。大模型看到 A 部分,就会自信地回答:“可以的,不需要配置安全证书”,这就导致了严重的乱回答(幻觉/误导)

说白了就是忽略了“前提”

哪些分片方式会导致这种问题?

第 1 梯队:高危区

如果你在项目中用了下面这两种方式,前面提到的“因为失去前提而导致 AI 乱回答”的问题是最严重、必现的

  • 固定大小分片 (Fixed-size Chunking)

    • 做法:死板地规定“每 300 个字切一刀”。

    • 断裂原因:它完全不看内容,哪怕刚好在一句“前提条件”的中间,它也会一刀切下去。

  • 递归字符分片 (Recursive Character Chunking)

    • 做法:LangChain4j 默认的recursive。它比固定大小聪明一点,会优先尝试按“换行符(\n)”或“句号()”来切,尽量保证句子的完整。

    • 断裂原因:虽然它保证了单句话的完整,但它没有结构感知能力。它根本不知道这一段话是不是属于上文那个“开发环境”标题下的内容。一旦字数攒够了,它就会无情地把前提留在上一个分片。

第 2 梯队:中危区

  • 语义分片 (Semantic Chunking)

    • 做法:让 Embedding 模型去计算相邻两个句子的相似度。如果发现第 5 句和第 6 句的语义突然发生了剧烈变化,就在这里切一刀。

    • 防范效果:它能完美保证“一个主题的事情在同一个分片里”。

    • 为什么还会断裂?它的局限性在于长距离依赖。比如第一段说了“以下操作针对 Linux 系统”,接着写了 2000 字的具体步骤(由于语义变化,这 2000 字会被切成 4 个语义片)。后面那 4 个分片由于离第一句太远,语义模型无法把“Linux”这个前提强行拉过来,导致后面分片的前提依然丢失。

第 3 梯队:安全区

如果你在项目中使用了下面这两种高级分片方式,你就基本不用担心上下文断裂的问题了:

  • 布局/结构感知分片 (Layout/Structure-Aware Chunking)

    • 做法:比如用MinerU 提取转 Markdown + LangChain4j 的MarkdownDocumentSplitter就不是按字数切,而是按文章的骨架(标题树)来切。

    • 为什么安全?这种分片方式允许你在切片时配置“回填属性”。框架在切开一小段文本时,会自动把它的各级父标题(包含所有环境、版本的前提)提取出来,拼在这段话的开头。

  • Document-Specific Chunking(特殊领域定制化分片)

    • 做法:针对表格、代码块、法律条款、简历等特殊格式,编写专门的解析器(RAGFlow)。

    • 为什么安全?比如一个长表格跨了三页,普通的切片会把表格行切碎。而定制化分片会强行把“表头(Column Header)”复制三份,拼在每一页被切碎的表格行前面。大模型无论拿到哪一段表格,都能看懂这一列数据代表什么,从而彻底杜绝了断章取义。

解决方法:

1. 标题/面包屑回填(Parent-Child / Chunk Context Enrichment)

这是最常用、性价比最高的工程手段。既然分片(Chunk)会丢失上下文,那我们在分片的时候,硬生生把它的“父亲”和“祖先”(标题路径)塞进文本里

  • 做法:在 MinerU 将 PDF 转成.md后,LangChain4j 拆分时,不要只切出那一段话,而是去解析它的 Markdown 标题树。

  • 效果:原本存入 ES 的文本只有一句孤零零的话,处理后变成:

[上下文前提:第一章-系统初始化 -> 1.2 环境搭建 -> 开发环境配置]在系统处于开发环境时,可以直接使用 root 密码登录,无需配置安全证书。

2. 父子文档块架构(Parent-Child Documents / Hierarchical Chunking)

不要让“检索粒度”和“喂给大模型的粒度”一样大。

  • 小分片(Child Chunk,用于检索):把文档切得很细(比如 100 字),只包含具体的细节,用来和用户的问题做极其精准的向量匹配。

  • 大分片(Parent Chunk,用于阅读):把整段话甚至整个章节(比如 2000 字,包含了所有的前置条件、背景说明)作为大分片。

  • ES 存储设计:在 ES 中,小分片里存一个字段叫parent_id,指向大分片。

运行逻辑

  1. 用户提问。
  2. ES 通过小分片的向量相似度,精准定位到了第 3 页的那句话。
  3. Java 后端拿到小分片后,不去拿它的文本,而是根据parent_id去 ES 里把那个包含了前因后果的2000 字大分片捞出来。
  4. 最终喂给大模型的是大分片。大模型读完上下几百字,自然就看到了那个“前提条件”。

3. 大模型摘要回填(Contextual Retrieval)

这是 Anthropic 提出的非常前沿且流行的一种做法。

  • 做法:在文件被 LangChain4j 切片之前,先把整篇长文档喂给一个便宜的大模型(或者利用长文本缓存),让大模型给每一个章节或者每一段话,自动生成一句一两百字的“背景大纲”。
  • 存储:把这个“背景大纲”拼到每一个细小分片的最前面,再进行向量化存入 ES。
  • 注意:确实效果炸裂,但如果文档有几万页,离线处理时对每个 Chunk 调大模型,Token 成本和耗时会非常高。
  • 降本秘籍:在实际落地时,强烈建议开启大模型长文本缓存(Prompt Caching)。把整篇长文档作为 Cache 挂在 LLM 内存里,然后滑动窗口让大模型批量生成 Chunk 摘要,这样可以降低 90% 的输入 Token 成本,速度提升好几倍。

4. 混合检索与重排(Hybrid Search + Rerank)—— 解决乱回答的终极护城河

有时候,哪怕你加了前提,向量检索还是可能因为“分值太接近”而把错误的答案排在最前面。这时候需要祭出两道杀手锏:

(1)混合检索(Hybrid Search)

在 ES 中同时使用向量检索(管语义)和关键字检索(管字面精准度)。如果用户提问里带了“生产环境”,关键字检索会强烈抗议,把带有“生产事故/生产环境”的 B 文档分数拉高。

补充:现在的 Elasticsearch 8.x+ 以及主流向量数据库,都已经原生支持了RRF(倒数排名融合)算法。在 Java 端(无论是用 Spring AI 还是 LangChain4j),你不需要自己去写复杂的归一化算法,直接在 ES 的查询请求中声明一个retriever,把knn(向量)和standard(BM25文本)组合在一起,ES 会在底层自动做 RRF 融合并返回最终的 Top K。

(2)重排模型(Reranker,如 BGE-Reranker)

第一步:用 ES 粗暴地通过向量相似度捞出最有可能的 Top 10 个分片(这时候可能包含那个没有前提的错误答案)。

第二步:把这 10 个分片和用户的问题一起丢给Rerank 模型。Rerank 模型极其聪明,它不看向量,而是像班主任批改作文一样,逐字逐句分析这 10 个分片里到底哪个和问题存在逻辑上的因果/前提关系

经过重排,那个真正安全的、带有限制条件的正确答案会被硬生生提到 Top 1。

是什么原因导致的这个问题?

这种“前提丢失”的现象,用大白话解释就是“断章取义”。

  • 向量化存储是无辜的:向量化模型的唯一工作,是把你给它的那一小段文本翻译成数学坐标。你给它一句“无需配置安全证书”,它就尽职尽责地把这句话定格在“不用证书”的数学坐标上。它没有前后眼,看不到第 3 页的大标题。

  • 真正的罪魁祸首是:硬性分片: 我们为了让大模型读得下、让 ES 算得快,强行用长宽、Token 数(比如每 500 字切一刀)把一篇完整的文章“乱刀砍碎”。这一刀下去,往往把“前提背景”和“核心结论”一刀两断,分到了不同的切片里。

所以,这是一种RAG 架构与生俱来的技术隐患。只要你切片,就必然面临上下文断裂的风险。

方案落地:

第一关:数据准备阶段(分片时——治本)

这是最容易掌控,也是效果最好的地方。

  • 技术手段:智能分片 + 上下文回填。

  • 怎么做:不要使用纯文本的recursive(按字数盲切),而是要使用Markdown 分片器(LangChain4j 里的MarkdownDocumentSplitter)。它在切片时会感知###标题。

  • 方案:在把切片丢给openAiEmbeddingModel.embedAll()之前,写一段 Java 逻辑,遍历List<TextSegment>,把当前的各级标题(或者上一段的背景)作为前缀,拼接到text字段的最前面。尽管引入前缀看似会带来微小的空间“噪声”,但现在的通用 Embedding 模型对这种带结构的前缀处理能力已经非常强。比起“因缺乏上下文而完全检索不到”,让向量具备上下文感知能力要重要得多

第二关:检索阶段(问 ES 时——治标)

如果数据已经存进去了,或者分片时没做好,我们可以在用户提问、去 ES 查数据的时候补救。

  • 技术手段:查询重写(Query Rewriting)或扩大召回。

  • 怎么做

当用户问:“可以不配证书直接登录吗?”

你不要直接拿这句话去查 ES。先让一个响应极快的小模型把问题改写一下:“请分析这句话背后可能的系统环境和前提条件,并生成新的检索词。”

小模型可能会帮你生成:“Spring Boot 登录、开发环境安全证书、生产环境安全证书”。

你拿着这多组关键词去 ES 里查,ES 就会把第 3 页和第 80 页的内容同时捞出来,把“正确的前提”一并带给大模型。

  • 弊端:小模型重写查询确实好,但高并发下会增加响应延时

    建议:在 Java 端做多线程并行查 ES,或者使用 ES 的Multi-Match,把小模型生成的关键词合并成一个复杂的布尔查询一次性丢给 ES,效率更高。

第三关:生成阶段(喂给大模型前——兜底)

这是数据从 ES 出来,准备组装给大模型(LLM)的最后一步。

  • 技术手段:重排(Rerank)与 Prompt 限制。

  • 怎么做

    • Rerank:从 ES 捞出 Top 5 之后,用 Java 调用一个 Rerank 接口(如 BGE-Reranker)。重排模型会强行检查,eg:“这 5 段话里,有没有哪段话包含了后面几段话的前提限制?”,会把带限制条件的段落排到最前面。

    • Prompt 严厉警告:在给大模型的系统提示词里加上死命令:

eg: “你是一个极其严谨的系统运维专家。在回答用户问题时,必须严格检查参考资料中是否存在‘环境(开发/生产)’、‘版本’等前置条件限制。如果资料中提及某种操作仅限特定环境,你必须在回答中首要说明,绝不能混淆!”

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询