跪拜 Guibai
← Back to the summary

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:

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":

image

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."

image

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:

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:

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.

image

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:

image

The overall architecture of AgentScope can be clearly divided into four layers:

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:

image

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:

image

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.