论文地址
原文链接: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)才能迁移到新任务。这个过程通常需要:
- 数周的训练时间:即使是相对较小的模型
- 缓慢的反馈循环:难以快速迭代和验证想法
- 高昂的试错成本:每次调整都需要重新训练
更致命的是,在产品市场匹配(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["返回结果"]
在这个循环中,每一步都涉及:
- 输入上下文:包含任务描述、历史动作、观察结果等
- 模型推理:基于上下文选择下一个动作
- 上下文更新:将新的动作和观察追加到上下文中
这导致了一个重要特征:随着任务的推进,输入上下文不断增长,而输出(通常是结构化的函数调用)保持相对简短。
在 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 执行复杂任务,上下文会快速增长。这带来两个问题:
- 上下文窗口限制:即使是 128K 的上下文窗口,也可能不够用
- 性能衰减:研究表明,在极长上下文中,模型的检索准确率会下降("迷失在中间"问题)
文件系统作为外部记忆
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 更可能:
- 先检查文件是否存在
- 尝试搜索文件的实际位置
- 或者询问用户文件路径
如果隐藏了这个错误,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)。不是完全随机地改变输出,而是:
- 保持语义一致性:变化不应该改变实际含义
- 保持结构合理性:不是胡乱改变,而是在合理范围内变化
- 打破模式识别:足够的变化来防止过度模式匹配
与提示工程的关系
传统的提示工程建议使用少样本示例来提高输出质量。但这个原则提醒我们:在 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 更关注生产环境的实际问题(成本、延迟)
对比总结表
| 特性 | Manus | LangChain | AutoGPT | ReAct |
|---|---|---|---|---|
| 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)
相关框架:
- Manus AI: https://manus.im
- LangChain: https://langchain.com
- AutoGPT: https://github.com/Significant-Gravitas/AutoGPT
- LangGraph: https://langchain-ai.github.io/langgraph/
推荐阅读:
- "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 团队的技术分享,结合个人理解和工程经验撰写。上下文工程是一个快速发展的领域,本文的观点和建议会随着技术进步而演进。