让 Manus 在生产环境中稳定运行的六项上下文工程技术
Manus 团队在不到一年的时间里重建了四次他们的智能体(agent)框架。这并非因为模型发生了变化 —— 底层 LLM 在稳步提升。他们之所以重建,是因为不断发现了更好的方式来塑造进入上下文窗口(context window)的内容。
他们将这一过程称为“随机研究生下降”(Stochastic Graduate Descent):手动的架构搜索、提示词微调和经验性猜想。这是对构建生产级智能体真实面貌的坦率描述。在经历了数百万次真实用户会话后,他们总结出了六种具体的技术,这些技术决定了一个长周期智能体(long-horizon agent)是会取得成功,还是会陷入混乱。
核心洞察说起来简单,内化却很难:“上下文工程(Context engineering)是一门微妙的艺术与科学,即用恰到好处的信息填充上下文窗口,以支持下一步操作。”一个典型的 Manus 任务运行约 50 次工具调用,输入与输出的 token 比例高达 100:1。在这样的规模下,你在上下文中放入了什么 —— 以及你是如何放入的 —— 决定了一切。
KV-Cache 命中率是真正的北极星指标
大多数构建智能体的团队会追踪准确率、延迟和任务完成率。Manus 追踪的则是一个大多数团队直到看到账单才会注意到的指标:KV-cache 命中率。
经济账非常直观。使用 Claude Sonnet,缓存的输入 token 每百万个仅需 0.30 美元;而未缓存的 token 则需要 3.00 美元。这是 10 倍的成本差异。当你的智能体会话中每产生一个输出 token 就涉及数百个输入 token 时,缓存未命中不仅令人心痛 —— 还会让产品在规模化时在经济上变得不可持续。
这促使 Manus 制定了一套工程规则,在违反它们之前,这些规则听起来微不足道:
- 永远不要在系统提示词中放入精确到秒的时间戳。单个字符的变化就会导致整个前缀缓存失效。
- 保持工具定义在不同请求间稳定。如果你动态地添加、删除或重新排序工具,每一个请求都会支付全额费用。
- 使用仅追加(append-only)的上下文结构。对先前操作或观察结果的任何原地修改,都会破坏该点之后所有内容的缓存。
- 确保确定性的 JSON 键排序。许多语言默认以随机顺序序列化 map。这是一个隐形的缓存杀手。
更深层的影响是:任何在上下文稳定前缀中引入动态变化的技术都是隐藏的成本中心。更新后的对话摘要、注入状态的系统提示词、按请求生成的提示词模板 —— 所有这些都可能在提高输出质量的同时破坏缓存效率。你必须同时衡量这两者。
通过 Logit 控制屏蔽工具,而非将其移除
在有状态的智能体中,管理工具可用性的一种自然方法是当工具不适用时将其从列表中移除。如果智能体处于“写作”状态,为什么要给它看文件系统工具?更少的噪点,更少的 token,更简洁的提示词。
这种方法是错误的。从工具列表中移除工具会改变稳定前缀并破坏缓存。更糟糕的是,如果上下文中的先前观察结果引用了一个不再定义的工具,模型就会遇到矛盾 —— 它有使用过某个不存在的工具的证据,这会降低推理质量。
Manus 转而采用解码过程中的 logit 掩码(logit masking)。工具定义在提示词中保持不变。在推理时,解码过程根据当前状态屏蔽掉无效的工具 token。模型永远不会在上下文历史和可用选项之间看到相互矛盾的信号。
他们通过三种函数调用模式来实现这一点。在 “auto” 模式下,模型决定是否调用任何函数。在 “required” 模式下,模型必须进行函数调用,但可以选择任何工具。在 “specified” 模式下,上下文会预填一个函数名称前缀,将模型约束在该工具系列中。Manus 为工具系列命名时使用了统一的前缀(如 browser_*、shell_*、file_*),正是为了在约束工具组时只需使用一个前缀掩码,而无需跟踪单个工具的状态。
工具数量也很重要。工具越多,效果越差。工具描述会消耗 token,而重叠的工具语义会导致模型对何时使用哪个工具产生困惑。Manus 保持了少于 20 个原子核心函数。直觉是:一个小型且区分明确的工具包优于一个带 有冗余条目的全面工具包。
使用文件系统作为无限的外部上下文
长周期任务面临一个天花板:工具输出 —— 网页、代码执行结果、文档内容 —— 可能是海量的。即使它们没有立即溢出上下文窗口,把所有内容塞进去也会降低推理质量。Transformer 在超长窗口中会出现“上下文腐烂”(context rot),即中间的信息受到的关注较少,从而导致有效消失。
标准解决方案是 RAG:嵌入分块、检索相关内容、注入摘要。Manus 拒绝了这种做法,认为其复杂性不必要。他们的答案是:将输出写入文件系统,并让智能体使用基础 Unix 工具(如 glob、grep、cat)来检索它们。
“文件系统的大小是无限的,天生具有持久性,并且可以由智能体直接操作。”无需嵌入模型,无需向量索引,也无需调优和调试检索流水线。
关键的约束是 Manus 所称的可恢复压缩(restorable compression)。当你压缩上下文时,只有在智能体稍后能够重建信息的情况下,你才被允许移除该信息。具体规则如下:
- 在摘要之后丢弃网页内容,但保留 URL —— 智能体可以重新抓取。
- 在上下文中省略文档内容,但保留文件路径 —— 智能体可以重新读取。
- 永远不要丢弃没有路径找回的信息。
这是与有损摘要的关键区别。摘要对什么是重要的做出了不可逆的决定。而可恢复压缩则将该决定推迟到智能体需要信息的那一刻。一个忘记了自己为什么写文件的智能体,其表现几乎肯定比一个能回头去查看的智能体要差。
实际结论是:对于大型工具输出,默认将其写入磁盘并给智能体一个路径。上下文中只保留下一次工具调用真正需要的内容。
通过任务复述让注意力回到目标
“迷失在中间”(lost-in-the-middle)的失效现象在 Transformer 研究中已有详尽记录:上下文窗口开头和结尾附近的信息比中间的信息获得更多的注意力。对于一个包含 50 个步骤的 Agent 任务,到第 30 步时,早期的目标和指令实际上对模型来说已经变得不可见了。
Manus 有意利用了这种注意力几何特性。他们的 Agent 维护一个 todo.md 文件,在每一步结束时都会在上下文末尾重写该文件,从而将当前任务目标推入模型的高注意力近因区。随着上下文的增长,全局计划通过浮动到末尾来保持在视野内。
这是一种持续的目标复述形式。与其信任模型能够记住第 0 步指定的任务目标,不如让 Agent 不断将其重新断言为最新的上下文条目。这种实现非常简单,以至于很容易被忽略,但它对长对话中目标连贯性的影响是巨大的。
架构在不断进化。早期的 Manus 让主执行代理(executor agent)直接管理 todo.md,这导致大约三分之一的操作浪费在任务列表的更新上——这些操作并没有推进任务,只是在做记录。解决方案是引入一个专门的规划器子代理(planner sub-agent)来处理所有的任务分解和列表管理,让执行者完全专注于采取行动。
在上下文中保留错误,不要清洗它们
有一种直觉但错误的本能,即通过删除失败的操作来清理 Agent 的上下文。模型尝试了某些不起作用的方法,观察结果是一个错误——为什么要带着它继续呢?用摘要替换它,或者直接删掉它。
Manus 保留了这些弯路。失败的操作、错误消息、堆栈跟踪——这些都留在上下文中。
其背后的推理是机制性的。模型需要看到它尝试了什么以及反馈是什么,以便更新其关于哪些方案有效的隐式信念。错误恢复——诊断失败、调整方法、尝试不同的方案——需要失败的证据。如果你从上下文中删除了错误,你就剥夺了模型推理当前情况为何存在以及失败路径是什么的能力。
Manus 团队将错误恢复描述为“真正 Agent 行为最清晰的指标之一”,并指出这在学术基准测试中始终代表不足,因为这些测试往往在干净、定义明确且没有注入故障的任务上测试 Agent。
这具有深刻的评估意义:如果你的基准测试不包含失败条件和恢复场景,你的性能数据可能会显著夸大你的 Agent 在生产环境中的实际表现。那些在干净的基准测试中得分很高但在混乱的真实任务中崩溃的 Agent,通常受困于过度清洗的上下文管道。
通过受控的观察差异打破节奏模式
模型是“优秀的模仿者”。当一个 Agent 处理 50 个结构相似的观察结果时——50 份简历评估、50 个产品页面、50 个 API 响应——统一的“行动-观察”节奏会导致模式过度泛化。模型开始将每个观察结果视为一个模板实例,而不是对其进行独立推理。
Manus 通过在观察结果的序列化方式中引入少量的结构化差异来抵消这一点:不同的模板、交替的措辞、排序或格式上的微小差异。目标是打破节奏,使模型能够对每个观察结果保持独立的注意力,而不是根据模式进行推断。
这条建议与 KV 缓存(KV-cache)的建议直接冲突。缓存建立在稳定性之上,而这种技术需要变动。Manus 通过在缓存重要的地方(系统提示词前缀、工具定义、结构不变性)保持稳定,而在注意力重要的地方(随每个工具调用而变化的观察内容)保持变动,从而化解了这一冲突。
这里的启示不是“到处都要保持不一致”。而是你应该了解上下文的哪些部分是与缓存相关的(它们需要被冻结),以及哪些部分是模型动态处理的(在那里进行一些变化可能是有益的)。大多数团队对这两部分一视同仁。
隔离是多智能体架构真正起作用的原因
关于多智能体系统的流行叙事强调专业化:研究员 Agent、编码员 Agent、审核员 Agent,每个都有自己的角色和领域专长。Manus 的生产经验指向了另一个更主要的益处:上下文隔离。
子代理之所以起作用,是因为它们获得了一个干净的上下文窗口,而不是因为它们扮演了不同的角色。一个被给予专注指令且只有极少前置上下文的子代理,其表现优于一个携带 50 个步骤累积状态并试图同时思考子任务细节的单一代理。
对于简单的任务,Manus 让规划器仅通过函数调用传递指令——子代理获得最少的上下文并在干净的隔离环境下运行。对于需要访问先前工作的复杂任务,规划器会共享轨迹上下文和文件系统访问权限,但子代理仍然保持自己的工具定义和系统指令。结果通过一个具有约束解码强制执行 schema 的 submit results 工具返回,确保了结构化的交接。
模型路由遵循任务类型而非 Agent 角色:Claude 用于编码,Gemini 用于多模态,OpenAI 模型用于重数学推理。多智能体架构使得这种路由变得简单,而不会让任何 Agent 的上下文被无关的能力信号污染。
Manus 对其框架(harness)设计进行的测试是:换入一个更强的模型。如果 Agent 性能没有提高,那么框架就是瓶颈。框架受限的性能是一种失效模式,即模型周围的工程设计抑制了模型实际能做的事情。这是一个具体的质量测试,大多数团队并没有明确地执行,但应该这样做。
这一切意味着什么
Manus 的六项技术并非独立的启发式方法。它们构成了一个连贯的模型,揭示了在长程任务中上下文窗口(context window)的本质。
上下文并非记录文本。它是一个经过精心管理的工作记忆。你选择包含什么、压缩什么、重复什么以及保留什么,决定了智能体在执行第 50 步时是否能保持与第 1 步相同的水准。如果将上下文视为发生过程的被动日志,你构建出的智能体将只能在演示环境中跑通,而在生产环境中则会性能退化。
经济维度使得这一点成为了必选项。在 100:1 的输入输出比以及缓存与未缓存 token 之间 10 倍的价差下,上下文工程(context engineering)不再是单纯的质量优化,而是一项成本控制手段。如果团队将上下文视为免费资源,那么在大规模扩展之前,他们就会因为成本问题被市场淘汰,而那时他们甚至还没意识到瓶颈并不在模型。
贯穿其中的设计哲学是:“如果模型的进步是不断上涨的潮水,我们希望做水面上的船,而不是固定在海床上的柱子。”构建一个能够随之漂浮的架构。不要让你的架构限制了那些你即将免费获得的提升。
- https://manus.im/blog/Context-Engineering-for-AI-Agents-Lessons-from-Building-Manus
- https://medium.com/@peakji/context-engineering-for-ai-agents-lessons-from-building-manus-71883f0a67f2
- https://arxiv.org/html/2505.02024v1
- https://www.zenml.io/llmops-database/context-engineering-strategies-for-production-ai-agents
- https://weaviate.io/blog/context-engineering
