Agent 实现方式理论篇:从单轮调用到多 Agent 协作

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

4 LangChain 官方文档:Models

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

7 LangChain 官方文档:Subagents

8 Yao et al. --- ReAct: Synergizing Reasoning and Acting in Language Models

9 LangChain 官方文档:Agents

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

16 LangGraph 官方文档:Interrupts

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

相关推荐
硅谷秋水1 小时前
WLA³:面向语义、动力学与运动学的世界潜动作建模
人工智能·机器学习·计算机视觉·语言模型·机器人
@陈小鱼1 小时前
基于CNN-Transformer的无袖带血压估计
人工智能·深度学习·神经网络·算法·cnn·transformer·血压
cu1431 小时前
细谈GM7123C的具体功能与其应用
c语言·c++·人工智能·嵌入式硬件
W***25921 小时前
Work Agent长程任务深度解读:AI自主执行复杂工作的底层机制
大数据·人工智能
金科AI评测笔记1 小时前
App竞品数据平台信息整理
大数据·人工智能
Margrop1 小时前
Ubuntu 22.04 硬升 26.04 实录:6KB/s 的下载、缩水的镜像,和一块“暂停营业”的牌子
人工智能
pride.li1 小时前
ISP标定-BLC标定(Black Level Calibration,黑电平校准)
人工智能·计算机视觉·接口隔离原则
中伟视界1 小时前
绿色矿山国标明日施行:边缘AI与AI布控球技术落地
大数据·人工智能·#深度学习·#机器视觉·#工业ai·#边缘计算·#矿山智能化
王中阳Go1 小时前
读者问"你用的什么 Agent":3 个 AI 员工的分工表和工具链
人工智能·后端·ai编程