目 录CONTENT

文章目录

【上下文工程】Agent的上下文工程:Manus实战经验深度解析

EulerBlind
2025-10-23 / 0 评论 / 0 点赞 / 6 阅读 / 0 字

论文地址

原文链接Context Engineering for AI Agents: Lessons from Building Manus

作者:Yichao 'Peak' Ji

发布时间:2025年7月18日

机构:Manus AI

核心内容概述

这篇文章来自 Manus AI 团队的技术分享,详细阐述了在构建生产级 AI Agent 系统时,关于上下文工程(Context Engineering)的核心设计理念与实践经验。Manus 是一个面向数百万用户的 AI Agent 产品,其团队在开发过程中积累了大量关于如何优化 Agent 上下文管理的宝贵经验。

文章的核心观点是:在当前的 AI Agent 开发范式中,上下文工程比端到端模型训练更具工程价值。这个选择背后有深刻的技术和商业考量,而如何设计和管理 Agent 的上下文,直接决定了系统的性能、成本和可维护性。

这不是一篇纯理论的技术文档,而是一份来自真实生产环境的"战地笔记"。Manus 团队经历了四次框架重构,通过无数次的试错和优化,最终总结出了这套上下文工程方法论。正如作者所说,他们戏称这个过程为"随机梯度下降"(Stochastic Gradient Descent, SGD)——虽然不够优雅,但确实有效。

技术背景:为什么选择上下文工程而非模型训练

在深入具体的技术细节之前,我们需要理解 Manus 团队面临的核心决策:是训练一个端到端的 Agent 模型,还是基于现有大模型的上下文学习能力来构建系统?

模型训练的困境

作者分享了他在 NLP 领域十年的经验教训。在 BERT 时代(2018年),模型必须经过微调(Fine-tuning)才能迁移到新任务。这个过程通常需要:

  1. 数周的训练时间:即使是相对较小的模型
  2. 缓慢的反馈循环:难以快速迭代和验证想法
  3. 高昂的试错成本:每次调整都需要重新训练

更致命的是,在产品市场匹配(PMF, Product-Market Fit)阶段,这种缓慢的迭代速度会严重拖累产品发展。作者提到了他上一个创业项目的惨痛教训:花费大量时间从头训练用于开放信息提取和语义搜索的模型,结果 GPT-3 和 Flan-T5 的出现让这些内部模型一夜之间变得过时。

上下文学习的优势

相比之下,基于上下文学习(In-Context Learning)的方法具有显著优势:

快速迭代:改进可以在几小时内交付,而不是几周。这对于快速验证产品假设至关重要。

模型无关性:产品与底层模型保持正交关系。当更强大的模型出现时,系统可以自动受益。用作者的比喻:如果模型进步是上涨的潮水,基于上下文工程的系统就是那条船,而不是固定在海床上的柱子。

工程可控性:上下文设计是纯粹的工程问题,不需要等待模型训练完成,可以通过系统性的方法进行优化。

这个决策背后体现了一个重要的工程哲学:在技术快速演进的领域,保持系统的灵活性和适应性比追求短期的性能优化更重要

核心原则一:围绕 KV 缓存进行设计

如果要选择一个最重要的指标,作者认为是 KV 缓存命中率(KV-cache Hit Rate)。这个指标直接影响两个生产环境中最关键的因素:延迟和成本。

AI Agent 的工作机制

要理解为什么 KV 缓存如此重要,我们需要先了解 AI Agent 的典型工作流程:

flowchart TD
    A["用户输入"] --> B["Agent 接收任务"]
    B --> C["根据上下文选择动作"]
    C --> D["在环境中执行动作"]
    D --> E["获得观察结果"]
    E --> F["更新上下文"]
    F --> G{"任务完成?"}
    G -->|否| C
    G -->|是| H["返回结果"]

在这个循环中,每一步都涉及:

  1. 输入上下文:包含任务描述、历史动作、观察结果等
  2. 模型推理:基于上下文选择下一个动作
  3. 上下文更新:将新的动作和观察追加到上下文中

这导致了一个重要特征:随着任务的推进,输入上下文不断增长,而输出(通常是结构化的函数调用)保持相对简短

在 Manus 的实际数据中,平均输入与输出的 token 比例约为 100:1。这意味着相比于聊天机器人,Agent 系统的预填充(Prefill)和解码(Decode)比例高度倾斜。

KV 缓存的成本影响

KV 缓存机制允许具有相同前缀的上下文重用之前的计算结果。这带来的成本差异是巨大的。以 Claude Sonnet 为例:

  • 缓存的输入 token:0.30 美元/百万 token
  • 未缓存的输入 token:3.00 美元/百万 token

这是 10 倍的成本差异!而且缓存还能显著减少首个 token 的生成时间(TTFT, Time To First Token),改善用户体验。

提高缓存命中率的实践

作者总结了三个关键实践来提高 KV 缓存命中率:

1. 保持提示前缀稳定

由于 LLM 的自回归特性,即使单个 token 的差异也会使该 token 之后的所有缓存失效。一个常见的反模式是:

# ❌ 错误做法:在系统提示开头包含时间戳
system_prompt = f"""
当前时间:{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
你是一个智能助手...
"""

这样做每秒都会产生不同的系统提示,完全破坏了缓存效果。更好的做法是:

# ✅ 正确做法:将时间信息放在后面或作为单独的消息
system_prompt = """
你是一个智能助手...

参考信息:
当前时间:{current_time}
"""

这里有个巧妙的设计思想:将变化的信息放在上下文的末尾,保持前缀的稳定性。这样至少系统提示的大部分内容可以被缓存。

2. 使上下文只追加(Append-Only)

避免修改之前的操作或观察结果。这要求:

  • 不要回溯修改历史记录:即使发现了错误,也应该通过新的观察来纠正
  • 确保序列化的确定性:很多编程语言在序列化 JSON 对象时不保证键顺序的稳定性

这是一个容易被忽视的细节。在 Python 中:

import json

# ❌ 可能导致缓存失效
data = {"action": "search", "params": {...}}
json_str = json.dumps(data)  # 键顺序可能不稳定

# ✅ 确保稳定的序列化
json_str = json.dumps(data, sort_keys=True)

虽然这看起来是个小细节,但在生产环境中,这种不确定性会悄无声息地降低缓存命中率,增加成本。

3. 延迟填充变化的信息

对于必须包含的变化信息(如时间戳),应该尽可能延迟填充,让更多的前缀保持稳定。作者甚至提到了一个有趣的观点:

"我曾经想象,如果未来的模型支持可变 slot(就像模板中的占位符),能够在保持缓存的情况下动态填充这些 slot,那将是一个巨大的优化。"

这个想法本质上是希望模型推理系统能够支持"部分缓存"——即使上下文中某些位置的内容发生变化,只要结构保持不变,就能重用大部分计算。

工程启示

从 KV 缓存的设计中,我们可以得到几个重要的工程启示:

成本意识应该贯穿设计:在设计 Agent 系统时,不能只考虑功能实现,还要时刻关注成本结构。一个看似无关紧要的设计选择(比如时间戳的位置)可能导致 10 倍的成本差异。

性能优化要从架构层面考虑:单纯的代码优化往往效果有限,真正的性能提升来自于对底层机制(如 KV 缓存)的深刻理解,并在架构设计中利用这些机制。

稳定性比灵活性更重要:在某些场景下,限制系统的灵活性(如强制使用 Append-Only 的上下文)反而能带来更好的性能和更低的成本。

监控关键指标:建议在生产环境中监控 KV 缓存命中率,将其作为核心指标之一。如果发现命中率下降,要立即排查是否有代码变更破坏了上下文的稳定性。

核心原则二:外部记忆系统的设计

随着 Agent 执行复杂任务,上下文会快速增长。这带来两个问题:

  1. 上下文窗口限制:即使是 128K 的上下文窗口,也可能不够用
  2. 性能衰减:研究表明,在极长上下文中,模型的检索准确率会下降("迷失在中间"问题)

文件系统作为外部记忆

Manus 采用的解决方案是:使用文件系统作为外部记忆(External Memory)

这是一个非常聪明的设计。在 Manus 的沙盒环境中,Agent 可以像人类开发者一样:

  • 写入文件:将长期信息(如任务描述、中间结果、代码片段)保存到文件中
  • 读取文件:需要时再加载相关信息
  • 组织信息:通过目录结构和文件命名来组织记忆
flowchart LR
    A["Agent 核心上下文"] --> B{"信息类型判断"}
    B -->|短期工作记忆| C["保持在上下文中"]
    B -->|长期记忆| D["写入文件系统"]
    D --> E["任务描述<br>task.md"]
    D --> F["代码片段<br>code.py"]
    D --> G["中间结果<br>results.json"]
    H["需要时读取"] --> D
    H --> A

外部记忆的优势

无限扩展:不受上下文窗口限制,理论上可以存储无限量的信息。

结构化组织:文件系统天然支持层级结构,Agent 可以通过目录和文件名来组织和检索信息。

持久化存储:即使 Agent 会话结束,信息仍然保存,可以跨会话使用。

成本优化:不需要将所有历史信息都保持在昂贵的上下文窗口中。

与人类记忆的类比

作者提到,这种设计类似于人类的工作方式:我们不会把所有信息都记在脑子里,而是会写笔记、创建文档、组织文件夹。当需要时,我们会查阅这些外部记忆。

这个类比揭示了一个深刻的洞察:好的 Agent 设计不应该试图让模型记住所有东西,而应该教会它如何有效地使用外部工具来扩展能力。这与人类智能的本质更接近——我们的智能不仅来自大脑的计算能力,更来自于善用外部工具(文字、书籍、计算机)来增强和扩展认知能力。

与 RAG 的区别

你可能会想:这不就是 RAG(Retrieval-Augmented Generation)吗?

实际上有重要区别:

主动性:在 RAG 中,检索通常是被动的,由系统根据查询自动触发。而在 Manus 中,Agent 主动决定何时读写文件,具有更强的控制能力。

结构性:RAG 通常基于语义相似度检索,而文件系统提供了更强的结构化组织能力。Agent 可以通过文件路径和命名来建立逻辑关系。

可观测性:文件系统的读写操作是显式的,更容易调试和理解 Agent 的行为。

对未来模型架构的启示

作者提到了一个有趣的思考:这种设计对状态空间模型(State Space Model, SSM)有什么启示?

SSM(如 Mamba)相比 Transformer 具有更高的推理效率,但缺乏完整的注意力机制,在处理长距离依赖时表现较弱。然而,如果 SSM 能够掌握基于文件的记忆管理——将长期状态外部化而不是保存在上下文中——那么它们的速度和效率优势可能会开启一类新型 Agent。

这个观点非常前瞻:未来的 Agent 可能不需要超长的上下文窗口,而是需要更好的外部记忆管理能力。这或许才是神经图灵机(Neural Turing Machine)真正的继任者。

工程实践建议

基于外部记忆系统的设计,我们可以得出以下实践建议:

设计清晰的文件组织规范:为 Agent 定义标准的目录结构和文件命名规则,就像为开发团队定义代码规范一样。例如:

/workspace
  /tasks          # 任务描述和计划
  /code           # 生成的代码
  /results        # 中间结果和输出
  /logs           # 执行日志
  /notes          # Agent 的工作笔记

提供文件操作工具:确保 Agent 有足够的文件操作能力,包括:

  • 创建、读取、更新、删除文件
  • 列出目录内容
  • 搜索文件内容(grep、find 等)
  • 移动和重命名文件

教会 Agent 何时使用外部记忆:在系统提示中明确指导 Agent 哪些信息应该外部化。例如:

  • 超过 1000 token 的内容应该写入文件
  • 需要长期保存的信息使用文件存储
  • 频繁引用的信息可以缓存在文件中

监控文件系统使用情况:跟踪 Agent 的文件操作模式,识别异常行为(如频繁读写同一文件、创建大量临时文件等)。

核心原则三:通过复述操控注意力

这是 Manus 的一个巧妙设计。如果你使用过 Manus,可能注意到一个有趣的现象:在处理复杂任务时,它会创建一个 todo.md 文件,并在任务进行过程中不断更新它,勾选已完成的项目。

为什么需要注意力操控

在 Manus 的实际使用中,一个典型任务平均需要约 50 次工具调用。这是一个很长的循环,Agent 很容易:

  • 偏离主题:在执行子任务时忘记了主要目标
  • 丢失目标:在长上下文中"迷失在中间"
  • 目标不一致:不同步骤之间的行为缺乏连贯性

待办事项列表的作用

通过不断重写待办事项列表,Manus 实现了一个简单但有效的机制:将全局计划复述到上下文的末尾

flowchart TD
    A["接收任务"] --> B["创建 todo.md"]
    B --> C["执行当前子任务"]
    C --> D["更新 todo.md"]
    D --> E{"所有任务完成?"}
    E -->|否| C
    E -->|是| F["完成"]
    
    style D fill:#e1f5ff

这个设计的巧妙之处在于:

利用位置偏差:研究表明,Transformer 模型对上下文末尾的信息更敏感。通过将目标放在末尾,可以提高模型对目标的关注度。

自然语言引导:不需要修改模型架构,完全通过自然语言来引导注意力。

可视化进度:待办事项列表不仅帮助 Agent 保持方向,也让用户清楚地看到任务进展。

实际效果示例

假设用户要求:"帮我分析这个项目的代码质量,生成报告"。Manus 可能会创建:

# 任务:代码质量分析

## 待办事项
- [x] 扫描项目结构
- [x] 分析 Python 代码风格
- [ ] 检查单元测试覆盖率
- [ ] 分析代码复杂度
- [ ] 检查安全问题
- [ ] 生成分析报告

在执行每个子任务后,Agent 会更新这个文件,勾选完成的项目。这样,即使上下文中包含了大量的代码片段和分析结果,Agent 仍然能清楚地知道当前处于哪个阶段,下一步应该做什么。

与思维链的联系

这个设计与思维链(Chain-of-Thought, CoT)提示有相似之处,但更进一步:

  • CoT:引导模型逐步推理,将推理过程显式化
  • Manus 的待办列表:不仅显式化推理过程,还通过不断复述来强化目标

其他应用场景

这个原则可以推广到其他场景:

代码生成任务:在生成大型代码库时,维护一个 implementation_plan.md,列出需要实现的模块和函数。

数据分析任务:创建 analysis_checklist.md,列出需要回答的问题和需要生成的图表。

调试任务:维护 debug_notes.md,记录已尝试的方法和待验证的假设。

工程启示

显式化目标管理:不要假设模型会自动记住所有目标,而要通过显式的机制来维护和强化目标。

利用位置偏差:将最重要的信息放在上下文的开头和末尾,这是 Transformer 注意力最集中的地方。

自我提醒机制:让 Agent 定期回顾和更新自己的目标和计划,而不是一次性接收任务后就埋头执行。

结构化思考:鼓励 Agent 将复杂任务分解为清晰的步骤,并通过外部化(如待办列表)来管理这些步骤。

核心原则四:保留错误的内容

这是一个反直觉但非常重要的原则:当 Agent 犯错时,不要清理错误痕迹,而要将错误保留在上下文中

常见的错误处理反模式

在很多 Agent 系统中,常见的做法是:

# ❌ 反模式:隐藏错误
try:
    result = agent.execute_action(action)
except Exception as e:
    # 重试,不记录错误
    result = agent.execute_action(action)

这种做法的问题是:擦除失败会移除证据,没有证据,模型就无法适应

为什么要保留错误

当模型看到一个失败的动作——以及由此产生的观察结果或堆栈跟踪——它会隐式地更新其内部信念。这会改变其先验(Prior),降低重复相同错误的可能性。

这本质上是一种上下文内学习(In-Context Learning):模型通过观察失败案例来学习什么不应该做。

实际案例

假设 Agent 尝试读取一个不存在的文件:

Action: read_file("/path/to/config.json")
Observation: Error - File not found: /path/to/config.json

如果保留这个错误信息,在后续步骤中,Agent 更可能:

  1. 先检查文件是否存在
  2. 尝试搜索文件的实际位置
  3. 或者询问用户文件路径

如果隐藏了这个错误,Agent 可能会重复尝试读取同一个不存在的文件。

错误恢复作为代理行为的指标

作者提出了一个有趣的观点:错误恢复能力是真正代理行为的最明显指标之一

这是因为:

现实环境充满不确定性:文件可能不存在、API 可能返回错误、网络可能超时。真正的 Agent 必须能够应对这些情况。

恢复能力体现智能:从错误中学习和恢复,比一次性执行成功更能体现智能水平。

实用性至关重要:在生产环境中,用户更关心 Agent 能否最终完成任务,而不是每一步都完美执行。

学术界的忽视

作者批评道:"在大多数学术工作和公共基准测试中,错误恢复仍然代表性不足,它们通常关注理想条件下的任务成功。"

这是一个重要的观察。现有的 Agent 基准测试(如 WebShop、ALFWorld)通常只测试在理想条件下的任务完成率,而忽略了:

  • 面对错误的恢复能力
  • 处理模糊或不完整信息的能力
  • 在部分失败后调整策略的能力

工程实践建议

详细记录错误信息:不仅要记录错误发生了,还要记录:

  • 完整的堆栈跟踪
  • 导致错误的输入参数
  • 环境状态(如文件系统状态)
# ✅ 好的做法:详细记录错误
try:
    result = execute_action(action)
    observation = {"status": "success", "result": result}
except Exception as e:
    observation = {
        "status": "error",
        "error_type": type(e).__name__,
        "error_message": str(e),
        "traceback": traceback.format_exc(),
        "attempted_action": action
    }

限制重试次数:避免无限循环,设置合理的重试上限。

max_retries = 3
for attempt in range(max_retries):
    try:
        result = execute_action(action)
        break
    except Exception as e:
        if attempt == max_retries - 1:
            # 记录最终失败
            context.append_observation(f"Failed after {max_retries} attempts: {e}")
        else:
            # 记录重试
            context.append_observation(f"Attempt {attempt + 1} failed: {e}, retrying...")

设计错误恢复提示:在系统提示中明确告诉 Agent 如何处理错误。

当你遇到错误时:
1. 仔细阅读错误消息,理解失败原因
2. 不要重复相同的操作,尝试不同的方法
3. 如果是文件不存在,先搜索或创建文件
4. 如果是权限问题,考虑使用其他方式
5. 如果多次失败,向用户寻求帮助

构建错误恢复测试集:创建专门的测试场景来评估 Agent 的错误恢复能力。

test_cases = [
    {"scenario": "file_not_found", "expected_recovery": "search_or_create_file"},
    {"scenario": "api_timeout", "expected_recovery": "retry_with_backoff"},
    {"scenario": "invalid_input", "expected_recovery": "validate_and_correct_input"},
]

与强化学习的联系

这个原则与强化学习中的探索-利用(Exploration-Exploitation)权衡有相似之处。保留错误信息,本质上是让 Agent 从负面奖励中学习,避免重复低回报的行为。

不过,这里的学习是在单次会话的上下文中进行的,而不是跨会话的参数更新。这是上下文学习的独特优势:无需重新训练,Agent 就能在当前任务中快速适应

核心原则五:不要被少样本示例所困

少样本提示(Few-Shot Prompting)是提高 LLM 输出的常用技术。但在 Agent 系统中,它可能会以微妙的方式适得其反。

少样本提示的陷阱

语言模型是优秀的模仿者。如果你的上下文充满了类似的过去行动-观察对,模型将倾向于遵循该模式,即使这不再是最优的

实际案例

作者提到了一个具体例子:当使用 Manus 帮助审查 20 份简历时,Agent 通常会陷入一种节奏——仅仅因为这是它在上下文中看到的,就重复类似的行动。

flowchart TD
    A["审查简历 1"] --> B["提取教育背景、工作经验"]
    B --> C["审查简历 2"]
    C --> D["提取教育背景、工作经验"]
    D --> E["审查简历 3"]
    E --> F["继续重复相同模式..."]
    
    style F fill:#ffcccc
    
    G["可能错过的"] --> H["特殊技能"]
    G --> I["项目经验"]
    G --> J["推荐信"]

这导致:

过度泛化:将第一份简历的分析模式应用到所有简历,忽略了每份简历的独特之处。

偏离目标:可能忽略了用户真正关心的评估维度。

产生幻觉:为了保持模式一致性,可能捏造相似的分析结果。

解决方法:引入多样性

Manus 的解决方案是:在行动和观察中引入少量的结构化变化

这包括:

不同的序列化模板:不要总是用相同的 JSON 结构,可以变换键的顺序或使用不同的字段名。

# 变化 1
{"action": "analyze", "target": "resume_1.pdf"}

# 变化 2
{"target": "resume_2.pdf", "action": "analyze"}

# 变化 3
{"operation": "analyze", "file": "resume_3.pdf"}

替代性措辞:使用不同的描述方式来表达相似的操作。

# 变化 1
"Read the file and extract key information"

# 变化 2
"Parse the document to identify important details"

# 变化 3
"Analyze the content and summarize main points"

顺序或格式上的微小噪音:在保持语义不变的情况下,引入一些随机性。

受控的随机性

这里的关键词是"受控"(Controlled)。不是完全随机地改变输出,而是:

  1. 保持语义一致性:变化不应该改变实际含义
  2. 保持结构合理性:不是胡乱改变,而是在合理范围内变化
  3. 打破模式识别:足够的变化来防止过度模式匹配

与提示工程的关系

传统的提示工程建议使用少样本示例来提高输出质量。但这个原则提醒我们:在 Agent 的长期交互中,少样本示例可能成为枷锁而非助力

这不是说少样本提示不好,而是要认识到它的局限性:

适用场景:单次查询、输出格式固定、任务类型单一。

不适用场景:长期交互、重复性任务、需要创造性变化。

工程实践建议

动态调整示例:不要在系统提示中放置固定的少样本示例,而是根据当前任务动态选择相关示例。

def get_relevant_examples(task_type, history):
    # 从历史中选择多样化的示例
    examples = example_bank.get(task_type)
    # 避免选择与最近历史太相似的示例
    diverse_examples = filter_dissimilar(examples, history[-5:])
    return diverse_examples[:3]

监控模式重复:检测 Agent 是否陷入重复模式。

def detect_pattern_loop(history, window=5):
    """检测最近的动作是否高度重复"""
    recent_actions = [h["action"] for h in history[-window:]]
    unique_ratio = len(set(recent_actions)) / len(recent_actions)
    return unique_ratio < 0.5  # 如果唯一性低于50%,可能陷入循环

主动打破模式:当检测到重复模式时,主动引入变化。

if detect_pattern_loop(history):
    # 在系统提示中添加提醒
    context.append_system_message(
        "注意:你最近的几个操作很相似。"
        "请考虑是否需要尝试不同的方法或视角。"
    )

多样化训练数据(如果进行微调):确保训练数据包含多样化的行动序列,避免单一模式。

与人类行为的对比

这个原则反映了一个有趣的现象:人类在处理重复性任务时,也容易陷入"自动驾驶"模式,机械地重复相同的步骤,而忽略了具体情境的差异。

好的专业人士会有意识地避免这种陷阱,保持对每个案例的独特性的敏感。同样,好的 Agent 系统也应该设计机制来防止过度模式匹配。

综合工程启示与实践建议

现在,让我们将这五个核心原则整合起来,看看如何在实际项目中应用。

设计一个上下文管理框架

基于 Manus 的经验,一个良好的上下文管理框架应该包括:

class ContextManager:
    def __init__(self):
        # 稳定的系统提示前缀(优化 KV 缓存)
        self.system_prefix = self._load_stable_prompt()
        
        # 外部记忆(文件系统)
        self.memory = FileSystemMemory()
        
        # 目标管理(待办列表)
        self.goals = GoalTracker()
        
        # 历史记录(包含错误)
        self.history = []
        
        # 多样性控制
        self.diversity_manager = DiversityManager()
    
    def add_observation(self, action, result, error=None):
        """添加观察结果,包括错误"""
        observation = {
            "action": action,
            "result": result,
            "error": error,  # 保留错误信息
            "timestamp": time.time()
        }
        self.history.append(observation)
        
        # 检查是否需要外部化长期记忆
        if self._should_externalize(observation):
            self.memory.save(observation)
            # 在上下文中只保留引用
            self.history[-1] = {"ref": "memory://observation_xxx"}
    
    def update_goals(self, completed_goal):
        """更新目标,并复述到上下文末尾"""
        self.goals.mark_completed(completed_goal)
        # 将更新后的目标列表追加到上下文
        return self.goals.to_markdown()
    
    def get_context(self):
        """获取当前上下文"""
        context = []
        
        # 1. 稳定的系统前缀(KV 缓存友好)
        context.append(self.system_prefix)
        
        # 2. 当前目标(注意力操控)
        context.append(self.goals.to_markdown())
        
        # 3. 相关的历史记录
        context.extend(self._get_relevant_history())
        
        # 4. 变化的信息放在最后(延迟填充)
        context.append(self._get_dynamic_info())
        
        return context
    
    def _should_externalize(self, observation):
        """判断是否应该将信息外部化"""
        # 超过 1000 token 的内容
        if len(str(observation)) > 4000:
            return True
        # 不常访问的历史记录
        if self._is_old(observation):
            return True
        return False
    
    def format_action(self, action):
        """引入多样性的格式化"""
        return self.diversity_manager.format(action)

监控关键指标

建立一个监控系统来跟踪上下文工程的效果:

class ContextMetrics:
    def __init__(self):
        self.metrics = {
            "kv_cache_hit_rate": [],
            "context_length": [],
            "external_memory_usage": [],
            "error_recovery_rate": [],
            "pattern_diversity": []
        }
    
    def log_kv_cache_hit(self, hit):
        """记录 KV 缓存命中"""
        self.metrics["kv_cache_hit_rate"].append(1 if hit else 0)
    
    def log_context_length(self, length):
        """记录上下文长度"""
        self.metrics["context_length"].append(length)
    
    def log_error_recovery(self, recovered):
        """记录错误恢复情况"""
        self.metrics["error_recovery_rate"].append(1 if recovered else 0)
    
    def get_report(self):
        """生成监控报告"""
        return {
            "avg_kv_hit_rate": np.mean(self.metrics["kv_cache_hit_rate"]),
            "avg_context_length": np.mean(self.metrics["context_length"]),
            "error_recovery_rate": np.mean(self.metrics["error_recovery_rate"]),
            "context_stability": self._calculate_stability()
        }

系统提示的最佳实践

基于这些原则,系统提示应该这样设计:

# 系统提示(稳定部分)

你是一个智能代理,能够通过工具调用来完成复杂任务。

## 核心能力
- 文件操作:读写文件来管理长期记忆
- 代码执行:在沙盒环境中运行代码
- 网络访问:查询外部信息

## 工作原则

### 记忆管理
- 将长期信息(>1000 token)写入文件
- 使用清晰的文件名和目录结构
- 需要时读取文件内容

### 任务规划
- 将复杂任务分解为步骤
- 创建 todo.md 跟踪进度
- 完成每步后更新待办列表

### 错误处理
- 仔细阅读错误消息
- 不要重复失败的操作
- 尝试不同的方法
- 如果多次失败,寻求帮助

### 执行策略
- 保持灵活性,避免陷入重复模式
- 根据具体情况调整方法
- 关注任务目标,而非执行过程

---

# 当前任务(动态部分)

[在这里插入具体任务描述和动态信息]

当前时间:{current_time}
工作目录:{working_directory}

测试和评估

构建一个全面的测试框架来评估 Agent 的性能:

class AgentEvaluator:
    def __init__(self):
        self.test_scenarios = self._load_scenarios()
    
    def evaluate(self, agent):
        results = {
            "success_rate": [],
            "error_recovery": [],
            "context_efficiency": [],
            "pattern_diversity": []
        }
        
        for scenario in self.test_scenarios:
            # 标准成功案例
            result = self._test_standard(agent, scenario)
            results["success_rate"].append(result)
            
            # 错误恢复案例
            error_result = self._test_error_recovery(agent, scenario)
            results["error_recovery"].append(error_result)
            
            # 上下文效率
            context_metrics = self._test_context_efficiency(agent, scenario)
            results["context_efficiency"].append(context_metrics)
            
            # 模式多样性
            diversity = self._test_pattern_diversity(agent, scenario)
            results["pattern_diversity"].append(diversity)
        
        return self._generate_report(results)
    
    def _test_error_recovery(self, agent, scenario):
        """测试错误恢复能力"""
        # 注入错误
        scenario_with_error = self._inject_error(scenario)
        
        # 观察 Agent 是否能恢复
        result = agent.execute(scenario_with_error)
        
        return {
            "recovered": result.success,
            "steps_to_recover": result.step_count,
            "recovery_strategy": result.strategy
        }

成本优化策略

基于 KV 缓存和外部记忆的原则,实施成本优化:

class CostOptimizer:
    def __init__(self):
        self.cache_stats = {}
        self.cost_per_token = {
            "uncached_input": 3.0 / 1_000_000,
            "cached_input": 0.3 / 1_000_000,
            "output": 15.0 / 1_000_000
        }
    
    def estimate_cost(self, context, expected_output_length):
        """估算当前调用的成本"""
        cached_tokens = self._count_cached_tokens(context)
        uncached_tokens = len(context) - cached_tokens
        
        input_cost = (
            cached_tokens * self.cost_per_token["cached_input"] +
            uncached_tokens * self.cost_per_token["uncached_input"]
        )
        output_cost = expected_output_length * self.cost_per_token["output"]
        
        return input_cost + output_cost
    
    def optimize_context(self, context):
        """优化上下文以降低成本"""
        # 1. 将不常用的信息外部化
        context = self._externalize_cold_data(context)
        
        # 2. 确保前缀稳定性
        context = self._stabilize_prefix(context)
        
        # 3. 压缩重复信息
        context = self._compress_duplicates(context)
        
        return context
    
    def analyze_cache_effectiveness(self):
        """分析缓存效果"""
        total_calls = len(self.cache_stats)
        cache_hits = sum(1 for s in self.cache_stats.values() if s["hit"])
        hit_rate = cache_hits / total_calls if total_calls > 0 else 0
        
        savings = sum(
            s["tokens_cached"] * (
                self.cost_per_token["uncached_input"] - 
                self.cost_per_token["cached_input"]
            )
            for s in self.cache_stats.values()
        )
        
        return {
            "hit_rate": hit_rate,
            "total_savings": savings,
            "average_cached_tokens": np.mean([
                s["tokens_cached"] for s in self.cache_stats.values()
            ])
        }

与其他 Agent 框架的对比

让我们将 Manus 的上下文工程方法与其他流行的 Agent 框架进行对比:

LangChain/LangGraph

相似之处

  • 都支持工具调用和链式执行
  • 都提供记忆管理机制

差异

  • LangChain 更关注模块化和可组合性,而 Manus 更关注上下文优化
  • LangChain 的记忆通常基于向量数据库,而 Manus 使用文件系统
  • Manus 更强调 KV 缓存优化和成本控制

AutoGPT/AgentGPT

相似之处

  • 都是自主的任务执行系统
  • 都支持长期任务和多步骤推理

差异

  • AutoGPT 更强调自主性和探索,而 Manus 更强调可控性和效率
  • Manus 的外部记忆设计更结构化
  • Manus 明确地将错误保留在上下文中,而 AutoGPT 可能会隐藏一些错误

ReAct

相似之处

  • 都采用"推理-行动-观察"的循环
  • 都强调将推理过程外显化

差异

  • ReAct 是一个提示方法,而 Manus 是一个完整的系统
  • Manus 增加了外部记忆和目标管理等额外机制
  • Manus 更关注生产环境的实际问题(成本、延迟)

对比总结表

特性ManusLangChainAutoGPTReAct
KV 缓存优化⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐
外部记忆文件系统向量数据库文件+向量不支持
错误处理保留错误部分保留自动重试依赖提示
成本意识⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐N/A
生产就绪⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐
模式多样性主动引入依赖模型依赖模型依赖提示

未来展望与开放问题

基于 Manus 的经验,我们可以思考 AI Agent 领域的一些未来方向:

1. 上下文压缩技术

随着任务复杂度增加,如何更高效地压缩和管理上下文?可能的方向:

层级摘要:对历史记录进行多层级的摘要,类似于文件系统的层级结构。

选择性遗忘:学习哪些信息可以安全遗忘,哪些必须保留。

上下文蒸馏:将长上下文蒸馏为更紧凑的表示,同时保留关键信息。

2. 更智能的外部记忆

文件系统是一个好的开始,但还有改进空间:

自动索引:Agent 自动为存储的信息创建索引,加速检索。

关联网络:构建信息之间的关联网络,支持更复杂的推理。

版本控制:像 Git 一样管理信息的版本,支持回溯和分支。

3. 动态上下文优化

根据任务特点和模型能力动态调整上下文策略:

自适应压缩:根据当前上下文长度和重要性动态调整压缩率。

智能缓存预测:预测哪些部分的上下文最可能被重用,优先优化这些部分。

任务感知的上下文构建:不同类型的任务使用不同的上下文构建策略。

4. 跨会话的学习

当前的上下文学习是会话级别的,如何实现跨会话的持续学习?

个性化记忆:为每个用户维护长期的个性化记忆。

知识积累:从多次会话中积累可复用的知识和模式。

元学习:学习如何更好地学习——优化上下文管理策略本身。

5. 多模态上下文

扩展到视觉、音频等多模态信息:

多模态记忆:如何有效存储和检索多模态信息?

跨模态引用:在文本上下文中引用视觉或音频信息。

模态特定的优化:不同模态可能需要不同的上下文管理策略。

6. 开放的研究问题

如何量化上下文质量? 我们需要更好的指标来评估上下文的质量和效率,而不仅仅是任务成功率。

最优的外部记忆架构是什么? 文件系统、向量数据库、图数据库、关系数据库,哪种更适合 Agent 的外部记忆?

如何自动学习上下文管理策略? 能否通过强化学习或其他方法,让 Agent 自动学习最优的上下文管理策略?

上下文工程的理论基础是什么? 我们需要更深入的理论研究,理解为什么某些上下文设计比其他更有效。

实践中的注意事项

基于 Manus 的经验,在实际应用上下文工程时需要注意:

不要过度优化

平衡性能和复杂度:不是所有的优化都值得实施。有时候简单的方案已经足够好。

关注核心瓶颈:先优化最重要的 20%,通常能带来 80% 的收益。

避免过早优化:在明确问题之前,不要盲目引入复杂的优化机制。

持续监控和迭代

建立监控体系:实时跟踪关键指标(KV 缓存命中率、上下文长度、成本等)。

A/B 测试:对于重要的改变,通过 A/B 测试来验证效果。

用户反馈:关注真实用户的反馈,有时候技术指标的改进不一定带来用户体验的提升。

适配不同的模型

模型特性差异:不同模型对上下文的处理能力不同,需要针对性优化。

成本结构差异:不同模型的定价策略不同,某些优化在一个模型上有效,在另一个模型上可能没有意义。

能力边界:了解模型的能力边界,不要期望上下文工程能解决所有问题。

文档和知识传承

记录设计决策:清楚地记录为什么这样设计,而不仅仅是如何实现。

案例库:积累典型的成功和失败案例,帮助团队学习。

最佳实践指南:将经验总结为可操作的指南,降低新成员的学习曲线。

个人思考与总结

这篇文章给我最大的启发是:上下文工程不仅是技术问题,更是系统设计问题

在传统的机器学习范式中,我们习惯于通过训练数据和模型架构来解决问题。但在大模型时代,提示工程和上下文工程变得同样重要,甚至更重要。这代表了一种新的工程范式:不是改变模型,而是改变模型看到的世界

Manus 的经验告诉我们,构建生产级 Agent 系统需要在多个维度上进行权衡:

性能 vs 成本:KV 缓存优化可以同时改善两者,这是罕见的双赢。

灵活性 vs 稳定性:Append-Only 的上下文牺牲了一些灵活性,但换来了更好的缓存性能。

自动化 vs 可控性:完全的自主性很诱人,但在生产环境中,可控性和可预测性往往更重要。

短期效率 vs 长期适应性:选择上下文工程而非模型训练,是在短期效率和长期适应性之间的明智权衡。

更深层次的,这篇文章让我思考:什么是真正的智能?

人类的智能不仅来自大脑的计算能力,更来自于:

  • 善用外部工具(笔记、书籍、计算机)
  • 从错误中学习
  • 灵活调整策略而不陷入固定模式
  • 通过自我提醒保持目标导向

Manus 的设计哲学正是模仿了人类智能的这些特点。这让我相信:好的 AI Agent 不应该是一个超级大脑,而应该是一个善于利用工具和环境的智能系统

从工程实践角度,我认为上下文工程的核心在于:

显式优于隐式:将推理过程、目标管理、错误处理都显式化,而不是依赖模型的隐式能力。

结构优于自由:通过结构化的设计(如文件系统、待办列表)来引导行为,比完全自由探索更可控。

适应优于完美:能够从错误中恢复、能够打破重复模式,比一次性完美执行更有价值。

效率优于能力:在模型能力已经足够的前提下,工程优化的重点应该转向效率和成本。

最后,我想说:Manus 团队的"随机梯度下降"过程——四次重构、无数次试错——恰恰展示了工程实践的真实面貌。没有一开始就完美的设计,只有通过不断迭代而逐渐清晰的认知。

这篇文章的价值不仅在于分享了具体的技术方案,更在于展示了一种工程思维方式:在快速变化的技术领域,保持灵活性、持续迭代、关注实际问题,比追求理论上的完美更重要

参考资源

原文地址

相关技术

  • KV 缓存机制原理
  • 上下文学习(In-Context Learning)
  • 少样本提示(Few-Shot Prompting)
  • ReAct 提示方法
  • 状态空间模型(State Space Models, SSM)

相关框架

推荐阅读

  • "Language Models are Few-Shot Learners" (GPT-3 论文)
  • "ReAct: Synergizing Reasoning and Acting in Language Models"
  • "Lost in the Middle: How Language Models Use Long Contexts"
  • "Efficient Streaming Language Models with Attention Sinks"

本文基于 Manus AI 团队的技术分享,结合个人理解和工程经验撰写。上下文工程是一个快速发展的领域,本文的观点和建议会随着技术进步而演进。

0
博主关闭了所有页面的评论