2026-05-14 · 架构
32
架构 · 2026-05-14

while 循环谁都会写,差距全在你喂给 LLM 的那串文字

作者:toy

先把两个词分清楚:Context 和 Context Window 不是一回事

这两个词被混着用太久了,写代码的时候迟早会踩坑。

上下文(Context),指的是 Agent 在执行任务时,实际拥有的所有信息。系统提示词、对话历史、检索到的文档、工具调用的结果、记忆模块注入的内容,全在里面。你可以把它理解成 Agent 此刻脑子里装的全部东西。

上下文窗口(Context Window),是模型层面的硬限制,说的是单次推理能处理的最大 token 数。128K、200K、1M 这些数字指的就是它。本质上是个容量上限。

我自己习惯用厨房来打比方:

上下文窗口是你厨房操作台的面积,上下文是你实际摆在台面上的食材、调料、菜谱和工具。台面就那么大,但你放什么、按什么顺序摆、什么时候撤下去,决定了你能不能高效做菜。

Context 是内容,Context Window 是装内容的容器。一字之差,工程上完全是两件事。

LLM 没有记忆,它只是把你塞进去的字读了一遍

劳伦斯(@LawrenceW_Zen)在 [[While 循环谁都会写,上下文工程才是真功夫]] 里讲过一个很容易被忽略的事实:LLM 每次被调用,对它来说都是第一次。

它不记得上一圈循环自己说了什么,不记得工具返回过什么结果。所谓的"它记得",完全是因为你把对话历史塞在 messages 里,让它从头读了一遍。

举个具体例子,一个 Agent 任务:"查明天上海和北京哪个下雨,下雨的城市帮我设带伞提醒"。

第一圈调用 LLM,messages 里就一句用户的话。LLM 决定先查上海。

第二圈,messages 里多了"调用 check_weather(上海)"加上"上海中雨"。LLM 知道上海下雨,但北京没查,于是去查北京。

第三圈,messages 里又多了北京晴天的结果。LLM 决定给上海设提醒。

第四圈,messages 里多了"提醒已设置"。LLM 判断任务完成,stop。

每一圈,messages 都比上一圈长一点。LLM 就是靠这串不断累积的文字,知道自己做到哪了、下一步该干什么。

这串文字就是 Agent 的工作记忆。没有它,LLM 每次都像失忆的人。有了它,多轮推理才能连贯。

工作台就那么大,活越来越多

问题来了:messages 列表只会越来越长。

每一圈循环都在往里塞东西。LLM 的回复、工具的结果、新的决策、新的子任务。简单任务四五圈就结束,复杂任务跑几十圈、上百圈都正常。一个查文档加改代码的活,跑下来三百轮工具调用很常见。

而上下文窗口有上限。超过这个上限,最早的内容会被截掉,模型开始遗忘前面发生过什么。

任务可以无限复杂,工作台的大小是有限的。这是 Agent 工程最硬的约束,没有之一。

所以才会有那一堆策略:摘要压缩历史对话、选择性检索而不是全量灌入、及时清理不再需要的中间结果、把工具返回的长 JSON 提炼成两三行人话。

每一个都是在解一个问题:怎么在有限的台面上,摆下最有价值的那一勺料。

工具调用也是文字游戏

很多人以为工具调用是什么神奇的机制。其实也是一段文字。

你给 LLM 的 tools 列表长这样:

工具名称:check_weather
工具描述:查询指定城市明天的天气预报
参数:
- city(字符串):城市名称,如上海、北京

LLM 看完这段描述,结合用户的任务,自己判断该调哪个、传什么参数,输出一段格式化的文字:

调用 check_weather(city="上海")

LLM 自己不会执行任何东西。它输出的只是一段文字,表达了它想调用这个工具的意图。真正去执行的,是 Agent Loop 里你写的代码。

它不知道 check_weather 背后是调了一个天气 API,还是爬了一个网页,还是查了一个数据库。它只看见了那段描述。

所以工具描述写得好不好,直接决定了 LLM 会不会用对。描述模糊,该调的时候不调,不该调的时候乱调。参数说明不清楚,传错参数。本质上还是 prompt 的问题。工具描述就是写给 LLM 看的说明书。

范式从 Prompt Engineering 跃迁到 Context Engineering

第一代 AI 工程师,大家拼的是 prompt 怎么写得巧。第二代开始拼工具调用怎么设计。到了 Agent 这一代,比的是上下文管理的功夫。

不是因为前两代不重要了,是因为前两代都被吸收进了上下文工程里。

Agent 开发者的日常,其实不是写 while 循环。循环就那十几行,写完几乎不用动。真正花时间的是这几件事:

系统提示词怎么写。太短,LLM 不知道要干嘛;太长,占用宝贵的窗口空间。哪些规则必须写进去,哪些可以让 skill 按需注入,哪些干脆删掉,每一条都得抠。

对话历史怎么管。这是最难的一块。历史越长,窗口越紧。什么时候触发压缩,压缩到什么粒度,关键决策点要不要原样保留,工具调用结果要不要先过一遍摘要,这些细节决定了 Agent 跑长任务的极限在哪。

工具结果怎么处理。一个 search API 返回五千字 JSON,原样塞进去等于自残。但摘要又可能丢掉 LLM 要用到的关键字段。怎么压、压多少、保留什么字段,往往要试很多版。

子 Agent 之间怎么切。多 Agent 协作的时候,主 Agent 和子 Agent 的上下文要不要共享、共享多少、怎么传递结果,全是上下文工程的范畴。

同样的 Opus,为什么不同 IDE 用起来味道不一样

这是我最近经常被问到的问题。

同一个 Opus 4.6,跑在 Cursor 上、Claude Code 上、Trae 上,体验差距明显。模型一样,价格一样,差在哪?

差在上下文管理水平。

谁先注入项目结构,谁懒得管。谁会动态加载 skill,谁一股脑全塞。谁的工具描述写得精准,谁的工具描述模棱两可。谁会在每一轮压缩历史,谁等窗口爆了才慌着截断。谁会让子 Agent 隔离上下文,谁让主 Agent 替子 Agent 收烂摊子。

这些都不是模型能力的问题。是 Harness 怎么管 Context 的问题。

劳伦斯有句话我很认同:Agent 代码骨架一小时就能写完,但上下文的设计和调优可能要几个月。市面上 Agent 框架的 while 循环大同小异,做出来的产品质量天差地别,差的就是这一层。

给一线 Agent 开发者的几个动作

写到这儿,给几个能直接动手的建议。

把每一次 LLM 调用的完整 messages 打印出来看一眼。你会惊讶地发现,自己塞进去的字有多少是冗余的。先别急着加新功能,先看看现在浪费了多少 token。

工具描述写完后,自己读一遍,假装你不知道这工具背后是什么。如果读完还得猜,那 LLM 也得猜。

对话历史超过一定长度就做压缩,别等爆窗口。压缩策略可以简单粗暴:保留最近 N 轮原文,前面的让 LLM 自己总结成三五行。能跑通就比不压强一个量级。

工具返回结果太长的,加一层"提炼器"。让小模型先把 JSON 压成两三行结论,再塞回主 Agent 的上下文。省下的 token 够你多跑十轮。

子 Agent 用完就丢。别让主 Agent 背着子 Agent 的全部工作记忆,那是台面爆炸的最快方式。

哪天你发现自己一周里有四天都在调 prompt、调工具描述、调压缩策略,恭喜,你已经在做 Context Engineering 了。

至于 while 循环那十几行代码,确实是谁都能写。

参考阅读:劳伦斯 @LawrenceW_Zen 的《While 循环谁都会写,上下文工程才是真功夫》。本文是顺着他的论证又往前走了半步。

目录 最新
← 左侧翻上一屏 · 右侧翻下一屏 · 中间唤出菜单