RAG-Embedding

Embedding 模型本質(zhì)是一個(gè)編碼器神經(jīng)網(wǎng)絡(luò)(通?;?Transformer),將文本壓縮成固定長(zhǎng)度的向量

        輸入文本
           ↓
    ┌─────────────────┐
    │   Tokenizer     │  "蘋果是水果" → [101, 679, 3221, 3717, 1963, 102]
    └────────┬────────┘
             ↓
    ┌─────────────────┐
    │  Transformer    │  多層 Self-Attention 提取語義特征
    │  Encoder 層     │
    │  (BERT結(jié)構(gòu))     │
    └────────┬────────┘
             ↓
    ┌─────────────────┐
    │   池化層         │  取 [CLS] token 或平均池化
    │  (Pooling)      │
    └────────┬────────┘
             ↓
    ┌─────────────────┐
    │   L2 歸一化      │  向量長(zhǎng)度歸一化為 1
    └────────┬────────┘
             ↓
    [0.023, -0.156, 0.891, ..., 0.034]  ← 768/1024/1536 維向量

一、Tokenizer

RAG 中的 Tokenizer(分詞/切塊)策略主要決定如何將原始文檔切分成適合檢索的片段(chunk),直接影響召回質(zhì)量。

1、Tokenizer的常見策略有一下幾種:

  • 1、按固定 token 數(shù)或字符數(shù)切分,可設(shè)置重疊窗口(overlap)避免語義斷裂。
[chunk1: 0-512 tokens]
[chunk2: 400-912 tokens]  ← overlap=112
[chunk3: 800-1312 tokens]
優(yōu)點(diǎn): 簡(jiǎn)單高效,易于實(shí)現(xiàn)
缺點(diǎn): 可能在句子/段落中間截?cái)?,破壞語義完整性
  • 2、遞歸字符切分(Recursive Character Splitting)
按優(yōu)先級(jí)依次嘗試分隔符:\n\n → \n → 。 → → 字符,盡量保持語義完整。
代表: LangChain 的 RecursiveCharacterTextSplitter
優(yōu)點(diǎn): 比固定切分更自然,尊重段落/句子邊界
缺點(diǎn): chunk 大小不均勻
  • 3、語義感知切分(Semantic-aware Chunking)
3.1 基于句子嵌入的語義切分
將文本按句子分割,計(jì)算相鄰句子的語義相似度
相似度驟降處作為切分點(diǎn)
代表: LlamaIndex SemanticSplitterNodeParser
3.2 基于 NLP 的句子邊界切分
使用 NLP 工具(spaCy、jieba)識(shí)別句子/詞語邊界
按句子為單位組合,控制 chunk 大小
  • 4、結(jié)構(gòu)化文檔切分(Structure-aware Chunking)

根據(jù)文檔本身結(jié)構(gòu)切分,保留層級(jí)關(guān)系:

文檔類型 切分依據(jù)
Markdown 標(biāo)題層級(jí)(H1/H2/H3)
HTML <section>, <p>, <div>
PDF 段落、頁面、表格
代碼 函數(shù)、類、模塊

優(yōu)點(diǎn): 語義最完整,chunk 有明確的業(yè)務(wù)含義

  • 5、父子切分(Parent-Child / Hierarchical Chunking)
    存儲(chǔ)大 chunk(parent),索引小 chunk(child):
    檢索時(shí)用小 chunk 精準(zhǔn)匹配
    返回時(shí)擴(kuò)展到父級(jí)大 chunk 保證上下文完整
[父 chunk: 整個(gè)段落 1000 tokens]
    ├── [子 chunk1: 128 tokens] ← 用于向量檢索
    ├── [子 chunk2: 128 tokens]
    └── [子 chunk3: 128 tokens]
  • 6、命題切分(Proposition Chunking)
用 LLM 將段落分解為原子性的、自包含的陳述句(proposition),每個(gè) proposition 獨(dú)立可理解。
優(yōu)點(diǎn): 檢索精度極高
缺點(diǎn): 預(yù)處理成本高(需要調(diào)用 LLM)
  • 7、Late Chunking(延遲切分)
先對(duì)整個(gè)文檔做 embedding,再切分,讓每個(gè) chunk 的向量帶有全局上下文信息,解決"切分后語義孤立"問題。

2、策略選型建議

場(chǎng)景 推薦策略
快速原型 固定大小 + overlap
通用文檔 遞歸字符切分
結(jié)構(gòu)化文檔(Markdown/HTML) 結(jié)構(gòu)感知切分
高精度問答 父子切分 / 命題切分
長(zhǎng)文檔全局理解 Late Chunking
中文文檔 結(jié)合 jieba 的句子邊界切分

3、核心調(diào)參指標(biāo):

  • chunk_size:通常 256~1024 tokens,取決于 embedding 模型上下文窗口
  • chunk_overlap:通常 10%~20% 的 chunk_size
  • 切分后建議對(duì)每個(gè) chunk 添加元數(shù)據(jù)(來源、標(biāo)題、頁碼),增強(qiáng)檢索后的可解釋性

二、Transformer Encoder

一句話:把一段話變成一組數(shù)字,讓電腦能"比較"兩段話是不是在說同一件事。

你和朋友聊天時(shí),你能馬上聽出"我餓了"和"想吃飯"是一個(gè)意思。但電腦只認(rèn)數(shù)字,所以需要一個(gè)翻譯器,把文字翻譯成數(shù)字,且保證意思相近的話,翻譯出來的數(shù)字也相近。

Transformer Encoder 就是這個(gè)翻譯器。


整個(gè)過程只有 4 步

第 1 步:拆字

電腦不認(rèn)識(shí)"蘋果手機(jī)推薦"這個(gè)字符串,需要先拆成小塊:

"蘋果手機(jī)推薦"
      ↓ 拆開
["蘋果", "手機(jī)", "推薦"]
      ↓ 每個(gè)詞給一個(gè)編號(hào)
[  678,   312,   891  ]

就像給每個(gè)詞發(fā)了一張編號(hào)卡,編號(hào)是查字典得來的。


第 2 步:給每個(gè)詞一個(gè)初始描述

光有編號(hào)沒用,需要給每個(gè)詞一個(gè)"畫像"——用 768 個(gè)數(shù)字描述它。

"蘋果" → [0.5, 0.1, 0.3, 0.8, 0.2, ... ] 共768個(gè)數(shù)字
"手機(jī)" → [0.3, 0.8, 0.6, 0.1, 0.4, ... ] 共768個(gè)數(shù)字
"推薦" → [0.7, 0.2, 0.5, 0.9, 0.3, ... ] 共768個(gè)數(shù)字

但此時(shí)有個(gè)大問題: 每個(gè)詞的畫像是"死"的。不管"蘋果"出現(xiàn)在"蘋果手機(jī)"還是"蘋果好吃"里,畫像都一樣。它還不理解上下文。


第 3 步:讓詞和詞之間"聊天"(Self-Attention)

這是最核心的一步。

打個(gè)比方:你新來一家公司,你只知道自己的崗位(初始畫像)。你需要和周圍同事聊天,了解部門整體在做什么,才能真正理解自己在這個(gè)團(tuán)隊(duì)里的角色。

Self-Attention 做的就是這件事:讓每個(gè)詞去問其他所有詞——"你和我什么關(guān)系?"

場(chǎng)景: "蘋果 手機(jī) 推薦"

"手機(jī)"開始問:
  → 問"蘋果": 你和我什么關(guān)系?
    "蘋果"回答: 我是你的品牌修飾詞,關(guān)系很密切! (分?jǐn)?shù): 80分)

  → 問"推薦": 你和我什么關(guān)系?
    "推薦"回答: 我是動(dòng)作,你是對(duì)象,有關(guān)系 (分?jǐn)?shù): 50分)

  → 問自己: 你和我什么關(guān)系?
    自己回答: 我就是我 (分?jǐn)?shù): 90分)

然后按分?jǐn)?shù)高低,把其他詞的信息"吸收"過來更新自己的畫像:

新的"手機(jī)"畫像 = 自身信息×40% + "蘋果"信息×35% + "推薦"信息×25%

更新后,"手機(jī)"的畫像里就融入了"蘋果"的信息,電腦就知道這里說的是蘋果品牌的手機(jī)了。

每個(gè)詞都這樣做一遍。一輪之后,所有詞都"理解"了上下文。

為什么要做 12 輪?

一輪只能理解最直接的關(guān)系。多輪之后理解越來越深:

第 1-2 輪:  知道"蘋果"和"手機(jī)"是挨在一起的
第 3-5 輪:  理解"蘋果手機(jī)"是一個(gè)品牌產(chǎn)品
第 6-9 輪:  理解整句話是"有人在找蘋果手機(jī)的推薦"
第 10-12輪: 形成高度抽象的語義理解,能和"iPhone哪款好"匹配上

類比:你在新公司第一天只認(rèn)識(shí)隔壁同事。一個(gè)月后認(rèn)識(shí)了整個(gè)部門。半年后理解了公司的戰(zhàn)略方向。每一輪"聊天"都讓理解更深一層。

多頭注意力是什么?

每一輪聊天不只聊一個(gè)話題,同時(shí)聊 12 個(gè)話題:

話題1: 誰修飾誰?       → "蘋果"修飾"手機(jī)"
話題2: 誰是動(dòng)作對(duì)象?    → "推薦"的對(duì)象是"手機(jī)"
話題3: 誰和誰意思相近?  → "推薦" ≈ "建議"
話題4: 誰挨著誰?       → "蘋果"緊挨"手機(jī)"
... 共12個(gè)話題同時(shí)進(jìn)行

每個(gè)話題聊出來的結(jié)果拼在一起,信息更全面。


第 3.5 步:FFN(深度消化)

每次"聊天"之后,每個(gè)詞需要單獨(dú)"消化"吸收到的信息:

"手機(jī)"剛吸收了"蘋果"和"推薦"的信息
    ↓ 經(jīng)過FFN"消化"
"手機(jī)"把新信息和自己已有的知識(shí)融合
    → 形成更成熟的語義理解

類比:開完會(huì)(Self-Attention)后回到工位整理筆記(FFN),把討論內(nèi)容轉(zhuǎn)化成自己的理解。


第 4 步:合并成一個(gè)句子向量

12 輪之后,每個(gè)詞都有了充分理解上下文的向量。最后需要合并成一個(gè)向量代表整句話:

"蘋果" → [0.31, 0.67, ...]
"手機(jī)" → [0.58, 0.44, ...]
"推薦" → [0.37, 0.71, ...]
              ↓
         池化層(Pooling)
              ↓
句子向量 → [0.42, 0.61, ...]  768個(gè)數(shù)字

這 768 個(gè)數(shù)字,就是"蘋果手機(jī)推薦"這句話在電腦眼里的"身份證號(hào)"。


總結(jié)

步驟 做了什么 大白話
拆字 文本變Token 把句子拆成詞
初始向量 Token變768維向量 給每個(gè)詞一張初始畫像
Self-Attention ×12輪 詞與詞交互 讓每個(gè)詞看看周圍詞,理解上下文
FFN 深度變換 開完會(huì)后整理筆記
Pooling 多個(gè)向量→1個(gè) 把所有詞的理解合并成句子的理解

本質(zhì)就是:拆詞 → 給初始畫像 → 反復(fù)交流更新畫像 → 合并成一個(gè)代表整句話的數(shù)字

三、池化層

經(jīng)過 Transformer Encoder 的 12 層處理后,每個(gè) Token 都有了自己的 768 維向量。但做檢索時(shí),我們需要一個(gè)向量代表整段話

池化層的工作就是:把多個(gè)詞向量,壓縮成一個(gè)句子向量。

Encoder 輸出:
[CLS]  → [0.31, 0.67, 0.45, ...]  768維
蘋果    → [0.45, 0.52, 0.38, ...]  768維
手機(jī)    → [0.58, 0.44, 0.61, ...]  768維
推薦    → [0.37, 0.71, 0.29, ...]  768維
[SEP]  → [0.12, 0.33, 0.55, ...]  768維
                  │
            池化層(Pooling)
                  │
                  ▼
句子向量 → [?, ?, ?, ...]  768維   ← 怎么算這個(gè)?

不同的池化策略,"怎么算"的方式不同,效果也不同。


四種主流池化策略

    1. CLS Pooling(取 [CLS] 向量)

做法: 直接取 [CLS] 這個(gè)特殊 Token 的向量作為句子向量,其他詞全部丟棄。

[CLS]  → [0.31, 0.67, 0.45, ...]  ← 直接用這個(gè)
蘋果    → [0.45, 0.52, 0.38, ...]  ← 丟棄
手機(jī)    → [0.58, 0.44, 0.61, ...]  ← 丟棄
推薦    → [0.37, 0.71, 0.29, ...]  ← 丟棄
[SEP]  → [0.12, 0.33, 0.55, ...]  ← 丟棄

句子向量 = [0.31, 0.67, 0.45, ...]

原理: BERT 在預(yù)訓(xùn)練時(shí),專門訓(xùn)練 [CLS] Token 去匯聚整句話的語義。經(jīng)過 12 層 Self-Attention,[CLS] 已經(jīng)"看過"所有詞,理論上包含了全句信息。

優(yōu)點(diǎn):

  • 計(jì)算最快,只取一個(gè)向量
  • BERT 原生設(shè)計(jì)就是用 [CLS] 做句子級(jí)任務(wù)

缺點(diǎn):

  • [CLS] 的預(yù)訓(xùn)練目標(biāo)是 NSP(下一句預(yù)測(cè)),不是語義相似度
  • 實(shí)測(cè)在語義檢索任務(wù)上效果不如 Mean Pooling
  • 信息過度集中在一個(gè) Token 上,容易丟失細(xì)節(jié)

適用: 分類任務(wù)(情感分析、文本分類)


    1. Mean Pooling(平均池化)

做法: 把所有 Token 的向量逐維取平均值。

[CLS]  → [0.31, 0.67, 0.45, ...]
蘋果    → [0.45, 0.52, 0.38, ...]
手機(jī)    → [0.58, 0.44, 0.61, ...]
推薦    → [0.37, 0.71, 0.29, ...]
[SEP]  → [0.12, 0.33, 0.55, ...]

第1維平均: (0.31+0.45+0.58+0.37+0.12) / 5 = 0.366
第2維平均: (0.67+0.52+0.44+0.71+0.33) / 5 = 0.534
第3維平均: (0.45+0.38+0.61+0.29+0.55) / 5 = 0.456
...

句子向量 = [0.366, 0.534, 0.456, ...]

帶 Attention Mask 的版本(實(shí)際使用)

實(shí)際文本長(zhǎng)度不一樣,短文本會(huì)用 [PAD] 填充到統(tǒng)一長(zhǎng)度。Padding 位置不應(yīng)該參與計(jì)算:

Token:  [CLS] 蘋果  手機(jī)  推薦  [SEP] [PAD] [PAD] [PAD]
Mask:   [  1,   1,   1,    1,    1,    0,    0,    0  ]

只對(duì) Mask=1 的位置求平均:
句子向量 = (CLS + 蘋果 + 手機(jī) + 推薦 + SEP) / 5

優(yōu)點(diǎn):

  • 每個(gè)詞都參與,信息保留最完整
  • 不依賴某個(gè)特殊 Token 的訓(xùn)練質(zhì)量
  • 在語義檢索任務(wù)上效果最好

缺點(diǎn):

  • 所有詞權(quán)重相同,"的""了"這類虛詞也參與,會(huì)稀釋關(guān)鍵詞信息

適用: RAG 語義檢索(業(yè)界主流方案)


    1. Max Pooling(最大池化)

做法: 在每一維上,取所有 Token 中的最大值。

             第1維   第2維   第3維
[CLS]  →     0.31   0.67   0.45
蘋果    →     0.45   0.52   0.38
手機(jī)    →     0.58   0.44   0.61
推薦    →     0.37   0.71   0.29
[SEP]  →     0.12   0.33   0.55

取每列最大值:
第1維: max(0.31,0.45,0.58,0.37,0.12) = 0.58  ← 來自"手機(jī)"
第2維: max(0.67,0.52,0.44,0.71,0.33) = 0.71  ← 來自"推薦"
第3維: max(0.45,0.38,0.61,0.29,0.55) = 0.61  ← 來自"手機(jī)"

句子向量 = [0.58, 0.71, 0.61, ...]

原理: 每一維取最大值,相當(dāng)于保留了"最顯著的特征"。如果某個(gè)詞在某個(gè)語義維度上激活很強(qiáng),就保留它。

優(yōu)點(diǎn):

  • 對(duì)關(guān)鍵詞敏感,突出特征明顯的詞
  • 不容易被虛詞和 Padding 稀釋

缺點(diǎn):

  • 丟失了詞序和比例信息
  • 只取極端值,對(duì)細(xì)膩語義差異不敏感
  • 一個(gè)"噪聲"詞的異常激活可能影響整體

適用: 關(guān)鍵詞匹配、短文本檢索


    1. Weighted Mean Pooling(加權(quán)平均池化)

做法: 給不同層/位置的 Token 分配不同權(quán)重,再加權(quán)平均。

4.1 按層加權(quán)(越深層權(quán)重越大)

BERT 有12層,每層都有輸出:

Layer 1 的"手機(jī)"向量  × 權(quán)重 0.02
Layer 2 的"手機(jī)"向量  × 權(quán)重 0.03
...
Layer 11 的"手機(jī)"向量 × 權(quán)重 0.15
Layer 12 的"手機(jī)"向量 × 權(quán)重 0.20  ← 最后一層權(quán)重最大

原理: 深層語義更抽象更適合檢索,給更大權(quán)重

4.2 按位置加權(quán)(越靠后權(quán)重遞增/遞減)

Token:  [CLS] 蘋果  手機(jī)  推薦  [SEP]
權(quán)重:    0.1   0.2   0.3   0.3   0.1

句子向量 = 0.1×CLS + 0.2×蘋果 + 0.3×手機(jī) + 0.3×推薦 + 0.1×SEP

4.3 按注意力分?jǐn)?shù)加權(quán)(Attention-weighted)

利用最后一層 Self-Attention 中 [CLS] 對(duì)各詞的注意力權(quán)重:

[CLS] 對(duì)各詞的注意力:
  蘋果: 0.30  ← 模型認(rèn)為"蘋果"很重要
  手機(jī): 0.35  ← "手機(jī)"最重要
  推薦: 0.25  ← 其次
  [SEP]: 0.10

句子向量 = 0.30×蘋果 + 0.35×手機(jī) + 0.25×推薦 + 0.10×SEP

優(yōu)點(diǎn):

  • 重要的詞貢獻(xiàn)更大,更精準(zhǔn)
  • 靈活性強(qiáng),可以根據(jù)任務(wù)調(diào)整權(quán)重

缺點(diǎn):

  • 權(quán)重需要額外學(xué)習(xí)或手工設(shè)計(jì)
  • 實(shí)現(xiàn)復(fù)雜度高

適用: 對(duì)精度有極高要求的場(chǎng)景


四種策略對(duì)比

策略 計(jì)算方式 信息保留 檢索效果 計(jì)算成本
CLS Pooling 取[CLS]向量 低(只取一個(gè)Token) 一般 最低
Mean Pooling 所有Token平均 高(每個(gè)詞都參與)
Max Pooling 每維取最大值 中(只保留極端值) 中等
Weighted Mean 加權(quán)平均 最高(按重要性分配) 最好 較高

主流 Embedding 模型都用什么池化?

模型 池化策略 備注
Sentence-BERT Mean Pooling 開創(chuàng)性工作,驗(yàn)證了Mean優(yōu)于CLS
OpenAI text-embedding-ada-002 未公開(推測(cè)Mean) 閉源模型
BGE 系列(智源) CLS Pooling 但經(jīng)過專門的對(duì)比學(xué)習(xí)訓(xùn)練CLS
GTE 系列(阿里) Mean Pooling 中文效果好
E5 系列(微軟) Mean Pooling 多語言支持好
Jina Embeddings Mean Pooling 長(zhǎng)文本支持好

實(shí)際建議

大多數(shù) RAG 場(chǎng)景 → 直接用 Mean Pooling,簡(jiǎn)單且效果最好
關(guān)鍵詞檢索場(chǎng)景  → 可以嘗試 Max Pooling
追求極致精度   → 用 Weighted Mean 或選擇已經(jīng)訓(xùn)練好的模型(如 BGE)

最重要的一點(diǎn): 池化策略的選擇遠(yuǎn)不如 Encoder 本身的訓(xùn)練質(zhì)量重要。一個(gè)經(jīng)過對(duì)比學(xué)習(xí)精心訓(xùn)練的模型,用 CLS 也能超過未經(jīng)訓(xùn)練的 Mean Pooling。選好模型比選池化策略更關(guān)鍵。

四、歸一化

每個(gè) Transformer Block 中出現(xiàn)兩次:

輸入
  │
  ▼
┌──────────────────────────┐
│  Self-Attention          │
└────────────┬─────────────┘
             │
     Add & LayerNorm  ← 第1次
             │
             ▼
┌──────────────────────────┐
│  Feed-Forward (FFN)      │
└────────────┬─────────────┘
             │
     Add & LayerNorm  ← 第2次
             │
             ▼
傳入下一層

這里的 "Add & LayerNorm" 其實(shí)是兩步操作:殘差連接(Add) + 層歸一化(LayerNorm)。

殘差連接(Add)
輸出 = 子層輸出 + 原始輸入
用大白話說:

你參加了一個(gè)培訓(xùn)班(Self-Attention / FFN)

不用殘差: 你把以前學(xué)的全忘了,只記得培訓(xùn)班的內(nèi)容
用殘差:   你保留了以前學(xué)的,再疊加培訓(xùn)班的新知識(shí)

原始輸入:  [0.5, 0.3, 0.8]  ← 你已有的知識(shí)
子層輸出:  [0.1, 0.4, -0.2] ← 培訓(xùn)班學(xué)到的新東西
殘差相加:  [0.6, 0.7, 0.6]  ← 新舊結(jié)合

作用:

  • 保證信息不會(huì)在深層網(wǎng)絡(luò)中完全丟失
  • 解決深層網(wǎng)絡(luò)"梯度消失"問題(訓(xùn)練時(shí)梯度可以通過殘差通道直接回傳)
  • 沒有殘差連接,12 層 Encoder 根本訓(xùn)練不起來
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • """1.個(gè)性化消息: 將用戶的姓名存到一個(gè)變量中,并向該用戶顯示一條消息。顯示的消息應(yīng)非常簡(jiǎn)單,如“Hello ...
    她即我命閱讀 4,813評(píng)論 0 6
  • 1、expected an indented block 冒號(hào)后面是要寫上一定的內(nèi)容的(新手容易遺忘這一點(diǎn)); 縮...
    庵下桃花仙閱讀 1,053評(píng)論 1 2
  • 一、工具箱(多種工具共用一個(gè)快捷鍵的可同時(shí)按【Shift】加此快捷鍵選取)矩形、橢圓選框工具 【M】移動(dòng)工具 【V...
    墨雅丫閱讀 1,427評(píng)論 0 0
  • 跟隨樊老師和伙伴們一起學(xué)習(xí)心理知識(shí)提升自已,已經(jīng)有三個(gè)月有余了,這一段時(shí)間因?yàn)樘鞖獾脑蛐菡n,順便整理一下之前學(xué)習(xí)...
    學(xué)習(xí)思考行動(dòng)閱讀 895評(píng)論 0 2
  • 一臉憤怒的她躺在了床上,好幾次甩開了他抱過來的雙手,到最后還堅(jiān)決的翻了個(gè)身,只留給他一個(gè)冷漠的背影。 多次嘗試抱她...
    海邊的藍(lán)兔子閱讀 945評(píng)論 1 4

友情鏈接更多精彩內(nèi)容