第23章 基础案例分析

第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类型示例
Stringstring"hello"
Integer/intinteger42
Double/doublenumber3.14
Boolean/booleanbooleantrue
Listarray["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函数调用、外部集成
StructuredOutputExamplecall(msg, Schema.class)数据提取、表单处理
SessionExampleSession, saveTo/loadFrom会话持久化、上下文保持
MsgHubExampleMsgHub, participants多智能体协作
SequentialPipelineExampleSequentialPipeline工作流编排
RAGExampleKnowledge, RAGMode知识增强回答

23.8.2 设计模式总结

  1. Builder模式:所有主要组件都使用Builder模式构建
  2. 响应式编程:使用Mono/Flux支持异步操作
  3. 注解驱动:通过注解简化工具定义
  4. 组合优于继承:通过组合不同组件构建Agent

23.8.3 下一步学习

在掌握了基础示例后,建议继续学习:

  • 第24章:高级案例分析(RAG进阶、路由、自动记忆)
  • 第25章:狼人杀游戏案例(完整多智能体应用)
  • 第26章:奶茶店系统(企业级分布式系统)

这些高级案例将展示如何将基础组件组合成复杂的生产级应用。

← 返回目录