OpenAI 发布 Agent 后,似乎让其他 Agent 公司更兴奋了。
首先是 Genspark,在 OpenAI 发布会之后立刻发推,表示自己”从来没想过作为一家只有24名员工的小公司,甚至能领先于 OpenAI “。
*Genspark在X上发布和ChatGPT Agent的同任务PK
昨天凌晨, 也开始发声——这家在今年 Agent 浪潮中,几乎唯一被真正持续关注的 Agent 公司,发布了自家首席科学家季逸超 Peak 的技术分享文章。
在这篇名为《AI Agent的上下文工程:构建Manus的经验教训》的文章里,Manus 分享了构建产品背后的思路,并讲述了自己踩过的坑。
最核心的要点是,Manus 认为构建一个基本靠谱的 Agent,上下文工程是不可或缺的要素。
因为就算模型将越来越强大、快速、廉价,但再强的模型也无法取代 Agent 对记忆、环境和反馈的需求——如何塑造上下文,最终决定了 Agent 运行速度多快,出错后恢复得多好,以及能扩展到多复杂的任务。
*Manus合伙人张涛对本文的分享
在更细致地工程方法论层面,Manus通过反复重构、不断尝试、以及在数百万用户的真实环境中测试,汲取的经验教训包括:
「四木相对论」对本文的(AI辅助)编译如下:
https://manus.im/blog/Context-Engineering-for-AI-Agents-Lessons-from-Building-Manus
刚开始做 Manus 的时候,我和团队面临一个关键决策:我们应该基于开源模型训练一个端到端 Agent 模型,还是利用最新大模型的上下文学习能力构建一个 AI Agent?
回想我最初十年搞 NLP 时,并没有这样的选择空间。
在 BERT 时代(没错,那已经是七年前的事了),模型在迁移到新任务前必须经过微调——而且在评估前还要再微调一遍。每次迭代都耗费数周时间,即便那些模型相对于如今的超大语言模型(LLM)规模很小。
对于快速迭代的应用(尤其是在产品与市场契合度尚不明确的阶段),这种缓慢的反馈循环是致命缺陷。
我的上一个初创公司就深受其害——当时我从零训练模型来做开放信息抽取(open information extraction,从非结构化文本中自动提取结构化信息的技术)和语义搜索,这个过程里的缓慢反馈,最后成了痛苦的教训。
紧接着 GPT-3 和 Flan-T5(Google的指令微调T5模型) 横空出世,我辛苦训练的自研模型瞬间毫无用处。具有讽刺意味的是,正是这些新模型开启了上下文学习的序幕——一条全新的前进道路。
血的教训让我们很快明白了选择的方向:Manus 将押注于上下文工程(context engineering)。
这意味着,我们可以用“小时”而非“星期”为单位来发布改进,同时我们的产品能够与底层模型进步保持”正交”——如果模型的进步是一场水涨船高的潮流,我们希望 Manus 是随之起伏的舟,而不是困在海床上的桩柱。
当然,上下文工程不是一条康庄大道,更像是一门实验科学——我们四次推倒重写了 Agent 框架,每一次都是在摸索出更佳的上下文塑造方式后痛下决心。我们开玩笑地把这种通过架构试验、提示词调整、经验猜测来优化的手工过程称为“SGD”(Stochastic Graduate Descent,影射 Stochastic Gradient Descent,随机梯度下降)。这个名字虽搞笑,但确实有效。
这篇文章将分享我们通过自身“SGD”找到的几个局部最优方案。如果你正在构建自己的 AI Agent,希望这些经验能帮助你更快收敛方向。
围绕 KV 缓存来设计
如果只能选择一个衡量指标,那么 KV 缓存命中率大概是生产环境 AI Agent 中最重要的单项指标,它直接影响延迟和成本。
*KV 缓存命中率(KV-cache hit rate),键值缓存是 Transformer 模型中存储注意力计算结果的机制,命中率高意味着可以重用之前的计算结果,能够提升性能、节省成本。
要理解背后缘由,我们先来看典型的 Agent 是如何运行的:
在收到用户输入后,Agent 会通过一系列工具调用(tool use)逐步完成任务。在每个迭代步骤中,模型会根据当前上下文从预定义的动作空间中选取一个动作。
这个动作随后在环境中执行(例如 Manus 的虚拟机沙盒),产生一个观察结果。然后,这个动作和它的观察结果会被追加到上下文中,形成下一次迭代的输入。如此循环往复,直到任务完成。
可以想见,每一步都会让上下文累积增长,而输出——通常是结构化的函数调用——却相对简短。因此在 Agent 场景中,输入预填充(prefilling)和输出解码(decoding)的比率高度失衡。例如在 Manus 中,平均输入:输出的字词(token)比约为 100 :1。
所幸,对前缀完全相同的上下文,我们可以利用 KV 缓存 ,极大缩短首Token 输出的等待时间(Time to First Token, TTFT)并降低推理成本——无论你是用自托管模型,还是在调用推理 API。
这并非细枝末节的小优化:以 Claude Sonnet 为例,有缓存命中的输入 token 成本约0.30美元/百万token,而未缓存的成本为3美元/百万token,差了整整 10 倍。
*具有相同前缀的上下文利用 KV 缓存加速模型推理,显著降低首字节延迟和推理成本
从上下文工程的角度,提高 KV 缓存命中率可以遵循以下几条关键实践:
另外,如果你使用如 vLLM 等框架自托管模型,务必确保启用了前缀/Prompt 缓存功能,并使用会话 ID 等手段确保在分布式部署中请求被路由到相同的工作节点进行推理。
掩码,不要移除(Mask, Don’t Remove)
随着 Agent 具备的能力越来越多,其动作空间(可用工具集合)自然会变得复杂——直白点说,就是可调用的工具数量呈爆炸式增长。最近 MCP 协议的流行是火上浇油。
如果你的平台允许用户自定义工具,相信我:总有人会往你精心设计的动作空间里硬塞上成百上千个乱七八糟的工具。结果,模型更可能选择错误的动作或者采取低效的路径。
简而言之,武器越多,Agent 反而变“笨”了。
很自然的应对措施,是设计一个动态动作空间——也许通过类似 RAG(检索增强生成) 的方式按需加载工具会解决问题。我们在 Manus 中也尝试过,但实验给出了明确的结论:除非万不得已,不要在一次迭代中动态添加或移除工具。
这主要有两个原因:
为了在解决这个问题的同时仍改进动作选择,Manus 引入了上下文感知的状态机(state machine,根据当前状态和输入确定下一个状态的计算模型。目的是给上下文做标记,来区分激活/屏蔽等不同的状态),来管理工具可用性。
这种方案不是移除工具,而是在解码过程中掩码token logits(模型输出的原始概率分布)以防止(或强制)基于当前上下文选择某些动作。
*token logits 就是模型在 softmax 前给所有候选词打的“原始分”,决定谁更可能成为下一个输出
*比较了直接移除工具与使用掩码技术的区别。左侧为直接移除,KV 缓存会失效;右侧为根据任务进展屏蔽掉某些动作,从而避免调用已不适用的工具,同时保持 KV 缓存的有效性
实际上,大多数模型提供商和推理框架都支持某种形式的响应预填充,允许在不修改工具定义的情况下约束模型可选的动作空间。
一般来说有三种函数调用模式(下面以 NousResearch 提出的 Hermes 格式为例):
利用上述机制,我们可以直接通过掩码 token logits 来约束动作选择。
例如,当用户提供新的输入时,Manus 必须立即回复而非调用动作。我们还特意设计了统一的工具命名前缀——例如所有浏览器相关工具都以 browser_ 开头,命令行工具都以 shell_ 开头。这样做,我们无需复杂的状态型输出处理器,也能轻松实现在特定状态下,只允许 Agent 从某一类工具中选择动作。
这些设计确保了 Manus Agent 的循环在模型驱动的架构下依然保持稳定。
将文件系统用作上下文
当今先进的 LLM 已提供了高达 128K 以上的超长上下文窗口。然而在真实的 AI Agent 场景中,这往往不够,有时还可能成为负担。这里有三个常见的痛点:
很多 Agent 系统会采用截断或压缩上下文的策略。但压缩过猛不可避免地会导致信息损失。问题在于:Agent 本质上必须基于全部先前状态来预测下一步动作——你无法可靠地预知十步之后哪个观察内容会变得至关重要。从逻辑上讲,任何不可逆的压缩都是有风险的。
正因如此,在 Manus 中我们将文件系统视为终极的上下文:它尺寸无限制、天然持久,并且能被 Agent 直接操作。模型学会按需将信息写入文件和从文件读取——将文件系统视为结构化的、外部化的记忆来使用,而不仅仅是存储介质。
*示意 Manus 如何将文件系统作为扩展的上下文来使用。模型可以在需要时将信息写入文件或从文件读取,将文件系统充当外部的结构化内存
我们的压缩策略始终设计为可还原的。
举例来说,只要保留了 URL,网页内容就可以从上下文中移除。同样地,只要沙盒里的文件路径仍在,文档的具体内容也可省略不放入上下文。通过这种方式,Manus 能在减少上下文长度的同时不永久丢失信息。
在开发这一特性的过程中,我不禁设想:让状态空间模型(SSM,State Space Model,一种与 Transformer 不同的序列模型架构,适合超长上下文、低显存、低延迟场景)在 Agent 需求下高效工作需要什么条件。
与 Transformer 不同,SSM 缺乏全局注意力机制,难以处理长距离的反向依赖(当前步骤的输出,需要依赖非常早的某一个历史信息)。但如果它们能掌握基于文件的记忆——将长期状态外部化到文件系统而不是全部塞进上下文——那么它们的高速度和高效能或许能催生新型 Agent。
神经图灵机(Neural Turing Machines) 之后,或许真正的下一代 Agent 将是具备外部记忆的 SSM。
通过“复述”操控注意力
如果你用过 Manus,可能注意到一个奇特现象:在处理复杂任务时,Manus 通常会创建一个名为 todo.md 的文件——并随着任务推进逐步更新这个文件,勾掉已完成的事项。
这不只是可爱的彩蛋行为——而是刻意为之的一种注意力操控机制。
*Manus 在复杂任务中创建并不断更新一个待办清单(todo.md),通过持续“复述”目标,将全局计划推送到模型最近的注意力范围内,从而避免在长上下文或复杂任务中出现“中途遗忘”目标的情况
在 Manus 中,一个典型任务平均需要调用约 50 次工具,这意味着一个很长的决策循环。由于 Manus 的决策依赖于 LLM,这使得 Manus 容易在长上下文或繁琐任务中跑题或遗忘先前的目标。
通过不断重写待办列表,Manus 实际是在上下文末尾重复陈述它的目标。
这相当于把全局计划不断刷新到模型“最近”的注意力范围里,从而避免了“中段遗失”的问题,减少了目标偏离。实际上,Manus 是利用自然语言在不更改模型架构的前提下引导自身关注当前的任务目标。
把错误留在上下文中
Agent 会犯错,这并非 Bug,而是现实。
语言模型可能会发生幻觉(编造不真实内容)、环境可能返回错误、外部工具可能失灵。各种意料之外的情况随时会出现。
在多步骤任务中,失败不是例外,而是循环的一部分。
然而,人们常常本能地想要掩盖这些错误:清理执行轨迹,重试动作,或重置模型状态然后寄希望于神奇的“温度参数”(Temperature)去随机给出不同结果。
这样做看起来安全、可控,但代价是:抹去错误就等于抹去了线索。没有了错误留下的证据,模型就无从适应和改进。
*当 Agent 执行多步任务时,错误与失败其实是循环的一部分
根据我们的经验,提高 Agent 行为的有效性有一个看似极其简单的方法:把走过的弯路留在上下文里。
当模型看到某个动作失败——以及随后的观察结果或报错——它会在潜意识中更新自己。这会让模型降低对类似动作的先验倾向,从而减少重犯同样错误的几率。
事实上,我们认为错误恢复能力是评判真正 AI Agent 行为的最明确指标之一。然而,在大多数学术研究和公开基准中,这一方面还未得到足够重视——它们往往聚焦于理想条件下任务一次性成功的表现。
不要被少样本/ Few-shot 困住
Few-shot prompting 是提升 LLM 输出质量的常用技巧。但在 Agent 系统中,它可能以微妙的方式起反作用。
语言模型是天生的模仿者,它们会模仿上下文中的行为模式。如果你的上下文里充斥着相似的“过去动作 – 观察”对数据,模型也会倾向于遵循同样的模式,即使这种模式已不再是最优解。
这在涉及重复决策或操作的任务中尤其危险。
比如用 Manus 批量审阅20份简历时,Agent 常常会进入一种节奏——仅仅因为上下文里有一系列相似的先例,它就不断重复类似的动作。结果可能导致偏航(drift,逐渐偏离正确轨道)、过度泛化(overgeneralization),甚至出现幻觉。
*在重复性任务中,如果上下文中的示例过于单一,模型往往会机械地沿用这种Few-shot示例模式
解决办法是引入多样性。
Manus 会在动作和观察中加入少量有结构的随机变化——例如使用不同的序列化模板、替换不同的措辞,或在顺序和格式上引入细微扰动。
这种受控的随机性有助于打破单调模式,微调模型的注意力。换言之,不要让 Few-shot 示例把 Agent 困在死胡同里。上下文越整齐划一,Agent 就越脆弱。
结语
上下文工程仍是一门新兴的学问——但对于 Agent 系统来说,它已经成为不可或缺的要素。
模型或许会变得越来越强大、快速、廉价,但再强的模型也无法取代对记忆、环境和反馈的需求。如何塑造上下文,最终决定了 Agent 的行为:运行速度多快,出错后恢复得多好,以及它能扩展到多复杂的任务。
在 Manus,我们通过反复重构、不断尝试、以及在数百万用户的真实环境中测试,才汲取了这些教训。
我们分享的内容并不是什么放之四海而皆准的真理——但确实是对我们有效的模式。如果它们哪怕能帮你避免一次痛苦的迭代,那么这篇文章就算没有白写。
Agent 的未来将由一个又一个上下文构建而成。请务必将它们打磨好。
发布者:Ai探索者,转载请注明出处:https://javaforall.net/250516.html原文链接:https://javaforall.net
