☰
基于 FastAPI + Qdrant 构建可解释、可约束的教育 Agent(三):知识清洗与结构感知切片
2026/10/10 3:27:25 网站建设 项目流程

基于 FastAPI + Qdrant 构建可解释、可约束的教育 Agent(三):知识清洗与结构感知切片

本文内容:系列第三篇,承接文档解析,介绍 RAG 入库前的两个环节——知识清洗与结构感知切片。清洗阶段逐行剔除重复、样板、纯链接与孤立符号,并以可复算的启发式规则计算质量分;切片阶段按块类型区别处理,标题不单独成块,表格与图片整块保留,正文按句子边界切分并保留重叠。

技术栈:Python 3.11、正则规则、结构化 dataclass;默认参数 target_size=1100、hard_max=1800、overlap=160。

文章目录

  • 基于 FastAPI + Qdrant 构建可解释、可约束的教育 Agent(三):知识清洗与结构感知切片
    • 1. 清洗与切片在 RAG 中的位置
    • 2. 知识清洗管线
    • 3. 质量分计算
    • 4. 结构感知切片
    • 5. 正文切分与 overlap
    • 6. 参数与工程处理
    • 7. 系列规划
    • 结语

1. 清洗与切片在 RAG 中的位置

文档解析产出结构化的 ParsedBlock 后,若直接按固定长度切分入库,会引入两类问题:

  • 解析结果中仍包含每页重复的页眉、版权声明、纯页码、乱码符号等低信息内容;
  • 固定长度切分会在句子中间、表格内部断开,破坏语义与表格结构。

项目将处理顺序固定为:解析 → 清洗(过滤 + 质量打分)→ 结构感知切片。在切块前剔除脏内容、在完整块上计算质量分,成本与准确性都更优。

2. 知识清洗管线

KnowledgeCleaningService.clean逐块、逐行处理,整体管线如下:

逐行过滤规则包括:

  • 重复行:长度在 4–80 之间、全篇出现不少于 3 次的行;
  • 样板行:页码、纯数字、分隔线、版权声明、机密标识等;
  • 纯链接行:整行匹配http(s)://;
  • 孤立符号:长度 ≤2 且不含中英文。

样板行通过预编译正则匹配:

BOILERPLATE_RE=re.compile(r"^(?:第\s*\d+\s*页|page\s*\d+|\d+|[-–—]+|课程资料\s*版权所有|版权所有|copyright|confidential|机密)$",re.I,)

逐行过滤实现:

def_clean_block_text(self,text,repeated):lines=[]forrawinstr(textor"").splitlines():line=_normalize_text(raw)ifnotline:continueiflineinrepeated:continueifself.BOILERPLATE_RE.match(line):continueifre.fullmatch(r"https?://\S+",line,re.I):continueiflen(line)<=2andnotre.search(r"[\u4e00-\u9fffA-Za-z]",line):continuelines.append(line)return_normalize_text("\n".join(lines))

重复行统计限定长度 4–80,避免短词在正常内容中重复出现被误删:

def_repeated_lines(self,blocks):counts=defaultdict(int)forblockinblocks:forrawinblock.text.splitlines():line=_normalize_text(raw)if4<=len(line)<=80:counts[line]+=1return{lineforline,countincounts.items()ifcount>=3}

3. 质量分计算

质量分不使用模型,而采用可复算的启发式规则,定义在knowledge_quality.py:

defscore_knowledge_text(text,block_type="text"):content=str(textor"").strip()ifnotcontent:return0.0ifblock_typein{"heading","table","visual_summary"}:return0.9signal=len(re.findall(r"[\u4e00-\u9fffA-Za-z0-9]",content))noise=len(re.findall(r"�|□|■|▯|[^\s\u4e00-\u9fffA-Za-z0-9,。;:、,.!?;:()()\[\]\-+*/|#]",content))density=signal/max(1,len(content))length_score=min(1.0,signal/80)noise_penalty=min(0.6,noise/max(1,len(content)))returnround(max(0.0,density*0.55+length_score*0.45-noise_penalty),3)

清洗时,文本为空或质量分低于 0.2 的块被丢弃并计入 low_quality;保留块将分数写入 metadata。文档质量分取保留块分数的均值,报告记录 total_blocks、kept_blocks、dropped_blocks、low_quality_blocks。

4. 结构感知切片

StructureAwareChunker.chunk按块类型区别处理:

关键规则:

  • heading 块跳过,不单独成块,标题信息通过 section_path 保留;
  • block_type 归一为 table、image(含 image、visual_summary)、text;
  • table / image 在长度不超过 hard_max 时整块保留,避免 Markdown 表格被切断;
  • text 块进入句子级切分;
  • 检索文本由章节路径与正文拼接,补充上下文。
forblockindoc.blocks:block_quality=float(block.metadata.get("quality_score",doc.quality_scoreor0.6))ifblock.block_typein{"heading"}:continueblock_type="table"ifblock.block_type=="table"else"image"ifblock.block_typein{"image","visual_summary"}else"text"texts=[block.text]ifblock_typein{"table","image"}andlen(block.text)<=self.hard_maxelseself._split_block(block.text)forpartintexts:section=block.section_pathorchapterordoc.document_name retrieval_text=_normalize_text("\n".join([section,part]))# 组装 StructuredChunk 与 metadata

每个 chunk 的 metadata 包含 document_id、chunk_id、chapter、section_path、chunk_index、chunk_type、quality_score、page、file_type、resource_type、retrieval_text,用于引用溯源、类型过滤与质量降权。

5. 正文切分与 overlap

正文块先按句末标点或换行切出句子单元,再贪心装箱:

def_split_block(self,text):units=re.split(r"(?<=[。!?;.!?])\s*|\n+",_normalize_text(text))units=[u.strip()foruinunitsifu.strip()]ifnotunits:units=[text]chunks,buf=[],""forunitinunits:iflen(buf)+len(unit)<=self.target_size:buf=f"{buf}\n{unit}".strip()ifbufelseunitcontinueifbuf:chunks.append(buf)prefix=buf[-self.overlap:]ifself.overlapandbufelse""buf=f"{prefix}\n{unit}".strip()ifprefixelseunitwhilelen(buf)>self.hard_max:chunks.append(buf[:self.hard_max])buf=buf[self.hard_max-self.overlap:]ifself.overlap<self.hard_maxelsebuf[self.hard_max:]ifbuf:chunks.append(buf)returnchunks

相邻块保留 overlap,避免完整答案横跨切块边界时无法被完整召回;hard_max 用于处理缺少标点的超长文本。

6. 参数与工程处理

默认切片参数如下:

参数默认值含义
target_size1100单块目标长度
hard_max1800单块硬上限
overlap160相邻块重叠长度

工程处理要点:

  • 清洗先于切片,避免脏内容在切块后扩散;
  • 质量分规则确定、可复算,不引入额外推理依赖;
  • 表格与图片整块保留,正文只在句子边界断开;
  • 章节路径前置到检索文本,提升短文本与表格行的召回语义。

7. 系列规划

知识工程部分后续将介绍查询分析与多路召回、多路结果融合、精排与动态 TopK、证据包构建。下一篇聚焦查询分析与多路召回。

结语

本文给出了知识清洗与结构感知切片的实现思路,核心是在入库前去除低信息内容、保留文档结构,并让每个 chunk 携带足够的上下文与元数据。相关实现仍在持续迭代,欢迎在评论区讨论改进方案。

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

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

立即咨询