ReActAgent 实战指南:构建会思考、能行动的 AI Agent
如果你希望 AI 不仅能聊天,还能真正做事——查数据库、调 API、做决策、从结果中学习——那你来对地方了。
本文将用 Solon AI 4.0 的 ReActAgent 带你构建生产级的 AI Agent。读完你将学会如何构建一个能够推理复杂问题、使用外部工具、并根据实际反馈调整行为的智能体。
ReActAgent 有何不同?
传统 LLM 擅长生成文本,但一旦需要与现实世界交互——查数据库、拉取实时数据、做计算——就无能为力了。
ReActAgent(Reason + Act)打破了这堵墙。它实现了一个认知循环:
思考 → 行动 → 观察 →(重复或结束)
Agent 思考下一步该做什么,行动(调用工具),观察结果,然后决定是继续还是交出最终答案。
这不是理论。Solon AI 的 ReActAgent 已经在自动客服、智能数据分析、多步工作流自动化等生产场景中得到验证。
1. 添加依赖
首先,在项目中添加 solon-ai-agent 模块:
<dependency>
<groupId>org.noear</groupId>
<artifactId>solon-ai-agent</artifactId>
</dependency>
如果使用了 Solon 的父 POM,版本会自动管理。否则请指定最新的 Solon 版本。
2. 构建 ChatModel(Agent 的大脑)
每个 Agent 都需要一个"大脑"——ChatModel 负责推理。用 Builder API 快速构建:
import org.noear.solon.ai.chat.ChatModel;
ChatModel chatModel = ChatModel.of("https://api.moark.com/v1/chat/completions")
.apiKey("your-api-key-here")
.model("Qwen3-32B")
.build();
也可以通过 YAML 配置后注入:
solon.ai.chat:
demo:
apiUrl: "http://127.0.0.1:11434/api/chat"
provider: "ollama"
model: "llama3.2"
@Inject("${solon.ai.chat.demo}")
ChatModel chatModel;
3. Hello World:你的第一个 ReActAgent
先从一个简单的例子开始——创建一个获取时间的工具和一个基础 Agent:
import org.noear.solon.ai.agent.react.ReActAgent;
import org.noear.solon.ai.annotation.ToolMapping;
import org.noear.solon.ai.annotation.Param;
import org.noear.solon.ai.chat.tool.AbsToolProvider;
import java.time.LocalDateTime;
// 1. 定义工具
public class TimeTool extends AbsToolProvider {
@ToolMapping(description = "获取当前的日期和时间")
public String getCurrentTime() {
return LocalDateTime.now().toString();
}
}
// 2. 构建并运行 Agent
public class HelloAgent {
public static void main(String[] args) throws Throwable {
ChatModel chatModel = ChatModel.of("https://api.moark.com/v1/chat/completions")
.apiKey("***")
.model("Qwen3-32B")
.build();
ReActAgent agent = ReActAgent.of(chatModel)
.role("你是一个可以查询时间的助手。")
.defaultToolAdd(new TimeTool())
.build();
String response = agent.prompt("现在几点了?")
.call()
.getContent();
System.out.println(response);
}
}
运行时,Agent 会:
- 思考:“用户想知道时间,我有一个
getCurrentTime工具” - 行动:调用
getCurrentTime() - 观察:拿到时间戳
- 回答:“当前时间是 2026-07-04T14:30:22……”
4. 实战:客服支持 Agent
我们来构建一个更实用的场景——支持查询订单和库存的客服 Agent。
第 1 步:定义工具
import org.noear.solon.ai.chat.tool.AbsToolProvider;
import org.noear.solon.ai.annotation.ToolMapping;
import org.noear.solon.ai.annotation.Param;
public class OrderTool extends AbsToolProvider {
@ToolMapping(description = "根据订单 ID 查询订单状态")
public String getOrderStatus(@Param(description = "订单 ID") String orderId) {
// 模拟数据库查询
if ("ORD-1001".equals(orderId)) {
return "订单 ORD-1001:已发货,预计 7 月 7 日送达";
} else if ("ORD-1002".equals(orderId)) {
return "订单 ORD-1002:待处理,付款未确认";
}
return "未找到订单:" + orderId;
}
@ToolMapping(description = "根据商品 ID 查询库存")
public String checkInventory(@Param(description = "商品 SKU") String sku) {
if ("SKU-A100".equals(sku)) {
return "库存充足:42 件";
} else if ("SKU-B200".equals(sku)) {
return "库存紧张:仅剩 3 件";
}
return "未找到商品:" + sku;
}
}
第 2 步:构建 Agent
ReActAgent supportAgent = ReActAgent.of(chatModel)
.name("customer_support")
.role("客服支持 Agent——处理订单查询和库存检查。")
.defaultToolAdd(new OrderTool())
.maxTurns(8) // 最大推理步数
.autoRethink(true) // 卡住时自动重新思考
.retryConfig(3, 1000L) // 重试 3 次,间隔 1 秒
.modelOptions(options -> {
options.temperature(0.1); // 低温度,确定性决策
})
.build();
String result = supportAgent.prompt("客户 ORD-1002 想知道订单什么时候到,能帮忙查一下吗?")
.call()
.getContent();
System.out.println(result);
Agent 会:
- 意识到需要查
ORD-1002 - 调用
getOrderStatus("ORD-1002") - 读到结果:“待处理,付款未确认”
- 向客户解释:付款尚未确认,所以还未发货
5. 添加拦截器:可观测性
生产环境中,你需要看到 Agent 的思考过程。ReActInterceptor 提供了完整的生命周期钩子:
import org.noear.solon.ai.agent.react.ReActInterceptor;
import org.noear.solon.ai.agent.react.ReActTrace;
import org.noear.solon.ai.agent.react.task.ToolExchanger;
ReActAgent observableAgent = ReActAgent.of(chatModel)
.name("observable_agent")
.role("我帮你处理各种任务。")
.defaultToolAdd(new OrderTool())
.defaultInterceptorAdd(new ReActInterceptor() {
@Override
public void onAgentStart(ReActTrace trace) {
System.out.println("🤖 Agent 启动。提示词:" + trace.getOriginalPrompt().getUserContent());
}
@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());
}
@Override
public void onObservation(ReActTrace trace, ToolExchanger toolExchanger,
ChatMessage observation, Throwable error,
long durationMs) {
if (error != null) {
System.err.println("❌ 工具调用失败:" + error.getMessage());
} else {
System.out.println("✅ 工具结果返回,耗时 " + durationMs + "ms");
}
}
@Override
public void onAgentEnd(ReActTrace trace) {
System.out.println("✅ Agent 任务完成。");
}
})
.build();
这样你就有了 Agent 每次决策的完整审计轨迹。
6. 流式响应
对于长时间运行的任务,使用 stream() 获取实时输出:
agent.prompt("分析我们的 Top 10 商品,给我一份销售摘要。")
.stream()
.doOnNext(resp -> {
System.out.print(resp.getMessage().getContent());
})
.doOnComplete(() -> {
System.out.println("\n✅ 分析完成!");
})
.subscribe();
7. 进阶:单次调用选项
通过 .options() 可以为单次调用调整行为:
agent.prompt("分析这个复杂数据集,生成 JSON 报告。")
.session(mySession) // 复用已有会话
.options(o -> o
.maxTurns(15) // 复杂任务给更多步数
.planningMode(true) // 启用规划阶段
.temperature(0.3) // 平衡创造性与精确性
.outputSchema("{\"type\":\"object\",\"properties\":{...}}") // 结构化输出
.toolAdd(new ReportingTool()) // 临时添加一个工具
)
.call();
选项一览
| 分类 | 方法 | 说明 | 默认值 |
|---|---|---|---|
| 控制 | maxTurns(int) |
最大推理步数 | 8 |
| 控制 | autoRethink(boolean) |
自动重新思考 | false |
| 控制 | retryConfig(int, long) |
重试次数与间隔 | 3, 1000ms |
| 模型 | temperature(double) |
随机性(0-2) | 0.5 |
| 模型 | max_tokens(long) |
最大生成 Token | — |
| 工具 | toolAdd(FunctionTool) |
临时添加工具 | — |
| 工具 | talentAdd(Talent) |
添加技能模块 | — |
| 扩展 | interceptorAdd(interceptor) |
添加拦截器 | — |
8. 会话与轨迹(Sessions & Traces)
ReActAgent 的会话支持带记忆的长时间对话:
import org.noear.solon.ai.agent.session.InMemoryAgentSession;
import org.noear.solon.ai.agent.AgentSession;
// 创建或复用会话
AgentSession session = InMemoryAgentSession.of("user-session-123");
// 第一轮
String r1 = agent.prompt("帮我找找 50 元以下的商品")
.session(session)
.call()
.getContent();
// 第二轮(Agent 记得上下文)
String r2 = agent.prompt("最便宜的那个运费多少?")
.session(session)
.call()
.getContent();
// 查看轨迹
ReActTrace trace = agent.getTrace(session);
System.out.println("总步数:" + trace.getStepCount());
// 或获取格式化摘要
System.out.println(trace.getFormattedHistory());
Trace 对象提供:
- 完整的思考/行动/观察历史(
getFormattedHistory()) - 步数和指标(
getStepCount()、getMetrics()) - 工具调用参数和结果
- 原始提示词和会话(
getOriginalPrompt()、getSession())
9. 轻量模型的 STRUCTURED_TEXT 模式
不是所有模型都原生支持工具调用。ReActAgent 支持 Text ReAct 模式——它通过正则从模型输出的文本中提取 Action: {json} 标签来执行工具。这使得它兼容更小、更轻量的模型,适合边缘部署和对成本敏感的场景。
执行风格(ReActStyle)在构建时通过 ReActAgentConfig 配置,可选择 ReActStyle.NATIVE_TOOL(原生工具调用,默认)和轻量的 ReActStyle.STRUCTURED_TEXT(结构化文本)。使用 STRUCTURED_TEXT 模式时,Agent 从模型输出中解析 Action: {json} 标签并执行对应的工具。
完整示例:电商支持 Agent
可直接复制运行的完整代码:
import org.noear.solon.ai.agent.react.ReActAgent;
import org.noear.solon.ai.agent.react.ReActInterceptor;
import org.noear.solon.ai.agent.react.ReActTrace;
import org.noear.solon.ai.agent.react.task.ToolExchanger;
import org.noear.solon.ai.annotation.ToolMapping;
import org.noear.solon.ai.annotation.Param;
import org.noear.solon.ai.chat.ChatModel;
import org.noear.solon.ai.chat.tool.AbsToolProvider;
import org.noear.solon.ai.chat.message.ChatMessage;
public class ECommerceSupportApp {
public static void main(String[] args) throws Throwable {
// 1. 构建模型
ChatModel model = ChatModel.of("https://api.moark.com/v1/chat/completions")
.apiKey("${API_KEY}")
.model("Qwen3-32B")
.build();
// 2. 构建 Agent
ReActAgent agent = ReActAgent.of(model)
.name("ecommerce_support")
.role("电商客服支持 Agent")
.defaultToolAdd(new OrderTool())
.defaultToolAdd(new InventoryTool())
.defaultInterceptorAdd(new LoggingInterceptor())
.defaultInterceptorAdd(new ContextCompressionInterceptor(...)) //【可选】如果轮数过多,需要压缩上下文
.maxTurns(10)
.autoRethink(true)
.build();
// 3. 运行
String answer = agent.prompt(
"客户想下单 SKU-A100,但发现 ORD-1001 还没收到。查一下两个情况,给客户解释。"
).call().getContent();
System.out.println(answer);
}
}
// 工具
class OrderTool extends AbsToolProvider {
@ToolMapping(description = "根据订单 ID 查询订单状态")
public String getOrderStatus(@Param(description = "订单 ID") String orderId) {
return "ORD-1001:已发货";
}
}
class InventoryTool extends AbsToolProvider {
@ToolMapping(description = "根据 SKU 查询商品库存")
public String checkStock(@Param(description = "商品 SKU") String sku) {
return "SKU-A100:42 件库存充足";
}
}
// 拦截器
class LoggingInterceptor implements ReActInterceptor {
@Override
public void onThought(ReActTrace trace, String thought,
AssistantMessage msg) {
System.out.println("💭 " + thought);
}
@Override
public void onAction(ReActTrace trace, ToolExchanger tool) {
System.out.println("🛠️ " + tool.getToolName());
}
}
要点总结
- ReActAgent 遵循 思考→行动→观察 循环——推理、行动、学习
- 工具通过
@ToolMapping和@Param注解定义——就是普通的 POJO - 拦截器让你对 Agent 的决策过程有完整的可观测性
- 单次调用选项让你在不重建 Agent 的前提下灵活调整行为
- Text ReAct 模式兼容不支持原生工具调用的轻量模型
- 会话和轨迹支持带完整审计日志的持久化对话
更多推荐


所有评论(0)