Agent 实现方式理论篇:从单轮调用到多 Agent 协作
0. 如何理解 Agent 的"实现方式"
0.1 本文的分类标准
本文使用"决策与行动的控制拓扑"作为一级分类标准。每一种架构都固定回答以下四个问题:
| 判断问题 | 所关注的系统性质 |
|---|---|
| 谁决定下一步? | 用户、开发者、单个 Agent、Planner,还是多个 Agent |
| 系统可以执行什么? | 只能生成文本,还是能够检索、调用 API、执行代码和改变外部状态 |
| 执行结果如何反馈? | 不反馈、进入下一固定节点、更新显式状态,或成为 Agent 的 Observation |
| 任务如何结束? | 单次调用自然结束、抵达终点节点、模型选择 Finish,或管理者汇总终止 |
这种分类描述的是系统整体如何运行。它不等价于论文算法分类,也不意味着不同模式完全互斥。一个 Plan-and-Execute 系统的 Executor 可以是 ReAct Agent;一个多 Agent 系统的 Manager 可以先规划,再调用多个采用不同工作流的专业 Agent。
0.2 为什么不直接讲 Prompt、Context、Loop 或 Harness
Prompt Engineering 决定模型怎样理解当前指令;Context Engineering 决定模型在某次调用中看到哪些信息;Memory 决定哪些状态可跨步骤或跨会话保存;Harness 负责工具执行、重试、权限、日志和停止条件。这些概念属于横向工程维度,而不是互斥的系统类型,咱们先讲理论再谈工程。
LangChain 当前官方文档也区分 Workflow 与 Agent:Workflow 具有预先确定的代码路径;Agent 则动态决定自己的过程和工具使用。1 这个区别构成本文后续分类的基础。
0.3 代码环境
本文示例采用当前 LangChain v1 风格 API。LangChain v1 将 create_agent 作为标准 Agent 构建入口,而 LangGraph 以 StateGraph、State、Node 与 Edge 表达工作流和 Agent 运行图。2 3
bash
pip install -U \
langchain==1.3.15 \
langgraph==1.2.11 \
langchain-openai==1.5.1
export OPENAI_API_KEY="你的 API Key"
export MODEL_NAME="openai:gpt-4.1-mini"
所有示例共享下面的模型初始化代码。MODEL_NAME 只是演示值,可以替换成读者已经配置的其他 LangChain 模型提供商。
python
import os
from langchain.chat_models import init_chat_model
MODEL_NAME = os.getenv("MODEL_NAME", "openai:gpt-4.1-mini")
model = init_chat_model(MODEL_NAME, temperature=0)
1. 单轮交互:Agent 系统的能力基线
1.1 基本结构
单轮交互是最简单的大模型应用形态:用户提供输入,模型完成一次生成,系统将结果返回。
用户输入 → 模型生成 → 最终输出
它可以完成问答、摘要、分类、提取、翻译、改写和结构化输出。LangChain 官方模型接口允许模型独立于 Agent 使用;invoke() 是最直接的单次调用方式。4
单轮交互通常不属于严格意义上的 Agent,因为系统没有持续的任务状态、外部行动、环境反馈,也不存在"根据反馈决定下一步"的运行时控制。
1.2 CoT 在单轮交互中的位置
Chain-of-Thought(CoT)论文将其定义为模型生成的一系列中间推理步骤。论文显示,提供 CoT 示例能够改善算术、常识和符号推理任务的表现。5
CoT 改变的是模型如何形成答案 ,而不是系统如何组织行动。一次模型调用即使产生了很长的中间推理,仍可能属于单轮交互:
问题 → 中间推理步骤 → 最终答案
因此,CoT 归属在单轮能力或横向推理机制中,而不与 Workflow、ReAct、Plan-and-Execute 并列。现代推理模型也可能将推理过程隐藏在模型内部;生产系统不应把模型公开输出完整思维链作为可靠性的前提。
1.3 基本实现
下面是最小的 LangChain 单轮调用。没有工具、图或 Agent harness。
python
from langchain.chat_models import init_chat_model
model = init_chat_model("openai:gpt-4.1-mini", temperature=0)
response = model.invoke(
[
{
"role": "user",
"content": "用三句话解释为什么入口路由通常仍属于工作流。",
}
]
)
print(response.content)
代码中的控制流只有一次 invoke()。无论模型内部是否进行了多步推理,应用层都没有第二次决策或外部动作。
1.4 能力边界
| 能力 | 单轮交互是否具备 |
|---|---|
| 生成、分类、提取 | 是 |
| 结构化输出 | 是 |
| 持续任务状态 | 默认没有 |
| 外部工具行动 | 默认没有 |
| 根据 Observation 改变路径 | 没有 |
| 自主决定何时结束 | 没有;模型调用结束即结束 |
单轮交互不是"不够先进"的架构。对于目标清晰、输入完整、一次生成足以完成且错误成本可控的任务,它往往是成本最低、最容易测试的实现。
2. 工作流:由系统预先限定任务路径
2.1 工作流的共同特征与论文背景
工作流将复杂任务拆成一组节点,并由开发者定义节点之间的连接。模型可以参与节点内部的生成、分类或判断,但系统整体仍在开发者限定的路径中运行。
PromptChainer 论文在 2022 年已经系统讨论了 LLM Chain:一个步骤的输出进入下一个步骤,多次模型调用可以完成单次调用难以处理的复杂任务。该工作强调中间结果转换、可视化编排和多粒度调试的重要性。6
LangGraph 当前官方资料将 Prompt Chaining、Routing、Parallelization、Orchestrator-Worker 和 Evaluator-Optimizer 都放在 Workflow 范畴,并将其与动态决定过程和工具的 Agent 区分开来。1
工作流有三种实现方式:
| 子模块 | 路径如何决定 | 选择发生的时间 |
|---|---|---|
| 静态编排 | 开发者固定顺序 | 开发时 |
| 选择式编排 | 从预设链路中选择 | 入口或指定路由节点 |
| 状态式编排 | 根据最新状态选择预设边 | 每个关键节点执行后 |
2.2 静态编排
2.2.1 基本结构
静态编排按照固定顺序执行节点:
输入 → 节点 A → 节点 B → 节点 C → 输出
例如,文档处理可以固定为"清洗文本 → 摘要 → 格式化"。每个节点可以调用 LLM 或普通函数,但节点顺序不会因中间结果而改变。
2.2.2 基本实现
下面使用 LangGraph 实现一个两节点静态工作流。
python
from typing import TypedDict
from langchain.chat_models import init_chat_model
from langgraph.graph import StateGraph, START, END
model = init_chat_model("openai:gpt-4.1-mini", temperature=0)
class State(TypedDict):
raw_text: str
cleaned_text: str
summary: str
def clean_text(state: State) -> dict:
cleaned = " ".join(state["raw_text"].split())
return {"cleaned_text": cleaned}
def summarize_text(state: State) -> dict:
response = model.invoke(
[
{
"role": "user",
"content": f"请用一句话总结下面内容:\n{state['cleaned_text']}",
}
]
)
return {"summary": response.content}
builder = StateGraph(State)
builder.add_node("clean", clean_text)
builder.add_node("summarize", summarize_text)
builder.add_edge(START, "clean")
builder.add_edge("clean", "summarize")
builder.add_edge("summarize", END)
graph = builder.compile()
result = graph.invoke(
{
"raw_text": "LangGraph 用状态、节点和边 编排任务。",
"cleaned_text": "",
"summary": "",
}
)
print(result["summary"])
LangGraph 中,State 是共享数据结构;Node 执行计算并返回状态更新;Edge 决定下一节点。3 本例全部使用固定边,因此属于静态编排。
2.2.3 特征
静态编排的主要优势是路径可预测、容易测试、成本可估计;限制是系统不能根据中间结果临时增加步骤或切换任务策略。
2.3 选择式编排
2.3.1 基本结构
选择式编排通常由 Router 先判断输入类型,再从开发者预设的链路中选择一条:
用户输入 → Router
├→ 产品链路
├→ 技术链路
└→ 通用链路
Router 可以由规则、传统分类模型、Embedding 相似度或 LLM 实现。它之所以通常仍属于工作流,是因为模型只能在预先定义的有限链路中选择,并不自行创造新的动作序列。
LangChain 当前多 Agent 文档也明确区分 Router 与 Supervisor:Router 通常进行一次分类并分发;Supervisor 是保持上下文并能跨多轮动态调用子 Agent 的完整 Agent。7
2.3.2 基本实现
下面使用结构化输出完成分类,再通过条件边进入不同节点。
python
from typing import Literal, TypedDict
from pydantic import BaseModel, Field
from langchain.chat_models import init_chat_model
from langgraph.graph import StateGraph, START, END
model = init_chat_model("openai:gpt-4.1-mini", temperature=0)
class RouteDecision(BaseModel):
route: Literal["product", "technical", "other"] = Field(
description="最适合处理当前请求的链路"
)
class State(TypedDict):
question: str
route: str
answer: str
router_model = model.with_structured_output(RouteDecision)
def classify(state: State) -> dict:
decision = router_model.invoke(
[
{
"role": "user",
"content": (
"把问题路由到 product、technical 或 other。"
f"\n问题:{state['question']}"
),
}
]
)
return {"route": decision.route}
def select_route(state: State) -> str:
return state["route"]
def product_chain(state: State) -> dict:
return {"answer": f"产品链路:{state['question']}"}
def technical_chain(state: State) -> dict:
return {"answer": f"技术链路:{state['question']}"}
def other_chain(state: State) -> dict:
return {"answer": f"通用链路:{state['question']}"}
builder = StateGraph(State)
builder.add_node("classify", classify)
builder.add_node("product", product_chain)
builder.add_node("technical", technical_chain)
builder.add_node("other", other_chain)
builder.add_edge(START, "classify")
builder.add_conditional_edges(
"classify",
select_route,
{
"product": "product",
"technical": "technical",
"other": "other",
},
)
builder.add_edge("product", END)
builder.add_edge("technical", END)
builder.add_edge("other", END)
graph = builder.compile()
result = graph.invoke(
{
"question": "LangGraph 的条件边怎么写?",
"route": "",
"answer": "",
}
)
print(result["answer"])
Router 虽然由 LLM 驱动,但其动作空间只有三个预设节点。系统不存在工具 Observation 反馈后的开放式再决策,因此仍是选择式工作流。
2.4 状态式编排
2.4.1 基本结构
状态式编排维护显式 State。节点读取状态并产生更新;条件边根据更新后的状态决定下一节点。它可以实现条件分支、循环、重试、暂停和恢复:
节点执行 → 更新 State → 条件判断 → 下一节点
↑ ↓
└── 修改与重试 ┘
LangGraph 的 Graph API 正是围绕 State、Nodes 与 Edges 构建;条件边可以根据当前状态将执行发送到一个或多个后续节点。3
2.4.2 基本实现
下面实现"生成草稿 → 审核 → 不合格则修改"的状态循环,并设置最大三次尝试。
python
from typing import TypedDict
from pydantic import BaseModel
from langchain.chat_models import init_chat_model
from langgraph.graph import StateGraph, START, END
model = init_chat_model("openai:gpt-4.1-mini", temperature=0)
class ReviewDecision(BaseModel):
approved: bool
feedback: str
class State(TypedDict):
topic: str
draft: str
feedback: str
approved: bool
attempts: int
review_model = model.with_structured_output(ReviewDecision)
def generate(state: State) -> dict:
prompt = f"为主题"{state['topic']}"写一段不超过 80 字的说明。"
if state["feedback"]:
prompt += f"\n请根据反馈修改:{state['feedback']}"
response = model.invoke([{"role": "user", "content": prompt}])
return {
"draft": response.content,
"attempts": state["attempts"] + 1,
}
def review(state: State) -> dict:
decision = review_model.invoke(
[
{
"role": "user",
"content": (
"检查草稿是否准确、清楚且不超过 80 字。"
"不合格时给出具体修改意见。"
f"\n草稿:{state['draft']}"
),
}
]
)
return {
"approved": decision.approved,
"feedback": decision.feedback,
}
def route_after_review(state: State) -> str:
if state["approved"] or state["attempts"] >= 3:
return "finish"
return "revise"
builder = StateGraph(State)
builder.add_node("generate", generate)
builder.add_node("review", review)
builder.add_edge(START, "generate")
builder.add_edge("generate", "review")
builder.add_conditional_edges(
"review",
route_after_review,
{"revise": "generate", "finish": END},
)
graph = builder.compile()
result = graph.invoke(
{
"topic": "状态式工作流与 ReAct 的区别",
"draft": "",
"feedback": "",
"approved": False,
"attempts": 0,
}
)
print(result["draft"])
该系统虽然存在循环和 LLM 审核,但允许的节点、边、重试上限和结束条件仍由开发者写定,所以更准确地说是状态式工作流或 Agentic Workflow,而不是开放式 ReAct。
2.5 工作流与 Agent 的边界
| 判断维度 | 工作流 | Agent |
|---|---|---|
| 路径 | 预先限定 | 运行时动态形成 |
| 动作空间 | 节点和边的有限集合 | 工具集合受限,但工具顺序可动态变化 |
| 中间反馈 | 更新状态并按规则走图 | 作为 Observation 进入模型决策 |
| 可测试性 | 较强 | 较难穷举 |
| 自治程度 | 低到中 | 中到高 |
一个状态图中可以嵌入 Agent 节点;一个 Agent 外部也可以由工作流控制。二者不是互斥技术栈,而是不同层次的控制结构。
3. ReAct:模型根据环境反馈决定下一步
3.1 论文引入
ReAct 论文于 2022 年提出,其核心贡献是让模型交错生成 reasoning traces 与 task-specific actions。推理帮助模型维护和更新行动计划;行动则让模型从知识库或环境获得新信息,再将这些信息反馈给后续决策。8
Thought → Action → Observation → Thought → Action → ... → Finish
ReAct 相对单轮 CoT 的关键变化,不是"推理步骤更多",而是模型的行动会改变或查询外部环境,环境结果又会改变下一次模型决策。
现代生产 Agent 通常采用模型原生 tool calling,而不要求模型公开输出 Thought: 文本。只要控制结构仍是"模型提出工具调用 → 运行时执行 → 工具结果返回模型 → 模型继续或结束",它就是 ReAct-style 工具 Agent。
3.2 与工作流的区别
工作流由开发者决定可行路径;ReAct 由模型根据 Observation 决定下一动作。开发者仍控制可用工具、权限和最大执行范围,但不必提前画出完整工具顺序。
工作流:输入 → 预设节点 A → 条件边 → 预设节点 B
ReAct:输入 → 模型选择工具 X → Observation
↓ ↑
模型再选择工具 Y 或结束
3.3 基本实现
LangChain v1 的 create_agent 提供标准工具 Agent harness。官方文档将 Agent 描述为模型在工具循环中持续调用工具直到任务完成。9
python
from langchain.agents import create_agent
from langchain.chat_models import init_chat_model
from langchain.tools import tool
model = init_chat_model("openai:gpt-4.1-mini", temperature=0)
@tool
def lookup_weather(city: str) -> str:
"""查询城市天气。"""
sample = {
"北京": "晴,18°C,空气质量良好",
"上海": "小雨,21°C,风力 3 级",
}
return sample.get(city, f"没有 {city} 的示例天气数据")
agent = create_agent(
model=model,
tools=[lookup_weather],
system_prompt="你是天气助手。需要天气信息时必须调用工具,再给出建议。",
)
result = agent.invoke(
{
"messages": [
{"role": "user", "content": "北京今天适合户外跑步吗?"}
]
}
)
print(result["messages"][-1].content)
该示例没有手工编写 while。create_agent 底层运行模型---工具循环:模型决定是否调用 lookup_weather,运行时执行工具并将工具结果返回模型,模型再生成最终回答或继续调用其他工具。9
3.4 实现要点
| 组成部分 | 作用 |
|---|---|
| Model | 解释用户目标并选择工具或结束 |
| Tool schema | 向模型说明动作名称、参数和用途 |
| Tool runtime | 真正执行函数、API、数据库或浏览器操作 |
| Observation | 工具结果,以 ToolMessage 等形式返回模型 |
| State / messages | 保存当前任务轨迹 |
| Stop policy | 限制迭代、时间、成本和高风险动作 |
ReAct 的优势是能处理工具顺序无法提前枚举的开放任务。它的风险包括重复调用、错误累积、成本波动和不可复现,因此生产系统通常会在外层增加预算、权限、超时、验证和 HITL。
4. Plan-and-Execute:将规划与执行分离
4.1 论文与架构背景
Plan-and-Solve Prompting 将复杂问题分成两个阶段:先制定计划并拆分子任务,再按计划完成子任务。原论文主要针对推理提示,不是完整工具 Agent,但它清晰表达了"先全局规划、后局部执行"的思想。10
在 Agent 架构中,Plan-and-Execute 通常包含 Planner、Executor 和可选 Replanner:
目标 → Planner → 计划 → Executor → 执行记录
↑ ↓
└── Replanner ┘
↓
最终答案
LangChain 的 Planning Agents 说明将 Planner 与 Executor 视为基本组成,并指出这种结构相对逐步 ReAct 可减少大型模型在每次工具调用后的重复参与,也更有利于使用较小执行模型或并行执行。11
ReWOO 进一步将 reasoning 与 Observation 解耦:Planner 预先生成带变量依赖的计划,Worker 执行任务,Solver 汇总结果,从而减少逐步交错观察带来的重复 prompt 成本。12
4.2 与 ReAct 的区别
| 对比项 | ReAct | Plan-and-Execute |
|---|---|---|
| 决策粒度 | 每一步行动前重新决定 | 先制定整体或阶段计划 |
| 全局视野 | 可能只关注下一行动 | Planner 显式考虑整体任务 |
| 工具执行 | 通常顺序发生 | 可按依赖串行或并行 |
| 遇到变化 | 每步自然适应 | 需要 Replanner 才能调整 |
| 成本 | 大模型可能被频繁调用 | 可将执行交给较小模型或普通工具 |
4.3 基本实现
下面使用 LangGraph 实现一个最小的 Plan → Execute → Replan/Finish 图。为保持示例简短,Executor 直接调用模型完成文本子任务;生产系统可以将其替换为工具、工作流或 ReAct Agent。
python
from typing import TypedDict
from pydantic import BaseModel, Field
from langchain.chat_models import init_chat_model
from langgraph.graph import StateGraph, START, END
model = init_chat_model("openai:gpt-4.1-mini", temperature=0)
class Plan(BaseModel):
steps: list[str] = Field(description="最多四个有序、可执行步骤")
class ReplanDecision(BaseModel):
finished: bool
final_answer: str = ""
remaining_steps: list[str] = Field(default_factory=list)
class State(TypedDict):
objective: str
plan: list[str]
completed: list[str]
final_answer: str
iterations: int
planner = model.with_structured_output(Plan)
replanner = model.with_structured_output(ReplanDecision)
def make_plan(state: State) -> dict:
result = planner.invoke(
[
{
"role": "user",
"content": (
"为目标制定最多四个可执行步骤。"
f"\n目标:{state['objective']}"
),
}
]
)
return {"plan": result.steps}
def execute_step(state: State) -> dict:
step = state["plan"][0]
history = "\n".join(state["completed"]) or "暂无"
response = model.invoke(
[
{
"role": "user",
"content": (
f"总体目标:{state['objective']}\n"
f"已完成:{history}\n"
f"现在只执行:{step}"
),
}
]
)
record = f"步骤:{step}\n结果:{response.content}"
return {
"plan": state["plan"][1:],
"completed": [*state["completed"], record],
"iterations": state["iterations"] + 1,
}
def replan_or_finish(state: State) -> dict:
completed = "\n\n".join(state["completed"])
# 到达安全上限或计划执行完毕时,直接汇总。
if state["iterations"] >= 4 or not state["plan"]:
response = model.invoke(
[
{
"role": "user",
"content": (
f"根据执行记录回答目标。\n"
f"目标:{state['objective']}\n{completed}"
),
}
]
)
return {"final_answer": response.content}
decision = replanner.invoke(
[
{
"role": "user",
"content": (
f"目标:{state['objective']}\n"
f"已完成:{completed}\n"
f"原计划剩余:{state['plan']}\n"
"判断是否可以结束;否则修订剩余步骤。"
),
}
]
)
if decision.finished:
return {"final_answer": decision.final_answer}
return {"plan": decision.remaining_steps or state["plan"]}
def route_after_replan(state: State) -> str:
return "finish" if state["final_answer"] else "continue"
builder = StateGraph(State)
builder.add_node("plan", make_plan)
builder.add_node("execute", execute_step)
builder.add_node("replan", replan_or_finish)
builder.add_edge(START, "plan")
builder.add_edge("plan", "execute")
builder.add_edge("execute", "replan")
builder.add_conditional_edges(
"replan",
route_after_replan,
{"continue": "execute", "finish": END},
)
graph = builder.compile()
result = graph.invoke(
{
"objective": "比较固定工作流与 ReAct,并给出各自适用场景。",
"plan": [],
"completed": [],
"final_answer": "",
"iterations": 0,
}
)
print(result["final_answer"])
这个例子展示的是分层控制:Planner 决定整体任务结构;Executor 每次只处理一个子任务;Replanner 根据执行记录决定继续、修改计划或结束。若任务需要并行,Planner 可以输出依赖图,再使用 LangGraph Send 或并行边调度独立任务。1 3
4.4 ReWOO 与 DAG 变体
ReWOO 允许计划步骤引用先前结果,例如 #E1,从而在不重新调用 Planner 的情况下执行依赖任务。12 LLMCompiler 则进一步由 Planner 流式生成任务 DAG,调度器在依赖满足后立即执行任务,Joiner 决定汇总或重新规划。11
这些变体仍属于 Plan-and-Execute 家族,因为共同点是:将高层规划与低层工具执行分离,并以显式任务结构协调执行。
5. 多 Agent:多个决策主体协作完成任务
5.1 论文与架构背景
多 Agent 不是简单地多调用几次模型,而是让多个拥有不同角色、上下文、工具或权限的决策主体通过消息、委派或共享状态合作。
AutoGen 论文提出通过多个可对话 Agent 构建 LLM 应用。这些 Agent 可以组合 LLM、人类输入和工具,开发者也可以定义它们之间的交互模式。13
LangChain 当前多 Agent 文档总结了 Subagents、Handoffs、Skills 和 Router 等模式。对于集中式控制,Supervisor/Subagents 是最直接的实现:主 Agent 保持会话上下文,并将专业子 Agent 包装成高层工具进行动态调用。7 14
5.2 多 Agent 与 Plan-and-Execute 的关系
Plan-and-Execute 按职责阶段 分离规划和执行;多 Agent 按决策主体分离角色。二者可以组合,但不等价:
| 系统 | 是否一定有多个 Agent | 是否一定有显式计划 |
|---|---|---|
| 单模型 Plan-and-Execute | 否 | 是 |
| Manager--Worker 多 Agent | 是 | 通常有 |
| Peer-to-peer 多 Agent | 是 | 不一定 |
| Debate / Review 多 Agent | 是 | 不一定 |
5.3 基本实现
下面使用当前 LangChain 推荐的 Subagents-as-tools 方式。研究 Agent 有检索工具;写作 Agent只负责组织文字;Supervisor 先调用研究 Agent,再把结果交给写作 Agent。
python
from langchain.agents import create_agent
from langchain.chat_models import init_chat_model
from langchain.tools import tool
model = init_chat_model("openai:gpt-4.1-mini", temperature=0)
def final_text(result: dict) -> str:
return str(result["messages"][-1].content)
@tool
def search_architecture_notes(topic: str) -> str:
"""查询 Agent 架构的示例知识库。"""
notes = {
"workflow": "工作流具有开发者预先限定的代码路径。",
"react": "ReAct 交错执行模型决策、工具行动和环境观察。",
"plan": "Plan-and-Execute 将总体规划与子任务执行分离。",
}
matched = [text for key, text in notes.items() if key in topic.lower()]
return " ".join(matched) or "没有匹配条目。"
research_agent = create_agent(
model=model,
tools=[search_architecture_notes],
system_prompt="你是研究员。先查找事实,再返回清晰的研究笔记。",
)
writer_agent = create_agent(
model=model,
tools=[],
system_prompt="你是技术作者。只根据提供的研究笔记写准确说明。",
)
@tool
def ask_research_agent(question: str) -> str:
"""调用研究子 Agent 收集事实。"""
result = research_agent.invoke(
{"messages": [{"role": "user", "content": question}]}
)
return final_text(result)
@tool
def ask_writer_agent(requirement: str, research_notes: str) -> str:
"""调用写作子 Agent,根据研究笔记完成写作。"""
result = writer_agent.invoke(
{
"messages": [
{
"role": "user",
"content": (
f"写作要求:{requirement}\n"
f"研究笔记:{research_notes}"
),
}
]
}
)
return final_text(result)
supervisor = create_agent(
model=model,
tools=[ask_research_agent, ask_writer_agent],
system_prompt=(
"你是总协调者。必须先调用研究 Agent;收到研究结果后,"
"再把完整研究结果交给写作 Agent,最后返回成稿。"
),
)
result = supervisor.invoke(
{
"messages": [
{
"role": "user",
"content": (
"写一段 120 字以内的文字,比较 workflow、"
"ReAct 和 Plan-and-Execute。"
),
}
]
}
)
print(final_text(result))
该实现有三个独立 Agent harness。Supervisor 只能看到两个高层工具,不直接看到研究 Agent 的底层检索工具。这种分层可以隔离上下文与权限,也方便不同团队独立维护专业 Agent。14
5.4 常见组织模式
| 多 Agent 模式 | 控制结构 | 典型用途 |
|---|---|---|
| Supervisor--Subagents | 中央管理者动态调用专业 Agent | 多领域个人助理、企业能力中心 |
| Manager--Worker | Manager 分解任务,Worker 并行执行 | 研究、批量文档、代码库修改 |
| Handoff | 当前 Agent 将会话控制权转交给另一个 Agent | 客服升级、跨专业连续对话 |
| Debate / Review | 多个 Agent 提案、批评和评审 | 方案比选、独立审查、代码评审 |
| Peer-to-peer | Agent 通过消息协商,没有固定中央控制 | 开放式模拟与协作实验 |
多 Agent 的代价是更多模型调用、上下文传递损耗、调试困难和责任边界复杂。只有当任务确实存在角色分工、独立权限、上下文隔离、并行处理或相互审查需求时,多 Agent 才具有结构性价值。
6. 贯穿所有实现方式的横向维度
一级架构回答"系统整体如何控制任务";横向维度回答"同一种架构怎样被实现得可靠、可控和可维护"。
6.1 Human-in-the-loop
HITL 描述人何时拥有授权、编辑、否决或接管权。它不是与 ReAct 或 Plan-and-Execute 互斥的 Agent 类型,而可以叠加于任何架构。
| HITL 方式 | 介入位置 | 典型权力 |
|---|---|---|
| 咨询式协作 | 模型输出后 | 修改、采纳或拒绝建议 |
| 动作前审批 | 高风险工具执行前 | Approve、Edit、Reject |
| 异常升级 | 低置信度、错误或策略冲突时 | 接管并决定恢复路径 |
| 事后审计 | 任务完成后 | 抽检、评分和建立改进数据 |
LangChain 当前提供 HumanInTheLoopMiddleware,它可以在工具调用执行前暂停 Agent;LangGraph 通过 checkpointer 保存状态,并使用 Command(resume=...) 恢复。15 16
下面给出一个发送邮件前人工审批的最小实现:
python
from langchain.agents import create_agent
from langchain.agents.middleware import HumanInTheLoopMiddleware
from langchain.chat_models import init_chat_model
from langchain.tools import tool
from langgraph.checkpoint.memory import InMemorySaver
from langgraph.types import Command
model = init_chat_model("openai:gpt-4.1-mini", temperature=0)
@tool
def send_email(to: str, subject: str, body: str) -> str:
"""发送邮件;演示中只返回确认文本。"""
return f"已向 {to} 发送邮件:{subject}"
agent = create_agent(
model=model,
tools=[send_email],
middleware=[
HumanInTheLoopMiddleware(
interrupt_on={
"send_email": {
"allowed_decisions": ["approve", "edit", "reject"]
}
}
)
],
checkpointer=InMemorySaver(),
)
config = {"configurable": {"thread_id": "email-review-demo"}}
pending = agent.invoke(
{
"messages": [
{
"role": "user",
"content": (
"给 team@example.com 发邮件,主题是周会,"
"正文是:周五下午三点开会。"
),
}
]
},
config=config,
)
# 实际应用应把 pending["__interrupt__"] 展示给审核人。
print(pending["__interrupt__"])
# 审核人批准后,必须使用相同的 thread_id 恢复。
resumed = agent.invoke(
Command(resume={"decisions": [{"type": "approve"}]}),
config=config,
)
print(resumed["messages"][-1].content)
生产环境应使用持久化 checkpointer,而不是内存实现;中断前后的外部副作用还应满足幂等要求。16
6.2 推理、搜索与反思
CoT、Tree of Thoughts(ToT)和 Reflexion 改变的是模型生成、候选搜索或失败学习方式,不是一级控制架构。
ToT 将线性 CoT 推广为可以生成、评估、前瞻和回溯的候选思路树。17 Reflexion 则让 Agent 将反馈转写为语言化反思,并保存在 episodic memory 中以改进后续尝试,而无需更新模型权重。18
这些机制可以嵌入任何一级架构:工作流可以加入 evaluator-optimizer 节点;ReAct 可以在失败后反思;Planner 可以使用树搜索比较多个计划;多 Agent 可以让独立 Reviewer 进行评价。
6.3 RAG、工具与动作空间
RAG、搜索、数据库、代码执行、浏览器和业务 API 描述的是系统能够访问哪些信息和产生哪些外部影响。它们不是独立控制架构。
同一个检索工具可以出现在不同模式中:工作流固定调用它;Router 选择是否进入检索链;ReAct 动态决定何时检索;Plan-and-Execute 将检索分配为一个子任务;多 Agent 则让研究 Agent 独占检索权限。
6.4 状态、记忆与 Context
State 是当前任务的显式快照;Memory 是跨步骤或跨会话保留的信息;Context 是某次模型调用实际看到的信息。三者相关,但不完全相同。
| 概念 | 回答的问题 |
|---|---|
| State | 系统当前处于什么阶段,已经产生了什么结果? |
| Memory | 哪些信息应在未来继续保留? |
| Context | 当前这次模型调用应该看到哪些信息? |
工作流、ReAct、Plan-and-Execute 和多 Agent 都需要管理这些信息,只是范围和隔离策略不同。
6.5 Loop、Harness 与运行治理
Loop 是控制流中的重复结构;Harness 是承载模型、工具、状态、重试、预算、权限和日志的运行外壳。ReAct 必然包含模型---工具反馈循环,但"有循环"并不自动意味着系统是 Agent:状态工作流和普通重试也可以包含循环。
生产系统通常还需要:最大迭代次数、超时、成本预算、工具参数校验、权限控制、敏感动作审批、检查点、幂等性、日志、追踪和离线评估。这些机制决定系统是否可靠上线,但不改变其一级架构归属。
结语:Agent 架构的本质是控制权分配
本文将单轮交互、工作流、ReAct、Plan-and-Execute 和多 Agent 放在同一系统级维度上:
单轮交互:没有后续任务控制
工作流:开发者预先限定可行路径
├─ 静态编排:固定顺序
├─ 选择式编排:从预设路径中选择
└─ 状态式编排:根据最新状态沿预设图流转
ReAct:一个模型根据工具 Observation 动态决定下一步
Plan-and-Execute:Planner 与 Executor 分层,必要时重新规划
多 Agent:控制权分散给多个具有角色、上下文或权限边界的主体
这套分类不是互斥的算法清单,而是理解系统控制拓扑的框架。它允许我们客观说明一个复杂系统:外层可能是状态工作流,中间由 Planner 分解任务,若干 Executor 采用 ReAct,专业能力由多个子 Agent 提供,而所有高风险动作都经过 HITL 审批。
真正稳定的架构分析,不是询问"是否使用了某个流行术语",而是持续追问:谁决定下一步?动作空间是什么?结果如何反馈?谁拥有终止、否决和接管权?
References
1 LangGraph 官方文档:Workflows and agents
2 LangChain 官方文档:What's new in LangChain v1
3 LangGraph 官方文档:Graph API overview
5 Wei et al. --- Chain-of-Thought Prompting Elicits Reasoning in Large Language Models
6 Wu et al. --- PromptChainer: Chaining Large Language Model Prompts through Visual Programming
8 Yao et al. --- ReAct: Synergizing Reasoning and Acting in Language Models
10 Wang et al. --- Plan-and-Solve Prompting
11 LangChain:Plan-and-Execute Agents
12 Xu et al. --- ReWOO: Decoupling Reasoning from Observations for Efficient Augmented Language Models
13 Wu et al. --- AutoGen: Enabling Next-Gen LLM Applications via Multi-Agent Conversation
14 LangChain 官方教程:Build a personal assistant with subagents
15 LangChain 官方文档:Human-in-the-loop
17 Yao et al. --- Tree of Thoughts: Deliberate Problem Solving with Large Language Models
18 Shinn et al. --- Reflexion: Language Agents with Verbal Reinforcement Learning