面向编码代理的上下文工程
提示词工程讲的是措辞。上下文工程讲的是措辞抵达时窗口里有什么,而后者的分量大得多。
把整个仓库连同一个问题一起丢给模型,并没有让它的工作变轻松。你把它变成了一个检索问题,然后它才有机会成为一个回答问题。它得先找到那个关键的角落,而在这个窗口里,每一个无关文件都在和那个相关文件争夺注意力。
常被忽略的正是这一点:上下文更大并不严格意味着更好。过了某个点它反而更差,而你还为此付得更多。
三种失效方式
- 稀释。信号还在,但被包围了。从长上下文中取回某个事实的准确率,会随着周围无关材料的体积上升而下降,其中处在长窗口中段的材料下降得最快。
- 矛盾。同一个函数的两个版本、与新代码相抵触的旧注释、过期的 README。模型无从判断哪一个还有效,有时就会选错。
- 漂移。长会话会积累被推翻的决定、被放弃的路径和已经修好的错误。这些统统还在窗口里,还在被反复读取,还在左右答案。
站得住脚的规则
它们并不高明,只是能在真实工作里活下来。
相关性胜过体量。十行能回答问题的内容,胜过一千行“答案就在其中某处”。如果你能指出那段代码,就指出来。
新鲜胜过完整。一个与当前行为相抵触的过期文件,比没有这个文件更糟,因为它产出的是一个自信的错误答案,而不是一个疑问。
硬上限胜过良好意愿。没有上限,上下文只会单调增长。代理循环内部从来不会有什么东西判定“我现在知道得够多了”。
一个窗口一件事。世上最便宜的上下文管理技巧,就是关掉会话。
落到实处是什么样
capsul context '为什么 webhook 处理函数返回 500' --open src/app/api/polar/webhook/route.ts组装上下文并报告它的开销,不消耗一次请求。
把上下文单独构建出来的意义,在于让看不见的那部分变得可见。你能在投入之前看到一项任务要花多少,也能比较同一个问题的两种问法。
去测量它
上下文工程有个诚实性问题,值得点破:这个领域里几乎所有主张都没有对照臂,因而不可证伪。如果你要改动上下文的组装方式,就在同一模型、同一任务上做有无该改动的对照,重复到足以看清噪声底线,然后公布区间而不是中位数。
常见问题
上下文工程是不是提示词工程换了个名字?
不是。提示词工程处理的是请求的措辞,那只占所发送内容的一小部分。上下文工程处理的是剩下九成多:哪些文件、哪段历史、哪些工具输出,以及什么被留在外面。
二十万 token 的窗口能消除这个问题吗?
它消除的是上限,不是问题。检索准确率仍然随体量下降,矛盾仍然造成混乱,而且你每一轮仍然要为每个 token 付费。
上下文预算应该设多少?
小到足以逼出一个取舍。具体数字没有“存在一个数字”重要,因为没有上限的代理会把给它的东西填满。
怎么知道一次上下文改动真的有帮助?
在同一模型上把同一任务用两种方式各跑若干遍,比较区间而不是某一次运行。代理会话的噪声大到让单次前后对比几乎毫无意义。
$ npm i -g @penra/capsul