AgentScope-Java: Alibaba's Answer to Building AI Agents Without Leaving the JVM
Foreword
How Java developers can quickly build enterprise-level AI Agent applications
Recently, the concept of AI Agent (intelligent agent) has become incredibly popular. From OpenClaw to Claude Code, from Manus to various Agent frameworks, it seems like overnight, "letting AI do the work itself" has become the hottest topic in the tech circle.
But many Java developers, when trying to get involved, have discovered an awkward problem — the mainstream Agent frameworks on the market are overwhelmingly part of the Python ecosystem.
LangChain? Python.
AutoGen? Python.
CrewAI? Still Python.
"Brother San, our team is all Java tech stack. Do we really have to learn Python specifically just to build Agents?"
Of course not.
Alibaba's open-source AgentScope-Java is an intelligent agent development framework built specifically for Java developers.
Today, this article will discuss AgentScope-Java with everyone, hoping it will be helpful to you.
More project practices at Java Assault Team Network: susan.net.cn/project
1. What exactly is AgentScope-Java?
1.1 Explained in one sentence
AgentScope-Java is an open-source Java framework from Alibaba for Agent-oriented programming, used to build intelligent agent applications based on Large Language Models (LLMs).
Its core goal is very clear — to allow Java developers to use their familiar language and toolchain to quickly build production-grade AI Agent applications.
1.2 What problems does AgentScope-Java solve?
Before AgentScope appeared, Java developers who wanted to build Agent applications basically had only two paths:
Path one: Use a Python framework.
Learn a new language, set up a new environment, maintain two tech stacks, team fragmentation.
Path two: Build wheels from scratch.
Write ReAct loops, implement tool calls, manage conversation memory, handle multi-Agent collaboration... each one is a major engineering task.
What AgentScope does is: Package all the infrastructure needed for Agent development — ReAct reasoning loops, tool calls, memory management, multi-agent collaboration, distributed deployment — into a single Java framework, ready to use out of the box.
1.3 How is it different from Spring AI Alibaba?
Many friends might ask: "Brother San, doesn't Alibaba have Spring AI Alibaba? What's the difference between this and that?"
This is a very good question. The positioning of the two is completely different:
- Spring AI Alibaba: Focuses on "AI capability access" — making it easy for Java applications to call various large model APIs, suitable for scenarios like RAG and chatbots.
- AgentScope-Java: Focuses on "Agent engineering" — enabling developers to build intelligent agent systems with autonomous reasoning, tool calling, and multi-Agent collaboration capabilities.
The two are not in competition, but rather can be used together. AgentScope is responsible for the Agent's "brain" (reasoning, decision-making, action), while Spring AI Alibaba is responsible for the "senses" (accessing various AI capabilities).
2. Core Concepts
The core design philosophy of AgentScope-Java 2.0 is very clear — provide two types of Agents, covering all scenarios from simple to complex.
2.1 ReActAgent: The lightest reasoning core
ReActAgent is the most basic Agent implementation in AgentScope. It implements a complete ReAct (Reasoning + Acting) reasoning loop.
So-called ReAct means letting the LLM autonomously complete tasks in a loop of "Think → Act → Observe → Think again":
ReActAgent is suitable for lightweight, single-session, no-persistent-state scenarios.
2.2 HarnessAgent: Production-grade engineering encapsulation
HarnessAgent is the production-grade entry point recommended by AgentScope 2.0.
On top of ReActAgent, it additionally encapsulates a set of engineering capabilities:
| Engineering Capability | Description |
|---|---|
| Workspace | Agent's persona, knowledge, skills, and memory are uniformly stored in a structured workspace |
| Long-term Memory | Cross-session memory persistence and semantic retrieval |
| Session Persistence | Conversation state is automatically saved, seamless recovery after restart |
| Sub-Agent Orchestration | The main Agent can delegate tasks to multiple sub-Agents |
| Sandbox Isolation | Tool execution runs in an isolated environment, ensuring security |
| Context Compaction | Long conversations are automatically compressed to prevent context overflow |
Core difference: ReActAgent solves "how to run this one conversation," while HarnessAgent solves "how to make a long-running Agent stable, secure, and scalable."
My suggestion: Use HarnessAgent directly for most scenarios.
Although it seems to have more configuration, these engineering capabilities are almost essential in a production environment.
3. Run your first Agent in 5 minutes
3.1 Prerequisites
AgentScope-Java 2.0 requires JDK 17 or higher, and recommends Maven 3.9+.
Check your Java version:
java -version
# Needs to output 17 or higher
3.2 Add Maven Dependencies
AgentScope's dependency design is very clear — core modules and model extensions are separated.
Step 1: Add core dependency
<dependency>
<groupId>io.agentscope</groupId>
<artifactId>agentscope-harness</artifactId>
<version>2.0.0</version>
</dependency>
agentscope-harness will automatically pull in agentscope-core, which includes the core implementations of ReActAgent and HarnessAgent.
Step 2: Add model extension
Add the corresponding extension dependency based on the model you want to use. Taking Tongyi Qianwen (DashScope) as an example:
<dependency>
<groupId>io.agentscope</groupId>
<artifactId>agentscope-extensions-model-dashscope</artifactId>
<version>2.0.0</version>
</dependency>
3.3 Configure API Key
AgentScope reads the API Key via environment variables. Taking DashScope as an example:
export DASHSCOPE_API_KEY="sk-your-api-key"
If you are using DeepSeek or an OpenAI-compatible service:
export OPENAI_API_KEY="sk-your-api-key"
3.4 First Agent: Minimal Example
The following code is the "Hello World" of AgentScope-Java — creating an Agent that can converse.
package com.example;
import io.agentscope.core.ReActAgent;
import io.agentscope.core.agent.RuntimeContext;
import io.agentscope.core.formatter.openai.OpenAIChatFormatter;
import io.agentscope.core.message.UserMessage;
import io.agentscope.core.model.GenerateOptions;
import io.agentscope.core.model.OpenAIChatModel;
import io.agentscope.core.tool.Toolkit;
import io.agentscope.harness.HarnessAgent;
import java.nio.file.Path;
public class FirstAgent {
public static void main(String[] args) {
// 1. Create Model (using DeepSeek as an example)
String apiKey = System.getenv("DEEPSEEK_API_KEY");
OpenAIChatModel model = OpenAIChatModel.builder()
.apiKey(apiKey)
.modelName("deepseek-chat")
.baseUrl("https://api.deepseek.com")
.stream(true) // Enable streaming output
.enableThinking(true) // Enable thinking mode
.formatter(new OpenAIChatFormatter())
.defaultOptions(GenerateOptions.builder()
.thinkingBudget(1024) // Thinking token budget
.build())
.build();
// 2. Create Agent
HarnessAgent agent = HarnessAgent.builder()
.name("Assistant")
.sysPrompt("You are a helpful AI assistant. Please answer questions in a friendly and concise manner.")
.model(model)
.workspace(Path.of("./workspace"))
.build();
// 3. Send message and get reply
UserMessage userMsg = new UserMessage("Hello, please introduce yourself");
String reply = agent.call(userMsg, RuntimeContext.empty())
.block()
.getTextContent();
System.out.println(reply);
}
}
Code breakdown:
- Step 1: Create
OpenAIChatModel, configure API address, model name, whether to use streaming output, and whether to enable thinking mode. - Step 2: Use
HarnessAgent.builder()to create an Agent, specifying the name, system prompt, model, and workspace directory. - Step 3: Construct a
UserMessage, callagent.call()to get the reply.
After running, you will see the Agent's reply. The whole process takes less than 10 lines of core code, and a conversational AI Agent is up and running.
4. Tool System: Giving the Agent "Hands and Feet"
Some friends might say: "What's the use of an Agent that can only chat? I want it to be able to call tools and execute operations!"
Don't worry. AgentScope's tool system is exactly for this.
An Agent without tools can only be an "armchair strategist." AgentScope uses the @Tool annotation to allow developers to register any Java method as a tool callable by the Agent.
4.1 Define Tools
Use the @Tool and @ToolParam annotations to define tools:
import io.agentscope.core.tool.Tool;
import io.agentscope.core.tool.ToolParam;
public class WeatherTools {
@Tool(name = "get_weather", description = "Get the current weather for a specified city")
public String getWeather(
@ToolParam(name = "city", description = "City name, e.g., 'Beijing'")
String city
) {
// Here you can call a real weather API
return city + " is sunny today, temperature 25°C";
}
@Tool(name = "calculate", description = "Perform a mathematical calculation")
public double calculate(
@ToolParam(name = "expression", description = "Mathematical expression")
String expression
) {
// Here you can integrate an expression calculation engine
return 42.0;
}
}
Key points:
- The
namein@Toolis the unique identifier for the tool, used by the Agent when calling it. - The
descriptionin@Tooldescribes the tool's function; the Agent decides when to call it based on this description. @ToolParamis annotated on method parameters to describe the meaning of the parameters.
4.2 Register Tools
Create a Toolkit instance and register the tools into it:
// Create toolkit
Toolkit toolkit = new Toolkit();
toolkit.registerTool(new WeatherTools());
// Pass the toolkit to the Agent
HarnessAgent agent = HarnessAgent.builder()
.name("Assistant")
.sysPrompt("You are an assistant that can use tools.")
.model(model)
.toolkit(toolkit) // Register tools
.workspace(Path.of("./workspace"))
.build();
4.3 Agent with Tools
public class ToolCallingExample {
public static void main(String[] args) {
// Create Model
OpenAIChatModel model = ...;
// Create toolkit
Toolkit toolkit = new Toolkit();
toolkit.registerTool(new WeatherTools());
// Create Agent and register tools
HarnessAgent agent = HarnessAgent.builder()
.name("Assistant")
.sysPrompt("You are an assistant that can use tools. When the user asks about the weather, call the get_weather tool.")
.model(model)
.toolkit(toolkit)
.build();
// User asks a question, Agent will autonomously decide whether to call a tool
UserMessage userMsg = new UserMessage("What's the weather like in Beijing today?");
String reply = agent.call(userMsg, RuntimeContext.empty())
.block()
.getTextContent();
System.out.println(reply);
// Output: Beijing is sunny today, temperature 25°C
}
}
Key understanding: In the ReAct loop, the Agent will autonomously decide whether to call a tool, which tool to call, and when to call it. The developer only needs to define the tools; the Agent itself judges "when to use what."
5. Multi-Agent Collaboration
Some friends might ask: "What if one Agent isn't enough? How do you handle complex tasks that require multiple Agents to collaborate?"
AgentScope 2.0 provides an orchestrator + workers pattern to achieve multi-Agent collaboration.
5.1 Core Pattern
The core concept of version 2.0 is: The main Agent acts as the "host," and sub-Agents act as "participants."
The main Agent is responsible for receiving user tasks, breaking down tasks, delegating to sub-Agents, and summarizing results.
5.2 Define Sub-Agents
Sub-Agents can be defined in a file-driven manner — by creating .md files in the workspace/subagents/ directory:
workspace/subagents/weather.md:
id: weather
description: Check city weather. Input: city name + date. Output: temperature range, whether it will rain.
sysPrompt: |
You are a weather assistant. When a user gives you a city and date, you return:
- Temperature (high/low)
- Whether it will rain
- Whether to bring an umbrella
Strictly three lines, no more than 60 characters.
workspace/subagents/flight.md:
id: flight
description: Check flight information. Input: departure city + arrival city + date.
sysPrompt: |
You are a flight inquiry assistant. Based on user input, provide a mock flight number and departure/arrival times.
5.3 Java-side Reinforcement
If a sub-Agent needs to call Java-side tools (like a real weather API), you can register it again on the Java side:
import io.agentscope.harness.agent.subagent.SubagentDeclaration;
// Java-side reinforcement for the weather sub-Agent
SubagentDeclaration weather = SubagentDeclaration.builder()
.name("weather")
.description("Check city weather; input city+date, return temperature range and whether to bring an umbrella")
.inlineAgentsBody("You are a weather assistant who will call tools to query real weather")
.build();
// Register sub-Agent in HarnessAgent
HarnessAgent agent = HarnessAgent.builder()
.name("TravelAssistant")
.model(model)
.subagent(weather) // Register sub-Agent
.workspace(Path.of("./workspace"))
.build();
The main Agent will decide for itself: whether it needs to call sub-Agents, which sub-Agents to call, and in what order.
6. Underlying Principles
6.1 Layered Architecture
AgentScope-Java adopts a classic layered architecture design:
The overall architecture of AgentScope can be clearly divided into four layers:
- Model Adaptation Layer: Responsible for communicating with different LLM providers, supporting OpenAI protocol, DashScope (Tongyi Qianwen), Anthropic Claude, Google Gemini, etc.
- ReAct Reasoning Layer: Implements the ReAct reasoning loop (Think → Act → Observe → Think again), serving as the "brain" of the entire Agent.
- Harness Engineering Layer: Encapsulates engineering capabilities like workspace, memory, sessions, sub-agents, and sandboxing on top of ReAct.
- Application Layer: Your business code.
6.2 Execution Flow of the ReAct Reasoning Loop
When a user message enters the Agent, the execution flow of the ReAct loop is as follows:
HarnessAgent inserts Hooks at key moments in the ReAct loop to implement functions like workspace loading, memory read/write, and session persistence.
6.3 Distributed Deployment Architecture
One of the most core upgrades in AgentScope 2.0 is native support for distributed deployment.
During the standalone development phase, state defaults to the local workspace directory.
When moving to production deployment, you simply switch the state backend to distributed storage:
With the same business code, you can switch from standalone mode to distributed mode just by changing the storage backend.
Any replica can restore the complete context of any user.
7. Practical Case: Multi-Agent Weather Assistant
Some friends might say: "I've got a single Agent running, but real business requires multiple Agents to collaborate. What do I do?"
AgentScope 2.0 provides a file-driven Subagent mechanism. You just need to place a few .md files in the workspace/subagents/ directory, and the main Agent will decide for itself "when to call whom."
Let's look at a complete practical example — Travel Assistant. The user asks: "I'm flying from Beijing to Hangzhou tomorrow, and after landing I'm going to West Lake. Should I bring an umbrella?"
In the 1.x era, you needed to write code to string together three Agents (weather → flight → attraction).
In the 2.0 era, the main Agent decides for itself whether to check the weather or flights first, and the three Subagents start in parallel.
7.1 Project Structure
travel-assistant/
├── pom.xml
└── workspace/
├── MEMORY.md
├── subagents/
│ ├── weather.md
│ ├── flight.md
│ └── attraction.md
└── state/
└── session-*.json # Auto-generated by JsonFileAgentStateStore
7.2 Three Subagent Files
workspace/subagents/weather.md:
id: weather
description: |
Check city weather.
Input: city name + date (YYYY-MM-DD).
Output: temperature range, whether it will rain, whether to bring an umbrella.
sysPrompt: |
You are a weather assistant.
When a user gives you a city and date, you return:
- Temperature (high/low, Celsius)
- Whether it will rain
- Whether to bring an umbrella
Strictly three lines, no more than 60 characters.
workspace/subagents/flight.md:
id: flight
description: |
Check flight information (mock).
Input: departure city + arrival city + date.
Output: flight number, departure time, arrival time.
sysPrompt: |
You are a flight inquiry assistant.
Based on user input, provide a mock flight number and departure/arrival times.
Note: This is a test environment, no real query needed, just provide reasonable mock data.
workspace/subagents/attraction.md:
id: attraction
description: |
Attraction information assistant (mock).
Input: city + attraction name.
Output: opening hours, whether reservation is needed, nearby transportation.
sysPrompt: |
You are a tour guide assistant.
Provide practical information about the attraction based on user input.
These three descriptions serve as a routing table for the main Agent — the main Agent relies entirely on the description to decide whether to spawn them.
7.3 Java-side Reinforcement for Subagents
If a Subagent needs to call real tools on the Java side (e.g., weather.md needs to connect to a real weather API behind the scenes), you can register it again on the Java side — HarnessAgent will merge the file and Java declarations:
import io.agentscope.core.model.DashScopeChatModel;
import io.agentscope.core.tool.Toolkit;
import io.agentscope.harness.HarnessAgent;
import io.agentscope.harness.agent.subagent.SubagentDeclaration;
import java.nio.file.Path;
public class TravelAssistant {
public static void main(String[] args) {
// 1. Create Model
DashScopeChatModel model = DashScopeChatModel.builder()
.apiKey(System.getenv("DASHSCOPE_API_KEY"))
.modelName("qwen-plus")
.build();
// 2. Create Toolkit and register weather query tool
Toolkit toolkit = new Toolkit();
toolkit.registerTool(new WeatherLookupTool()); // Real weather API tool
// 3. Java-side reinforcement for weather subagent — tools whitelist filters tools inherited from parent agent
SubagentDeclaration weather = SubagentDeclaration.builder()
.name("weather")
.description("Check city weather; input city+date, return temperature range and whether to bring an umbrella")
.inlineAgentsBody("You are a weather assistant who will call tools to query real weather")
.build();
// 4. Create HarnessAgent, register subagent
HarnessAgent agent = HarnessAgent.builder()
.name("TravelAssistant")
.model(model)
.toolkit(toolkit)
.workspace(Path.of("./workspace"))
.subagent(weather) // Java-side reinforced subagent
.build();
// 5. Run
UserMessage userMsg = new UserMessage(
"I'm flying from Beijing to Hangzhou tomorrow, and after landing I'm going to West Lake. Should I bring an umbrella?"
);
String reply = agent.call(userMsg, RuntimeContext.empty())
.block()
.getTextContent();
System.out.println(reply);
}
}
Key understanding: During the reasoning process, the main Agent will autonomously decide whether it needs to call Subagents, which Subagents to call, and in what order.
The entire "orchestration" process is completed by the LLM; you don't need to hardcode a Pipeline.
8. Practical Case: MCP Protocol Tools
Some friends might say: "Tool calling requires writing Java classes yourself. If I want to integrate external services like GitHub, databases, or Slack, do I have to wrap each one myself?"
No.
AgentScope 2.0 supports the MCP (Model Context Protocol) protocol. You only need to declare an MCP server in one line in workspace/tools.json, and the Agent will automatically discover and register tools at startup.
8.1 What is MCP?
MCP is an open protocol launched by Anthropic in 2024 that allows LLM applications to discover and call external tools in a unified way.
AgentScope 2.0 treats MCP servers as a "source" of Agent tools — you declare an MCP server in tools.json, and when the Agent starts, it connects to it via stdio or sse protocol, automatically treating the tools exposed by the server as the Agent's own tools.
8.2 First MCP Integration
workspace/tools.json:
{
"mcpServers": {
"github": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-github"],
"env": {
"GITHUB_PERSONAL_ACCESS_TOKEN": "${env:GITHUB_TOKEN}"
}
}
}
}
When HarnessAgent.builder().workspace(path) starts, it automatically scans the mcpServers section of workspace/tools.json, connects to each server, and registers the tools with the Agent — no extra switch needed:
HarnessAgent agent = HarnessAgent.builder()
.name("GitHubAssistant")
.model(model)
.workspace(Path.of("./workspace")) // Automatically loads tools.json
.build();
Once running, the Agent can call tools like create_issue, list_repos, search_code exposed by the GitHub MCP server.
8.3 Three Connection Methods
MCP supports three transport protocols:
| Protocol | Applicable Scenario | Declaration Method |
|---|---|---|
| stdio | Local process, most common | command + args |
| sse | Remote HTTP SSE server | url + headers |
| ws | Bidirectional WebSocket | url + headers |
stdio example (connecting to local filesystem):
{
"mcpServers": {
"filesystem": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-filesystem", "./data"]
}
}
}
sse example (connecting to a remote knowledge base):
{
"mcpServers": {
"remote-knowledge": {
"url": "https://mcp.example.com/sse",
"headers": {
"Authorization": "Bearer ${env:MCP_TOKEN}"
}
}
}
}
8.4 Don't want to write JSON? Configure directly in Java code
Sometimes you want to dynamically assemble parameters in code — for example, reading a token from an environment variable or switching timeouts based on the environment.
In this case, you can configure it directly in Java code:
import io.agentscope.harness.agent.tools.McpServerConfig;
import io.agentscope.harness.agent.tools.ToolsConfig;
ToolsConfig cfg = new ToolsConfig();
Map<String, McpServerConfig> servers = new LinkedHashMap<>();
McpServerConfig github = new McpServerConfig();
github.setTransport("stdio");
github.setCommand("npx");
github.setArgs(List.of("-y", "@modelcontextprotocol/server-github"));
github.setEnv(Map.of("GITHUB_PERSONAL_ACCESS_TOKEN", System.getenv("GITHUB_TOKEN")));
servers.put("github", github);
cfg.setMcpServers(servers);
// Then pass it in via HarnessAgent's toolsConfig() method
The effect is exactly the same as tools.json.
8.5 Common MCP Servers
| MCP Server | Purpose | Install Command |
|---|---|---|
| server-github | GitHub operations (create Issues, search code, etc.) | npx -y @modelcontextprotocol/server-github |
| server-filesystem | Local filesystem read/write | npx -y @modelcontextprotocol/server-filesystem |
| server-postgres | PostgreSQL database queries | npx -y @modelcontextprotocol/server-postgres |
| server-slack | Slack message sending | npx -y @modelcontextprotocol/server-slack |
| server-puppeteer | Browser automation (web scraping, screenshots) | npx -y @modelcontextprotocol/server-puppeteer |
After integrating with the MCP ecosystem, the capability boundaries of AgentScope's Agents are greatly expanded — as long as a tool can be exposed via MCP, the Agent can call it.
9. Pros and Cons
Pros
1. Seamless Java ecosystem integration AgentScope is perfectly compatible with mainstream Java tech stacks like Spring Boot, Spring Cloud, and Maven. For Java teams, the learning curve is very gentle.
2. Dual Agent architecture, covering all scenarios ReActAgent meets lightweight needs, HarnessAgent covers production-grade engineering needs. From prototype to production, one framework handles it all.
3. Comprehensive tool system
Using the @Tool annotation, any Java method can be registered as an Agent tool. The Agent autonomously decides when to call it within the ReAct loop.
4. Native multi-Agent collaboration Built-in orchestrator + workers pattern, the main Agent can delegate tasks to multiple sub-Agents, supporting both synchronous and asynchronous modes.
5. Production-grade engineering capabilities Workspace, long-term memory, session persistence, context compression, sandbox isolation — HarnessAgent packages all the engineering capabilities needed for enterprise-grade Agents.
6. Native support for distributed deployment Supports multiple state storage backends like Redis, MySQL, and PostgreSQL, and supports horizontal scaling with Kubernetes.
7. Multi-model support Built-in support for OpenAI protocol (DeepSeek, GLM, Ollama, etc.), DashScope (Tongyi Qianwen), Anthropic Claude, Google Gemini.
8. MCP/A2A protocol support Supports Model Context Protocol and Agent-to-Agent protocol, allowing integration with tools and services in the MCP ecosystem.
Cons
1. Relatively new AgentScope-Java 1.0 was released in December 2025, and 2.0 went GA in July 2026. Compared to mature frameworks like Spring AI, the community accumulation is less.
2. Learning curve HarnessAgent's engineering concepts (workspace, memory, sub-agents, etc.) require a certain learning cost.
3. Ecosystem not as rich as Spring AI Currently, the number of third-party integrations and extensions is not as high as Spring AI Alibaba.
4. Documentation leans towards English Although official Chinese documentation is provided, some in-depth content is still primarily in English.
10. Applicable Scenarios
| Scenario | Recommendation Level | Reason |
|---|---|---|
| Intelligent Customer Service System | Strongly Recommended | Multi-Agent collaboration + knowledge base RAG |
| Ops Diagnosis Agent | Strongly Recommended | Autonomous reasoning + tool calling + log analysis |
| Financial Analysis Agent | Strongly Recommended | Structured output + multi-step reasoning |
| Code Assistance Agent | Recommended | Tool calling + code execution sandbox |
| Enterprise Internal Knowledge Assistant | Recommended | RAG + long-term memory |
| Simple Chatbot | Possibly Over-engineered | Spring AI Alibaba is sufficient |
| Existing Spring AI Ecosystem | Needs Evaluation | The two can be used together |
More project practices at Java Assault Team Network: susan.net.cn/project
Summary
Returning to the original question: How do Java developers build AI Agents?
AgentScope-Java provides a very complete answer.
It is not a simple port that "translates a Python framework into Java," but rather an Agent framework designed specifically for Java developers, starting from the actual situation of the Java ecosystem.
ReActAgent lets you quickly get an Agent prototype running, and HarnessAgent lets you turn that prototype into a production-grade application.
The @Tool annotation makes defining tools as natural as writing ordinary Java methods, and the sub-Agent system makes multi-Agent collaboration clear and controllable.
The most crucial point is — it eliminates the need for Java developers to learn Python just to build Agents.