react - ReActAgent 配置与构建
2026年7月30日 下午4:11:22
ReActAgent 采用 “Planning + Reasoning + Acting(规划 + 推理 + 行动)” 闭环模式。它能够根据用户目标,自主思考(Thought)、选择工具执行动作(Action)、观察结果(Observation),直至完成任务。
| 分类 | 参数名称 | 类型 | 默认值 | 说明 |
|---|---|---|---|---|
| 身份定义 | name | String | react_agent | 智能体唯一标识,决定了 Session 存储中的 TraceKey(__name)。 |
| role | String | / | 核心字段。角色描述,帮助模型识别自身角色或供团队调度。 | |
| profile | AgentProfile | / | 核心字段。挡案描述,帮助模型识别自身角色或供团队调度。 | |
| 决策大脑 | chatModel | ChatModel | / | 充当大脑,负责理解需求、分派任务与总结。 |
| modelOptions | Consumer | / | 用于精细控制模型的参数(如调低 Temperature 以稳健决策)。 | |
| instruction | String | 中文模板 | 核心指令。告诉模型要怎么做,要注意什么。 | |
| systemPrompt | String | / | 系统提示词(与 role + instruction 互为替代)。 | |
| 执行控制 | maxTurns | int | 5 | 单次任务允许的最大推理步数,防止成员间无限"思考"导致死循环。 |
| retryConfig | int, long | 3, 1000L | 决策失败或解析异常时的自动重试次数及延迟。 | |
| autoRethink | boolean | false | 无法得出答案时是否自动重新思考 | |
| 存储输出 | sessionWindowSize | int | 10 | 记忆窗口大小。加载最近 N 条历史消息作为上下文。 |
| outputKey | String | / | 任务结束后的结果回填至 FlowContext 的键名。 | |
| outputSchema | String/Type | / | 结构化输出。约束输出格式(JSON Schema),确保结果符合业务预期。 | |
| 扩展定制 | interceptors | List | / | 生命周期拦截器,用于监控思考过程、工具调用等过程。 |
| tools | Map | / | 工具。 | |
| toolContext | Map | / | 工具调用时共享的上下文数据(如数据库连接、用户信息)。 | |
| talents | List | / | 才能。 | |
| attr(name, val) | String, Object | - | 设置单个自定义属性,运行时可读取,@since 4.0.4 | |
| attrs(vals) | Map | - | 批量设置自定义属性,@since 4.0.4 | |
| 运行模式 | planningMode | boolean | false | 推理前先制定执行计划(Plan-ReAct 模式) |
| planningInstruction | String/Function | - | 自定义规划指令 | |
| feedbackMode | boolean | false | 允许主动寻求外部帮助/人工介入 | |
| feedbackDescription | String/Function | - | 反馈描述 | |
| feedbackReasonDescription | String/Function | - | 反馈原因描述 |
关键配置点补充说明
- 关于职责描述 (description):在 ReActAgent 中,描述不仅是给人看的,更是给"模型"看的。一个清晰的描述能让模型更准确地判断何时该调用什么工具。
- 关于终止标识 (finishMarker):系统会根据
name自动生成。当模型认为任务已达成,输出该标识后,Agent 将提取内容作为最终答复。 - 关于最大推理回合数 (maxTurns):在推理协作中,模型可能会产生反复确认或死循环。该参数是"保险丝",确保系统不会因为无限对话而耗尽 Token。
2、ReActAgent 构建
- 基础版:具备工具能力的智能体
适用于逻辑固定的线性任务。赋予智能体一组工具,让其自主调度解决问题。
// 创建一个具备数据库查询能力的智能体
ReActAgent dbAgent = ReActAgent.of(chatModel)
.name("data_helper")
.role("数据助手,负责查询用户信息及订单状态")
// 1. 注入工具(支持注解方法或 FunctionTool 实例)
.defaultToolAdd(new MyUserTools())
// 2. 限制步数防止死循环
.maxTurns(5)
.autoRethink(true)
.build();
// 执行:模型会根据问题判断是否需要调用工具
String result = dbAgent.prompt("帮我查一下用户 ID 为 1001 的最近一笔订单金额")
.call()
.getContent();
- 进阶版:精细化控制专家团队
这是一个包含重试策略、拦截监控及性能调优的复杂示例。
// 创建一个全能的技术支持专家
ReActAgent techAgent = ReActAgent.of(chatModel)
// --- 1. 身份与职责定义 ---
.name("tech_support_expert")
.role("技术支持专家(负责处理复杂的客户技术问题,包括查询数据库和排查日志)")
// --- 2. 注入工具与重试策略 ---
.defaultToolAdd(dbTool)
.defaultToolAdd(logTool)
.retryConfig(3, 2000L) // 决策失败自动重试
.maxTurns(12) // 允许最多 12 步推理,处理深度问题
.autoRethink(true) //启用自我反思(由 llm 决定超过 maxTurns 后,还要不要继续)
// --- 3. 配置决策大脑的运行策略 ---
.modelOptions(options -> {
options.temperature(0.1); // 调低温度,让决策更严谨
})
// --- 4. 插入定制化逻辑 ---
.defaultInterceptorAdd(new ReActInterceptor() {
@Override
public void onThought(ReActTrace trace, String thoughtContent, AssistantMessage assistantMessage) {
System.out.println("🤖 思考中: " + thoughtContent);
}
@Override
public void onAction(ReActTrace trace, ToolExchanger toolExchanger) {
System.out.println("🛠️ 执行工具: " + toolExchanger.getToolName() + ",参数: " + toolExchanger.getArgs());
}
})
.build();
// 执行调用:模型会分析问题,决定先查数据,再分析情况
String finalAnswer = techAgent.prompt("用户 ID 为 9527 的反馈登录失败,请排查原因并给出建议。").call().getContent();
3、ReActInterceptor 接口参考
/*
* Copyright 2017-2025 noear.org and authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.noear.solon.ai.agent.react;
import org.noear.solon.ai.agent.AgentInterceptor;
import org.noear.solon.ai.agent.react.task.ToolExchanger;
import org.noear.solon.ai.chat.ChatResponse;
import org.noear.solon.ai.chat.interceptor.ChatInterceptor;
import org.noear.solon.ai.chat.message.AssistantMessage;
import org.noear.solon.ai.chat.message.ChatMessage;
import org.noear.solon.ai.chat.tool.ToolCall;
import org.noear.solon.lang.Nullable;
import org.noear.solon.lang.Preview;
import java.util.Collection;
import java.util.List;
/**
* ReAct 智能体拦截器
* <p>提供对智能体起止、模型推理、工具执行等全生命周期的监控与干预能力</p>
*
* @author noear
* @since 3.8.1
*/
@Preview("3.8.1")
public interface ReActInterceptor extends AgentInterceptor, ChatInterceptor {
/**
* 智能体生命周期:开始执行前
*/
default void onAgentStart(ReActTrace trace) {
}
/**
* 推理节点:Reason 阶段开始前(在 systemPrompt 构建和消息组装之前触发)
* <p>适合做上下文压缩、工作记忆窗口管理等预处理操作</p>
*/
default void onReasonStart(ReActTrace trace, StringBuilder systemPromptBuf) {
}
/**
* 推理节点:Reason 请求失败且即将再次尝试时触发。
* <p>拦截器可以在此根据异常调整 WorkingMemory。返回 true 表示已为下一次请求
* 修改了请求上下文;ReasonTask 会在下一次尝试中重新组装消息和请求。</p>
*
* @param trace 当前推理追踪
* @param error 本次请求异常
* @param attempt 即将进行的尝试序号(从 1 开始)
* @param systemPrompt 当前 Reason 使用的系统提示词
* @return 是否修改了下一次请求所依赖的上下文
* @since 4.0.4
*/
default boolean onReasonRetry(ReActTrace trace, Throwable error, int attempt, String systemPrompt) {
return false;
}
/**
* 推理节点:接收 LLM 返回的原始推理消息
*/
default void onReasonEnd(ReActTrace trace, ChatResponse resp, AssistantMessage message, long durationMs) {
}
/**
* 计划节点:接收 LLM 返回的原始推理消息
*/
default void onPlan(ReActTrace trace, AssistantMessage message) {
}
/**
* @since 4.0.4
*/
default void onActionStart(ReActTrace trace, Collection<ToolExchanger> toolCalls) {
}
/**
* 动作节点:调用功能工具 (Action) 前触发
* <p>可用于权限控制、参数合法性预检</p>
*/
default void onToolCallStart(ReActTrace trace, ToolExchanger toolExchanger) {
}
/**
* 观察节点:工具执行完成后触发(100% 强闭环,放在 finally 块中)
* <p>无论成功、失败、挂起、中断,此方法保证被调用</p>
*
* @param trace ReAct 追踪上下文
* @param toolExchanger 工具交换器(含 toolName、args、result)
* @param observation 观察结果消息(成功时为工具输出,失败时为错误描述;挂起/中断时为空消息)
* @param durationMs 工具执行耗时(毫秒)
* @param error 执行异常(成功时为 null)
*/
default void onToolCallEnd(ReActTrace trace, ToolExchanger toolExchanger,
@Nullable ChatMessage observation,
@Nullable Throwable error,
long durationMs) {
}
/**
* @since 4.0.4
*/
default void onActionEnd(ReActTrace trace, Collection<ToolExchanger> toolCalls) {
}
/**
* 智能体生命周期:任务结束(成功或异常中止)时触发
*/
default void onAgentEnd(ReActTrace trace) {
}
//-------------------
/**
* 思考节点:Reason 阶段完成后触发
* <p>无论是否解析出有效的 thoughtContent,此方法都会被调用</p>
*
* @param trace ReAct 追踪上下文
* @param thoughtContent 提取后的思考内容(可能为空字符串)
* @param assistantMessage 原始 LLM 响应消息(含 toolCalls、content、reasoning 等完整信息)
* @deprecated 4.0.4 {@link #onReasonEnd(ReActTrace, ChatResponse, AssistantMessage, long)}
*/
@Deprecated
default void onThought(ReActTrace trace, String thoughtContent, AssistantMessage assistantMessage) {
}
/**
* 动作节点:调用功能工具 (Action) 前触发
* <p>可用于权限控制、参数合法性预检</p>
*
* @deprecated 4.0.4 {@link #onToolCallStart(ReActTrace, ToolExchanger)}
*/
@Deprecated
default void onAction(ReActTrace trace, ToolExchanger toolExchanger) {
}
/**
* 观察节点:工具执行完成后触发(100% 强闭环,放在 finally 块中)
* <p>无论成功、失败、挂起、中断,此方法保证被调用</p>
*
* @param trace ReAct 追踪上下文
* @param toolExchanger 工具交换器(含 toolName、args、result)
* @param observation 观察结果消息(成功时为工具输出,失败时为错误描述;挂起/中断时为空消息)
* @param durationMs 工具执行耗时(毫秒)
* @param error 执行异常(成功时为 null)
* @deprecated 4.0.4 {@link #onToolCallEnd(ReActTrace, ToolExchanger, ChatMessage, Throwable, long)}
*/
@Deprecated
default void onObservation(ReActTrace trace, ToolExchanger toolExchanger,
@Nullable ChatMessage observation,
@Nullable Throwable error,
long durationMs) {
}
}
- ChatInterceptor
/*
* Copyright 2017-2025 noear.org and authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.noear.solon.ai.chat.interceptor;
import org.noear.solon.ai.chat.ChatOptions;
import org.noear.solon.ai.chat.ChatRequest;
import org.noear.solon.ai.chat.ChatResponse;
import org.noear.solon.ai.chat.ChatSession;
import org.noear.solon.ai.chat.prompt.Prompt;
import reactor.core.publisher.Flux;
import java.io.IOException;
/**
* 聊天拦截器
*
* @author noear
* @since 3.3
*/
public interface ChatInterceptor extends ToolInterceptor {
/**
* 预处理(在构建请求之前触发)
* <p>用于动态调整配置、补充或修改提示词(Prompt)以及注入系统指令</p>
*
* @param session 当前聊天会话(可用于获取历史消息、元数据或状态标记)
* @param options 聊天配置(可修改,影响模型参数等)
* @param originalPrompt 原始提示词(包含用户消息和上下文)
* @param systemMessage 系统指令容器(可追加,将作为 System Message 发送)
*/
default void onPrepare(ChatSession session, ChatOptions options, Prompt originalPrompt, StringBuilder systemMessage){
}
/**
* 拦截 Call 请求
*
* @param req 请求
* @param chain 拦截链
*/
default ChatResponse interceptCall(ChatRequest req, CallChain chain) throws IOException {
return chain.doIntercept(req);
}
/**
* 拦截 Stream 请求
*
* @param req 请求
* @param chain 拦截链
*/
default Flux<ChatResponse> interceptStream(ChatRequest req, StreamChain chain) {
return chain.doIntercept(req);
}
}