我在关于幻觉的博文中收到了以下评论。
我想知道你能不能写点关于失去上下文的内容。每次我问 4-5 个追问之后,它就完全忘记上下文是什么了。我称之为失智症……哈哈!
那么,我们开始吧!
让我们设想这样一个场景。你正与一个 AI 助手深入交谈——它在帮你调试代码,经过几个来回的交流,它开始真正理解你的问题。你向它提供了关于项目结构、你看到的具体错误以及你已经尝试过的方法等上下文。
然后,到了第 6 条消息,你问了一个跟进问题……它却像是面对一个完全陌生的人一样回复。"能多告诉我一些关于你的项目吗?" 它问道,完全忽略了你刚刚精心提供的五条消息的上下文。
听起来很熟悉吧?这是开发者在与 AI 助手协作时最常见的挫败感之一,它有一个专门的术语:上下文窗口限制。
每个大型语言模型(LLM)都有一个所谓的上下文窗口——可以把它想象成模型的短期记忆。这个窗口有固定的大小,以 token 为单位(大致上,1 token ≈ ¾ 个英文单词;中文则约 1 token ≈ 1-2 个汉字)。
当你向 AI 发送消息时,模型接收到的不仅仅是你的最新问题。提供商会发送整个对话历史——你发送的每一条消息、AI 的每一条回复,以及系统指令和工具定义。所有这些都需要塞进上下文窗口内。
下面是一个简单的可视化方式:
# 上下文工作方式的简化示例
context_window = 4096 # tokens
system_prompt = 200 # tokens
conversation = [
"用户: 帮我调试这个函数", # 6 tokens
"AI: 错误信息是什么?", # 5 tokens
"用户: TypeError: 'NoneType' object...", # 8 tokens
# ... 多条消息之后 ...
# 总对话: 4100 tokens
# 可用空间: 4096 - 200 = 3896
# 结果: 204 tokens 装不下 = 最早的消息被丢弃!
]
当对话超出上下文窗口时,必须有所取舍。AI 提供商必须决定保留什么、丢弃什么,通常情况下,他们优先丢弃最早的消息。
这被称为"滑动窗口"或FIFO(先进先出)策略。对话的开头被静默地推到了窗口边缘之外,你精心提供的上下文也随之丢失。
上下文窗口的大小在不同模型之间差异巨大:
| 模型 | 上下文窗口 |
|---|---|
| GPT-3.5 | 4,096 tokens |
| GPT-4 | 8,192 - 128,000 tokens |
| Claude 3 | 200,000 tokens |
| Gemini 1.5 Pro | 1,000,000+ tokens |
| Llama 3 | 8,192 tokens |
"但是等等," 你可能会说,"我用的是 GPT-4,有 128K 上下文!为什么它还是会忘记东西?"
问得好!即使有巨大的上下文窗口,仍然会出现两个额外的问题:
研究表明,LLM 最关注的是上下文窗口开头和结尾的信息,而中间的信息则倾向于……丢失。没错,字面意义上的"迷失在中间"。
这意味着,即使你早期的上下文在技术上可以放入窗口,模型可能并没有给予它应有的关注。
即使某个模型支持 128K tokens,AI 提供商和应用开发者往往也会设置更小的实际限制,以控制成本和响应时间。处理更多 tokens = 更多计算 = 更多成本 = 更慢的响应。
现在来看好消息——以下是你能实际采取的措施:
最简单的修复方法:定期总结已经讨论过的内容并重新陈述。
不建议:
用户:那第 42 行的错误呢?
建议:
用户:之前我们在调试 auth.js 中的身份验证流程。
函数 `validateToken()` 在第 42 行抛出了一个 TypeError。
我已经尝试过检查空值。还有什么可能导致这个问题?
这本质上是在自己管理上下文——你在显式地将重要的上下文重新注入到最新消息中。
许多 AI 编码工具(如 Cursor、Continue.dev 和 Cline)支持项目级上下文文件:
# CLAUDE.md 或 .cursorrules
## 项目上下文
- 这是一个使用 App Router 的 Next.js 14 应用
- 我们使用 Prisma 进行数据库访问
- 身份验证由 NextAuth.js 处理
- 数据库是 Supabase 上的 PostgreSQL
该工具会自动将这个文件注入到每一次对话中,因此即使聊天历史超出了窗口,这些关键上下文也会得以保留。
对于更复杂的应用,RAG 是首选的解决方案:
# 简化的 RAG 示例
query = "身份验证流程是怎样的?"
relevant_docs = vector_db.search(query, top_k=5)
context = "
".join(relevant_docs)
prompt = f"""使用以下上下文来回答问题。
上下文:{context}
问题:{query}"""
一些高级用户会维护一个"上下文缓冲区"——一个手动更新的运行摘要:
## 当前会话上下文(每 5 条消息更新一次)
- 项目:电商结算重构
- 分支:feat/checkout-v2
- 当前问题:PaymentIntent 创建失败,返回 402
- 已修改文件:checkout.ts, payment.ts, cart.ts
- 关键决策:使用 Stripe Elements,不使用自定义 UI
- 阻塞项:需要 API 密钥轮换审批
不同的 AI 工具处理上下文的方式不同:
业界正在积极解决这个问题:
AI 忘记你的上下文并不是一个 bug——这是当前基于 Transformer 模型的一个根本性架构限制。但理解为什么会发生,能让你有效地规避它。
对当今的开发者来说,最实用的方法是:
请记住:AI 并非故意无礼或健忘。它只是在自身架构的限制内运行。与这些限制合作,而非对抗它们。
原文出处:https://dev.to/aws/why-does-ai-forget-what-you-said-and-how-to-fix-it-52f6
一个热爱技术的程序员,喜欢分享前沿AI知识和开发经验。