不写一行 Python,用 Java 撸一个多智能体:AgentScope-Java 2.0 上手实测

不写一行 Python,用 Java 撸一个多智能体:AgentScope-Java 2.0 上手实测

AI Agent 的框架生态几乎是 Python 的天下------LangChain、AutoGen、CrewAI,想用 Java 搭 Agent,要么维护第二套语言栈,要么拿 Spring AI 一点点手搓。阿里开源的 AgentScope-Java 给了另一个选项:在 JVM 里把 ReAct 推理、工具调用、多智能体编排一次做齐。本文基于 2.0.1 版本,从零跑通第一个 Agent,并验证它最被低估的能力------跨进程会话恢复。

你能获得什么

  • AgentScope-Java 与 Spring AI Alibaba 的定位差异,选型不纠结
  • 10 分钟跑通第一个 HarnessAgent(含可复制代码)
  • 一次「杀掉进程再启动,Agent 还记得你」的完整实测
  • 三个真实踩坑与 Key 安全实践

一、为什么 Java 开发者值得关注这个框架

先交代背景:AgentScope 是阿里通义实验室开源的智能体框架家族,Python 版早已开源,AgentScope-Java 是其官方 Java 实现,2025 年 11 月发布 1.0,目前最新为 2.0.1,已在阿里集团内部 13+ 业务线生产使用。

对 Java 团队来说,它解决的是一个很具体的问题:不用引入 Python 栈,就能获得生产级的多智能体能力------ReAct 推理循环、工具调用、记忆管理、多 Agent 协作,全部以 Maven 依赖的形式进入你现有的 Spring Boot 工程。

社区里经常被拿来和 Spring AI Alibaba 对比,两者其实是同一团队不同小组的作品,定位互补:

AgentScope-Java Spring AI Alibaba
出身 阿里云自研 跟随 Spring 生态
侧重 多智能体通信、角色分工、状态同步 单 Agent 复杂工作流编排(Graph)
抽象 HarnessAgent 工程外壳 Spring familiar 的 Bean/Starter 风格
适合 多角色协作、长跑任务 已有 Spring 体系的单 Agent 增强

一句话:单 Agent + 工作流选 Spring AI Alibaba;多智能体协作选 AgentScope-Java。 本文的主角是后者。

二、两个核心概念:ReActAgent 与 HarnessAgent

打开源码前,先建立最小心智模型。

【图1:HarnessAgent 架构图】

  • ReActAgent:框架的最小内核,实现 Think → Act → Observe 的推理循环。一个请求进来,模型自己决定要不要调工具、观察结果、继续思考,直到产出答案。适合单轮、无状态的轻量任务。
  • HarnessAgent:推荐的生产入口。它复用同一套 ReAct 循环,但在外面包了一层工程外壳------workspace(人格/记忆/技能)、会话持久化、上下文自动压缩、子智能体编排、沙箱隔离。

区别在于:ReActAgent 只回答「这一轮怎么推理」,HarnessAgent 回答「下一轮怎么办、明天怎么办、上下文爆了怎么办、进程挂了怎么办」。新手建议直接从 HarnessAgent 入手,这些工程能力早晚都要用上。

三、10 分钟跑通第一个 Agent

环境要求:JDK 17+(本文用 21)、Maven 3.9+。

3.1 引入依赖

两个依赖搞定,模型按需选择(本文用 OpenAI 兼容协议接 DeepSeek,成本低、国内直连):

xml 复制代码
<dependency>
    <groupId>io.agentscope</groupId>
    <artifactId>agentscope-harness</artifactId>
    <version>2.0.1</version>
</dependency>
<dependency>
    <groupId>io.agentscope</groupId>
    <artifactId>agentscope-extensions-model-openai</artifactId>
    <version>2.0.1</version>
</dependency>

如果只需要裸的 ReActAgent(不要 workspace、持久化、沙箱),单独引 agentscope-core 即可。模型侧还有 dashscope / anthropic / gemini / ollama 等扩展模块,换模型只换依赖和一行配置。

3.2 配置 API Key

重点立规矩:Key 一律走环境变量,绝不硬编码。硬编码的 Key 一旦提交仓库或误入截图,等于公开钱包密码:

bash 复制代码
export DEEPSEEK_API_KEY=sk-xxx

IDEA 用户在 Run Configuration → Environment variables 里配置:

代码里统一收敛到一个工厂类,缺失时给出友好提示:

java 复制代码
package com.mk.agentscope.agent;

import io.agentscope.extensions.model.openai.OpenAIChatModel;
import io.agentscope.extensions.model.openai.formatter.OpenAIChatFormatter;

/**
 * 模型工厂:统一从环境变量读取 API Key,避免密钥硬编码进仓库。
 *
 * <p>使用前先设置环境变量(Git Bash / CMD / IDEA Run Configuration 均可):
 * <pre>
 *   export DEEPSEEK_API_KEY=sk-xxx
 * </pre>
 * 详见项目根目录 README.md 与 .env.example。
 */
public final class ModelFactory {

    private static final String API_KEY_ENV = "DEEPSEEK_API_KEY";
    private static final String BASE_URL = "https://api.deepseek.com";
    private static final String MODEL_NAME = "deepseek-chat";

    private ModelFactory() {
    }

    public static OpenAIChatModel build() {
        String apiKey = System.getenv(API_KEY_ENV);
        if (apiKey == null || apiKey.isBlank()) {
            throw new IllegalStateException("未检测到环境变量 " + API_KEY_ENV
                    + ",请先设置:export DEEPSEEK_API_KEY=sk-xxx(详见 README.md)");
        }
        return OpenAIChatModel.builder()
                .apiKey(apiKey)
                .modelName(MODEL_NAME)
                .baseUrl(BASE_URL)
                .stream(true)
                .formatter(new OpenAIChatFormatter())
                .build();
    }
}

3.3 十行代码构建 Agent

java 复制代码
package com.mk.agentscope.agent;

import io.agentscope.core.agent.RuntimeContext;
import io.agentscope.core.message.Msg;
import io.agentscope.core.message.UserMessage;
import io.agentscope.harness.agent.HarnessAgent;
import io.agentscope.harness.agent.memory.compaction.CompactionConfig;

import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Scanner;

/**
 * 会话持久化演示。
 *
 * <p>演示 HarnessAgent 的跨进程会话恢复能力:
 * <ol>
 *   <li>第一次运行:告诉 Agent 你的名字和在做的事,然后 exit 退出;</li>
 *   <li>第二次运行:直接问「我叫什么、在做什么」,Agent 能答出上一次的内容。</li>
 * </ol>
 * 原理:AgentState 自动持久化到 {@code ~/.agentscope/state/<agentName>/<userId>/<sessionId>/},
 * 同一 sessionId 再次调用时自动恢复。运行后观察该目录与
 * {@code .agentscope/workspace/}(人格 / 记忆 / 会话日志)的变化,即可截图写文章。
 *
 * <p>运行前设置:export DEEPSEEK_API_KEY=sk-xxx
 */
public class SessionResumeDemo {

    private static final String SESSION_ID = "demo-session";
    private static final String USER_ID = "mk";

    public static void main(String[] args) {
        HarnessAgent agent = HarnessAgent.builder()
                .name("note-taker")
                .sysPrompt("你是一个帮助用户记录笔记的助手,需要记住用户提到的关键信息。")
                .model(ModelFactory.build())
                .workspace(Paths.get(".agentscope/workspace"))
                .compaction(CompactionConfig.builder()
                        .triggerMessages(30)
                        .keepMessages(10)
                        .build())
                .build();

        RuntimeContext ctx = RuntimeContext.builder()
                .sessionId(SESSION_ID)
                .userId(USER_ID)
                .build();

        // 状态目录(AgentState 自动落盘位置,注意是在「用户主目录」下,不是项目目录)
        Path stateDir = Paths.get(System.getProperty("user.home"),
                ".agentscope", "state", "note-taker", USER_ID, SESSION_ID);

        System.out.println("=== AgentScope-Java 会话持久化演示 ===");
        System.out.println("sessionId=" + SESSION_ID + "(两次运行请保持相同)");
        System.out.println("输入消息开始对话,输入 exit 退出。");
        System.out.println("建议:第一次运行说「我叫 MK,在写 AgentScope-Java 系列文章」,退出后重新运行本程序再问「我叫什么」。");
        System.out.println("状态落盘目录:" + stateDir);

        try (Scanner scanner = new Scanner(System.in)) {
            while (scanner.hasNextLine()) {
                String line = scanner.nextLine().trim();
                if ("exit".equalsIgnoreCase(line)) {
                    break;
                }
                if (line.isEmpty()) {
                    continue;
                }
                Msg reply = agent.call(new UserMessage(line), ctx).block();
                System.out.println("[agent] " + (reply == null ? "(无回复)" : reply.getTextContent()));
            }
        }
        System.out.println("已退出。查看状态文件:" + stateDir.resolve("agent_state.json"));
    }
}

三个关键点:

  1. sysPrompt 定义人格 ,但 HarnessAgent 的人格不只在代码里------下一节你会看到它落在 workspace 的 AGENTS.md 文件上;
  2. RuntimeContext 是身份载体 :sessionId 决定会话存储路径,userId 区分用户。同一套代码,靠这两个字段天然支持多租户;
  3. call(...) 是阻塞式返回,streamEvents(...) 是流式返回,按场景选。

3.4 见证时刻:跨进程会话恢复

现在做本文的核心实验。运行程序,输入:

我叫 MK,正在写 AgentScope-Java 的公众号系列文章。

Agent 正常回应后,输入 exit 退出,然后重新执行一遍启动命令------这是一个全新的 JVM 进程。这次只问一句:

我叫什么?在做什么?

【图4:两次运行的终端对比截图】

Agent 准确答出了「MK」和「在写 AgentScope-Java 系列文章」。第一轮对话发生在已经死掉的进程里,凭什么第二个进程知道?

答案在两个目录。

状态目录 :会话状态在每次调用后自动持久化到用户主目录下(注意不是项目目录):

  • Windows:C:\Users\你的用户名\.agentscope\state\note-taker\mk\demo-session\agent_state.json
  • macOS / Linux:~/.agentscope/state/note-taker/mk/demo-session/agent_state.json

路径里的三段分别是 agent 名(note-taker)、用户 ID(mk)、会话 ID(demo-session),与代码里 name / userId / sessionId 一一对应。新进程用相同 sessionId 启动时自动加载这个文件恢复上下文。

【图5:state 目录与 agent_state.json 截图(打开文件确认无 Key 再截)】

workspace 目录 .agentscope/workspace/:这是 Agent 的「家」,里面躺着三样东西------

  • AGENTS.md:人格定义(框架自动生成,可手改,改完下次推理即生效)
  • memory/:分层长期记忆,对话超过阈值后自动蒸馏事实沉淀
  • sessions/:永不压缩的原始会话日志

【图6:workspace 目录树截图】

这就是 HarnessAgent 和「玩具 Demo」的分水岭:Agent 的状态不依赖进程内存,进程只是它的一个化身。 生产环境把本地文件后端换成 RedisAgentStateStore,多副本部署任意节点都能恢复用户上下文,代码不用改------这个留到 P4 展开。

四、进阶:流式输出

做 Web 界面时需要打字机效果,把 call() 换成 streamEvents(),拿到的是类型化事件流:

java 复制代码
agent.streamEvents(new UserMessage("帮我把今天的内容关键点列三条"))
    .doOnNext(event -> {
        if (event.getType() == AgentEventType.TEXT_BLOCK_DELTA) {
            System.out.print(((TextBlockDeltaEvent) event).getDelta());
        } else if (event.getType() == AgentEventType.TOOL_CALL_START) {
            System.out.println("\n[tool] " + ((ToolCallStartEvent) event).getToolCallName());
        }
    }).blockLast();

TEXT_BLOCK_DELTA 是文本增量,TOOL_CALL_START 是工具调用开始------事件流直接映射到前端的 SSE/WebSocket 推送,天然适配实时渲染。

五、踩坑记录

坑 1:Key 硬编码。 我的第一版就把 Key 写在了 OpenAIChatModel.builder().apiKey("sk-...") 里,跑是能跑,但这是开源/交付前的必修项。统一收敛到 ModelFactory 读环境变量,并确认 .gitignore 排除 .env 和 .agentscope/。

坑 2:版本迭代快,锁版本。 2.0 系列 API 有过一轮重构(1.x 的 Msg 构造方式和 2.0 不同),文章和工程都明确锁定 2.0.1,升级时看 Release Notes 再动。

坑 3:workspace 用相对路径,跟着工作目录走。 Paths.get(".agentscope/workspace") 是相对 JVM 启动目录的,IDEA 里跑和命令行 mvn exec:java 跑生成的 workspace 位置一致的前提是工作目录相同;部署到服务器时建议改绝对路径。

六、总结与下期预告

AgentScope-Java 2.0 给出的承诺是:Java 团队不必迁就 Python 生态,也能搭建生产级多智能体系统。本文验证了它最基础也是最关键的一环------状态在进程之外,Agent 才是连续的。

下一篇 P2 进入实战核心:用 @Tool 注解把普通 Java 方法变成 Agent 的工具,让 Agent 真正「动手」查数据、写文件,并拆解框架自动生成 JSON Schema 的机制。

框架官方文档:https://java.agentscope.io

基于 agentscope-harness 2.0.1,DeepSeek API


相关推荐
DisonTangor2 个月前
【腾讯混元雪耻归来】 Hy4 preview:770B 参数 MoE 旗舰模型,1M 上下文全面开源
人工智能·算法·开源·aigc·腾讯云·腾讯云ai代码助手
Lalolander2 个月前
WorkBuddy App 可以连接电脑吗?远程操控桌面端怎么用?
运维·电脑·腾讯云ai代码助手·workbuddy
朴实赋能2 个月前
妇儿医院 AI 助手怎么落地?CareWork 本地化智能体的多 Agent 协同与合规边界设计
大数据·人工智能·腾讯云ai代码助手·ai 智能体·医疗多 agent 协同·妇儿医院 ai 助手·本地化部署 ai
MGS浪疯3 个月前
我用 WorkBuddy 做了一个能记住前文的 AI 小说编辑器
人工智能·编辑器·腾讯云·腾讯云ai代码助手·workbuddy开发者分享季·codebuddy开发者分享季
阿伟AI说4 个月前
Codex 桌面版接入国产模型系列二:Codex++
java·开源软件·ai编程·腾讯云ai代码助手
华万通信king4 个月前
腾讯云ADP Agent Portal入门:从零搭建企业级AI智能体
腾讯云·腾讯云ai代码助手·adp
wanmeijuhao5 个月前
腾讯云 AI 代码助手编程挑战赛 + 构建开发板垃圾图片识别AI对话的Copilot
人工智能·腾讯云·copilot·腾讯云ai代码助手
小明说Java6 个月前
Ollama本地安装基础教程
ollama·腾讯云ai代码助手
榮華7 个月前
DOTA全图透视辅助下载DOTA全图科技辅助下载DOTA外挂下载魔兽争霸WAR3全图下载
数据库·科技·游戏·游戏引擎·游戏程序·ai编程·腾讯云ai代码助手