🪟 Windows TippsThe Gemini desktop app is now available for Windows(11.09.2026 um 17:06 Uhr)
⚠️ Malware / Trojaner / VirenWindows 11 just dropped the tool ransomware abused, Microsoft says don’t restore WMIC(10.09.2026 um 20:11 Uhr)
⚠️ Malware / Trojaner / VirenVorsicht: Android-Malware verschlüsselt Ihre Handys und nimmt heimlich Fotos auf(11.09.2026 um 09:35 Uhr)
🕵️ SicherheitslückenMicrosoft geht endlich eines der nervigsten Probleme von Windows 11 an(11.09.2026 um 11:58 Uhr)
💾 IT Security ToolsSysinternals Suite(11.09.2026 um 12:00 Uhr)
🕵️ SicherheitslückenDefender 0-Day ShieldBreak (CVE-2026-69414) nicht sauber gepatcht - BornCity(11.09.2026 um 12:52 Uhr)
🪟 Windows TippsThe Gemini desktop app is now available for Windows(11.09.2026 um 17:06 Uhr)
⚠️ Malware / Trojaner / VirenWindows 11 just dropped the tool ransomware abused, Microsoft says don’t restore WMIC(10.09.2026 um 20:11 Uhr)
⚠️ Malware / Trojaner / VirenVorsicht: Android-Malware verschlüsselt Ihre Handys und nimmt heimlich Fotos auf(11.09.2026 um 09:35 Uhr)
🕵️ SicherheitslückenMicrosoft geht endlich eines der nervigsten Probleme von Windows 11 an(11.09.2026 um 11:58 Uhr)
💾 IT Security ToolsSysinternals Suite(11.09.2026 um 12:00 Uhr)
🕵️ SicherheitslückenDefender 0-Day ShieldBreak (CVE-2026-69414) nicht sauber gepatcht - BornCity(11.09.2026 um 12:52 Uhr)

🔧 Programmierung 🕛 vor 2 Monaten 9 Min Lesezeit
0

Solon 4.0 ReActAgent: A Practical Guide to Building AI Agents That Think and Act

↗ Quelle (dev.to)
🗣️ Stimme:
📑 Inhaltsübersicht

If you've ever wanted an AI that doesn't just chat but actually does things — queries databases, calls APIs, makes decisions, and learns from results — you're in the right place.



In this tutorial, I'll show you how to build production-ready AI agents using Solon 4.0's ReActAgent. By the end, you'll have built an agent that can reason through complex problems, use external tools, and adapt its behavior based on real-world feedback.









What Makes ReActAgent Different?



Traditional LLMs are great at generating text, but they hit a wall when they need to interact with the real world — checking a database, fetching live data, or performing calculations.



ReActAgent (Reason + Act) breaks through that wall. It implements a cognitive loop:




CODE
Thought → Action → Observation → (repeat or finish)






The agent thinks about what to do next, acts by calling a tool, observes the result, and decides whether to continue or deliver the final answer.



This isn't just theory. Solon's ReActAgent has been used in production for automated customer support, intelligent data analysis, and multi-step workflow automation.









1. Adding the Dependency



First, add the solon-ai-agent module to your project:




CODE
<dependency>
<groupId>org.noear</groupId>
<artifactId>solon-ai-agent</artifactId>
</dependency>







Note: If you're using Solon's parent POM, the version is managed automatically. Otherwise, use the latest Solon version.










2. Building a ChatModel (The Agent's Brain)



Every agent needs a "brain" — a ChatModel that powers reasoning. Let's build one using the fluent API:




CODE
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();






You can also configure it via YAML and inject it:




CODE
solon.ai.chat:
demo:
apiUrl: "http://127.0.0.1:11434/api/chat"
provider: "ollama"
model: "llama3.2"









CODE
@Inject("${solon.ai.chat.demo}")
ChatConfig chatConfig;

ChatModel chatModel = ChatModel.of(chatConfig).build();












3. Hello World: Your First ReActAgent



Let's start simple. Create a tool and a basic agent:




CODE
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. Define a tool
public class TimeTool extends AbsToolProvider {
@ToolMapping(description = "Get the current date and time")
public String getCurrentTime() {
return LocalDateTime.now().toString();
}
}

// 2. Build and run the 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("You are a helpful assistant that can check the time and date.")
.defaultToolAdd(new TimeTool())
.build();

String response = agent.prompt("What time is it right now?")
.call()
.getContent();

System.out.println(response);
}
}






When you run this, the agent will:





  1. Think: "The user wants to know the time. I have a getCurrentTime tool."


  2. Act: Call getCurrentTime().


  3. Observe: Get the timestamp.


  4. Respond: "The current time is 2026-07-04T14:30:22..."









4. A Real-World Example: Customer Support Agent



Let's build something more practical — a support agent that can query an order database and check inventory.






Step 1: Define the Tools






CODE
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 = "Query order status by order ID")
public String getOrderStatus(@Param(description = "The order ID") String orderId) {
// Simulate database lookup
if ("ORD-1001".equals(orderId)) {
return "Order ORD-1001: SHIPPED, estimated delivery July 7";
} else if ("ORD-1002".equals(orderId)) {
return "Order ORD-1002: PENDING, payment not confirmed";
}
return "Order not found: " + orderId;
}

@ToolMapping(description = "Check product inventory by product ID")
public String checkInventory(@Param(description = "The product SKU") String sku) {
// Simulate inventory check
if ("SKU-A100".equals(sku)) {
return "In stock: 42 units";
} else if ("SKU-B200".equals(sku)) {
return "Low stock: 3 units remaining";
}
return "Product not found: " + sku;
}
}









Step 2: Build the Agent with Configuration






CODE
ReActAgent supportAgent = ReActAgent.of(chatModel)
.name("customer_support")
.role("Customer Support Agent — you handle order inquiries and inventory checks.")
.defaultToolAdd(new OrderTool())
.maxTurns(8) // Max reasoning steps
.autoRethink(true) // Auto-rethink when stuck
.retryConfig(3, 1000L) // Retry 3 times, 1s delay
.modelOptions(options -> {
options.temperature(0.1); // Low temperature for deterministic decisions
})
.build();

String result = supportAgent.prompt("Customer ORD-1002 wants to know when their order will arrive. Can you check?")
.call()
.getContent();

System.out.println(result);






The agent will:




  1. Realize it needs to check ORD-1002

  2. Call getOrderStatus("ORD-1002")

  3. Read the result: "PENDING, payment not confirmed"

  4. Explain to the customer that payment hasn't been confirmed yet









5. Adding Interceptors for Observability



In production, you need visibility into what your agent is thinking. ReActInterceptor gives you lifecycle hooks:




CODE
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("I help with various tasks.")
.defaultToolAdd(new OrderTool())
.defaultInterceptorAdd(new ReActInterceptor() {

@Override
public void onAgentStart(ReActTrace trace) {
System.out.println("🤖 Agent started. Prompt: " + trace.getOriginalPrompt().getUserContent());
}

@Override
public void onThought(ReActTrace trace, String thoughtContent,
AssistantMessage assistantMessage) {
System.out.println("💭 Thinking: " + thoughtContent);
}

@Override
public void onAction(ReActTrace trace, ToolExchanger toolExchanger) {
System.out.println("🛠️ Tool: " + toolExchanger.getToolName()
+ ", args: " + toolExchanger.getArgs());
}

@Override
public void onObservation(ReActTrace trace, ToolExchanger toolExchanger,
ChatMessage observation, Throwable error,
long durationMs) {
if (error != null) {
System.err.println("❌ Tool failed: " + error.getMessage());
} else {
System.out.println("✅ Tool result in " + durationMs + "ms");
}
}

@Override
public void onAgentEnd(ReActTrace trace) {
System.out.println("✅ Agent finished.");
}
})
.build();






This gives you a full audit trail of every decision your agent makes.









6. Streaming Responses



For long-running tasks, use stream() to get real-time output:




CODE
agent.prompt("Analyze our top 10 products and give me a sales summary.")
.stream()
.doOnNext(resp -> {
System.out.print(resp.getMessage().getContent());
})
.doOnComplete(() -> {
System.out.println("\n✅ Analysis complete!");
})
.subscribe();












7. Advanced: Per-Call Options



You can fine-tune behavior for individual calls using .options():




CODE
agent.prompt("Analyze this complex dataset and generate a JSON report.")
.session(mySession) // Reuse an existing session
.options(o -> o
.maxTurns(15) // More turns for complex tasks
.planningMode(true) // Enable planning phase
.temperature(0.3) // Balance creativity and precision
.outputSchema("{\"type\":\"object\",\"properties\":{...}}") // Structured output
.toolAdd(new ReportingTool()) // Add temporary tool for this call
)
.call();









Available Options at a Glance






























































Category Method Description Default
Control maxTurns(int) Max reasoning steps 8
Control autoRethink(boolean) Enable auto-rethink false
Control retryConfig(int, long) Retry count & delay 3, 1000ms
Model temperature(double) Randomness (0-2) 0.5
Model max_tokens(long) Max tokens to generate
Tools toolAdd(FunctionTool) Add tool temporarily
Tools talentAdd(Talent) Add talent/skill
Extension interceptorAdd(interceptor) Add interceptor








8. Working with Sessions and Traces



ReActAgent sessions enable long-running conversations with memory:




CODE
import org.noear.solon.ai.agent.session.InMemoryAgentSession;
import org.noear.solon.ai.agent.AgentSession;

// Create or reuse a session
AgentSession session = InMemoryAgentSession.of("user-session-123");

// First turn
String r1 = agent.prompt("Find me products under $50")
.session(session)
.call()
.getContent();

// Second turn (agent remembers context)
String r2 = agent.prompt("What's the shipping time for the cheapest one?")
.session(session)
.call()
.getContent();

// Inspect the trace
ReActTrace trace = agent.getTrace(session);
System.out.println("Total steps: " + trace.getStepCount());

// Or get a formatted summary
System.out.println(trace.getFormattedHistory());






The trace object gives you:




  • Complete thought/action/observation history (getFormattedHistory())

  • Step count and metrics (getStepCount(), getMetrics())

  • Tool call arguments and results

  • Original prompt and session (getOriginalPrompt(), getSession())









9. Text Mode for Lightweight Models



Not all models support native tool calls. ReActAgent supports Text ReAct mode — it uses regex to extract Action: {json} tags from the model's text output. This makes it compatible with smaller, lighter models that don't have native tool-call support — perfect for edge deployments and cost-sensitive scenarios.



The execution style (ReActStyle) is configured at build time through ReActAgentConfig, choosing between ReActStyle.NATIVE (OpenAI-style tool_calls, default) and the lightweight ReActStyle.TEXT approach. When using Text mode, the agent parses Action: {json} tags from the model's output and executes the corresponding tool.









Complete Example: E-Commerce Support Agent



Here's a full, copy-paste-ready example:




CODE
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. Build the model
ChatModel model = ChatModel.of("https://api.moark.com/v1/chat/completions")
.apiKey("${API_KEY}")
.model("Qwen3-32B")
.build();

// 2. Build the agent
ReActAgent agent = ReActAgent.of(model)
.name("ecommerce_support")
.role("E-commerce Support Agent")
.defaultToolAdd(new OrderTool())
.defaultToolAdd(new InventoryTool())
.defaultInterceptorAdd(new LoggingInterceptor())
.maxTurns(10)
.autoRethink(true)
.build();

// 3. Run
String answer = agent.prompt(
"Customer wants to order SKU-A100 but saw ORD-1001 hasn't arrived yet. " +
"Check both and explain the situation."
).call().getContent();

System.out.println(answer);
}
}

// Tools
class OrderTool extends AbsToolProvider {
@ToolMapping(description = "Query order status by order ID")
public String getOrderStatus(@Param(description = "Order ID") String orderId) {
// Your database logic here
return "ORD-1001: SHIPPED";
}
}

class InventoryTool extends AbsToolProvider {
@ToolMapping(description = "Check product inventory by SKU")
public String checkStock(@Param(description = "Product SKU") String sku) {
// Your inventory logic here
return "SKU-A100: 42 units in stock";
}
}

// Interceptor
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());
}
}












Key Takeaways





  1. ReActAgent follows a Thought → Action → Observation loop — it reasons, acts, and learns.


  2. Tools are defined with @ToolMapping and @Param annotations — simple POJOs.


  3. Interceptors give you full observability into the agent's decision process.


  4. Per-call options let you fine-tune behavior without rebuilding the agent.


  5. Text ReAct mode works with lightweight models that don't support native tool calls.


  6. Sessions and Traces enable persistent conversations with full audit trails.



Solon's ReActAgent brings production-grade AI agent capabilities to the Java ecosystem with minimal boilerplate. The same framework design philosophy — restraint, efficiency, openness — applies here: you get powerful agent capabilities without framework lock-in.






Want to learn more? Check out the .

Vollständiger Original-Bericht
Ausführliche Details, Code-Beispiele & Hersteller-Stellungnahme auf dev.to.
↗ Original-Artikel auf dev.to lesen
Wie bewertest du diesen Beitrag?
1 Klick Feedback
Teilen mit Netzwerk & Team:

Community-Analysen & Experten-Meinungen 0

Verfasse deine eigene Analyse, teile Workarounds oder diskutiere diesen Vorfall im Blog.
Noch keine Community-Analyse verfasst. Markiere einen Textabschnitt oder klicke oben auf Eigene Analyse verfassen“!
Community Pulse: Relevanz-Einschätzung
1 Klick Experten-Votum
🔴 Akute Relevanz 0%
🟡 In Evaluierung 0%
🟢 Keine Auswirkung 0%
Spannende Innovation 0%
Verwandte Story-Cluster & Quellen (Vektor-KI)
Port 8095 Engine
1 Quelle
The Gemini desktop app is now available for Windows
1 Quelle
Windows 11 just dropped the tool ransomware abused, Microsoft says don’t restore WMIC
1 Quelle
Vorsicht: Android-Malware verschlüsselt Ihre Handys und nimmt heimlich Fotos auf
Ähnliche Beiträge
🔍 Verwandte News

Auch interessante Nachrichten Solon 4.0 ReActAgent: A Practical Guide to Building AI Agents That Think and Act

Thematisch verwandte Begriffe: Solon, ReActAgent, Practical, Guide · 6 Treffer

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...