Agent开发实战-语义切片
·
语义切片
核心原理一:为什么传统切片(Fixed-size Chunking)会失败?
传统的切法是按字符数硬切(比如每 300 个字一段,重叠 50 个字)。
- 语义断裂: 假设你的日记写道:“我今天非常开心,因为…(此处切断)…我捡到了 100 块钱。”
- 后果: 向量模型在检索时,第一段只有“开心”没原因,第二段只有“捡钱”没情绪。模型无法理解两者的因果关系。
核心原理二:语义切片(Semantic Chunking)的底层逻辑
语义切片不再看字数,而是看**“意思有没有变”**。它的工作流程如下:
- 句子拆分: 首先把你的长篇日记按标点符号(句号、感叹号)拆成一个个独立的句子。
- 向量化(Embedding): 利用模型(如 BGE-small)将每个句子转化成一个高维空间里的坐标。
- 相似度计算: 计算相邻两个句子之间的余弦相似度(Cosine Similarity)。
- 如果两句话离得很近,说明它们在聊同一个话题。
- 如果距离突然拉远,说明你可能转场了(从聊“宠物”转到了聊“晚饭”)。
- 断点识别(Breakpoint Detection): 设定一个阈值(Threshold)。当相似度低于这个阈值时,系统就会在这里“切一刀”。
核心原理三:Embedding 模型(BGE 系列)
你在计划中看到的 BGE (Beijing Academy of Artificial Intelligence General Embedding) 是目前工业界的首选。
- 什么是 Embedding? 它像是一本“翻译字典”,把自然语言翻译成数字向量。
- 空间关系: 在这个高维空间里,“猫”和“狗”的距离很近,“猫”和“手机”的距离很远。
- BGE 的优势: 针对中文优化极好,且模型尺寸小(Base/Small 版本),在你的 4060 显卡上运行几乎不占资源,推理速度极快。
核心原理四:RAG 系统的整体架构预习
虽然今天只做切片,但你要明白切片在整个 RAG (Retrieval-Augmented Generation) 链路中的位置:
- Data Ingestion(数据入库): 也就是你今天做的,解析 -> 切片 -> 向量化 -> 存入数据库。
- Retrieval(检索): 用户提问时,去库里找最相关的切片。
- Augmentation(增强): 把找回来的切片塞进 Prompt。
- 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)} 个语义切片")
更多推荐


所有评论(0)