Skip to content

LV020-文档处理

想让 AI 真正“懂”我们的知识?关键在于如何把杂乱无章的文档变成结构化、可检索的智能资产。

让模型 "读懂" 海量文本的关键在于将非结构化文档转化为易于检索的向量形式。具体流程通常包括:文档分片向量化索引构建 三个步骤。

一、文档分片(Chunking)

首先将长文档切分为较小的段落或片段,以适应模型上下文窗口限制。常见的分片策略是按固定字数或句子数切分,并在片段间引入重叠(overlap)以保留上下文连贯。例如,可将每篇博客按段落拆分成长度约 500 字的片段并保留前一片段的末句作为重叠。分片的目的在于减少每个输入片段的 "噪音",突出相关信息,并确保后续 embedding 过程能捕捉局部语义。

下面是一个 Python 示例:

python
# -*- coding: utf-8 -*-
# 假设 texts 列表包含若干长文档字符串
texts = ["""
人工智能(Artificial Intelligence),英文缩写为AI。是研究、开发用于模拟、延伸和扩展人的智能的理论、方法、技术及应用系统的一门新技术科学。
人工智能是计算机科学的一个分支,它企图了解智能的实质,并生产出一种新的能以人类智能相似的方式做出反应的智能机器,该领域的研究包括机器人、语言识别、
图像识别、自然语言处理和专家系统等。
"""]

chunk_size = 100  # 每个片段约 100 字符
overlap = 20      # 重叠部分长度
documents = []
for text in texts:
    # 简单按照固定长度切分,并添加重叠
    chunks = [text[i:i+chunk_size] for i in range(0, len(text), chunk_size - overlap)]
    documents.extend(chunks)
print(f"切分后得到 {len(documents)} 个文档片段")
print(f"documents={documents}")

【例】运行结果如下:

shell
E:\AI\ai-llm-demo [master  +1 ~0 -0 !]> python test.py
切分后得到 3 个文档片段
documents=['\n人工智能(Artificial Intelligence),英文缩写为AI。是研究、开发用于模拟、延伸和扩展人的 智能的理论、方法、技术及应用系统的一门新技术科学。\n人工智能是计算机科学的一个分支,它', '学。\n人工智能是计算机科学的一个分支,它企图了解智能的实质,并生产出一种新的能以人类智能相似的方式做出反应的智能机器,该领域的研究包括机器人、语言识别、\n图像识别、自然语言处理和专家系统等。\n', '别、自然语言处理和专家系统等。\n']

上面的代码演示了将文档列表按固定长度切分片段。在实际应用中,可以使用现有工具如 LangChainLlamaIndex 提供的文本分割器,这些工具支持按句子、段落甚至编程代码单元进行智能切分,并可配置重叠大小。例如,LlamaIndex 默认采用 1024 tokens 的块大小并附带一定重叠。

二、向量化(Vectorization)

对每个文档片段,通过预训练的 文本嵌入模型 提取向量表示。嵌入模型可以选择通用的预训练模型(如 sentence-transformers 系列)或领域专用模型。若使用 OpenAI 的 API,也可以采用诸如 text-embedding-ada-002 等模型获取向量。向量化后的结果是一个高维向量(数百维到上千维不等),捕捉了文本片段的语义特征。这些向量将作为 "知识" 的表征被存储备用。

我这里在本地使用ollama运行了一个 qwen3-embedding:0.6b 模型,我们可以用 Python 写一个示例:

python
# -*- coding: utf-8 -*-
# https://ollama.com/blog/embedding-models
from ollama import embed

# 示例使用
texts = ["""
人工智能(Artificial Intelligence),英文缩写为AI。是研究、开发用于模拟、延伸和扩展人的智能的理论、方法、技术及应用系统的一门新技术科学。
人工智能是计算机科学的一个分支,它企图了解智能的实质,并生产出一种新的能以人类智能相似的方式做出反应的智能机器,该领域的研究包括机器人、语言识别、
图像识别、自然语言处理和专家系统等。
"""]

def split_documents(texts, chunk_size=100, overlap=20):
    """
    将文本列表按照指定大小切分成文档片段
    
    Args:
        texts (list): 文本列表,每个元素是一个长文档字符串
        chunk_size (int): 每个片段的字符数
        overlap (int): 片段之间的重叠字符数
    
    Returns:
        list: 切分后的文档片段列表
    """
    documents = []
    for text in texts:
        # 简单按照固定长度切分,并添加重叠
        chunks = [text[i:i+chunk_size] for i in range(0, len(text), chunk_size - overlap)]
        documents.extend(chunks)
    return documents


def get_embedding(text, model_name="qwen3-embedding:0.6b"):
    """
    使用 Ollama 获取文本的向量表示
    
    Args:
        text (str): 输入文本
        model_name (str): 使用的预训练模型名称
    
    Returns:
        list: 文本的向量表示
    """
    try:
        response = embed(model=model_name, input=text)
        return response['embeddings'][0]
    except Exception as e:
        print(f"获取 embedding 时出错: {e}")
        return None

documents = split_documents(texts, chunk_size=100, overlap=20)
print(f"切分后得到 {len(documents)} 个文档片段")
print(f"documents={documents}")
print()

# 获取每个文本的向量表示
embeddings_list = []
for i, text in enumerate(documents):
    print(f"正在获取文本 {i+1} 的向量表示...")
    print(f"文本内容: {text}")
    embedding = get_embedding(text)
    if embedding is not None:
        embeddings_list.append(embedding)
        print(f"向量维度: {len(embedding)}")
        print("-" * 50)
    else:
        print(f"获取文本 '{text}' 的向量表示失败")
        embeddings_list.append(None)

【例】qwen3-embedding:0.6b 默认是1024维度的。

shell
E:\AI\ai-llm-demo [master  +1 ~0 -0 !]> python test.py
切分后得到 3 个文档片段
documents=['\n人工智能(Artificial Intelligence),英文缩写为AI。是研究、开发用于模拟、延伸和扩展人的智能的理论、方法、技术及应用系统的一门新技术科学。\n人工智能是计算机科学的一个分支,它', '学。\n人工智能是计算机科学的一个分 支,它企图了解智能的实质,并生产出一种新的能以人类智能相似的方式做出反应的智能机器,该领域的研究包括机器人、语言 识别、\n图像识别、自然语言处理和专家系统等。\n', '别、自然语言处理和专家系统等。\n']

正在获取文本 1 的向量表示...
文本内容:
人工智能(Artificial Intelligence),英文缩写为AI。是研究、开发用于模拟、延伸和扩展人的智能的理论、方法、技术及应用系统的一门新技术科学。
人工智能是计算机科学的一个分支,它
向量维度: 1024
--------------------------------------------------
正在获取文本 2 的向量表示...
文本内容: 学。
人工智能是计算机科学的一个分支,它企图了解智能的实质,并生产出一种新的能以人类智能相似的方式做出反应的智能机器, 该领域的研究包括机器人、语言识别、
图像识别、自然语言处理和专家系统等。

向量维度: 1024
--------------------------------------------------
正在获取文本 3 的向量表示...
文本内容: 别、自然语言处理和专家系统等。

向量维度: 1024
--------------------------------------------------

在实际场景中,应考虑批量请求以提高向量提取的效率,并留意 API 调用的费用。同时需要为每个向量保存元数据,例如该片段所属的文档 ID、段落位置等,以便检索结果用于生成答案时可以定位来源。

注意:使用的时候要选支持embedding的模型。我这里用了QwenLM/Qwen3-Embedding

Model TypeModelsSizeLayersSequence LengthEmbedding DimensionMRL SupportInstruction Aware
Text EmbeddingQwen3-Embedding-0.6B0.6B2832K1024YesYes
Text EmbeddingQwen3-Embedding-4B4B3632K2560YesYes
Text EmbeddingQwen3-Embedding-8B8B3632K4096YesYes

三、构建索引

将得到的向量集合插入到选定的向量数据库中,建立索引以支持相似度检索。多数向量数据库提供便捷的方法插入批量向量并自动构建索引。例如,使用 Chroma 向量库,可以这样创建索引并存储向量:

python
# 安装 Chroma 数据库的 Python 库(需要在有网络的环境执行)
# pip install chromadb
from chromadb import Client
client = Client()
collection = client.create_collection("knowledge_base")

# 批量插入向量及其关联的文本或元数据
collection.add(
    embeddings=embeddings,
    documents=documents,
    ids=[f"doc_{i}" for i in range(len(documents))]
)

以上代码演示了使用 Chroma 创建一个名为"knowledge_base"的集合,并添加向量数据和对应文本。在添加时我们为每个向量指定了一个 ID,用于将检索结果与原始内容关联。不同的向量数据库添加向量的方式会有所区别,但本质都是将文本向量及其标识存储起来,供后续相似度搜索。

这个示例并不完整,可以看这个:01_quick_start/20_Embedding/15_chromdb.py

四、总结

经过以上三步,我们就将文档转化为了 AI 知识库。当用户提问时,RAG 流程会将问题向量化,在向量数据库中检索语义相似的几个片段,作为上下文提供给 LLM 生成答案。这种方式使得 LLM 的回答既基于自身掌握的语言知识,又参考了检索到的权威资料,从而提高准确性和可信度。

参考资料:

博客/企业文档如何变成 AI 知识库(文档分片、向量化、构建索引) | Jimmy Song