当前位置: 首页 > news >正文

RAG-Semantic Chunking

Semantic Chunking(语义分块)实现详解

Semantic Chunking介绍

  • Semantic Chunking(语义分块)是一种高级文本处理技术,通过分析文本的语义连贯性来智能地将长文本分割成有意义的语义单元。与传统的固定长度分块方法不同,语义分块能够识别自然的语义边界,保持上下文的完整性,从而提高检索增强生成(RAG)系统的性能。

    该技术通过计算相邻句子之间的语义相似度,识别语义断点,在语义变化显著的位置进行分割,确保每个文本块都包含完整且相关的信息。这种方法能够有效减少信息碎片化,提高检索精度,进而增强大语言模型生成回答的质量和连贯性。

技术原理

  • Semantic Chunking的工作流程主要包括以下几个关键步骤:

    1. 文本预处理:将文档转换为纯文本并分割成句子
    2. 句子向量化:为每个句子生成嵌入向量表示
    3. 相似度计算:计算相邻句子之间的语义相似度
    4. 断点识别:基于相似度变化识别语义断点
    5. 语义分块:根据断点将句子组合成语义连贯的文本块
    6. 块向量化:为生成的语义块创建嵌入向量
    7. 语义检索:基于用户查询检索最相关的语义块

代码实现

  • Semantic Chunking的核心组件实现

    def get_embedding(text):"""为文本生成嵌入向量"""response = client.embeddings.create(model=semantic_chunking_config.embedding_model_id,input=text)embedding_data = np.array(response.data[0].embedding)return embedding_datadef cosine_similarity(vec1, vec2):"""计算两个向量之间的余弦相似度"""return np.dot(vec1, vec2) / (np.linalg.norm(vec1) * np.linalg.norm(vec2))def compute_breakpoints(similarities, method="percentile", threshold=90):"""根据相似度下降计算分块的断点"""# 根据选定的方法确定阈值if method == "percentile":# 计算相似度分数的第 X 百分位数threshold_value = np.percentile(similarities, threshold)elif method == "standard_deviation":# 计算相似度分数的均值和标准差mean = np.mean(similarities)std_dev = np.std(similarities)# 将阈值设置为均值减去 X 倍的标准差threshold_value = mean - (threshold * std_dev)elif method == "interquartile":# 计算第一和第三四分位数(Q1 和 Q3)q1, q3 = np.percentile(similarities, [25, 75])iqr = q3 - q1  # iqr为四分位全距# 使用 IQR 设置阈值threshold_value = q1 - 1.5 * iqr  # 这个是箱线图的下线else:# 如果提供了无效的方法,则抛出异常raise ValueError("Invalid method. Choose 'percentile', 'standard_deviation', or 'interquartile'.")# 找出相似度低于阈值的索引return [i for i, sim in enumerate(similarities) if sim < threshold_value]def split_into_chunks(sentences, breakpoints):"""将句子分割为语义块"""chunks = []  # 初始化空列表存储文本块start = 0  # 初始化起始索引# 遍历每个断点以创建块for bp in breakpoints:# 将从起始位置到当前断点的句子块追加到列表中chunks.append("。".join(sentences[start:bp + 1]) + "。")start = bp + 1  # 将起始索引更新为断点后的下一个句子# 将剩余的句子作为最后一个块追加chunks.append("。".join(sentences[start:]))return chunks
    
  • 配置管理与参数设置

    class Config(BaseModel):"""配置类,集中管理所有配置参数"""llm_base_url: str = os.getenv("LLM_BASE_URL")llm_api_key: str = os.getenv("LLM_API_KEY")embedding_model_id: str = os.getenv("EMBEDDING_MODEL_ID")llm_model_id: str = os.getenv("LLM_MODEL_ID")chunk_size: int = 500chunk_overlap: int = 100top_k: int = 2temperature: float = 0.1top_p: float = 0.8presence_penalty: float = 1.05max_tokens: int = 4096
    

断点识别算法

  • Semantic Chunking实现了三种断点识别算法:

    算法描述适用场景
    百分位法将相似度低于特定百分位数的点识别为断点适用于相似度分布较为均匀的文本
    标准差法将相似度低于均值减去X倍标准差的点识别为断点适用于相似度分布接近正态分布的文本
    四分位距法使用箱线图下界识别异常低的相似度点作为断点适用于相似度分布存在明显异常值的文本

工作流程详解

  • Semantic Chunking的完整工作流程可以分为以下几个阶段:

    阶段操作功能描述
    1文档加载从PDF文件中提取文本内容
    2句子分割将文本按句号分割成句子列表
    3句子向量化为每个句子生成嵌入向量表示
    4相似度计算计算相邻句子之间的余弦相似度
    5断点识别使用选定算法识别语义断点
    6语义分块根据断点将句子组合成语义连贯的文本块
    7块向量化为生成的语义块创建嵌入向量
    8查询处理接收用户查询并转换为向量表示
    9语义检索检索与查询最相关的语义块
    10上下文构建将检索到的语义块组织成结构化上下文
    11回答生成使用大语言模型基于上下文生成回答

语义检索实现

  • Semantic Chunking中的语义检索实现:

    def semantic_search(query, text_chunks, chunk_embeddings, k=5):"""查询找到最相关的文本块"""# 为查询生成嵌入query_embedding = get_embedding(query)# 计算查询嵌入与每个块嵌入之间的余弦相似度similarities = [cosine_similarity(query_embedding, emb) for emb in chunk_embeddings]# 获取最相似的 k 个块的索引top_indices = np.argsort(similarities)[-k:][::-1]# 返回最相关的 k 个文本块return [text_chunks[i] for i in top_indices]
    

使用示例

  • 完整使用流程示例

    if __name__ == "__main__":# 加载PDF文档pdf_path = 'data/AI_Information.en.zh-CN.pdf'extracted_text = extract_text_from_pdf(pdf_path=pdf_path)# 每个句子以中文 "。" 结尾,创建句子级别的embeddingsentences = extracted_text.split("。")sentences = [sentence for sentence in sentences if sentence]sentence_embeddings = [get_embedding(sentence) for sentence in sentences]logger.info(f"共生成了 {len(sentence_embeddings)} 个句子embedding.")# 计算相似度similarities = [cosine_similarity(sentence_embeddings[i], sentence_embeddings[i + 1]) for i in range(len(sentence_embeddings) - 1)]# 计算分块的断点(这里使用百分位法)breakpoints = compute_breakpoints(similarities, method="percentile", threshold=90)logger.info(f"共生成了 {len(breakpoints)} 个断点.")# 将文本基于断点分割成语义块text_chunks = split_into_chunks(sentences, breakpoints)logger.info(f"共生成了 {len(text_chunks)} 个文本块.")# 创建语义块的嵌入向量chunk_embeddings = [get_embedding(chunk) for chunk in text_chunks]# 评估查询性能with open('data/val.json', encoding="utf-8") as f:val_data = json.load(f)# 批量评估evaluation_scores = []for entry in val_data:query = entry['question']reference_answer = entry['ideal_answer']ai_response, evaluation_score = evaluate_response(query=query,reference_answer=reference_answer,text_chunks=text_chunks,chunk_embeddings=chunk_embeddings)evaluation_scores.append((query, reference_answer, ai_response, float(evaluation_score)))# 计算平均分df = pd.DataFrame(evaluation_scores, columns=['query', 'reference_answer', 'ai_response', 'evaluation_score'])logger.info(f'平均分:{df['evaluation_score'].mean()}')  # 平均分:0.62
    

与传统分块方法的比较

  • Semantic Chunking与传统固定长度分块的对比:

    特性传统固定长度分块语义分块
    分块依据字符数或token数语义连贯性
    上下文完整性可能在句子中间截断保持语义单元完整
    块长度均匀一致不等长,根据语义变化
    信息密度可能包含不相关信息语义相关性高
    实现复杂度简单较复杂
    计算开销中等(需要计算嵌入和相似度)
    检索效果一般更好

性能优化建议

  • 基于Semantic Chunking的实现,以下是一些可能的优化方向:

    1. 多级分块:结合段落级和句子级分块,形成层次化的分块结构
    2. 自适应阈值:根据文档特性动态调整断点识别的阈值
    3. 并行处理:对句子嵌入生成和相似度计算进行并行化处理
    4. 缓存机制:缓存常用句子和块的嵌入向量,减少重复计算
    5. 混合断点算法:结合多种断点识别算法的优势,提高断点识别的准确性
    6. 语义增强:在分块过程中保留关键词和实体信息,增强语义表示

总结

  • Semantic Chunking作为一种高级文本处理技术,通过识别自然的语义边界,将长文本分割成语义连贯的文本块,有效提高了检索增强生成系统的性能。与传统的固定长度分块相比,语义分块能够更好地保持上下文的完整性,减少信息碎片化,提高检索精度。

    实验结果显示,基于语义分块的RAG系统在测试集上获得了0.62的平均评分,与传统分块方法相当,但在处理复杂查询和需要深度语义理解的场景中,语义分块展现出更大的优势。随着断点识别算法的进一步优化,语义分块技术有望在RAG系统中发挥更重要的作用。

http://www.xdnf.cn/news/1236205.html

相关文章:

  • 一加Ace5无法连接ColorOS助手解决(安卓设备ADB模式无法连接)
  • 迈向透明人工智能: 可解释性大语言模型研究综述
  • JavaScript 性能优化实战指南:从运行时到用户体验的全面提升​
  • LangGraph认知篇-Persistence 持久化
  • 嵌入式学习日志——数据结构(一)
  • Supergateway教程
  • 使用DrissionPage实现xhs笔记自动翻页并爬取笔记视频、图片
  • Day22--回溯--77. 组合,216. 组合总和 III,17. 电话号码的字母组合
  • Kafka 是什么?
  • 《汇编语言:基于X86处理器》第11章 MS-Windows编程(3)
  • 【stm32】按键控制LED以及光敏传感器控制蜂鸣器
  • OSPF知识点整理
  • 实战《从0开始使用SwiftUI搭建记账软件》- 2、SwiftUI 知识点详解与使用场景
  • 6.1、Redis多级缓存原理和优化、Redis部分参数优化调整
  • 【超分辨率专题】PiSA-SR:单步Diff超分新突破,即快又好,还能在线调参
  • Linux 摄像头实时抓取:V4L2、FFmpeg 与 GStreamer 全面讲解
  • python工具方法51 视频数据的扩充(翻转、resize、crop、re_fps)
  • Transformer模型用于MT信号相关性预测与分析
  • 《深入浅出RabbitMQ:从零基础到面试通关》
  • 渗透作业4
  • wordpress登陆前登陆后显示不同的顶部菜单
  • 数据结构代码
  • 08.Redis 持久化
  • AOP动态代理
  • #C语言——刷题攻略:牛客编程入门训练(四):运算
  • 大屏项目展示
  • 面向智能体的上下文工程:策略、实现与 LangGraph 实践
  • 09.Redis 常用命令
  • STM32-ESP8266通过MQTT与阿里云通讯
  • Coze 打通飞书多维表格,实现数据增删改查操作实战详解