Skip to main content

Overview

The ReAct (Reasoning + Acting) pattern combines LLM reasoning with tool execution. This comprehensive example demonstrates:
  • Creating ReAct agents with custom tools
  • Using built-in tools (calculator, datetime, string, JSON)
  • Chain agents for sequential workflows
  • Parallel agents for concurrent execution
  • MapReduce patterns for distributed processing
  • AutoAgent for automatic strategy selection

What You’ll Learn

  • Building custom tools with ReActTool trait
  • Configuring ReAct agents with ReActAgent::builder()
  • Implementing tool execution logic
  • Chaining multiple agents together
  • Parallel multi-agent execution
  • Using the Actor model for concurrent agents

Prerequisites

  • Rust 1.75 or higher
  • OpenAI API key
  • Understanding of async/await

Source Code Overview

This is a large example with 960+ lines. Here are the key components:
use async_trait::async_trait;
use mofa_sdk::react::ReActTool;
use serde_json::Value;

/// Web search tool (mock implementation)
struct WebSearchTool;

#[async_trait]
impl ReActTool for WebSearchTool {
    fn name(&self) -> &str {
        "web_search"
    }

    fn description(&self) -> &str {
        "Search the web for information. Input should be a search query."
    }

    fn parameters_schema(&self) -> Option<Value> {
        Some(serde_json::json!({
            "type": "object",
            "properties": {
                "query": {
                    "type": "string",
                    "description": "The search query"
                }
            },
            "required": ["query"]
        }))
    }

    async fn execute(&self, input: &str) -> Result<String, String> {
        let query = if let Ok(json) = serde_json::from_str::<Value>(input) {
            json.get("query")
                .and_then(|v| v.as_str())
                .unwrap_or(input)
                .to_owned()
        } else {
            input.to_owned()
        };

        // Mock search results
        let results = match query.to_lowercase().as_str() {
            q if q.contains("rust") => {
                "Rust is a systems programming language focused on safety..."
            }
            _ => "Search results found..."
        };

        Ok(results.to_string())
    }
}

Running the Example

1
Set API Key
2
export OPENAI_API_KEY="your-api-key"

# Optional: Custom endpoint
export OPENAI_BASE_URL="http://localhost:11434/v1"
export OPENAI_MODEL="gpt-4"
3
Run All Examples
4
cd examples/react_agent
cargo run
5
Run Specific Example
6
# Run basic example
cargo run -- 1

# Run actor model example
cargo run -- 2

# Run chain example
cargo run -- chain

# Run parallel example
cargo run -- parallel

Example Scenarios

The example includes 10 different scenarios:
Simple agent with web search and calculator tools.Demonstrates: Tool selection, reasoning steps, final answer
ReAct agent running in an actor system.Demonstrates: Concurrent execution, status monitoring, message passing
Automatically selects between direct response and ReAct reasoning.Demonstrates: Strategy selection, performance optimization
Using calculator, string, JSON, datetime tools.Demonstrates: Tool ecosystem, composition
Stream reasoning steps in real-time.Demonstrates: Async streaming, progress updates
Combining custom and built-in tools.Demonstrates: Tool integration, extensibility
Sequential pipeline: Researcher → Writer → Editor.Demonstrates: Multi-stage processing, data flow
Concurrent expert analysis from multiple perspectives.Demonstrates: Parallel execution, result aggregation
Parallel agents with LLM-based result synthesis.Demonstrates: Intelligent aggregation, synthesis
Distribute tasks, process in parallel, reduce results.Demonstrates: Distributed processing, scalability

Key Concepts

ReAct Loop

The ReAct agent follows a reasoning loop:

Built-in Tools

MoFA provides several ready-to-use tools:

Calculator

Evaluate mathematical expressions
calculator()

DateTime

Get current time and date
datetime_tool()

String

String manipulation operations
string_tool()

JSON

Parse and manipulate JSON
json_tool()

Tool Implementation

To create a custom tool:
use async_trait::async_trait;
use mofa_sdk::react::ReActTool;

struct MyTool;

#[async_trait]
impl ReActTool for MyTool {
    fn name(&self) -> &str {
        "my_tool"
    }

    fn description(&self) -> &str {
        "Description of what the tool does"
    }

    fn parameters_schema(&self) -> Option<Value> {
        Some(serde_json::json!({
            "type": "object",
            "properties": {
                "param": {"type": "string"}
            },
            "required": ["param"]
        }))
    }

    async fn execute(&self, input: &str) -> Result<String, String> {
        // Tool logic here
        Ok(format!("Result: {}", input))
    }
}

Configuration Options

Agent Builder

let agent = ReActAgent::builder()
    .with_llm(llm)                    // LLM for reasoning
    .with_tools(tools)                 // Available tools
    .with_max_iterations(8)            // Max reasoning steps
    .with_temperature(0.7)             // LLM temperature
    .with_system_prompt(prompt)        // Custom instructions
    .with_verbose(true)                // Log reasoning steps
    .build_async()
    .await?;

Chain Configuration

let chain = chain_agents(agents)
    .with_transform(|output, next| {
        format!("Previous: {}\nNext: {}", output, next)
    })
    .with_verbose(true);

Parallel Configuration

let parallel = ParallelAgent::new()
    .add("agent1", agent1)
    .add("agent2", agent2)
    .with_aggregation(AggregationStrategy::Concatenate)
    .with_verbose(true);

Expected Output

==========================================================
Example 1: Basic ReAct Agent
==========================================================

Task: What is Rust programming language and when was it first released?

[Step 1] Thought: I need to search for information about Rust
[Step 2] Action: web_search("Rust programming language")
[Step 3] Observation: Rust is a systems programming language...
[Step 4] Thought: Now I have enough information
[Step 5] Final Answer: Rust is a systems programming language that...

--- Result ---
Success: true
Iterations: 5
Duration: 3421ms

Final Answer:
Rust is a systems programming language focused on safety, concurrency, 
and performance. It was first released in stable version 1.0 on May 15, 2015.

Common Use Cases

Research Assistant

Search, analyze, and summarize information

Code Analysis

Analyze codebases and suggest improvements

Data Processing

Transform and analyze data with tools

Task Automation

Automate complex multi-step workflows

Troubleshooting

Problem: Tool returns an errorSolution: Implement error handling in tools:
async fn execute(&self, input: &str) -> Result<String, String> {
    match self.do_work(input) {
        Ok(result) => Ok(result),
        Err(e) => Err(format!("Tool error: {}", e))
    }
}
Problem: Agent hits iteration limitSolution: Increase max_iterations or improve prompts:
.with_max_iterations(10)
.with_system_prompt("Be concise and direct")
Problem: Agent takes too longSolution: Use AutoAgent or reduce iterations:
let auto_agent = AutoAgent::new(llm, react_agent)
    .with_auto_mode(true);

Next Steps

Multi-Agent

Coordinate multiple ReAct agents

Workflow

Orchestrate complex workflows

Custom Tools

Build advanced custom tools

ReAct Guide

Deep dive into ReAct pattern

Build docs developers (and LLMs) love