觉得langchain的文本分割器种类与参数难以界定?自己动手编写文本分割函数!
编写Python脚本处理文本数据 #生活知识# #科技生活# #编程学习#
觉得langchain的文本分割器种类与参数难以界定?自己动手编写文本分割函数!
a.背景信息:将一个chatgpt所需的参考下文(文档问答+基础数据)进行文本分割参考下文的文档信息(节选)如下:
参考下文的基础数据信息(节选)如下:
首先,经过langchain的TokenTextSplitter分割器去分割,会造成的问题之一为,size的不均匀,有些块会过小。(即文本块的方差较大)且如果按照tokens计算的方式去划分的话造成问题:
一个问题的回答可能会被分成两部分,导致第二部分不匹配任何问题的答案,就会变为无关信息。因为我自己最终采用的策略是将最相关的4个文本块进行拼接作为下为提供给chatgpt,是按照最大的tokens走的,如果文本块的tokens过小,会使得chatgpt参考的上下文过少从而导致问题回答出现偏差。 b. 如何解决?为了解决以上问题,决定自己编写文本分割函数。
首先为一个计算tokens的函数:
import tiktoken def tokens_count(text:str): encoder=tiktoken.encoding_for_model("gpt-3.5-turbo") tokens=len(encoder.encode(text)) return tokens 12345
利用encoder=tiktoken.encoding_for_model得到大语言模型的编码器,使用它进行编码得到的是字符串序列转化为的tokens序列
token序列解释:
token序列为一个大列表其中列表的每个元素代表一个token,(一个token可能代表一个字符,也可能代表多个字符,也能多个token代表一个字符)
如果在切片解码过程中,多个token代表的一个字符被分开的话,会在末尾产生’�’字符。
from langchain.schema.document import Document def my_split(path, block_length, stop_list, overlap_range): with open(path, "r", encoding="utf-8") as f: text = f.readlines() text_str = str() for i in range(len(text)): text_str += text[i] encoder=tiktoken.encoding_for_model("gpt-3.5-turbo") encode_text_str=encoder.encode(text_str) blocks = [] start_idx = 0 remaining_tokens=tokens_count(text_str) remaining_str=copy(text_str) #文本分块 while remaining_tokens!=0: #print("dfd") if block_length >remaining_tokens: blocks.append(remaining_str) break temp_str=encoder.decode(encode_text_str[:block_length-overlap_range])[:-1] remaining_str=remaining_str[len(temp_str):] encode_text_str=encoder.encode(remaining_str) toprange_str=encoder.decode(encode_text_str[:overlap_range]) stop_idx = None for j in stop_list: for i in range(len(toprange_str) - 1, -1, -1): if toprange_str[i] == j: stop_idx = i break if stop_idx: temp_str+=toprange_str[:stop_idx+1] remaining_str=remaining_str[stop_idx+1:] encode_text_str=encoder.encode(remaining_str) blocks.append(temp_str) else: temp_str+=toprange_str remaining_str=remaining_str[len(toprange_str):] encode_text_str=encoder.encode(remaining_str) blocks.append(temp_str) remaining_tokens=tokens_count(remaining_str) #去掉标记并形成document对象 for i in range(len(blocks)): blocks[i] = blocks[i].replace('#', '') blocks[i] = Document(page_content=blocks[i], metadata={"source": path}) return blocks
12345678910111213141516171819202122232425262728293031323334353637383940414243444546 A. 标记:path: 为原始文本路径
block_length:一个文本块的最大tokens
stop_list: 优先级标记切分列表
overlap_range: block_length-overlap_range为一个文本块的最小tokens,即在**[block_length-overlap_range,block_length]**范围内按照标记优先级进行检索,找到最优切分点。
C. 运行流程: 1. 初始化首先读取文件得到文件字符串:text_str
之后设置
remaining_str作为剩余的字符串
encode_text_str作为tokens序列(为剩余字符串的)
remaining_tokens作为剩余tokens
2. 循环:条件: remaining_tokens!=0
一个循环内流程:
将encoder.decode(encode_text_str[:block_length-overlap_range])[:-1] 作为确定字符串(-1是为了取消’�’字符造成的影响)
toprange_str=encoder.decode(encode_text_str[:overlap_range]) 作为判断是否存在切分点的未确定字符串
for j in stop_list: for i in range(len(toprange_str) - 1, -1, -1): if toprange_str[i] == j: stop_idx = i break 12345
为了让tokens最接近最大tokens,使用倒序遍历字符串,找到最优先标记并返回索引
最终判断:
if stop_idx: temp_str+=toprange_str[:stop_idx+1] remaining_str=remaining_str[stop_idx+1:] encode_text_str=encoder.encode(remaining_str) blocks.append(temp_str) else: temp_str+=toprange_str remaining_str=remaining_str[len(toprange_str):] encode_text_str=encoder.encode(remaining_str) blocks.append(temp_str) remaining_tokens=tokens_count(remaining_str) 123456789101112
就是将不确定字符串与确定字符串进行拼接,并更新remaining_tokens,remaining_str,encode_text_str
c.最终结果: 我们由上图可以看出文本块的tokens数值方差较小且由于我们的优先级标记机制,每个文本块都是最完美或是接近切分的。
网址:觉得langchain的文本分割器种类与参数难以界定?自己动手编写文本分割函数! https://www.yuejiaxmz.com/news/view/261256
相关内容
使用 LangChain 的 RecursiveCharacterTextSplitter 进行代码分割txt文本分割器免费版
txt文本分割器app
txt文本分割器安卓版
txt文本分割器吾爱破解
【可能是全网最丝滑的LangChain教程】十四、LangChain进阶之Text Splitters
LangChain教程
大语言模型常见的文本切分方式整理汇总
哪里有免费音频分割软件?这五种免费音频分割器颇为实用
分割器怎么调角度