Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit ca712c8

Browse files
authored
feat(example): Introduce multiagent pattern practices and docs. (agentscope-ai#910)
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`.
1 parent 59fa986 commit ca712c8

139 files changed

Lines changed: 10749 additions & 459 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/maven-ci.yml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,12 +111,15 @@ jobs:
111111
if: runner.os == 'Linux'
112112
run: |
113113
export PATH="$HOME/.mvnd/bin:$PATH"
114-
mvnd -B clean verify
114+
# -T1: single-threaded build so reactor order is respected and agentscope-core
115+
# is installed before modules (e.g. subagent) that resolve it from the reactor.
116+
mvnd -B -T1 clean verify
115117
116118
- name: Build and Test with Coverage [Windows]
117119
if: runner.os == 'Windows'
118120
run: |
119-
& "~\.mvnd\bin\mvnd.cmd" -B clean verify
121+
# -T1: single-threaded build so reactor order is respected (see Linux step).
122+
& "~\.mvnd\bin\mvnd.cmd" -B -T1 clean verify
120123
121124
- name: Upload coverage reports to Codecov
122125
if: runner.os == 'Linux'

.licenserc.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ header:
5151
- '**/*.handlers'
5252
- '**/*.schemas'
5353
- '**/*.nojekyll'
54+
- '**/*.sql'
5455
- '.git/'
5556
- '.github/**'
5657
- '**/.gitignore'
Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
# Handoffs Multi-Agent Example
2+
3+
This module implements the **handoffs** pattern with **AgentScope**: sales and support agents as separate graph nodes, using **AgentScopeAgent** and handoff tools to transfer control. Distinct sales and support agents exist as separate nodes in a StateGraph. Handoff tools navigate between agent nodes by updating `active_agent`, which the parent graph's conditional edges use for routing.
4+
5+
## Architecture
6+
7+
- **Separate agents as graph nodes**
8+
Sales and support agents are separate nodes. Both use AgentScope ReActAgent via `AgentScopeAgent` with Toolkit. The parent StateGraph routes between them based on `active_agent`.
9+
10+
- **Handoff tools**
11+
- `TransferToSupportTool`: Sales agent (AgentScopeAgent) uses it to hand off to support. Registered via AgentScope Toolkit; uses `ToolContextHelper.getStateForUpdate()` to update `active_agent`.
12+
- `TransferToSalesTool`: Support agent (AgentScopeAgent) uses it to hand off to sales. Registered via AgentScope Toolkit; uses `ToolContextHelper.getStateForUpdate()` to update `active_agent`.
13+
14+
- **Conditional routing**
15+
- `route_initial`: START → sales_agent or support_agent (default: sales).
16+
- `route_after_sales`: If `active_agent` is support_agent → support_agent; else → END.
17+
- `route_after_support`: If `active_agent` is sales_agent → sales_agent; else → END.
18+
19+
## Modifying state in AgentScope tools
20+
21+
AgentScope tools receive `ToolContext` (auto-injected) and can read/update graph state:
22+
23+
```java
24+
@Tool(name = "transfer_to_sales", description = "...")
25+
public String transferToSales(
26+
@ToolParam(name = "reason", description = "...") String reason,
27+
ToolContext toolContext) {
28+
// Update state: put keys into the map; merged when node completes
29+
ToolContextHelper.getStateForUpdate(toolContext).ifPresent(update ->
30+
update.put("active_agent", "sales_agent"));
31+
return "Transferred to sales agent.";
32+
}
33+
```
34+
35+
**Read state:**
36+
```java
37+
OverAllState state = ToolContextHelper.getState(toolContext).orElse(null);
38+
```
39+
40+
**Update state:**
41+
Put keys into `getStateForUpdate(toolContext)`; the graph must declare those keys in its key strategies (e.g. `ReplaceStrategy` for `active_agent` or `extraState`).
42+
43+
See `UpdateExtraStateTool` for a full example that reads state and updates `extraState`.
44+
45+
## Design choices
46+
47+
1. **AgentScope Toolkit for both agents**
48+
Sales and support agents both use `io.agentscope.core.tool.Toolkit` and `ReActAgent.builder().toolkit(toolkit)`. Handoff tools use `io.agentscope.core.tool.Tool`; `ToolContext` is auto-injected for state updates.
49+
50+
2. **State update**
51+
Tools use `ToolContextHelper.getStateForUpdate(toolContext)` to set `active_agent` (or other keys). The update is merged into the graph state when the agent node completes.
52+
53+
3. **ToolContext in tools**
54+
Tools use `io.agentscope.core.tool.Tool` and optional `@ToolParam`; `ToolContext` is auto-injected for reading/updating graph state.
55+
56+
## Project layout
57+
58+
```
59+
agentscope-examples/multiagent-patterns/handoffs/
60+
├── README.md
61+
├── pom.xml
62+
└── src/main/
63+
├── java/.../handoffs/multiagent/
64+
│ ├── AgentScopeApplication.java
65+
│ ├── AgentScopeHandoffsConfig.java # StateGraph, agents, routing
66+
│ ├── AgentScopeHandoffsService.java # invokes graph
67+
│ ├── AgentScopeHandoffsRunner.java # optional demo (agentscope.runner.enabled)
68+
│ ├── route/
69+
│ │ ├── RouteInitialAction.java # START → sales or support
70+
│ │ ├── RouteAfterSalesAction.java # sales → support or END
71+
│ │ └── RouteAfterSupportAction.java # support → sales or END
72+
│ ├── state/
73+
│ │ └── AgentScopeStateConstants.java
74+
│ └── tools/
75+
│ ├── TransferToSalesTool.java # support → sales (AgentScope Toolkit)
76+
│ ├── TransferToSupportTool.java # sales → support (AgentScope Toolkit)
77+
│ └── UpdateExtraStateTool.java # read state + update extraState
78+
└── resources/
79+
└── application.yml
80+
```
81+
82+
## How to run
83+
84+
### Prerequisites
85+
86+
- JDK 17+
87+
- Maven 3.6+
88+
- **DashScope API key**: `export AI_DASHSCOPE_API_KEY=your-key`
89+
90+
### Build
91+
92+
From the repo root:
93+
94+
```bash
95+
./mvnw -pl agentscope-examples/multiagent-patterns/handoffs -am -B package -DskipTests
96+
```
97+
98+
Or from this directory:
99+
100+
```bash
101+
cd agentscope-examples/multiagent-patterns/handoffs
102+
mvn -B package -DskipTests
103+
```
104+
105+
### Run the demo on startup
106+
107+
Set `agentscope.runner.enabled=true` in `application.yml`, then start the app:
108+
109+
```bash
110+
./mvnw -pl agentscope-examples/multiagent-patterns/handoffs spring-boot:run
111+
```
112+
113+
Or run without the demo:
114+
115+
```bash
116+
./mvnw -pl agentscope-examples/multiagent-patterns/handoffs spring-boot:run
117+
```
118+
119+
Default port is 8089. Open the chat UI at `http://localhost:8089/chatui/index.html` (if available) to interact with Sales/Support and see handoffs.
120+
121+
### Using in your own code
122+
123+
```java
124+
@Autowired
125+
AgentScopeHandoffsService service;
126+
127+
var result = service.run("Hi, I'm having trouble with my account login. Can you help?");
128+
result.messages().forEach(msg -> System.out.println(msg.getText()));
129+
```
130+
131+
## Configuration
132+
133+
- **`spring.ai.dashscope.api-key`**
134+
Required. Defaults to `AI_DASHSCOPE_API_KEY` env var.
135+
136+
- **`agentscope.runner.enabled`**
137+
If `true`, runs the AgentScope multi-agent handoffs demo on startup. Default: `false`.
138+
139+
## Related
140+
141+
- [AgentScope Java](https://java.agentscope.io/) - AgentScope framework documentation
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!--
3+
~ Copyright 2024-2026 the original author or authors.
4+
~
5+
~ Licensed under the Apache License, Version 2.0 (the "License");
6+
~ you may not use this file except in compliance with the License.
7+
~ You may obtain a copy of the License at
8+
~
9+
~ https://www.apache.org/licenses/LICENSE-2.0
10+
~
11+
~ Unless required by applicable law or agreed to in writing, software
12+
~ distributed under the License is distributed on an "AS IS" BASIS,
13+
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
~ See the License for the specific language governing permissions and
15+
~ limitations under the License.
16+
-->
17+
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
18+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
19+
<modelVersion>4.0.0</modelVersion>
20+
<parent>
21+
<groupId>io.agentscope</groupId>
22+
<artifactId>agentscope-examples</artifactId>
23+
<version>${revision}</version>
24+
<relativePath>../../pom.xml</relativePath>
25+
</parent>
26+
27+
<artifactId>handoffs</artifactId>
28+
<name>Examples::AgentScope Handoffs</name>
29+
<description>Multi-agent orchestration with AgentScope (all AgentScopeAgent) using Spring AI Alibaba</description>
30+
31+
<properties>
32+
<spring-ai-alibaba.version>1.1.2.2</spring-ai-alibaba.version>
33+
</properties>
34+
35+
<dependencyManagement>
36+
<dependencies>
37+
<dependency>
38+
<groupId>org.springframework.boot</groupId>
39+
<artifactId>spring-boot-dependencies</artifactId>
40+
<version>${spring.boot.version}</version>
41+
<type>pom</type>
42+
<scope>import</scope>
43+
</dependency>
44+
<dependency>
45+
<groupId>com.alibaba.cloud.ai</groupId>
46+
<artifactId>spring-ai-alibaba-bom</artifactId>
47+
<version>${spring-ai-alibaba.version}</version>
48+
<type>pom</type>
49+
<scope>import</scope>
50+
</dependency>
51+
</dependencies>
52+
</dependencyManagement>
53+
54+
<dependencies>
55+
<dependency>
56+
<groupId>org.springframework.boot</groupId>
57+
<artifactId>spring-boot-starter</artifactId>
58+
</dependency>
59+
60+
<dependency>
61+
<groupId>com.alibaba.cloud.ai</groupId>
62+
<artifactId>spring-ai-alibaba-starter-agentscope</artifactId>
63+
</dependency>
64+
</dependencies>
65+
66+
<build>
67+
<plugins>
68+
<plugin>
69+
<groupId>org.springframework.boot</groupId>
70+
<artifactId>spring-boot-maven-plugin</artifactId>
71+
</plugin>
72+
</plugins>
73+
</build>
74+
75+
<repositories>
76+
<repository>
77+
<snapshots>
78+
<enabled>false</enabled>
79+
</snapshots>
80+
<id>spring-milestones</id>
81+
<name>Spring Milestones</name>
82+
<url>https://repo.spring.io/milestone</url>
83+
</repository>
84+
<repository>
85+
<releases>
86+
<enabled>false</enabled>
87+
</releases>
88+
<snapshots>
89+
<enabled>true</enabled>
90+
<updatePolicy>always</updatePolicy>
91+
</snapshots>
92+
<id>sonatype-snapshots</id>
93+
<name>Sonatype Snapshot Repository</name>
94+
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
95+
</repository>
96+
</repositories>
97+
</project>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
/*
2+
* Copyright 2024-2026 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package io.agentscope.examples.handoffs.multiagent;
17+
18+
import org.springframework.boot.SpringApplication;
19+
import org.springframework.boot.autoconfigure.SpringBootApplication;
20+
import org.springframework.boot.context.event.ApplicationReadyEvent;
21+
import org.springframework.context.ApplicationListener;
22+
import org.springframework.context.annotation.Bean;
23+
import org.springframework.core.env.Environment;
24+
25+
@SpringBootApplication
26+
public class AgentScopeApplication {
27+
28+
public static void main(String[] args) {
29+
SpringApplication.run(AgentScopeApplication.class, args);
30+
}
31+
32+
@Bean
33+
public ApplicationListener<ApplicationReadyEvent> applicationReadyEventListener(
34+
Environment environment) {
35+
return event -> {
36+
System.out.println("\n🎉========================================🎉");
37+
System.out.println("✅ AgentScope Multi-Agent example has started!");
38+
System.out.println("🎉========================================🎉\n");
39+
};
40+
}
41+
}

0 commit comments

Comments
 (0)