Java 调用 AgentScope 示例
概述
AgentScope Java SDK 是 AgentScope 多智能体框架的 Java 版本,当前版本为 2.0,支持在 Java 项目中直接构建和运行 AI Agent,无需调用外部 Python 服务。
官方文档:https://java.agentscope.io/v2/zh/docs/index.html
本文通过 4 个渐进式 Demo 演示核心用法:
| Demo | 功能 |
|---|---|
| Demo01 | 基础对话(非流式) |
| Demo02 | 流式输出(逐 token) |
| Demo03 | 多轮对话 + 会话持久化 + 用户隔离 |
| Demo04 | Skill 调用 + Think 过程打印 |
环境要求
- JDK 17+
- Maven 3.9+
Maven 依赖
<properties>
<agentscope.version>2.0.2</agentscope.version>
</properties>
<dependencies>
<!-- AgentScope Harness:HarnessAgent + 工作区 + 记忆管理 + 子 Agent -->
<dependency>
<groupId>io.agentscope</groupId>
<artifactId>agentscope-harness</artifactId>
<version>${agentscope.version}</version>
</dependency>
<!-- OpenAI 兼容模型扩展(支持 DeepSeek、本地代理等) -->
<dependency>
<groupId>io.agentscope</groupId>
<artifactId>agentscope-extensions-model-openai</artifactId>
<version>${agentscope.version}</version>
</dependency>
</dependencies>
agentscope-harness 会自动引入 agentscope-core。其他模型提供商(DashScope、Anthropic、Gemini 等)有独立的 agentscope-extensions-model-* 扩展包。
模型配置
Demo 中统一使用 OpenAI 兼容接口,配置示例(使用环境变量管理敏感信息):
// 从环境变量读取,避免硬编码
static final String API_KEY = System.getenv("OPENAI_API_KEY");
static final String BASE_URL = System.getenv("OPENAI_BASE_URL"); // 兼容接口时设置
static final String MODEL = "deepseek-v4-flash"; // 替换为实际模型名
若使用 DashScope(通义千问),可改用 agentscope-extensions-model-dashscope 并设置 DASHSCOPE_API_KEY:
import io.agentscope.extensions.model.dashscope.DashScopeChatModel;
DashScopeChatModel model = DashScopeChatModel.builder()
.apiKey(System.getenv("DASHSCOPE_API_KEY"))
.modelName("qwen-max")
.stream(false)
.build();
Demo01:基础对话
最简单的用法:构建 HarnessAgent → 发送消息 → 获取回复。
import io.agentscope.core.agent.RuntimeContext;
import io.agentscope.core.message.UserMessage;
import io.agentscope.extensions.model.openai.OpenAIChatModel;
import io.agentscope.harness.agent.HarnessAgent;
import java.nio.file.Paths;
public class Demo01BasicChat {
public static void main(String[] args) {
// 1. 构建模型(OpenAI 兼容)
OpenAIChatModel model = OpenAIChatModel.builder()
.apiKey(System.getenv("OPENAI_API_KEY"))
.baseUrl(System.getenv("OPENAI_BASE_URL")) // 兼容接口时设置
.modelName("deepseek-v4-flash")
.stream(false)
.build();
// 2. 构建 HarnessAgent
HarnessAgent agent = HarnessAgent.builder()
.name("assistant")
.sysPrompt("你是一个乐于助人的 AI 助手,请用中文回答用户问题。")
.model(model)
.workspace(Paths.get("/tmp/agentscope-demo/workspace"))
.disableCompaction() // demo 中关闭上下文压缩
.disableFilesystemTools() // demo 中关闭文件系统工具
.disableShellTool() // demo 中关闭 shell 工具
.build();
// 3. 构建运行上下文(sessionId 标识会话,userId 标识用户)
RuntimeContext ctx = RuntimeContext.builder()
.sessionId("demo01-session")
.userId("demo-user")
.build();
// 4. 发送消息,call() 返回 Mono<Msg>,.block() 阻塞等待回复
var reply1 = agent.call(
new UserMessage("你好!请用一句话介绍 AgentScope Java SDK。"), ctx
).block();
System.out.println("助手:" + (reply1 != null ? reply1.getTextContent() : ""));
var reply2 = agent.call(
new UserMessage("Java 和 Python 哪个更适合做后端开发?"), ctx
).block();
System.out.println("助手:" + (reply2 != null ? reply2.getTextContent() : ""));
agent.close();
}
}
关键 API:
| API | 说明 |
|---|---|
HarnessAgent.builder() |
构建 Agent,包含工作区、记忆、会话持久化等工程能力 |
RuntimeContext |
每次调用的上下文,携带 sessionId、userId |
agent.call(msg, ctx) |
发送消息,返回 Mono<Msg>(响应式) |
reply.getTextContent() |
从回复中提取纯文本内容 |
Demo02:流式输出
使用 streamEvents() 订阅事件流,实时打印每个 token。
import io.agentscope.core.event.AgentEventType;
import io.agentscope.core.event.TextBlockDeltaEvent;
import io.agentscope.core.event.ToolCallStartEvent;
// 开启流式模式
OpenAIChatModel model = OpenAIChatModel.builder()
.apiKey(System.getenv("OPENAI_API_KEY"))
.baseUrl(System.getenv("OPENAI_BASE_URL"))
.modelName("deepseek-v4-flash")
.stream(true) // 关键:开启流式
.build();
HarnessAgent agent = HarnessAgent.builder()
.name("stream-assistant")
.sysPrompt("你是一个乐于助人的 AI 助手,请用中文回答用户问题。")
.model(model)
.workspace(Paths.get("/tmp/agentscope-demo/workspace"))
.disableCompaction()
.disableFilesystemTools()
.disableShellTool()
.build();
RuntimeContext ctx = RuntimeContext.builder()
.sessionId("demo02-session")
.userId("demo-user")
.build();
// streamEvents 返回 Flux<AgentEvent>,逐事件处理
agent.streamEvents(new UserMessage("请列出 Java 的 5 个核心特性,每条一行。"), ctx)
.doOnNext(event -> {
AgentEventType type = event.getType();
if (type == AgentEventType.TEXT_BLOCK_DELTA) {
// 文本增量:实时打印 token
System.out.print(((TextBlockDeltaEvent) event).getDelta());
System.out.flush();
} else if (type == AgentEventType.TOOL_CALL_START) {
// 工具调用开始
System.out.println("\n[工具调用] "
+ ((ToolCallStartEvent) event).getToolCallName());
} else if (type == AgentEventType.AGENT_END) {
System.out.println("\n[回复完成]");
}
})
.blockLast(); // 阻塞直到流结束
常用 AgentEventType:
| 事件类型 | 说明 |
|---|---|
TEXT_BLOCK_START / TEXT_BLOCK_DELTA / TEXT_BLOCK_END |
文本块开始/增量/结束 |
THINKING_BLOCK_START / THINKING_BLOCK_DELTA / THINKING_BLOCK_END |
模型思考过程(Think) |
TOOL_CALL_START / TOOL_CALL_END |
工具调用开始 / 结束 |
TOOL_RESULT_START / TOOL_RESULT_END |
工具结果开始 / 结束 |
MODEL_CALL_START / MODEL_CALL_END |
模型调用开始 / 结束 |
AGENT_START / AGENT_END / AGENT_RESULT |
Agent 级别事件 |
Demo03:多轮对话与会话持久化
HarnessAgent 通过 sessionId 自动管理上下文,不同 userId 的会话完全隔离。
import io.agentscope.harness.agent.memory.compaction.CompactionConfig;
// 开启压缩:超过 30 条消息时触发,保留最近 10 条
HarnessAgent agent = HarnessAgent.builder()
.name("chat-assistant")
.sysPrompt("你是一个乐于助人的 AI 助手,请用中文回答用户问题,回答简洁。")
.model(model)
.workspace(Paths.get("/tmp/agentscope-demo/workspace"))
.compaction(CompactionConfig.builder()
.triggerMessages(30)
.keepMessages(10)
.build())
.disableFilesystemTools()
.disableShellTool()
.build();
// ── 场景 1:Alice 的多轮对话(同一 session,Agent 记住上下文)──────
RuntimeContext aliceCtx = RuntimeContext.builder()
.sessionId("alice-session-01")
.userId("alice")
.build();
agent.call(new UserMessage("我叫 Alice,今天想学习 AgentScope。"), aliceCtx).block();
agent.call(new UserMessage("AgentScope 支持哪些模型?"), aliceCtx).block();
// Agent 记住了用户名字
var r3 = agent.call(new UserMessage("你还记得我叫什么名字吗?"), aliceCtx).block();
System.out.println(r3.getTextContent()); // → "你叫 Alice"
// ── 场景 2:Bob 的独立会话(不同 userId,完全隔离)──────────────────
RuntimeContext bobCtx = RuntimeContext.builder()
.sessionId("bob-session-01")
.userId("bob")
.build();
// Bob 不知道 Alice 的存在
var r4 = agent.call(new UserMessage("你知道 Alice 是谁吗?"), bobCtx).block();
System.out.println(r4.getTextContent()); // → "我不知道 Alice"
// ── 场景 3:Alice 恢复会话(相同 sessionId,跨进程持久化)────────────
// 进程重启后,相同 sessionId 依然能恢复上下文
var r5 = agent.call(new UserMessage("我之前跟你说我在学什么?"), aliceCtx).block();
System.out.println(r5.getTextContent()); // → "你说你在学 AgentScope"
会话状态存储:
默认使用 JsonFileAgentStateStore,状态保存到 ~/.agentscope/state/<agentId>/<userId>/<sessionId>/agent_state.json。生产环境可替换为 Redis 或 MySQL:
// Redis 状态存储(需引入 agentscope-extensions-redis)
HarnessAgent agent = HarnessAgent.builder()
// ...
.stateStore(new RedisAgentStateStore(redisClient))
.build();
Demo04:Skill 调用
Skill 是基于 Markdown 的指令包,无需写新工具代码即可扩展 Agent 能力。Agent 通过内置工具 load_skill_through_path 读取 SKILL.md 指令,再用已有工具按指令执行。
Skill 目录结构
src/main/resources/skills/
├── code-reviewer/
│ ├── SKILL.md # 必需:frontmatter 元数据 + 指令
│ └── references/
│ └── java-style-guide.md # 可选:参考资料,Agent 按需读取
└── data-analyzer/
└── SKILL.md
SKILL.md 格式
---
name: code-reviewer
description: 当用户需要代码评审、代码质量分析、风格检查或最佳实践建议时使用。
---
# Code Reviewer Skill
你是一位专业的代码评审专家。当用户提交代码片段进行评审时,请按以下步骤执行:
## 评审维度
1. **代码质量**:检查代码逻辑是否正确、是否有潜在 bug
2. **安全性**:是否存在安全漏洞(如 SQL 注入、空指针等)
...
参考规范请见 `references/java-style-guide.md`
注意:
description决定 Agent 是否使用这个 Skill,要写得具体("当用户需要… 时使用"),而不是泛泛的功能描述。
加载并使用 Skill
import io.agentscope.core.skill.repository.ClasspathSkillRepository;
// 1. 从 classpath 加载(对应 src/main/resources/skills/)
ClasspathSkillRepository skillRepo = new ClasspathSkillRepository("skills");
// 查看已加载的 skill
skillRepo.getAllSkillNames().forEach(name -> System.out.println(" - " + name));
// 输出:
// - code-reviewer
// - data-analyzer
// 2. 构建带 skill 的 Agent(注意:不要 disableFilesystemTools/disableShellTool)
HarnessAgent agent = HarnessAgent.builder()
.name("skill-agent")
.sysPrompt("你是一个专业的技术助手,擅长代码评审和数据分析。\n"
+ "当用户提出相关需求时,请主动使用合适的 skill 来完成任务。\n"
+ "请用中文回复。")
.model(model)
.workspace(Paths.get("/tmp/agentscope-demo/skill-workspace"))
.skillRepository(skillRepo) // 注册 skill 仓库
.disableCompaction()
.build();
// 3. 每次使用唯一 sessionId,确保每次全新推理(避免 session 缓存影响 think 输出)
RuntimeContext ctx = RuntimeContext.builder()
.sessionId("code-review-" + System.currentTimeMillis())
.userId("demo-user")
.build();
// 4. 直接提问,Agent 会自动判断并加载对应 skill
String question = "请帮我评审以下代码:\n```java\nString sql = \"SELECT * FROM users WHERE id=\" + userId;\n```";
streamAndPrint(agent, question, ctx);
打印 Think 过程
支持思考型模型时,THINKING_BLOCK_* 事件携带模型的推理过程,可用于调试 Agent 决策逻辑:
import io.agentscope.core.event.ThinkingBlockDeltaEvent;
private static void streamAndPrint(HarnessAgent agent, String message, RuntimeContext ctx) {
agent.streamEvents(new UserMessage(message), ctx)
.doOnNext(event -> {
AgentEventType type = event.getType();
// ── 思考过程(Think)──────────────────────────────────────────
if (type == AgentEventType.THINKING_BLOCK_START) {
System.out.println("\n┌─ 💭 Think ─────────────────────────────");
} else if (type == AgentEventType.THINKING_BLOCK_DELTA) {
System.out.print(((ThinkingBlockDeltaEvent) event).getDelta());
System.out.flush();
} else if (type == AgentEventType.THINKING_BLOCK_END) {
System.out.println("\n└────────────────────────────────────────\n");
// ── 正式回复文本 ──────────────────────────────────────────────
} else if (type == AgentEventType.TEXT_BLOCK_DELTA) {
System.out.print(((TextBlockDeltaEvent) event).getDelta());
System.out.flush();
// ── 工具调用(含 Skill 加载)─────────────────────────────────
} else if (type == AgentEventType.TOOL_CALL_START) {
String toolName = ((ToolCallStartEvent) event).getToolCallName();
if (toolName.contains("load_skill")) {
System.out.println("\n\n[>> 正在加载 Skill: " + toolName + " <<]");
} else {
System.out.println("\n[工具调用] " + toolName);
}
// ── 回复结束 ──────────────────────────────────────────────────
} else if (type == AgentEventType.AGENT_END) {
System.out.println();
}
})
.blockLast();
}
运行输出示例:
=== 已加载 Skills ===
- code-reviewer
- data-analyzer
┌─ 💭 Think ─────────────────────────────
用户要求评审一段 SQL 拼接代码。这是 SQL 注入漏洞的典型写法。
有 code-reviewer 技能可用,我应该先加载它来提供专业评审。
└────────────────────────────────────────
[>> 正在加载 Skill: load_skill_through_path <<]
## 代码评审报告
### 总体评价
**1 / 5** — 存在严重 SQL 注入漏洞,不可上生产...
Think 不显示的原因:若 sessionId 复用,Agent 直接返回缓存的历史回复,不会重新推理,自然没有 think 事件。每次调用使用
System.currentTimeMillis()生成唯一 sessionId 即可解决。
其他 Skill 仓库类型
除 ClasspathSkillRepository 外,还支持多种来源:
// 文件系统(本地目录)
new FileSystemSkillRepository(Paths.get("/path/to/skills"))
// Git 仓库(需引入 agentscope-extensions-skill-git-repository)
new GitSkillRepository("https://github.com/your-org/team-skills.git")
// 多仓库叠加(后注册的优先级更高,同名 skill 后者覆盖前者)
HarnessAgent.builder()
.skillRepository(communitySkills) // 低优先级
.skillRepository(teamSkills) // 高优先级
.build();
项目结构
agentscope-java-demo/
├── pom.xml
└── src/main/
├── java/com/example/demo/
│ ├── Demo01BasicChat.java # 基础对话
│ ├── Demo02StreamOutput.java # 流式输出
│ ├── Demo03MultiTurnChat.java # 多轮对话 + 会话持久化
│ └── Demo04SkillDemo.java # Skill 调用 + Think 打印
└── resources/skills/
├── code-reviewer/
│ ├── SKILL.md
│ └── references/java-style-guide.md
└── data-analyzer/
└── SKILL.md
编译运行:
mvn package -q -DskipTests
java -cp target/agentscope-java-demo-1.0-SNAPSHOT.jar com.example.demo.Demo01BasicChat
java -cp target/agentscope-java-demo-1.0-SNAPSHOT.jar com.example.demo.Demo02StreamOutput
java -cp target/agentscope-java-demo-1.0-SNAPSHOT.jar com.example.demo.Demo03MultiTurnChat
java -cp target/agentscope-java-demo-1.0-SNAPSHOT.jar com.example.demo.Demo04SkillDemo
参考资料
- AgentScope Java SDK GitHub
- AgentScope Java 官方文档 v2
- 快速开始
- Tool 与 Skill 文档
- Harness Skill 文档