一、为什么学 Multi-Agent 一定会遇到 State?

刚开始学 Multi-Agent 的时候,我们很容易把注意力放在“Agent 角色”上。

比如一个典型的多 Agent 系统可能会有:

Planner Agent:负责拆解任务
Executor Agent:负责执行任务
Tool Agent:负责调用工具
Reviewer Agent:负责检查结果
Replanner Agent:负责重新规划
Supervisor Agent:负责调度整体流程

看起来好像只要把这些 Agent 都写出来,一个 Multi-Agent 系统就完成了。

但真正落到代码里,你马上会遇到一堆问题:

用户原始问题存在哪里?
Planner 生成的计划存在哪里?
Executor 执行到第几步了?
工具调用结果要怎么传给下一个 Agent?
某一步执行失败了,错误信息谁保存?
Replanner 根据什么判断是否需要重新规划?
最终回答从哪里汇总?

这时候你会发现:

Multi-Agent 的难点不是“有几个 Agent”,而是这些 Agent 之间如何共享信息、传递上下文、更新任务进度。

这就是 State 的作用。

在单 Agent 场景中,我们可能只需要把用户问题和历史对话拼成 Prompt,然后发给大模型就行。

但是在 Multi-Agent 场景中,一次用户请求可能会经过多个节点:

用户输入
  ↓
Planner 生成计划
  ↓
Executor 执行步骤
  ↓
Tool 调用外部系统
  ↓
Replanner 判断是否重新规划
  ↓
Final Agent 汇总答案

这个过程中,每一步都会产生新的中间结果。

这些中间结果不能只存在模型的“脑子里”,因为大模型本身并不会真正帮你维护程序状态。

所以我们需要一个统一的状态对象,把整个任务执行过程记录下来。

这个东西,在很多 Agent 框架里会被称为:

State
GraphState
AgentState
WorkflowState
OverallState

名字可以不同,但本质都是一样的:

它是一次 Agent 工作流运行过程中的全局上下文对象。


二、OverallState 到底是什么?

可以先用一句话理解:

OverallState 就是整个 Multi-Agent 工作流运行过程中的“任务档案袋”。

它不是大模型自动保存的,也不是 ChatMemory 那种单纯的聊天记录,而是程序主动维护的一份任务状态。

比如用户输入:

帮我分析一下最近服务报错的原因,并生成一份排障报告。

这个请求进入系统后,不能只是简单丢给大模型。

更合理的做法是,把它变成一个任务状态:

public class OverallState {

    private String userInput;

    private List<String> plan;

    private String currentStep;

    private Map<String, Object> toolResults;

    private List<String> observations;

    private String errorMessage;

    private Boolean needReplan;

    private String finalAnswer;
}

这个对象里可以保存:

用户原始输入
任务拆解计划
当前执行步骤
工具调用结果
Agent 中间输出
错误信息
是否需要重新规划
最终回答

所以,OverallState 不是某个神秘的 AI 概念。

它本质上就是:

后端程序为了管理 Agent 工作流,设计出来的一个上下文状态对象。

你可以把它类比成一次请求的“全局变量”,但它比普通全局变量更有边界。

它通常只属于一次任务执行过程。

比如:

用户 A 发起一次告警分析任务 → 创建一个 OverallState
用户 B 发起一次知识库问答任务 → 创建另一个 OverallState

每个任务都有自己的 State,互不干扰。

这也是为什么 Multi-Agent 系统必须考虑 sessionId、conversationId、taskId 这些东西。

因为你不能让不同用户、不同任务的状态混在一起。


三、State 和 Prompt 是一回事吗?

这是学习 Agent 时非常容易混淆的地方。

很多人会觉得:

既然最后都是发给大模型,那 State 不就是 Prompt 吗?

其实不是。

它们的关系应该这样理解:

State 是程序中保存的上下文数据。
Prompt 是每次调用大模型时临时组装出来的输入。

也就是说,State 是“原材料仓库”,Prompt 是“这一次喂给模型的材料包”。

举个例子。

假设当前 State 是这样的:

{
  "userInput": "分析订单服务异常",
  "plan": [
    "查询最近 10 分钟错误日志",
    "检索相关故障知识库",
    "分析可能原因",
    "生成排障报告"
  ],
  "currentStep": "查询最近 10 分钟错误日志",
  "toolResults": {
    "logSearch": "出现大量 Redis connection timeout"
  },
  "needReplan": false
}

当 Executor Agent 要工作时,程序可能会根据 State 组装一个 Prompt:

你是一个执行 Agent。

用户问题:
分析订单服务异常

当前执行步骤:
查询最近 10 分钟错误日志

已有计划:
1. 查询最近 10 分钟错误日志
2. 检索相关故障知识库
3. 分析可能原因
4. 生成排障报告

已有工具结果:
出现大量 Redis connection timeout

请基于当前步骤继续执行,并返回观察结果。

这个 Prompt 是临时生成的。

但是 State 会继续存在,并且会被后续节点继续读取和修改。

所以两者关系是:

State 负责保存完整任务上下文。
Prompt 负责把其中一部分上下文组织成模型能理解的输入。

这就是为什么我觉得 Agent 工程里不能只盯着 Prompt。

Prompt 很重要,但 Prompt 只是某一次模型调用的输入。

真正贯穿整个工作流的是 State。


四、State、Prompt、Memory 三者有什么区别?

在 Agent 系统里,这三个概念经常放在一起:

State
Prompt
Memory

但它们不是一个东西。

可以这样区分:

概念 作用 生命周期 典型内容
Prompt 本次模型调用的输入 一次 LLM 调用 system、user input、历史片段、工具说明
State 当前任务执行状态 一次任务或一次工作流 计划、步骤、工具结果、错误、最终答案
Memory 跨轮次或长期保存的信息 多轮对话甚至长期存在 用户偏好、历史摘要、长期记忆、知识经验

举个更直观的例子。

用户说:

帮我分析订单服务为什么一直报错。

系统可能会这样处理:

Prompt:
这一次发给模型看的内容。

State:
这次排障任务执行过程中的所有中间状态。

Memory:
之前用户说过他项目里订单服务依赖 Redis、MySQL、RabbitMQ,这些长期信息可以被检索出来辅助分析。

所以三者的关系可以总结为:

Memory 提供历史经验
State 管理当前任务过程
Prompt 组织本次模型输入

在一个复杂 Agent 系统里,三者通常会一起工作:

用户输入
  ↓
读取 Memory 中的相关历史信息
  ↓
创建当前任务 State
  ↓
根据 State + Memory 组装 Prompt
  ↓
调用模型或工具
  ↓
把结果写回 State
  ↓
必要时再更新 Memory

这就比单纯的“用户输入 → 大模型回答”复杂很多了。

也正是因为多了这些工程层,Agent 才能真正从 Demo 走向项目。


五、多 Agent 是怎么围绕 State 协作的?

理解了 State 之后,再看 Multi-Agent,就会清楚很多。

多个 Agent 不是各说各的,而是围绕同一个 State 工作。

可以抽象成:

Agent = 读取 State → 执行自己的职责 → 更新 State

例如 Planner Agent:

public class PlannerAgent {

    public void run(OverallState state) {
        String userInput = state.getUserInput();

        List<String> plan = callLLMToMakePlan(userInput);

        state.setPlan(plan);
        state.setCurrentStep(plan.get(0));
    }
}

Executor Agent:

public class ExecutorAgent {

    public void run(OverallState state) {
        String currentStep = state.getCurrentStep();

        Object result = executeStep(currentStep);

        state.getToolResults().put(currentStep, result);
    }
}

Replanner Agent:

public class ReplannerAgent {

    public void run(OverallState state) {
        boolean needReplan = judgeNeedReplan(state);

        state.setNeedReplan(needReplan);

        if (needReplan) {
            List<String> newPlan = callLLMToReplan(state);
            state.setPlan(newPlan);
        }
    }
}

Final Agent:

public class FinalAgent {

    public void run(OverallState state) {
        String answer = summarizeFinalAnswer(state);

        state.setFinalAnswer(answer);
    }
}

从这个角度看,多 Agent 并不是玄学。

它其实就是不同职责的处理节点,共同操作一个任务状态。

Planner 负责写入 plan
Executor 负责写入 toolResults
Replanner 负责写入 needReplan 和 newPlan
Final Agent 负责写入 finalAnswer

每个 Agent 都只负责自己那一部分。

这就像后端项目里的业务流程:

Controller 接收请求
Service 编排业务逻辑
Repository 查询数据
DTO 传递数据
Response 返回结果

只不过在 Agent 系统里,某些节点的逻辑不是传统代码写死的,而是通过大模型推理、工具调用、RAG 检索来完成。


六、DAG 固定了,为什么还能 Replan?

这个问题也很关键。

很多人看到 DAG 或 Workflow,会有一个误解:

既然流程图已经固定了,那它不就是死流程吗?
那还怎么体现 Agent 的动态性?

其实不是。

DAG 固定的是流程结构,不是每次执行的具体内容。

比如我们可以设计这样一个流程:

Start
  ↓
Planner
  ↓
Executor
  ↓
Check
  ↓
是否完成?
  ├── 是 → Final
  └── 否 → Replanner → Executor

这个图的结构是固定的。

但是每次任务执行时,具体怎么走,要看 State。

比如:

如果 Executor 执行成功:
needReplan = false
进入 Final

如果 Executor 执行失败:
needReplan = true
进入 Replanner

如果工具结果不完整:
needReplan = true
重新补充计划

如果发现问题已经解决:
needReplan = false
直接生成最终结果

也就是说:

DAG 定义的是“可能的路径”,State 决定的是“这一次走哪条路径”。

这就像后端代码里的 if else。

代码结构是固定的,但不同输入会走不同分支。

Agent Workflow 也是一样。

if (state.getNeedReplan()) {
    replanner.run(state);
    executor.run(state);
} else {
    finalAgent.run(state);
}

所以,DAG 和动态规划并不矛盾。

真正让流程动态起来的,不是 DAG 本身,而是 State 中不断变化的数据。


七、结合 Spring AI Alibaba 怎么理解?

在 Spring AI Alibaba 或类似 Agent 框架里,我们看到的一些概念,比如:

Graph
Node
Edge
State
OverAllState
Agent
ToolCallback
ChatClient
Advisor

其实可以放到同一张图里理解。

Graph / Workflow:
定义任务流程结构。

Node:
流程中的一个执行节点,可以是 Agent,也可以是普通函数。

Agent:
具有模型调用能力的节点。

ToolCallback:
Agent 可以调用的外部工具。

State / OverallState:
整个流程运行时共享的上下文。

ChatClient:
真正和大模型交互的客户端。

Advisor:
在模型调用前后增强上下文,比如记忆、RAG、日志等。

如果用一句话串起来:

Workflow 定义流程,Node 执行步骤,Agent 调用模型,ToolCallback 调用工具,OverallState 负责在这些节点之间传递上下文。

比如一次智能运维任务可以这样理解:

用户输入告警问题
  ↓
创建 OverallState
  ↓
Planner Node 读取 userInput,生成 plan,写入 State
  ↓
Log Tool Node 查询日志,写入 toolResult
  ↓
Knowledge Agent 检索知识库,写入 ragResult
  ↓
Diagnosis Agent 分析原因,写入 diagnosis
  ↓
Replanner Node 判断信息是否足够
  ↓
Final Node 汇总最终报告

在这个过程中,最重要的不是某一个 Agent 有多聪明,而是:

每一步产生的信息能不能被正确保存;
每一个 Agent 能不能拿到自己需要的上下文;
失败后能不能根据状态重新规划;
最终答案能不能基于完整状态汇总。

这就是 State 的价值。


八、结合 SuperBizAgent:一个智能运维场景

假设在 SuperBizAgent 里,用户输入:

订单服务最近 10 分钟大量报错,帮我分析原因。

这个时候可以创建一个任务状态:

OverallState state = new OverallState();

state.setUserInput("订单服务最近 10 分钟大量报错,帮我分析原因。");
state.setTaskType("AIOps");
state.setNeedReplan(false);

然后 Planner Agent 先生成计划:

1. 查询订单服务最近 10 分钟错误日志
2. 分析日志中的异常关键词
3. 检索知识库中类似故障案例
4. 判断是否和 Redis、MySQL、MQ 等依赖有关
5. 生成排障结论和处理建议

此时 State 变成:

{
  "userInput": "订单服务最近 10 分钟大量报错,帮我分析原因。",
  "taskType": "AIOps",
  "plan": [
    "查询订单服务最近 10 分钟错误日志",
    "分析日志中的异常关键词",
    "检索知识库中类似故障案例",
    "判断是否和 Redis、MySQL、MQ 等依赖有关",
    "生成排障结论和处理建议"
  ],
  "currentStep": "查询订单服务最近 10 分钟错误日志",
  "needReplan": false
}

接着 Executor 调用日志查询工具,发现:

Redis connection timeout

于是写回 State:

{
  "toolResults": {
    "logSearch": "订单服务出现大量 Redis connection timeout"
  }
}

然后 Knowledge Agent 检索知识库,找到类似案例:

当 Redis 连接池耗尽或网络抖动时,订单服务可能出现接口超时和下单失败。

继续写回 State:

{
  "ragResult": "Redis 连接池耗尽可能导致订单服务接口超时。"
}

Diagnosis Agent 再根据日志和知识库结果生成诊断:

{
  "diagnosis": "初步判断订单服务异常与 Redis 连接超时有关,可能原因包括连接池配置过小、Redis 服务负载过高、网络抖动。"
}

如果此时 Replanner 判断信息不足,比如没有 Redis 监控指标,就可以设置:

{
  "needReplan": true,
  "missingInfo": "缺少 Redis 当前连接数、CPU、内存、慢查询等指标。"
}

然后重新生成补充计划:

1. 查询 Redis 当前连接数
2. 查询 Redis CPU 和内存使用率
3. 查询 Redis 慢查询日志
4. 结合订单服务错误日志重新分析

这就是 Replan。

它不是模型突然“灵光一现”,而是根据 State 中已有信息和缺失信息进行判断。

最终,如果信息足够,Final Agent 就可以基于 State 汇总报告:

问题现象:
订单服务最近 10 分钟大量报错。

关键日志:
出现 Redis connection timeout。

可能原因:
Redis 连接池耗尽、Redis 服务负载过高、网络抖动。

建议排查:
1. 检查 Redis 当前连接数和最大连接数配置。
2. 检查订单服务连接池配置。
3. 查看 Redis CPU、内存、慢查询指标。
4. 如果连接数打满,可临时扩容连接池或优化热点访问。

整个过程看起来像是多个 Agent 在协作。

但底层本质是:

多个 Agent 在不断读取和更新同一个任务状态。


九、为什么说 State 是 Agent 工程化的核心?

如果没有 State,多 Agent 很容易变成下面这种情况:

Planner 生成了计划,但 Executor 不知道。
Executor 调用了工具,但 Replanner 不知道结果。
Replanner 觉得要重试,但不知道之前失败在哪。
Final Agent 想总结,但拿不到完整过程。

这就会导致系统看起来有很多 Agent,但实际上每个 Agent 都是割裂的。

真正可用的 Multi-Agent 系统,一定要解决这几个问题:

1. 状态怎么创建?
2. 状态怎么传递?
3. 状态怎么更新?
4. 状态怎么隔离?
5. 状态怎么持久化?
6. 状态怎么参与 Prompt 组装?
7. 状态怎么决定流程分支?

这些问题,才是 Multi-Agent 工程化真正绕不开的地方。

如果只是写几个 Agent 类,然后每个类里面调用一次大模型,这还只是 Demo。

如果能把 State 管起来,才开始接近真正的 Agent 系统。


十、面向项目开发的设计建议

如果要在自己的项目里设计 Multi-Agent,我建议不要一上来就写很多 Agent。

应该先设计 State。

比如可以先问自己:

这个任务的输入是什么?
中间过程会产生哪些结果?
哪些信息需要被后续 Agent 使用?
哪些状态决定流程分支?
哪些错误需要记录?
最终答案需要哪些字段?

然后再设计一个状态对象:

@Data
public class AgentTaskState {

    private String taskId;

    private String sessionId;

    private String userInput;

    private String taskType;

    private List<String> plan;

    private Integer currentStepIndex;

    private Map<String, Object> toolResults = new HashMap<>();

    private Map<String, Object> agentResults = new HashMap<>();

    private List<String> observations = new ArrayList<>();

    private List<String> errors = new ArrayList<>();

    private Boolean needReplan = false;

    private String finalAnswer;
}

然后每个 Agent 都遵守一个统一规则:

只读取自己需要的状态;
只写入自己负责的结果;
不要随便覆盖其他 Agent 的输出;
每次关键变化都记录 observation;
失败信息写入 errors;
是否需要 Replan 写入 needReplan。

这样整个系统才会清晰。

你甚至可以把 Agent 抽象成统一接口:

public interface AgentNode {

    void run(AgentTaskState state);
}

然后每个 Agent 实现这个接口:

public class PlannerNode implements AgentNode {

    @Override
    public void run(AgentTaskState state) {
        // 读取 userInput
        // 调用大模型生成 plan
        // 写回 state
    }
}
public class ExecutorNode implements AgentNode {

    @Override
    public void run(AgentTaskState state) {
        // 读取 currentStep
        // 调用工具或模型执行
        // 写回 toolResults / agentResults
    }
}
public class ReplannerNode implements AgentNode {

    @Override
    public void run(AgentTaskState state) {
        // 读取已有执行结果
        // 判断是否需要重新规划
        // 更新 needReplan / plan
    }
}

这样设计之后,Multi-Agent 就不再是几个大模型调用的堆叠,而是一个有结构、有状态、有流程控制的系统。


十一、总结

今天这篇文章主要想表达一个观点:

Multi-Agent 的核心不是“多个 Agent”,而是“多个 Agent 如何围绕 State 协作”。

Planner、Executor、Replanner、Supervisor 这些名字都很重要,但如果没有 State,它们之间就无法真正协作。

可以把整个关系总结成一句话:

Prompt 决定这一次模型怎么看问题;
Memory 决定系统能记住什么历史;
State 决定整个任务怎么推进。

在 Spring AI Alibaba 或其他 Agent 框架里,我们看到的 OverallState,本质上就是一次工作流执行过程中的全局任务上下文。

它负责保存用户输入、任务计划、执行步骤、工具结果、错误信息、重规划标记和最终答案。

理解了 State,再去看 DAG、Workflow、Replan、Supervisor,就会清楚很多。

DAG 不是死流程。

它只是定义了可能的执行路径。

真正决定流程怎么走的,是 State 中不断变化的数据。

所以,想把 Multi-Agent 从 Demo 写成项目,第一步不是疯狂加 Agent,而是先问自己:

我的 State 设计清楚了吗?

如果 State 设计不清楚,Agent 越多,系统越乱。

如果 State 设计清楚,Agent 才能真正协作起来。

这也是我最近学习 Multi-Agent 最大的感受:

Agent 工程化,表面是在调模型,本质是在管理上下文。

Logo

欢迎加入 MCP 技术社区!与志同道合者携手前行,一同解锁 MCP 技术的无限可能!

更多推荐