
Agentic 系统落地实践指南:六种架构模式与上下文工程
Agentic 系统落地实践指南:六种架构模式与上下文工程
从 ReAct 循环到多智能体协作,系统梳理构建生产级 Agentic 系统的核心组件、上下文工程技巧与六种主流架构模式,并给出可运行的伪代码与选型建议。
对话式 AI 与 Agentic AI 已经是生成式 AI 的两类不同基础用例。把一个智能体从概念验证推进到可靠、可上线的企业工作流,需要在可扩展性、响应速度和成本效益三个维度上同时达标。本指南面向已经了解大模型基本调用方式、准备把智能体投入实际业务的工程师,系统梳理 Agentic 系统的核心组件、上下文工程方法,以及六种经过验证的架构模式。文中给出的代码为伪代码,用于说明编排逻辑,落地时需要按所选框架的 API 调整。
为什么需要智能体
仅仅从数据中获取对话式的洞察,往往不足以完成业务闭环。大语言模型具备规划、推理和行动的能力,而智能体是围绕模型这个「大脑」构建的逻辑结构:它调用工具、访问外部 API、修正自身错误,并与其他智能体协作。
Agentic 系统依赖大量高频决策来推进工作流,例如下一步该做什么、把下一步委派给哪个智能体、使用哪个工具、当前上下文是否足以回应用户。这些决策如果全部交给大模型完成,延迟和成本都会迅速失控。因此,把确定性的决策负载从大模型中剥离出来,交给低成本、经过校准的决策模型处理,让大模型专注于深度推理与综合,是当前架构演进的一个重要方向。
与检索技术从扁平的语义搜索演进为专门的确定性拓扑结构类似,智能体领域也在从朴素的「单智能体循环」走向精心设计的多智能体工作流和受约束的架构。
准备工作
在动手搭建之前,需要先确认以下前置条件。这些条件决定了后续架构模式能否顺利落地。
- 模型能力确认:所选的基础模型必须原生支持工具调用(Tool Calling / Function Calling)。这是智能体与外部世界交互的前提,不支持工具调用的模型只能做纯文本生成。
- 工具层封装:把需要调用的外部能力封装成可执行函数,例如
search_web、query_database、send_email,以及能在沙箱中执行 Python 脚本的代码解释器。每个工具需要明确入参 schema、返回格式和错误类型。 - 控制流机制选型:确定采用刚性控制流(状态机或有向无环图)还是柔性控制流(开放式推理循环)。前者可预测、易调试,后者灵活但难以约束。
- 记忆存储:准备短期工作记忆(当前活跃的提示窗口)和长期情景记忆(历史交互的向量存储)两套机制。
- 可观测性:记录每一步的输入、输出、工具调用参数与耗时,否则线上问题几乎无法定位。
- 人工审核通道:为非读取类操作准备暂停与恢复机制,包括状态序列化存储和审核界面。
关于模型版本、上下文窗口大小、缓存定价等易变信息,请以各模型厂商官网当前公布的信息为准,不要依赖本文或任何二手资料中的具体数字。
核心组件
一个 AI 智能体由四个支柱构成,理解它们是理解后续所有架构模式的基础。
核心大模型:推理引擎
基础模型负责编排整体逻辑。在 Agentic 系统中,模型是否原生支持工具调用至关重要。如果模型只能输出文本而无法结构化地表达「我要调用哪个函数、传什么参数」,编排层就只能靠正则解析文本,脆弱且难以维护。
工具与动作
工具是智能体可以调用的可执行函数,范围从 API 封装到沙箱内的代码执行。工具设计的关键在于返回值的可控性:一个返回整页 HTML 的搜索工具,可能在一次调用后就撑爆上下文窗口。因此工具层应当承担初步的裁剪和格式化职责。
规划与控制流
控制流决定智能体如何决定下一步。刚性控制流用状态机或 DAG 明确限定可能的转移路径,柔性控制流则允许模型自由推理。生产系统通常混合使用:外层用图结构约束大阶段,内层在单个节点内允许 ReAct 循环。
记忆
记忆分为短期和长期。短期工作记忆就是当前活跃的提示窗口,容量有限且成本敏感。长期情景记忆通常用向量库存储历史交互,按语义相关性检索,而不是把全部历史塞进提示。
上下文工程:被忽视的成功标准
在 Agentic 系统中,上下文工程是能否上线的关键判据。传统提示的上下文是静态的,而智能体的上下文高度动态:随着它采取行动,会不断累积观察结果、错误信息和中间思考。如果把每一条观察都追加到提示里,上下文窗口会迅速膨胀,导致延迟上升、成本失控。更麻烦的是,当上下文变成一大块文本时,模型可能丢失中间部分的细节事实,导致下游智能体给出错误或不完整的回答。
以下技术用于控制上下文的增长。
状态投影
只注入当前步骤严格必需的上下文。如果智能体已经从研究阶段进入写作阶段,原始的研究日志就应当从活跃上下文中移除。写作智能体不需要看到抓取的几十个网页,也不需要看到分析阶段写坏的那几版脚本。
记忆剪枝与摘要
用二次模型调用压缩历史步骤,通常使用更小、更便宜的模型,例如把「最近五次搜索结果总结成关键事实」之后再追加到活跃提示中。这样既保留了信息,又控制了 token 消耗。
结构化草稿区
提示模型把中间推理写入指定的 JSON 字段或 XML 标签,例如 <thought>我应该先查一下 API 文档</thought>。这些结构化片段可以在后续轮次中被程序化解析并过滤掉,从而节省空间。
语义记忆检索
把过去的智能体动作当作向量数据库来对待。不加载完整对话历史,而是只检索与当前障碍语义相关的历史动作。这在长周期任务中尤其有效。
提示缓存
部分模型厂商提供提示缓存能力。在复杂 Agentic 系统中,系统提示和工具定义很容易超过数千 token,但它们是静态指令,在系统生命周期内不会变化。把这类静态系统指令放在上下文窗口顶部,厂商就可以把这些预计算的注意力状态缓存进键值缓存。当智能体循环十次时,只需为新增的观察结果付费,能显著降低推理成本。具体支持情况与计费方式请以厂商官网当前信息为准。
人在回路
企业应用不能信任自主智能体在无人监督下执行所有操作。大模型本质上是非确定性的,因此任何非读取类操作都可能产生不期望的后果,例如删除数据库表、授权支付、给客户发邮件。
人在回路是一种控制流机制:智能体暂停执行状态,等待人工审核。以状态图实现为例,调用特定工具(如 send_email_tool)会中断图的执行,状态被序列化到数据库,执行停止。人工在界面上审阅草拟的邮件,必要时修改,然后点击批准。编排器随后带着批准后的状态恢复图的执行。
设计要点是:中断点应当精确到具体工具,而不是整个节点;状态序列化必须完整,否则恢复后智能体会丢失上下文;审核界面需要展示足够的信息让审核者做出判断,而不是只给一个「批准」按钮。
操作步骤:六种架构模式
模式一:标准 ReAct 循环
ReAct(Reason + Act)是 Agentic 工作流的基础构件。它让大模型在「思考」和「行动」之间交替:先推理该做什么,再调用工具并观察结果,然后基于结果重新思考它与目标的关系。
工作方式:给智能体一个系统提示,描述其角色、可用工具和应遵循的规则。用户给出任务后,智能体进入一个循环。每次迭代输出一段「思考」解释其逻辑,随后输出一个「行动」(工具调用)。编排层拦截这个行动,执行工具,把「观察」结果返回给大模型。大模型重新评估局势,直到它认为信息足够,输出最终回答。
上下文工程要点:这里需要管理「智能体草稿区」。随着循环推进,提示线性增长:系统提示 + 用户查询 + 思考一 + 行动一 + 观察一 + 思考二 + 行动二 + 观察二……为防止膨胀,可以实现观察截断。如果工具返回一大段 HTML 文档,编排层应当在把它送回智能体之前截断,或先跑一个摘要脚本。否则一次网页搜索就可能淹没上下文窗口。
def react_agent_loop(user_query, tools, max_iterations=10):
system_prompt = build_system_prompt(tools)
context = [SystemMessage(system_prompt), UserMessage(user_query)]
for _ in range(max_iterations):
response = llm.generate(context)
if response.is_final_answer():
return response.content
tool_name, tool_args = parse_tool_call(response)
context.append(AIMessage(response.content))
try:
raw_observation = execute_tool(tool_name, tool_args)
# 上下文工程:截断过大的观察结果,防止膨胀
if len(raw_observation) > 2000:
observation = summarize_with_cheap_llm(raw_observation)
else:
observation = raw_observation
except Exception as e:
# 把错误反馈回去,让智能体自行修正
observation = f"Tool Error: {str(e)}. 请修正参数后重试。"
context.append(ToolMessage(observation))
return "Error: 智能体在达到最大迭代次数后仍未完成任务。"
优点:灵活性高,能处理路径无法预先硬编码的任务,根据收到的观察动态调整;具备错误恢复能力,工具失败时错误会反馈给大模型,它可以推理出绕行方案,例如换一个 URL、修正工具参数或回退到另一个工具。
缺点:延迟和成本高,单次查询可能需要十次顺序的大模型调用,即使有提示缓存也要耗费时间并消耗大量 token;漂移与幻觉,在高度复杂的任务中,智能体可能忘记原始目标,进入一连串无关的工具调用,或在某个坏掉的工具上无限循环。
适用场景:开放式、研究导向的任务,步骤顺序无法预先确定。适合数据分析、深度网络研究,或在隔离沙箱中调试代码。一般不建议用于确定性强、低延迟、面向用户的聊天应用,因为用户期望快速得到精确回复。
模式二:顺序多智能体工作流
当任务复杂到单个 ReAct 智能体无法可靠处理时,就需要拆解。顺序多智能体工作流像工厂流水线:不让一个超级智能体一次做完所有事,而是把高度专业化的智能体串联起来,把前一个的输出作为后一个的结构化输入。
工作方式:序列中每个智能体都有聚焦的角色、有限的工具集和非常具体的上下文窗口。以研究任务为例:研究智能体用搜索工具收集原始数据并抓取网页,整理出原始资料;分析智能体接收资料,处理数据、执行数值计算(通常通过写 Python 代码),提取关键指标;写作智能体拿到分析指标,格式化成最终可交付的报告。
上下文工程要点:这个架构通过状态投影体现上下文工程。写作智能体不需要看到研究阶段抓取的几十个网页,也不需要看到分析阶段写坏的四版 Python 脚本,它只接收最终的分析简报。这样隔离了上下文窗口,避免了「中间迷失」问题,并显著降低 token 消耗。
实现上通常使用状态图,在节点之间传递严格定义的 State 对象。
from typing import TypedDict, Annotated
class WorkflowState(TypedDict):
user_request: str
raw_research: str
numerical_analysis: str
final_report: str
def researcher_node(state: WorkflowState):
# 上下文投影:只注入原始用户请求
prompt = f"你是资深研究员。围绕以下主题收集全面数据:{state['user_request']}"
state['raw_research'] = researcher_agent.run(prompt)
return state
def analyst_node(state: WorkflowState):
# 上下文投影:只注入原始研究资料,忽略用户请求
prompt = f"从以下研究资料中提取数值趋势和指标:{state['raw_research']}"
state['numerical_analysis'] = data_analyst_agent.run(prompt)
return state
def writer_node(state: WorkflowState):
# 上下文投影:注入分析结果,撰写最终文档
prompt = f"基于以下分析撰写最终报告:{state['numerical_analysis']}"
state['final_report'] = writer_agent.run(prompt)
return state
优点:每个智能体的上下文窗口小且聚焦,推理质量更稳定;各阶段可独立测试和替换;token 消耗可控。
缺点:流程刚性,难以处理需要回溯的任务;如果上游输出质量差,错误会沿链条传播;阶段划分需要人工设计,前期投入较大。
适用场景:流程明确、阶段可清晰划分的内容生产、数据处理和报告生成类任务。
模式三:并行扇出与聚合
当多个子任务之间没有依赖关系时,顺序执行就是浪费。并行扇出模式把任务拆成若干独立子任务同时执行,再用一个聚合节点合并结果。
工作方式:编排层把用户请求分发给多个工作智能体,每个智能体处理一个维度,例如分别检索不同数据源、分别评估不同方案、分别从不同角度审查同一份文档。所有子任务完成后,聚合智能体接收全部结果,去重、消解冲突、综合成统一输出。
上下文工程要点:聚合节点最容易膨胀,因为它要接收所有分支的输出。做法是让每个分支在返回前先自我压缩,输出结构化摘要而非原始文本;聚合节点只接收这些摘要,必要时再按需回查某个分支的详细结果。
优点:墙钟时间显著缩短;单个分支失败不影响其他分支;天然适合多源信息汇总。
缺点:并发调用会带来瞬时成本峰值;聚合阶段的冲突消解逻辑需要仔细设计,否则会产出自相矛盾的结果。
适用场景:多源检索、多方案评估、文档多角度审查。
模式四:路由与分发
并非所有请求都需要完整的智能体流程。路由模式先用一个轻量分类器判断请求类型,再把它分发给对应的处理路径。
工作方式:入口处放一个分类节点,它可以是小模型,也可以是规则引擎。分类结果决定后续走哪条路径:简单问答直接由单次模型调用回答,不需要工具;需要实时信息的走检索增强路径;需要多步操作的进入 ReAct 循环;涉及敏感操作的进入带人工审核的工作流。
上下文工程要点:路由决策本身只应看到用户请求和少量元数据,不应看到完整历史。分类器的提示要短,输出要结构化,例如只返回一个枚举值。
优点:大幅降低平均成本和延迟,因为大部分简单请求不会触发昂贵的多步循环;各路径可独立优化。
缺点:分类错误会导致请求走错路径,需要设计兜底和重试机制;路由逻辑本身需要持续维护。
适用场景:面向用户的通用助手,请求类型分布广泛且长尾明显。
模式五:反思与自我修正
单次生成的结果往往不够好。反思模式在生成之后增加一个评审环节,由评审者指出问题,生成者据此修改,循环若干轮直到达标或达到轮次上限。
工作方式:生成智能体产出初稿;评审智能体依据明确的评价标准检查初稿,输出结构化的缺陷列表;生成智能体接收缺陷列表并修订。评审标准必须具体,例如「是否覆盖了用户提出的三个约束」「是否存在未标注来源的数据」,而不是笼统的「写得好不好」。
上下文工程要点:评审者只需要看到初稿和评价标准,不需要看到生成过程中的全部推理。修订者只需要看到初稿和缺陷列表,不需要看到评审者的完整推理链。这样每一轮的上下文都保持精简。
优点:输出质量明显提升;缺陷列表可记录,便于后续分析系统性弱点。
缺点:成本随轮次线性增长;如果评审标准模糊,可能陷入无意义的反复修改;需要设置硬性轮次上限。
适用场景:对输出质量要求高、且评价标准可以明确表达的任务,例如代码生成、合同草拟、技术文档撰写。
模式六:带约束的图工作流
最复杂也最可控的模式,是把整个流程建模为一张状态图:节点是智能体或工具,边是允许的转移,条件边根据状态决定走向。智能体在节点内部可以自由推理,但节点之间的跳转受图结构约束。
工作方式:定义全局状态对象,包含所有需要在节点间传递的字段。每个节点读取它需要的字段,写入它产出的字段。条件边检查状态,决定下一步走哪个节点。循环通过显式的回边实现,并配有计数器防止无限循环。人工审核作为特殊节点插入,触发时序列化状态并暂停。
上下文工程要点:状态对象本身就是上下文投影的载体。每个节点只从状态中读取自己声明的字段,而不是把整个状态塞进提示。字段的粒度需要设计:太粗会导致上下文膨胀,太细会导致节点间传递成本上升。
优点:流程完全可预测、可调试、可回放;天然支持人工审核和断点恢复;便于做合规审计。
缺点:前期设计成本高;图结构一旦确定,应对未预期情况的能力受限;状态 schema 的演进需要谨慎管理。
适用场景:企业级关键业务流程,对可审计性、可恢复性和合规性有硬性要求的场景。
一个完整示例
下面把顺序多智能体工作流与人在回路结合起来,构成一个可运行的最小示例:接收一个研究请求,依次经过研究、分析、写作三个阶段,最终在发送前暂停等待人工批准。
from typing import TypedDict
class PipelineState(TypedDict):
user_request: str
raw_research: str
numerical_analysis: str
draft_report: str
approved: bool
def build_pipeline():
graph = StateGraph(PipelineState)
graph.add_node("researcher", researcher_node)
graph.add_node("analyst", analyst_node)
graph.add_node("writer", writer_node)
graph.add_node("human_review", human_review_node)
graph.add_node("sender", sender_node)
graph.set_entry_point("researcher")
graph.add_edge("researcher", "analyst")
graph.add_edge("analyst", "writer")
graph.add_edge("writer", "human_review")
# 条件边:只有批准后才发送,否则回到写作节点
graph.add_conditional_edges(
"human_review",
lambda state: "sender" if state["approved"] else "writer",
{"sender": "sender", "writer": "writer"}
)
graph.add_edge("sender", END)
return graph.compile(interrupt_before=["human_review"])
def human_review_node(state: PipelineState):
# 实际实现中,这里会序列化状态并等待外部审核结果
# 审核界面展示 state['draft_report'],人工修改后写回
return state
运行流程如下:
- 调用
pipeline.invoke({"user_request": "..."}),图从研究节点开始执行。 - 研究节点执行内部的 ReAct 循环,调用搜索工具,产出原始资料并写入
raw_research。 - 分析节点只读取
raw_research,执行数值计算,把结果写入numerical_analysis。 - 写作节点只读取
numerical_analysis,产出草稿写入draft_report。 - 执行到
human_review之前中断,状态被序列化保存。 - 人工在界面上审阅草稿,修改后置
approved为真并恢复执行。 - 条件边判断
approved,为真则进入发送节点,为假则回到写作节点重新生成。
这个示例体现了本指南的几条核心原则:每个节点只看到自己需要的上下文;非读取类操作前有明确的中断点;状态对象承载了全部跨节点信息,使流程可回放、可审计。
注意事项
- 循环必须有上限:无论是 ReAct 循环还是图上的回边,都要设置最大迭代次数或最大轮次,否则一个坏掉的工具会让系统无限消耗资源。
- 工具返回值必须可控:在工具层做截断或摘要,不要指望模型自己忽略无关内容。一次返回整页 HTML 的调用就可能挤占掉后续所有步骤的空间。
- 错误要作为观察反馈回去:把异常信息格式化成模型能理解的文本,让它有机会修正参数或换用其他工具,而不是直接让整个流程失败。
- 非读取操作一律走人工审核:删除数据、发起支付、对外发送消息这类操作,在无人监督下执行的风险不可接受。
- 上下文窗口的中间部分容易被忽略:当上下文很长时,模型可能丢失中间位置的细节。这正是状态投影和摘要压缩要解决的问题,不要靠加大窗口来回避。
- 提示缓存需要特定的上下文组织方式:静态的系统提示和工具定义要放在顶部,动态内容追加在后面,缓存才可能命中。具体支持范围和计费方式以模型厂商官网当前信息为准。
- 成本与延迟随轮次线性增长:多步循环、反思轮次、并行分支都会放大开销。上线前应当基于真实流量分布估算平均成本,而不是只看单次调用的理想情况。
- 模型版本与能力会变化:工具调用支持情况、上下文窗口大小、缓存机制、定价都可能在版本更新中调整,落地前请查阅厂商官网的当前文档。
选择哪种模式,取决于任务的确定性程度、对延迟和成本的容忍度,以及对可审计性的要求。多数生产系统不会只用一种模式,而是以带约束的图工作流为骨架,在节点内部按需嵌入 ReAct 循环、并行扇出或反思环节。