让AI改个登录模块,支付系统崩了
上周我用 Cursor 重构一个老项目,差点把自己送走。
事情是这样的。那个电商后台大概有 200 多个文件,我懒得细看,直接把整个项目丢给 AI,然后敲了一行:"帮我把用户认证模块从 JWT 改成 OAuth2。"
它噼里啪啦一顿输出。我扫了一眼,变量命名风格没问题,目录结构也对,就直接合了。当时是周四下午 4 点半,我还想着今天能早点走。
结果周五上午测试组杀过来,说支付流程全线崩溃。
我排查了将近三个小时,最后发现问题藏在一个特别恶心的地方——AI 生成的 OAuth 回调地址,用的是我们三个月前废弃的旧域名。那个域名在项目文档里明明标了"已弃用",但因为我无脑塞了整个项目进去,AI 反而被这些过时信息带偏了。
教训:上下文不是越多越好。
上下文窗口到底有多"贵"
先简单解释一下。现在主流的 AI 编程助手,不管是 Copilot、Cursor 还是国产的通义灵码,底层都是大模型。这些模型有个"上下文窗口",就是它能一次性看到多少内容。
打个比方,上下文窗口就像你的办公桌:
- 桌面太小(4K tokens),只能放当前正在写的这个函数
- 桌面中等(32K tokens),能放下整个文件加几个依赖
- 桌面超大(128K 甚至 1M tokens),理论上能放下整个项目
但问题是,桌面大了不代表效率高。
我上个月专门测过一次。在 128K 的上下文窗口下,把整个项目无脑丢进去:
- AI 响应速度下降大概 40%
- 代码准确率反而降低 15% 左右
- Token 消耗翻了 3 到 5 倍
这就好比你桌上堆了两百份文件,找个订书机反而要翻半天。而且大模型的注意力机制本身就有"中间丢失"的问题——上下文中间部分的信息,它天然就记不太住。2024 年底有几篇论文专门讨论这个,感兴趣可以搜"lost in the middle"。
三种我实际在用的方案
踩过几次坑之后,我开始系统地折腾上下文管理这件事。目前实践下来,有三种方案比较靠谱。
方案一:摘要式压缩
这个思路很简单——别让 AI 记住所有细节,只让它记住"摘要"。
具体做法是,在对话轮次之间,用一个轻量级模型把历史对话做摘要提取:
def compress_context(conversation_history, max_tokens=2000):
if count_tokens(conversation_history) <= max_tokens:
return conversation_history
# 保留最近 3 轮完整对话
recent = conversation_history[-3:]
# 对更早的对话做摘要
older = conversation_history[:-3]
summary = llm.summarize(older,
instruction="提取关键技术决策和代码变更")
return summary + recent我在一个 React 项目里试过。原本聊到第 20 轮的时候,AI 就开始忘记我们约定好的组件命名规范。加上摘要压缩后,聊到 50 轮它还能记住核心约定。
等等,这里我要更正一下——不是 50 轮都记住,是大部分核心约定能保留。像那种"这个变量用驼峰还是下划线"的细节还是会丢。但说实话,这种细节丢了反而好,因为太长的对话本来就应该重新确认一遍规范。
优点:实现简单,大多数场景够用
缺点:会丢细节,不适合需要精确追溯的场景
方案二:结构化记忆
这个方案更进阶。思路是把 AI 的记忆分层存储,类似计算机的缓存机制。
我现在的做法:
- **热记忆**:当前会话的完整上下文(最近 10 轮)
- **温记忆**:当前文件 + 直接引用的依赖(实时检索)
- **冷记忆**:项目文档、架构决策、编码规范(向量化存储)
这里有个坑我踩过。最早用关键词匹配来检索冷记忆,结果"用户登录"和"用户认证"就匹配不上。后来换成向量嵌入,效果好很多。
嗯...这个比较复杂。搭建成本确实高,需要维护向量数据库。我现在用的是 Qdrant 自建,轻量够用。团队里也有人直接用 Pinecone 的云服务,省心但贵一些。
const projectMemory = {
hotContext: [],
warmContext: [],
async retrieveColdMemory(query) {
const queryEmbedding = await getEmbedding(query);
return vectorDB.search(queryEmbedding, { topK: 5 });
}
};优点:记忆持久,跨会话也能保持一致
缺点:搭建成本高,小项目杀鸡用牛刀
方案三:滑动窗口 + 重要性评分
这是我现在最常用的方案,算是前两种的折中。
核心逻辑是给每条信息打分,分数高的保留,分数低的压缩或丢弃:
- 用户明确说"记住这个":+10 分
- 涉及架构决策:+8 分
- 代码片段:+5 分
- 闲聊内容:+1 分
- 超过 10 轮未引用:每轮 -1 分
上下文快满的时候,优先淘汰低分内容。
这个方案的好处是灵活。有一次我跟 AI 讨论数据库设计,中间穿插了几句吐槽 MySQL 的玩笑话。按这个评分机制,玩笑话很快就被淘汰了,但表结构设计一直保留着。
据我了解,Cursor 内部大概也是类似的机制,只是他们的评分维度更多。2025 年初他们公开了一部分技术细节,有兴趣可以去看他们的博客。
我目前的工具箱
说点实际的。我现在日常开发中的组合:
- **日常编码**:Cursor + 自定义的滑动窗口规则
- **复杂重构**:先用方案一压缩历史,再开新会话
- **团队协作**:把编码规范、项目文档做成结构化的冷记忆库
工具方面,LangChain 和 LlamaIndex 都提供了不错的记忆管理组件。如果你用国产模型,通义千问的 Assistants API 也内置了类似的机制,不用自己从头造轮子。
一个还在折腾的方向
最近我在尝试一个更有意思的方案——让 AI 自己决定该记住什么。
思路是给 AI 一个"记事本"工具,它可以在对话过程中主动记录关键信息。下次对话开始时,先把记事本内容注入上下文。
初步测试下来,效果意外地好。AI 会在讨论到重要决策时主动记笔记,甚至会在后续对话中说"根据我们之前的讨论,你倾向于用方案 B..."
不过这个方案还在实验阶段。有时候 AI 会记一些莫名其妙的东西。上周它在我调试 CSS 的时候,郑重其事地记了一笔:"用户喜欢用 #ff6b6b 这个红色。"
哭笑不得。
上下文管理这事儿,说到底是个取舍的艺术。给太多信息,AI 会迷失;给太少,它会瞎猜。找到平衡点需要对自己的项目有足够的理解。
我现在养成了一个习惯:在开始复杂任务前,先花 5 分钟想清楚"哪些信息是 AI 真正需要的"。这 5 分钟往往能省下后面好几个小时的 debug 时间。
你们在用 AI 编程助手的时候,遇到过什么失忆导致的坑吗?或者有什么独家的上下文管理技巧?评论区聊聊。
#AI编程 #上下文管理 #工程实践 #效率工具
读者评论 3