FEATURED · 精选文章

RAG 文档更新后答非所问:沿 Trace 排查切块、版本与召回分数

发布时间 / 2026/8/16 9:37:48
来源 / 创域科博编辑部
栏目 / 资讯中心
RAG 文档更新后答非所问:沿 Trace 排查切块、版本与召回分数 RAG 文档更新后答非所问沿 Trace 排查切块、版本与召回分数知识库更新后出现新旧规则混答先沿一次 Request ID 查看文档版本、Chunk 边界、召回列表与 Rerank 分数。没有这条 Trace直接重建索引或换模型都只是猜。切块破坏表格、旧版本未下线、过滤条件缺失和重排退化都会造成相似现象。排查时一次验证一个假设并用固定问题集做回归。1. 用可复现输入还原召回偏差在该 RAG 架构中文档经过 Chunk 拆分通过 Embedding 模型转为向量存入 VectorDB检索阶段先进行 ANN 近邻搜索取 Top 20 交付 Reranker 排序最后挑选前 3 个片段拼接成 Prompt 提交给大模型。准备一份同时包含表格、多层标题和新旧版本条款的脱敏文档再用固定问题触发检索。记录格式可以像下面这样ID、得分和文本都由本次测试产生# 测试 Trace 字段 [DEBUG] [RAG_Query] ReqIDrequest_id querytest_question doc_versionversion [DEBUG] [Vector_Search] Rank1 Scorescore_1 ChunkIDchunk_id_1 content_hashhash_1 [DEBUG] [Vector_Search] Rank2 Scorescore_2 ChunkIDchunk_id_2 content_hashhash_2 [INFO] [LLM_Generate] cited_chunkschunk_ids answer_checkpass_or_fail检查每个被引用的 Chunk它是否保留表头和上层标题metadata 是否含文档版本过滤条件是否排除了旧版本。固定长度切分可能把表格从中间断开但不能只凭一条错误回答就认定根因还要对照原文、召回列表和版本过滤结果。2. 基于 OpenTelemetry Trace 证据链的故障定位为查明切块与召回异常的根因沿着可观测性追踪系统OpenTelemetry Trace构建故障定位证据链。从原始 Markdown 文件导入到 VectorDB 向量存储再到 LLM 生成链路中的诊断节点分布如下根据证据链分析工程链路中存在两个关键缺口解析切块缺口缺乏针对 Markdown 结构标题、表格、代码块的语义感知切块Semantic Chunking导致关键语境丢失在切块边界之外。检索闸门缺口缺乏检索得分的安全底线Score Threshold。即使 Top 1 的 Rerank 相似度较低系统仍将低质片段拼入 Prompt 提交给 LLM导致大模型在依据不足时产生幻觉。3. 感知结构的语义切块与动态 Score 闸门实现基于上述分析在工程层引入基于 AST 的 Markdown 结构化切块器并在检索层增加带有降级回退机制的动态 Score 闸门。以下是修复后的 Python 实现代码import re from typing import List, Dict, Any, Optional from dataclasses import dataclass dataclass class DocumentChunk: chunk_id: str content: str metadata: Dict[str, Any] vector: Optional[List[float]] None class SemanticMarkdownSplitter: 感知 Markdown 结构的语义切块器保护标题上下文与表格完整性 def __init__(self, max_chunk_size: int 800, overlap: int 100): self.max_chunk_size max_chunk_size self.overlap overlap def split_markdown(self, text: str, doc_id: str) - List[DocumentChunk]: chunks: List[DocumentChunk] [] lines text.split(\n) current_headers [] current_block [] current_length 0 table_mode False for line in lines: # 捕获 Markdown 标题层级构建上下文面包屑 header_match re.match(r^(#{1,6})\s(.), line) if header_match: level len(header_match.group(1)) title header_match.group(2).strip() # 更新当前标题面包屑链 current_headers current_headers[:level-1] current_headers.append(title) # 判定表格边界严禁在表格中途发生切块 if line.strip().startswith(|): table_mode True else: table_mode False line_len len(line) # 超出限制且不在表格内部时触发分块 if current_length line_len self.max_chunk_size and not table_mode and current_block: breadcrumb .join(current_headers) chunk_text f【文档路径: {breadcrumb}】\n \n.join(current_block) chunks.append(DocumentChunk( chunk_idf{doc_id}_chk_{len(chunks)}, contentchunk_text, metadata{headers: list(current_headers), doc_id: doc_id} )) # 保留 overlap 重叠行维持连贯性 current_block current_block[-2:] if len(current_block) 2 else [] current_length sum(len(l) for l in current_block) current_block.append(line) current_length line_len if current_block: breadcrumb .join(current_headers) chunk_text f【文档路径: {breadcrumb}】\n \n.join(current_block) chunks.append(DocumentChunk( chunk_idf{doc_id}_chk_{len(chunks)}, contentchunk_text, metadata{headers: list(current_headers), doc_id: doc_id} )) return chunks class GuardedRAGRetriever: 带得分闸门与降级策略的 RAG 检索器 def __init__(self, vector_store, reranker_client, min_score_threshold: float): self.vector_store vector_store self.reranker reranker_client self.min_score_threshold min_score_threshold def retrieve_with_fallback(self, query: str) - Dict[str, Any]: # 1. 初筛 raw_candidates self.vector_store.similarity_search(query, top_k20) if not raw_candidates: return {status: FALLBACK, context: , reason: 向量库召回为空} # 2. Rerank 重排序 ranked_results self.reranker.rerank(queryquery, documents[c.content for c in raw_candidates]) # 3. 执行阈值过滤闸门 valid_chunks [ doc for doc, score in ranked_results if score self.min_score_threshold ] if not valid_chunks: # 当所有片段得分都很低时拒绝强行回答防止大模型产生幻觉 return { status: FALLBACK, context: , reason: f最高召回得分低于安全阈值 ({self.min_score_threshold}) } final_context \n---\n.join(valid_chunks[:3]) return {status: SUCCESS, context: final_context, reason: 正常召回}工程落地的核心在于给 Chunk 携带标题路径、文档版本和内容哈希并让表格保持完整。min_score_threshold不提供通用默认值在标注问题集上扫描候选阈值同时查看正确召回和错误接受再按业务对误答与拒答的成本取值。没有达到阈值时进入降级路径也仍要监控错误拒答。4. 回归验证与对比数据分析在测试环境加载含表格与多级标题的脱敏文档使用固定回归问题集验证问题数量以覆盖主要文档类型为准避免把真实历史提问直接复制进测试材料。对比数据如下指标采集来源要回答的问题RecallK 与表格类召回标注问题集、召回列表结构切块是否找到了正确 Chunk错误引用与拒答答案引用、人工标注得分闸门是否减少误答又增加了多少错误拒答Rerank 分数分布重排器原始输出阈值是否适用于当前模型和文档类型文档版本命中Chunk metadata、索引版本旧版本是否仍被召回按文档类型分别填写 RecallK、拒答准确率、错误引用率和降级比例。得分闸门是否有效要与无闸门基线在同一问题集上比较不能用一组未给来源的百分比替代回归结果。5. RAG 系统工程治理规则总结这类问题可以留下三条检查规则按文档结构选择切块方式针对 Markdown、PDF、HTML 等格式测试结构感知切块并核对标题面包屑与表格是否完整短纯文本不必为了统一而强行走复杂解析。用标注集选择 Rerank 阈值比较候选阈值下的正确召回、错误接受与拒答不把某个得分当成跨模型通用的安全线。在 Trace 中记录可追溯摘要与 Score关联 Request ID、文档版本、Chunk ID、得分和内容哈希正文只在受控调试流程中按权限查看避免把知识库内容写入普通日志。把版本、Chunk、得分和引用答案串到同一条 Trace 后才有条件判断问题出在解析、检索、重排还是生成阶段。
RELATED — 相关阅读

相关资讯

LATEST — 最新资讯

最新发布

TODAY — 本日精选

新闻

WEEKLY — 本周精选

新闻

MONTHLY — 本月精选

新闻