Why ReActAgent Beats a Single LLM Call: Reasoning + Acting Loop Explained

The article breaks down the ReAct reasoning‑acting loop that powers AgentScope's ReActAgent, details its builder parameters, and compares the synchronous call() method with the streaming stream() approach, showing when each should be used for backend processing or interactive UI.

Tech Ocean
Tech Ocean
Tech Ocean
Why ReActAgent Beats a Single LLM Call: Reasoning + Acting Loop Explained

1. ReAct = Reasoning While Acting

Traditional QA follows a "ask once, answer once" pattern, whereas ReAct alternates Reasoning and Acting . The model first thinks (e.g., "I need the weather"), then acts by invoking a tool, observes the tool's result, and repeats until a final answer is produced. This loop enables agents to decompose tasks, call tools, and dynamically adjust based on intermediate results. The official diagram (shown below) visualises the cycle, which runs up to maxIters times (default 10) to avoid infinite loops.

ReAct reasoning‑acting loop
ReAct reasoning‑acting loop

2. Constructing a ReActAgent – Full Parameter Overview

name

(required): the agent’s identifier. model (required): the large language model to use. sysPrompt: system prompt that defines persona and rules. toolkit: toolbox of tools (covered in Day 4). maxIters: maximum reasoning iterations, default 10. stateStore / defaultSessionId: state persistence (Day 5). hooks: hooks before/after Reasoning, Acting, and Summary. modelExecutionConfig / toolExecutionConfig: timeout and retry settings for model and tool calls.

3. call() : Get the Complete Reply at Once

The simplest invocation blocks until the model finishes and returns a Mono<Msg>. After calling .block(), getTextContent() extracts the text. This method is suited for backend batch jobs or internal services where real‑time display is unnecessary, but the user experiences a noticeable wait for long responses.

ReActAgent agent = ReActAgent.builder()
        .name("Assistant")
        .sysPrompt("你是一个简洁的助手。")
        .model("dashscope:qwen-plus")
        .toolkit(new Toolkit())
        .build();

Msg response = agent.call(new UserMessage("你好,用一句话自我介绍")).block();
System.out.println(response.getTextContent());

4. stream() : Incremental Token‑by‑Token Output

stream()

returns a Flux<Event>. Each event carries either a REASONING chunk, a TOOL_RESULT, or a HINT. By configuring StreamOptions, developers can select which event types to receive, enable incremental delivery, and include reasoning tokens for a type‑writer effect.

Toolkit toolkit = new Toolkit(); // register tools in Day 4
ReActAgent agent = ReActAgent.builder()
        .name("StreamingAgent")
        .sysPrompt("你是一个带数学工具的助手。")
        .model(DashScopeChatModel.builder()
                .apiKey(System.getenv("DASHSCOPE_API_KEY"))
                .modelName("qwen-max")
                .stream(true)
                .formatter(new DashScopeChatFormatter())
                .build())
        .toolkit(toolkit)
        .build();

StreamOptions opts = StreamOptions.builder()
        .eventTypes(EventType.REASONING, EventType.TOOL_RESULT)
        .incremental(true)
        .includeReasoningChunk(true)
        .build();

agent.stream(List.of(new UserMessage("3 乘以 7 等于几?")), opts, null)
        .doOnNext(event -> {
            if (event.getType() == EventType.REASONING && !event.isLast()) {
                System.out.print(event.getMessage().getTextContent());
            } else if (event.getType() == EventType.TOOL_RESULT && event.isLast()) {
                System.out.println("
[工具结果] " + event.getMessage().getTextContent());
            }
        })
        .blockLast();

5. Choosing Between call() and stream()

Return type : call()Mono<Msg>; stream()Flux<Event>.

Experience : call() waits for the full response; stream() delivers tokens/events in real time.

Suitable scenarios : call() for batch processing or internal APIs; stream() for chat UIs, Web SSE, or long replies where users benefit from incremental display.

Text extraction : call() uses resp.getTextContent(); stream() requires aggregating events.

In short: use stream() for human‑facing interfaces and call() for programmatic consumption.

6. Day 3 Summary

ReAct loop: Reason → Act → Observe repeats until an answer is formed. maxIters defaults to 10 to prevent endless loops. call() returns a complete Msg synchronously – simple but blocks. stream() (or streamEvents()) yields a Flux<Event> for incremental output.

Event types: REASONING, TOOL_RESULT, HINT. StreamOptions controls which events appear and whether they are incremental.

Next up (Day 4) will show how to equip the Act step with custom tools using the @Tool annotation and explore permission control via ToolBase.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

javaAI agentsLLMReActStreamingTool CallingAgentScope
Tech Ocean
Written by

Tech Ocean

Focused on AI programming, sharing ready-to-use development efficiency solutions.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.