RAG 中的上下文注入

上下文注入在干什么?

前面幾步已經(jīng)完成了檢索,拿到了相關(guān)文檔。但 LLM 并不會自動"知道"這些文檔的內(nèi)容。上下文注入就是把檢索到的文檔"喂"給 LLM 的過程。

檢索結(jié)果: 3段相關(guān)文檔
    │
    ▼
上下文注入: 把文檔組織好,拼進 Prompt
    │
    ▼
LLM 讀到這些文檔,基于它們生成回答

聽起來簡單,但怎么拼、拼多少、拼什么順序、加什么指令,直接決定了最終回答的質(zhì)量。


一、最簡單的注入方式

Prompt = 指令 + 檢索到的文檔 + 用戶問題

具體形式:
┌──────────────────────────────────────────────┐
│ 請根據(jù)以下參考資料回答用戶的問題。              │  ← 系統(tǒng)指令
│ 如果資料中沒有相關(guān)信息,請如實說明。            │
│                                              │
│ 【參考資料】                                  │  ← 檢索到的文檔
│ [1] iPhone 15 Pro 搭載 A17 Pro 芯片,        │
│     采用3nm工藝,性能提升顯著...              │
│ [2] 電池容量為3274mAh,支持USB-C充電...       │
│ [3] 起售價7999元,有四種顏色可選...            │
│                                              │
│ 【用戶問題】                                  │  ← 用戶原始問題
│ iPhone 15 Pro 值不值得買?                    │
└──────────────────────────────────────────────┘

這就是最基礎(chǔ)的上下文注入。但實際工程中遠比這復(fù)雜。


二、Prompt 結(jié)構(gòu)設(shè)計

2.1 基礎(chǔ)三段式

┌──────────────────────────────────────────┐
│  System Prompt (系統(tǒng)指令)                 │
│  告訴 LLM 它的角色和行為規(guī)則              │
├──────────────────────────────────────────┤
│  Context (檢索到的上下文)                 │
│  從向量數(shù)據(jù)庫檢索到的文檔片段              │
├──────────────────────────────────────────┤
│  User Query (用戶問題)                   │
│  用戶的原始提問                           │
└──────────────────────────────────────────┘

2.2 完整工程級結(jié)構(gòu)

┌──────────────────────────────────────────────────┐
│  System Prompt                                   │
│  ┌────────────────────────────────────────────┐  │
│  │ 角色定義: 你是一個專業(yè)的數(shù)碼產(chǎn)品顧問         │  │
│  │ 行為約束: 只根據(jù)提供的資料回答               │  │
│  │ 輸出格式: 分點回答,給出明確建議             │  │
│  │ 兜底策略: 資料不足時如實說明                 │  │
│  └────────────────────────────────────────────┘  │
├──────────────────────────────────────────────────┤
│  Context (上下文)                                │
│  ┌────────────────────────────────────────────┐  │
│  │ 元數(shù)據(jù): [來源: Apple官網(wǎng)] [更新: 2024-09]   │  │
│  │ 內(nèi)容: iPhone 15 Pro 搭載 A17 Pro 芯片...   │  │
│  ├────────────────────────────────────────────┤  │
│  │ 元數(shù)據(jù): [來源: 評測文章] [更新: 2024-10]    │  │
│  │ 內(nèi)容: 電池實測續(xù)航8.5小時...                │  │
│  ├────────────────────────────────────────────┤  │
│  │ 元數(shù)據(jù): [來源: 價格平臺] [更新: 2024-11]    │  │
│  │ 內(nèi)容: 當(dāng)前最低價格6899元...                 │  │
│  └────────────────────────────────────────────┘  │
├──────────────────────────────────────────────────┤
│  Chat History (對話歷史, 可選)                    │
│  ┌────────────────────────────────────────────┐  │
│  │ 用戶: 我在考慮換手機                        │  │
│  │ 助手: 您目前用的是什么機型?                 │  │
│  │ 用戶: iPhone 13                            │  │
│  └────────────────────────────────────────────┘  │
├──────────────────────────────────────────────────┤
│  User Query                                      │
│  ┌────────────────────────────────────────────┐  │
│  │ iPhone 15 Pro 值不值得買?                  │  │
│  └────────────────────────────────────────────┘  │
└──────────────────────────────────────────────────┘

三、上下文注入的核心策略

3.1 文檔數(shù)量控制(Top-K 選擇)

檢索返回很多結(jié)果,不能全塞進去:

問題: LLM 上下文窗口有限(4K/8K/32K/128K tokens)

檢索返回 20 條結(jié)果:
  #1  score=0.96  "iPhone 15 Pro 芯片..."        ← 高度相關(guān)
  #2  score=0.94  "iPhone 15 Pro 電池..."        ← 高度相關(guān)
  #3  score=0.91  "iPhone 15 Pro 價格..."        ← 高度相關(guān)
  #4  score=0.85  "iPhone 15 對比 14..."         ← 相關(guān)
  #5  score=0.80  "蘋果發(fā)布會總結(jié)..."            ← 有點相關(guān)
  ...
  #15 score=0.55  "三星 Galaxy S24..."           ← 不太相關(guān)
  #20 score=0.40  "手機殼推薦..."               ← 無關(guān)

策略:
  方式1: 固定 K=5,取前5條
  方式2: 設(shè)置閾值 score>0.85,動態(tài)取
  方式3: 固定 K + 閾值結(jié)合,取 Top-5 且 score>0.8

太多的問題:

  • 超出上下文窗口
  • 無關(guān)內(nèi)容干擾 LLM,降低回答質(zhì)量("噪聲淹沒信號")
  • 成本增加(按 token 收費)

太少的問題:

  • 信息不夠,LLM 無法生成完整回答
  • 遺漏關(guān)鍵細節(jié)

經(jīng)驗值:

簡單事實問答:  K = 3~5
復(fù)雜分析問答:  K = 5~10
長文檔總結(jié):    K = 10~20
多輪對話:      K = 3~5 (留空間給對話歷史)

3.2 文檔排序策略

相關(guān)性排序(默認):

按檢索分?jǐn)?shù)從高到低:
[1] score=0.96  最相關(guān)的放最前面
[2] score=0.94
[3] score=0.91

Lost in the Middle 問題:

研究發(fā)現(xiàn) LLM 有個特點——對開頭和結(jié)尾的內(nèi)容記憶最深,中間容易忽略。

LLM 對不同位置信息的關(guān)注度:

位置:    [開頭]  [中間偏前]  [正中間]  [中間偏后]  [結(jié)尾]
關(guān)注度:   高        中         低         中        高

示意圖:
關(guān)注度
  ▲
  │ ██                                         ██
  │ ████                                     ████
  │ ██████                                 ██████
  │ ████████         ████████████         ████████
  │ ██████████████████████████████████████████████
  └──────────────────────────────────────────────?
   開頭                 中間                  結(jié)尾

應(yīng)對策略——三明治排列:

普通排列:
[1] 最相關(guān)    ← LLM 重點關(guān)注 ?
[2] 次相關(guān)    ← LLM 關(guān)注減弱
[3] 第三相關(guān)  ← LLM 最容易忽略 ?
[4] 第四相關(guān)  ← LLM 關(guān)注回升
[5] 第五相關(guān)  ← LLM 重點關(guān)注 ?

三明治排列 (把最重要的放兩頭):
[1] 最相關(guān)    ← LLM 重點關(guān)注 ?
[3] 第三相關(guān)  ← 無所謂
[5] 第五相關(guān)  ← 無所謂
[4] 第四相關(guān)  ← 無所謂
[2] 次相關(guān)    ← LLM 重點關(guān)注 ?

3.3 元數(shù)據(jù)注入

光注入原文不夠,加上元數(shù)據(jù)能讓 LLM 更好地判斷和引用:

不帶元數(shù)據(jù):
[1] iPhone 15 Pro 搭載 A17 Pro 芯片...

帶元數(shù)據(jù):
[1] [來源: Apple官網(wǎng)] [日期: 2024-09-15] [類型: 產(chǎn)品介紹]
    iPhone 15 Pro 搭載 A17 Pro 芯片...

LLM 就能回答:
"根據(jù) Apple 官網(wǎng) 2024年9月 的信息,iPhone 15 Pro 采用了..."
  → 有出處,可驗證,更可信

常見元數(shù)據(jù)類型:

文檔級:
  - 來源 (source): Apple官網(wǎng) / 評測文章 / 用戶評價
  - 日期 (date): 2024-09-15
  - 作者 (author): xxx評測
  - 文檔標(biāo)題 (title): iPhone 15 Pro 詳細評測

chunk級:
  - 所屬章節(jié) (section): 第三章 - 性能測試
  - 頁碼 (page): P.23
  - chunk編號: chunk_3 of 15
  - 相似度分?jǐn)?shù): 0.94

3.4 上下文壓縮(Context Compression)

當(dāng)檢索到的內(nèi)容太長,可以先壓縮再注入:

原始 chunk (500 tokens):
"iPhone 15 Pro 是蘋果公司于2023年9月12日在Apple Park
 發(fā)布的旗艦智能手機。發(fā)布會由Tim Cook主持。當(dāng)天天氣晴朗,
 現(xiàn)場座無虛席。該手機搭載了全新的A17 Pro芯片,基于臺積電
 3nm工藝制造。芯片擁有190億個晶體管。GPU性能比上一代
 提升了20%。支持硬件級光線追蹤。存儲方面提供256GB、
 512GB和1TB三個版本..."

用戶問的是 "A17芯片性能如何"

壓縮后 (150 tokens):
"iPhone 15 Pro 搭載 A17 Pro 芯片,臺積電3nm工藝,
 190億晶體管。GPU性能比上一代提升20%,支持硬件級光線追蹤。"

只保留和問題相關(guān)的信息,去掉無關(guān)描述

三種壓縮方式:

方式 做法 優(yōu)缺點
LLM 提取 用一個小模型先提取相關(guān)句子 效果好,但多一次 LLM 調(diào)用
關(guān)鍵句抽取 計算每句話與 query 的相似度,取高分句 快,不需要額外模型
摘要生成 用 LLM 生成文檔摘要后注入 適合長文檔,但可能丟細節(jié)

3.5 多輪對話中的上下文管理

多輪對話時,Prompt 里不只有檢索文檔,還有對話歷史,空間更緊張:

總上下文窗口: 8192 tokens

分配:
  System Prompt:     ~200 tokens
  檢索文檔:          ~3000 tokens
  對話歷史:          ~2000 tokens
  用戶當(dāng)前問題:       ~100 tokens
  保留給回答:        ~2500 tokens
  安全余量:          ~400 tokens

對話歷史的管理策略:

策略1: 滑動窗口 —— 只保留最近 N 輪對話

  第1輪: 用戶問A → 回答A      ← 丟棄
  第2輪: 用戶問B → 回答B(yǎng)      ← 丟棄
  第3輪: 用戶問C → 回答C      ← 保留
  第4輪: 用戶問D → 回答D      ← 保留
  第5輪: 用戶問E (當(dāng)前)        ← 當(dāng)前

策略2: 摘要壓縮 —— 早期對話壓縮成摘要

  [摘要] 用戶在咨詢iPhone 15 Pro,關(guān)注芯片性能和價格
  第4輪: 用戶問D → 回答D      ← 保留原文
  第5輪: 用戶問E (當(dāng)前)        ← 當(dāng)前

策略3: 關(guān)鍵輪次保留 —— 只保留和當(dāng)前問題相關(guān)的歷史輪次

  對話歷史5輪,只有第2輪和第4輪與當(dāng)前問題相關(guān)
  → 只保留第2輪和第4輪

3.6 查詢改寫(Query Rewriting)

有時用戶的問題不適合直接拿去檢索,先改寫再檢索效果更好:

場景: 多輪對話

第1輪: 用戶: "介紹一下 iPhone 15 Pro"
第2輪: 用戶: "它的電池怎么樣?"
                ↑
         "它"指什么? 直接拿 "它的電池怎么樣" 去檢索
         檢索不到有效結(jié)果!

改寫后: "iPhone 15 Pro 的電池續(xù)航怎么樣?"
         → 現(xiàn)在能檢索到了 ?

改寫策略:

策略1: 指代消解
  "它的電池" → "iPhone 15 Pro 的電池"

策略2: 意圖擴展
  "iPhone好不好" → "iPhone 15 Pro 優(yōu)缺點評測"

策略3: 多查詢生成 (一個問題變多個)
  "iPhone 15 Pro 值不值得買?"
    → 查詢1: "iPhone 15 Pro 性能評測"
    → 查詢2: "iPhone 15 Pro 價格性價比"
    → 查詢3: "iPhone 15 Pro 用戶口碑"
  分別檢索,合并結(jié)果,覆蓋更全面

策略4: HyDE (假設(shè)性文檔嵌入)
  讓 LLM 先"假裝回答"用戶問題,生成一個假設(shè)性文檔
  用這個假設(shè)性文檔去檢索(而不是用問題本身)
  因為文檔和文檔的語義比問題和文檔更接近

四、Reranker 重排序

檢索返回的 Top-K 是用 Embedding 向量的相似度排序的。但 Embedding 是分別編碼 query 和 document 的(雙塔模型),精度有限。

Reranker 用交叉編碼器(Cross-Encoder)對 query 和 document 聯(lián)合打分,更精準(zhǔn):

雙塔模型 (Embedding檢索):
  Query  → Encoder → 查詢向量 ┐
                               ├→ 余弦相似度 → 0.92
  Doc    → Encoder → 文檔向量 ┘

  Query 和 Doc 分開編碼,交互不夠充分

交叉編碼器 (Reranker):
  [Query + Doc] → Encoder → 相關(guān)性分?jǐn)?shù) → 0.87

  Query 和 Doc 拼在一起編碼,每個詞都能看到對方
  理解更深入,但計算更慢

兩階段流程:

向量檢索 (快,粗排): 100萬條 → Top-50     ~10ms
Reranker (慢,精排): Top-50  → Top-5      ~100ms

先用向量快速縮小范圍,再用 Reranker 精細排序

五、完整的上下文注入流水線

用戶: "iPhone 15 Pro 值不值得買?"
  │
  ▼
① 查詢改寫
  │ 結(jié)合對話歷史消解指代,擴展意圖
  │ → "iPhone 15 Pro 性能價格優(yōu)缺點評測"
  ▼
② 向量檢索 (Top-20)
  │ Encoder編碼 → 向量庫檢索 → 20條候選
  ▼
③ Reranker 重排序 (Top-5)
  │ Cross-Encoder 精細打分 → 5條精選
  ▼
④ 上下文壓縮
  │ 去掉與問題無關(guān)的句子,保留關(guān)鍵信息
  ▼
⑤ 元數(shù)據(jù)附加
  │ 給每條文檔加上來源、日期等標(biāo)簽
  ▼
⑥ 排序策略
  │ 三明治排列 / 相關(guān)性排序
  ▼
⑦ Prompt 組裝
  │ System + Context + History + Query
  ▼
⑧ LLM 生成回答
  │
  ▼
"根據(jù) Apple 官網(wǎng)和多個評測的信息,
 iPhone 15 Pro 搭載 A17 Pro 芯片...
 綜合來看,如果你目前使用 iPhone 13,
 升級到 15 Pro 是值得的,因為..."

六、常見問題與調(diào)優(yōu)

問題 原因 解決方案
LLM 回答"我不知道"但文檔里有答案 文檔被放在了中間位置,LLM 忽略了 用三明治排列,或減少文檔數(shù)量
回答和文檔內(nèi)容矛盾 LLM 的預(yù)訓(xùn)練知識干擾 System Prompt 強調(diào)"只根據(jù)提供的資料回答"
回答太籠統(tǒng)不具體 檢索到的是泛泛而談的文檔 減小 chunk_size,讓檢索更精準(zhǔn)
回答包含過時信息 檢索到了舊文檔 元數(shù)據(jù)加時間過濾,優(yōu)先取最新文檔
多輪對話越聊越差 對話歷史占用太多空間 用滑動窗口或摘要壓縮歷史
回答混入了無關(guān)內(nèi)容 Top-K 太大,混入了低相關(guān)文檔 降低 K 值,或加相似度閾值過濾
用戶問題太模糊檢索不準(zhǔn) 短查詢信息量不足 加查詢改寫,或多查詢擴展
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

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

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