上下文注入在干什么?
前面幾步已經(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) | 短查詢信息量不足 | 加查詢改寫,或多查詢擴展 |