第2章 环境搭建与第一个智能体

第2章 环境搭建与第一个智能体

本章目标:搭建开发环境,运行第一个智能体,理解基本代码结构


2.1 环境准备

2.1.1 JDK 安装

AgentScope-Java 需要 JDK 17 或更高版本。推荐使用以下发行版:

发行版推荐指数下载地址
Eclipse Temurin⭐⭐⭐⭐⭐https://adoptium.net/
Amazon Corretto⭐⭐⭐⭐⭐https://aws.amazon.com/corretto/
Oracle JDK⭐⭐⭐⭐https://www.oracle.com/java/
GraalVM⭐⭐⭐⭐https://www.graalvm.org/

验证安装:

# 检查 Java 版本
$ java -version
openjdk version "17.0.9" 2023-10-17
OpenJDK Runtime Environment Temurin-17.0.9+9 (build 17.0.9+9)
OpenJDK 64-Bit Server VM Temurin-17.0.9+9 (build 17.0.9+9, mixed mode)

# 确保版本号 >= 17

注意:如果你的系统安装了多个 JDK 版本,请确保 JAVA_HOME 指向 JDK 17+。

2.1.2 构建工具

确保安装了 Maven 或 Gradle:

Maven(推荐):

$ mvn -v
Apache Maven 3.9.6
Maven home: /usr/local/maven
Java version: 17.0.9, vendor: Eclipse Adoptium

Gradle:

$ gradle -v
Gradle 8.5
Build time:   2023-11-29 14:08:57 UTC
Kotlin:       1.9.20

2.1.3 获取 API Key

AgentScope 支持多种 LLM 提供商。本教程主要使用 DashScope(阿里云百炼),因为:

  • 免费试用额度充足
  • 国内访问速度快
  • 中文能力优秀

获取 DashScope API Key:

  1. 访问 阿里云百炼控制台
  2. 登录或注册阿里云账号
  3. 进入「API-KEY」页面
  4. 创建并复制 API Key

设置环境变量:

# Linux/macOS
export DASHSCOPE_API_KEY=sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

# Windows PowerShell
$env:DASHSCOPE_API_KEY="sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"

# Windows CMD
set DASHSCOPE_API_KEY=sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

安全提示:永远不要将 API Key 硬编码在代码中或提交到版本控制系统。

其他提供商的 API Key:

提供商环境变量获取地址
OpenAIOPENAIAPIKEYhttps://platform.openai.com/api-keys
AnthropicANTHROPICAPIKEYhttps://console.anthropic.com/
GoogleGOOGLEAPIKEYhttps://aistudio.google.com/app/apikey

2.2 项目配置

2.2.1 创建 Maven 项目

方式一:命令行创建

mvn archetype:generate \
  -DgroupId=com.example \
  -DartifactId=agentscope-demo \
  -DarchetypeArtifactId=maven-archetype-quickstart \
  -DinteractiveMode=false

cd agentscope-demo

方式二:IDE 创建

在 IntelliJ IDEA 或 Eclipse 中创建新的 Maven 项目。

2.2.2 添加依赖

编辑 pom.xml,添加 AgentScope 依赖:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
                             http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.example</groupId>
    <artifactId>agentscope-demo</artifactId>
    <version>1.0-SNAPSHOT</version>

    <!-- ========================================
         【JDK 版本配置】
         AgentScope 需要 JDK 17+
         ======================================== -->
    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <dependencies>
        <!-- ========================================
             【AgentScope 核心依赖】
             all-in-one 包含:
             - agentscope-core: 核心功能
             - DashScope SDK: 阿里云模型
             - MCP SDK: MCP 协议支持
             ======================================== -->
        <dependency>
            <groupId>io.agentscope</groupId>
            <artifactId>agentscope</artifactId>
            <version>1.0.7</version>
        </dependency>

        <!-- ========================================
             【可选:其他模型提供商】
             如果需要使用 OpenAI、Anthropic 等
             ======================================== -->
        <!-- OpenAI -->
        <!--
        <dependency>
            <groupId>com.openai</groupId>
            <artifactId>openai-java</artifactId>
            <version>0.8.0</version>
        </dependency>
        -->

        <!-- ========================================
             【日志实现】
             AgentScope 使用 SLF4J,需要提供实现
             ======================================== -->
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.4.14</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <!-- ========================================
                 【编译器插件】
                 启用 -parameters 保留方法参数名
                 (虽然 AgentScope 不强制要求,但推荐开启)
                 ======================================== -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.11.0</version>
                <configuration>
                    <parameters>true</parameters>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

2.2.3 Gradle 配置(可选)

如果使用 Gradle,在 build.gradle 中添加:

plugins {
    id 'java'
}

group = 'com.example'
version = '1.0-SNAPSHOT'

java {
    sourceCompatibility = JavaVersion.VERSION_17
    targetCompatibility = JavaVersion.VERSION_17
}

repositories {
    mavenCentral()
}

dependencies {
    // AgentScope 核心
    implementation 'io.agentscope:agentscope:1.0.7'
    
    // 日志实现
    implementation 'ch.qos.logback:logback-classic:1.4.14'
}

// 保留方法参数名
tasks.withType(JavaCompile) {
    options.compilerArgs += ['-parameters']
}

2.3 Hello World:第一个智能体

2.3.1 最简示例

创建 src/main/java/com/example/HelloAgent.java

package com.example;

// ========================================
// 【导入说明】
// ========================================
import io.agentscope.core.ReActAgent;           // 核心智能体类
import io.agentscope.core.message.Msg;          // 消息类
import io.agentscope.core.message.MsgRole;      // 消息角色枚举
import io.agentscope.core.message.TextBlock;    // 文本内容块
import io.agentscope.core.model.DashScopeChatModel;  // DashScope 模型

import java.util.List;

/**
 * AgentScope Hello World 示例
 * 
 * 这是最简单的智能体示例,展示了:
 * 1. 如何创建模型
 * 2. 如何创建智能体
 * 3. 如何发送消息并获取响应
 */
public class HelloAgent {
    
    public static void main(String[] args) {
        // ========================================
        // 【步骤 1】获取 API Key
        // ========================================
        // 从环境变量读取 API Key,避免硬编码
        String apiKey = System.getenv("DASHSCOPE_API_KEY");
        
        // 安全检查:确保 API Key 已设置
        if (apiKey == null || apiKey.isEmpty()) {
            System.err.println("错误:请设置环境变量 DASHSCOPE_API_KEY");
            System.err.println("示例:export DASHSCOPE_API_KEY=sk-xxx");
            System.exit(1);
        }
        
        // ========================================
        // 【步骤 2】创建 LLM 模型
        // ========================================
        // DashScopeChatModel 是连接阿里云百炼的模型实现
        // 使用 Builder 模式配置各项参数
        DashScopeChatModel model = DashScopeChatModel.builder()
                .apiKey(apiKey)           // API 密钥
                .modelName("qwen-max")    // 模型名称:qwen-max 是通义千问的旗舰模型
                .stream(true)             // 启用流式输出(可选,提升用户体验)
                .build();
        
        // 可选的模型:
        // - qwen-max: 最强能力,适合复杂任务
        // - qwen-plus: 平衡性能和成本
        // - qwen-turbo: 速度最快,成本最低
        
        // ========================================
        // 【步骤 3】创建智能体
        // ========================================
        // ReActAgent 是框架提供的主要智能体实现
        // 使用 ReAct 算法:推理(Reasoning) + 行动(Acting) 循环
        ReActAgent agent = ReActAgent.builder()
                .name("Assistant")        // 智能体名称
                                          // - 用于日志和多智能体场景的身份识别
                                          
                .sysPrompt("你是一个友好的 AI 助手。请用简洁清晰的语言回答问题。")
                                          // 系统提示词
                                          // - 定义智能体的角色和行为
                                          // - 会作为第一条 system 消息发送给 LLM
                                          
                .model(model)             // 关联 LLM 模型
                                          // - 智能体的"大脑"
                
                .build();
        
        // ========================================
        // 【步骤 4】构建用户消息
        // ========================================
        // Msg 是 AgentScope 的核心消息类
        // 使用 Builder 模式构建消息内容
        Msg userMessage = Msg.builder()
                .name("user")             // 发送者名称(可选)
                .role(MsgRole.USER)       // 消息角色:用户消息
                .content(List.of(         // 消息内容:ContentBlock 列表
                        TextBlock.builder()
                                .text("你好!请用一句话介绍一下你自己。")
                                .build()
                ))
                .build();
        
        // 简化写法:使用 textContent() 快捷方法
        // Msg userMessage = Msg.builder()
        //         .textContent("你好!请用一句话介绍一下你自己。")
        //         .build();
        
        // ========================================
        // 【步骤 5】调用智能体
        // ========================================
        System.out.println("发送消息: " + userMessage.getTextContent());
        System.out.println("等待响应...\n");
        
        // agent.call() 返回 Mono<Msg>(响应式类型)
        // .block() 阻塞等待结果(同步调用)
        Msg response = agent.call(userMessage).block();
        
        // ========================================
        // 【步骤 6】处理响应
        // ========================================
        if (response != null) {
            // getTextContent() 提取所有 TextBlock 的文本内容
            String textContent = response.getTextContent();
            System.out.println("智能体回复: " + textContent);
            
            // 可选:查看更多响应信息
            System.out.println("\n--- 响应详情 ---");
            System.out.println("生成原因: " + response.getGenerateReason());
            
            // 如果有 Token 用量信息
            if (response.getChatUsage() != null) {
                System.out.println("输入 Token: " + response.getChatUsage().getInputTokens());
                System.out.println("输出 Token: " + response.getChatUsage().getOutputTokens());
            }
        } else {
            System.err.println("错误:未收到响应");
        }
    }
}

2.3.2 运行示例

命令行运行:

# 确保设置了环境变量
export DASHSCOPE_API_KEY=sk-xxx

# 编译
mvn compile

# 运行
mvn exec:java -Dexec.mainClass="com.example.HelloAgent"

IDE 运行:

在 IntelliJ IDEA 或 Eclipse 中,右键点击 HelloAgent.java,选择「Run」。

预期输出:

发送消息: 你好!请用一句话介绍一下你自己。
等待响应...

智能体回复: 你好!我是通义千问,一个由阿里云开发的 AI 助手,
随时准备为你解答问题、提供帮助。

--- 响应详情 ---
生成原因: MODEL_STOP
输入 Token: 42
输出 Token: 35

2.4 添加工具能力

仅仅能对话的智能体是不够的。让我们给智能体添加工具调用能力。

2.4.1 定义工具类

创建 src/main/java/com/example/TimeTools.java

package com.example;

// ========================================
// 【导入说明】
// ========================================
import io.agentscope.core.tool.annotation.Tool;
import io.agentscope.core.tool.annotation.ToolParam;

import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;

/**
 * 时间相关工具类
 * 
 * 工具类是普通的 Java 类,通过注解声明为工具。
 * 智能体可以根据用户需求自动调用这些工具。
 */
public class TimeTools {
    
    // ========================================
    // 【工具定义】获取当前时间
    // ========================================
    @Tool(
        name = "get_current_time",           // 工具名称:LLM 看到的名称
        description = "获取指定时区的当前时间"  // 工具描述:帮助 LLM 理解何时使用
    )
    public String getCurrentTime(
            // ========================================
            // 【参数定义】
            // @ToolParam 的 name 属性是必需的!
            // Java 运行时默认不保留参数名,必须显式指定
            // ========================================
            @ToolParam(
                name = "timezone",                    // 参数名:必须指定
                description = "时区,如:Asia/Shanghai, America/New_York, Europe/London",
                required = false                      // 是否必需,默认 true
            ) 
            String timezone
    ) {
        // 默认使用上海时区
        if (timezone == null || timezone.isEmpty()) {
            timezone = "Asia/Shanghai";
        }
        
        try {
            ZonedDateTime now = ZonedDateTime.now(ZoneId.of(timezone));
            return now.format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss z"));
        } catch (Exception e) {
            return "无法识别的时区: " + timezone + ",请使用标准时区格式";
        }
    }
    
    // ========================================
    // 【工具定义】计算时间差
    // ========================================
    @Tool(
        name = "get_days_until",
        description = "计算从今天到指定日期还有多少天"
    )
    public String getDaysUntil(
            @ToolParam(
                name = "target_date",
                description = "目标日期,格式:yyyy-MM-dd,如:2024-12-31"
            )
            String targetDate
    ) {
        try {
            var target = java.time.LocalDate.parse(targetDate);
            var today = java.time.LocalDate.now();
            long days = java.time.temporal.ChronoUnit.DAYS.between(today, target);
            
            if (days > 0) {
                return "距离 " + targetDate + " 还有 " + days + " 天";
            } else if (days < 0) {
                return targetDate + " 已经过去了 " + (-days) + " 天";
            } else {
                return "今天就是 " + targetDate + "!";
            }
        } catch (Exception e) {
            return "日期格式错误,请使用 yyyy-MM-dd 格式";
        }
    }
}

2.4.2 创建带工具的智能体

创建 src/main/java/com/example/ToolAgent.java

package com.example;

import io.agentscope.core.ReActAgent;
import io.agentscope.core.message.Msg;
import io.agentscope.core.model.DashScopeChatModel;
import io.agentscope.core.tool.Toolkit;

import java.util.Scanner;

/**
 * 带工具能力的智能体示例
 * 
 * 展示了:
 * 1. 如何定义和注册工具
 * 2. 智能体如何自动选择和调用工具
 * 3. 交互式对话
 */
public class ToolAgent {
    
    public static void main(String[] args) {
        String apiKey = System.getenv("DASHSCOPE_API_KEY");
        if (apiKey == null || apiKey.isEmpty()) {
            System.err.println("请设置环境变量 DASHSCOPE_API_KEY");
            System.exit(1);
        }
        
        // ========================================
        // 【步骤 1】创建模型
        // ========================================
        DashScopeChatModel model = DashScopeChatModel.builder()
                .apiKey(apiKey)
                .modelName("qwen-max")
                .stream(true)
                .build();
        
        // ========================================
        // 【步骤 2】创建工具包并注册工具
        // ========================================
        // Toolkit 是工具的容器,管理所有可用工具
        Toolkit toolkit = new Toolkit();
        
        // registerTool() 扫描类中的 @Tool 注解方法
        // 自动注册为可用工具
        toolkit.registerTool(new TimeTools());
        
        // 可以注册多个工具类
        // toolkit.registerTool(new CalculatorTools());
        // toolkit.registerTool(new SearchTools());
        
        // ========================================
        // 【步骤 3】创建带工具的智能体
        // ========================================
        ReActAgent agent = ReActAgent.builder()
                .name("TimeAssistant")
                .sysPrompt("""
                    你是一个时间助手,可以:
                    1. 查询世界各地的当前时间
                    2. 计算距离某个日期还有多少天
                    
                    当用户询问时间相关问题时,请使用提供的工具获取准确信息。
                    回答要简洁明了。
                    """)
                .model(model)
                .toolkit(toolkit)        // 关联工具包
                .maxIters(5)             // 最大迭代次数(防止无限循环)
                .build();
        
        // ========================================
        // 【步骤 4】交互式对话
        // ========================================
        System.out.println("=".repeat(50));
        System.out.println("时间助手已启动!");
        System.out.println("示例问题:");
        System.out.println("  - 现在北京时间几点?");
        System.out.println("  - 纽约现在几点?");
        System.out.println("  - 距离2025年还有多少天?");
        System.out.println("输入 'exit' 退出");
        System.out.println("=".repeat(50));
        System.out.println();
        
        try (Scanner scanner = new Scanner(System.in)) {
            while (true) {
                System.out.print("你: ");
                String input = scanner.nextLine().trim();
                
                if (input.isEmpty()) {
                    continue;
                }
                
                if ("exit".equalsIgnoreCase(input)) {
                    System.out.println("再见!");
                    break;
                }
                
                try {
                    // 发送消息并获取响应
                    Msg response = agent.call(
                            Msg.builder().textContent(input).build()
                    ).block();
                    
                    if (response != null) {
                        System.out.println("助手: " + response.getTextContent());
                    }
                } catch (Exception e) {
                    System.err.println("错误: " + e.getMessage());
                }
                System.out.println();
            }
        }
    }
}

2.4.3 运行测试

mvn exec:java -Dexec.mainClass="com.example.ToolAgent"

对话示例:

==================================================
时间助手已启动!
示例问题:
  - 现在北京时间几点?
  - 纽约现在几点?
  - 距离2025年还有多少天?
输入 'exit' 退出
==================================================

你: 现在北京时间几点?
助手: 北京时间现在是 2024-03-15 14:30:25 CST。

你: 纽约现在是几点?
助手: 纽约现在是 2024-03-15 02:30:30 EDT。

你: 距离今年国庆节还有多少天?
助手: 距离 2024-10-01 还有 200 天。

你: exit
再见!

2.5 理解 ReAct 循环

2.5.1 什么是 ReAct

ReAct(Reasoning + Acting)是当前最流行的智能体设计模式。它的核心思想是:

观察(Observation) → 思考(Reasoning) → 行动(Acting) → 循环

在 AgentScope 中,ReAct 循环的工作流程是:

┌─────────────────────────────────────────────────────────────┐
│                       ReAct 循环                             │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│   用户输入                                                   │
│      │                                                      │
│      ▼                                                      │
│   ┌─────────────────┐                                       │
│   │   推理阶段       │  LLM 分析:                           │
│   │  (Reasoning)    │  - 理解用户意图                        │
│   │                 │  - 决定是否需要调用工具                 │
│   │                 │  - 选择合适的工具和参数                 │
│   └────────┬────────┘                                       │
│            │                                                │
│            ▼                                                │
│      ┌──────────┐                                           │
│      │ 需要工具? │                                           │
│      └────┬─────┘                                           │
│           │                                                 │
│     ┌─────┴─────┐                                           │
│     │           │                                           │
│    是          否                                            │
│     │           │                                           │
│     ▼           ▼                                           │
│  ┌──────────┐  ┌──────────┐                                 │
│  │ 行动阶段 │  │ 生成回复 │                                  │
│  │ (Acting) │  │          │                                  │
│  │          │  │ 返回给   │                                  │
│  │ 执行工具 │  │ 用户     │                                  │
│  └────┬─────┘  └──────────┘                                 │
│       │                                                     │
│       ▼                                                     │
│  ┌──────────┐                                               │
│  │ 工具结果 │                                                │
│  │ 存入记忆 │                                                │
│  └────┬─────┘                                               │
│       │                                                     │
│       └───────────────────┐                                 │
│                           ▼                                 │
│                    返回推理阶段                              │
│                                                             │
└─────────────────────────────────────────────────────────────┘

2.5.2 观察 ReAct 过程

添加一个简单的日志 Hook 来观察 ReAct 过程:

import io.agentscope.core.hook.Hook;
import io.agentscope.core.hook.HookEvent;
import io.agentscope.core.hook.PreReasoningEvent;
import io.agentscope.core.hook.PostReasoningEvent;
import io.agentscope.core.hook.PreActingEvent;
import io.agentscope.core.hook.PostActingEvent;
import io.agentscope.core.message.ToolUseBlock;
import reactor.core.publisher.Mono;

import java.util.List;

/**
 * 日志 Hook:观察 ReAct 循环过程
 */
public class LoggingHook implements Hook {
    
    @Override
    public <T extends HookEvent> Mono<T> onEvent(T event) {
        // ========================================
        // 【推理阶段开始】
        // ========================================
        if (event instanceof PreReasoningEvent e) {
            System.out.println("\n[推理开始] 输入消息数: " + 
                    e.getInputMessages().size());
        }
        
        // ========================================
        // 【推理阶段结束】
        // ========================================
        if (event instanceof PostReasoningEvent e) {
            var msg = e.getReasoningMessage();
            List<ToolUseBlock> tools = msg.getContentBlocks(ToolUseBlock.class);
            
            if (tools.isEmpty()) {
                System.out.println("[推理完成] 直接生成回复");
            } else {
                System.out.println("[推理完成] 决定调用 " + tools.size() + " 个工具:");
                for (ToolUseBlock tool : tools) {
                    System.out.println("  - " + tool.getName() + 
                            "(" + tool.getInput() + ")");
                }
            }
        }
        
        // ========================================
        // 【行动阶段开始】
        // ========================================
        if (event instanceof PreActingEvent e) {
            System.out.println("[执行工具] " + e.getToolUse().getName());
        }
        
        // ========================================
        // 【行动阶段结束】
        // ========================================
        if (event instanceof PostActingEvent e) {
            System.out.println("[工具结果] " + 
                    e.getToolResult().getTextContent().substring(0, 
                            Math.min(50, e.getToolResult().getTextContent().length())) + 
                    "...");
        }
        
        return Mono.just(event);
    }
}

在创建智能体时添加 Hook:

ReActAgent agent = ReActAgent.builder()
        .name("TimeAssistant")
        .sysPrompt("...")
        .model(model)
        .toolkit(toolkit)
        .hooks(List.of(new LoggingHook()))  // 添加 Hook
        .build();

输出示例:

你: 纽约现在几点?

[推理开始] 输入消息数: 2
[推理完成] 决定调用 1 个工具:
  - get_current_time({"timezone":"America/New_York"})
[执行工具] get_current_time
[工具结果] 2024-03-15 02:30:30 EDT...
[推理开始] 输入消息数: 4
[推理完成] 直接生成回复

助手: 纽约现在是凌晨 2:30(东部时间)。

2.6 本章小结

本章我们完成了:

  1. 环境搭建

- 安装 JDK 17+ - 配置 Maven/Gradle - 获取 API Key

  1. 项目配置

- 添加 AgentScope 依赖 - 配置编译选项

  1. 第一个智能体

- 创建模型和智能体 - 发送消息获取响应 - 理解基本代码结构

  1. 添加工具能力

- 使用 @Tool 和 @ToolParam 注解 - 注册工具到 Toolkit - 交互式对话

  1. 理解 ReAct 循环

- 推理 + 行动的循环模式 - 使用 Hook 观察执行过程


练习

  1. 修改系统提示:尝试修改 sysPrompt,观察智能体行为变化
  2. 添加新工具:实现一个计算器工具,支持加减乘除
  3. 尝试其他模型:将 qwen-max 改为 qwen-plus,比较响应速度
  4. 观察 Token 用量:记录不同对话的 Token 消耗

常见问题

Q: 运行时报错 "DASHSCOPEAPIKEY not found"

A: 确保正确设置了环境变量。在 IDE 中可能需要在运行配置中单独设置。

Q: 工具没有被调用

A: 检查:

  1. @ToolParam 的 name 是否正确设置
  2. 工具描述是否清晰,让 LLM 知道何时使用
  3. 用户问题是否与工具相关

Q: 响应很慢

A:

  1. 首次调用可能较慢(建立连接)
  2. 尝试使用 qwen-turbo 模型
  3. 检查网络连接

下一章 → 第3章 消息系统

← 返回目录