2025 上下文工程最新进展深度解析(2):Peak Ji 分享 Manus最新的上下文工程经验
2025 上下文工程最新进展深度解析(2):Peak Ji 分享 Manus最新的上下文工程经验
2025 上下文工程最新进展深度解析(2):Peak Ji 分享 Manus最新的上下文工程经验 2025 上下文工程最新进展深度解析(2):Peak Ji 分享 Manus最新的上下文工程经验 Modified October 16, 2025 Audio or video is not supported Please download the file and open it with the appropriate software. 1.mp4 · 148.59MB 1 00:00 因为即使你可以将所有这些笔记和搜索结果保存到文件中,让子智能体重新读取所有内容,但你只是在浪费延迟和上下文。 如果你计算token的数量,你可能会使用更多的token来做这件事。 对于那些需要完整历史记录的场景,就使用共享内存模式,但要注意,共享上下文是昂贵的 因为每个子智能体都有一个更大的输入需要预填充,这意味着你会在输入token上花费更多,而且由于系统提示和行动空间不同,你无法重用KV缓存,所以你必须支付全价。 上下文卸载 当人们说“卸载”时,他们通常指的是将工作上下文的一部分移动到外部文件中。 但随着你的系统增长,特别是如果你决定集成MCP,有一天你会意识到工具本身也会占用大量上下文,上下文中有太多的工具会导致混淆。 我们称之为“上下文混淆”,模型可能会调用错误的工具,甚至是根本不存在的工具。 所以我们必须找到一种方法来卸载工具。 目前一种常见的方法是对工具描述进行动态RAG(检索增强生成)。 例如,根据当前任务或状态按需加载工具。 但这也会导致两个问题。 首先,由于工具定义位于上下文的前面,你的KV缓存每次都会重置。 最重要的是,模型过去对已移除工具的调用仍然在上下文中。 所以这可能会误导模型调用无效的工具或使用无效的参数。 为了解决这个问题,我们正在Manus中试验一种 新的分层行动空间。 基本上,我们可以让Manus从三个不同层次的抽象中进行选择: 第一层是函数调用, 第二层是沙箱实用程序, 第三层是包和API。 让我们深入探讨这三层行动空间。 函数调用层卸载 这是经典的,每个人都知道。 由于约束解码,它是模式安全的。但我们都知道它的缺点。 例如,我们提到了破坏缓存,以及太多的工具调用可能会导致混淆。 所以,在Manus中,我们现在只使用固定数量的原子函数。 例如,读写文件、执行shell命令、在互联网上搜索文件,以及一些浏览器操作。 我们认为这些原子函数有非常清晰的边界,它们可以协同工作,组成更复杂的工作流。 沙箱程序卸载 然后我们将其他所有东西都卸载到下一层,即沙箱实用程序。 如你所知,每个Manus会话都在一个完整的虚拟机沙箱内运行。 它运行在我们自己定制的Linux系统上,这意味着Manus可以使用shell命令来运行我们为Manus开发的预装实用程序。 例如,我们有一些格式转换器、语音识别实用程序,甚至还有一个非常特殊的,我们称之为MCP CLI,这就是我们调用MCP的方式。 我们不将MCP工具注入到函数调用空间中,而是在沙箱内通过命令行界面完成所有操作。 实用程序非常棒,因为你可以添加新功能而无需触及模型的函数调用空间。 你知道,这就像你电脑里预装的一些命令,如果你熟悉Linux,你总能知道如何找到那些新命令,你甚至可以运行 help来弄清楚如何使用一个新工具。 另一个好处是,对于较大的输出,它们可以直接写入文件或分页返回结果,你可以使用所有那些Linux工具,如grep、cat、less、more等来即时处理这些结果。 所以这里的权衡是,它对于大输出非常好,但对于与前端的低延迟来回交互就不那么好了,因为你总是需要可视化你的智能体的交互并展示给用户。 所以这里有点棘手,但我们认为它已经卸载了很多东西。 包和API卸载 在这里,Manus可以编写Python脚本来调用预授权的API或自定义包。 例如,Manus可能会使用一个3D设计库进行建模,或者调用一个金融API来获取市场数据。实际上,我们已经代表用户购买了所有这些API并为他们支付了费用,这包含在订阅中。 所以我们基本上在Manus中预装了很多API密钥,Manus可以使用这些密钥访问这些API。 我认为这非常适合那些需要在内存中进行大量计算,但不需要将所有数据都推送到模型上下文中的任务。 例如,想象一下你正在分析一只股票一整年的价格数据。你不会把所有数字都喂给模型。 相反,你应该让脚本来计算,只把摘要放回上下文中。 而且, 由于代码和API是高度可组合的,你实际上可以在一步中链接很多东西。 例如,在一个典型的API中,你可以在一个Python脚本中完成获取城市名称、获取城市ID、获取天气等所有操作。 我一个朋友有一篇名为《CodeAct》的论文,很多人都在讨论。 CodeAct是一个通用的多轮交互框架,适用于LLM Agent的实际应用。 它定义了三个角色: Agent、用户和环境。 Agent通过与用户或环境的交互接收观察(输入),并通过生成Python代码来执行行动(输出)。 CodeAct的核心思想是 将所有与环境交互的行动统一为Python代码,Agent通过执行代码并接收执行结果来进行多轮交互。 我认同这样的想法,因为代码是可组合的,可以在一步中完成很多事情,但它也不是模式安全的。 但在代码上进行约束解码非常非常困难。 所以你应该为这些功能找到合适的场景。 对我们来说,使用所有可以在编译器或解释器运行时内部处理的东西,Manus用代码来做,否则使用沙箱实用程序或函数调用。 好处是,如果你有这三层,从模型的角度来看,所有三个级别仍然通过标准的函数调用。所以接口保持简单、缓存友好,并且在函数之间是正交的。 Audio or video is not supported Please download the file and open it with the appropriate software. 1.mp4 · 148.59MB 1 00:00 Audio or video is not supported Please download the file and open it with the appropriate software. 1.mp4 · 148.59MB 1 00:00 因为即使你可以将所有这些笔记和搜索结果保存到文件中,让子智能体重新读取所有内容,但你只是在浪费延迟和上下文。 如果你计算token的数量,你可能会使用更多的token来做这件事。 对于那些需要完整历史记录的场景,就使用共享内存模式,但要注意,共享上下文是昂贵的 因为每个子智能体都有一个更大的输入需要预填充,这意味着你会在输入token上花费更多,而且由于系统提示和行动空间不同,你无法重用KV缓存,所以你必须支付全价。 上下文卸载 当人们说“卸载”时,他们通常指的是将工作上下文的一部分移动到外部文件中。 但随着你的系统增长,特别是如果你决定集成MCP,有一天你会意识到工具本身也会占用大量上下文,上下文中有太多的工具会导致混淆。 我们称之为“上下文混淆”,模型可能会调用错误的工具,甚至是根本不存在的工具。 所以我们必须找到一种方法来卸载工具。 目前一种常见的方法是对工具描述进行动态RAG(检索增强生成)。 例如,根据当前任务或状态按需加载工具。 但这也会导致两个问题。 首先,由于工具定义位于上下文的前面,你的KV缓存每次都会重置。 最重要的是,模型过去对已移除工具的调用仍然在上下文中。 所以这可能会误导模型调用无效的工具或使用无效的参数。 为了解决这个问题,我们正在Manus中试验一种 新的分层行动空间。 基本上,我们可以让Manus从三个不同层次的抽象中进行选择: 第一层是函数调用, 第二层是沙箱实用程序, 第三层是包和API。 让我们深入探讨这三层行动空间。 函数调用层卸载 这是经典的,每个人都知道。 由于约束解码,它是模式安全的。但我们都知道它的缺点。 例如,我们提到了破坏缓存,以及太多的工具调用可能会导致混淆。 所以,在Manus中,我们现在只使用固定数量的原子函数。 例如,读写文件、执行shell命令、在互联网上搜索文件,以及一些浏览器操作。 我们认为这些原子函数有非常清晰的边界,它们可以协同工作,组成更复杂的工作流。 沙箱程序卸载 然后我们将其他所有东西都卸载到下一层,即沙箱实用程序。 如你所知,每个Manus会话都在一个完整的虚拟机沙箱内运行。 它运行在我们自己定制的Linux系统上,这意味着Manus可以使用shell命令来运行我们为Manus开发的预装实用程序。 例如,我们有一些格式转换器、语音识别实用程序,甚至还有一个非常特殊的,我们称之为MCP CLI,这就是我们调用MCP的方式。 我们不将MCP工具注入到函数调用空间中,而是在沙箱内通过命令行界面完成所有操作。 实用程序非常棒,因为你可以添加新功能而无需触及模型的函数调用空间。 你知道,这就像你电脑里预装的一些命令,如果你熟悉Linux,你总能知道如何找到那些新命令,你甚至可以运行 help来弄清楚如何使用一个新工具。 另一个好处是,对于较大的输出,它们可以直接写入文件或分页返回结果,你可以使用所有那些Linux工具,如grep、cat、less、more等来即时处理这些结果。 所以这里的权衡是,它对于大输出非常好,但对于与前端的低延迟来回交互就不那么好了,因为你总是需要可视化你的智能体的交互并展示给用户。 所以这里有点棘手,但我们认为它已经卸载了很多东西。 包和API卸载 在这里,Manus可以编写Python脚本来调用预授权的API或自定义包。 例如,Manus可能会使用一个3D设计库进行建模,或者调用一个金融API来获取市场数据。实际上,我们已经代表用户购买了所有这些API并为他们支付了费用,这包含在订阅中。 所以我们基本上在Manus中预装了很多API密钥,Manus可以使用这些密钥访问这些API。 我认为这非常适合那些需要在内存中进行大量计算,但不需要将所有数据都推送到模型上下文中的任务。 例如,想象一下你正在分析一只股票一整年的价格数据。你不会把所有数字都喂给模型。 相反,你应该让脚本来计算,只把摘要放回上下文中。 而且, 由于代码和API是高度可组合的,你实际上可以在一步中链接很多东西。 例如,在一个典型的API中,你可以在一个Python脚本中完成获取城市名称、获取城市ID、获取天气等所有操作。 我一个朋友有一篇名为《CodeAct》的论文,很多人都在讨论。 CodeAct是一个通用的多轮交互框架,适用于LLM Agent的实际应用。 它定义了三个角色: Agent、用户和环境。 Agent通过与用户或环境的交互接收观察(输入),并通过生成Python代码来执行行动(输出)。 CodeAct的核心思想是 将所有与环境交互的行动统一为Python代码,Agent通过执行代码并接收执行结果来进行多轮交互。 我认同这样的想法,因为代码是可组合的,可以在一步中完成很多事情,但它也不是模式安全的。 但在代码上进行约束解码非常非常困难。 所以你应该为这些功能找到合适的场景。 对我们来说,使用所有可以在编译器或解释器运行时内部处理的东西,Manus用代码来做,否则使用沙箱实用程序或函数调用。 好处是,如果你有这三层,从模型的角度来看,所有三个级别仍然通过标准的函数调用。所以接口保持简单、缓存友好,并且在函数之间是正交的。 因为你知道,我们提到的沙箱实用程序,仍然使用shell工具来访问这些工具,使用shell函数。 同样,如果你在第三方应用程序中使用API,只是使用文件函数来写入或读取文件,然后使用shell函数来执行它。 这不会给模型增加开销,它仍然是模型被训练过的、已经熟悉的所有东西。 所以,让我们把视野拉远,将这五个维度联系起来: 卸载、缩减、检索、隔离和缓存。 你会发现它们并非相互独立。 我们可以看到, 卸载和检索可以实现更高效的缩减,而稳定的检索则使隔离变得安全。 隔离也会减慢上下文并降低缩减的频率。更多的隔离和缩减也会影响缓存效率和输出质量。 所以,归根结底,我认为上下文工程是一门科学与艺术,需要在多个可能相互冲突的目标之间取得完美的平衡。 这真的很难。 回顾Manus发布以来的六七个月, 我们所见过的最大飞跃 实际上并非来自添加更多花哨的上下文管理层或巧妙的检索技巧。 它们都来自简化,来自移除不必要的技巧,以及更多地信任模型。 每当我们简化架构时,系统就会变得更快、更稳定、更智能。 因为我们认为上下文工程的目标是让模型的工作更简单,而不是更难。 所以,如果今天你能从中学到一件事,我认为那应该是:少构建,多理解。 未完待续。。。 相关分享文档地址: https://hqexj12b0g.feishu.cn/wiki/T7Wwwcz82icWaFk3jOecb4lPnSb 相关文章: 2025上下文工程最新进展深度解析(1):Manus Co founder Peak Ji与LangChain Lance的分享 2025上下文工程最新进展深度解析(1):Manus Co founder Peak Ji与LangChain Lance的分享 AI Agent 迎来了上量的阶段,好的开始! AI Agent 迎来了上量的阶段,好的开始! 2025下半程,Agent War正式开打!刺刀已然见红! 2025下半程,Agent War正式开打!刺刀已然见红! 🔗 原文链接: https://mp.weixin.qq.com/s/ MJJbc44... https://mp.weixin.qq.com/s/ MJJbc44... 原创 Brad强 一支烟花AI2025年10月16日 16:42 上海 Context Engineering for AI Agents PEAK JI · MANUS.IM LESSONS FROM BUILDING MANUS Manus的上下文工程 Peak Ji 之前在 25 年 7 月份分享的内容: 🔗 https://manus.im/zh cn/blog/Context Engineering for AI Agents Lessons from Building Manus 下面的内容是Peak 25年10月分享的内容: 我非常激动今天能在这里分享一些我们从构建Manus中学到的关于上下文工程的新鲜经验。 我之所以说“新鲜经验”,是因为我意识到我上一篇关于上下文工程的博客文章是在七月份写的,而今年是“智能体之年”,所以七月基本上是上个世纪的事了。 当然,在这次会议之前,我又回去读了一遍,幸运的是,我认为我在那篇博客中写的大部分内容今天仍然适用。但我不想浪费大家的时间,只是重复博客里已经有的内容。 所以今天,我想深入探讨一些我之前没有深入或者完全没有涉及的领域。实际上,我们将重点关注Lance之前幻灯片中“不鼓励”的那一栏, 因为我个人认为,探索那些非共识的想法往往能带来最大的启发。 为什么需要上下文工程? 我今天分享的一切都已经在Manus的生产环境中得到了实战检验,但我不知道它能持续多久,因为事情变化得太快了。尤其是在今天,微调或后训练模型已经变得更加容易。 例如,思考机器团队(Thinking Machine team)刚刚发布了Tinker API,我非常喜欢它的设计。 但对我来说,“为什么需要上下文工程”这个问题实际上是经过了几个痛苦的认识阶段才得出的。 在创办Manus之前,我已经在自然语言处理(NLP)领域工作了十多年,这基本上就是我们所说的构建语言模型,但在ChatGPT之前。 Manus实际上是我的第二或第三家公司。 在我之前的创业公司,我们从头开始训练自己的语言模型,用于开放领域信息提取,并在此基础上构建知识图谱和语义搜索引擎。 那段经历非常痛苦。 我们产品的创新速度完全受限于模型的迭代速度。 你知道,即使在当时,模型比现在小得多,但一个单一的训练加评估周期可能需要一到两周。 最糟糕的是,那时我们还没有达到产品市场契合(PMF),却把所有时间都花在改进那些可能对产品根本不重要的基准测试上。 所以我认为,初创公司真的应该尽可能长时间地依赖通用模型和上下文工程,而不是过早地构建专门的模型。当然,我想现在这已经成为某种共识了。 但随着你的产品成熟和开源基础模型变得更强大, 我知道你很可能会想: “嘿,也许我应该选择一个强大的基础模型,用我的数据进行微调,让它在我的用例中表现得非常好。” 我们也尝试过,结果发现这是另一个陷阱。 为了让AI真正发挥作用,你通常需要固定一个行动空间,围绕你当前的产品行为设计一个奖励机制,并生成大量的策略内(on policy)部署和反馈。 但是,这也是危险的,因为我们仍处于AI和智能体的早期阶段。 一切都可能在一夜之间发生变化。 对我们来说,典型的例子就是MCP(Model Context Protocol)的推出。 它彻底改变了Manus的设计,从一个紧凑的静态行动空间变成了一个可以无限扩展的东西。 如果你曾经训练过自己的模型,你就会知道这种开放领域问题是超级难以优化的。 当然,你可以投入大量精力进行后训练以确保泛化能力,但那样你不就基本上是在试图自己成为一家语言模型公司吗? 因为你基本上是在重建他们已经构建好的那一层,这是重复劳动。 所以,在所有这些铺垫之后,我的观点是: 要坚定地划清界限。 目前,上下文工程是应用和模型之间最清晰、最实用的界限。 所以,相信你的选择。 上下文缩减 我想澄清两种不同的压缩操作,因为我们认为上下文缩减虽然引人入胜,但也是一个新概念。有很多方法可以做到这一点。 在Manus,我们将其分为 压缩(compaction) 和 摘要(summarization) 。 对于压缩,在Manus中,每个工具调用和工具结果实际上都有两种不同的格式:完整格式和紧凑格式。 紧凑版本会去除任何可以从文件系统或外部状态中重建的信息。 例如,假设你有一个写入文件的工具,它可能有路径(path)和内容(content)两个字段。但是一旦工具返回,你可以确保文件已经存在于环境中。 所以在紧凑格式中,我们可以安全地丢弃超长的内容字段,只保留路径。 如果你的智能体足够聪明,那么每当它需要再次读取该文件时,它都可以简单地通过路径来检索。 所以,没有信息真正丢失,只是被外部化了。 我们认为这种可逆性至关重要,因为智能体确实会基于之前的行动和观察进行链式预测,你永远不知道哪个过去的行动会在10步之后突然变得超级重要。 你无法预测。 所以,这是一种通过压缩实现的可逆缩减。 当然,压缩只能带你走这么远。 最终,你的上下文仍然会增长并触及天花板。 那时,我们就将压缩与更传统的摘要结合起来,但我们做得非常小心。 例如,在进行摘要之前,我们可能会将上下文的关键部分卸载到文件中。 有时我们甚至会更激进,我们可以将整个摘要前的上下文转储为文本文件或简单的日志文件到文件系统中,以便我们以后可以随时恢复。 就像Lance刚才提到的,有些人只使用glob和grep,你知道,glob也适用于日志文件。 所以如果模型足够聪明,它甚至知道如何检索那些摘要前的上下文。 所以我认为这里的区别在于,压缩是可逆的,而摘要不是。 两者都减少了上下文长度,但它们的行为非常不同。 为了让这两种方法共存,我们必须在顶层跟踪一些上下文长度阈值。 比如,你的模型有硬性的上下文限制,比如说100万个token,这在今天很常见。 但实际上,大多数模型在更早的时候就开始性能下降,通常在200k左右,你会开始看到我们所说的“上下文腐烂”(context rot),比如重复、推理变慢、质量下降。 所以,通过大量的评估,识别出那个“腐烂前”的阈值非常重要。 它通常在128k到200k之间,并将其用作上下文缩减的触发器。 每当你的上下文大小接近这个阈值时,你就必须触发上下文缩减,但要从压缩开始,而不是摘要。 压缩并不意味着压缩整个历史记录。 我们可能会压缩最早的50%的工具调用,同时保留较新的工具调用的完整细节,这样模型仍然有新鲜的few shot示例,知道如何正确使用工具。 否则,在最坏的情况下,模型会模仿这种行为,并输出那些缺少字段的紧凑格式,那就完全错了。 在压缩之后, 我们必须检查我们从这次压缩操作中实际获得了多少空闲上下文。 就像这张图所示,经过多轮压缩后,有时收益非常小,因为即使是紧凑格式,它仍然使用上下文。这时我们才进行摘要。 但也要记住, 在进行摘要时,我们总是使用完整版本的数据,而不是紧凑版本。 我们仍然会保留最后几个工具调用和工具结果的完整细节,而不是摘要,因为这可以让模型知道它从哪里中断,并能更平滑地继续。 否则你会发现,摘要之后,模型有时会改变它的风格和语气。 我们发现 保留几个完整的工具调用和工具结果示例真的很有帮助。 上下文隔离 我非常同意Cognition的博客,他们警告不要使用多智能体设置,因为当你有多个智能体时,它们之间的信息同步就成了一场噩梦。 但是,你知道,这不是一个新问题。 多进程或多线程协调在计算机编程的早期就是一个经典挑战。我认为我们可以从中借鉴一些智慧。 我不知道今天这里有多少Go语言的程序员,但在Go编程语言社区, 有一句来自这个Gopher的名言: “不要通过共享内存来通信,而要通过通信来共享内存。” 当然,这并不直接适用于智能体,有时甚至对智能体是错误的。 但我认为重要的是,它突出了两种截然不同的模式: 通过通信或通过共享内存。 如果我们将这里的“内存”一词翻译成“上下文”,我们可以很清楚地看到这种并行关系。 “通过通信”更容易理解,因为它是经典的子智能体设置。 例如, 主智能体编写一个提示,然后发送给子智能体,子智能体的整个上下文只包含该指令。 我们认为,如果一个任务有一个简短、清晰的指令,并且只关心最终输出,比如在代码库中搜索特定代码片段,那么就应该使用通信模式,保持简单。 因为主智能体不关心子智能体如何找到代码,它只需要结果。 这就像Cloud code通常使用其“任务”工具将一个独立的、清晰的任务委托给某个子智能体一样。 但对于更复杂的场景,相比之下,“通过共享内存”意味着子智能体可以看到整个先前的上下文,也就是所有的工具使用历史。 但是,子智能体有自己的系统提示和自己的行动空间。 例如,想象一个深度研究场景,最终报告依赖于大量中间搜索和笔记。 在这种情况下,你应该考虑使用共享内存模式,或者用我们的话说,通过共享上下文。