Vibe编程的上下文管理
我们高估了AI的记忆能力,低估了它的编排能力。
微信 ezpoda免费咨询:AI编程 | AI模型微调| AI私有化部署
AI模型价格对比 | AI工具导航 | ONNX模型库 | Tripo 3D | Meshy AI | ElevenLabs | KlingAI | ArtSpace | Phot.AI | InVideo
我认为上下文管理是AI驱动开发中最重要的技能之一,但奇怪的是,与其他AI相关话题相比,几乎没有人谈论它。我们讨论提示词工程,讨论使用哪个模型,讨论智能体工作流和工具使用。但比所有这些都更重要的是,实际上决定你的AI会话产出优秀工作还是平庸工作的,是你管理上下文的能力(或者你是否真的在管理它)。
很多使用AI工具的开发者把所有这些"上下文"的讨论当作可以忽略的AI术语,这不难理解为什么。AI开发工具已经变得如此简单,一个经验丰富的开发者只需将氛围编程与批判性思维结合起来(这就是Sens-AI框架的核心理念),就能变得非常高效,甚至根本不需要考虑上下文。这很讽刺,因为尽管有大量"我实际上是个文盲但我靠氛围编程构建了一个完整的多租户SaaS平台"的文章,尽管大家都普遍担心AI会让所有开发者失业,但你多年来磨练的开发技能恰恰使你在使用AI编写代码时特别有效——而上下文管理正是这些技能真正大放异彩的地方。
为了确保我们达成共识,上下文(基本上)就是AI此刻正在思考的一切:你的提示词、到目前为止的对话、它读取的文件、你们一起做出的决定。当你启动一个全新的AI会话时,它的上下文会被清空,从零开始,只带着它被赋予的初始指令。管理上下文对于构建AI智能体和技能至关重要。但当你使用Claude Code、Cursor或Copilot等工具进行日常开发工作时,它也非常重要。上下文通常以token来衡量,而且数量是有限的。当上下文窗口(即AI模型一次能够处理和保留的最大信息量,包括输入和输出token)被填满时,AI开始丢失对事物的追踪,那时你就会看到它给出错误和奇怪的答案。
不幸的是,很多开发者读到像上一段这样的段落时,眼睛就呆滞了。不知怎么的,它被归类到我们大脑中与学习构建系统如何工作相同的地方:无聊的东西,我们不知为何真的不想去想它,因为它把我们带离了"真正的"编程。这很遗憾,因为当我们不理解上下文如何工作的基本原理时,我们浪费了大量时间。
例如,这里有一件我看到的开发者一直在做的、绝对不该做的事情。他们正深入一个AI编码会话,AI已经建立起了对他们代码库的详细理解(例如,它注意到了模式,正在做出好的决策等)。然后他们开始看到"压缩对话"的消息,或者注意到Cursor或Copilot中的上下文使用指示器在填满,而他们并不真正知道这意味着什么。但他们学到了关闭会话并开始一个新会话似乎能解决这个问题。不幸的是,他们所做的只是用完全失忆代替了压缩。新会话继续运行,产生的输出看起来很好,但它给出的答案更差,生成的代码也更差,因为它从不完整的信息中工作。
真正奇怪的是,我在2006年,远在AI出现之前,就在《应用软件项目管理》(Applied Software Project Management)中写了关于非常相似的事情:缺失的需求尤其阴险,因为它们很难被发现。我当时写的是需求,而不是AI上下文,但问题是相同的。我已经写过提示词工程就是需求工程,而这是另一个平行的例子成立的领域。当需求缺失时,没有工件来标记它,你最终只会得到不做它应该做的事情的代码。当AI会话中缺少上下文时,没有错误信息告诉你AI忘记了什么;你只会得到更差的答案。
糟糕的上下文管理的成本实际上是可衡量的。Microsoft Dev Blog上的一位开发者最近计时了他自己的重新定向开销,发现他每天花了一个多小时向AI重新解释它在之前会话中已经知道的事情。他不是一个人。现在已经有了整个框架和托管服务致力于给智能体持久记忆,从查询Copilot本地会话数据库的轻量级CLI到Cloudflare的托管记忆服务。其中一些工具确实有用,但它们是你需要评估、集成和维护的解决方案,然后才能帮助你。
我在本文和下一篇文章中的目标是给你四件你可以今天就做的事情,使用你已经使用的任何AI工具。本文涵盖问题:为什么上下文管理很重要,以及上下文丢失如何影响你的AI输出的质量。下一篇文章涵盖在构建Quality Playbook和Octobatch中出现的具体实践,这些是你可以在自己的提示词、技能和智能体中立即使用的东西。我将使用来自这些项目的真实例子,因为我认为它们有一些你可以借鉴的好例子。
1、我们在两个方向上都误解了AI
我认为贯穿所有这些的主线是开发者既高估又低估了AI。我们高估了它能记住多少东西,以及它为我们记住事物和做决策的能力。所以我们就把一堆东西塞进上下文窗口,假设AI会搞定一切,然后当它产生幻觉或忘记时就会感到恼火。
另一方面,我们严重低估了它作为编排器的能力。你的提示词不仅仅要问一个问题或让AI生成什么东西。你可以给它一个多步骤的工作流,每一步都将其结果写入文件,AI会协调整个过程,派生子任务并在中断的地方继续。
当开发者不认真对待上下文管理或编排时,你会得到一个特定的循环。他们把上下文窗口当作无限的,把所有东西都塞进去。然后当会话变得太长,AI开始丢失追踪时,他们就把一切都扔掉,重新开始。他们从不考虑替代方案,即设计工作流让AI跨独立会话从外部化文件中工作。
我在构建Quality Playbook时发现了这一点。上下文管理在会话内部工作得如此之好,以至于我意识到会话本身就是瓶颈。我在一个提示词中运行playbook。我想我在一个Copilot GPT-5.4会话中有超过1500万token的记录,那个会话运行了几个小时,我并行运行了八个。顺便说一句,这就是为什么我被Copilot限速了54小时,这完全公平。
playbook在运行过程中将一切都写入文件,这就是为什么那些运行能够持续那么长时间。但我不想要这种行为。在单个会话中运行1500万token是很昂贵的,如果你使用的是按量付费的API token而不是像Copilot或Claude Max或Cursor这样的固定费率计划,这种使用量可能会让你大吃一惊。我想让那些不想一次性消耗那么多资源的开发者也能使用这个playbook。而且因为上下文已经外部化到文件了,拆分成独立阶段变得很容易。
2、让AI在工作过程中把上下文写下来
在我介绍管道如何拆分之前,我想谈谈使拆分首先成为可能的实践:在工作过程中将开发上下文存储在文件中。
我不是指在会话结束时让AI导出笔记,或者事后写一份"经验教训"文档。我的意思是从一开始就将它融入到你给AI的实际指令中,让它在工作过程中持续地编写和更新上下文。对于Octobatch,即我智能体工程的第一个实验批量LLM编排器(我在"意外编排器"中写了开发过程),我让AI在每个文件夹中编写开发者上下文,这确实使启动新会话变得非常容易。
这在实践中是这样的。在Octobatch上的每个新Claude Code会话都从一行开始:"读取ai_context/DEVELOPMENT_CONTEXT.md并引导自己继续开发。"该文件包含一个加载序列:先读这个,然后扇出到scripts/、tui/、pipelines/中的组件级CONTEXT.md文件,每个都在适当的细节级别描述自己的子系统。到AI读完时,它就知道项目是什么、如何构建、当前在进行什么以及活跃的bug是什么。
我认为这是左移。与其在每个提示词中放约束(不要使用additionalProperties: false,始终用–limit 3测试),不如让这些规则存在于CONTEXT.md文件中。提示词保持干净,因为文档做了繁重的工作。
更新上下文文件是每个任务的一部分。在我们提交任何东西之前,我让AI审查上下文文件,确保它们反映了我们刚刚做了什么。如果我们添加了功能或修复了bug,上下文文件应该在提交之前反映这一点。过时的上下文导致与过时的文档相同的问题,只不过更糟,因为AI实际上依赖它来做决策。
我想明确说明我所说的"开发上下文"是什么意思。具体来说,它是新AI会话加速所需的信息:项目是什么、如何构建以及沿途做了哪些决策。像Claude Code这样的工具在每个会话开始时从像AGENTS.md这样的文件读取开发上下文(你实际上可以去那个网站了解更多),如果你在构建开发上下文和保持更新方面做得足够彻底,你可以让它们完全引导好。它们是你AI会话的蓝图。我在《应用软件项目管理》中写过,没有需求构建软件类似于没有蓝图建造房子。在没有外部化上下文的情况下运行AI会话是同样的错误。你依赖的是某人头脑中的东西,而不是写下来的东西。而当你与AI合作时,"某人的头脑"是一个会被压缩或丢弃的上下文窗口。
最重要的是我头脑中的东西与AI头脑中的东西一致。上下文文件只是帮助我们弄清楚我们是否达成一致的便捷方式。当我在一个有良好DEVELOPMENT_CONTEXT.md的文件夹中启动一个新的Claude Code会话时,AI读取它,我们立即对齐。当我在没有它的情况下启动会话时,AI必须从头开始重新发现一切,它总是会遗漏东西。重新发现总是有损的。
如果你还没有把写上下文文件作为工作流的一部分,那么我接下来要描述的所有更高级的技巧都无关紧要。这是基础。
3、包含原因,否则AI会撤销你的决策
这些上下文文件中有一个具体的东西必须包含进去,我花了一段时间才学到为什么它如此重要:每个决策背后的推理。
Octobatch的DEVELOPMENT_CONTEXT.md有一个叫做"关键技术学习"的部分,有49个条目,每个都采用特定格式:发生了什么、为什么重要、什么时候发现的、在代码中的哪里适用。该部分的顶部有一条加粗的注意事项:"重要:始终包含每项学习的推理('原因')。这可以防止未来的会话'重构'一个经过深思熟虑的决策。"
那条注释在那里是因为没有它,AI会完全那样做。我在Octobatch中有一个案例,我们使用递归的set_timer()而不是set_interval()来自动刷新,因为Textual的set_interval()回调在被推送的屏幕上不能可靠地服务。如果上下文文件中没有"原因",未来的会话会查看那段代码,看到一个"更干净"的替代方案,然后帮助性地把它重构回被破坏的方式。
同样的原则适用于质量标准。不要只说"核心逻辑90%的覆盖率"。要说"核心逻辑90%的覆盖率,因为表达式求值涉及随机性和种子设置,细微的bug会产生看似合理但错误的输出。醉酒水手重新播种bug通过了所有视觉检查。只有统计验证发现顺序种子创建了相关性偏差(77.5%落入水中,而不是理论上的50/50)。"没有"原因",未来的AI会话会将覆盖率目标往下压。任何没有附上理由的标准或架构决策或异常的代码模式都有被不知道它在解决什么问题的AI优化掉的风险。
4、垃圾回收问题
很多人喜欢把上下文窗口说成你的AI的短期或工作记忆,把持久化到磁盘的上下文说成长期记忆。就个人而言,我不确定那些与人类记忆的类比效果有多好。我认为找到与我们管理代码中内存的方式类似的思考上下文的方法要有用得多。
我特别觉得将上下文压缩与垃圾回收进行比较很有帮助——同样,不是完美的类比,但很有用。当你看Java中的GC图时,你会看到内存慢慢填满,然后在每次GC后突然下降。那个下降是运行时找出什么仍然被引用并释放其他一切。
上下文窗口做同样的事情。你的对话积累token,AI的上下文窗口填满,然后压缩发生。工具(或模型)决定保留什么和丢弃什么。压缩是有损的和自动的,你无法控制什么幸存下来。
Java开发者花了几十年学习设计他们的分配模式,这样垃圾回收就不会破坏任何重要的东西。AI开发者需要学习同样的事情,而且学习曲线应该更短,因为概念直接转移。
当你让AI把重要状态写入文件时,你是在把它从那个易失空间中提升出来。这出奇地容易做到。只需告诉AI把它的上下文写到一个Markdown文件。例如,你可以将与特定域相关的所有上下文放到一个特定文件中,比如如果AI注意到了一个行为契约,你可以让它把所有相关上下文写入一个叫CONTRACTS.md的文件。如果它做了一个设计决策,那可以放入DEVELOPMENT_CONTEXT.md——这是我经常用来记录引导新AI会话处理代码所需的所有重要上下文的模式。这些文件存在于磁盘上,在上下文窗口之外,压缩无法触及它们。但如果你在没有外部化任何东西的情况下开始新会话,你就像关闭应用程序并丢失了内存中的所有东西一样。
我第一次构建Octobatch的批量编排器时,它是一个带有内存状态和很多希望的Python脚本。它对小批量有效,但在规模上崩溃了,这基本上就是大多数开发者现在对AI上下文所做的事情:把所有东西保留在上下文窗口中,希望它能撑住,尽管一旦会话变长和代码库变复杂,这就会停止工作。
5、很容易陷入上下文管理的某一个极端
Quality Playbook的存在部分就是因为这个问题。当我构建需求管道时,我发现单次需求生成在大约70个需求后就耗尽了注意力。模型忘记了它之前注意到的行为契约。而且这是完全不可见的。你得不到堆栈跟踪或错误信息或任何类型的警告,只有不完整的输出,无法知道缺少了什么。
缺陷越久不被纠正,它就越根深蒂固,在它之上构建的东西就越多。上下文漂移的工作方式也是如此。当AI在会话早期丢失对一个设计决策的追踪时,建立在那个丢失上下文之上的一切都会加剧错误。就像后期发现的缺陷一样,你不知道出了什么问题,因为原始上下文已经消失了。
我在对virtio-win运行playbook时有一个具体的例子。版本1.3.32发现了四个bug。版本1.3.33,在做一些更改后,只发现了一个。那个回退只有因为我有EXPLORATION.md才能诊断出来,这是一个外部化的中间状态文件,捕获了AI在其探索阶段观察到的东西。没有它,唯一可观察到的输出就是"这次bug少了"。我无法告诉playbook是变差了,还是bug更难了,还是它只是遗漏了什么。没有外部化的状态,我无法回答这些问题中的任何一个。
管道中的契约文件正是为了解决这个问题而存在的。当模型忘记了它之前注意到的行为契约时,这种遗忘通常是不可见的。但有了契约文件,每一条观察在开始任何需求工作之前都被写下来。如果一个契约在文件中但没有对应的需求,那是一个可见的、可搜索的缺口。你可以看到什么被遗忘了并修复它。
但过度补偿同样容易。如果LLM必须不断在八个不同的参考文件之间跳转,它的上下文窗口会碎片化,你就会开始得到幻觉。我见过这种情况发生。你把所有上下文文件和需求文档和设计文档加载到会话中,AI变得更差,而不是更好。它把所有的注意力都花在导航参考文件上,而不是思考问题。
我在Quality Playbook中遇到了这个问题,当时我把对virtio-win的运行范围从10个文件扩大到大约60个。结果是分析了6倍的文件但发现了75%更少的bug。模型把它的上下文消耗在设备驱动程序上,而不是深入到bug实际所在的传输层。更广的范围意味着更浅的分析。
目标不是保存一切。你必须决定外部化什么、在上下文中保留什么、以及放弃什么。最好的上下文文件恰好包含AI这个会话需要的东西,不多也不少。
6、帮助你的AI管理上下文也帮助你
关于所有这些有趣的是,良好的上下文管理真正利用了你的开发专业知识,而且这是那些你做得越多就变得越好的开发者的事情之一。我在本文中描述的每一个实践——写下你的决策,记录你为什么做这些决策,有意识地把什么放入会话、什么不放——都是开发者一直被告知要做的事情。我们编写ADR和设计文档和内联注释来解释不明显的选择,我们都知道我们应该做得更多。当你与AI合作时,不这样做的成本变得即时可见。你的上下文文件最终成为了你本应一直编写的项目文档,只不过现在有东西在另一端,如果你跳过它,真的会出问题。
一旦你开始把上下文当作你主动管理的东西来思考,你就可以开始围绕它设计你的工作流。这就是Quality Playbook发生的事情,当时它从一个单一的1500万token会话变成了一组独立阶段,阶段之间有干净的交接,整个拆分在第一次就成功了,因为上下文已经被外部化到文件了。
原文链接: Why Doesn't Anyone Teach Developers About Context Management?
汇智网翻译整理,转载请标明出处