Why Jack‑of‑All Agents Fail – Router Delegation and Subagents in AgentScope Java

The article explains AgentScope 2.0’s “agent‑as‑tool” philosophy, showing how a Router agent can dynamically delegate tasks to specialist ReActAgents via @Tool methods, and how HarnessAgent’s Subagent feature enables long‑running, user‑direct interactions, with concrete Java code illustrating both patterns.

Tech Ocean
Tech Ocean
Tech Ocean
Why Jack‑of‑All Agents Fail – Router Delegation and Subagents in AgentScope Java

AgentScope 2.0 abandons the fixed Pipeline/DAG model of version 1 and adopts an “agent‑as‑tool” approach, where an agent can be invoked as a tool by another agent.

Router delegation: each specialist agent is wrapped in a method annotated with @Tool. Inside the method a dedicated ReActAgent (e.g., PythonAgent, PoemAgent) is built and its call method returns a Msg. The Router agent uses a large‑model prompt to decide, based on user intent, which specialist tool to invoke.

public class SpecialistTools {
    @Tool(name = "generate_python_code", description = "Generate Python code from a request")
    public Msg generatePython(@ToolParam(name = "demand", description = "Python code requirement") String demand) {
        ReActAgent python = ReActAgent.builder()
            .name("PythonAgent")
            .sysPrompt("You are a Python expert, generate code according to the demand.")
            .model("dashscope:qwen-max")
            .toolkit(new Toolkit())
            .build();
        return python.call(new UserMessage(demand)).block();
    }

    @Tool(name = "generate_poem", description = "Write a poem from a request")
    public Msg generatePoem(@ToolParam(name = "demand", description = "Poem requirement") String demand) {
        ReActAgent poet = ReActAgent.builder()
            .name("PoemAgent")
            .sysPrompt("You are a poet, write a poem according to the demand.")
            .model("dashscope:qwen-max")
            .toolkit(new Toolkit())
            .build();
        return poet.call(new UserMessage(demand)).block();
    }
}

The router is assembled with the toolkit and decides at runtime which tool to call:

Toolkit toolkit = new Toolkit();
toolkit.registerTool(new SpecialistTools());

ReActAgent router = ReActAgent.builder()
    .name("Router")
    .sysPrompt("You are a routing agent, dispatch user requests to the correct expert tool.")
    .model("dashscope:qwen-max")
    .toolkit(toolkit)
    .build();

// User asks for a quicksort implementation → router automatically invokes generate_python_code
router.call(new UserMessage("Help me write a Python quicksort")).block();

A key detail is that a @Tool method now returns a Msg (the specialist agent’s reply) instead of a plain String, allowing the tool output to be another agent’s product.

Subagent capability: For longer‑running or interactive scenarios, HarnessAgent can spawn a child agent that is optionally exposed to the user via expose_to_user=true. The child agent communicates through a Channel, emitting a SubagentExposedEvent that carries a subagentId. The client can then bypass the main agent and talk directly to the sub‑agent.

HarnessAgent orchestrator = HarnessAgent.builder()
    .name("orchestrator")
    .sysPrompt("You are an orchestrator. When research is needed, spawn a researcher sub‑agent with expose_to_user=true.")
    .model("dashscope:qwen-plus")
    .build();

ChatUiChannel chat = orchestrator.channel(ChatUiChannel.create());
AtomicReference<String> subId = new AtomicReference<>();

chat.sendStream(SendOptions.userId("user-1"), "Help me research recent AI trends")
    .doOnNext(event -> {
        if (event instanceof SubagentExposedEvent e) {
            subId.set(e.getSubagentId()); // obtain sub‑agent ID
        }
    })
    .blockLast();

if (subId.get() != null) {
    chat.sendToSubagentStream(subId.get(), "Explain the key LLM agent concepts")
        .doOnNext(e -> {
            if (e instanceof TextBlockDeltaEvent te) System.out.print(te.getDelta());
        })
        .blockLast();
}

Choosing between the two paradigms:

Router delegation (@Tool) – Simple division of labor; one‑shot request‑response; specialist agents are instantiated inside the tool method.

Subagent (Harness) – Supports long‑running, stateful interactions; the user can continue chatting with the sub‑agent directly; declaration can be done via a Markdown file.

Key concepts summarized:

Agent as tool – wrap specialist agents with @Tool and let the router dynamically delegate.

Router delegation – @Tool method creates a ReActAgent, calls it, and returns a Msg.

Subagent – HarnessAgent spawns a child agent, exposes its ID through SubagentExposedEvent, and enables direct user‑to‑sub‑agent communication via a channel.

ChatUiChannel – gateway for streaming events, suitable for Web SSE.

Relevant links:

AgentScope Java documentation: https://java.agentscope.io/v2/zh/intro.html
Multi‑agent documentation: https://java.agentscope.io/v1/zh/docs/multi-agent/overview.html
GitHub repository: https://github.com/agentscope-ai/agentscope-java
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.

javaMulti-AgenttoolAgentScopeReActAgentsubagentRouter Delegation
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.