Skip to content

Introduce multiagent pattern practices and docs.#910

Open
chickenlj wants to merge 8 commits intoagentscope-ai:mainfrom
chickenlj:multiagent-patterns
Open

Introduce multiagent pattern practices and docs.#910
chickenlj wants to merge 8 commits intoagentscope-ai:mainfrom
chickenlj:multiagent-patterns

Conversation

@chickenlj
Copy link
Collaborator

Multi-agent systems coordinate specialized agents or components to handle complex workflows. Not every complex task needs multiple agents—a single agent with the right tools and prompt can often suffice.

This pull request introduces several supervisor, handoffs, routing, etc. multiagent patterns that are built on Spring AI Alibaba Graph and AgentScope.

Examples

1. Supervisor

  • Location: agentscope-examples/multiagent-patterns/supervisor
  • Description: A central supervisor ReActAgent exposes calendar and email as tools (schedule_event, manage_email), invokes them from user requests, and combines results. Specialist capabilities are implemented as AgentScope ReActAgents with Model and registered via Toolkit.registration().subAgent().
  • Run: ./mvnw -pl agentscope-examples/multiagent-patterns/supervisor spring-boot:run. Optionally set supervisor.run-examples=true to run two sample conversations (calendar + email) on startup.

2. Pipeline

  • Location: agentscope-examples/multiagent-patterns/pipeline
  • Description: Uses Spring AI Alibaba SequentialAgent, ParallelAgent, and LoopAgent with AgentScopeAgent sub-agents and AgentScope Model (DashScopeChatModel).
    • SequentialAgent (sequential_sql_agent): Natural language → SQL generation → SQL scoring.
    • ParallelAgent (parallel_research_agent): One topic researched in parallel from technology, finance, and market angles; results merged into one report.
    • LoopAgent (loop_sql_refinement_agent): Loops “generate SQL → score” until score > 0.5.
  • Run: ./mvnw -pl agentscope-examples/multiagent-patterns/pipeline spring-boot:run. Optionally set pipeline.runner.enabled=true to run all three pipeline demos on startup.

3. Routing

  • Location: agentscope-examples/multiagent-patterns/routing
  • Description: Classifies the user query, invokes specialist AgentScopeAgents (GitHub, Notion, Slack) in parallel, and synthesizes results into one answer.
    • Simple: AgentScopeRoutingAgent + RouterService (invoke router then synthesize).
    • Graph: StateGraph with preprocess → routing node (LlmRoutingAgent) → postprocess.
  • Run: ./mvnw -pl agentscope-examples/multiagent-patterns/routing spring-boot:run. Optionally set routing.runner.enabled=true or routing-graph.runner.enabled=true for the corresponding demo.

4. Skills (progressive disclosure)

  • Location: agentscope-examples/multiagent-patterns/skills
  • Description: A single SQL assistant ReActAgent loads skills from classpath skills/ (e.g. sales_analytics, inventory_management) via AgentScope ClasspathSkillRepository and SkillBox. The model sees only skill descriptions first and loads full SKILL.md on demand with the read_skill tool.
  • Run: ./mvnw -pl agentscope-examples/multiagent-patterns/skills spring-boot:run. Optionally set skills.runner.enabled=true to run one sample query on startup.

5. Subagent

  • Location: agentscope-examples/multiagent-patterns/subagent
  • Description: A central orchestrator (AgentScopeAgent) delegates work to multiple sub-agents (e.g. codebase-explorer, web-researcher, dependency-analyzer) via Task / TaskOutput tools. Sub-agents can be defined in Markdown or in code (ReActAgent/AgentScopeAgent); the orchestrator is exposed via a CompiledGraph.
  • Run: ./mvnw -pl agentscope-examples/multiagent-patterns/subagent spring-boot:run. Optionally set subagent.run-interactive=true for interactive chat.

6. Handoffs

  • Location: agentscope-examples/multiagent-patterns/handoffs
  • Description: Sales and support AgentScopeAgents as separate graph nodes. Tools (e.g. transfer_to_support, transfer_to_sales) update state (e.g. active_agent); the graph routes between nodes based on that state for role handoffs over multiple turns.
  • Run: ./mvnw -pl agentscope-examples/multiagent-patterns/handoffs spring-boot:run. Optionally set agentscope.runner.enabled=true for the demo. Default port 8089; can be used with the chat UI.

7. Workflow (custom)

  • Location: agentscope-examples/multiagent-patterns/workflow
  • Description: Custom multi-step flows with StateGraph; two sub-examples:
    • RAG (workflow.rag.enabled=true): Query → rewrite → retrieve → prepare → Agent (ReActAgent + context) → response.
    • SQL (workflow.sql.enabled=true): list_tables → get_schema → generate_query (AgentScopeAgent + SQL tools), using H2 in-memory with a Chinook-like schema.
  • Run:
    • RAG: ./mvnw -pl agentscope-examples/multiagent-patterns/workflow spring-boot:run -Dspring-boot.run.arguments="--workflow.rag.enabled=true --workflow.runner.enabled=true"
    • SQL: Same, but use --workflow.sql.enabled=true instead of --workflow.rag.enabled=true.

@chickenlj chickenlj requested review from a team and Copilot March 10, 2026 11:19
@cla-assistant
Copy link

cla-assistant bot commented Mar 10, 2026

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces seven multi-agent pattern examples for AgentScope (Supervisor, Pipeline, Routing, Skills, Subagent, Handoffs, and Workflow), along with corresponding documentation updates in both English and Chinese.

Changes:

  • Added seven new Spring Boot example modules under agentscope-examples/multiagent-patterns/ demonstrating various multi-agent orchestration patterns built on Spring AI Alibaba Graph and AgentScope.
  • Added new documentation pages in docs/en/multi-agent/ and docs/zh/multi-agent/ covering each pattern, plus a new agent-as-tool.md feature doc.
  • Updated docs/_toc.yml to reorganize the Multi Agent section and add the new pattern pages, and corrected cross-reference links in existing docs.

Reviewed changes

Copilot reviewed 137 out of 139 changed files in this pull request and generated 29 comments.

Show a summary per file
File Description
agentscope-examples/pom.xml Registers the 7 new multiagent-patterns submodules
agentscope-examples/multiagent-patterns/supervisor/ Supervisor pattern: central ReActAgent delegates calendar/email tasks as sub-agent tools
agentscope-examples/multiagent-patterns/pipeline/ Pipeline patterns: SequentialAgent, ParallelAgent, LoopAgent with AgentScopeAgent sub-agents
agentscope-examples/multiagent-patterns/routing/ Routing pattern: classifies queries, invokes GitHub/Notion/Slack specialist agents in parallel
agentscope-examples/multiagent-patterns/skills/ Skills (progressive disclosure) pattern: SQL assistant loads skill schemas on demand
agentscope-examples/multiagent-patterns/subagent/ Subagent pattern: orchestrator delegates to Markdown/API-defined sub-agents via Task tools
agentscope-examples/multiagent-patterns/workflow/ Custom workflow pattern: RAG and SQL agents using StateGraph with H2 in-memory DB
agentscope-examples/multiagent-patterns/handoffs/ Handoffs pattern: sales/support agents with state-driven routing between graph nodes
agentscope-examples/quarkus/src/main/resources/application.properties Adds native build configuration
docs/_toc.yml Adds new multi-agent pattern pages to TOC, reorganizes the Multi Agent section
docs/en/task/agent-as-tool.md New English documentation for Agent as Tool feature
docs/en/multi-agent/supervisor.md, skills.md New English pattern documentation
docs/zh/multi-agent/supervisor.md, skills.md New Chinese pattern documentation
docs/en/multi-agent/multiagent-debate.md, docs/zh/multi-agent/multiagent-debate.md Updated links to new patterns
docs/en/task/tool.md, docs/zh/task/tool.md Fixed relative links to agent-as-tool.md
docs/en/task/msghub.md, docs/zh/task/msghub.md Fixed cross-directory links to pipeline/multiagent-debate
docs/en/intro.md, docs/zh/intro.md Removed MsgHub from top-level multi-agent section

Comment on lines +1 to +64
/*
* Copyright 2025-2026 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.cloud.ai.examples.multiagents.workflow.sqlagent;

import com.alibaba.cloud.ai.graph.CompiledGraph;
import com.alibaba.cloud.ai.graph.OverAllState;
import com.alibaba.cloud.ai.graph.exception.GraphRunnerException;
import org.springframework.ai.chat.messages.AssistantMessage;
import org.springframework.ai.chat.messages.Message;
import org.springframework.ai.chat.messages.UserMessage;

import java.util.List;
import java.util.Map;
import java.util.Optional;

/**
* Service that invokes the SQL agent graph.
*/
public class SqlAgentService {

private final CompiledGraph graph;

public SqlAgentService(CompiledGraph graph) {
this.graph = graph;
}

/**
* Run the SQL agent with the given question.
*/
public SqlAgentResult run(String question) throws GraphRunnerException {
Map<String, Object> inputs = Map.of("messages", List.of(new UserMessage(question)), "question", question);
Optional<OverAllState> resultOpt = graph.invoke(inputs);

if (resultOpt.isEmpty()) {
return new SqlAgentResult(question, null, null);
}

OverAllState state = resultOpt.get();
@SuppressWarnings("unchecked")
List<Message> messages = (List<Message>) state.value("messages").orElse(List.of());
String answer = messages.stream()
.filter(m -> m instanceof AssistantMessage)
.map(m -> m instanceof org.springframework.ai.chat.messages.AssistantMessage am ? am.getText() : "")
.reduce((a, b) -> b)
.orElse(null);

return new SqlAgentResult(question, answer, state);
}

public record SqlAgentResult(String question, String answer, OverAllState state) {
}
Copy link

Copilot AI Mar 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The SqlAgentService and RagAgentService have nearly identical implementations with the same run method pattern, result record structure, and state extraction logic. The only differences are the graph instance and the input map construction. This duplication could be refactored into a shared base class or utility, following the DRY principle.

Copilot uses AI. Check for mistakes.
Comment on lines +53 to +57
## Related Documentation

- [Agent as Tool](../task/agent-as-tool.md) - Sub-agent registration and SubAgentConfig
- [Subagents](./subagent.md) - Orchestrator with Task/TaskOutput and Markdown/API sub-agents
- [Pipeline](./pipeline.md) - Sequential and parallel agent composition
Copy link

Copilot AI Mar 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The en/multi-agent/supervisor.md and zh/multi-agent/supervisor.md files both end without a final newline (no line after line 57 in the English version). The related documentation pages should have a closing newline for proper markdown rendering, but more importantly, the English supervisor.md doesn't end with a newline character at line 57. Additionally, the same issue applies to skills.md for both languages. Consider also that these files lack a handoffs.md link in their "Related Documentation" sections even though multiagent-debate.md links to handoffs—and supervisor/skills are all part of the same multiagent patterns family.

Copilot uses AI. Check for mistakes.
name: skills-sql-assistant

# Set to true to run the skills (progressive disclosure) demo on startup.
skills.runner.enabled: true
Copy link

Copilot AI Mar 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The skills/src/main/resources/application.yml also defaults skills.runner.enabled: true. This will cause the skills demo to run automatically on startup with real LLM API calls. Consider defaulting to false.

Copilot uses AI. Check for mistakes.
Comment on lines +10 to +11
# Set to true to run the AgentScope multi-agent handoffs demo on startup.
agentscope.runner.enabled: true
Copy link

Copilot AI Mar 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The pipeline.runner.enabled and workflow.runner.enabled flags are used, but handoffs/src/main/resources/application.yml defaults agentscope.runner.enabled: true, which also defaults pipeline.runner.enabled: true in pipeline/src/main/resources/application.yml. These are fine if intentional for demos, but are inconsistent with the PR description which says these flags are "optional". However note: both supervisor.run-examples (not runner.enabled) inconsistency makes it harder for users to understand which property controls what.

Copilot uses AI. Check for mistakes.
Comment on lines +113 to +114
- [subagents.md](../../../multiagents/subagents.md) - Subagent architecture documentation
- [spring-ai-agent-utils subagent-demo](../../../multiagents/spring-ai-agent-utils/examples/subagent-demo) - Similar pattern with Spring AI community tools
Copy link

Copilot AI Mar 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The subagent/README.md at line 113 references ../../../multiagents/subagents.md and ../../../multiagents/spring-ai-agent-utils/examples/subagent-demo, which appear to be relative paths to files that are not part of this repository. These references will be broken links in the rendered README.

Copilot uses AI. Check for mistakes.
Comment on lines +44 to +52
URL u = new URL(url);
try (InputStream in = u.openStream();
Scanner scanner = new Scanner(in, StandardCharsets.UTF_8.name()).useDelimiter("\\A")) {
String content = scanner.hasNext() ? scanner.next() : "";
if (content.length() > 15000) {
content = content.substring(0, 15000) + "\n...[truncated]";
}
return content;
}
Copy link

Copilot AI Mar 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The WebFetchTool.webFetch method uses new URL(url) and u.openStream() which does not set connection or read timeouts. A slow or non-responding URL will block the calling thread indefinitely, which in a reactive/agentic context can cause the entire agent invocation to hang. Consider using HttpURLConnection with explicit timeout settings, or a proper HTTP client library with timeout support.

Copilot uses AI. Check for mistakes.
Comment on lines +78 to +81
if (query.toUpperCase().contains("INSERT") || query.toUpperCase().contains("UPDATE")
|| query.toUpperCase().contains("DELETE") || query.toUpperCase().contains("DROP")) {
return "Error: Only SELECT queries are allowed.";
}
Copy link

Copilot AI Mar 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The SqlTools.runQuery method performs a keyword-based blocklist check to prevent write operations (INSERT, UPDATE, DELETE, DROP), but this approach can be bypassed. For example, a query like SELECT * FROM (DELETE FROM table RETURNING *) t or a comment injection may evade the string-contains check. Also the check is case-insensitive via .toUpperCase() but the check for "DROP" does not cover "TRUNCATE" or "ALTER" statements. Since this is a demo/example, this is a moderate concern rather than a critical one, but it should at least be documented as a limitation.

Copilot uses AI. Check for mistakes.
Comment on lines +113 to +117
}
catch (Exception e) {
return true;
}
}
Copy link

Copilot AI Mar 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The BackgroundTask.waitForCompletion method at line 114 catches a generic Exception (which would include ExecutionException from completed-exceptionally futures) and returns true. This is misleading: it signals the caller that the task completed, even though it completed with an error. The caller in TaskOutputTool then calls bgTask.isCompleted() but the distinction between completed-normally and completed-exceptionally is lost for the wait return value. The ExecutionException case should either be documented explicitly or return true but the method name better reflects "isDone" rather than "completed successfully".

Copilot uses AI. Check for mistakes.
Comment on lines +113 to +118
toolkit.registration()
.subAgent(() -> calendarAgent)
.apply();
toolkit.registration()
.subAgent(() -> emailAgent)
.apply();
Copy link

Copilot AI Mar 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The supervisor/SupervisorConfig.supervisorAgent method registers calendarAgent and emailAgent as sub-agents via lambda: () -> calendarAgent and () -> emailAgent. These lambdas always return the same instance (the Spring-managed bean). According to the documentation in agent-as-tool.md (line 49), it's noted that lambdas must create a new instance for each call. However, here the same bean instance is returned, which means the sub-agent's InMemoryMemory will accumulate conversation history across multiple supervisor calls, potentially causing context confusion or memory growth.

Copilot uses AI. Check for mistakes.
Comment on lines +18 to +44
import com.alibaba.cloud.ai.graph.agent.tools.task.BackgroundTask;

import java.util.function.Supplier;

/**
* Repository for managing background tasks.
* <p>
* Inspired by spring ai TaskRepository, enables the main agent to
* launch sub-agents in the background and retrieve results later via TaskOutputTool.
*
*/
public interface TaskRepository {

/**
* Get a background task by its ID.
* @param taskId the task identifier
* @return the background task, or null if not found
*/
BackgroundTask getTask(String taskId);

/**
* Add a new background task to the repository.
* @param taskId the task identifier
* @param taskExecution the supplier that executes the task and returns its output
* @return the created background task
*/
BackgroundTask putTask(String taskId, Supplier<String> taskExecution);
Copy link

Copilot AI Mar 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The TaskRepository interface at lines 18-19 imports com.alibaba.cloud.ai.graph.agent.tools.task.BackgroundTask, but the BackgroundTask class in this module is defined in io.agentscope.examples.subagent.tools.task.BackgroundTask. This import of a different BackgroundTask from com.alibaba.cloud.ai.graph in the interface but a locally-defined BackgroundTask in DefaultTaskRepository suggests a class naming conflict. The DefaultTaskRepository uses the local BackgroundTask, while the interface signature imports from com.alibaba.cloud.ai.graph. This is a potential compilation error or type mismatch at runtime.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants