语义切片

核心原理一:为什么传统切片(Fixed-size Chunking)会失败?

传统的切法是按字符数硬切(比如每 300 个字一段,重叠 50 个字)。

  • 语义断裂: 假设你的日记写道:“我今天非常开心,因为…(此处切断)…我捡到了 100 块钱。”
  • 后果: 向量模型在检索时,第一段只有“开心”没原因,第二段只有“捡钱”没情绪。模型无法理解两者的因果关系。

核心原理二:语义切片(Semantic Chunking)的底层逻辑

语义切片不再看字数,而是看**“意思有没有变”**。它的工作流程如下:

  1. 句子拆分: 首先把你的长篇日记按标点符号(句号、感叹号)拆成一个个独立的句子。
  2. 向量化(Embedding): 利用模型(如 BGE-small)将每个句子转化成一个高维空间里的坐标。
  3. 相似度计算: 计算相邻两个句子之间的余弦相似度(Cosine Similarity)
    • 如果两句话离得很近,说明它们在聊同一个话题。
    • 如果距离突然拉远,说明你可能转场了(从聊“宠物”转到了聊“晚饭”)。
  4. 断点识别(Breakpoint Detection): 设定一个阈值(Threshold)。当相似度低于这个阈值时,系统就会在这里“切一刀”。

核心原理三:Embedding 模型(BGE 系列)

你在计划中看到的 BGE (Beijing Academy of Artificial Intelligence General Embedding) 是目前工业界的首选。

  • 什么是 Embedding? 它像是一本“翻译字典”,把自然语言翻译成数字向量。
  • 空间关系: 在这个高维空间里,“猫”和“狗”的距离很近,“猫”和“手机”的距离很远。
  • BGE 的优势: 针对中文优化极好,且模型尺寸小(Base/Small 版本),在你的 4060 显卡上运行几乎不占资源,推理速度极快。

核心原理四:RAG 系统的整体架构预习

虽然今天只做切片,但你要明白切片在整个 RAG (Retrieval-Augmented Generation) 链路中的位置:

  1. Data Ingestion(数据入库): 也就是你今天做的,解析 -> 切片 -> 向量化 -> 存入数据库。
  2. Retrieval(检索): 用户提问时,去库里找最相关的切片。
  3. Augmentation(增强): 把找回来的切片塞进 Prompt。
  4. Generation(生成): 模型根据 Prompt 回答问题。

代码实战

from langchain_experimental.text_splitter import SemanticChunker
from langchain_community.embeddings import HuggingFaceEmbeddings
import os
import warnings
warnings.filterwarnings('ignore')

# 模型本地存储路径
model_path = "./local_models/bge-small-zh-v1.5"

# 1. 加载 Embedding 模型 (首次会自动下载到本地,以后直接使用本地模型)
print("正在加载 Embedding 模型...")
if os.path.exists(model_path):
    print("使用本地模型...")
    embeddings = HuggingFaceEmbeddings(
        model_name=model_path,
        # model_kwargs={'device': 'cpu'} # 使用 CPU
        model_kwargs={'device': 'cuda'} # 使用 GPU
    )
else:
    print("首次运行,正在下载模型到本地...")
    # 确保本地目录存在
    os.makedirs(os.path.dirname(model_path), exist_ok=True)
    # 下载并保存模型到本地
    from sentence_transformers import SentenceTransformer
    model = SentenceTransformer("BAAI/bge-small-zh-v1.5")
    model.save(model_path)
    print("模型下载完成,使用本地模型...")
    embeddings = HuggingFaceEmbeddings(
        model_name=model_path,
        # model_kwargs={'device': 'cpu'} # 使用 CPU
        model_kwargs={'device': 'cuda'} # 使用 GPU
    )

# 2. 初始化语义切片器
# breakpoint_threshold_type="percentile" 意思是:
# 找出所有相邻句子相似度差距最大的前 5% 的地方作为切割点
text_splitter = SemanticChunker(
    embeddings, 
    breakpoint_threshold_type="percentile",
    breakpoint_threshold_amount=9
)

# 3. 读取 gbk 编码的文件并转换为 utf8
print("正在读取文件并转换编码...")
with open('data.txt', 'r', encoding='gbk', errors='ignore') as f:
    file_content = f.read()

# 4. 执行语义切片
print("正在进行语义计算与切片...\n")
docs = text_splitter.create_documents([file_content])

# 5. 查看结果
for i, doc in enumerate(docs):
    print(f"--- Chunk {i+1} ---")
    print(doc.page_content)
    print("------------------\n")

# 6. 统计切片数量
print(f"共生成 {len(docs)} 个语义切片")
Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐