📦 什麼是 Context Window?
💡 一句話理解 Context Window = AI 一次能「看到」多少內容。就像工作桌面大小——桌子越大,能同時攤開的資料越多。
2026 主流模型 Context Window
| 模型 | Context Window | 約等於 |
|---|---|---|
| GPT-4o | 128K tokens | ~10 萬字中文 |
| Claude Sonnet 4.6 | 200K tokens | ~15 萬字中文 |
| Gemini 2.5 Pro | 1M tokens | ~75 萬字中文 |
| DeepSeek V4 | 1M tokens | ~75 萬字中文 |
| GPT-4o-mini | 128K tokens | ~10 萬字中文 |
| Llama 3.1 405B | 128K tokens | ~10 萬字中文 |
⚠️ 能放不代表品質一樣好。研究顯示,當 context 超過 64K tokens,大部分模型在「中間位置」的資訊理解力會明顯下降(“Lost in the Middle” 問題)。
🤔 什麼時候 Context 不夠用?
| 場景 | 需要的 context | 問題 |
|---|---|---|
| 分析一本書 | 50-200K tokens | 大部分模型放得下,但品質不穩 |
| 分析一整個 codebase | 200K-2M tokens | 超過大部分模型上限 |
| 長對話(100+ 輪) | 50K+ tokens | Token 費用爆炸 |
| 知識庫問答 | 無限文件 | 不可能全塞進去 |
🔧 四大策略
策略 1:RAG(最常用)
不把所有資料塞進 context——只檢索最相關的段落。
全部文件(10 萬份)
↓ Embedding + 向量搜尋
最相關的 5 段(2000 tokens)
↓ 和問題一起送給 LLM
精準回答
適合: 知識庫問答、客服、文件搜尋
優點: context 用量極小、可擴展到無限文件量
缺點: 檢索品質決定回答品質
→ 詳見 RAG 完全指南
策略 2:Map-Reduce(處理超長文件)
把長文件切段,每段分別處理,最後合併結果。
def map_reduce_summarize(long_text, chunk_size=3000):
"""Map-Reduce 摘要:處理超長文件"""
# 1. Map:把長文切成小段,各自摘要
chunks = split_text(long_text, chunk_size)
summaries = []
for i, chunk in enumerate(chunks):
summary = client.chat.completions.create(
model="gpt-4o-mini", # 用便宜的模型做 Map
messages=[{
"role": "user",
"content": f"請摘要以下段落的重點(150 字內):\n\n{chunk}"
}],
max_tokens=200
).choices[0].message.content
summaries.append(summary)
print(f"Map {i+1}/{len(chunks)} 完成")
# 2. Reduce:合併所有摘要,生成最終摘要
combined = "\n\n".join(summaries)
final = client.chat.completions.create(
model="gpt-4o", # 用強模型做 Reduce
messages=[{
"role": "user",
"content": f"以下是一份文件各段落的摘要,請整合成一篇完整的摘要:\n\n{combined}"
}],
max_tokens=1000
).choices[0].message.content
return final
適合: 超長文件摘要、報告分析
優點: 理論上無文件長度限制
缺點: 各段獨立處理,可能遺漏跨段落的關聯
策略 3:Refine(迭代精練)
逐段讀取,每讀完一段就更新當前的理解。像人讀書一樣——邊讀邊記筆記。
def refine_analysis(chunks, question):
"""Refine:逐步精練回答"""
current_answer = "目前還沒有足夠資訊回答。"
for i, chunk in enumerate(chunks):
current_answer = client.chat.completions.create(
model="gpt-4o",
messages=[{
"role": "user",
"content": f"""根據以下新的資訊,更新你的回答。
## 問題
{question}
## 目前的回答
{current_answer}
## 新的資訊(第 {i+1} 段)
{chunk}
請整合新資訊,更新回答。如果新資訊和問題無關,保持現有回答不變。"""
}],
max_tokens=1000
).choices[0].message.content
print(f"Refine {i+1}/{len(chunks)} 完成")
return current_answer
適合: 需要跨段落理解的深度分析
優點: 保持上下文連貫性
缺點: 逐段處理速度慢、前面段落資訊可能被稀釋
策略 4:對話記憶管理
長對話(100+ 輪)的 token 會快速膨脹,需要策略管理。
Sliding Window(滑動窗口)
def sliding_window_chat(messages, max_context=20):
"""只保留最近 N 輪對話"""
system_msg = messages[0] # 永遠保留 system prompt
recent = messages[-max_context:] # 保留最近 20 輪
return [system_msg] + recent
Summary Memory(摘要記憶)
class SummaryMemory:
"""自動摘要壓縮歷史對話"""
def __init__(self, max_messages=10):
self.max_messages = max_messages
self.summary = ""
self.recent_messages = []
def add(self, role, content):
self.recent_messages.append({"role": role, "content": content})
# 對話超過上限時,壓縮舊對話為摘要
if len(self.recent_messages) > self.max_messages:
old = self.recent_messages[:5]
self.recent_messages = self.recent_messages[5:]
old_text = "\n".join(f"{m['role']}: {m['content']}" for m in old)
self.summary = client.chat.completions.create(
model="gpt-4o-mini",
messages=[{
"role": "user",
"content": f"將以下對話摘要為 100 字:\n\n之前的摘要:{self.summary}\n\n新對話:\n{old_text}"
}],
max_tokens=150
).choices[0].message.content
def get_messages(self, system_prompt):
msgs = [{"role": "system", "content": system_prompt}]
if self.summary:
msgs.append({
"role": "system",
"content": f"先前對話摘要:{self.summary}"
})
msgs.extend(self.recent_messages)
return msgs
💰 Token 省錢技巧
| 技巧 | 節省 | 做法 |
|---|---|---|
| 精簡 System Prompt | 20-40% | 刪除冗餘指令,用條列取代長文 |
| 壓縮歷史對話 | 50-70% | 用 Summary Memory 取代完整歷史 |
| 只傳必要的 context | 30-50% | RAG 只傳 top-3 相關段落 |
| 用便宜模型做 Map | 60-80% | Map-Reduce 的 Map 階段用 mini 模型 |
| 設定 max_tokens | 10-30% | 避免模型產生過長的輸出 |
| Prompt Caching | 50-90% | OpenAI/Anthropic 的 Prompt Cache 功能 |
Prompt Caching(重大省錢術)
當你的 System Prompt 或 context 很長且不常變時,API 會自動快取,減少 Token 計費。
# OpenAI Prompt Caching(自動啟用)
# 當 system prompt 超過 1024 tokens 且重複使用時
# 快取命中的 token 只收 50% 費用
# Anthropic Prompt Caching(需明確啟用)
response = client.messages.create(
model="claude-sonnet-4-20260514",
max_tokens=1000,
system=[{
"type": "text",
"text": LONG_SYSTEM_PROMPT, # 你的長 system prompt
"cache_control": {"type": "ephemeral"} # 啟用快取
}],
messages=[{"role": "user", "content": user_input}]
)
# 快取命中的 token 只收 10% 費用!
🆚 Long Context vs RAG:怎麼選?
| 面向 | Long Context | RAG |
|---|---|---|
| 文件數量 | 少量大文件 | 大量文件 |
| 成本 | 💰💰💰 每次都送全文 | 💰 只送相關段落 |
| 精度 | 可能 Lost in the Middle | 取決於檢索品質 |
| 速度 | 長 context 推理較慢 | 快(context 短) |
| 適合 | 單一文件深度分析 | 知識庫搜尋、客服 |
💡 實用建議
- 文件 < 50 頁 → 直接塞進 context(Long Context)
- 文件 > 50 頁或多份文件 → 用 RAG
- 需要跨文件比較 → Map-Reduce
- 兩者結合:RAG 先縮小範圍 → Long Context 做深度分析
❓ FAQ
Context Window 是越大越好嗎?
不一定。大 context window 有兩個問題:1) 成本高——128K tokens 的單次呼叫可能花幾塊美金 2) 品質不穩——“Lost in the Middle” 問題讓中間位置的資訊容易被忽略。針對性地用 RAG 檢索通常品質更好。
中文的 token 怎麼算?
中文大約每字 1-2 個 token。128K tokens ≈ 8-10 萬字中文。可以用 tiktoken 套件精確計算。注意不同模型的 tokenizer 不同,同一段文字的 token 數可能不一樣。
對話太長怎麼辦?
三種方案:1) Sliding Window——只保留最近 N 輪 2) Summary Memory——壓縮舊對話為摘要 3) RAG——把歷史對話存入向量 DB,需要時檢索。推薦 Summary Memory,兼顧成本和連貫性。