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.
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-javaSigned-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Tech Ocean
Focused on AI programming, sharing ready-to-use development efficiency solutions.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
