我们该如何设计AI Agents
AI Agents 无疑是今年科技圈最火爆的话题之一,在研究了几个月AI Agents之后,我尝试归纳下我对AI Agents的理解以及我们应该如何设计AI Agents。
本篇文章总计两万余字,系统讨论了我们该如何设计AI Agents,阅读预计需要45分钟。
前言
AI Agents 无疑是今年科技圈最火爆的话题之一,在研究了几个月AI Agents之后,我尝试归纳下我对AI Agents的理解以及我们应该如何设计AI Agents。
当我们在研究一些优秀AI Agents时,比如Claude Code、Manus,我们发现我们不仅仅应当把它视为一个AI Agent,而应当把它看作一个系统,这个系统是我们在实现以模型为核心代表的通用人工智能(AGI)之前会长期存在的一个需求、场景,或者说是技术概念,所以我们的设计视角可以从如何设计AI Agent向如何设计“AI System” 转变,而这个转变将会要求我们在设计AI Agent的时候要求其模块化、结构化和确定性。
所以,我们可以从这个方向归纳下什么是AI Agents,AI Agents是我们抵达通用人工智能(AGI)之前,为驾驭大模型强大而不可靠的智能,所必须构建的结构化、确定性的工程系统。
全文目录如下:
从深度理解上下文工程开始
提示工程VS上下文工程
我们为什么需要上下文工程?
什么是RAG?
上下文工程中会遇到的问题
LangChain团队的标准化建议AI Agent的核心架构范式
维度一:认知架构
维度二:系统拓扑
Single-Agent还是Multi-Agent一个健壮的AI Agent所应该具备的
一、外部化的确定性状态
二、受锚定的行动循环
三、分层的认知治理
四、显式的协作协议
从深度理解上下文工程开始
提示工程VS上下文工程
提示工程 (Prompt Engineering)
提示工程 (Prompt Engineering) 是一门为实现单次、特定目标而精心设计与AI对话指令的艺术。 伴随着ChatGPT3.5的问世,这一概念迅速进入公众视野并广为人知。它的核心聚焦于即时性、对话式的交互,其目标是通过反复调整和迭代提示词(Prompt),在单次请求中引导模型产出最满意的结果。尽管听起来像是基础操作,但它在构建复杂的AI Agents中依然扮演着不可或缺的角色,尤其体现在系统提示词 (System Prompt) 的设定和核心规则 (Rules) 的定义上,它们共同构成了Agent行为的基石。
上下文工程 (Context Engineering)
Context Engineering在Karpathy的推广下,被越来越人熟知。如果说提示工程是战术层面的“对话艺术”,那么Context Engineering 则是为应对更复杂挑战而自然演进出的系统级学科。
要理解它,我们首先需要明确“上下文”(Context)的本质。Context,即我们提供给大语言模型(LLM)的全部输入信息。 由于LLM本身是无状态、无记忆的,为了让对话得以延续或让任务得以完成,我们必须在每次请求中,将所有相关的历史信息、背景知识和指令等打包成一个完整的上下文提供给它。 然而,任何模型能接收的信息量都存在一个上限,这个限制被称为**“上下文窗口”(Context Window)**。
因此,Context Engineering可以被定义为:一门围绕有限的“上下文窗口”进行极致优化的系统性技术,其核心目标是为LLM构建一个最高效、最相关、最无歧义的信息环境。
好,到此我们可以简单对比下Prompt Engineering和Context Engineering:
我们用一句话总结一下,提示工程是“对话的艺术”,而上下文工程是“构建AI Agents的架构科学”。
我们为什么需要上下文工程?
下面这张图展示了一些主流模型的Context Window的大小:
我们可能有一个疑问:随着模型版本的迭代,Context Window似乎在不断扩大,我们是不是只要等待一个“足够大”的窗口,就不再需要上下文工程了?
答案是否定的,因为“窗口大”并不意味着“信息有序”,大量信息堆在一起会导致分心、混乱甚至错误。因此上下文工程并非是应对当前技术限制的一种临时的技术方案,而是一门处理AI信息输入的、具有长期价值的核心工程学科。其必要性主要体现在以下三个层面:
1.规模的极限:“足够大”的Context Window并不存在
首先,尽管我们见证了Context Window的飞速扩张,各大模型厂商也在追逐更大的Context Window,但认为它会无限增长直至问题消失,可能过于乐观。随着摩尔定律的放缓和规模法则(Scaling Law)边际效益的递减,追求一个能容纳所有信息的“足够大”窗口正面临着基础计算和架构层面的巨大挑战。可以断言,在可预见的未来,Context Window仍将是一种宝贵且有限的资源。
因此,上下文工程的核心任务之一,就是将上下文窗口视为一种必须高效管理的稀缺资源。它的目标不是等待一个更大的“容器”,而是通过精巧的设计,确保每一寸空间都发挥出最大的价值。
2.经济的考量:成本与延迟的双重约束
其次,我们也面对着一个直接的商业现实:成本和延迟。
- 成本 (Cost): 在商业应用中,每一次对LLM的调用都与成本直接挂钩,而成本通常按处理的Token数量计算。一个未经优化的、臃肿的上下文请求,在大规模应用中,会迅速累积成巨大的开销。
- 延迟 (Latency): 更大的上下文意味着模型需要更长的处理时间,这直接影响用户体验。在一个追求即时响应的时代,一个反应迟钝的AI应用,很大程度上就是一个失败的应用。
3.性能的悖论:“大海捞针”与注意力的衰减
最后,更大的Context Window并不总是带来更好的性能。研究和实践都揭示了一种“大海捞针”(Needle in a Haystack)或“迷失在中间”(Lost in the Middle)的现象:当提供给模型的上下文中充满了大量信息时,即使是顶级模型,其“注意力”也可能被稀释,导致它忽略或无法准确提取出深埋在冗长文本中的关键细节。
- 尽管 Gemini 2.5 Pro 支持百万级别token的上下文,但如何在智能体(Agent)中有效地利用它,是一个全新的研究前沿。在这次智能体实验中我们观察到,当上下文长度显著超过10万token时,该智能体表现出一种倾向:它更倾向于从其庞大的历史记录中重复旧有的行为,而不是综合信息来制定新的计划。(引用自Drew Breunig《How Long Contexts Fail》)
这不仅仅是“注意力失焦”,更是一种信噪比(Signal-to-Noise Ratio)的问题。 上下文工程在此扮演重要的角色。它不是将原始、未经处理的信息“暴力”灌输给模型,而是通过检索增强生成(RAG)、对话摘要、信息排序、隔离等技术,为模型精心准备一份简洁、相关、结构化的详情摘要,确保核心信号(Signal)不会被无关的噪音(Noise)所淹没。 那么,我们如何从海量数据中精准地为模型找到它真正需要的信息呢?答案之一是一种强大的技术范式:检索增强生成(RAG)。
什么是RAG?
RAG简介
RAG,全称为检索增强生成(Retrieval-Augmented Generation),是一种将信息检索(Information Retrieval)与大语言模型的生成能力相结合的强大技术范式。顾名思义,其核心机制在于“先检索,后生成”:在回应用户请求之前,首先从一个庞大的外部知识库中检索出最相关的信息片段,然后将这些信息作为精准的上下文注入到提示词中,引导模型生成更准确、更具体、更有依据的回答。
RAG最初因其在构建企业知识库和问答系统中的卓越表现而广为人知。随后,它迅速成为AI搜索引擎背后的核心技术。而随着AI Agent的兴起,RAG的内涵被进一步拓展和深化,它不再仅仅是“问答”的工具,更是为Agent提供动态知识、构建其“长期记忆”和“世界模型”的关键组件。
RAG的工作流程
RAG的实现可以清晰地划分为两个阶段:准备阶段和回答阶段。
阶段一:准备阶段
这个阶段是一次性的、在后台完成的数据预处理工作,其目标是将非结构化的知识源转化为机器可以高效检索的结构化索引。
- 数据分片 (Chunking)
数据分片即将长文档(如PDF、Word、HTML)切分成更小的、有意义的信息块(Chunks)。分片并非简单的文本切割。它是RAG流程中第一个,也是最关键的调优环节。一个好的分片策略,应该确保每个信息块在语义上是完整且自洽的。分片过大,会引入过多噪音;分片过小,则可能丢失关键的上下文。分片的质量直接决定了后续检索效果的天花板。 - 向量化与索引 (Vectorization & Indexing)
使用一个强大的嵌入模型(Embedding Model)将每一个文本块转换为一个高维度的数学向量(Vector)。这些向量捕捉了文本的语义信息,然后被存储在一个专门的向量数据库(Vector Database) 中,并建立索引。这一步的本质是将人类的语言世界映射到一个数学空间。在这个空间里,“距离”代表了“语义的相似度”。这就为我们后续进行“模糊”但精准的语义检索奠定了基础,让系统不再局限于简单的关键词匹配,而是能够真正理解查询的意图。
阶段二:回答阶段
这个阶段是当用户发起真实提问时,系统实时执行的流程。
- 检索召回 (Retrieval)
当用户提出问题时,系统首先将用户的问题也进行向量化,然后用这个“问题向量”去向量数据库中进行“相似度搜索”,快速找出与问题语义最接近的Top-K个文本块。这是RAG效率的核心。我们瞬间将问题的范围从海量的信息缩小到了相关的几个段落。这一步极大地降低了后续LLM的处理负担,是解决成本、延迟和注意力稀释问题的关键。 - 重排序 (Re-ranking)
从初步召回的多个文本块中,进一步筛选和排序,选出与用户问题最精准、最相关的几个。单纯的向量相似度有时会出错(例如,一个介绍“苹果公司”的段落可能在向量上与“苹果手机”很近,但用户问的是后者)。重排序是增加系统智能性的重要步骤,它相当于一个“二次精选” 的过程。可以使用更轻量的交叉编码器(Cross-encoder)模型,甚至直接利用LLM本身(即“LLM as a Judge”模式)来对召回结果进行打分和排序,确保最终提供给生成模型的“参考资料”是优中选优的。 - 增强与生成 (Augmentation & Generation)
将用户的原始问题与经过重排序后的最优文本块,共同组合成一个增强后的提示词(Augmented Prompt),然后将这个完整的提示词发送给LLM。 LLM接到的指令不再是孤立的“请回答……”,而是结构化的“请根据以下参考资料:[...插入检索到的文本块...],来回答这个问题:[...]”。这种方式强制模型将其回答“锚定” 在我们提供的、可信的事实之上,从而极大地减少了“模型幻觉”(Hallucination),并使其生成的内容既具备了LLM的流畅表达能力,又拥有了外部知识的准确性和实时性。 这最后一步的注入与组织方式,被称为 Augmented Prompt,是RAG的关键所在。
Agentic RAG
在我们理解了基础 RAG 的工作流程之后,一个自然而然的问题浮现了:如果第一轮检索到的文档质量不高,或者用户的问题本身就很模糊,这个线性的、固定的流程该如何应对?答案是——它无法应对。传统的 RAG 是线性不循环的,每一步都按预设规则执行,缺乏灵活性和判断力。
而Agentic RAG,或者说“Agent驱动的 RAG”,正是为了解决这一根本性缺陷而设计的。它不再是一个固定的流水线,而是一个动态的、具备思考和决策能力的智能系统。Agentic RAG 的本质,是将一个具备自主规划、自我反思和动态工具使用能力的 AI Agent,嵌入到 RAG 流程的核心。这个 Agent 扮演着“研究员”的角色,它会主动评估每一步的结果,并决定下一步是该深化研究、另辟蹊径,还是已经可以得出结论。
我们可以从下面这张图简单理解下Agentic RAG 工作流程:
与传统RAG相比,Agentic RAG 嵌入了自主代理,可以动态决定要查询的工具或数据源,并可能根据需要在多个数据库(或其他工具)之间切换。
为了直观理解这一架构,我们可以用一段极简的代码来模拟其核心逻辑:
# 1. Define a "Tool Kit" containing all available tools.
tool_kit = {
"vector_search_engine_a": lambda q: f"Found documents about '{q}' from knowledge base A...",
"vector_search_engine_b": lambda q: f"Found reports about '{q}' from knowledge base B...",
"web_search": lambda q: f"Found the latest news about '{q}' from a web search...",
"calculator": lambda expr: f"The result of calculating '{expr}' is {eval(expr)}",
}
# 2. Core logic for the "Retrieval Agent".
def retrieval_agent(user_query: str):
"""
This function simulates the core workflow of an Agentic RAG process.
"""
print(f"--- Agent received query: '{user_query}' ---")
# === Step 1: Analyze the query & select the right tool (The Agent's "brain" makes a decision) ===
# In a real-world scenario, this step would be handled by an LLM (e.g., through Function Calling).
# Here, we simulate the LLM's decision-making process with simple if-else logic.
if "Product A" in user_query:
tool_to_use = "vector_search_engine_a"
elif "sales" in user_query:
tool_to_use = "vector_search_engine_b"
elif "calculate" in user_query:
tool_to_use = "calculator"
else:
tool_to_use = "web_search"
print(f"Decision: Use tool '{tool_to_use}'")
# === Step 2: Call the selected tool to retrieve information ===
tool_function = tool_kit[tool_to_use]
information = tool_function(user_query) # Execute the tool
print(f"Tool returned information: {information}")
# === Step 3: LLM generates the final answer based on the retrieved information ===
# The retrieved information and the original query are passed to the LLM.
final_response = f"LLM Answer: Based on the retrieved information '{information}', the answer to your query '{user__query}' is..."
print(f"Generating final answer...")
return final_response
# --- Running an example ---
# Example: This query requires retrieving sales data from knowledge base B.
user_question = "How were the sales of Product A last year?"
response = retrieval_agent(user_question)
print("\n--- Final Output ---")
print(response)
RAG为我们提供了一个强大的框架,但它只是整个Context Engineering学科中的一个核心组件。要真正构建一个稳定、可靠且高效的Context Engineering系统,我们必须深入探讨在进行上下文工程时会普遍遇到的问题。
上下文工程中会遇到的问题
为了深刻理解在设计AI Agents时上下文工程所面临的挑战,我们选择三篇深刻的文章进行剖析,这三篇文章分别从实证观察、一线工程实践和大规模系统架构三个独特且互补的视角,来尝试勾勒问题的全貌。
一、 Drew Breunig的《How Long Contexts Fail》
这篇文章我在上文当中也有引用,本文通过实证观察,命名了四种具体的、可复现的失败模式。这些模式揭示了当上下文被不加管理地扩展时,模型的认知与推理能力会如何系统性地失灵。
- 上下文毒害 (Context Poisoning):指代错误信息的持续性污染。当模型自身的一次错误输出(如幻觉或错误的中间推理)被反馈到后续的上下文中,这个错误就会成为一个被固化的“事实”。模型会基于这个被污染的状态进行后续决策,导致错误的累积和传递,最终使任务走向不可逆的失败。这是一种由系统自身状态反馈导致的内生性错误。
- 上下文分心 (Context Distraction):描述了信噪比下降导致的注意力稀释。随着上下文长度增加,无关或低相关性的信息(例如,大量的API定义、冗长的对话历史)会稀释关键信息的权重。模型有限的注意力资源被分散,导致它无法聚焦于核心指令或当前任务最关键的数据点,从而降低了任务执行的准确性。
- 上下文困惑 (Context Confusion):这是“分心”的加剧。过量的、尤其是不必要的上下文信息,不仅会分散模型的注意力,更会对其决策空间造成干扰。例如,面对数十个当前任务根本用不上的工具定义,模型可能会被这些选项“迷惑”,从而做出非优甚至错误的行为选择(如调用一个不相关的工具)。
- 上下文冲突 (Context Clash):指代上下文中存在的信息不一致性对模型推理能力的破坏。当上下文中包含逻辑上相互矛盾的指令或事实时(例如,早期基于不完整信息做出的判断与后期更正的信息并存),模型的推理过程会陷入混乱。它无法有效仲裁这些冲突,导致其行为变得不稳定或完全瘫痪。
Breunig的文章的深刻之处在于,它将上下文工程的问题从一个模糊的工程挑战,具体化为了一系列可以被识别、诊断和研究的认知失效模式。
二、 Manus团队的《Context Engineering for AI Agents》
如果说Breunig的文章描述了“症状”,那么Manus团队的这篇文章则深入到了“病因”。它并非理论探讨,而是从大量、痛苦的实验和迭代总结出的一系列深刻的工程原则。
- 性能与成本的物理约束:KV缓存
智能体“长输入、短输出”的工作模式,使其性能和成本极度依赖于KV缓存的命中率。任何破坏上下文前缀稳定性的动态内容(如时间戳),都会导致缓存失效,成本和延迟剧增。这暴露了上下文的动态性与计算资源的静态优化之间的根本矛盾。 - 有限上下文与无限信息空间的矛盾
上下文窗口是有限的,但智能体需要处理的信息(工具、文档)可能是无限的。如何将一个庞大的信息空间映射到有限的上下文中,同时避免Breunig描述的“分心”与“困惑”问题?而且动态移除工具会破坏KV缓存。 - 模型内在认知偏见的操控
LLM并非完美的逻辑推理机,它存在固有的认知偏见,如过度关注上下文末尾的信息和对模式的过度模仿。若不加以管理,这些偏见会导致智能体偏离长期目标或陷入行为定式。
三、 Anthropic的《Multi-Agent Research System》
Anthropic的文章则将这个问题提升到了一个新的维度:当从单个智能体扩展到多智能体系统时,上下文工程会演变成一个复杂的系统架构问题。在多智能体环境中,上述所有问题都会被指数级放大,并催生出新的、更高层次的挑战。
- 全局上下文污染与信息过载
在一个多智能体系统中,最直接的问题是信息隔离的失效。如果没有架构层面的强制约束,所有智能体的思考过程、工具使用历史和中间输出会涌入一个统一的、巨大的“全局上下文池”。这导致任何一个智能体的上下文都不可避免地被其他智能体产生的、但与其当前任务无关的大量信息所“污染”。这种系统性的上下文污染,将直接最大化Breunig所描述的“上下文分心”和“上下文困惑”效应,使得任何一个专业智能体都难以在其充满噪音的认知空间中高效工作。 - 共享状态的不一致与并发冲突
多智能体协作的本质要求它们能够共享一个对任务全局状态的共同理解。然而,当多个自主的智能体并发工作时,一个根本性的挑战随之而来:如何维护这个共享状态的一致性?如果没有一个结构化的、受控的共享空间,系统将面临严重的并发问题。智能体可能会基于过时的信息制定计划,或者一个智能体的关键输出可能会被另一个智能体无意中覆盖。这种状态同步的缺失,使得智能体之间无法进行可靠的、可累积的协作,从而导致整个系统任务的崩溃。 - 无差别的能力分配与安全风险
当系统采用专业化的智能体(如“研究员”、“代码执行器”)时,一个关键的架构问题是能力的分配。如果系统缺乏一种机制来为每个智能体分配其角色所需的最小化工具集,那么所有工具的定义都必须被加载到每个智能体的上下文中。这首先从上下文工程的角度,用大量无关信息加剧了上下文的臃肿和“困惑”问题,直接损害了专业智能体的性能。其次,它造成了严重的安全和操作风险——一个本应只负责撰写报告的智能体,却拥有了执行任意代码的权限,这在任何生产系统中都是不可接受的。
综上,上下文工程所面临的挑战,是一个从模型具体的认知失效,到单智能体核心的工程制约,再到多智能体复杂的系统架构,层层递进、环环相扣的系统性难题。
面对这些深刻且复杂的难题,LangChain团队提出的标准化建议为我们提供了宝贵的顶层设计思路。需要明确的是,这些建议更多是作为一套具有战略指导意义的框架,而非旨在解决所有具体问题的万能良方,但其作为深度参考的价值毋庸置疑。
LangChain团队的标准化建议
LangChain将上下文工程的核心挑战,拆解为对信息生命周期进行管理的四个关键策略。这四个策略共同构成了一个系统性的解决方案,旨在将上下文管理转变为一门真正的“工程学科”
一、 写入上下文 (Writing Context)
“写入”是指将信息持久化到上下文窗口之外的存储中。这从根本上承认了上下文窗口的物理局限性,并将智能体的“记忆”从易失的、有限的“RAM”扩展到了一个近乎无限的、可持久化的“硬盘”(如向量数据库、文件系统、SQL数据库)。
解决的问题:
- 它直接回应了Manus团队指出的“有限上下文与无限信息空间的矛盾”。通过建立一个外部记忆库,智能体获得了处理海量文档、保留长期历史、积累知识的能力,而不受限于任何特定模型的窗口大小。Manus提出的“使用文件系统作为上下文”正是这一策略的具体实践。
- 它为结构化地管理智能体状态提供了物理基础。信息不再是临时的文本流,而是可以被管理、索引、甚至版本化的数据,这为解决Breunig描述的“上下文毒害”问题提供了可能——因为我们可以对写入外部记忆库的信息进行审查和修正。
二、 选择上下文 (Selecting Context)
“选择”是指在智能体执行任务的每一步,从外部记忆库中精准地检索出与当前步骤最相关的信息,并将其注入到上下文窗口中。这本质上就是RAG(检索增强生成)的核心操作。
这是对抗Breunig提出的“上下文分心”与“上下文困惑”的最直接武器。通过“选择”而非“堆砌”,系统确保了进入上下文窗口的信息具有极高的信噪比。模型不再需要面对所有可能的工具或全部历史记录,而只需聚焦于一小部分经过筛选的关键信息,从而极大地提升了决策的准确性。
三、 压缩上下文 (Compressing Context)
“压缩”是在信息被“选择”之后、进入上下文窗口之前的精炼步骤。它旨在通过各种技术(如总结摘要、实体提取、剔除冗余信息,或者使用独立模型),在不损失核心语义的前提下,最大程度地减少所选信息的Token数量。
它直接缓解了Manus团队关注的性能与成本的物理约束。更少的Token意味着更低的API调用成本、更快的模型响应速度以及对KV缓存更友好的使用模式。即使“选择”出的文档是相关的,其中也可能包含大量无关的样板文字。压缩技术能够帮助模型直接触达信息的核心,进一步降低了认知负荷,是对抗“上下文分心”的深度净化。
四、 隔离上下文 (Isolating Context)
“隔离”是一种架构性思想,它要求将注入上下文的不同类型信息,在逻辑上和结构上进行拆分和区隔。这意味着系统指令、用户输入、选择的上下文(工具、文档)、以及智能体的思考链(Scratchpad)不应混为一谈,而应作为独立的、结构化的模块进行组合。
- 它直接对应了Anthropic在多智能体系统中提出的“上下文范围界定(Scoping)”的核心思想。隔离,就是在单个智能体内部实现了微观的“作用域”。这种模块化使得上下文的管理更加清晰、可预测,并极大地降低了不同信息部分之间互相干扰的可能性(即Breunig所说的“上下文冲突”)。
- 它为从业者们普遍面临的上下文组合难题提供了一种结构化的、工程化的应对思路。Manus的文章通过其六大精巧的工程原则,恰恰证明了上下文的组合是一个需要对不同信息部分(如工具定义、思考过程、错误信息)进行精细操控的复杂问题。LangChain的‘隔离’策略,正是试图从一个更高的架构层面,为这个被实践证明极其复杂的组合问题带来秩序和可预测性,从而减少对零散技巧和大量试错的依赖。
AI Agent的核心架构范式
AI Agent的架构设计是紧密围绕产品需求展开。不同的产品形态,决定了其对智能体在自主性、鲁棒性与成本效益上的不同权衡。因此,本章将深入剖析业界的核心Agent架构,并重点聚焦于那些能够构建出真正强大、具备复杂问题解决能力的智能体的架构思想。
通过对业界经典理论与前沿实践的深度整合,我们可以从两个正交的维度来解构AI Agent的架构设计:认知架构与系统拓扑。
维度一:认知架构
认知架构定义了单个智能体的内部工作流,即它如何感知环境、进行推理并做出决策。
层级 0: 反应式架构 (Reflexive Architecture)
反应式架构是智能体行为最基础的形态。它的核心特征是无状态(Stateless),即不维护任何关于过去的内部记忆。其决策逻辑是一个从当前感知到直接行动的简单映射,严格遵循预设的“条件-动作”规则。
可以将其理解为一个纯粹的“IF-THEN”执行器:IF 观察到特定条件,THEN 立即执行相应动作。
在大型语言模型的时代,这种架构的典型体现就是一次独立的、无聊天历史记录的API调用。模型接收一个提示(即“条件”),并生成一个回复(即“动作”),这个过程不依赖于任何先前的交互。
虽然因其缺乏记忆和规划能力,反应式架构通常不被视为严格意义上的“智能体”,但它是不可或缺的基础构件。所有更复杂的认知架构,其最终的“行动”步骤,都依赖于这个最底层的反应式执行核心。
层级 1: ReAct架构 (Reactive Deliberation)
ReAct架构是现代大型语言模型(LLM)智能体的事实标准基线。它在最简单的“反应式架构”基础上,引入了两个至关重要的概念:显式的内部思考(Reasoning)和基于行动的外部信息获取,从而形成了一个动态的“思考-行动”循环。
1.ReAct的核心运行流程
ReAct架构将智能体的决策过程,从一个黑盒变成了一个相对透明、可解释的循环。这个循环由三个核心步骤组成:
- Thought (思考): Agent首先基于当前收到的所有信息(包括最初的任务和之前所有步骤的结果),生成一段内部思考。这段思考是它对自己当前处境的分析、对目标的拆解,以及对下一步行动的规划。例如:“我需要创建一个贪吃蛇游戏,首先我需要创建HTML、CSS和JavaScript三个文件。”
- Action (行动): 基于“思考”得出的结论,Agent决定执行一个具体的“行动”。这个行动几乎总是调用一个外部工具。例如:write_to_file("index.html", "<html>...")。
- Observation (观察): “行动”(即工具调用)被执行后,会从外部环境返回一个结果。这个结果就是“观察”。例如,write_to_file工具可能会返回“文件写入成功”。这个观察结果会被反馈给Agent。
2.ReAct的实现原理
ReAct 模式的优雅之处在于,它并非依赖特殊的模型训练,而是通过一个高度结构化的系统提示词 (System Prompt) 来实现对通用大语言模型的行为引导。 这个引导通常分为以下几个步骤:
-
行为规约 (Behavioral Mandate):明确定义模型的角色和必须遵循的输出格式。比如它强制模型必须以<thought>、<action>等标签来组织每一次的输出,确保了 Agent 运行流程的确定性。
-
能力清单 (Capability Manifest): 向模型清晰地列出所有可用的工具,包括每个工具的精确名称、功能描述和参数定义。这让模型知道自己“能做什么”。
-
情境感知 (Situational Awareness): 动态地向模型提供当前的环境信息,如操作系统、当前工作目录等。这让模型的决策能够基于真实情境。
-
在上下文演示 (In-Context Demonstration): 通过提供一到两个完整的任务解决范例(Few-shot Examples),向模型“演示”而非“说教”如何运用 ReAct 循环。模型通过模仿这些范例,学会在新任务中遵循同样的“思考-行动”逻辑。
层级 2: 规划式架构 (Proactive Planning)
单ReAct 架构虽然强大,但其本质是短视的、反应性的。它在每一步都只根据当前观察做出最优的下一步决策,这在处理简单任务时非常高效。然而,当面对需要多个步骤、长期规划的复杂目标时,纯粹的 ReAct 智能体很容易迷失方向——它可能陷入局部最优解的循环,或者因中间步骤的微小偏差而逐渐偏离最终目标。
规划式架构(Plan-and-Execute)从根本上解决了 ReAct 的一些局限性。它的核心思想源于计算机科学中最经典的分治策略(Divide and Conquer):将长期、复杂的战略规划,与短期、具体的战术执行彻底解耦。
1.核心思想:规划与执行的分离
这种架构将智能体的认知过程明确地划分为两个独立且先后衔接的阶段,以此来降低单一决策循环的认知负担:
- 规划阶段 (Planning Phase): 在这个阶段,智能体(或一个专门的“规划器”模型)的首要任务不是执行,而是理解用户的最终意图,并将其分解为一个结构化的、有序的行动计划。这个计划是实现最终目标的宏观路线图。
- 执行阶段 (Execution Phase): 在这个阶段,智能体(或一个专门的“执行器”智能体)的角色转变为一个专注的任务完成者。它不再需要思考整体战略,其唯一职责就是接收上一步生成的计划,并忠实地、一步一步地完成其中的每一个子任务。
2.实践中的体现:从 todo.md到 LangGraph
这个看似简单的两阶段模型,在当今最前沿的 AI Agent 中有着丰富且强大的实现:
- todo list 作为计划的具象化: 正如我们在 Manus和其他多个编程 Agent 的演示中所看到的,它们在处理复杂编码任务时,第一步往往是在工作目录中生成一个 todo.md 或类似的任务清单文件。这个 todo list 就是“规划”阶段产出的具体工件(Artifact)。它将一个模糊的需求(例如“创建一个贪吃蛇游戏”)转化为一个清晰、可执行的步骤序列(1. 创建HTML文件;2. 创建CSS文件;3. 实现JS游戏逻辑...)。这个清单成为了“执行”阶段的唯一行动依据。
- LangGraph 的形式化定义: LangChain 团队在其高级框架 LangGraph 中,将这一模式形式化为一个计算图(Computation Graph)。用户的请求首先进入一个“规划器节点”(Planner Node),该节点负责生成任务列表。然后,这个列表被传递到一个“执行器节点”(Executor Node),该节点内部通常运行着一个 ReAct 循环,负责消费并完成任务列表中的每一项。这种节点化的实现,完美地体现了规划与执行在逻辑和计算上的彻底分离。
3.关键机制:动态的“重新规划” (Re-planning)
一个真正强大的规划式架构并非是死板的。在执行完一个或多个步骤后,环境可能会发生变化,或者初步的结果可能与预期不符。因此,高级的 Plan-and-Execute 实现都包含一个“重新规划”(Re-planning)的反馈循环。
- 工作流: 执行器在完成一个步骤后,会将结果反馈给一个“重新规划器”(Re-planner)模型。这个模型会评估当前的任务完成情况、历史执行记录和最新的计划,然后决定是继续执行下一步,还是对剩余的计划进行修改、补充,甚至完全重写。
- 价值: 这个动态修正的环节,将规划式架构的“远见”与 ReAct 架构的“适应性”完美结合,使得智能体既能保持对长远目标的聚焦,又能灵活应对执行过程中的意外情况。
规划式架构是智能体从“能解决简单问题”到“能系统性地完成复杂项目”的关键一步。它通过引入战略性的前期规划,为智能体的行为提供了明确的方向,极大地提升了其在长周期任务中的可靠性、可预测性和最终成功率。无论是通过简单的 todo list,还是通过 LangGraph 这样的复杂图结构,其“先规划、后执行、再调整”的核心思想,都是构建高级自主智能体不可或缺的组成部分。
层级 3: 反思式架构 (Reflective / Meta-Cognitive)
反思式架构的核心,是为智能体注入一种至关重要的能力——元认知(Meta-Cognition),即对自身思考和行为的审视、评估与修正。它标志着Agent从一个单纯的“任务执行者”向一个能够进行“质量控制”的“问题解决者”的转变。
1.核心挑战:对抗单次生成的不可靠性
此架构的根本动机,是为了解决所有基于LLM的系统都面临的内在缺陷:单次生成的随机性与不可靠性。一个LLM在一次调用中,可能会产生事实错误(幻觉)、逻辑谬误或次优解。一个没有反思能力的Agent,一旦在某个环节犯错,便很容易将这个错误作为后续步骤的输入,造成错误的累积和放大,最终导致任务失败。
2.架构模式:执行与批判的分离
为了实现反思,该架构在逻辑上将执行流程解耦为两个核心角色,形成一个内部的“生成-评估-修正”反馈循环:
- 执行者 (Executor): 负责根据当前任务产出初步的结果。这可以是ReAct循环中的一次行动结果,也可以是规划式架构中的一个完整计划。
- 批判者 (Critique): 负责审视“执行者”的产出。它的任务不是自己动手解决问题,而是作为内部的“质检员”,依据一套预设标准(例如,代码是否遵循规范、文本是否事实准确、计划是否高效)来评估输出,并生成一份具体的、可操作的改进建议。 这个循环会持续迭代,直到“批判者”对“执行者”的输出感到满意为止。
3.反思的两个主要应用层面
针对“过程”的反思 - 即Re-planning:
这是我们在规划式架构中已经看到的模式。这里的反思对象是“计划”本身。在执行完一个或多个步骤后,Agent会审视剩余的计划是否仍然有效、是否需要根据新的观察结果进行调整。这确保了Agent在长周期任务中战略路径的正确性。
针对“产出”的反思 - 更广义的自我批判:
这是更强大、更通用的反思模式。这里的反思对象是每一步的具体产出物。例如:
- 代码生成: 执行者生成一段代码后,批判者(可能是另一个LLM,配置了专门的审查Prompt)会检查其是否存在bug、是否符合性能要求、是否遵循了项目编码规范。
- 报告撰写: 执行者写完一段摘要后,批判者会检查其是否遗漏了关键信息、是否存在事实性错误(可能需要调用搜索工具进行交叉验证)。 反思式架构的引入,是构建高质量AI Agent的必要条件。它通过建立内部的质量控制循环,系统性地降低了LLM的随机性带来的风险。
维度二:系统拓扑
系统拓扑定义了当多个智能体存在时,它们之间的组织关系、通信协议和协作模式。
拓扑 0: 单体 (Solo Agent)
单体拓扑,即系统中仅存在一个独立的智能体进行工作。这是最基础、最普遍的系统结构,也是所有更复杂的多智能体拓扑的基本构成单元。
在这种拓扑结构中,所有的感知、思考、规划和行动都由一个统一的中心实体来完成。它独自承担了从理解用户意图、与外部环境(通过工具)交互,到最终完成任务的全部职责。无论其内部的认知架构多么复杂——无论是简单的ReAct,还是包含规划与反思的高级模式——决策权始终集中于这一点。
单体拓扑是构建AI Agent的起点,适用于绝大多数任务边界清晰、领域相对单一的应用场景。然而,当我们开始面对需要多种专业技能深度协作、流程极其复杂的开放式问题时,单体拓扑的局限性便会凸显,这也自然而然地引出了下一层次的架构思想——多智能体系统拓扑。
拓扑 1: 层级式拓扑 (Hierarchical Topology)
当任务的复杂性超出了单个智能体的处理能力时,层级式拓扑便成为最直观、最强大的解决方案。它摒弃了让一个“通才”智能体独自应对所有挑战的思想,转而采用分工与协作的模式,其核心思想是模仿人类成熟的组织管理结构。
1.核心思想:角色的专业化与中心化协调
这种架构的本质是“分而治之”。它在系统中引入了明确的角色分工和管理层级,通常由两类智能体组成:
- 管理者/协调者 这是整个系统的“大脑”和“项目经理”。它位于拓扑的中心,不直接执行具体的底层任务。其核心职责包括:
- 任务分解 : 理解用户的顶层、模糊的请求,并将其分解为一系列具体的、可执行的子任务。
- 任务分配 : 基于对每个子任务所需技能的理解,将它们精准地分配给最合适的“工作者”智能体。
- 监督与整合: 跟踪所有子任务的完成进度,并在所有工作者返回结果后,负责将这些零散的部分整合成一个连贯的、完整的最终产出。
- 工作者/专家: 这些是专注于特定领域的“专家”。每一个工作者都为完成一类特定任务而优化,拥有自己专属的工具集和知识背景。例如:
- 研究员Agent: 拥有访问搜索引擎、读取网页等工具。
- 编码Agent: 拥有读写文件、执行代码、使用Linter等工具。
- 数据分析Agent: 拥有执行SQL查询、生成图表等工具。
2.信息流:中心化的星型网络
在这种拓扑中,信息流动是中心化的。所有的通信都必须经过“管理者”这个核心节点,形成一个星型网络。工作者之间通常不直接通信,而是将自己的产出和状态更新汇报给管理者,再由管理者决定下一步的行动或将信息传递给另一个工作者。
正如 Anthropic 的多智能体系统所展示的,这种模式通常依赖于一个“共享草稿板”或类似的共享记忆空间,而管理者正是这个空间的主要读者和仲裁者。它通过审视工作者的输出,扮演了我们在“反思式架构”中讨论的“批判者”角色,从而为整个系统的执行流程提供了至关重要的质量控制。
层级式拓扑是将传统软件工程中的“分层设计”和“模块化”思想,成功引入AI Agent领域的典范。它为构建能够处理大型、跨领域、边界清晰的复杂项目的智能体系统提供了一套可靠、稳健的蓝图,是目前企业级Agent应用中最主流和最成功的设计模式。
拓扑 2: 对等网络拓扑 (Peer-to-Peer Network Topology)
层级式拓扑通过引入明确的指挥链,成功地解决了复杂任务的分解问题。然而,这种“自上而下”的刚性结构,也限制了智能体之间更动态、更灵活的协作可能性。当一个问题无法被清晰地预先分解,或者需要多个专家进行多轮、平等的协商才能找到最优解时,对等网络拓扑便应运而生。
1.核心思想:去中心化的专家协作
此架构的哲学核心是从“组织”转向“社区”。它摒弃了中心化的“管理者”,将所有智能体置于一个平等的、去中心化的网络中。在这个结构里,每个智能体都是一个“专家”或“同行”,它们之间没有固有的上下级关系,可以进行直接的点对点通信。
可以将其想象成一个专家圆桌会议。每个专家(如“数据科学家”、“市场分析师”、“法律顾问”)都可以自由地向任何其他专家提问、分享自己的发现、或对别人的观点提出反驳,而无需通过一个中心“主持人”来转达。
2.信息流与协作机制
信息流: 其拓扑结构是一个网状网络(Mesh Network),理论上任何一个智能体都可以直接与网络中的其他任何智能体进行通信。信息流动的路径不再是固定的星型或树状,而是根据任务的需要动态形成。 协作机制: 由于没有了中心指挥,其核心协作机制从层级式的“委派”转变为“协商”和“共识构建”。
- 一个智能体可能会向网络中的所有成员广播一个问题或一个初步的解决方案。
- 其他智能体接收到信息后,会从各自的专业领域出发,对其进行评估、批判或补充。
- 通过这样多轮的提议、反馈、修正的循环,整个智能体网络共同将一个解决方案打磨至最终形态。最终的产出往往是多个专家视角综合后的结果。
对等网络拓扑是为解决那些本质上需要多视角、迭代和协商的复杂问题而设计的。它最适用于头脑风暴、复杂系统设计、多方利益相关者模拟、以及需要通过辩论来消除谬误和达成共识的探索性任务。
它的优势在于极高的灵活性、鲁棒性(没有单点故障)和潜在的创造力(因为观点可以自由碰撞)。然而,其代价是协调的复杂性急剧增加,可能会面临无法达成共识(死锁)或通信成本过高的问题,对智能体之间的通信协议设计提出了极高的要求。
拓扑 3: 群体式拓扑 (Swarm Topology)
在工程实践中,“群体拓扑”一词常被用来描述一种与生物学“群体智能”截然不同的、高度实用的多智能体协作模式。其核心并非追求自下而上的“涌现”智能,而是构建一个由多个、异构的、专业的智能体组成的“专家池”,并通过动态的、有状态的“任务接力”来完成复杂的用户旅程。
这种架构的哲学是:系统本身不试图成为一个解决所有问题的“通才”,而是作为一个高效的调度中心,在恰当的时机激活最合适的“专家”来处理当前的任务阶段。
1.核心思想:作为“可调用服务”的智能体与控制权移交
在这种拓扑中,每个独立的智能体(例如,“机票预订Agent”、“酒店预订Agent”)都被视为一个独立的、可按需激活的“服务”或“能力单元”。
该架构的灵魂在于控制权的切换(Handoff)。当一个当前活跃的智能体完成了其专业领域的任务,并且识别出用户的下一个意图超出了自己的能力范围时,它并不会将问题上报给一个“管理者”,而是会触发一个控制权移交机制,将整个任务的上下文状态和执行权限,直接、平级地传递给“专家池”中下一个最适合的智能体。
2.信息流:通过环境的间接通信
信息的主要载体是一个共享的、持续增长的上下文(例如,与用户的完整对话历史)。当一个智能体被“激活”时,它可以访问这个完整的历史记录,从而无缝地理解任务进行到哪一步。
这种协作模式可以被看作是一场“专家接力赛”。
- 初始时,系统根据用户请求,激活第一个专家智能体(例如,机票Agent)。
- 该智能体全权负责处理所有与其专业相关的交互,而“专家池”中的其他智能体则处于待命状态。
- 当该智能体完成其阶段性任务(订完机票)后,它的最后一步是发出一个信号,指明下一个应该接力的专家(例如,酒店Agent)。
- 系统随即“唤醒”指定的下一个专家,并将完整的上下文交给它。新的专家从中断处无缝接手,开始处理下一阶段的任务。
群体拓扑(在工程实践的语境下)是为解决那些需要依次动用多种不同专业技能来完成的、端到端的复杂用户任务而设计的。它是一种极其模块化和可扩展的架构。
Single-Agent还是Multi-Agent
在探讨了从单体到群体的多种系统拓扑之后,我们自然会遇到一个核心的架构抉择:我们应该致力于构建一个无所不能的、强大的单体Agent,还是一个由多个专家组成的协作系统?
这个问题,具体化为业界两篇标志性文章的对撞:一篇是Cognition AI(Devin的创造者)的《Don’t Build Multi-Agents》;另一篇还是Anthropic的《How we built our multi-agent research system》。
Cognition的警告:警惕“无协议的并行”
Cognition的论点,并非是对“多智能体”概念的全盘否定,而是对一种特定失败模式的精确打击:天真的、无结构的、并行的多智能体协作。
在其“Flappy Bird”思想实验中,一个主智能体将任务分解给两个并行工作的子智能体(一个做背景,一个做小鸟)。最终的失败是必然的,因为它触犯了两条根本性原则:
- 上下文完整性的丧失: 子智能体只接收到孤立的指令,而丢失了“克隆Flappy Bird”这个决定整体美术风格和物理引擎的最高上下文。
- 隐式决策的冲突: 两个并行的智能体,在缺乏沟通协议的情况下,各自对“游戏风格”做出了独立的、相互冲突的隐式决策,导致其产出无法整合。
Cognition的深刻洞见在于:在缺乏一个强制性的、共享的上下文和统一的决策仲裁机制时,增加Agent的数量只会指数级地增加系统的混乱度(熵),而非算力。 他们所批判的,是“无政府状态”下的协作。
Anthropic的实践:证明“有协议的协作”
与此相对,Anthropic的系统之所以成功,恰恰因为它不是一个Cognition所批判的“无政府系统”。相反,它是一个高度结构化的、有协议的协作典范。
- 它不是并行的,而是结构化的流水线 : 任务按照“开发者 -> 批判者 -> 测试者”的清晰串行流程执行,并通过反馈循环进行迭代,从根本上杜绝了并行带来的决策冲突。
- 它不是无政府的,而是角色驱动且受协调的: 每个Agent都有专门的角色和限定的能力范围。更重要的是,系统通过一个显式的“协调器”(Orchestrator)来管理上下文的流转,并通过“共享草稿板”和专门的“批判者”角色,建立了一个强制性的质量保证环节。
- 它的上下文不是孤立的,而是共享和统一的: 所有Agent都围绕一个共同的任务状态(代码库、Issue描述、共享草-稿板)进行工作,确保了上下文在整个任务周期中的完整性与一致性。
那一个同时应用了前述多种强大架构思想的智能体,其实际形态是怎样的?我们可以使用LangChain团队提到的Deep Agents结构来进行讨论。
根据其定义,一个“Deep Agents”系统通常由以下四个核心组件构成,而这些组件恰恰呼应了我们之前的所有讨论:
- Planning Tool (规划工具): 这直接对应了我们的规划式认知架构。智能体并非盲目地进行反应,而是首先利用规划工具(例如,生成一个todo.md任务清单)来分解复杂目标,为后续的执行提供一个清晰的、结构化的路线图。这赋予了智能体“远见”。
- File System (文件系统): 这正是上下文工程思想的具象化体现。文件系统被用作一个外部的、持久化的记忆和工作空间,解决了上下文窗口有限的根本矛盾。大型的观察结果、中间产物、甚至长期的记忆,都可以被“卸载”到文件中,而Agent在上下文中只保留对这些文件的引用。这赋予了智能体“记忆”和可靠的“真理之源”。
- Sub Agents (子智能体): 这呼应了多智能体系统拓扑的优势。当面对一个需要多种专业技能的任务时,主智能体可以像一个项目经理一样,将特定的子任务(如“进行深度网络搜索”或“审查代码”)委派给专门的子智能体。这实现了任务的模块化和专业化,赋予了智能体“分工协作”的能力。
- System Prompt (系统提示): 这是将所有组件粘合在一起的“宪章”。一个详尽、精密的系统提示,定义了Agent的核心身份、必须遵循的行为准则、以及如何协同使用规划工具、文件系统和子智能体来达成最终目标。这赋予了智能体“灵魂”和行为的“确定性”。
“Deep Agents”模型清晰地表明,一个强大的AI Agent并非单一架构的产物,而是一个将规划、记忆、协作和核心逻辑融为一体的复合系统。
介绍完了以上,相信我们对于如何设计AI Agents已经有了一套自己的思路,我们接下来就尝试将其抽象出来。
一个健壮的AI Agent所应该具备的
我们已经达成共识:设计AI Agent的命题,已经无可逆转地演变为设计“AI System”的工程挑战。一个健壮的Agent,其本质是一个成功地将大语言模型(LLM)的“概率性智能”约束在“确定性系统”之内的工程产物。它的健壮性并非源于模型本身的“更聪明”,而是源于系统架构的“更可靠”。
要实现这一点,我们的设计必须建立在以下四大支柱之上,它们共同组成了健壮Agent的所应该具备的。
一、外部化的确定性状态
Agent的“记忆”从易失的、与逻辑纠缠的上下文中彻底剥离,使其成为一个外部的、结构化的、可被精确读写的工程对象。这是对抗上下文毒害与上下文冲突的根本解法。
这一支柱是我们对“上下文工程”所有讨论的最终归宿。无论是RAG的信息检索,还是LangChain的“写入/选择”策略,其根本目的,都是为了实现状态管理的确定性,将易变的“心智”固化为可靠的“数据”。它标志着我们将Agent从一个“对话伙伴”转变为一个“可观测系统”的工程决心。
1. 外部化
为什么必须外部化?
LLM本身是无状态的。每一次与LLM对话,都是一次从零开始的、基于当前提示的“冷启动”。将历史记录、中间状态等信息保留在上下文中,本质上是在构建一个“易失性内存”。这个内存不仅容量有限,而且极其不稳定——任何对提示的微小改动都可能破坏其结构,导致KV缓存失效,成本和延迟剧增。更糟糕的是,它无法在多次任务或多个Agent之间共享。
如何实现外部化?
系统的“Source of Truth”必须存在于LLM的易失上下文之外。LLM是状态的使用者,而非拥有者。
a.文件系统作为状态存储
最直接的方式,就是将Agent的工作状态持久化到其工作目录的文件中。
- state.json: 用于存储结构化的、键值对形式的当前状态,如工作变量、任务进度等。
- scratchpad.md 或 memory.log: 用于以追加(append-only)的方式,记录每一步的思考链、行动和观察,形成一个不可变的、可审计的历史记录。
示例 state.json 文件:
{
"current_task_id": "task-003",
"files_created": ["index.html", "style.css"],
"last_error": null,
"steps_completed": 2
}
b.Key-Value存储
当需要更快的读写速度或处理并发请求时,可以使用Redis这样的内存数据库。它可以存储更复杂的数据结构,并为多Agent系统提供一个共享的、低延迟的状态中心。
c.向量数据库作为长期记忆
这是对RAG思想的延伸。Agent的每一次重要“经历”(一个成功的解决方案、一次失败的尝试及其原因)都可以被向量化,并存入向量数据库。当Agent面临新任务时,它可以首先检索过去最相似的“经历”,从而实现“举一反三”,这是一种真正意义上的“长期记忆”。
2.结构化契约
为什么必须结构化?
自然语言的歧义性是构建确定性系统的天敌。“修复登录页的bug”这句话,对于不同的上下文,可能有十种不同的解释。依赖LLM去猜测意图,就是在为系统注入不可控的随机性。
如何实现结构化?
状态的传递不应依赖自然语言的模糊性。对Agent的输入和历史记录,都必须是机器可解析的结构化数据。
a.任务契约作为输入
任何分配给Agent的任务,都应首先被转化为一个结构化的“任务契约”。这个契约可以用JSON或YAML来定义,它强制了任务的明确性。
示例 TaskContract.yaml
:
task_id: "DEPLOY-WEBAPP-PROD-20250820"
objective: "Deploy the latest version of the web application to the production server."
context:
git_repository: "https://github.com/user/webapp.git"
server_credentials: "secret_key_for_prod_server"
required_files:
- "./Dockerfile"
- "./.env.production"
deliverables:
- type: "url"
description: "The final, publicly accessible URL of the deployed application."
- type: "log_file"
description: "A log file of the deployment process."
constraints:
- "Do not restart the database service."
- "Deployment must be completed within 15 minutes."
b.结构化执行日志
Agent的历史记录,不应是一个扁平的文本文件,而应是一个由结构化事件组成的日志。
示例 execution_log.jsonl
(JSON Lines格式):
{"step": 1, "timestamp": "...", "type": "thought", "content": "The objective is to deploy the webapp. First, I need to SSH into the server."}
{"step": 2, "timestamp": "...", "type": "action", "tool": "ssh_execute", "input": {"command": "ls -l"}}
{"step": 3, "timestamp": "...", "type": "observation", "status": "success", "output": "total 0\ndrwxr-xr-x 2 root root 4096 Aug 20 05:20 webapp"}
这种格式使得我们可以轻松地对Agent的行为进行查询、分析和可视化,为调试和优化提供了坚实的数据基础。
3.受控突变
为什么必须受控?
这是确保Agent始终与现实锚定的关键。LLM在其思考中,可能会产生“状态幻觉”——它认为自己已经完成了某个操作,但实际上并没有。如果系统完全信任它的内心独白,那么整个任务就会建立在虚假的前提之上。
如何实现受控?
对状态的任何更改,都必须是一次由确定性工具执行的、可验证的事务性操作。LLM的角色是“提议者”,而“执行者”和“验证者”必须是系统本身。
架构模式:提议-执行-验证 循环 (Propose-Execute-Verify Loop)
- 提议 (Propose): LLM的输出不是一个动作的宣告,而是一个结构化的行动提议。
- 执行 (Execute): 系统的调度器(Orchestrator)解析这个JSON,调用一个确定性的 write_file 函数。 LLM本身绝不直接接触文件系统.
- 验证 (Verify): 工具执行后,调度器必须进行验证。它会检查文件是否真的被创建,内容是否正确
- 更新 (Update): 只有在验证成功后,调度器才会将一个包含真实结果的、结构化的“观察”事件,写入到外部的执行日志中。这个日志才是LLM在下一个循环中可以信赖的事实。
二、受锚定的行动循环
确保Agent的每一次“思考-行动”循环都与一个可信的、真实的外部环境进行强制锚定,从而保证其行为的有效性和反馈的真实性。来对抗模型幻觉和意图漂移。
这一支柱是对ReAct架构的深刻重申,并强调了Manus沙盒环境的绝对必要性。ReAct的真正威力不在于“思考”本身,而在于它强制Agent的每一次思考都必须通过“行动”和“观察”,与一个不容置疑的现实进行对撞和校准。
1.行动具象化 (Grounding)
为什么必须具象化?
LLM的原生输出是自然语言。一个Agent如果仅仅停留在生成“我将要创建一个文件”这样的文本,那么它就从未与现实世界发生交互。这种纯语言层面的意图是无法验证、无法执行的“空头支票”。具象化,就是强制LLM将其模糊的意图,转化为一个机器可以无歧义执行的、结构化的指令。
如何实现具象化?
一个决策的唯一有效表达,是调用一个定义明确、行为确定的工具。
- 模式:强制的工具调用(Forced Tool Calling)
这是现代Agent架构的核心。通过系统提示的强力约束,或者利用模型本身提供的功能(如OpenAI的Function Calling),我们强制LLM的“行动”输出必须是一个特定格式的JSON对象。- 反模式(Ungrounded - 未具象化):
LLM输出一段自然语言,系统需要用正则表达式等脆弱的方法去解析。
- 反模式(Ungrounded - 未具象化):
Thought: I should write the initial Python code.
Action: Okay, I will now use the write_file tool to create a file named app.py with the content "print('Hello World')".
这种方式极易出错,因为语言的微小变化都可能导致解析失败。
- 最佳实践(Grounded - 具象化):
LLM被强制输出一个结构化的JSON,代表一个具体的函数调用。
{
"thought": "I should write the initial Python code to get the project started.",
"action": {
"tool_name": "write_file",
"parameters": {
"path": "app.py",
"content": "print('Hello World')"
}
}
}
这个JSON对象就是Agent意图的唯一、可信的具象化表达。系统的调度器(Orchestrator)可以直接解析并执行这个“协议”,而无需进行任何模糊的猜测。
2.环境仲裁 (Environmental Arbitration)
为什么必须由环境仲裁?
这是对抗模型“事实性幻觉”的最有力武器。LLM在执行完一步后,可能会“幻觉”出自己期望的结果。例如,一个git push
命令可能因为权限问题失败了,但LLM可能会在它的思考链中假设推送已经成功,并继续执行后续依赖此操作的步骤。
如何实现环境仲裁?
行动的最终结果,必须由一个受控的外部环境(沙盒)来唯一裁定。LLM无权判断自己的行动是否成功,环境拥有最终解释权。
架构模式:调度器-沙盒执行模型 (Orchestrator-Sandbox Execution Model)
- 调度器接收提议: 系统的核心逻辑——调度器,接收来自LLM的结构化“行动提议”。
- 在沙盒中执行:调度器在一个隔离且受控的沙盒环境中,调用相应的确定性工具函数。例如,执行一个run_shell命令。
- 捕获真实结果: 沙盒必须被设计为能捕获行动的全部、真实的后果。对于一个shell命令,这意味着捕获三个关键信息:exit_code(退出码)、stdout(标准输出)和stderr(标准错误)。
- 生成结构化观察: 调度器将这些真实的后果,封装成一个结构化的“观察”对象。
示例:执行一个失败的git push
命令
# This is the code within the dispatcher.
def run_shell_in_sandbox(command: str) -> dict:
# result = subprocess.run(...)
# ...
# Assume the command fails.
return {
"command": command,
"status": "error",
"exit_code": 128,
"stdout": "",
"stderr": "fatal: Authentication failed for 'https://github.com/user/repo.git/'"
}
# The action proposed by the LLM.
action_proposal = {"tool_name": "run_shell", "parameters": {"command": "git push"}}
# The dispatcher executes the action and gets the actual result, arbitrated by the environment.
observation = run_shell_in_sandbox(action_proposal["parameters"]["command"])
这个observation
字典,就是由现实世界(沙盒)裁定的、不容置疑的结果。
3.无损反馈 (Lossless Feedback)
为什么反馈必须无损?
系统设计者常常会将复杂的错误信息总结为“操作失败”。这是一种致命的错误。这种有损的、经过人为解释的反馈,会剥夺LLM进行精确调试和自我修正所需的最关键信息。一个详细的错误堆栈,对于LLM来说,不是噪音,而是解决问题的路线图(可参考manus博文中关于“保留错误内容”的表述)。
如何实现无损反馈?
环境的观察结果,作为Ground Truth,必须被无损地、不经解释地注入回Agent的下一次决策输入中。
- 实践原则:序列化并完整注入 (Serialize and Inject Fully)
上一步由“环境仲裁”生成的结构化observation对象,应该被完整地序列化(例如,转换为JSON字符串),并作为下一个提示词中“Observation”部分的内容,原封不动地提供给LLM。
示例:构建下一个提示的一部分
...
<thought>
I have written the code to app.py. Now I need to push it to the remote repository.
</thought>
<action>
{
"tool_name": "run_shell",
"parameters": {
"command": "git push"
}
}
</action>
<observation>
{
"command": "git push",
"status": "error",
"exit_code": 128,
"stdout": "",
"stderr": "fatal: Authentication failed for 'https://github.com/user/repo.git/'"
}
</observation>
当LLM在下一个循环中看到这个完整的、无损的observation
时,它能够精确地理解到:“我的git push
行动失败了,状态是错误,原因是‘认证失败’。” 基于这条高质量、未经污染的信息,它的下一步“思考”就极有可能是:“认证失败了。我需要检查我的凭证,或者寻找一个配置了访问令牌的工具。”
这个行动具象化 -> 环境仲裁 -> 无损反馈的循环,构建了一个强大的现实锚点。它强制Agent的每一步思考结果,都必须接受一次物理世界的检验,从而使其能够在复杂、动态的环境中保持方向,并从错误中有效学习。
三、分层的认知治理
任何单一认知模式的内在局限性,通过构建层层递进的“认知检查与平衡”机制,系统性地提升决策质量和复杂任务的成功率。
这一支柱将我们对“认知架构”的讨论,从一个关于“ReAct、规划、反思”的选择题,提升为一个关于如何将它们组合成一个有监督的认知系统的架构题。一个健壮的Agent并非只选择其中一种模式,而是将它们作为不同层级,协同工作,以确保其行为既高效又可靠。
1.战术执行层 (Tactical Execution)
这一层的能提供的核心价值在于反应速度和对现实的即时适应性,然而它的根本缺陷在于短视(Myopia),一个纯粹的ReAct智能体就像一个只看脚下三步路的徒步者,它能完美地避开眼前的石头,却可能在一个巨大的山谷里原地打转,因为它缺乏一张地图。
所以其底层必须拥有一个高效的ReAct循环,作为系统运行的保障,负责处理具体的、原子化的执行任务。
架构模式:封装为“任务执行器”服务 (Task Executor Service)
我们不应将ReAct循环视为整个Agent,而应将其封装成一个可被上层调用的、专用的“执行器”服务。
- 输入: 一个单一、明确的任务描述。例如:"Read the file 'config.yaml' and extract the 'database_url' value."
- 过程: 在内部,它运行我们熟悉的“思考-行动-观察”循环,使用read_file等基础工具来完成这个具体目标。
- 输出: 一个结构化的结果对象,包含任务状态(成功/失败)和产出。例如:{"status": "success", "result": "postgresql://user:pass@host:port/db"}。
示例伪代码:
class TacticalExecutor:
def run(self, single_task: str) -> dict:
# Internal ReAct loop logic here...
# Uses tools to achieve the single_task
# ...
return {"status": "success", "result": ...}
# 上层调用
executor = TacticalExecutor()
result = executor.run("Find all '.py' files in the current directory.")
2.战略规划层 (Strategic Planning)
为了克服战术层的短视。当面对一个复杂目标(如“搭建一个完整的Flask应用”)时,系统必须首先拥有一张“地图”。规划层的作用就是绘制这张地图,为短视但高效的执行层提供方向和目标。
架构模式:规划-执行模型 (Plan-and-Execute Model)
- 规划器Agent (Planner Agent): 接收用户的顶层、模糊的请求。它的唯一任务是将其分解为一个结构化的、有序的行动计划。这个计划本身就是一个外部化的确定性状态(呼应支柱一)。
- 调度器 (Orchestrator): 读取这份计划,并像一个项目经理一样,逐项将其分派给战术执行层。
示例 plan.yaml(由规划器生成):
- task_id: 1
description: "Create a project directory named 'flask_app'."
status: "pending"
- task_id: 2
description: "Inside 'flask_app', create a file named 'app.py'."
status: "pending"
dependencies: [1] # Depends on the completion of task 1
- task_id: 3
description: "Write basic Flask boilerplate code to 'app.py'."
status: "pending"
dependencies: [2]
调度器会读取这个YAML文件,首先将task_id: 1
的任务描述交给TacticalExecutor
,待其成功返回后,再继续执行task_id: 2
。
3.元认知监督层 (Meta-Cognitive Supervision)
为了对抗LLM的内在随机性和不可靠性。一个没有监督的系统,即使有完美的计划和执行力,也可能产出低质量或错误的结果(例如,代码有安全漏洞,总结遗漏了关键事实)。监督层的作用是引入一个内部的质量保证流程。
在流程的关键节点,一个“批判者”作为系统的“良知”,对规划的合理性(过程反思)和产出的质量(产出反思)进行审查。
模式一:过程反思 - 动态重新规划 (Process Reflection - Dynamic Re-planning)
在战略规划层和战术执行层之间插入一个反馈循环。
- 执行器在完成一个步骤后,如果遇到错误或意外的观察结果,调度器不会盲目继续。
- 它会调用一个“批判者/重规划器”Agent。
- 输入给这个Agent的,是原始计划、已完成的步骤和意外的观察结果。
- 它的任务是生成一个修正后的新计划。 示例交互:
- 调度器: “@Critique, 原计划是安装requests库,但执行时发现系统没有pip。请更新计划。”
- 批判者输出 (新 plan.yaml)
- task_id: 2a # New step inserted
description: "Install pip using the system's package manager."
status: "pending"
- task_id: 2b # Original step modified
description: "Install the 'requests' library using pip."
status: "pending"
dependencies: [2a]
模式二:产出反思 - 自我修正 (Output Reflection - Self-Correction)
在一个步骤的产出物(如一段代码)生成后,引入一个强制的审查环节。
- 执行器生成code_v1。
- 调度器将code_v1交给一个专门配置的“代码审查者”Agent。
- 审查者Agent可能会使用linter等工具,并输出一份结构化的审查报告:{"issues": [{"type": "security", "suggestion": "Use 'defusedxml' instead of 'xml.etree.ElementTree' to prevent XML vulnerabilities."}]}。
- 调度器将code_v1和这份审查报告,一并交给执行器,并下达一个新任务:“请根据审查建议,修正这段代码。”
这个由战术、战略和监督构成的三层治理结构,将一个简单的ReAct循环,提升为了一个具备远见、执行力和自我修正能力的、高度可靠的认知系统。
四、显式的协作协议
在多Agent系统中,必须通过明确的、强制性的通信和组织协议来约束个体之间的交互,以此来管理系统级的复杂性,防止“上下文污染”和“状态冲突”。
这一支柱是对“系统拓扑”探讨的本质提炼。它指出,无论是层级式、对等式还是群体式,其成功的关键都不在于拓扑的形状,而在于其背后运行的、不容违背的协作协议。这直接回应了Anthropic在构建多智能体系统时遇到的核心挑战,并将其解决方案——一个高度结构化的系统——提升为了一个普适的工程原则
1.能力范围限定 (Capability Scoping)
在一个多Agent系统中,让所有Agent都拥有所有工具,是一种灾难性的设计。这会导致两个核心问题:
- 安全风险与权限蔓延 : 一个本应只负责信息检索的“研究员”Agent,却拥有了执行任意代码或删除文件的权限,这在任何生产环境中都是不可接受的。
- 认知过载 : 向一个Agent提供大量与其当前任务无关的工具,会严重污染其上下文(即我们之前讨论的“上下文困惑”),降低其选择正确工具的准确性,使其行为变得不可预测。
每个Agent的权限(可访问的工具、可修改的状态)必须由其角色进行严格限定和强制隔离。
架构模式:基于角色的Agent能力控制 (Agent Role-Based Access Control - A-RBAC)
系统的调度器(Orchestrator)必须扮演“权限管理器”的角色。
- 定义角色与工具集: 在系统配置中,明确定义每个角色及其被授权的工具列表。 示例 roles.yaml:
roles:
- name: researcher
description: "Responsible for gathering information from various sources."
allowed_tools:
- web_search
- read_file
- read_url
- name: developer
description: "Responsible for writing and modifying code."
allowed_tools:
- read_file
- write_file
- run_shell_command
- linter
- 动态注入上下文: 当调度器激活一个特定角色的Agent(例如researcher)时,它仅仅将该角色对应的工具定义(web_search, read_file等)注入到LLM的上下文窗口中。对于这个Agent实例而言,run_shell_command等工具是完全不存在的,它从根本上就无法“看到”或“想到”去使用它们
2.结构化通信 (Structured Communication)
让两个Agent通过自然语言进行“对话”,是在系统内部引入了最大的不确定性来源。自然语言是为人机交互设计的,而非机器间的信令。Agent间的通信必须像微服务架构中的API调用一样,是可预测、可解析、无歧义的。
也就是所有跨Agent的通信,必须遵循预定义的、机器可解析的数据模式。
架构模式:Agent通信协议 (Agent Communication Protocol - ACP)
定义一个全局的JSON Schema作为Agent间所有消息的统一格式。 示例 ACP_Message.json:
{
"sender_id": "manager_agent_01",
"recipient_id": "developer_agent_04",
"timestamp": "2025-08-20T10:00:00Z",
"intent": "DELEGATE_TASK", // e.g., DELEGATE_TASK, REQUEST_INFO, REPORT_RESULT
"payload": {
// The payload's structure depends on the intent.
// For DELEGATE_TASK, the payload IS the Task Contract from Pillar One.
"task_id": "DEV-TASK-007",
"objective": "Refactor the authentication module to use JWT.",
"context": { ... },
"deliverables": { ... }
}
}
当一个Agent(如manager_agent
)需要与另一个Agent协作时,它生成的不是一段话,而是这样一个结构化的消息。系统的调度器负责路由这些消息,并确保接收方能够正确解析。同样,developer_agent
完成任务后的回复,也必须是遵循同样协议的、包含status
和result
字段的结构化消息。
3.所有权转移 (Ownership Transfer)
在复杂的任务流中,最大的混乱源于责任不清。如果两个Agent都认为自己应该处理同一个任务,就会产生资源竞争和重复工作。如果没有任何Agent认为自己应该处理,任务就会被无限期地搁置,导致系统死锁。
所以对一个任务或状态的所有权和控制权,必须在Agent之间进行显式地、可追溯地移交。
架构模式:状态驱动的所有权模型 (State-Driven Ownership Model)
系统的核心状态(来自支柱一)必须包含一个字段,明确指明当前拥有任务控制权的Agent。
- 在状态中定义所有者 示例 task_state.json:
{
"task_id": "DEPLOY-WEBAPP-PROD-20250820",
"status": "in_progress",
"current_owner": "developer_agent_04", // The 'developer' is currently working on it
"history": [ ... ]
}
- 将所有权移交作为行动的一部分
当一个Agent完成其阶段性任务时,它的最后一步,是提议下一个所有者。 developer_agent_04的最后一次LLM输出:
{
"thought": "I have finished writing and testing the code. Now it needs to be reviewed by the quality assurance agent.",
"action": {
"tool_name": "handoff_task",
"parameters": {
"next_owner_role": "qa_agent",
"notes": "Code implementation complete, ready for review."
}
}
}
- 调度器执行所有权变更
调度器接收到这个handoff_task行动,它会验证qa_agent角色是否存在且可用,然后原子性地更新中心状态文件: 更新后的task_state.json:
{
"task_id": "...",
"status": "pending_review",
"current_owner": "qa_agent_01", // Ownership has been explicitly transferred
"history": [ ... ]
}
通过这种方式,任务的流转变成了一系列可审计的、确定性的状态转移,系统的行为在任何时刻都是清晰和可预测的。
这四大支柱共同构筑了一个健壮Agent系统的基础。它们将我们的设计焦点,从对LLM智能的无限期望,转移到了对系统协议、状态和流程的严格工程控制之上。
结语
恭喜各位非常有耐心的能看到这里,我们的探索始于一个基本问题:“我们该如何设计AI Agents?”。从深度理解上下文工程,到审视“认知架构”与“系统拓扑”,我们最终发现,这个问题的答案,引导我们走向了一场深刻的范式转变。
正如我在前言中所述,AI Agent并非一个孤立的“智能体”,而是一个复杂的“AI系统”。这场从“Agent”到“System”的视角转变,意味着我们的角色,也必须从“提示工程师”或“上下文工程师”,转变为严谨的“系统架构师”。
我们不再将希望完全寄托于底层大模型那强大而不可预测的智能涌现。相反,我们选择通过工程的确定性来驾驭这份智能。本文最后一章“一个健壮的AI Agent所应该具备的”回答了我们可能会遇到的所有核心挑战:
- 上下文工程的最终目的,将易变的“信息”固化为可靠的“状态”。
- 如何将不同的认知与协作模式,从脆弱的“可选框架”提升为可靠的“工程系统”。
- 无论是单个Agent还是多个Agent,其健壮性的根源,都来自对这些普适协议的共同遵循。
设计AI Agent的征途依然漫长,通用人工智能(AGI)的黎明尚未到来。但在这条必经之路上,未来的突破将不仅属于那些能创造出更强大“智能”的人,更将属于那些能为这份智能,构建出更可靠、更优雅“系统”的我们。
因为,智能给出了起点,唯有协议,方能抵达终点。
鸣谢/参考
LangChain: https://python.langchain.com/docs/introduction/
Context Engineering: https://blog.langchain.com/context-engineering-for-agents/
Manus's blog: https://manus.im/blog/Context-Engineering-for-AI-Agents-Lessons-from-Building-Manus
Drew Breunig's blog: https://www.dbreunig.com/2025/06/22/how-contexts-fail-and-how-to-fix-them.html/
Cognition's blog: https://cognition.ai/blog/dont-build-multi-agents/
Anthropic's blog: https://www.anthropic.com/engineering/multi-agent-research-system/
Deep Agents: https://blog.langchain.com/deep-agents/
Agentic RAG: https://langchain-ai.github.io/langgraph/tutorials/rag/langgraph_agentic_rag/
以上,还要感谢看到过的开源世界的仓库、论文、博客与教程,感谢各位。