1. 从“字”到“词”:为什么大模型的世界里没有“你好”

如果你刚开始接触大模型,可能会被一个看似简单的问题绊住:为什么我输入“你好,世界”,模型返回的文本长度(Token数)不是4,而是5、6甚至更多?为什么我精心设计的提示词,有时会被模型“曲解”?这一切的根源,都始于一个最基础、也最容易被忽视的概念: Token

很多人把Token简单理解为“单词”,这是第一个认知误区。在中文大模型的世界里,尤其是像ChatGPT、文心一言、通义千问这类基于Transformer架构的模型,Token是模型“看见”和“理解”世界的最小单位。它不是我们人类理解的“字”或“词”,而是一种经过复杂算法切割后的 文本片段 。这个切割过程,就是 分词(Tokenization)

让我用一个最直接的例子来说明。假设我们有一个极其简单的英文句子:“I love apple pie.”。作为人类,我们自然将其分为四个单词: [“I”, “love”, “apple”, “pie.”] 。但对于大模型的分词器(Tokenizer)来说,情况可能完全不同。以OpenAI的 cl100k_base (GPT-4/3.5-turbo等模型使用)分词器为例,这句话可能会被切分成: [“I”, “ love”, “ apple”, “ pie”, “.”] 。看到了吗?“pie”和句号被分开了,而且“love”和“apple”前面多了一个空格(在分词中,空格经常被当作一个独立字符或与前一个词合并处理)。这个列表中的每一个元素,如 “I” “ love” “ pie” ,就是一个Token。

现在,把场景切换到中文。“你好世界”这四个字,用不同的分词器处理,结果天差地别:

  • 按字分词 [“你”, “好”, “世”, “界”] -> 4个Token。这是最朴素的方式,但会丢失“你好”、“世界”这些词的语义信息。
  • 按词分词(如jieba) [“你好”, “世界”] -> 2个Token。更符合人类直觉,但“你好”可能在某些语境下被拆开(如“你的好处”)。
  • 大模型常用分词器(如BERT的WordPiece,GPT的BPE) :很可能被切成 [“你”, “好”, “世”, “界”] [“你”, “好”, “世界”] 。为什么?因为大模型的分词器是在海量语料上通过统计学习“学”出来的,目标是找到一种平衡:既能用有限的词汇表(例如5万到10万个Token)覆盖绝大多数文本,又能让每个Token尽可能承载有意义的语义。对于它来说,“世界”可能是一个常见的组合,所以成为一个Token;“你好”虽然常见,但“你”和“好”作为独立Token的出现频率极高,组合成新Token的收益不大,所以可能被分开。

理解这一点至关重要。 Token是模型与文本交互的“货币”和“接口” 。我们输入的提示词(Prompt)、模型生成的每一个字,都需要先兑换成Token,在模型的内部进行计算。Token数量的多少,直接关系到API调用成本(按Token计费)、模型的处理效率(有上下文窗口限制,如128K Tokens),以及最关键的—— 模型对语义的理解精度 。一个糟糕的分词,可能会让“武汉市长江大桥”被理解成“武汉市长 江大桥”,从而彻底歪曲后续的生成逻辑。

所以,别再问“这个模型的中文理解能力如何”这种空泛的问题了。一个更精准的切入点是: 这个模型使用的分词器,对中文的切割方式是否高效、是否合理? 这,才是真正入门大模型的第一课。

2. 分词器:大模型如何“学会”阅读——BPE/WordPiece算法深度拆解

既然Token如此重要,那么大模型究竟是如何“学会”将连续文本切成一个个Token的呢?这背后主要是两种核心算法: BPE(Byte Pair Encoding,字节对编码) WordPiece 。它们听起来复杂,但核心思想可以用一个“合并游戏”来理解。

想象你有一本巨大的、包含所有互联网文本的书。最开始,你的词汇表里只有最基本的“字母表”,比如英文的26个字母加上一些标点符号,中文的几千个单字。你的目标是:通过不断合并出现频率最高的“符号对”,来构建一个规模固定(比如5万个)的新词汇表,这个词汇表里的每一个元素,就是一个Token。

2.1 BPE算法:从字母到“词根”的进化史

BPE的过程非常直观:

  1. 初始化 :将训练语料中的所有文本拆分成最小的单元。对于英文,就是字母和常见符号;对于中文,可以是单字(Character)。
  2. 统计与合并 :扫描整个语料库,找出 出现频率最高的一对相邻符号 。比如,“e”和“s”经常连在一起出现(如“yes”,“best”),那么就把“es”合并成一个新的符号,加入词汇表。
  3. 迭代 :重复步骤2,不断合并最高频的符号对,直到词汇表达到我们预设的大小(比如5万次合并后,词汇表有5万+基础符号个条目)。

这个过程就像生物进化。一开始只有氨基酸(字母),然后氨基酸组合成短肽(高频字母对,如“th”,“ing”),短肽再组合成蛋白质(更长的子词,如“ation”,“ness”)。最终形成的词汇表里,既包含完整的常见单词(如“the”,“cat”),也包含大量的词根、词缀和常见词组(如“ized”,“pre-”,“-able”)。

OpenAI的GPT系列(包括ChatGPT)主要使用BPE的变体 。它的一个关键特点是 将空格视为一个普通字符 。这就是为什么在GPT的Token中,你经常看到像 “ love” (前面带空格)这样的Token。因为空格和“love”在语料中频繁相邻出现,所以被合并了。这带来了一个好处:模型能明确感知到单词的边界,对于英文这种以空格分隔单词的语言处理起来更高效。

2.2 WordPiece算法:BPE的“概率升级版”

WordPiece是Google为BERT模型提出的,核心思想与BPE类似,但合并策略从“频率最高”变成了“能最大程度提升语言模型概率”的一对。

简单来说,它不仅仅看两个符号是否经常一起出现,还要计算:如果把这两个符号合并成一个新符号,用这个新符号重新表示整个语料库,那么语料库作为一个整体的出现可能性(似然概率)提升了多少?它选择能带来最大概率提升的那一对进行合并。

这听起来有点绕,但你可以理解为一种更“聪明”的合并。它倾向于合并那些组合后语义更稳定、更不可分割的片段。 BERT、ALBERT等模型使用WordPiece 。对于中文,BERT通常直接以字为单位进行WordPiece学习,所以它的中文词汇表看起来就是一堆单字加上一些常见双字词(如“中国”、“经济”)。

2.3 实战观察:不同分词器的差异

我们可以用代码直观感受一下。假设我们使用 transformers 库(一个主流的开源NLP库):

from transformers import AutoTokenizer

# 加载不同的分词器
tokenizer_gpt2 = AutoTokenizer.from_pretrained("gpt2") # 使用BPE
tokenizer_bert = AutoTokenizer.from_pretrained("bert-base-chinese") # 使用WordPiece

text = "深度学习模型正在理解人类的语言。"

tokens_gpt2 = tokenizer_gpt2.tokenize(text)
tokens_bert = tokenizer_bert.tokenize(text)

print("GPT-2 (BPE) Tokens:", tokens_gpt2)
print("BERT (WordPiece) Tokens:", tokens_bert)

输出可能会类似于:

GPT-2 (BPE) Tokens: ['深', '度', '学', '习', '模', '型', '正', '在', '理', '解', '人', '类', '的', '语', '言', '。']
BERT (WordPiece) Tokens: ['深', '度', '学', '习', '模', '型', '正', '在', '理', '解', '人', '类', '的', '语', '言', '。']

(注:由于示例模型和具体词汇表版本,结果可能不同,但中文上两者常都退化为字级别分词)

而对于英文句子 "unhappily"

  • BPE可能会切成 [“un”, “happ”, “ily”] ,因为它学到了“un”这个前缀,“happ”这个根,和“ily”这个后缀。
  • WordPiece可能会切成 [“un”, “##hap”, “##pily”] ## 表示子词前缀),它更强调合并后整体的概率增益。

关键心得 :选择模型时,了解其底层分词器对中文的处理粒度至关重要。如果你的任务涉及大量专业术语、成语或新兴网络用语,一个以“字”为主的分词器可能会丢失关键语义关联,导致模型表现不佳。此时,可能需要寻找针对中文优化过、包含更多常见词汇的分词器模型(如一些国产大模型),或者考虑在输入前对文本进行预处理。

3. 从Token到语义:Embedding如何让文字拥有“向量灵魂”

Token只是离散的符号。计算机,包括神经网络,无法直接理解“苹果”这个词代表一种水果。它们只认识数字。那么,如何将“苹果”这个Token转换成模型能处理的数字形式呢?第一步是 索引化 :词汇表中的每个Token都有一个唯一的ID。比如,“苹果”可能对应ID 12345。

但ID 12345和ID 12346(比如“香蕉”)之间,除了数字大小,没有任何语义关系。这显然不行。我们需要一种方法,让“苹果”和“香蕉”的表示既不同(因为它们是不同的水果),又相似(因为它们都是水果),并且与“汽车”的表示相差甚远。

这就是 Embedding(嵌入/向量化) 登场的时候。它的核心思想是: 为词汇表中的每一个Token,学习一个固定长度的、稠密的实数向量(例如一个长度为768或1024的数组) 。这个向量不是随机的,而是在模型训练过程中,根据这个Token在数十亿甚至数万亿文本中出现的上下文,不断调整优化而来的。

3.1 Embedding的本质:高维空间中的语义地图

你可以把Embedding向量想象成在一个非常高维(比如768维)的空间中的一个点。这个空间就是模型的“语义空间”。在这个空间里:

  • 语义相似的词,距离相近 。“国王”和“王后”的向量点会很靠近;“苹果”和“香蕉”也会比较靠近,但可能位于“水果”这个更大的聚类区域内。
  • 语义关系可以向量运算 。经典的例子是: vec(“国王”) - vec(“男人”) + vec(“女人”) ≈ vec(“王后”) 。这说明模型捕捉到了“性别”这种抽象关系。
  • 上下文改变位置 。同一个词在不同语境下,可以有不同的向量(通过模型的上下文编码层实现,如Transformer),但它的基础Token Embedding提供了一个起始的“锚点”。

3.2 如何得到Embedding?

在大模型(如GPT、LLaMA)中,Embedding通常是一个可学习的查找表(Lookup Table),也叫 Embedding Layer 。它的行数等于词汇表大小(V),列数等于隐藏层维度(D)。当我们输入一个Token ID(如12345)时,模型就从这个表中取出第12345行的那个D维向量,作为这个Token的初始表示。

这个查找表的值,是在预训练阶段通过 掩码语言模型(MLM) 自回归语言模型 任务学到的。模型的任务是预测被掩盖的单词,为了做好预测,它必须让每个Token的向量能够很好地与其他Token的向量协作,从而在整体上反映出复杂的语义和语法规律。

3.3 实战:获取并使用Embedding

我们以使用 sentence-transformers 库获取文本的Embedding为例,它封装了生成高质量句子向量的模型(如BGE、all-MiniLM-L6-v2)。

from sentence_transformers import SentenceTransformer

# 加载一个轻量级的Embedding模型
model = SentenceTransformer('all-MiniLM-L6-v2')

# 准备文本
sentences = ["我喜欢吃苹果", "香蕉是一种热带水果", "今天天气真好"]

# 生成Embedding向量
embeddings = model.encode(sentences)

print(f"句子数量: {len(embeddings)}")
print(f"每个句子的向量维度: {embeddings[0].shape}") # 通常是384维
print(f"前10个维度值示例: {embeddings[0][:10]}")

# 计算句子间的余弦相似度
from sklearn.metrics.pairwise import cosine_similarity

similarity_matrix = cosine_similarity(embeddings)
print("\n句子间相似度矩阵:")
print(similarity_matrix)

运行后,你会得到三个句子的向量(每个都是384个浮点数),以及它们之间的相似度。你会发现,“我喜欢吃苹果”和“香蕉是一种热带水果”的相似度,会高于它们各自与“今天天气真好”的相似度,因为前两句都关于“水果”。

核心避坑点 encode 方法内部已经包含了 分词(Tokenization) 向量化(Embedding) 两个步骤。它首先用其内置的分词器将句子切成Token,然后将这些Token的向量通过模型(通常是Transformer的池化层)聚合成一个固定的句子向量。所以,我们通常无需手动处理单个Token的Embedding,除非你在做非常底层的模型研究或定制。对于大多数应用(搜索、聚类、检索),直接使用成熟的句子Embedding模型是最高效的选择。

4. 语义搜索实战:用Embedding构建你的私人知识库助手

理解了Token和Embedding的原理,我们现在可以做一个非常实用且强大的项目: 基于语义的本地知识库问答系统 。它的核心思路是:将你的私人文档(如PDF、TXT、Markdown)转换成Embedding向量存储起来,当用户提问时,将问题也转换成向量,然后在向量数据库中快速找到与问题语义最相关的文档片段,最后将这些片段作为上下文,交给大模型(如GPT)生成精准的答案。

这个架构通常被称为 RAG(Retrieval-Augmented Generation,检索增强生成) 。它完美结合了Embedding的语义理解能力和大模型的生成能力,既能利用外部知识,又能避免大模型的“幻觉”(胡编乱造)。

4.1 系统架构与工具选型

  1. 文档加载与切分 :我们需要将长文档切成适合处理的小块(Chunks)。因为Embedding模型有输入长度限制(通常512或1024个Token)。切分时要注意保持语义完整性,比如按段落、按标题切分,避免从句子中间切断。

    • 工具推荐 LangChain RecursiveCharacterTextSplitter MarkdownTextSplitter 。它们能根据字符、分隔符递归切分,并保持一定的重叠窗口,防止上下文断裂。
  2. 文本向量化 :将切分后的文本块转化为Embedding向量。

    • 模型推荐 BGE(BAAI/bge-base-zh) GTE(thenlper/gte-base-zh) 。这些都是针对中文优化的、开源的、效果很好的文本嵌入模型。 sentence-transformers 库完美支持。
  3. 向量存储与检索 :存储向量,并实现基于余弦相似度的快速检索。

    • 工具推荐 :轻量级首选 Chroma ,功能全面可选 FAISS (Facebook AI Similarity Search)。它们都是内存或本地磁盘向量数据库,无需复杂部署。
  4. 大模型集成 :将检索到的相关文本块组合成提示词(Prompt),发送给大模型生成答案。

    • 选择 :可以使用OpenAI API、国内大模型API(如文心、讯飞),或本地部署的开源模型(如ChatGLM、Qwen)。

4.2 分步实现代码详解

我们以处理一组Markdown格式的技术文档为例,构建一个本地问答系统。

# 步骤1:安装必要库
# pip install langchain langchain-community sentence-transformers chromadb pypdf

import os
from langchain_community.document_loaders import DirectoryLoader, TextLoader
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.embeddings import HuggingFaceEmbeddings
from langchain.vectorstores import Chroma
from langchain.chains import RetrievalQA
from langchain.llms import OpenAI  # 示例用OpenAI,可替换为其他LLM
from langchain.prompts import PromptTemplate
import getpass

# 步骤2:加载文档(假设文档在 ./docs 目录下)
documents = []
for root, dirs, files in os.walk("./docs"):
    for file in files:
        if file.endswith(".md") or file.endswith(".txt"):
            path = os.path.join(root, file)
            loader = TextLoader(path, encoding='utf-8')
            documents.extend(loader.load())
print(f"已加载 {len(documents)} 个文档")

# 步骤3:切分文本
text_splitter = RecursiveCharacterTextSplitter(
    chunk_size=500,  # 每个块的最大字符数(可根据Embedding模型调整)
    chunk_overlap=50, # 块之间的重叠字符数,防止信息割裂
    separators=["\n\n", "\n", "。", "!", "?", ";", ",", " ", ""] # 中文优先分隔符
)
chunks = text_splitter.split_documents(documents)
print(f"切分为 {len(chunks)} 个文本块")

# 步骤4:初始化Embedding模型
# 使用BGE中文模型,device='cuda'如果有GPU
embedding_model = HuggingFaceEmbeddings(
    model_name="BAAI/bge-base-zh-v1.5",
    model_kwargs={'device': 'cpu'},
    encode_kwargs={'normalize_embeddings': True} # 归一化,方便余弦相似度计算
)

# 步骤5:创建向量数据库
# persist_directory 指定持久化目录,下次可直接加载
vector_db = Chroma.from_documents(
    documents=chunks,
    embedding=embedding_model,
    persist_directory="./chroma_db" 
)
vector_db.persist() # 保存到磁盘
print("向量数据库已创建并持久化。")

# 步骤6:设置大模型(这里需要你的API Key)
# 注意:生产环境请使用环境变量管理密钥,不要硬编码!
os.environ["OPENAI_API_KEY"] = getpass.getpass("请输入你的OpenAI API Key: ")
llm = OpenAI(model_name="gpt-3.5-turbo", temperature=0.1) # temperature调低,答案更确定

# 步骤7:创建检索问答链
prompt_template = """
请根据以下上下文信息回答问题。如果上下文信息不足以回答问题,请直接说“根据提供的信息,我无法回答这个问题”,不要编造答案。

上下文:
{context}

问题:{question}
请给出专业、准确的回答:
"""
PROMPT = PromptTemplate(
    template=prompt_template, input_variables=["context", "question"]
)

qa_chain = RetrievalQA.from_chain_type(
    llm=llm,
    chain_type="stuff", # 最简单的方式,将所有检索到的上下文拼接到Prompt中
    retriever=vector_db.as_retriever(search_kwargs={"k": 3}), # 检索最相关的3个块
    chain_type_kwargs={"prompt": PROMPT},
    return_source_documents=True # 返回来源文档,便于溯源
)

# 步骤8:进行问答
query = "什么是Transformer模型中的注意力机制?"
result = qa_chain({"query": query})
print(f"问题:{query}")
print(f"答案:{result['result']}")
print("\n--- 来源文档片段 ---")
for i, doc in enumerate(result['source_documents']):
    print(f"[片段{i+1}]: {doc.page_content[:200]}...") # 打印前200字符

4.3 关键细节与调优经验

  1. 分块策略是成败关键 chunk_size 不是越大越好。太大可能包含无关信息,稀释核心内容;太小则可能丢失完整语义。对于技术文档,500-1000字符是个不错的起点。 chunk_overlap 设置50-150字符,能有效缓解边界信息丢失问题。
  2. Embedding模型选择 bge-base-zh 在中文通用任务上表现均衡。如果你的文档领域特殊(如医学、法律),可以尝试在领域数据上微调Embedding模型,或寻找领域专用的模型。
  3. 检索数量k k=3 k=4 通常是个安全的选择。太少可能信息不全,太多则可能引入噪声并增加Prompt长度(消耗更多Token和费用)。可以通过少量测试问题来调整。
  4. Prompt工程 :示例中的Prompt模板虽然简单,但明确指令“不要编造答案”对于减少幻觉至关重要。你还可以在Prompt中加入角色设定(“你是一个技术专家”)、输出格式要求等,以进一步控制生成质量。
  5. 成本与性能权衡 :使用云API大模型(如GPT-4)生成答案,质量高但持续产生费用。对于内部知识库,可以考虑用检索到的文档片段作为上下文,驱动一个较小的、本地部署的开源模型(如Qwen-7B-Chat)来生成答案,实现完全本地化、零成本的解决方案。

这个实战项目将Token、分词、Embedding、向量检索和大模型生成串联了起来,构成了当前AI应用开发中最核心的范式之一。通过动手实现它,你不仅能深刻理解这些概念如何协同工作,更能获得一个极具实用价值的工具雏形。

5. 避坑指南:Token与Embedding应用中的高频陷阱

在实际开发和调试中,仅仅理解原理是不够的,更重要的是识别和避开那些常见的“坑”。以下是我在项目中反复遇到的一些典型问题及其解决方案。

5.1 Token计数不准导致的预算超标或截断

  • 问题 :调用按Token计费的API(如OpenAI)时,自己估算的Token数和实际消耗差异巨大,导致费用超支。或者,输入的提示词因超出模型上下文窗口而被静默截断,导致模型回答不完整。
  • 根因
    1. 错误地以“字数”或“单词数”估算Token。中英文混合时尤其不准。
    2. 忽略了不同模型使用不同的分词器。GPT-3.5、GPT-4、Claude、LLaMA的分词方式都不同。
    3. 提示词中的系统指令、用户消息、助理消息的格式(如ChatML格式)本身也会占用Token。
  • 解决方案
    • 必须使用官方或准确的分词工具进行计数 。对于OpenAI系列,使用 tiktoken 库。
    import tiktoken
    encoding = tiktoken.encoding_for_model("gpt-4") # 指定模型
    tokens = encoding.encode("你的提示词在这里")
    print(f"Token数量: {len(tokens)}")
    # 也可以解码查看具体分词结果
    print([encoding.decode_single_token_bytes(token).decode('utf-8', errors='replace') for token in tokens[:10]])
    
    • 在构造复杂提示词时,实时计算Token数 。特别是在实现“动态上下文”或“历史对话”功能时,务必在添加每轮对话前检查总Token数是否接近上限(如128K的90%),并制定裁剪策略(如优先移除最早的历史记录)。
    • 了解模型的上下文窗口和计价方式 。例如,GPT-4 Turbo是128K上下文,但输入和输出分开计价。长上下文虽然方便,但费用也更高,需权衡。

5.2 中文Embedding效果不佳:语义相似但向量距离远

  • 问题 :用开源的Embedding模型处理中文句子对时,明明语义很相似,但计算出的余弦相似度却很低(例如低于0.5)。
  • 根因
    1. 模型未针对中文优化 :许多优秀的Embedding模型(如 all-MiniLM-L6-v2 )主要基于英文语料训练,对中文的语义空间映射不佳。
    2. 文本预处理不一致 :比如一句做了去除停用词、标点,另一句没有,导致向量表征的基础就不同。
    3. 领域不匹配 :通用Embedding模型在处理特定领域(如金融、生物)文本时,难以捕捉领域内特有的语义关联。
  • 解决方案
    • 换用或微调中文SOTA模型 :优先选择 BAAI/bge-*zh* moka-ai/m3e-base GTE 等明确针对中文优化的模型。它们是当前中文Embedding任务的事实标准。
    • 标准化预处理流程 :对所有文本采用相同的清洗步骤(如统一转小写、去除特殊字符但保留中文标点等)。对于检索任务,有时保留停用词反而更好,因为它们可能携带语气或逻辑信息。
    • 领域微调(进阶) :如果拥有大量领域标注数据(句子对和相似度分数),可以在预训练的中文Embedding模型基础上进行微调,让模型更好地适应你的数据分布。Hugging Face的 sentence-transformers 库提供了完善的训练接口。

5.3 向量检索返回无关内容:检索精度低

  • 问题 :RAG系统中,用户的问题很明确,但向量数据库返回的前几个文本块却完全不相关。
  • 根因
    1. 分块策略不当 :这是最常见的原因。块太大,包含了多个主题,噪声淹没了信号;块太小,语义不完整,Embedding无法准确表征。
    2. 检索方式单一 :仅使用简单的“向量相似度”检索,可能无法处理关键词完全匹配但语义不同,或语义相同但表述迥异(如“怎么做” vs “如何实现”)的情况。
    3. Embedding模型“偏见” :模型可能对某些类型的表述或领域存在系统性偏差。
  • 解决方案
    • 迭代优化分块 :这是最重要的步骤。尝试不同的 chunk_size chunk_overlap ,并用一批典型问题测试检索召回率。对于结构化工整的文档(如API文档),可以尝试按标题( # ## )进行分割。
    • 采用混合检索(Hybrid Search) :结合 稠密向量检索 (语义相似)和 稀疏向量检索 (关键词匹配,如BM25)。 Chroma Weaviate 等向量库已支持混合检索。这能同时保证语义的灵活性和关键词的精确性。
    • 重排序(Re-ranking) :先通过向量检索召回较多的候选结果(如k=20),然后使用一个更精细的、专门用于判断相关性的**交叉编码器(Cross-Encoder)**模型对这20个结果进行重排序,只取Top-3给大模型。虽然多了一步,但精度提升显著。 sentence-transformers 也提供了Cross-Encoder模型。
    • 查询扩展 :在检索前,先用大模型对原始用户问题进行改写或扩展,生成多个同义或相关的查询语句,分别进行检索,然后合并结果。这能提高召回率。

5.4 Embedding服务报错: No embedding model is loaded

  • 问题 :在运行RAG或相似度计算应用时,遇到类似 ValueError: No embedding model is loaded. Set rag_embedding_model to a valid sentence-transformers model. 的错误。
  • 根因 :这通常发生在使用某些封装好的框架或工具(如 llama_index , LangChain 的某些版本)时,没有正确初始化或指定Embedding模型。
  • 解决方案
    • 检查模型名称 :确保传入的模型名称字符串是 sentence-transformers 库支持的、存在于Hugging Face Hub上的有效模型名。例如 “BAAI/bge-small-zh-v1.5”
    • 显式初始化Embedding对象 :不要依赖框架的默认设置。如LangChain中,应使用:
    from langchain.embeddings import HuggingFaceEmbeddings
    embeddings = HuggingFaceEmbeddings(model_name="BAAI/bge-base-zh-v1.5")
    # 然后将这个embeddings对象传递给向量数据库或检索器
    
    • 网络问题 :首次加载模型需要从Hugging Face下载,确保网络通畅。也可以提前将模型下载到本地,通过 model_name=“/path/to/your/local/model” 指定本地路径。
    • 版本兼容性 :检查你使用的框架版本与 sentence-transformers 库版本的兼容性。有时升级或降级其中一个可以解决问题。

Token和Embedding是大模型时代的基石技术,它们将人类模糊的语言转化为机器可精确计算的空间几何关系。从理解一个句子如何被拆解成Token,到这些Token如何被映射为高维空间中的点,再到如何利用这些点之间的“距离”来寻找信息、生成答案——这条路径,构成了当今绝大多数大模型应用的底层逻辑。

我个人的体会是,初期多花时间在“分块”和“Embedding模型选型”这两个环节上,是性价比最高的投资。一个糟糕的分块策略会让后续所有精妙的检索和生成设计付诸东流。而选择一个与你的数据领域和任务目标匹配的Embedding模型,就如同为你的知识库选择了一位理解力合格的“图书管理员”。

最后,一个小技巧:在构建生产级RAG系统时,除了关注检索的“准确性”,一定要建立一套评估“答案质量”的机制。可以人工标注一批“问题-标准答案”对,定期用你的系统去回答这些问题,从“事实准确性”、“答案完整性”、“与上下文相关性”等多个维度进行评分。只有通过持续的评估和迭代,才能让基于Token和Embedding的系统真正可靠地运转起来。

更多推荐