首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >Agent之ReAct Agent的前世今生与实践落地

Agent之ReAct Agent的前世今生与实践落地

作者头像
阳光宅猿
发布2026-05-11 13:52:43
发布2026-05-11 13:52:43
1500
举报
如果抛开具体工程实现,只看 ReAct 的最小原理,它核心只有 3 个环节:1、Reason 当前怎么理解问题,下一步该做什么?

2、Act 执行一个动作,通常是工具调用?

3、Observe 读取动作结果,并把结果反馈回下一轮推理

也就是最经典的:

Reason -> Act -> Observe -> Reason -> ...

所以从理论最小闭环看,ReAct 其实只需要 3 个原子节点就够了。

01、标准ReAct Agent节点设计

三个原子节点只是基础的ReAct Agent,大部门工程里会长成6个,甚至更多。因为一旦从论文原理走到生产系统,光有 Reason / Act / Observe 通常不够。你会马上遇到这些现实问题:

1、上下文越来越长怎么办?

2、工具无限调用怎么办?

3、什么时候该结束?

4、超过轮次怎么办?

5、最终答案如何单独收口?

6、是否要做审批、回放、容错?

于是很多团队会在3个原子节点之外,再补上“工程节点”。一般工程里会有6个节点,其实可以分成两类:

1. 原理核心节点:ReasoningNode、ActionNode、ObservationNode这 3 个才最接近 ReAct 的理论原型。

2. 工程增强节:SummarizingNode、LimitExceededNode、FinalAnswerNode

这 3 个不是 ReAct 理论本身必需的,而是为了让 ReAct 更能在真实系统里稳定运行。

02、ReAct 底层原理只有“必要结构”和“常见增强结构”

一、必要结构

这部分才是 ReAct 的本体:推理结构:用来判断当前状态、决定下一步行为。行动结构:执行一个动作或工具。观察结构:消化行动结果,并反馈给推理层。

这是 ReAct 的不可再少骨架。

二、常见增强结构

这部分不是理论强制,但在工程里常见:

1、终止结构:判断什么时候结束,有的系统把它写成条件分支,不单独做节点,有的系统会做成 FinalAnswerNode。

2、超限兜底结构:防止无限循环,有的系统单独做 LimitExceededNode。

3、上下文压缩结构:长任务常常需要摘要,所以会有 SummarizingNode。

4、答案验收结构:判断答案是否真的满足任务要求,有的系统会单独加 validator 节点。

5、人工审批结构:高风险动作要人工确认,有些系统会单独做 approval 节点。

6、错误恢复结构:工具失败、状态异常、重试分流,有时也会做成独立节点。

所以从底层看,ReAct 不是一个固定 6 节点模板,而是一种“围绕 Reason-Act-Observe 的循环式决策范式”。

你可以把它理解成两层

第一层:论文级 ReAct

最小闭环只有:Reason、Act、Observe

第二层:系统级 ReAct

为了可上线、可治理、可持续运行,会扩成:推理节点、执行节点、观察节点、终止节点、摘要节点、超限节点、校验节点、审批节点、错误恢复节点、记忆更新节点。

03、ReAct 是原理,节点拆分是工程设计

因为很多人容易把“某个项目里的节点划分”误认为“ReAct 的标准定义”。其实不是。比如不同系统可能这么拆:

方案 A:极简型

Reason、Act、Observe

方案 B:常规工程型

Reason、Act、Observe、FinalAnswer、LimitExceeded

方案 C:长任务增强型

Reason、Act、Observe、Summarize、Validate、FinalAnswer、LimitExceeded。

方案 D:企业治理型

Reason、Action、Plan、Approval、Act、Observe、Validate、Audit、FinalAnswer。

它们都可以是 ReAct,只是工程粒度不同。它已经从“理论 ReAct”进化到了“生产可控 ReAct”。

从底层原理上,ReAct 的本体只有 3 个核心环节:Reason、Act、Observe。

但每个工程里的多个个节点,不是 ReAct 的唯一标准答案,而是围绕这 3 个核心环节做出的工程化扩展。

04、如何实现?

以企业治理型为例,采用SpringAiAlibaba来实现对应的多个节点,从而达到工程级别ReActAgent。

这类“企业治理型 ReAct”非常适合用 spring ai alibaba 的 StateGraph 来实现。

核心思路就是:

1、每个节点实现一个 NodeAction。

2、所有中间变量放进 OverAllState。

3、用 Dispatcher 决定下一跳。

4、把治理能力拆成显式节点,而不是塞进 Prompt。

一、节点怎么定义

先定义状态键:

代码语言:javascript
复制
public interface GovStateKeys {
    String USER_MESSAGE = "user_message";
    String MESSAGES = "messages";
    String ACTION_PLAN = "action_plan";
    String NEED_APPROVAL = "need_approval";
    String APPROVAL_GRANTED = "approval_granted";
    String TOOL_CALLS = "tool_calls";
    String TOOL_RESULTS = "tool_results";
    String OBSERVATION = "observation";
    String VALIDATION_PASSED = "validation_passed";
    String AUDIT_RECORD = "audit_record";
    String FINAL_ANSWER = "final_answer";

    String REASON_NODE = "reason";
    String ACTION_PLAN_NODE = "action_plan";
    String APPROVAL_NODE = "approval";
    String ACT_NODE = "act";
    String OBSERVE_NODE = "observe";
    String VALIDATE_NODE = "validate";
    String AUDIT_NODE = "audit";
    String FINAL_NODE = "final";
}

二、各节点怎么实现

1. ReasonNode

作用:判断当前任务要不要拆计划、要不要直接答、要不要走工具。

代码语言:javascript
复制
public class ReasonNode implements NodeAction {
    private final ChatModel chatModel;
    public ReasonNode(ChatModel chatModel) {
        this.chatModel = chatModel;
    }
    @Override
    public Map<String, Object> apply(OverAllState state) {
        String userMessage = state.value(GovStateKeys.USER_MESSAGE, "");
        // 这里可以调用 LLM,让它输出结构化决策
        boolean needPlan = userMessage.length() > 50; // 示例
        return Map.of(
                "need_plan", needPlan,
                "current_phase", "reasoning"
        );
    }
}

2. ActionPlanNode

作用:把复杂目标拆成可执行动作计划,不是最终任务计划,而是当前执行计划。

代码语言:javascript
复制
public class ActionPlanNode implements NodeAction {
    private final ChatModel chatModel;
    public ActionPlanNode(ChatModel chatModel) {
        this.chatModel = chatModel;
    }
    @Override
    public Map<String, Object> apply(OverAllState state) {
        String userMessage = state.value(GovStateKeys.USER_MESSAGE, "");
        String actionPlan = """
                1. 查询相关数据
                2. 判断是否涉及高风险动作
                3. 如需审批则等待审批
                4. 执行工具
                5. 校验结果
                """;
        return Map.of(
                GovStateKeys.ACTION_PLAN, actionPlan,
                "current_phase", "action_plan"
        );
    }
}

3. ApprovalNode

作用:判断当前计划是否涉及高风险动作,是否需要人工审批。

代码语言:javascript
复制
public class ApprovalNode implements NodeAction {
    @Override
    public Map<String, Object> apply(OverAllState state) {
        String plan = state.value(GovStateKeys.ACTION_PLAN, "");
        boolean needApproval = plan.contains("删除") || plan.contains("写文件") || plan.contains("执行命令");
        if (needApproval) {
            return Map.of(
                    GovStateKeys.NEED_APPROVAL, true,
                    GovStateKeys.APPROVAL_GRANTED, false,
                    "current_phase", "awaiting_approval"
            );
        }
        return Map.of(
                GovStateKeys.NEED_APPROVAL, false,
                GovStateKeys.APPROVAL_GRANTED, true,
                "current_phase", "approval_skipped"
        );
    }
}

4. ActNode

作用:真正执行工具。

代码语言:javascript
复制
public class GovActionNode implements NodeAction {
    private final ToolExecutionExecutor executor;
    public GovActionNode(ToolExecutionExecutor executor) {
        this.executor = executor;
    }
    @Override
    public Map<String, Object> apply(OverAllState state) throws Exception {
        if (!state.value(GovStateKeys.APPROVAL_GRANTED, false)) {
            return Map.of("current_phase", "blocked");
        }
        var toolCalls = state.<List<AssistantMessage.ToolCall>>value(GovStateKeys.TOOL_CALLS).orElse(List.of());
        var result = executor.execute(toolCalls, "conv-1", "agent-1", false, "user-1", "");
        return Map.of(
                GovStateKeys.TOOL_RESULTS, result.responses(),
                "current_phase", "act"
        );
    }
}

5. ObserveNode

作用:把工具结果变成结构化观察。

代码语言:javascript
复制
public class GovObservationNode implements NodeAction {
    @Override
    public Map<String, Object> apply(OverAllState state) {
        var toolResults = state.value(GovStateKeys.TOOL_RESULTS, List.of());
        String observation = "已获取工具结果,共 " + toolResults.size() + " 条";
        return Map.of(
                GovStateKeys.OBSERVATION, observation,
                "current_phase", "observe"
        );
    }
}

6. ValidateNode

作用:校验结果是否满足任务要求,是否要继续补证据。

代码语言:javascript
复制
public class ValidateNode implements NodeAction {
    @Override
    public Map<String, Object> apply(OverAllState state) {
        String observation = state.value(GovStateKeys.OBSERVATION, "");
        boolean passed = observation != null && !observation.isBlank();
        return Map.of(
                GovStateKeys.VALIDATION_PASSED, passed,
                "current_phase", "validate"
        );
    }
}

7. AuditNode

作用:记录整个动作链,满足审计要求。

代码语言:javascript
复制
public class AuditNode implements NodeAction {
    @Override
    public Map<String, Object> apply(OverAllState state) {
        String record = """
                {
                  "phase":"audit",
                  "approved": %s,
                  "validated": %s
                }
                """.formatted(
                state.value(GovStateKeys.APPROVAL_GRANTED, false),
                state.value(GovStateKeys.VALIDATION_PASSED, false)
        );
        return Map.of(
                GovStateKeys.AUDIT_RECORD, record,
                "current_phase", "audit"
        );
    }
}

8. FinalAnswerNode

作用:统一收口输出。

代码语言:javascript
复制
public class GovFinalAnswerNode implements NodeAction {
    @Override
    public Map<String, Object> apply(OverAllState state) {
        String observation = state.value(GovStateKeys.OBSERVATION, "");
        String finalAnswer = "最终结论:" + observation;
        return Map.of(
                GovStateKeys.FINAL_ANSWER, finalAnswer,
                "current_phase", "final"
        );
    }
}

三、Dispatcher 怎么写

代码语言:javascript
复制
ReasonDispatcher
public class ReasonDispatcher implements EdgeAction {
    @Override
    public String apply(OverAllState state) {
        boolean needPlan = state.value("need_plan", false);
        return needPlan ? GovStateKeys.ACTION_PLAN_NODE : GovStateKeys.FINAL_NODE;
    }
}
ApprovalDispatcher
public class ApprovalDispatcher implements EdgeAction {
    @Override
    public String apply(OverAllState state) {
        boolean granted = state.value(GovStateKeys.APPROVAL_GRANTED, false);
        return granted ? GovStateKeys.ACT_NODE : GovStateKeys.FINAL_NODE;
    }
}
ValidateDispatcher
public class ValidateDispatcher implements EdgeAction {
    @Override
    public String apply(OverAllState state) {
        boolean passed = state.value(GovStateKeys.VALIDATION_PASSED, false);
        return passed ? GovStateKeys.AUDIT_NODE : GovStateKeys.REASON_NODE;
    }
}

四、整个图怎么挂起来

这部分最关键,和你当前工程的 buildReActGraph(...) 是同一种写法。

代码语言:javascript
复制
StateGraph graph = new StateGraph("governed-react-agent", keyStrategyFactory)
        .addNode(GovStateKeys.REASON_NODE, AsyncNodeAction.node_async(new ReasonNode(chatModel)))
        .addNode(GovStateKeys.ACTION_PLAN_NODE, AsyncNodeAction.node_async(new ActionPlanNode(chatModel)))
        .addNode(GovStateKeys.APPROVAL_NODE, AsyncNodeAction.node_async(new ApprovalNode()))
        .addNode(GovStateKeys.ACT_NODE, AsyncNodeAction.node_async(new GovActionNode(executor)))
        .addNode(GovStateKeys.OBSERVE_NODE, AsyncNodeAction.node_async(new GovObservationNode()))
        .addNode(GovStateKeys.VALIDATE_NODE, AsyncNodeAction.node_async(new ValidateNode()))
        .addNode(GovStateKeys.AUDIT_NODE, AsyncNodeAction.node_async(new AuditNode()))
        .addNode(GovStateKeys.FINAL_NODE, AsyncNodeAction.node_async(new GovFinalAnswerNode()))
        .addEdge(StateGraph.START, GovStateKeys.REASON_NODE)
        .addConditionalEdges(GovStateKeys.REASON_NODE,
                AsyncEdgeAction.edge_async(new ReasonDispatcher()),
                Map.of(
                        GovStateKeys.ACTION_PLAN_NODE, GovStateKeys.ACTION_PLAN_NODE,
                        GovStateKeys.FINAL_NODE, GovStateKeys.FINAL_NODE
                ))
        .addEdge(GovStateKeys.ACTION_PLAN_NODE, GovStateKeys.APPROVAL_NODE)
        .addConditionalEdges(GovStateKeys.APPROVAL_NODE,
                AsyncEdgeAction.edge_async(new ApprovalDispatcher()),
                Map.of(
                        GovStateKeys.ACT_NODE, GovStateKeys.ACT_NODE,
                        GovStateKeys.FINAL_NODE, GovStateKeys.FINAL_NODE
                ))
        .addEdge(GovStateKeys.ACT_NODE, GovStateKeys.OBSERVE_NODE)
        .addEdge(GovStateKeys.OBSERVE_NODE, GovStateKeys.VALIDATE_NODE)
        .addConditionalEdges(GovStateKeys.VALIDATE_NODE,
                AsyncEdgeAction.edge_async(new ValidateDispatcher()),
                Map.of(
                        GovStateKeys.AUDIT_NODE, GovStateKeys.AUDIT_NODE,
                        GovStateKeys.REASON_NODE, GovStateKeys.REASON_NODE
                ))
        .addEdge(GovStateKeys.AUDIT_NODE, GovStateKeys.FINAL_NODE)
        .addEdge(GovStateKeys.FINAL_NODE, StateGraph.END);

这 8 个节点不是为了“把图画复杂”,而是为了把不同责任显式拆开:

  • Reason 决定理解与分流
  • ActionPlan 决定当前动作计划
  • Approval 决定能不能做
  • Act 真正去做
  • Observe 看结果
  • Validate 判断结果够不够好
  • Audit 留痕
  • FinalAnswer 统一交付

这套拆法的最大价值是:

治理能力不再藏在 Prompt 里,而是变成可控、可审计、可插拔的节点。

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2026-05-02,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 阳光宅猿 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档