第23章 基础案例分析
本章深入分析AgentScope-Java框架中的基础示例,帮助读者理解框架的核心用法和最佳实践。我们将逐一剖析quickstart目录下的典型示例,从代码结构、设计思路到运行机制进行全面解读。
23.1 示例概览
23.1.1 基础示例目录结构
agentscope-examples/
├── quickstart/ # 快速入门示例
│ ├── ToolCallingExample.java # 工具调用示例
│ ├── StructuredOutputExample.java # 结构化输出示例
│ ├── SessionExample.java # 会话管理示例
│ ├── MsgHubExample.java # 消息中心示例
│ ├── SequentialPipelineExample.java # 顺序管道示例
│ ├── PlanNotebookExample.java # 计划管理示例
│ ├── VisionExample.java # 多模态示例
│ └── StreamingWebExample.java # 流式Web示例
├── advanced/ # 高级示例
│ ├── RAGExample.java # RAG示例
│ ├── LangfuseExample.java # 可观测性示例
│ ├── RoutingByToolCallsExample.java # 路由示例
│ └── AutoMemoryExample.java # 自动记忆示例
└── ...
23.1.2 示例功能速查表
| 示例 | 核心功能 | 难度 | 适用场景 |
|---|---|---|---|
| ToolCallingExample | 工具调用 | 入门 | 函数调用、API集成 |
| StructuredOutputExample | 结构化输出 | 入门 | 数据提取、表单处理 |
| SessionExample | 会话持久化 | 入门 | 聊天机器人、连续对话 |
| MsgHubExample | 多智能体对话 | 中级 | 团队协作、群聊模拟 |
| SequentialPipelineExample | 管道处理 | 中级 | 工作流、内容处理 |
| RAGExample | 知识检索增强 | 中级 | 文档问答、知识库 |
23.2 工具调用示例深入分析
23.2.1 示例目标
ToolCallingExample演示了如何为Agent配备工具能力,使其能够执行时间查询、数学计算和信息搜索等实际操作。
23.2.2 核心架构
┌──────────────────────────────────────────────────────────────┐
│ ToolCallingExample │
├──────────────────────────────────────────────────────────────┤
│ ┌─────────────────────────────────────────────────────────┐ │
│ │ ReActAgent │ │
│ │ ┌─────────┐ ┌───────────────┐ ┌─────────────────┐ │ │
│ │ │ Model │ │ Memory │ │ Toolkit │ │ │
│ │ │(qwen) │ │ (InMemory) │ │ (SimpleTools) │ │ │
│ │ └─────────┘ └───────────────┘ └─────────────────┘ │ │
│ └─────────────────────────────────────────────────────────┘ │
│ │ │
│ ┌─────────────────────────▼─────────────────────────────┐ │
│ │ SimpleTools │ │
│ │ ┌────────────────┐ ┌────────────┐ ┌─────────────┐ │ │
│ │ │get_current_time│ │ calculate │ │ search │ │ │
│ │ │ (时区时间查询) │ │ (四则运算) │ │ (模拟搜索) │ │ │
│ │ └────────────────┘ └────────────┘ └─────────────┘ │ │
│ └───────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────┘
23.2.3 完整代码解析
步骤1:创建工具类
/**
* 工具类使用普通Java类定义,通过注解声明工具方法
*/
public static class SimpleTools {
/**
* 时间查询工具
* @Tool注解标记方法为可被Agent调用的工具
* @ToolParam注解描述参数,帮助LLM理解如何使用
*/
@Tool(
name = "get_current_time",
description = "Get the current time in a specific timezone")
public String getCurrentTime(
@ToolParam(
name = "timezone",
description = "Timezone name, e.g., 'Asia/Tokyo', 'America/New_York'")
String timezone) {
try {
ZoneId zoneId = ZoneId.of(timezone);
LocalDateTime now = LocalDateTime.now(zoneId);
DateTimeFormatter formatter =
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
return String.format("Current time in %s: %s",
timezone, now.format(formatter));
} catch (Exception e) {
return "Error: Invalid timezone. Try 'Asia/Tokyo' or 'America/New_York'";
}
}
/**
* 计算器工具
* 支持基本的四则运算
*/
@Tool(name = "calculate", description = "Calculate simple math expressions")
public String calculate(
@ToolParam(
name = "expression",
description = "Math expression to evaluate, e.g., '123 + 456', '10 * 20'")
String expression) {
try {
expression = expression.replaceAll("\\s+", "");
double result;
if (expression.contains("+")) {
String[] parts = expression.split("\\+");
result = Double.parseDouble(parts[0]) + Double.parseDouble(parts[1]);
} else if (expression.contains("-")) {
String[] parts = expression.split("-");
result = Double.parseDouble(parts[0]) - Double.parseDouble(parts[1]);
} else if (expression.contains("*")) {
String[] parts = expression.split("\\*");
result = Double.parseDouble(parts[0]) * Double.parseDouble(parts[1]);
} else if (expression.contains("/")) {
String[] parts = expression.split("/");
result = Double.parseDouble(parts[0]) / Double.parseDouble(parts[1]);
} else {
return "Error: Unsupported operation. Use +, -, *, or /";
}
return String.format("%s = %.2f", expression, result);
} catch (Exception e) {
return "Error: Invalid expression. Example: '123 + 456'";
}
}
/**
* 搜索工具(模拟实现)
* 实际项目中可以接入搜索API
*/
@Tool(name = "search", description = "Search for information (simulated)")
public String search(
@ToolParam(name = "query", description = "Search query")
String query) {
String lowerQuery = query.toLowerCase();
if (lowerQuery.contains("ai")) {
return "Search results for 'artificial intelligence':\n"
+ "1. AI is the simulation of human intelligence by machines\n"
+ "2. Common AI applications: chatbots, image recognition\n"
+ "3. Major AI technologies: machine learning, deep learning";
} else if (lowerQuery.contains("java")) {
return "Search results for 'java':\n"
+ "1. Java is a high-level, object-oriented programming language\n"
+ "2. First released by Sun Microsystems in 1995\n"
+ "3. Known for 'Write Once, Run Anywhere' philosophy";
} else {
return String.format("Search results for '%s': (simulated)", query);
}
}
}
步骤2:注册工具到Toolkit
// 创建工具包
Toolkit toolkit = new Toolkit();
// 注册工具类实例
// Toolkit会自动扫描@Tool注解的方法
toolkit.registerTool(new SimpleTools());
System.out.println("Registered tools:");
System.out.println(" - get_current_time: Get current time in a timezone");
System.out.println(" - calculate: Evaluate simple math expressions");
System.out.println(" - search: Simulate search functionality");
步骤3:创建配备工具的Agent
ReActAgent agent = ReActAgent.builder()
.name("ToolAgent")
.sysPrompt(
"You are a helpful assistant with access to tools. "
+ "Use tools when needed to answer questions accurately. "
+ "Always explain what you're doing when using tools.")
.model(
DashScopeChatModel.builder()
.apiKey(apiKey)
.modelName("qwen-max")
.stream(true)
.enableThinking(false)
.formatter(new DashScopeChatFormatter())
.build())
.toolkit(toolkit) // 关键:配置工具包
.memory(new InMemoryMemory())
.build();
23.2.4 执行流程分析
用户: "现在东京几点了?"
│
▼
┌─────────────────────────────────────────────────────────┐
│ Step 1: Reasoning (推理阶段) │
│ Agent分析问题,识别需要调用get_current_time工具 │
│ 生成工具调用参数: {"timezone": "Asia/Tokyo"} │
└─────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────┐
│ Step 2: Acting (执行阶段) │
│ 框架调用SimpleTools.getCurrentTime("Asia/Tokyo") │
│ 返回: "Current time in Asia/Tokyo: 2026-01-15 10:30:45"│
└─────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────┐
│ Step 3: Reasoning (再次推理) │
│ Agent将工具结果整合到回答中 │
│ 输出: "现在东京时间是2026年1月15日10点30分45秒。" │
└─────────────────────────────────────────────────────────┘
23.2.5 最佳实践要点
| 要点 | 说明 |
|---|---|
| 工具描述清晰 | description要准确描述工具功能,帮助LLM正确选择 |
| 参数说明完整 | 每个参数都要有详细描述和示例 |
| 错误处理完善 | 工具方法应处理异常情况,返回友好的错误信息 |
| 返回值格式化 | 返回结构化的结果,便于Agent理解和引用 |
23.3 结构化输出示例深入分析
23.3.1 示例目标
StructuredOutputExample展示如何让Agent输出结构化的JSON数据,而不是自由文本,这对于数据提取和系统集成场景非常重要。
23.3.2 核心架构
┌──────────────────────────────────────────────────────────────┐
│ StructuredOutputExample │
├──────────────────────────────────────────────────────────────┤
│ │
│ ┌───────────────────────────────────────────────────────┐ │
│ │ ReActAgent │ │
│ │ │ │ │
│ │ call(msg, Schema) │ │
│ │ │ │ │
│ │ ▼ │ │
│ │ ┌─────────────────────────────────────────────────┐ │ │
│ │ │ StructuredOutputHook │ │ │
│ │ │ ┌─────────────────┐ ┌───────────────────────┐ │ │ │
│ │ │ │ Schema生成 │→│ JSON解析与验证 │ │ │ │
│ │ │ │ (generate_response)│ (自动重试机制) │ │ │ │
│ │ │ └─────────────────┘ └───────────────────────┘ │ │ │
│ │ └─────────────────────────────────────────────────┘ │ │
│ └───────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────┐ ┌─────────────┐ ┌────────────────┐ │
│ │ProductRequirements│ │ ContactInfo │ │SentimentAnalysis│ │
│ │ - productType │ │ - name │ │ - sentiment │ │
│ │ - brand │ │ - email │ │ - scores │ │
│ │ - minRam │ │ - phone │ │ - topics │ │
│ │ - maxBudget │ │ - company │ │ - summary │ │
│ │ - features │ │ │ │ │ │
│ └─────────────────┘ └─────────────┘ └────────────────┘ │
└──────────────────────────────────────────────────────────────┘
23.3.3 Schema定义
/**
* 产品需求提取Schema
* 字段类型会自动映射到JSON Schema类型
*/
public static class ProductRequirements {
public String productType; // 产品类型
public String brand; // 品牌偏好
public Integer minRam; // 最低内存(GB)
public Double maxBudget; // 最高预算
public List<String> features; // 特性列表
public ProductRequirements() {} // 必须有无参构造函数
}
/**
* 联系人信息提取Schema
*/
public static class ContactInfo {
public String name; // 姓名
public String email; // 电子邮件
public String phone; // 电话
public String company; // 公司名称
public ContactInfo() {}
}
/**
* 情感分析结果Schema
* 包含数值类型字段
*/
public static class SentimentAnalysis {
public String overallSentiment; // "positive", "negative", "neutral"
public Double positiveScore; // 0.0 到 1.0
public Double negativeScore; // 0.0 到 1.0
public Double neutralScore; // 0.0 到 1.0
public List<String> keyTopics; // 关键话题
public String summary; // 分析总结
public SentimentAnalysis() {}
}
23.3.4 结构化输出调用方式
同步阻塞方式
/**
* 产品需求提取示例
*/
private static void runProductAnalysisExample(ReActAgent agent) {
String query = "I'm looking for a laptop. I need at least 16GB RAM, "
+ "prefer Apple brand, and my budget is around $2000. "
+ "It should be lightweight for travel.";
System.out.println("Query: " + query);
// 创建用户消息
Msg userMsg = Msg.builder()
.role(MsgRole.USER)
.content(TextBlock.builder()
.text("Extract the product requirements from this query: " + query)
.build())
.build();
try {
// 关键:传入Schema类型作为第二个参数
Msg msg = agent.call(userMsg, ProductRequirements.class).block();
// 从消息中提取结构化数据
ProductRequirements result = msg.getStructuredData(ProductRequirements.class);
// 使用强类型访问提取的数据
System.out.println("Extracted structured data:");
System.out.println(" Product Type: " + result.productType);
System.out.println(" Brand: " + result.brand);
System.out.println(" Min RAM: " + result.minRam + " GB");
System.out.println(" Max Budget: $" + result.maxBudget);
System.out.println(" Features: " + result.features);
} catch (Exception e) {
System.err.println("Error: " + e.getMessage());
}
}
流式方式
/**
* 流式结构化输出
* 支持在流式处理过程中获取结构化结果
*/
private static void runStreamProductAnalysisExample(ReActAgent agent) {
Msg userMsg = Msg.builder()
.role(MsgRole.USER)
.content(TextBlock.builder()
.text("Extract the product requirements from this query: " + query)
.build())
.build();
try {
// 使用stream方法,传入StreamOptions和Schema类型
Flux<Event> eventFlux = agent.stream(
userMsg,
StreamOptions.defaults(),
ProductRequirements.class
);
// 获取最后一个事件中的结构化数据
ProductRequirements result = eventFlux.blockLast()
.getMessage()
.getStructuredData(ProductRequirements.class);
System.out.println("Extracted structured data:");
System.out.println(" Product Type: " + result.productType);
System.out.println(" Brand: " + result.brand);
} catch (Exception e) {
System.err.println("Error: " + e.getMessage());
}
}
23.3.5 类型映射关系
| Java类型 | JSON Schema类型 | 示例 |
|---|---|---|
| String | string | "hello" |
| Integer/int | integer | 42 |
| Double/double | number | 3.14 |
| Boolean/boolean | boolean | true |
| List | array | ["a", "b"] |
| 嵌套对象 | object | {"key": "value"} |
23.3.6 工作原理
1. 调用 agent.call(msg, Schema.class)
│
▼
2. StructuredOutputHook自动激活
- 将Schema转换为JSON Schema
- 创建generate_response工具
│
▼
3. PreReasoning事件
- 设置tool_choice强制使用generate_response
- 将JSON Schema注入prompt
│
▼
4. LLM生成符合Schema的JSON响应
│
▼
5. PostReasoning事件
- 解析JSON响应
- 验证是否符合Schema
- 失败时自动重试
│
▼
6. 返回Msg,包含getStructuredData()方法
23.4 会话管理示例深入分析
23.4.1 示例目标
SessionExample展示如何实现对话的持久化存储,使用户能够在不同会话间保持上下文连续性。
23.4.2 核心架构
┌──────────────────────────────────────────────────────────────┐
│ SessionExample │
├──────────────────────────────────────────────────────────────┤
│ │
│ ┌───────────────────────────────────────────────────────┐ │
│ │ ReActAgent │ │
│ │ ┌─────────────┐ ┌─────────────────────────────────┐ │ │
│ │ │ Memory │ │ StateModule │ │ │
│ │ │ (InMemory) │ │ saveTo() / loadFrom() │ │ │
│ │ └──────┬──────┘ └──────────────┬──────────────────┘ │ │
│ └─────────┼────────────────────────┼───────────────────┘ │
│ │ │ │
│ ▼ ▼ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ JsonSession │ │
│ │ ┌───────────────────────────────────────────────┐ │ │
│ │ │ ~/.agentscope/examples/sessions/ │ │ │
│ │ │ ├── default_session.json │ │ │
│ │ │ ├── user_001.json │ │ │
│ │ │ └── ... │ │ │
│ │ └───────────────────────────────────────────────┘ │ │
│ └─────────────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────────────────┘
23.4.3 完整代码解析
步骤1:设置会话存储
// 定义会话存储路径
// 使用用户目录下的.agentscope文件夹
Path sessionPath = Paths.get(
System.getProperty("user.home"),
".agentscope",
"examples",
"sessions"
);
// 创建JsonSession实例
// JsonSession使用JSON文件持久化会话数据
Session session = new JsonSession(sessionPath);
步骤2:创建带会话支持的Agent
// 创建内存组件
InMemoryMemory memory = new InMemoryMemory();
Toolkit toolkit = new Toolkit();
// 构建Agent
ReActAgent agent = ReActAgent.builder()
.name("Assistant")
.sysPrompt(
"You are a helpful AI assistant with persistent memory. "
+ "You can remember information from previous conversations.")
.toolkit(toolkit)
.memory(memory)
.model(
DashScopeChatModel.builder()
.apiKey(apiKey)
.modelName("qwen-max")
.stream(true)
.enableThinking(false)
.formatter(new DashScopeChatFormatter())
.build())
.build();
步骤3:加载已有会话
private static void loadSession(
ReActAgent agent,
Session session,
String sessionId,
InMemoryMemory memory) {
// 检查会话是否存在
if (session.exists(SimpleSessionKey.of(sessionId))) {
// 从会话存储中加载Agent状态
agent.loadFrom(session, sessionId);
int messageCount = memory.getMessages().size();
System.out.println("Session loaded: " + sessionId
+ " (" + messageCount + " messages)");
if (messageCount > 0) {
System.out.println("Type 'history' to view previous messages.");
}
} else {
System.out.println("New session created: " + sessionId);
}
}
步骤4:运行对话循环
private static void runConversation(
ReActAgent agent,
Session session,
String sessionId) throws Exception {
System.out.println("=== Chat Started ===");
System.out.println("Commands: 'exit' to quit, 'history' to view message history\n");
while (true) {
System.out.print("You> ");
String input = reader.readLine();
// 退出命令
if (input == null || "exit".equalsIgnoreCase(input.trim())) {
break;
}
if (input.trim().isEmpty()) {
continue;
}
// 历史记录命令
if ("history".equalsIgnoreCase(input.trim())) {
showHistory(agent.getMemory());
continue;
}
try {
// 构建用户消息
Msg userMsg = Msg.builder()
.role(MsgRole.USER)
.content(TextBlock.builder().text(input).build())
.build();
// 调用Agent处理
Msg response = agent.call(userMsg).block();
if (response != null) {
System.out.println("Agent> " + MsgUtils.getTextContent(response) + "\n");
}
// 关键:每次交互后保存会话
agent.saveTo(session, sessionId);
} catch (Exception e) {
System.err.println("Error: " + e.getMessage());
}
}
}
步骤5:保存会话
private static void saveSession(
ReActAgent agent,
Session session,
String sessionId) {
try {
// 保存Agent状态到会话存储
agent.saveTo(session, sessionId);
System.out.println("\nSession saved: " + sessionId);
System.out.println("Resume this conversation later by entering the same session ID.");
} catch (Exception e) {
System.err.println("Warning: Failed to save session: " + e.getMessage());
}
}
23.4.4 会话文件格式
{
"memory": {
"messages": [
{
"role": "USER",
"content": [
{
"type": "text",
"text": "Hello, my name is Alice"
}
],
"timestamp": "2026-01-15T10:30:00Z"
},
{
"role": "ASSISTANT",
"content": [
{
"type": "text",
"text": "Hello Alice! Nice to meet you. How can I help you today?"
}
],
"timestamp": "2026-01-15T10:30:05Z"
}
]
}
}
23.4.5 使用场景
| 场景 | 描述 |
|---|---|
| 聊天机器人 | 用户关闭应用后再次打开,继续之前的对话 |
| 客服系统 | 保存客户历史咨询记录,提供上下文连续的服务 |
| 学习助手 | 记住用户的学习进度和偏好 |
| 任务管理 | 保存未完成的任务状态,下次继续处理 |
23.5 MsgHub多智能体对话示例
23.5.1 示例目标
MsgHubExample展示如何使用MsgHub实现多个Agent之间的消息广播和协同对话。
23.5.2 核心架构
┌──────────────────────────────────────────────────────────────┐
│ MsgHubExample │
├──────────────────────────────────────────────────────────────┤
│ │
│ ┌───────────┐ │
│ │ MsgHub │ │
│ │ 广播中心 │ │
│ └─────┬─────┘ │
│ ┌─────────────┼─────────────┐ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌───────────┐ ┌───────────┐ ┌───────────┐ │
│ │ Alice │ │ Bob │ │ Charlie │ │
│ │ (乐观派) │ │ (务实派) │ │ (创意派) │ │
│ │ │ │ │ │ │ │
│ │ Model │ │ Model │ │ Model │ │
│ │ Memory │ │ Memory │ │ Memory │ │
│ └───────────┘ └───────────┘ └───────────┘ │
│ │
│ 消息流: 公告 → Alice发言 → 广播 → Bob发言 → 广播 → Charlie发言│
└──────────────────────────────────────────────────────────────┘
23.5.3 创建多个Agent
// 使用MultiAgentFormatter支持多智能体场景
DashScopeChatModel model = DashScopeChatModel.builder()
.apiKey(apiKey)
.modelName("qwen-plus")
.formatter(new DashScopeMultiAgentFormatter()) // 多智能体格式器
.build();
// 创建三个不同性格的Agent
ReActAgent alice = ReActAgent.builder()
.name("Alice")
.sysPrompt(
"You are Alice, an optimistic student who always sees the bright side. "
+ "Be brief (1-2 sentences) and enthusiastic in your responses.")
.model(model)
.memory(new InMemoryMemory())
.toolkit(new Toolkit())
.build();
ReActAgent bob = ReActAgent.builder()
.name("Bob")
.sysPrompt(
"You are Bob, a pragmatic student who focuses on practical concerns. "
+ "Be brief (1-2 sentences) and realistic in your responses.")
.model(model)
.memory(new InMemoryMemory())
.toolkit(new Toolkit())
.build();
ReActAgent charlie = ReActAgent.builder()
.name("Charlie")
.sysPrompt(
"You are Charlie, a creative student who thinks outside the box. "
+ "Be brief (1-2 sentences) and imaginative in your responses.")
.model(model)
.memory(new InMemoryMemory())
.toolkit(new Toolkit())
.build();
23.5.4 基础阻塞模式
private static void basicConversationExample(
ReActAgent alice,
ReActAgent bob,
ReActAgent charlie) {
// 创建讨论公告
Msg announcement = Msg.builder()
.name("system")
.role(MsgRole.SYSTEM)
.content(TextBlock.builder()
.text("Let's discuss: What's the best way to learn a new programming language? "
+ "Each person share ONE brief idea.")
.build())
.build();
// 使用try-with-resources确保资源清理
try (MsgHub hub = MsgHub.builder()
.name("StudentDiscussion")
.participants(alice, bob, charlie) // 注册参与者
.announcement(announcement) // 设置公告
.enableAutoBroadcast(true) // 启用自动广播
.build()) {
// 进入Hub(设置订阅并广播公告)
hub.enter().block();
System.out.println("Announcement: " + MsgUtils.getTextContent(announcement));
// 依次让每个Agent发言
// 发言会自动广播给其他参与者
System.out.println("\n[Alice's turn]");
Msg aliceResponse = alice.call().block();
printAgentResponse("Alice", aliceResponse);
System.out.println("\n[Bob's turn]");
Msg bobResponse = bob.call().block();
printAgentResponse("Bob", bobResponse);
System.out.println("\n[Charlie's turn]");
Msg charlieResponse = charlie.call().block();
printAgentResponse("Charlie", charlieResponse);
// 验证消息传播
System.out.println("\n--- Memory Verification ---");
System.out.println("Alice's memory: " + alice.getMemory().getMessages().size());
System.out.println("Bob's memory: " + bob.getMemory().getMessages().size());
System.out.println("Charlie's memory: " + charlie.getMemory().getMessages().size());
}
// Hub自动关闭,订阅自动清理
}
23.5.5 响应式链式模式
private static void reactiveConversationExample(
ReActAgent alice,
ReActAgent bob,
ReActAgent charlie) {
// 清空之前示例的记忆
alice.getMemory().clear();
bob.getMemory().clear();
charlie.getMemory().clear();
Msg announcement = Msg.builder()
.name("system")
.role(MsgRole.SYSTEM)
.content(TextBlock.builder()
.text("Quick question: What's your favorite programming paradigm?")
.build())
.build();
MsgHub hub = MsgHub.builder()
.name("ReactiveDiscussion")
.participants(alice, bob, charlie)
.announcement(announcement)
.build();
// 完全响应式的链式调用
// 使用then()连接各个步骤,doOnSuccess()处理中间结果
hub.enter()
.doOnSuccess(h ->
System.out.println("Announcement: " + MsgUtils.getTextContent(announcement)))
.then(alice.call())
.doOnSuccess(msg ->
System.out.println("[Alice]: " + MsgUtils.getTextContent(msg)))
.then(bob.call())
.doOnSuccess(msg ->
System.out.println("[Bob]: " + MsgUtils.getTextContent(msg)))
.then(charlie.call())
.doOnSuccess(msg ->
System.out.println("[Charlie]: " + MsgUtils.getTextContent(msg)))
.then(hub.exit())
.doOnSuccess(v ->
System.out.println("\n--- Reactive chain completed ---"))
.block(); // 只在最后阻塞一次
}
23.5.6 消息传播机制
时间线:
t0: Hub进入,公告广播
┌─────────────────────────────────────────────┐
│ 公告: "What's the best way to learn..." │
└──────────────┬──────────────────────────────┘
│
┌─────────┼─────────┐
▼ ▼ ▼
Alice Bob Charlie
[公告] [公告] [公告]
t1: Alice发言
Alice ────────────────────────────────────→ 广播
[公告] [公告] [公告]
[Alice发言] [公告] [公告]
[Alice发言] [Alice发言]
t2: Bob发言
Alice Bob Charlie
[公告] [公告] [公告]
[Alice] [Alice] [Alice]
[Bob] [Bob] [Bob]
t3: Charlie发言
Alice Bob Charlie
[公告] [公告] [公告]
[Alice] [Alice] [Alice]
[Bob] [Bob] [Bob]
[Charlie] [Charlie] [Charlie]
23.6 顺序管道示例深入分析
23.6.1 示例目标
SequentialPipelineExample展示如何使用顺序管道将多个Agent串联起来,构建内容处理工作流。
23.6.2 核心架构
┌──────────────────────────────────────────────────────────────┐
│ SequentialPipelineExample │
├──────────────────────────────────────────────────────────────┤
│ │
│ 输入: English Article │
│ │ │
│ ▼ │
│ ┌─────────────────┐ │
│ │ Translator │ Agent 1: 翻译 │
│ │ (英文→中文) │ │
│ └────────┬────────┘ │
│ │ 中文文本 │
│ ▼ │
│ ┌─────────────────┐ │
│ │ Summarizer │ Agent 2: 摘要 │
│ │ (生成摘要) │ │
│ └────────┬────────┘ │
│ │ 中文摘要 │
│ ▼ │
│ ┌─────────────────────┐ │
│ │ SentimentAnalyzer │ Agent 3: 情感分析 │
│ │ (分析情感倾向) │ │
│ └────────┬────────────┘ │
│ │ │
│ ▼ │
│ 输出: Sentiment + Summary │
└──────────────────────────────────────────────────────────────┘
23.6.3 创建专用Agent
/**
* 翻译Agent
* 专注于英译中,保持原意和语气
*/
private static ReActAgent createTranslator(String apiKey) {
return ReActAgent.builder()
.name("Translator")
.sysPrompt(
"You are a professional translator. "
+ "Translate the given English text to Chinese accurately. "
+ "Preserve the original meaning and tone. "
+ "Only output the translated text, no explanations.")
.model(
DashScopeChatModel.builder()
.apiKey(apiKey)
.modelName("qwen-plus")
.stream(true)
.enableThinking(false)
.formatter(new DashScopeChatFormatter())
.build())
.memory(new InMemoryMemory())
.toolkit(new Toolkit())
.build();
}
/**
* 摘要Agent
* 生成简洁的2-3句摘要
*/
private static ReActAgent createSummarizer(String apiKey) {
return ReActAgent.builder()
.name("Summarizer")
.sysPrompt(
"You are a professional content summarizer. "
+ "Generate a concise summary of the given text in 2-3 sentences. "
+ "Capture the main points and key message. "
+ "Keep the summary in the same language as the input. "
+ "Only output the summary, no additional comments.")
.model(
DashScopeChatModel.builder()
.apiKey(apiKey)
.modelName("qwen-plus")
.stream(true)
.enableThinking(false)
.formatter(new DashScopeChatFormatter())
.build())
.memory(new InMemoryMemory())
.toolkit(new Toolkit())
.build();
}
/**
* 情感分析Agent
* 分析文本的情感倾向并给出分类
*/
private static ReActAgent createSentimentAnalyzer(String apiKey) {
return ReActAgent.builder()
.name("SentimentAnalyzer")
.sysPrompt(
"You are a sentiment analysis expert. "
+ "Analyze the emotional tone of the given text. "
+ "Classify the sentiment as: Positive, Negative, Neutral, or Mixed. "
+ "Explain the reasoning behind your classification in 1-2 sentences. "
+ "Format your response as:\n"
+ "Sentiment: [classification]\n"
+ "Reasoning: [explanation]\n"
+ "Summary: [repeat the input text]")
.model(
DashScopeChatModel.builder()
.apiKey(apiKey)
.modelName("qwen-plus")
.stream(true)
.enableThinking(false)
.formatter(new DashScopeChatFormatter())
.build())
.memory(new InMemoryMemory())
.toolkit(new Toolkit())
.build();
}
23.6.4 构建和执行管道
public static void main(String[] args) throws Exception {
String apiKey = ExampleUtils.getDashScopeApiKey();
// 创建三个专用Agent
ReActAgent translator = createTranslator(apiKey);
ReActAgent summarizer = createSummarizer(apiKey);
ReActAgent sentimentAnalyzer = createSentimentAnalyzer(apiKey);
// 使用Builder模式构建顺序管道
SequentialPipeline pipeline = SequentialPipeline.builder()
.addAgent(translator) // 第一步:翻译
.addAgent(summarizer) // 第二步:摘要
.addAgent(sentimentAnalyzer) // 第三步:情感分析
.build();
System.out.println("Pipeline created with 3 agents:");
System.out.println(" [1] Translator → [2] Summarizer → [3] Sentiment Analyzer");
// 准备输入
String article = "Artificial Intelligence has revolutionized the technology industry...";
Msg inputMsg = Msg.builder()
.role(MsgRole.USER)
.content(TextBlock.builder().text(article).build())
.build();
// 执行管道
long startTime = System.currentTimeMillis();
Msg result = pipeline.execute(inputMsg)
.block(Duration.ofMinutes(3)); // 设置超时
long executionTime = System.currentTimeMillis() - startTime;
// 输出结果
if (result != null) {
String resultText = MsgUtils.getTextContent(result);
System.out.println("FINAL RESULT:");
System.out.println(resultText);
}
System.out.println("\nExecution time: " + executionTime + "ms");
}
23.6.5 执行流程详解
输入文章 (英文):
┌────────────────────────────────────────────────────────────────┐
│ "Artificial Intelligence has revolutionized the technology │
│ industry in recent years. Machine learning algorithms now │
│ power everything from recommendation systems to autonomous │
│ vehicles..." │
└────────────────────────────────────────────────────────────────┘
│
▼
┌────────────────────────────────┐
│ Step 1: Translator │
│ 输入: English Article │
│ 输出: 中文翻译 │
└────────────────┬───────────────┘
│
▼
┌────────────────────────────────────────────────────────────────┐
│ "人工智能近年来彻底改变了科技行业。机器学习算法现在为从推荐系统 │
│ 到自动驾驶汽车的各种应用提供动力..." │
└────────────────────────────────────────────────────────────────┘
│
▼
┌────────────────────────────────┐
│ Step 2: Summarizer │
│ 输入: 中文翻译 │
│ 输出: 简洁摘要 │
└────────────────┬───────────────┘
│
▼
┌────────────────────────────────────────────────────────────────┐
│ "人工智能正在推动科技革命,机器学习已广泛应用于各个领域。虽然 │
│ AI带来机遇,但也引发了伦理和就业方面的讨论。" │
└────────────────────────────────────────────────────────────────┘
│
▼
┌────────────────────────────────┐
│ Step 3: SentimentAnalyzer │
│ 输入: 摘要 │
│ 输出: 情感分析结果 │
└────────────────┬───────────────┘
│
▼
┌────────────────────────────────────────────────────────────────┐
│ Sentiment: Mixed │
│ Reasoning: 文本既提到了AI带来的积极变革,也指出了相关的担忧 │
│ Summary: 人工智能正在推动科技革命... │
└────────────────────────────────────────────────────────────────┘
23.6.6 管道设计最佳实践
| 原则 | 说明 |
|---|---|
| 单一职责 | 每个Agent只做一件事,专注于特定任务 |
| 明确输入输出 | 定义清晰的数据格式,确保上下游衔接 |
| 无需解释 | 中间Agent只输出结果,不要额外解释 |
| 合理超时 | 根据任务复杂度设置合适的超时时间 |
| 错误隔离 | 单个环节失败不影响整体诊断 |
23.7 RAG知识检索示例
23.7.1 示例目标
RAGExample展示如何构建知识库并让Agent基于检索结果进行增强回答。
23.7.2 核心架构
┌──────────────────────────────────────────────────────────────┐
│ RAGExample │
├──────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Knowledge Pipeline │ │
│ │ │ │
│ │ 文档 ──→ TextReader ──→ 分块 ──→ 嵌入 ──→ 存储 │ │
│ │ │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Query Pipeline │ │
│ │ │ │
│ │ 查询 ──→ 嵌入 ──→ 向量搜索 ──→ 检索结果 ──→ Agent │ │
│ │ │ │
│ └─────────────────────────────────────────────────────┘ │
│ │
│ ┌──────────────────┐ ┌──────────────────────────────┐ │
│ │ DashScopeText │ │ InMemoryStore │ │
│ │ Embedding │ │ (1024维向量存储) │ │
│ │ (text-embedding │ │ │ │
│ │ -v3) │ │ │ │
│ └──────────────────┘ └──────────────────────────────┘ │
└──────────────────────────────────────────────────────────────┘
23.7.3 构建知识库
// 步骤1:创建嵌入模型
EmbeddingModel embeddingModel = DashScopeTextEmbedding.builder()
.apiKey(apiKey)
.modelName("text-embedding-v3")
.dimensions(1024) // 嵌入向量维度
.build();
// 步骤2:创建向量存储
VDBStoreBase vectorStore = InMemoryStore.builder()
.dimensions(1024)
.build();
// 步骤3:创建知识库
Knowledge knowledge = SimpleKnowledge.builder()
.embeddingModel(embeddingModel)
.embeddingStore(vectorStore)
.build();
23.7.4 添加文档
private static void addSampleDocuments(Knowledge knowledge) {
// 示例文档
String[] documents = {
"AgentScope is a multi-agent system framework developed by ModelScope...",
"AgentScope supports various agent types including ReActAgent...",
"RAG (Retrieval-Augmented Generation) is a technique that enhances...",
"AgentScope Java is the Java implementation of AgentScope framework...",
"Vector stores are used in RAG systems to store and search..."
};
// 创建文本阅读器
// 参数:最大块大小、分割策略、重叠大小
TextReader reader = new TextReader(512, SplitStrategy.PARAGRAPH, 50);
for (int i = 0; i < documents.length; i++) {
String docText = documents[i];
// 从字符串创建输入
ReaderInput input = ReaderInput.fromString(docText);
try {
// 读取并分块
List<Document> docs = reader.read(input).block();
if (docs != null && !docs.isEmpty()) {
// 添加到知识库(自动计算嵌入向量)
knowledge.addDocuments(docs).block();
System.out.println("Added document " + (i + 1));
}
} catch (Exception e) {
System.err.println("Error adding document: " + e.getMessage());
}
}
}
23.7.5 Agentic RAG模式
/**
* Agentic模式下,Agent自主决定何时检索知识
* 知识检索作为工具提供给Agent使用
*/
private static void demonstrateAgenticMode(String apiKey, Knowledge knowledge) {
ReActAgent agent = ReActAgent.builder()
.name("RAGAgent")
.sysPrompt(
"You are a helpful assistant with access to a knowledge retrieval tool. "
+ "When you need information from the knowledge base, "
+ "use the retrieve_knowledge tool. Always explain what you're doing.")
.model(
DashScopeChatModel.builder()
.apiKey(apiKey)
.modelName("qwen-max")
.stream(true)
.enableThinking(false)
.formatter(new DashScopeChatFormatter())
.build())
.toolkit(new Toolkit())
.memory(new InMemoryMemory())
// RAG配置
.knowledge(knowledge)
.ragMode(RAGMode.AGENTIC) // Agentic模式
.build();
// 启动交互式对话
ExampleUtils.startChat(agent);
}
23.7.6 Generic RAG模式
/**
* Generic模式下,系统自动为每个查询检索相关知识
* 知识作为上下文注入到Agent的推理过程中
*/
private static void demonstrateGenericMode(String apiKey, Knowledge knowledge) {
ReActAgent agent = ReActAgent.builder()
.name("RAGAssistant")
.sysPrompt(
"You are a helpful assistant with access to a knowledge base. "
+ "Use the provided knowledge to answer questions accurately.")
.model(
DashScopeChatModel.builder()
.apiKey(apiKey)
.modelName("qwen-max")
.stream(true)
.enableThinking(false)
.formatter(new DashScopeChatFormatter())
.build())
.memory(new InMemoryMemory())
.toolkit(new Toolkit())
// RAG配置
.knowledge(knowledge)
.ragMode(RAGMode.GENERIC) // Generic模式
.retrieveConfig(
RetrieveConfig.builder()
.limit(3) // 最多检索3个文档
.scoreThreshold(0.3) // 相似度阈值
.build())
.build();
ExampleUtils.startChat(agent);
}
23.7.7 两种模式对比
| 特性 | Generic模式 | Agentic模式 |
|---|---|---|
| 检索时机 | 每次查询自动检索 | Agent决定何时检索 |
| 控制程度 | 系统自动化 | Agent自主控制 |
| 适用场景 | 简单问答 | 复杂推理任务 |
| Token消耗 | 较高(每次都检索) | 较低(按需检索) |
| 配置复杂度 | 简单 | 需要配置工具 |
23.8 本章小结
本章深入分析了AgentScope-Java框架的核心基础示例:
23.8.1 关键知识点
| 示例 | 核心API | 应用场景 |
|---|---|---|
| ToolCallingExample | @Tool, @ToolParam, Toolkit | 函数调用、外部集成 |
| StructuredOutputExample | call(msg, Schema.class) | 数据提取、表单处理 |
| SessionExample | Session, saveTo/loadFrom | 会话持久化、上下文保持 |
| MsgHubExample | MsgHub, participants | 多智能体协作 |
| SequentialPipelineExample | SequentialPipeline | 工作流编排 |
| RAGExample | Knowledge, RAGMode | 知识增强回答 |
23.8.2 设计模式总结
- Builder模式:所有主要组件都使用Builder模式构建
- 响应式编程:使用Mono/Flux支持异步操作
- 注解驱动:通过注解简化工具定义
- 组合优于继承:通过组合不同组件构建Agent
23.8.3 下一步学习
在掌握了基础示例后,建议继续学习:
- 第24章:高级案例分析(RAG进阶、路由、自动记忆)
- 第25章:狼人杀游戏案例(完整多智能体应用)
- 第26章:奶茶店系统(企业级分布式系统)
这些高级案例将展示如何将基础组件组合成复杂的生产级应用。