关于 agentscope-java
agentscope-java 是基于 Project Reactor、面向 Java 17+ 的响应式多 Agent 框架。此技能指导编码 Agent 正确使用其 API,涵盖非阻塞代码、项目配置与常见用法。
主要功能
- 01基于 Reactor 的异步 Agent 操作
- 02消息驱动的 Agent 通信
- 03可组合的串行与并行流水线
- 04Toolkit 工具与生命周期钩子
- 05Java 17 配置与 API 指引
适用场景
- 01编写非阻塞的 AgentScope Java 逻辑
- 02配置模型与 Maven 依赖
- 03创建工具、钩子和 Agent 流水线
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ agentscope-ai/ agentscope-java --skill agentscope-java安装后在 Claude Code 中输入/agentscope-java确认已加载。
详细介绍
当用户要求你编写 AgentScope Java 代码时,请严格遵循以下说明。
关键规则——绝不可违反
🚫 绝对禁止:
- 绝不要在示例代码中使用
.block()——这是最常见的错误。只有在main()方法或测试代码中明确创建可运行示例时,才可以使用.block()。 - 绝不要使用
Thread.sleep()——请改用Mono.delay()。 - 绝不要使用
ThreadLocal——请使用 Reactor Context 和Mono.deferContextual()。 - 绝不要硬编码 API 密钥——始终使用
System.getenv()。 - 绝不要默默忽略错误——始终记录错误并提供回退值。
- 绝不要使用错误的导入路径——共享模型接口位于
io.agentscope.core.model.*;提供商模型位于io.agentscope.extensions.model.<provider>.*。
✅ 始终遵循:
- 对所有异步操作使用
Mono和Flux。 - 使用
.map()、.flatMap()、.then()链接操作。 - 使用 Builder 模式创建 Agent、模型和消息。
- 使用
.onErrorResume()或.onErrorReturn()处理错误。 - 使用 SLF4J 为重要操作添加日志。
- 使用正确的导入:
import io.agentscope.extensions.model.dashscope.DashScopeChatModel; - 使用正确的 API(许多方法并不存在或已更改):
- 使用
toolkit.registerTool(),而不是registerObject() - 使用
toolkit.getToolNames(),而不是getTools() - 使用
event.getToolUse().getName(),而不是getToolName() - 使用
result.getOutput(),而不是getContent()(ToolResultBlock) - 使用
event.getToolResult(),而不是getResult()(PostActingEvent) - 使用
toolUse.getInput(),而不是getArguments()(ToolUseBlock) - 模型 Builder:没有
temperature()方法,请使用defaultOptions(GenerateOptions.builder()...) - Hook 事件:没有
getMessages()、getResponse()、getIterationCount()、getThinkingBlock()方法 - ToolResultBlock:没有
getToolUseName()方法,请改用event.getToolUse().getName() - ToolResultBlock.getOutput() 返回
List<ContentBlock>,而不是String,需要进行转换 - @ToolParam 格式:必须使用
@ToolParam(name = "x", description = "y"),而不是@ToolParam(name="x")
- 使用
生成代码时
首先:确定上下文
- 这是
main()方法或测试代码吗?→ 可以使用.block()(但请添加警告注释) - 这是 Agent 逻辑、服务方法或库代码吗?→ 禁止使用
.block()
对于你提供的每个代码示例:
- 检查:是否使用了
.block()?→ 如果在非 main、非测试代码中使用了,请重写。 - 检查:所有操作是否都为非阻塞?→ 如果不是,请修正。
- 检查:是否处理了错误?→ 如果没有,请添加。
- 检查:API 密钥是否来自环境变量?→ 如果不是,请修改。
- 检查:导入是否正确?→ 如果从
io.agentscope.core.model.*导入提供商模型,请改为io.agentscope.extensions.model.<provider>.*。
Agent 逻辑的默认代码结构:
// ✅ CORRECT - Non-blocking, reactive (use this pattern by default)
return model.generate(messages, null, null)
.map(response -> processResponse(response))
.onErrorResume(e -> {
log.error("Operation failed", e);
return Mono.just(fallbackValue);
});
// ❌ WRONG - Never generate this in agent logic
String result = model.generate(messages, null, null).block(); // DON'T DO THIS
仅用于 main() 方法(添加警告注释):
public static void main(String[] args) {
// ⚠️ .block() is ONLY allowed here because this is a main() method
Msg response = agent.call(userMsg).block();
System.out.println(response.getTextContent());
}
项目设置
创建新的 AgentScope 项目时,请使用正确的 Maven 依赖:
Maven 配置(pom.xml)
用于生产环境(推荐):
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>io.agentscope</groupId>
<artifactId>agentscope</artifactId>
<version>1.0.12</version>
</dependency>
</dependencies>
用于本地开发(如果正在处理源代码):
<properties>
<agentscope.version>1.0.12</agentscope.version>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>io.agentscope</groupId>
<artifactId>agentscope-core</artifactId>
<version>${agentscope.version}</version>
</dependency>
<dependency>
<groupId>io.agentscope</groupId>
<artifactId>agentscope-extensions-model-dashscope</artifactId>
<version>${agentscope.version}</version>
</dependency>
</dependencies>
⚠️ 重要:版本选择
- 生产环境使用
agentscope:1.0.12(稳定版,来自 Maven Central) - 仅在开发 AgentScope 本身时使用
agentscope-core:1.0.12 - 绝不要使用版本
0.1.0-SNAPSHOT——该版本不存在
⚠️ 关键:常见依赖错误
❌ 错误——这些构件不存在:
<dependency>
<groupId>io.agentscope</groupId>
<artifactId>agentscope-model-dashscope</artifactId>
</dependency>
<dependency>
<groupId>io.agentscope</groupId>
<artifactId>agentscope-model-openai</artifactId>
</dependency>
❌ 错误——这些版本不存在:
<dependency>
<groupId>io.agentscope</groupId>
<artifactId>agentscope-core</artifactId>
<version>0.1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>io.agentscope</groupId>
<artifactId>agentscope</artifactId>
<version>0.1.0</version>
</dependency>
✅ 正确——使用稳定版本:
<dependency>
<groupId>io.agentscope</groupId>
<artifactId>agentscope</artifactId>
<version>1.0.12</version>
</dependency>
可用模型类(特定提供商的扩展模块)
// DashScope (Alibaba Cloud)
import io.agentscope.extensions.model.dashscope.DashScopeChatModel;
// OpenAI
import io.agentscope.extensions.model.openai.OpenAIChatModel;
// Gemini (Google)
import io.agentscope.extensions.model.gemini.GeminiChatModel;
// Anthropic (Claude)
import io.agentscope.extensions.model.anthropic.AnthropicChatModel;
// Ollama (Local models)
import io.agentscope.extensions.model.ollama.OllamaChatModel;
可选扩展
<dependency>
<groupId>io.agentscope</groupId>
<artifactId>agentscope-extensions-mem0</artifactId>
<version>${agentscope.version}</version>
</dependency>
<dependency>
<groupId>io.agentscope</groupId>
<artifactId>agentscope-extensions-rag-dify</artifactId>
<version>${agentscope.version}</version>
</dependency>
项目概述与架构
AgentScope Java 是一个基于 Project Reactor 和 Java 17+ 构建的响应式、消息驱动型多 Agent 框架。
核心抽象
Agent:执行的基本单元。大多数 Agent 都扩展AgentBase。Msg:Agent 之间交换的消息对象。Memory:存储对话历史(InMemoryMemory、LongTermMemory)。Toolkit&AgentTool:定义 Agent 可使用的能力。Model:与大模型(OpenAI、DashScope、Gemini、Anthropic 等)交互。Hook:在生命周期的不同阶段拦截并修改 Agent 执行过程。Pipeline:以串行或并行模式编排多个 Agent。
响应式特性
几乎所有操作(Agent 调用、模型推理、工具执行)都返回 Mono<T> 或 Flux<T>。
核心设计原则
- 非阻塞:所有 I/O 操作均为异步
- 消息驱动:Agent 通过不可变的
Msg对象通信 - 可组合:Agent 和 Pipeline 可以嵌套和组合
- 可扩展:Hook 和自定义工具支持深度定制
编码规范与最佳实践
2.1 Java 版本与风格
目标版本为 Java 17(LTS),以获得最大的兼容性:
- 使用 Java 17 特性(Record、Switch 表达式、instanceof 模式匹配、
var、Sealed 类) - 避免使用 Java 21+ 预览特性(switch 中的模式匹配、Record 模式)
- 遵循标准 Java 约定(类名使用 PascalCase,方法和变量名使用 camelCase)
- 适当使用 Lombok(用于 DTO/Message 的
@Data、@Builder) - 数据类优先采用不可变设计
- 使用能体现领域概念的有意义的名称
⚠️ 关键:避免使用预览特性
// ❌ WRONG - Requires Java 21 with --enable-preview
return switch (event) {
case PreReasoningEvent e -> Mono.just(e); // Pattern matching in switch
default -> Mono.just(event);
};
// ✅ CORRECT - Java 17 compatible
if (event instanceof PreReasoningEvent e) { // Pattern matching for instanceof (Java 17)
return Mono.just(event);
} else {
return Mono.just(event);
}
2.2 响应式编程(关键)
⚠️ 切勿在 Agent 逻辑中阻塞
阻塞操作会中断响应式链并导致性能问题。
规则:
- ❌ 切勿使用
.block()执行 Agent 逻辑(仅可用于main方法或测试) - ✅ 单个结果使用
Mono(例如agent.call()) - ✅ 流式响应使用
Flux(例如model.stream()) - ✅ 使用
.map()、.flatMap()、.then()链接操作 - ✅ 使用
Mono.defer()进行延迟求值 - ✅ 使用
Mono.deferContextual()访问响应式上下文
示例:
// ❌ WRONG - Blocking
public Mono<String> processData(String input) {
String result = externalService.call(input).block(); // DON'T DO THIS
return Mono.just(result);
}
// ✅ CORRECT - Non-blocking
public Mono<String> processData(String input) {
return externalService.call(input)
.map(this::transform)
.flatMap(this::validate);
}
2.3 消息处理(Msg)
使用 Builder 模式创建消息:
Msg userMsg = Msg.builder()
.role(MsgRole.USER)
.content(TextBlock.builder().text("Hello").build())
.name("user")
.build();
内容块:
TextBlock:用于文本内容ThinkingBlock:用于思维链(CoT)推理ToolUseBlock:用于工具调用ToolResultBlock:用于工具输出
辅助方法:
// Prefer safe helper methods
String text = msg.getTextContent(); // Safe, returns null if not found
// Avoid direct access
String text = msg.getContent().get(0).getText(); // May throw NPE
2.4 实现 Agent
扩展 AgentBase 并实现 doCall(List<Msg> msgs):
public class MyAgent extends AgentBase {
private final Model model;
private final Memory memory;
public MyAgent(String name, Model model) {
super(name, "A custom agent", true, List.of());
this.model = model;
this.memory = new InMemoryMemory();
}
@Override
protected Mono<Msg> doCall(List<Msg> msgs) {
// 1. Process inputs
if (msgs != null) {
msgs.forEach(memory::addMessage);
}
// 2. Call model or logic
return model.generate(memory.getMessages(), null, null)
.map(response -> Msg.builder()
.name(getName())
.role(MsgRole.ASSISTANT)
.content(TextBlock.builder().text(response.getText()).build())
.build());
}
}
2.5 工具定义
使用 @Tool 注解定义基于函数的工具。工具可以返回:
String(同步)Mono<String>(异步)Mono<ToolResultBlock>(用于复杂结果)
⚠️ 关键:@ToolParam 格式
- ✅ 正确:
@ToolParam(name = "city", description = "City name") - ❌ 错误:
@ToolParam(name="city", description="...")(=两侧没有空格) - ❌ 错误:
@ToolParam("city")(缺少 name= 和 description=)
同步工具示例:
public class WeatherTools {
@Tool(description = "Get current weather for a city. Returns temperature and conditions.")
public String getWeather(
@ToolParam(name = "city", description = "City name, e.g., 'San Francisco'")
String city) {
// Implementation
return "Sunny, 25°C";
}
}
异步工具示例:
public class AsyncTools {
private final WebClient webClient;
@Tool(description = "Fetch data from trusted API endpoint")
public Mono<String> fetchData(
@ToolParam(name = "url", description = "API endpoint URL (must start with https://api.myservice.com)")
String url) {
// SECURITY: Validate URL to prevent SSRF
if (!url.startsWith("https://api.myservice.com")) {
return Mono.just("Error: URL not allowed. Must start with https://api.myservice.com");
}
return webClient.get()
.uri(url)
.retrieve()
.bodyToMono(String.class)
.timeout(Duration.ofSeconds(10))
.onErrorResume(e -> Mono.just("Error: " + e.getMessage()));
}
}
注册到 Toolkit:
Toolkit toolkit = new Toolkit();
toolkit.registerTool(new WeatherTools());
toolkit.registerTool(new AsyncTools());
Hook 系统
Hook 可在生命周期的不同阶段拦截并修改 Agent 执行过程。
Hook 接口
public interface Hook {
<T extends HookEvent> Mono<T> onEvent(T event);
default int priority() { return 100; } // Lower = higher priority
}
常见 Hook 事件
PreReasoningEvent:LLM 推理之前(可修改)PostReasoningEvent:LLM 推理之后(可修改)ReasoningChunkEvent:流式推理分块(通知)PreActingEvent:工具执行之前(可修改)PostActingEvent:工具执行之后(可修改)ActingChunkEvent:流式工具执行(通知)
Hook 示例
兼容 Java 17+(推荐):
Hook loggingHook = new Hook() {
@Override
public <T extends HookEvent> Mono<T> onEvent(T event) {
// Use if-instanceof instead of switch patterns (Java 17 compatible)
if (event instanceof PreReasoningEvent e) {
log.info("Reasoning with model: {}", e.getModelName());
return Mono.just(event);
} else if (event instanceof PreActingEvent e) {
log.info("Calling tool: {}", e.getToolUse().getName());
return Mono.just(event);
} else if (event instanceof PostActingEvent e) {
log.info("Tool {} completed", e.getToolUse().getName());
return Mono.just(event);
} else {
return Mono.just(event);
}
}
@Override
public int priority() {
return 500; // Low priority (logging)
}
};
ReActAgent agent = ReActAgent.builder()
.name("Assistant")
.model(model)
.hook(loggingHook)
.build();
替代方案:传统 if-else(Java 17):
Hook loggingHook = new Hook() {
@Override
public <T extends HookEvent> Mono<T> onEvent(T event) {
if (event instanceof PreReasoningEvent) {
PreReasoningEvent e = (PreReasoningEvent) event;
log.info("Reasoning with model: {}", e.getModelName());
} else if (event instanceof PreActingEvent) {
PreActingEvent e = (PreActingEvent) event;
log.info("Calling tool: {}", e.getToolUse().getName());
} else if (event instanceof PostActingEvent) {
PostActingEvent e = (PostActingEvent) event;
log.info("Tool {} completed", e.getToolUse().getName());
}
return Mono.just(event);
}
@Override
public int priority() {
return 500;
}
};
优先级指南:
- 0-50:关键系统 Hook(身份验证、安全)
- 51-100:高优先级 Hook(验证、预处理)
- 101-500:普通优先级 Hook(业务逻辑)
- 501-1000:低优先级 Hook(日志、指标)
PIPELINE 模式
Pipeline 用于在结构化工作流中编排多个 Agent。
顺序 Pipeline
按顺序执行 Agent(一个 Agent 的输出成为下一个 Agent 的输入):
SequentialPipeline pipeline = SequentialPipeline.builder()
.addAgent(researchAgent)
.addAgent(summaryAgent)
.addAgent(reviewAgent)
.build();
Msg result = pipeline.execute(userInput).block();
扇出 Pipeline
并行执行 Agent 并汇总结果:
FanoutPipeline pipeline = FanoutPipeline.builder()
.addAgent(agent1)
.addAgent(agent2)
.addAgent(agent3)
.build();
Msg result = pipeline.execute(userInput).block();
适用场景:
- 顺序:每个 Agent 都依赖前一个 Agent 的输出时
- 扇出:Agent 可以独立工作且需要汇总结果时
内存管理
内存中(短期)
Memory memory = new InMemoryMemory();
长期记忆
// Configure long-term memory
LongTermMemory longTermMemory = Mem0LongTermMemory.builder()
.apiKey(System.getenv("MEM0_API_KEY"))
.userId("user_123")
.build();
// Use with agent
ReActAgent agent = ReActAgent.builder()
.name("Assistant")
.model(model)
.longTermMemory(longTermMemory)
.longTermMemoryMode(LongTermMemoryMode.BOTH) // STATIC_CONTROL, AGENTIC, or BOTH
.build();
内存模式:
STATIC_CONTROL:框架自动管理内存(通过 Hook)AGENTIC:Agent 决定何时使用内存(通过工具)BOTH:结合两种方式
MCP(模型上下文协议)集成
AgentScope 支持 MCP,可用于集成外部工具和资源。
// Create MCP client
// SECURITY: In production, use a specific version or a local binary to prevent supply chain attacks
McpClientWrapper mcpClient = McpClientBuilder.stdio()
.command("npx")
.args("-y", "@modelcontextprotocol/[email protected]", "/path/to/files") // Always pin versions
.build();
// Register with toolkit
Toolkit toolkit = new Toolkit();
toolkit.registration()
.mcpClient(mcpClient)
.enableTools(List.of("read_file", "write_file"))
.apply();
// Use with agent
ReActAgent agent = ReActAgent.builder()
.name("Assistant")
.model(model)
.toolkit(toolkit)
.build();
测试
使用 StepVerifier 进行单元测试
@Test
void testAgentCall() {
Msg input = Msg.builder()
.role(MsgRole.USER)
.content(TextBlock.builder().text("Hello").build())
.build();
StepVerifier.create(agent.call(input))
.assertNext(response -> {
assertEquals(MsgRole.ASSISTANT, response.getRole());
assertNotNull(response.getTextContent());
})
.verifyComplete();
}
模拟外部依赖
@Test
void testWithMockModel() {
Model mockModel = mock(Model.class);
when(mockModel.generate(any(), any(), any()))
.thenReturn(Mono.just(ChatResponse.builder()
.text("Mocked response")
.build()));
ReActAgent agent = ReActAgent.builder()
.name("TestAgent")
.model(mockModel)
.build();
// Test agent behavior
}
测试最佳实践:
- 始终使用
StepVerifier测试响应式链 - 模拟外部依赖(模型、API)
- 测试错误情况和边界条件
- 验证 Hook 是否正确调用
- 测试超时和取消场景
代码风格指南
日志记录
private static final Logger log = LoggerFactory.getLogger(MyClass.class);
// Use parameterized logging
log.info("Processing message from user: {}", userId);
log.error("Failed to call model: {}", modelName, exception);
错误处理
// Prefer specific error messages
return Mono.error(new IllegalArgumentException(
"Invalid model name: " + modelName + ". Expected one of: " + VALID_MODELS));
// Use onErrorResume for graceful degradation
return model.generate(msgs, null, null)
.onErrorResume(e -> {
log.error("Model call failed, using fallback", e);
return Mono.just(fallbackResponse);
});
空值安全
// Use Optional for nullable returns
public Optional<AgentTool> findTool(String name) {
return Optional.ofNullable(tools.get(name));
}
// Use Objects.requireNonNull for validation
public MyAgent(Model model) {
this.model = Objects.requireNonNull(model, "Model cannot be null");
}
注释
// Use Javadoc for public APIs
/**
* Creates a new agent with the specified configuration.
*
* @param name The agent name (must be unique)
* @param model The LLM model to use
* @return Configured agent instance
* @throws IllegalArgumentException if name is null or empty
*/
public static ReActAgent create(String name, Model model) {
// Implementation
}
// Use inline comments sparingly, only for complex logic
// Calculate exponential backoff: 2^attempt * baseDelay
Duration delay = Duration.ofMillis((long) Math.pow(2, attempt) * baseDelayMs);
主要库
- Reactor Core:用于响应式编程的
Mono、Flux - Jackson:JSON 序列化/反序列化
- SLF4J:日志记录(
private static final Logger log = LoggerFactory.getLogger(MyClass.class);) - OkHttp:用于模型 API 的 HTTP 客户端
- MCP SDK:模型上下文协议集成
- JUnit 5:测试框架
- Mockito:模拟框架
- Lombok:减少样板代码
禁止的做法
❌ 绝对不要这样做
-
在响应式链中阻塞
// ❌ WRONG return someMonoOperation().block(); -
使用 Thread.sleep() 或阻塞式 I/O
// ❌ WRONG Thread.sleep(1000); // ✅ CORRECT return Mono.delay(Duration.ofSeconds(1)); -
未同步就修改共享状态
// ❌ WRONG private List<Msg> messages = new ArrayList<>(); public void addMessage(Msg msg) { messages.add(msg); // Not thread-safe } -
静默忽略错误
// ❌ WRONG .onErrorResume(e -> Mono.empty()) // ✅ CORRECT .onErrorResume(e -> { log.error("Operation failed", e); return Mono.just(fallbackValue); }) -
在响应式代码中使用 ThreadLocal
// ❌ WRONG ThreadLocal<String> context = new ThreadLocal<>(); // ✅ CORRECT return Mono.deferContextual(ctx -> { String value = ctx.get("key"); // Use value }); -
创建 Agent 时未妥善管理资源
// ❌ WRONG - No cleanup public void processRequests() { for (int i = 0; i < 1000; i++) { ReActAgent agent = createAgent(); agent.call(msg).block(); } } -
将 API 密钥或机密硬编码
// ❌ WRONG String apiKey = "sk-1234567890"; // ✅ CORRECT String apiKey = System.getenv("OPENAI_API_KEY"); -
使用 Java 预览功能(需要 --enable-preview)
// ❌ WRONG - Requires Java 21 with --enable-preview return switch (event) { case PreReasoningEvent e -> handleReasoning(e); case PostActingEvent e -> handleActing(e); default -> Mono.just(event); }; // ✅ CORRECT - Java 17 compatible if (event instanceof PreReasoningEvent e) { return handleReasoning(e); } else if (event instanceof PostActingEvent e) { return handleActing(e); } else { return Mono.just(event); }
常见陷阱与解决方案
❌ 阻塞操作
// WRONG
Msg response = agent.call(msg).block(); // Don't block in agent logic
// CORRECT
return agent.call(msg)
.flatMap(response -> processResponse(response));
❌ 空值处理
// WRONG
String text = msg.getContent().get(0).getText(); // May throw NPE
// CORRECT
String text = msg.getTextContent(); // Safe helper method
// OR
String text = msg.getContentBlocks(TextBlock.class).stream()
.findFirst()
.map(TextBlock::getText)
.orElse("");
❌ 线程上下文
// WRONG
ThreadLocal<String> context = new ThreadLocal<>(); // May not work in reactive streams
// CORRECT
return Mono.deferContextual(ctx -> {
String value = ctx.get("key");
// Use value
});
❌ 吞掉错误
// WRONG
.onErrorResume(e -> Mono.empty()) // Silent failure
// CORRECT
.onErrorResume(e -> {
log.error("Failed to process: {}", input, e);
return Mono.just(createErrorResponse(e));
})
完整示例
package com.example.agentscope;
import io.agentscope.core.ReActAgent;
import io.agentscope.core.hook.Hook;
import io.agentscope.core.hook.HookEvent;
import io.agentscope.core.hook.ReasoningChunkEvent;
import io.agentscope.core.memory.InMemoryMemory;
import io.agentscope.core.message.Msg;
import io.agentscope.core.message.MsgRole;
import io.agentscope.core.message.TextBlock;
import io.agentscope.core.model.Model;
import io.agentscope.core.tool.Tool;
import io.agentscope.core.tool.ToolParam;
import io.agentscope.core.tool.Toolkit;
import io.agentscope.extensions.model.dashscope.DashScopeChatModel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import reactor.core.publisher.Mono;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
/**
* Complete example demonstrating AgentScope best practices.
*/
public class CompleteExample {
private static final Logger log = LoggerFactory.getLogger(CompleteExample.class);
public static void main(String[] args) {
// 1. Create model (no .temperature() method, use defaultOptions)
Model model = DashScopeChatModel.builder()
.apiKey(System.getenv("DASHSCOPE_API_KEY"))
.modelName("qwen-plus")
.stream(true)
.build();
// 2. Create toolkit with tools
Toolkit toolkit = new Toolkit();
toolkit.registerTool(new WeatherTools());
toolkit.registerTool(new TimeTools());
// 3. Create hook for streaming output
Hook streamingHook = new Hook() {
@Override
public <T extends HookEvent> Mono<T> onEvent(T event) {
if (event instanceof ReasoningChunkEvent e) {
String text = e.getIncrementalChunk().getTextContent();
if (text != null) {
System.out.print(text);
}
}
return Mono.just(event);
}
@Override
public int priority() {
return 500; // Low priority
}
};
// 4. Build agent
ReActAgent agent = ReActAgent.builder()
.name("Assistant")
.sysPrompt("You are a helpful assistant. Use tools when appropriate.")
.model(model)
.toolkit(toolkit)
.memory(new InMemoryMemory())
.hook(streamingHook)
.maxIters(10)
.build();
// 5. Use agent
Msg userMsg = Msg.builder()
.role(MsgRole.USER)
.content(TextBlock.builder()
.text("What's the weather in San Francisco and what time is it?")
.build())
.build();
try {
System.out.println("User: " + userMsg.getTextContent());
System.out.print("Assistant: ");
// ⚠️ IMPORTANT: .block() is ONLY allowed in main() methods for demo purposes
// NEVER use .block() in agent logic, service methods, or library code
Msg response = agent.call(userMsg).block();
System.out.println("\n\n--- Response Details ---");
System.out.println("Role: " + response.getRole());
System.out.println("Content: " + response.getTextContent());
} catch (Exception e) {
log.error("Error during agent execution", e);
System.err.println("Error: " + e.getMessage());
}
}
/**
* Example tool class for weather information.
*/
public static class WeatherTools {
@Tool(description = "Get current weather for a city. Returns temperature and conditions.")
public String getWeather(
@ToolParam(name = "city", description = "City name, e.g., 'San Francisco'")
String city) {
log.info("Getting weather for city: {}", city);
// Simulate API call
return String.format("Weather in %s: Sunny, 22°C, Light breeze", city);
}
}
/**
* Example tool class for time information.
*/
public static class TimeTools {
private static final DateTimeFormatter FORMATTER =
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
@Tool(description = "Get current date and time")
public String getCurrentTime() {
LocalDateTime now = LocalDateTime.now();
String formatted = now.format(FORMATTER);
log.info("Returning current time: {}", formatted);
return "Current time: " + formatted;
}
}
}
快速参考
创建 Agent
ReActAgent agent = ReActAgent.builder()
.name("AgentName")
.sysPrompt("System prompt")
.model(model)
.toolkit(toolkit)
.memory(memory)
.hooks(hooks)
.maxIters(10)
.build();
创建消息
Msg msg = Msg.builder()
.role(MsgRole.USER)
.content(TextBlock.builder().text("Hello").build())
.build();
注册工具
Toolkit toolkit = new Toolkit();
toolkit.registerTool(new MyTools());
创建 Hook
Hook hook = new Hook() {
public <T extends HookEvent> Mono<T> onEvent(T event) {
// Handle event
return Mono.just(event);
}
};
创建 Pipeline
SequentialPipeline pipeline = SequentialPipeline.builder()
.addAgent(agent1)
.addAgent(agent2)
.build();