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) | 添加拦截器 | — |