慣性聚合 高效追蹤和閱讀你感興趣的部落格、新聞、科技資訊
閱讀原文 在慣性聚合中打開

推薦訂閱源

小众软件
小众软件
博客园 - 叶小钗
有赞技术团队
有赞技术团队
大猫的无限游戏
大猫的无限游戏
博客园_首页
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
L
LangChain Blog
Hugging Face - Blog
Hugging Face - Blog
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
aimingoo的专栏
aimingoo的专栏
Blog — PlanetScale
Blog — PlanetScale
爱范儿
爱范儿
T
Tailwind CSS Blog
Jina AI
Jina AI
量子位
Stack Overflow Blog
Stack Overflow Blog
人人都是产品经理
人人都是产品经理
J
Java Code Geeks
V
Visual Studio Blog
月光博客
月光博客

博客园_首页

Plist 二进制格式 第30篇文章:一个大三计科生的自白 Manim如何在数学公式中完美显示中文? Docker 部署 RocketMQ 5 并发编程核心概念辨析 C#事务处理最佳实践:别再让“主表存了、明细丢了”的破事发生 CLI 是什么?为什么大厂突然集体卷命令行? 【从0到1构建一个ClaudeAgent】协作-自主Agent # linux红帽教程-手把手教学 UIImageView 设置图片不生效的原因排查 .NET生态下Native AOT兼容的Cron任务调度框架 Python 潮流周刊#147:Python 和 Ruby 的 JIT 故事 - 豌豆花下猫 可持久化线段树/主席树 学习笔记 如何实现 Claude Code 和 Codex 等 Agent CLI 的自动重试 - Newbe36524 WebSocket 连接池生产级实现:实时行情高可用与负载均衡 - Walter先生 关于代码注释的思考 MicroPython对接大模型:uopenai + 火山方舟实现文字聊天和图片理解 从词向量到大模型:NLP 技术演进浅记 LangChain使用deep agent并且加载SKILL 零成本打造专业域名邮箱:Cloudflare + Gmail 终极配置保姆级全攻略 【从0到1构建一个ClaudeAgent】协作-团队协议 - 程序员Seven 最小二乘问题详解20:无先验约束下的增量式SFM自由网平差 痞子衡嵌入式:大话双核i.MXRT1180之XIP应用里实现可靠Flash IAP的方法 AI Chat 封装, SemanticKerne.AiProvider.Unified 已发布 Windows下右键编辑js文件无法打开记事本——在注册表中使用环境变量 在后台服务中使用 Scoped 服务,为什么总是报错? H200 安装驱动并使用sglang启动模型 wireshark 抓包Trap上报告警内容 我用 AI 辅助开发了一系列小工具(2):图片压缩工具 [A Primer On MC and CC] 2.1 Memory Consistency 1 - 指令重排序和 SC 模型 Oracle数据库SCN推进技术详解与实践指南 玩转控件:封装个带图片的Label控件 Claude Code 4.7 真正该升级的不是模型,而是你的工作流 我用AI写了一个颜值拉满的桌面媒体播放器,全程没动一行代码,这就是AI编程新范式 5. WorkBuddy: 小龙虾的灵魂三件套,让你的小龙虾不只是工具 SQLite 分片方案实战:三种分片策略的深度对比 告别简陋 UI!一款基于 Fluent Design 和基于 WinUI 的开源免费、现代化的 Avalonia UI 控件库 关于二进制排列组合枚举的总结 AI开发-python-LangGraph框架(3-27-LangGraph从零实现大模型智能决策工作流) ElasticSearch主分片和副本分片概念详解 【002】HTTPS 粗解:证书、TLS 握手与对后端配置的影响 Hermes Agent 一周暴涨五万 Star,但我劝你别急着追 一个面向产品化的 Electron + Vue 3 桌面应用脚手架 明明连接的是Redis的DB0,为什么能查到DB3的数据? 【从0到1构建一个ClaudeAgent】协作-Agent团队 熟悉电子元器件之后,电子小白下一步该怎么走? MAF快速入门(23)通过C#类定义Skills .NET 高级开发 | 手写一个对象映射框架 FastAPI数据库ORM怎么选?我肝了三个Demo后,终于不再纠结了 mysqldump 参数拾遗:在遗忘与铭记之间
完整學習LLM(六):上下文窗口是什麼,為什麼模型會忘東西
养肥胖虎 · 2026-05-27 · via 博客园_首页

完整學習LLM(六):上下文窗口是什麼,為什麼模型會忘東西

好傢伙,

上一篇我們聊了 Embedding.

當時說到一個很關鍵的點:

Embedding 負責把文本變成向量.
RAG 負責根據語義找到相關資料.
大模型負責基於資料組織答案.

但這裡馬上就會遇到一個新問題:

資料找到了以後,到底怎麼交給大模型?

比如我問:

請根據這份部署文檔,告訴我 battle monitor 怎麼上線.

RAG 檢索到了 5 段資料.

歷史對話裡還有我前面問過的問題.

系統提示詞裡還寫著回答規則.

這些東西最後都要放到哪裡?

答案就是:

放進上下文窗口.

所以今天這篇就專門聊一個很基礎,但很容易誤解的概念:

上下文窗口是什麼?
為什麼模型會忘東西?
為什麼不是窗口越大就一定越好?

0.背景:為什麼要學上下文窗口

我最開始用大模型時,對它的感覺是:

它好像能記住我剛才說過什麼.

比如我先說:

我現在在寫一篇關於 RAG 的文章.

然後我再問:

幫我把剛才那個主題換一個標題.

模型通常能知道"剛才那個主題"指的是 RAG.

這就很像記憶.

但用久了以後會發現:

聊太長,它會忘.
資料太多,它會漏.
前面明明說過,後面它卻像沒看見.

這個時候就不能只說一句:

模型記性不好.

更準確的說法是:

這次請求裡,模型能看到的內容是有限的.

這個有限範圍,就是上下文窗口.

1.先給一個直覺:上下文窗口就是這次請求的可見範圍

我現在對上下文窗口的理解是:

上下文窗口 = 模型在一次請求裡能夠看到和處理的 token 範圍.

注意這裡有兩個關鍵詞:

一次請求
token 範圍

也就是說,模型不是把我們所有聊天內容都永久放在腦子裡.

每次調用模型時,系統會把一批內容打包給它.

這批內容可能包括:

系統提示詞
開發者提示詞
歷史對話
用戶當前問題
RAG 檢索出來的資料
工具調用結果
預留給模型輸出的空間

這些內容加起來,不能超過模型允許處理的上下文範圍.

可以先看這張圖:

上下文窗口的滑動直覺

這張圖想表達的是:

對話和資料是一條很長的流.
上下文窗口只覆蓋其中一段.
新問題和新資料進來時,太早的內容可能會離開窗口.

所以模型"忘了",很多時候不是它真的產生了人類意義上的遺忘.

而是:

那段內容沒有被放進這一次請求裡.

2.上下文窗口裡到底裝了什麼

很多人會把上下文窗口理解成:

聊天記錄長度.

這不算錯,但不完整.

上下文窗口不只是聊天記錄.

它更像一次請求的總預算.

裡面裝的東西可能很多:

系統規則
  -> 你要怎麼回答,哪些不能做

歷史對話
  -> 用戶前面問過什麼,模型前面答過什麼

當前問題
  -> 用戶這一次真正要問什麼

檢索資料
  -> RAG 找回來的文檔片段

工具結果
  -> 數據庫查詢結果,接口返回內容,代碼執行結果

輸出空間
  -> 模型接下來要生成答案的位置

這些東西都要佔 token.

所以一個很現實的問題是:

窗口不是隻給輸入用的.
輸出也要佔空間.

比如一個模型的上下文窗口最多能處理一批 token.

如果輸入已經塞得很滿,那留給輸出的空間就會變少.

反過來,如果希望模型輸出很長,輸入就不能無限塞.

這就是為什麼我說上下文窗口更像預算:

一次請求的上下文預算

這張圖裡最重要的是第二條:

RAG 資料塞太多時,模型不一定更聰明.

因為塞進去的內容越多,模型越需要在裡面找重點.

如果資料裡混進了很多無關內容,模型反而可能被幹擾.

這也是為什麼 RAG 系統不能只做一件事:

把所有搜索結果都扔給模型.

它通常還需要:

召回
重排
過濾低分片段
壓縮摘要
控制 TopK

說白了:

上下文窗口有限,所以要把最有價值的內容放進去.

3.為什麼模型會忘東西

這裡可以拆成三種情況.

第一種:內容根本沒進這次請求

這是最常見的.

比如我前面很早說過:

我的項目叫 Lighter.

但後面聊了很長.

如果系統為了控制上下文長度,把早期對話裁掉了.

那模型這次請求裡就看不到這句話.

它自然可能不知道 Lighter 是什麼.

這不是參數忘了.

而是:

這次輸入裡沒有這條信息.

第二種:內容進來了,但太靠前或太分散

有些時候,內容確實在上下文裡.

但上下文太長.

關鍵信息埋在中間.

模型可能沒有穩定抓住它.

這就涉及一個很有名的問題:

Lost in the Middle

簡單說就是:

長上下文裡,模型不一定能同等有效地利用每個位置的信息.

有些信息放在開頭或結尾更容易被用到.

埋在中間時,模型可能更容易漏掉.

所以長上下文不是萬能藥.

窗口變大以後,還要考慮:

哪些內容放前面
哪些內容放後面
哪些內容要壓縮
哪些內容要重複強調

第三種:用戶以為它是長期記憶

還有一種誤解是:

我告訴過模型一次,它以後就應該一直記得.

但大多數普通調用裡,模型並不會因為一次聊天就改寫自己的參數.

它能利用的通常是:

這次請求裡的上下文

如果系統有記憶功能,那也是另外一層工程能力.

比如:

把用戶偏好保存到數據庫
下次聊天前再取出來
重新塞進上下文

這和模型參數本身記住不是一回事.

可以用這張圖區分:

上下文窗口不等於長期記憶

這張圖裡我想強調一句話:

上下文窗口是臨時工作臺.
外部資料是資料庫.
模型參數是訓練時形成的能力.

這三件事不要混成一個東西.

4.用一個例子理解:為什麼它前面知道,後面又不知道

假設我們在寫一個後端部署文檔問答助手.

一開始用戶說:

我的項目是 battle monitor.
它由 Go API、PostgreSQL、Nginx 組成.

然後用戶問了很多問題:

數據庫怎麼配置?
Nginx 怎麼反代?
Docker Compose 怎麼寫?
日誌怎麼看?
健康檢查接口是什麼?

聊到後面,用戶突然問:

那這個項目上線前還要檢查什麼?

如果系統把所有歷史都完整塞進上下文,模型大概率知道"這個項目"指 battle monitor.

但如果歷史太長,系統只保留最近幾輪:

用戶: 日誌怎麼看?
助手: ...
用戶: 健康檢查接口是什麼?
助手: ...
用戶: 那這個項目上線前還要檢查什麼?

這時候模型可能只知道:

有日誌
有健康檢查
可能是某個項目

但它不一定知道:

這是 battle monitor
用了 Go API、PostgreSQL、Nginx

所以它可能會給一個泛泛的上線檢查清單.

這就解釋了為什麼有時候我們會覺得:

它前面明明知道,後面又忘了.

實際上更準確的流程是:

早期信息
  -> 曾經在上下文裡
  -> 後來窗口滑動
  -> 早期信息被裁掉
  -> 新請求裡看不到
  -> 回答變泛

5.上下文窗口和 RAG 是什麼關係

上一篇講 Embedding 時,我們說 RAG 大概是:

用戶提問
  -> 檢索相關資料
  -> 把資料交給模型
  -> 模型基於資料回答

現在可以把中間那步說得更準確一點:

把資料交給模型 = 把資料塞進上下文窗口.

所以 RAG 的效果不只取決於:

能不能搜到資料.

還取決於:

搜到的資料有沒有放進上下文
放進去的位置是否合理
放進去的資料是否太多
有沒有和用戶問題放在一起
有沒有保留足夠輸出空間

這也是為什麼一個 RAG 系統可能會出現這種情況:

向量數據庫確實搜到了正確文檔.
但模型最後回答還是不準.

原因可能不是 Embedding 錯了.

而是:

正確文檔被別的片段擠掉了
正確文檔埋在太長上下文中間
提示詞沒有要求模型優先依據來源
輸出空間不夠

所以工程上經常會做這些事:

只取 TopK
對召回結果 rerank
把長文檔壓縮成短摘要
把關鍵來源放到問題附近
讓模型按引用回答

這不是形式主義.

而是在管理上下文窗口.

6.上下文窗口越大越好嗎

我的答案是:

大窗口很有用,但不是越大就自動越好.

大窗口能解決一些問題.

比如:

能放更長的文檔
能保留更多歷史對話
能一次處理更多工具返回結果

這當然有價值.

但它也帶來新的問題:

輸入成本更高
響應可能更慢
無關內容更容易混進去
模型不一定能穩定利用所有位置的信息
調試更難

所以我現在更願意把上下文窗口當成一個資源.

不是說:

有多少塞多少.

而是問:

這次回答真正需要哪些信息?
哪些是噪音?
哪些可以摘要?
哪些必須原文保留?

這和寫代碼有點像.

內存大當然好.

但你不能因為內存大,就把所有東西都塞進一個函數.

上下文窗口也是一樣.

大窗口給了更大的空間.

但工程上還是要管理.

7.它和 Token、Embedding 的關係

到這裡,前面幾篇文章可以串起來了.

先是 Token:

文本進入模型之前,要先被切成 token.

然後是 Embedding:

文本可以被表示成向量,用來做語義相似度比較.

現在是上下文窗口:

模型一次請求最多能處理多少 token.

這三件事放在一起:

Token 決定文本怎麼被切開.
Embedding 幫我們找到相關資料.
上下文窗口決定這些內容最多能帶進去多少.

如果放到 RAG 裡,流程就是:

用戶問題
  -> 切成 token
  -> 生成向量
  -> 檢索相關資料
  -> 選擇一部分資料
  -> 塞進上下文窗口
  -> 模型生成答案

所以這篇文章其實是在回答上一篇留下的問題:

Embedding 找到資料以後,資料怎麼進入模型?

答案就是:

進入上下文窗口.

8.容易踩的坑

第一個坑:

以為上下文窗口等於模型記憶.

不是.

它更像一次請求的臨時工作臺.

第二個坑:

以為窗口越大,回答一定越好.

也不是.

窗口大隻是能放更多內容.

但內容是否相關、位置是否合理、提示詞是否清楚,仍然很重要.

第三個坑:

RAG 把資料全塞進去.

這很容易讓模型在一堆材料裡迷路.

應該先篩選,再重排,必要時壓縮.

第四個坑:

忽略輸出空間.

如果輸入塞滿了,模型後面生成答案的空間也會受影響.

第五個坑:

長對話不做總結.

長對話裡,可以定期把歷史壓縮成摘要.

再把摘要放進後續上下文.

這樣比機械保留所有歷史更穩.

9.這些引用到底說明了什麼

這裡還是按之前的習慣,把引用說人話一點.

OpenAI 的 Conversation State 文檔

OpenAI 的文檔裡會講到,多輪對話本質上需要把歷史消息作為上下文提供給模型.

這說明一件事:

模型能接上前文,不是因為它自動永久記住了所有對話.
而是因為系統把相關歷史作為輸入的一部分傳給了它.

所以這篇文章裡說的"上下文窗口是一次請求的可見範圍",可以從這裡理解.

Anthropic 的 Context Windows 文檔

Anthropic 的文檔會直接把 context window 解釋為模型一次能處理的文本範圍.

這對初學者最有幫助的一點是:

上下文窗口有上限.
輸入、輸出、歷史、資料都要在這個上限裡安排.

也就是說,窗口不是一個抽象概念.

它會直接影響你怎麼設計長文檔問答、Agent、RAG 和多輪對話.

Lost in the Middle 論文

這篇論文討論的是長上下文裡一個很現實的問題:

模型不一定總能穩定利用上下文中間的信息.

它提醒我們:

窗口變大,不代表所有位置的信息都一樣容易被模型用到.

所以在寫 RAG 或長上下文應用時,不能只追求塞更多.

還要關心信息的位置、排序和壓縮.

Attention Is All You Need

這篇論文是 Transformer 的起點之一.

本文引用它不是為了提前講 Transformer 細節.

而是為了引出下一篇:

模型為什麼能在一段上下文裡看不同 token 之間的關係?

這個問題就會走到 Transformer 和 Attention.

10.總結

這篇文章先記住一句話:

上下文窗口不是長期記憶.
它是模型一次請求裡能看到和處理的 token 範圍.

所以模型會"忘東西",常見原因是:

那段內容沒有進這次請求
內容太長導致關鍵信息被淹沒
用戶把上下文當成了長期記憶

放到工程裡,我現在會這樣理解:

Embedding 負責找資料.
上下文窗口負責裝資料.
Prompt 負責告訴模型怎麼用資料.
模型負責組織答案.

上下文窗口越大越有價值.

但它不是免死金牌.

真正要做的是:

把最該看的內容,放到模型這次最容易看見的位置.

下一篇我們繼續往下走:

Transformer 為什麼重要?
為什麼現在主流 LLM 基本都繞不開它?

參考資料

主要看它對多輪對話狀態的說明:模型能接上前文,是因為歷史消息被作為上下文提供給模型.

主要看它對 context window 的直觀解釋:模型一次能處理的內容有範圍,輸入和輸出都要在這個範圍裡安排.

主要看它說明長上下文裡的信息位置問題:上下文變長以後,模型不一定能同等穩定地使用每個位置的信息.

這篇論文提出 Transformer 架構,下一篇聊 Transformer 和 Attention 時會正式展開.