孔某人 2025-10-17 00:30 北京
Context Engineering in Manus
title: Context Engineering for AI Agents with LangChain and Manusurl: https://www.youtube.com/watch?v=6_BcCthVvb8date: 20251014
孔某人按
我现在会把Manus描述为让我尊敬的公司。虽然说本文分享的经验并非需要多高的智力、需要烧掉多少钱才能获得。但真的在探索并分享的公司寥寥无几。这让我想到了DeepSeek,就做自己想做的事情,分享自己的结果,仅此而已。
全文文字凝练稿
00:00:06
Lance:
我是Lance,LangChain的创始工程师之一。今天和我一起的是来自Manus的Peak。
Peak:
大家好,我是Manus的联合创始人兼首席科学家,负责设计agent框架。
Lance:
Manus是一个很酷的产品,我用了很长时间。几个月前他们发布了一篇关于context engineering的博客文章,对我影响很大。
我会先简要介绍我理解的context engineering并引用他们的文章,然后Peek会做演讲,讲一些文章中没有涵盖的新想法。如果你已经读过那篇文章,这些新内容应该会很有意思。我先做个铺垫,然后交给Peek,最后我们会做Q&A。
你可能听说过context engineering这个术语,它在今年早些时候出现。从Google搜索趋势来看,context engineering是在ChatGPT之后开始兴起的,那是2022年12月。
当我们有了chat model这个新东西后,人们对如何prompt这些模型产生了极大兴趣。Prompt engineering作为一个学科应运而生。Context engineering在今年5月左右开始在Google Trends上升,这与"agent之年"的概念有些关联。
为什么?如果你一直在构建Agent,会观察到context会增长,而且在构建agent时以一种特殊的方式增长。我们有一个LLM绑定了一些工具,LLM可以在循环中自主调用工具。
挑战在于每次调用工具,你都会得到一个tool observation返回,它会被追加到chat列表中。这些消息会随时间增长,所以当Agent运行时,你会看到消息的无限制爆炸式增长。
例如,Manus在他们的文章中提到,典型任务需要大约50次工具调用。Anthropic也类似地提到,生产环境的Agent可能会进行数百轮对话。
所以挑战在于,Agent因为越来越长时间运行且自主,会自由使用工具。通过这些工具调用的累积,你会积累大量context。
Gretel发布了一份很好的报告讨论context rot。观察结果很简单:随着context增长,性能会下降。这就是一个悖论:Agent因为工具调用而使用大量context,但我们知道随着context增长性能会下降。
这是我们许多人面临的挑战,我认为这催生了context engineering这个术语。Karpathy今年早些时候在Twitter上创造了这个词。
你可以把context engineering理解为一门精妙的艺术和科学,用恰当的信息填充context window以支持下一步操作。所以要对抗构建Agent时发生的context爆炸——当它们自由调用工具时,所有这些工具消息累积在消息队列中,必须被管理,以便在所有时间点向agent呈现正确的信息,让它做出正确的下一步决策。
00:03:45
为了解决这个问题,我想强调几个常见主题,我们在包括Manus在内的许多工作中都看到了。
第一个想法是context offloading。核心思想是,你不需要所有context都存在于agent的消息历史中。你可以把信息offload出去,发送到别处,这样它就在context window之外,但可以被检索。
最流行的想法之一就是使用文件系统。以工具消息的输出为例,把它dump到文件系统,只向agent返回必要的最小信息,这样它可以在需要时引用完整context。但那个完整的payload,比如token很重的web搜索结果,不会永久地塞进你的context window。
许多项目都使用这个方法:Manus、我们的Dev Agents项目、OpenDevin研究。实际上agent state的作用类似于外部文件系统。Claude Code和LangChain agents也大量使用。将context offload到文件系统在生产环境Agent中非常普遍。
第二个是reducing context。Offloading是拿token很重的工具消息,不把它全部发回消息列表,而是dump到文件系统,只在需要时检索。Reducing context类似,但你是在总结或压缩信息。
总结工具调用输出是一种直观的方法,我们在Open Deep Research中就这样做。Pruning工具调用或工具消息也是一种方法。
很有意思的是,Claude Sonnet 4.5实际上已经把这个加入了——如果你看他们最近的发布,现在开箱即用就支持pruning旧的工具调用及其输出。这已经内置到他们的SDK中了。
总结或压缩完整消息历史,你在Claude Code的compaction功能中能看到,一旦达到整体context window的某个百分比就会触发。Cognition也谈到在agent到agent交接时总结或pruning的想法。
Reducing context是一个非常流行的主题,从Claude Code到我们的Open Deep Research、Cognition,Claude Sonnet 4.5也整合了这个。
Retrieving context是当今的经典辩论之一——检索context的正确方法。Cursor的Lee Robinson在OpenAI Demo Day上有一个很好的演讲,我会分享这些幻灯片。
他谈到Cursor使用indexing和semantic search,以及更简单的基于文件的搜索工具,比如glob和grep。Claude Code只使用文件系统和简单搜索工具,特别是glob和grep。
有不同的方法为agent按需检索context:indexing和semantic search,或者文件系统和简单文件搜索工具。两者都可以非常有效,各有利弊,我们可以在Q&A中讨论。但context retrieval对于构建有效的Agent至关重要。
Context isolation是另一个主要主题,特别是通过multi-agents分离context。每个sub-agent都有自己的context window,允许关注点分离。
Manus、我们的Dev Agents工作、Open Deep Research都使用这个。Claude的研究中使用了sub-agents,Claude的multi-agent researcher和Claude Code都支持sub-agents。Sub-agents是执行context isolation的常见方法。
00:08:05
Caching context很有意思,Manus对此谈了很多,我会让Peek稍后详细讲,但我认为这也是一个非常有趣的技巧。
我展示一个我们在Open Deep Research中看到的简单例子。这是我们一个非常受欢迎的repo,是一个开源的deep research实现,性能与一些最佳实现相当。你可以查看我们的repo,我们有Deep Research的结果显示我们排在前十。
它有三个阶段:研究的scoping、使用multi-agent架构的研究阶段本身,以及最后的一次性写作阶段。
我们使用offloading。我们创建一个brief来规划研究计划,然后offload它,所以它不只是保存在context window中,而是独立保存的。在我们的案例中可以从LangGraph state访问,但也可以从文件系统访问。
你创建一个研究计划,offload它,它总是可访问的。你去做一堆工作,可以按需把它拉回来,放在消息列表的末尾,这样agent就可以访问并随时使用,来执行写作阶段。
我们使用offloading来帮助引导研究和写作阶段。我们使用reduction来总结研究本身内部token很重的搜索工具调用的观察结果。我们在研究本身内部的sub-agents之间使用context isolation。
这总结了这些不同想法在一系列不同项目中的应用。实际上Peek会专门讲Manus以及他们学到的一些经验教训。现在我想让Peek继续演讲,因为我想确保我们有足够的时间给他和提问环节。
00:10:25
Peak:
我今天分享我们从构建Manus中学到的一些关于context engineering的新经验。我说新经验,是因为你提到的那篇关于context engineering的博客文章是我在7月写的。
这是agent之年,所以7月基本上就是上个世纪了。在这次演讲之前,我回去又读了一遍。我在那篇博客中写的大部分内容今天仍然成立,但我不想浪费大家的时间重复博客里已经有的内容。
所以今天我想深入探讨一些我之前要么没有深入讨论,要么根本没有涉及的领域。实际上我们会关注Lance早期幻灯片中的discourage列,因为我个人认为探索那些非共识的想法往往会带来最大的启发。
今天演讲的主题是这些:首先我们会讨论一个更大的问题,为什么我们需要context engineering。然后会有更多关于context reduction的内容,更多关于context isolation的内容,最后是一些关于context offloading的新东西,我们正在Manus内部测试。
我今天分享的所有内容都在Manus的生产环境中,经过了实战检验,但我不知道它能持续多久,因为事情变化太快了。
好,让我们从第一个大问题开始:为什么我们需要context engineering,特别是当fine-tuning或post-training模型今天已经变得更容易获得的时候。例如,Hugging Face团队刚刚发布了TGI API,我很喜欢,设计很漂亮。
但对我来说,为什么需要context engineering这个问题,是通过几个痛苦的认识阶段得出的。
在创办Manus之前,我已经在自然语言处理或NLP领域工作了10多年,也就是我们在ChatGPT之前所说的构建语言模型。Manus实际上是我的第二或第三家公司。
在我之前的创业公司,我们从头开始训练自己的语言模型,做开放域信息提取、构建知识图谱,以及在此基础上的语义搜索引擎。那很痛苦。我们产品的创新速度完全受限于模型的迭代速度。
即使在那时,模型比今天小得多,但单个训练加评估周期仍然可能需要一到两周。最糟糕的是,那时我们还没有达到PMF,我们把所有时间都花在改进可能对产品根本不重要的benchmark上。
所以创业公司真的应该尽可能长时间地依赖通用模型和context engineering,而不是过早构建专门的模型。当然,现在这已经是某种常识了。
但随着你的产品成熟,开源基础模型变得更强,你会很容易想,嘿,也许我应该选一个强大的基础模型,用我的数据fine-tune它,让它在我的用例上表现得非常好。我们也试过。你猜怎么着?这是另一个陷阱。
要让RL真正运作良好,你通常需要固定一个action space,围绕当前产品行为设计reward,并生成大量on-policy的rollouts和反馈。但这也很危险,因为我们仍处于AI和Agent的早期阶段。一切都可能在一夜之间改变。
对我们来说,经典的例子是MCP的发布。它完全改变了Manus的设计,从一个紧凑的静态action space变成了无限可扩展的东西。如果你训练过自己的模型,你知道这种开放域问题超级难优化。
当然,你可以投入大量精力进行post-training来确保泛化。但那样你不就是在试图成为另一个OpenAI公司吗?因为你基本上是在重建他们已经构建的同一层。那是重复劳动。
所以经过所有这些铺垫,这是我的观点:要坚定你划定界限的地方。现在,context engineering是应用和模型之间最清晰、最实用的边界。所以相信你的选择。
00:15:00
好,让我们谈谈真正的技术。第一个话题,context reduction。
我想澄清两种不同的compaction操作,因为context reduction很有趣,但它也是一个新概念。有很多方法可以做到这一点,在Manus我们把它们分为compaction和summarization。
对于compaction,在Manus中,每个工具调用和工具结果实际上有两种不同的格式:full format和compact format。Compact版本首先剔除任何可以从文件系统或外部状态重建的信息。
例如,假设你有一个写文件的工具,它可能有两个字段:path和content字段。但一旦工具返回,你可以确保文件已经存在于环境中。所以在compact format中,我们可以安全地删除超长的content字段,只保留path。如果你的agent足够聪明,每当它需要再次读取该文件时,它可以简单地通过path检索它。所以没有信息真正丢失,只是外部化了。
这种可逆性至关重要,因为Agent会基于之前的actions和observations进行链式预测。你永远不知道哪个过去的action会在10步之后突然变得超级重要。你无法预测。所以这是通过compaction实现的可逆reduction。
当然,compaction只能带你走这么远。最终你的context仍然会增长并触及上限。这时我们将compaction与更传统的summarization结合起来。但我们做得非常小心。
例如,在summarization之前,我们可能会将context的关键部分offload到文件中。有时我们甚至更激进,我们可以将整个pre-summary context作为文本文件或简单的日志文件dump到文件系统中,以便稍后恢复。
就像Lance刚才提到的,有些人只使用globbing、grep。Globbing、grep对日志文件也有效。所以如果模型足够聪明,它甚至知道如何检索那些被summarized的pre-summarized context。
区别在于compaction是可逆的,但summarization不是。两者都减少了context长度,但它们的行为非常不同。
为了让这两种方法共存,我们必须在顶部跟踪一些context thresholds。你会有模型的硬context限制,比如100万tokens,今天很常见。但实际上大多数模型开始退化得更早,通常在200K左右。你会开始看到我们所说的context rot——重复、推理变慢、质量下降。
所以通过大量评估,识别那个pre-rot threshold非常重要,通常是128K到200K,并将其用作context reduction的触发器。每当你的context大小接近它时,你必须触发context reduction。但从compaction开始,而不是summarization。
Compaction不意味着压缩整个历史。我们可能compact最旧的50%的工具调用,同时保持较新的完整细节。所以模型仍然有新鲜的few-shot examples,知道如何正确使用工具。否则在最坏的情况下,模型会模仿行为并输出那些缺少字段的compact format。那完全错了。
Compaction之后,我们必须检查从这个compaction操作中实际获得了多少自由context。有时,在这个图中,经过多轮compaction后,收益很小,因为即使compact仍然使用context,这时我们就进行summarization。
但也要记住,在summarization时,我们总是使用数据的full版本,而不是compact版本。我们仍然保持最后几个工具调用和工具结果的完整细节,而不是summary,因为这可以让模型知道它在哪里停下来,并更顺畅地继续。
否则你会看到,在summarization之后,有时模型会改变它的风格、改变它的语气,我们发现保持几个完整的工具调用和工具结果examples真的有帮助。
00:19:22
好,现在我们已经讨论了reduction,让我们谈谈isolation。
我非常同意Cognition博客中的警告,不要使用multi-agent设置,因为当你有多个Agent时,在它们之间同步信息会变成噩梦。但这不是一个新问题。Multi-process或multi-thread协调一直是早期计算机编程中的经典挑战。我认为我们可以借鉴一些智慧。
在Go编程语言社区,有一句著名的话来自这个Gopher:"不要通过共享内存来通信。相反,通过通信来共享内存。"当然,这不是直接关于agent的,对于Agent有时甚至是错的。
但重要的是它突出了两种不同的模式:by communicating或by sharing memory。如果我们把这里的memory翻译成context,我们可以看到这个类比非常清楚。
By communicating是更容易理解的,因为它是经典的sub-agent设置。例如,main agent写一个prompt,如果prompt被发送到sub-agent,sub-agent的整个context只包含那个指令。
如果一个任务有简短清晰的指令,并且只有最终输出重要,比如在代码库中搜索特定片段,那就使用communication模式并保持简单,因为main agent不关心sub-agent如何找到代码,它只需要结果。这就是Claude Code通常做的,使用它的task工具将分离的清晰任务委托给一些sub-agents。
但对于更复杂的场景,相反,by sharing memory意味着sub-agent可以看到整个之前的context,意味着所有的工具使用历史。但sub-agent有它自己的system prompt和它自己的action space。
例如,想象一个Deep Research场景。最终报告依赖于大量中间搜索和笔记。在这种情况下,你应该考虑使用shared memory模式,或者用我们的语言说,by sharing context。
因为即使你可以将所有那些笔记和搜索保存到文件中,让sub-agent再次读取所有内容,但你只是在浪费延迟和context。如果你计算token数量,也许你使用的token甚至更多。
所以对于那些需要完整历史的场景,只需使用shared memory模式。但要注意,sharing context有点昂贵,因为每个sub-agent都有更大的输入要prefill,你会在input tokens上花费更多。而且由于system prompt和action space不同,你无法重用KV cache,所以你必须支付全价。
00:22:18
最后我们来谈谈context offloading(上下文卸载)。人们说offload时,通常指的是将工作上下文的部分内容移到外部文件中。
但随着系统的增长,特别是如果你决定集成MCP,你会发现工具本身也会占用大量上下文。工具太多会导致混乱,我们称之为context confusion(上下文混乱)。模型可能会调用错误的工具,甚至调用不存在的工具。
所以我们必须找到方法来卸载工具。目前常见的方法是对工具描述做dynamic RAG,比如根据当前任务或状态按需加载工具。
但这也会带来两个问题。首先,由于工具定义位于上下文的前端,你的KV cache每次都会重置。更重要的是,模型过去对已移除工具的调用仍然留在上下文中,这可能通过few-shot效应导致模型调用无效的工具或使用无效的参数。
为了解决这个问题,我们在Manus中实验了一种新的分层action space。本质上,我们让Manus可以从三个不同抽象层级中选择:#1 function calling,#2 sandbox utilities,#3 packages和API。
我们深入看看这三层。先从Level 1的function calling开始。这是经典方法,大家都知道。它通过constraint decoding保证schema安全,但我们都知道缺点,比如前面提到的会破坏cache,太多工具调用会造成混乱。
所以在Manus中,我们只使用固定数量的原子函数,比如读写文件、执行shell命令、搜索文件和互联网,以及一些浏览器操作。我们认为这些原子函数有非常清晰的边界,它们可以组合成更复杂的工作流。
然后我们把其他所有东西都卸载到下一层,也就是sandbox utilities。每个Manus会话都运行在一个完整的虚拟机沙箱中,运行在我们定制的Linux系统上。这意味着Manus可以使用shell命令来运行我们为Manus开发的预装工具。
比如,我们有格式转换器、语音识别工具,还有一个很特殊的工具叫Manus MCP CLI,这是我们调用MCP的方式。我们不会把MCP工具注入到function calling空间,而是在沙箱内通过命令行界面完成所有操作。
Utilities的好处是,你可以在不触及模型function calling空间的情况下添加新能力。如果你熟悉Linux,你总能找到这些新命令,甚至可以运行--help来了解如何使用新工具。
另一个好处是,对于大量输出,它们可以写入文件或分页返回结果,你可以用grep、cat、less、more等Linux工具即时处理结果。权衡是它对大量输出很好,但对需要低延迟的前后端交互不太理想,因为你总是需要可视化agent的交互并展示给用户。
然后是最后一层,我们称之为packages和APIs。这里Manus可以编写脚本来调用预授权的API或自定义包。比如,Manus可能使用3D设计库进行建模,或调用金融API获取市场数据。实际上,我们代表用户购买了所有这些API,包含在订阅中。所以我们在Manus中预装了很多API密钥,Manus可以访问这些API甚至密钥。
我认为这些非常适合需要大量计算和内存、但不需要把所有数据推入模型上下文的任务。比如,如果你分析一只股票全年的价格数据,你不会把所有数字喂给模型,而是让脚本计算,只把摘要放回上下文。
而且,由于代码和API高度可组合,你实际上可以在一步中串联很多操作。比如在一个典型的API中,你可以在一个Python脚本里完成获取城市名称、获取城市ID、获取天气。还有一篇我朋友写的论文叫CodeAct,很多人在讨论。我认为是同样的思路,因为代码是可组合的,可以在一步中做很多事情。
但它也不是schema安全的,很难对CodeAct做constraint decoding。所以我们认为应该为这些特性找到合适的场景。对我们来说,所有能在编译器、解释器、运行时内处理的事情,我们都用代码来做,否则我们使用sandbox utilities或function calls。
好处是,如果你有这三层,从模型的角度看,这三个层级仍然通过标准的function calls进行。所以接口保持简单、对cache友好,并且函数之间正交。因为sandbox utilities仍然通过shell函数访问,而使用API作为第三方应用时,你只是用file函数来读写文件,然后用shell函数执行。
所以我们认为这不会给模型增加开销,仍然是模型训练过的、已经熟悉的东西。
00:28:24
让我们放大视角,把这五个维度连接起来:offload、reduce、retrieve、isolate和cache。你会发现它们不是独立的。
Offload和retrieve能实现更高效的reduction,稳定的retrieval使isolation安全。但isolation也会减缓上下文增长,降低reduction的频率。然而,更多的isolation和reduction也会影响cache效率和输出质量。
所以归根结底,我认为context engineering是一门科学和艺术,需要在多个潜在冲突的目标之间找到完美平衡。这真的很难。
好,在结束之前,我想留给大家一个最后的思考,它有点与我刚才说的一切相反,那就是请避免context过度工程化。
回顾Manus发布以来的六七个月,实际上我们见到的最大飞跃并非来自添加更多花哨的context管理层或巧妙的retrieval技巧,而是来自简化,来自移除不必要的技巧并更多地信任模型。
每次我们简化架构,系统都变得更快、更稳定、更智能。因为我们认为,context engineering的目标是让模型的工作更简单,而不是更难。
所以如果你今天只记住一件事,我认为应该是:少构建,多理解。
Lance:
我们这里有一系列问题,我们可以开始回答,需要的话可以参考回slides。Peek,你的slides可以分享给大家吗?
Peak:
可以,我之后可以分享PDF版本。
Lance:
好的。我先看看这些问题,我们可以从最近的问题开始。
00:30:49
LLM如何调用各种shell工具?它如何知道哪些工具存在以及如何调用它们?也许你可以解释一下Manus使用的多层沙箱设置。
Peak:
可以想象你在使用一台新电脑,如果你了解Linux,你知道所有工具都位于/usr/bin。我们实际上做了两件事。
首先,我们在系统提示中有一个提示,告诉Manus,有很多预装的命令行工具位于某个特定文件夹。而且对于最常用的工具,我们已经在系统提示中列出了,但非常紧凑。我们不会告诉agent如何使用工具,只是列出它们,并告诉agent可以安全地使用--help标志,因为所有工具都是我们团队开发的,格式相同。
Lance:
我知道你谈了很多使用文件系统。你对使用索引的看法如何?你们会动态创建向量存储吗?如果处理的上下文足够大,你们如何处理?
Peak:
我认为这个领域没有对错之分。但在Manus,我们不使用索引数据库,因为现在每个Manus会话的沙箱都是新的,用户希望快速交互。所以实际上我们没有时间动态构建索引。
我们更像Claude Code,依赖grep和glob。但我认为如果你考虑构建更长期的记忆,或者想集成企业知识库,你仍然需要依赖外部向量索引,因为这关系到你能访问的信息量。但对于Manus,它在沙箱中操作,对于编程agent,你在代码库中操作,所以这取决于规模。
Lance:
那是个很好的后续问题。假设我是用户,我有Manus账户,我在多个会话中与Manus交互。你们有记忆的概念吗?Claude有claude.md文件,它们在Claude Code的所有不同会话中持久存在。你们如何处理长期记忆?
Peak:
实际上在Manus中,我们有一个叫"知识"的概念,有点像显式记忆。比如,每次你可以告诉Manus,"记住,每次我要求某些东西时以Excel格式交付",它不会自动插入到某个记忆中,而是会弹出一个对话框说,"这是我从之前对话中学到的,你想接受还是拒绝?"这是显式的,需要用户确认。
但我们也在探索更自动化的方式。比如,与聊天机器人相比,agent中一个很有趣的现象是用户更频繁地纠正agent。例如,Manus常犯的一个错误是在做数据可视化时,如果你使用中文、日文或韩文,很多时候会有字体问题,渲染的可视化中会出现错误。
所以用户经常会说,"你应该使用Noto Sans CJK字体"。对于这类事情,不同用户会有相同的纠正,我们需要找到一种方法来利用这种集体反馈,我们称之为通过在线学习实现自我改进的agent,但是以无参数的方式。
00:34:15
Lance:
这里有个不同的问题,我也经常思考。你在演讲最后提到,你们通过移除东西获得了很多收益。这很大程度上可能是因为模型能力在提升,所以你可以随着时间移除scaffolding。
你如何看待这个问题?因为这是我面临的最大挑战之一——随着时间推移,模型变得更好,我可以移除某些scaffolding部分。所以你是在一个不断上升的基础上构建,就像水位在上升。你会每隔几个月随着新版本发布重新审视架构并删除内容吗?你如何处理这个问题?
Peak:
这是个非常好的问题。实际上我们已经重构了Manus五次,我们在3月发布Manus,现在已经是10月了,五次。
所以我们认为你不能停止,因为模型不仅在改进,而且在变化,模型行为随时间在变化。一种方法是你可以与模型提供商密切合作,但我们也有另一个内部理论来评估和设计我们的agent架构。
我之前在Twitter上发过,基本上我们不关心静态基准测试的静态性能。相反,我们固定agent架构,在不同模型间切换。如果你的架构能从切换到更强模型中获得很多收益,那么某种程度上你的架构更具未来适应性,因为明天的弱模型可能和今天的强模型一样好。
所以我们认为在弱模型和强模型之间切换可以给你一些明年会发生什么的早期信号,让你有时间准备架构。
对于Manus Lite,我们经常每一到两个月做这种review。我们经常在内部使用开源模型,也许还有专有模型的早期访问权限,来准备下一个版本,甚至在下一个模型发布之前。
Lance:
这是个很好的观察。你实际上可以通过切换今天存在的不同模型来测试你的架构。这很有道理。
00:36:35
存储数据的格式有什么最佳实践或考虑因素吗?比如markdown文件、纯文本日志,你有特别偏好的吗?你如何看待文件格式?
Peak:
我认为不是纯文本或markdown的问题,我们总是优先考虑基于行的格式,因为这允许模型使用grep或按行范围读取。
而且Markdown有时会带来一些麻烦。你知道,模型被训练得很擅长使用Markdown,但有些模型如果你太频繁使用Markdown,它们经常会输出太多bullet points。
所以实际上我们更倾向于使用纯文本。
Lance:
有道理。
00:37:29
关于compaction和summarization,我们聊聊summarization。如何prompt来产生好的总结?Summarization是不可逆的,如果prompt不当会丢失信息。我想到的最佳答案是调整prompt以获得高召回率,你怎么看?
Peak:
我们尝试了很多prompt优化,发现一个简单方法非常有效:不要用自由形式的prompt让AI生成所有内容,而是定义一种schema,就像一个表单,有很多字段让AI填写。
例如,这里是我修改的文件,这是用户的目标,这是我停下的地方。如果使用这种更结构化的schema,输出是稳定的,你可以在此基础上迭代。所以不要使用自由形式的summarization。
Lance:
所以你用结构化输出而不是自由形式的summarization,来强制某些内容总是被总结?那compaction呢?
比如一个搜索工具,你有原始的搜索工具输出作为原始消息,然后compaction就只是像文件名之类的东西,对吗?
Peak:
对,不仅适用于工具调用,也适用于工具的结果。我们发现Manus中几乎每个操作都是可逆的,如果你能把它卸载到文件系统或外部状态。
对于大多数任务,你已经有了唯一标识符。例如,文件操作有文件路径,浏览器操作有URL,搜索操作有查询。所以它自然就在那里了。
Lance:
我想再强调一下这个问题,因为我经常遇到。比如agent使用搜索,执行后返回一个token量很大的工具调用。我不想把整个工具消息返回给agent,但又希望所有信息都可供agent做下一个决策时访问,同时不想让巨大的上下文块留在消息历史中。
你可以发送完整消息但稍后删除,Claude就这么做。也可以先总结再发送摘要,或者发送所有内容然后做compaction。你具体怎么考虑?
Peak:
这取决于场景。对于复杂搜索,比如有多个查询,你想收集重要内容并丢弃其他内容,我认为应该使用sub agents,或者我们内部称之为agent as tool。
从模型角度看,它仍然是一个函数,可能叫advanced search,但它触发的实际上是另一个sub agent,那个sub agent更像是一个workflow,有固定的输出schema返回给agent。
对于更简单的搜索,比如只是搜索Google,我们就使用完整详细格式并追加到上下文中,依赖compaction机制。但我们也总是指示模型将中间见解或关键发现写入文件,以防compaction发生得比模型预期的早。
如果你做得好,通过compaction实际上不会丢失太多信息,因为有时那些旧的工具调用在某个阶段后就不相关了。
Lance:
明白了。我喜欢agent as tool这个想法,我们也经常这么做,确实非常有效。
00:41:41
这引出了另一个有意思的点,你也提到了一点——agent间通信。你怎么处理这个问题?
Cognition的Walden Yan写了一篇很好的博客,说这是Devin的一个主要问题。如何确保agent间传递足够的信息,但又不会用太多上下文过载sub agent的prefill?
Peak:
Manus一个月前推出了Deep Research功能。我们内部称之为Agentic MapReduce,因为我们从MapReduce的设计中获得了灵感。
这对Manus来说有点特殊,因为session背后有一个完整的虚拟机。所以我们从主agent向sub agent传递信息的一种方式是共享同一个sandbox,文件系统就在那里,你只需要传递不同的路径。
我认为向sub agent发送信息并不难,更复杂的是如何从不同的agent获得正确的输出。我们这里有个技巧:每次主agent想要生成一个新的sub agent,或者可能10个sub agent时,你必须让主agent定义输出schema。
在sub agent的角度,有一个特殊的工具叫submit result。我们使用constrained decoding来确保sub agent提交回主agent的内容符合主agent定义的schema。
所以你可以想象这种MapReduce操作会生成一种类似电子表格的东西,而电子表格受schema约束。
Lance:
你在summarization和agent间通信中都使用schemas和结构化输出,就像用schemas作为agent和sub agent之间,或者工具和agent之间的契约,来确保以结构化、完整的方式传递足够的信息。
00:43:51
关于模型有什么想法?我想你们用Anthropic,但你们用开源模型吗?做微调吗?你谈到了很多关于KV Cache的工作,那可能需要用开源模型。你怎么考虑模型选择?
Peak:
我们现在不用任何开源模型,有意思的是这不是因为质量,而是成本。
我们常认为开源模型可以降低成本,但如果你达到Manus的规模,并且在构建真正的agent——输入远长于输出,那么KV Cache就超级重要。如果使用开源方案,分布式KV Cache很难实现。
如果使用那些前沿LLM提供商,他们有更可靠的全球分布式基础设施。所以有时如果你算一下,至少对Manus来说,使用这些旗舰模型有时甚至比使用开源模型更便宜。
现在我们不只用Anthropic。对我们来说,Anthropic模型是agentic任务的最佳选择,但我们也看到Gemini和OpenAI新模型的进展。
我认为现在这些前沿实验室的方向并没有趋同。例如,如果你做coding,当然应该用Claude;如果你想做更多多模态的事情,应该用Gemini;OpenAI的模型在复杂数学和推理方面超级好。
所以我认为对于像我们这样的应用公司,一个优势是我们不必只基于一个模型构建。你可以做一些任务级路由,甚至子任务或步骤级路由,如果你能做好KV Cache validation。
所以我认为这对我们是优势,我们内部做了很多评估来了解哪些模型用于哪些子任务。
Lance:
明白了。我想澄清一点,关于KV Cache,你从提供商那里使用什么具体功能来管理cache?比如Anthropic有input caching,是这个意思吗?
00:46:05
工具选择是个经典问题。你说不使用工具描述的索引和基于语义相似度动态获取工具。你怎么处理?太多工具的阈值是什么?
Peak:
Yeah, 首先,这取决于模型,不同模型对工具的容量不同。但我认为经验法则是不要包含超过30个工具,这只是我脑海中的一个随机数字。
但实际上,如果你在构建一个通用AI agent like Manus,你要确保那些原生函数是超级原子化的。所以实际上我们需要放入action space的原子化函数并没有那么多。
对于Manus,我们现在只有10到20个原子化函数,其他所有东西都在sandbox里。所以我们不需要动态拉取工具。
Lance:
让我解释得更清楚一点。你有比如10个工具可以被agent直接调用,但agent也可以选择写一个脚本然后执行脚本,这极大地扩展了action space,而不需要为每个可能的脚本设置独立工具。所以一个非常通用的工具,比如写脚本然后运行它,就能做很多事情,是这个意思吗?
Peak:
对,是的。我们为什么如此自信地称Manus为通用agent?因为它运行在计算机上,而计算机是图灵完备的。
计算机是人类最好的发明,理论上agent可以做任何事情,可能是一个初级实习生能用计算机做的任何事情。所以有了shell工具和文本编辑器,我们认为它已经是图灵完备的了。你可以把很多东西卸载到sandbox。
Lance:
明白了。那Manus是怎样的?你提到了Codex和code agents。我理解Codex中模型总是会生成一个脚本,然后在代码sandbox中运行,所以每个工具调用实际上都是生成并运行一个脚本。
听起来你做的是混合方法,有时模型可以直接调用工具,但其他时候它可以选择在sandbox中做一些事情,对吗?
Peak:
对,我认为这非常重要,因为我们实际上尝试过完全使用Codex for Manus,但问题是如果你使用代码,你无法利用constrained decoding,事情可能会出错。
但你知道,Codex有一些特殊的用例,就像我之前在slides中提到的,比如处理大量数据。你不必把所有东西都放在工具结果中,而是把它放在Python的运行时内存中,只把结果返回给模型。
所以我们认为应该以混合方式来做。
Lance:
明白了,允许工具调用,你有一些工具(可能10个左右)直接调用,还有一些工具实际上在sandbox本身中运行。
00:49:34
Planning呢?Manus有这个todo工具,会生成一个todo列表和任务清单,跟我讲讲这个。
Peak:
这很有意思,因为一开始Manus使用todo.md范式。我不想用"愚蠢"这个词,但实际上它浪费了很多轮次。在三四月份,如果你查看一些Manus任务的日志,可能有1/3的action是关于更新todo列表的,浪费了很多tokens。
所以现在我们使用更结构化的planning。比如你用Manus,底部有一个planner,在系统内部它也是一种工具调用,我们用agent as tool范式实现的。所以有一个独立的agent在管理计划。
实际上现在最新版本我们不再使用todo.md了。当然,todo.md仍然有效,可以生成好的结果,但如果你想节省tokens,可以找到另一种方式。
Lance:
明白了,所以是一个planner agent,对于子任务更像是agent as tool调用类型的东西。
Peak:
对。有一个独立的agent很重要,它有不同的视角,可以做一些外部审查,你可以为planning使用不同的模型。例如,有时Grok可以生成一些非常有趣的见解。
Lance:
那关于multi-agent呢?你可能有一个planning agent,有自己的上下文窗口,制定计划,产生某种计划对象,可能是一个文件,或者直接调用sub agents。你怎么考虑这个?通常建议使用多少个不同的sub agents?
Peak:
这也取决于你的设计。但在Manus,Manus实际上不是典型的multi-agent系统。
比如我们见过很多按角色划分的不同Agent,像设计师agent、编程agent、经理agent。我们不这么做,因为我们认为这是人类公司的运作方式,这是由于人类上下文的局限性。
在Manus,Manus是一个multi-agent系统,但我们不按角色划分。我们只有很少的Agent。
举例来说,我们有一个巨大的通用执行器agent、一个planner agent、一个知识管理agent,可能还有一些数据API注册agent。
我们对添加更多sub agents非常谨慎,因为就像我们之前提到的,通信非常困难。我们更多地将sub agents实现为agent as tool,就像之前提到的。
Lance:
这是个很好的观点。我经常看到这个错误,或者不知道算不算错误,但经常看到agent的拟人化,比如"我的设计师agent"。我认为在sub agents中套用人类组织架构图是一种牵强的类比。
那knowledge manager会做什么,比如knowledge manager的任务是什么?
Peak:
甚至更简单。就像我们提到的,我们有一个知识系统,knowledge agent做的就是审查用户和agent之间的对话,找出应该保存在长期记忆中的内容。就这么简单。
Lance:
明白了,就像一个记忆管理器、planner,然后你有可以调用sandbox中所有工具或操作的通用执行器sub agent。这很有道理,保持简单。
00:53:20
关于guard railing和安全性,有人问了这个问题。你怎么考虑这个?我想sandbox的好处就在这里,跟我讲讲你的想法。
Peak:
这是个非常敏感的问题,因为如果你有一个连接到互联网的sandbox,一切都是危险的。
所以我们在guard railing上投入了很多精力。至少我们不让信息离开sandbox。例如,如果你遇到prompt injection,我们对出站流量有一些检查,确保没有tokens会离开sandbox。
如果用户想从sandbox打印一些东西出来,我们有那种移除机制来确保没有信息离开sandbox。
但另一方面,我们在Manus中有一个浏览器,浏览器非常复杂。例如,如果你登录一些网站,你可以选择让Manus持久化你的登录状态。这变得非常棘手,因为有时网页的内容也可能是恶意的,可能在做prompt injection。我认为这在某种程度上超出了应用公司的范围。所以我们与那些computer use模型提供商密切合作,比如Anthropic和Google,他们在添加很多guardrails。所以现在在Manus中,每次你做一些敏感操作,无论是在浏览器中还是在sandbox中,Manus都会要求手动确认,你必须接受它,否则你必须接管自己完成。
所以我认为我们很难设计一个AI的、设计得很好的解决方案,但这是一个渐进的方法。现在我们让用户更频繁地接管,但如果模型本身的guardrail变得更好,我们可以做得更少。
Lance:
关于eval的话题呢?这在网上讨论了很多。你可能看到了Claude Code,他们谈到对代码做更少的正式eval,因为代码evals基本上饱和了,更多是内部dogfooding。你怎么看待eval?它们有用吗?什么eval真正有用?你的方法是什么?
Peak:
在Manus发布时,我们使用像GAIA这样的公开学术benchmarks。但在向公众发布后,我们发现它非常不对齐。在GAIA上得高分的模型,用户并不喜欢。所以现在我们使用三种不同的评估。
首先,最重要的是,对于Manus中每个完成的session,我们会请求用户给出反馈,1到5星。这是金标准,我们总是关心平均用户评分,这是第一位的。
第二,我们仍然使用一些内部自动化测试,有可验证的结果。例如,我们创建了自己的数据集,有明确的答案。
我们也仍然使用很多公开学术benchmark,但我们也创建了一些更专注于执行的数据集,因为大多数benchmark都是只读测试。所以我们设计了一些执行任务或事务性任务。因为我们有sandbox,可以频繁重置测试环境。这些是自动化部分。
最重要的第三点,我们有很多实习生。你必须使用很多真实的人类实习生来评估网站生成或数据可视化这样的事情,因为很难设计一个好的奖励模型来判断输出是否视觉上吸引人。这关乎品味。所以我们仍然依赖很多人工评估。
00:57:10
Lance:
我想问一个问题:使用可验证奖励的强化学习,对比直接构建工具调用Agent。
比如Claude Code,他们的优势在于自己构建了harness,可以在harness上进行RL训练,让模型在他们提供的工具上表现得非常好。你们做RL吗?
因为这种情况下需要使用开源模型。我最近一直在研究这个,就是直接使用模型提供商的工具调用能力,还是在自己的环境和harness中自己做RL。
Peak:
在创办Manus之前,我是做模型训练的,做了很多年的pre-training和post-training RL。
但我必须说,现在如果你有足够的资源,可以尝试。但实际上,如我之前提到的,MCP在这里是个重大变革。因为如果你要支持MCP,你就不是在使用固定的action space。如果不是固定的action space,就很难设计好的reward,而且无法生成大量的rollouts,反馈会不平衡。
所以如果你想构建一个支持MCP的模型,你实际上是在自己构建foundation model。我认为社区里的每个人,每个模型公司,都在为你做同样的事情。
所以现在我不认为应该在RL上花太多时间。但如我之前提到的,我们正在探索新的方式,可能称之为个性化或某种在线学习,但使用parameter-free的方式,比如集体反馈。
Lance:
沿着这个思路再问一个问题:比如Anthropic在Claude Code中对某些工具进行了强化学习和可验证奖励的训练。
你们有没有发现,可以通过模仿他们的harness,使用相似的工具名称来解锁同样的能力?比如我相信他们使用了glob、grep以及其他一些文件系统操作工具。你们能否通过在自己的harness中使用完全相同的工具、相同的工具名称和描述来复现同样的功能?
Peak:
我没有明确的答案。但对我们来说,我们实际上尝试不使用相同的名称,因为如果你设计自己的函数,可能对该函数有不同的需求,输入参数可能会不同。
所以你不想让模型混淆。如果模型在大量post-training数据上训练过某些内部工具,你不想让模型产生困惑。
交流与合作
如果希望和我交流讨论,或参与相关的讨论群,或者建立合作,请加微信,联系方式请点击 -> 专栏简介 及 联系方式 2024。
本文于2025.10.17 首发于微信公众号。
