当前位置: 首页 > 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.lryc.cn/news/608613.html

相关文章:

  • cursor 使用方法
  • CVE-2025-5947 漏洞场景剖析
  • Claude Code氛围编程经历: 6周干了三年的活
  • vscode的Remote-SSH插件配置SSH主机方法
  • python工具方法51 视频数据的扩充(翻转、resize、crop、re_fps)
  • N1——one-hot编码
  • ABAP SQL更新DB小技巧 WITH INDICATORS
  • [硬件电路-151]:数字电路 - 模拟电路与数字电路的本质
  • MySQL Redo Log
  • GitLab 代码管理平台部署及使用
  • lua中 list.last = last 和list[last]=value区别
  • JavaScript:编程世界中的“语盲”现象
  • 回归的wry
  • 关于vllm【常见问题解决方案】
  • vllm0.8.5:自定义聊天模板qwen_nonthinking.jinja,从根本上避免模型输出<think>标签
  • 【python实用小脚本-169】『Python』所见即所得 Markdown 编辑器:写完即出网页预览——告别“写完→保存→刷新”三连
  • k8s+isulad 国产化技术栈云原生技术栈搭建1-VPC
  • OSPF HCIP
  • Starrocks ShortCircuit短路径的调度
  • 华为云云服务高级顾问叶正晖:华为对多模态大模型的思考与实践
  • 基于云模型的模糊综合风险评估Matlab代码
  • Matlab 高斯牛顿法拟合曲线
  • K8S部署ELK(四):部署logstash
  • MATLAB小波分析工具包进行时间序列的小波功率谱分析
  • 后端研发转型爬虫实战:Scrapy 二开爬虫框架的避坑指南
  • 量子物理学的前沿意义虚无、形式混乱
  • 0803 思维导图+小项目
  • Python爬虫实战:研究awesome-python工具,构建技术资源采集系统
  • uniapp 跨端开发
  • 机器学习——下采样(UnderSampling),解决类别不平衡问题,案例:逻辑回归 信用卡欺诈检测