目录:
1. 面向生产环境的智能体工程平台
2. 快速上手 从零构建生产级智能体
3. Agent —— 智能体的核心抽象与工程化实践
4. Message & Event —— 消息模型与事件流深度解
5. Middleware —— 无侵入式智能体扩展机制深度解析
6. Model —— 统一模型接入层与容错机制深度解析
7. Permission System —— 权限控制系统深度解析
8. Tool —— 工具系统架构与生产级实践深度解析
9. Context —— 运行时上下文与状态管理深度解析

一、引言:工具是智能体的"手和脚"

没有工具的 LLM 只能"说"。有了工具,智能体才能"做"——查询数据库、调用 API、执行计算、读写文件、搜索网络。

在 AgentScope Java 2.0 的构建块体系中,Tool(工具) 是连接智能体推理能力与外部世界的执行层。官方文档将其定位为 io.agentscope.core.tool 包下的完整工具框架,提供:

注解驱动定义 × 自动 JSON Schema 生成 × 响应式执行 × 工具组动态管理 × MCP 协议集成 × 权限管控 × 沙箱隔离

AgentScope Java 的工具系统有四个显著特点:

  • 注解驱动:@Tool + @ToolParam,一个普通 Java 方法秒变工具
  • 响应式原生:同步、异步 Mono、流式 Flux 全支持
  • 自动 Schema:框架自动生成 JSON Schema,LLM 可以直接理解
  • 工具组管理:按场景动态激活/停用工具
    本文将系统解析 AgentScope Java 2.0 工具系统的完整架构。

二、工具系统架构总览

2.1 分层架构

┌─────────────────────────────────────────────────────────────────┐
│                        Agent 层                                   │
│   ReActAgent / HarnessAgent                                     │
│   在 ReAct 循环中自主决定调用哪个工具、何时调用                     │
└──────────────────────────────┬──────────────────────────────────┘
                               │
                               ▼
┌─────────────────────────────────────────────────────────────────┐
│                     Toolkit(工具编排中心)                        │
│   注册全量工具 → toolFilter 过滤 → 生成 JSON Schema → 分发给模型  │
└──────────────────────────────┬──────────────────────────────────┘
                               │
                               ▼
┌─────────────────────────────────────────────────────────────────┐
│                     ToolGroup(工具分组)                          │
│   按域组织工具,支持动态激活/停用                                   │
└──────────────────────────────┬──────────────────────────────────┘
                               │
                               ▼
┌─────────────────────────────────────────────────────────────────┐
│                     ToolBase(工具基类)                           │
│   统一抽象:名称、描述、参数 Schema、执行逻辑、安全检查             │
└──────────────────────────────┬──────────────────────────────────┘
                               │
              ┌────────────────┼────────────────┐
              ▼                ▼                ▼
┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐
│  ReflectiveTool  │ │   内置工具        │ │   MCP 工具       │
│  (@Tool 注解)    │ │  Bash/Read/Write │ │  外部 MCP Server │
└──────────────────┘ └──────────────────┘ └──────────────────┘

2.2 核心组件关系

组件职责包路径
@Tool / @ToolParam注解驱动的工具定义io.agentscope.core.tool
Toolkit工具注册、编排、Schema 生成io.agentscope.core.tool
ToolGroup按域分组、动态激活io.agentscope.core.tool
ToolBase / AgentTool工具统一抽象基类io.agentscope.core.tool
ReflectiveFunctionTool注解 → 可执行工具的适配器io.agentscope.core.tool
ToolsConfig工具过滤配置(allow/deny)io.agentscope.harness.agent.tools
内置工具集Bash/Read/Write/Edit/Glob/Grep/Skillio.agentscope.harness.tools
MCP 集成外部 MCP Server 工具发现io.agentscope.core.tool.mcp

三、注解驱动:@Tool + @ToolParam

3.1 基本定义

AgentScope 2.0 采用注解驱动方式定义工具,开发者只需在普通 Java 方法上添加注解,框架自动完成:

  • 方法签名解析
  • JSON Schema 生成
  • 参数类型映射
  • 工具注册
import io.agentscope.core.tool.Tool;
import io.agentscope.core.tool.ToolParam;

public class WeatherTools {
    
    @Tool(name = "get_weather", description = "获取指定城市的当前天气信息")
    public String getWeather(
            @ToolParam(name = "city", description = "城市名称,如:北京、上海") 
            String city,
            @ToolParam(name = "unit", description = "温度单位:celsius 或 fahrenheit", required = false) 
            String unit) {
        
        // 实际业务逻辑
        return String.format("%s:晴天,气温 25℃", city);
    }
}

3.2 自动生成的 JSON Schema

框架通过反射自动将上述方法转换为 LLM 可理解的 JSON Schema:

{
  "type": "function",
  "function": {
    "name": "get_weather",
    "description": "获取指定城市的当前天气信息",
    "parameters": {
      "type": "object",
      "properties": {
        "city": {
          "type": "string",
          "description": "城市名称,如:北京、上海"
        },
        "unit": {
          "type": "string",
          "description": "温度单位:celsius 或 fahrenheit"
        }
      },
      "required": ["city"]
    }
  }
}

核心价值:开发者无需手动编写 JSON Schema,框架自动生成,LLM 可以直接理解并调用。

3.3 支持的返回类型

返回类型说明适用场景
String同步返回文本结果简单查询
Mono异步返回网络请求、数据库查询
Flux流式返回大文件读取、实时数据
byte[]二进制数据图片、文件下载
自定义对象自动序列化为JSON 结构化数据

3.4 异步工具示例

@Tool(name = "search_database", description = "在数据库中搜索记录")
public Mono<String> searchDatabase(
        @ToolParam(name = "query", description = "搜索关键词") String query,
        @ToolParam(name = "table", description = "目标表名") String table) {
    
    return Mono.fromCallable(() -> {
        // 异步数据库查询
        List<Record> results = dbService.search(table, query);
        return formatResults(results);
    }).subscribeOn(Schedulers.boundedElastic());
}

3.5 上下文注入

工具方法可以注入运行时上下文信息:

@Tool(name = "get_user_orders", description = "获取当前用户的订单列表")
public String getUserOrders(
        @ToolParam(name = "status", description = "订单状态过滤", required = false) 
        String status,
        RuntimeContext ctx) {  // 自动注入,不暴露给 LLM
    
    String userId = ctx.getUserId();
    return orderService.getOrders(userId, status).toString();
}

设计精妙之处:RuntimeContext 参数不会出现在 JSON Schema 中,LLM 不知道它的存在,但工具执行时可以获取当前用户、会话等上下文信息。

四、Toolkit:工具编排中心

4.1 核心职责

Toolkit 是工具系统的编排中心,负责:

  1. 注册所有工具(Java 工具 + MCP 工具)
  2. 生成工具描述列表(JSON Schema)
  3. 根据 toolFilter 过滤可见工具
  4. 分发工具调用请求
  5. 管理工具生命周期

4.2 注册与使用

// 创建 Toolkit 并注册工具
Toolkit toolkit = new Toolkit();
toolkit.registerTool(new WeatherTools());
toolkit.registerTool(new DatabaseTools());
toolkit.registerTool(new FileOperationTools());

// 构建 Agent 时传入 Toolkit
ReActAgent agent = ReActAgent.builder()
    .name("assistant")
    .model("dashscope:qwen-plus")
    .sysPrompt("你是一个全能助手。")
    .toolkit(toolkit)
    .build();

4.3 工具调用流程

用户消息到达
    │
    ▼
Agent 推理(Reasoning)
    │
    ▼ 模型决定调用工具
┌─────────────────────────────────────────────────────────┐
│  Toolkit.execute(toolUseBlock)                           │
│                                                          │
│  1. 根据 toolName 查找已注册工具                          │
│  2. 权限检查(PermissionEngine)                          │
│  3. 参数反序列化(JSON → Java 对象)                      │
│  4. 调用工具方法                                         │
│  5. 结果序列化(Java 对象 → String/JSON)                 │
│  6. 返回 ToolResultBlock                                 │
└─────────────────────────────────────────────────────────┘
    │
    ▼
Agent 继续推理(下一轮 Reasoning)

4.4 工具批处理(_ToolCallBatch)

当模型在一轮推理中同时请求调用多个工具时,Toolkit 支持并发批处理:

模型输出: [ToolUseBlock_1, ToolUseBlock_2, ToolUseBlock_3]
    │
    ▼
Toolkit.executeBatch()
    │
    ├── 并发执行 Tool_1 ──→ Result_1
    ├── 并发执行 Tool_2 ──→ Result_2
    └── 并发执行 Tool_3 ──→ Result_3
    │
    ▼
合并为 [ToolResultBlock_1, ToolResultBlock_2, ToolResultBlock_3]

生产意义:并发执行显著减少多工具调用场景的总耗时,从串行的 T1+T2+T3 降低为 max(T1,T2,T3)。

五、ToolGroup:按域组织与动态激活

5.1 设计动机

在实际业务中,一个 Agent 可能注册了 20+ 个工具,但不同场景下只需要激活其中一部分:

  • 客服场景:只需订单查询、物流追踪
  • 运维场景:需要服务器监控、日志查询
  • 开发场景:需要代码搜索、文件编辑

5.2 ToolGroup 定义

// 定义工具组
ToolGroup customerServiceGroup = ToolGroup.builder()
    .name("customer-service")
    .description("客服相关工具")
    .tools("query_order", "track_logistics", "refund_request")
    .build();

ToolGroup devOpsGroup = ToolGroup.builder()
    .name("devops")
    .description("运维相关工具")
    .tools("check_server", "query_logs", "restart_service")
    .build();

// 注册到 Toolkit
toolkit.registerGroup(customerServiceGroup);
toolkit.registerGroup(devOpsGroup);

5.3 动态激活/停用

// 运行时动态切换工具组
toolkit.activateGroup("customer-service");
toolkit.deactivateGroup("devops");

// Agent 此时只能看到客服工具
// 模型不会收到 devops 工具的描述

5.4 Agent 自主管理工具组

AgentScope 2.0 支持 Agent 自主决定激活/停用工具组:

// 内置元工具:ResetTools
// Agent 可以通过调用 reset_tools 工具来切换自己的工具集
@Tool(name = "reset_tools", description = "切换当前可用的工具组")
public String resetTools(
        @ToolParam(name = "group_name", description = "要激活的工具组名称") 
        String groupName) {
    toolkit.activateGroup(groupName);
    return "已切换到工具组: " + groupName;
}

设计哲学:让模型自己决定需要什么能力,而非框架强制编排。

六、内置工具集详解

6.1 工具全景

AgentScope Java 2.0 通过 HarnessAgent 提供了一套开箱即用的内置工具:

工具功能权限级别
Bash执行 Shell 命令高危(需权限管控)
Read读取文件内容低危
Write写入文件中危
Edit编辑文件(精确替换)中危
Glob文件名模式匹配低危
Grep文件内容搜索低危
Skill查看可用技能低危
ResetTools切换工具组(元工具)中危

6.2 Bash 工具:最复杂的权限检查

public class BashTool extends ToolBase {
    
    @Override
    public ToolResult execute(Map<String, Object> input, ToolContext ctx) {
        String command = (String) input.get("command");
        
        // 1. 内置安全检查(不可绕过)
        SecurityCheckResult check = validateCommand(command);
        if (!check.isSafe()) {
            return ToolResult.error("命令被安全策略拦截: " + check.getReason());
        }
        
        // 2. 在沙箱中执行
        ProcessResult result = sandbox.execute(command, 
            Duration.ofSeconds(30));  // 超时保护
        
        // 3. 截断过长输出
        String output = truncate(result.getOutput(), MAX_OUTPUT_LENGTH);
        
        return ToolResult.success(output);
    }
}

安全特性:

  • 危险命令黑名单(rm -rf /、mkfs、dd if=)
  • 敏感路径保护(~/.ssh/、/etc/passwd、.env)
  • 执行超时保护
  • 输出长度截断
  • 沙箱隔离执行

6.3 文件操作工具(Read/Write/Edit)

// Read:读取文件
@Tool(name = "read_file", description = "读取指定文件的内容")
public String readFile(
        @ToolParam(name = "file_path", description = "文件路径") String filePath,
        @ToolParam(name = "offset", description = "起始行号", required = false) Integer offset,
        @ToolParam(name = "limit", description = "读取行数", required = false) Integer limit) {
    // 支持分页读取大文件
}

// Write:写入文件
@Tool(name = "write_file", description = "将内容写入指定文件")
public String writeFile(
        @ToolParam(name = "file_path", description = "文件路径") String filePath,
        @ToolParam(name = "content", description = "要写入的内容") String content) {
    // 自动创建目录、权限检查
}

// Edit:精确编辑
@Tool(name = "edit_file", description = "精确替换文件中的指定内容")
public String editFile(
        @ToolParam(name = "file_path", description = "文件路径") String filePath,
        @ToolParam(name = "old_string", description = "要替换的原文") String oldString,
        @ToolParam(name = "new_string", description = "替换后的内容") String newString) {
    // 精确匹配替换,避免全文重写
}

6.4 搜索工具(Glob/Grep)

// Glob:文件名匹配
@Tool(name = "glob", description = "按模式匹配搜索文件")
public String glob(
        @ToolParam(name = "pattern", description = "匹配模式,如 **/*.java") String pattern) {
    // 返回匹配的文件路径列表
}

// Grep:内容搜索
@Tool(name = "grep", description = "在文件中搜索指定内容")
public String grep(
        @ToolParam(name = "pattern", description = "搜索模式(正则)") String pattern,
        @ToolParam(name = "path", description = "搜索路径", required = false) String path,
        @ToolParam(name = "include", description = "文件过滤", required = false) String include) {
    // 返回匹配行及上下文
}

6.5 Skill 工具与 ResetTools 元工具

// Skill:查看可用技能描述
@Tool(name = "skill", description = "查看指定技能的详细说明")
public String viewSkill(
        @ToolParam(name = "skill_name", description = "技能名称") String skillName) {
    // 返回 workspace/skills/ 目录下的技能文档
}

// ResetTools:切换工具组
@Tool(name = "reset_tools", description = "重置当前可用的工具集")
public String resetTools(
        @ToolParam(name = "tools", description = "要激活的工具列表") List<String> tools) {
    // 动态调整 Agent 可见的工具集
}

七、ToolBase 协议:统一工具抽象

7.1 接口定义

public interface AgentTool {
    
    /** 工具名称(唯一标识) */
    String getName();
    
    /** 工具描述(给 LLM 看的) */
    String getDescription();
    
    /** 参数 JSON Schema */
    Map<String, Object> getParameterSchema();
    
    /** 执行工具 */
    ToolResult execute(Map<String, Object> input, ToolContext ctx);
    
    /** 是否为外部工具(前端执行) */
    default boolean isExternalTool() { return false; }
    
    /** 安全检查(不可绕过) */
    default boolean isSafe(Map<String, Object> input) { return true; }
}

7.2 ToolBase 抽象基类

public abstract class ToolBase implements AgentTool {
    
    private final String name;
    private final String description;
    private final Map<String, Object> parameterSchema;
    private final boolean externalTool;
    
    /**
     * 安全检查 —— 在 PermissionEngine 之前执行,不可绕过
     */
    @Override
    public boolean isSafe(Map<String, Object> input) {
        return true;  // 子类可覆写
    }
    
    /**
     * 实际执行逻辑
     */
    @Override
    public abstract ToolResult execute(Map<String, Object> input, ToolContext ctx);
}

7.3 两种适配器

适配器说明适用场景
ReflectiveFunctionTool将 @Tool 注解方法适配为 AgentTool业务自定义工具
McpTool将 MCP Server 的远程工具适配为 AgentTool外部 MCP 集成

7.4 externalTool 机制

// 前端工具:不在后端执行,而是发送事件给前端
public class ApprovalTool extends ToolBase {
    
    public ApprovalTool() {
        super("request_approval", "请求人工审批", schema, true);  // externalTool = true
    }
    
    @Override
    public ToolResult execute(Map<String, Object> input, ToolContext ctx) {
        // 不会实际执行,而是触发 PermissionRequestEvent
        // Agent 暂停,等待前端用户操作后恢复
        throw new ExternalToolExecutionException();
    }
}

设计意图:支持 HITL(Human-in-the-Loop)场景,某些"工具"的执行主体是前端用户而非后端服务。

八、MCP 协议集成

8.1 声明式接入

AgentScope 2.0 通过 workspace/tools.json 实现一行声明一个 MCP Server:

{
  "mcpServers": {
    "github": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-github"],
      "env": {
        "GITHUB_TOKEN": "${GITHUB_TOKEN}"
      }
    },
    "postgres": {
      "url": "http://localhost:3001/sse",
      "transport": "sse"
    },
    "slack": {
      "command": "python",
      "args": ["-m", "mcp_slack_server"],
      "transport": "stdio"
    }
  }
}

8.2 支持的传输协议

协议说明适用场景
stdio标准输入输出本地进程
sseServer-Sent EventsHTTP 长连接
wsWebSocket双向实时通信

8.3 工具发现流程

Agent 启动
    │
    ▼
读取 workspace/tools.json
    │
    ▼
┌─────────────────────────────────────────────────────────┐
│  对每个 MCP Server:                                     │
│  1. 建立连接(stdio/sse/ws)                             │
│  2. 调用 tools/list 获取工具列表                          │
│  3. 将每个远程工具适配为 McpTool(实现 AgentTool 接口)     │
│  4. 注册到 Toolkit                                      │
└─────────────────────────────────────────────────────────┘
    │
    ▼
Agent 可调用所有本地 + 远程工具

8.4 工具命名冲突解决

当多个 MCP Server 暴露同名工具时,按以下优先级保留:

优先级来源说明
最高Toolkit 中 Java 端注册的工具本地优先
第一个启动成功的 MCP Server先到先得
后续同名工具被忽略 + WARN 日志

8.5 McpMeta:调用元数据

// MCP 工具调用时可传递元数据
McpMeta meta = McpMeta.builder()
    .sessionId(ctx.getSessionId())
    .userId(ctx.getUserId())
    .build();

九、工具分组与过滤:workspace/tools.json + toolFilter

9.1 配置化工具过滤

2.0 提供 ToolsConfig 按 allow/deny 精确匹配过滤:

{
  "roles": {
    "customer-service": {
      "allow": ["query_order", "track_logistics", "get_weather"],
      "deny": ["bash", "write_file", "edit_file"]
    },
    "dba": {
      "allow": ["execute_sql", "read_file", "grep"],
      "deny": ["bash", "write_file"]
    },
    "admin": {
      "allow": ["*"],
      "deny": []
    }
  }
}

9.2 Java 端配置

HarnessAgent agent = HarnessAgent.builder()
    .name("customer-service-agent")
    .model("dashscope:qwen-plus")
    .toolkit(toolkit)
    .toolFilter(ToolsConfig.builder()
        .allow("query_order", "track_logistics", "get_weather")
        .deny("bash", "write_file", "edit_file")
        .build())
    .build();

9.3 设计优势

同一套工具,两个角色,两个视野。

  • Toolkit 注册全量工具(一次注册)
  • ToolsConfig 按角色过滤(多次复用)
  • 新增角色只需加配置,不改 Java 代码

十、工具与权限系统的集成

10.1 执行链路

模型决定调用工具
    │
    ▼
┌─────────────────────────────────────────────────────────┐
│ Step 1: ToolBase.isSafe() —— 工具自身安全检查(不可绕过)  │
└──────────────────────────────┬──────────────────────────┘
                               │ 通过
                               ▼
┌─────────────────────────────────────────────────────────┐
│ Step 2: PermissionEngine.evaluate() —— 权限规则匹配       │
│   DENY 规则 → ASK 规则 → ALLOW 规则 → Mode 默认 → 兜底   │
└──────────────────────────────┬──────────────────────────┘
                               │ ALLOW
                               ▼
┌─────────────────────────────────────────────────────────┐
│ Step 3: Middleware.onActing() —— 中间件拦截               │
│   追踪 / 审计 / 限流 / 参数校验                           │
└──────────────────────────────┬──────────────────────────┘
                               │
                               ▼
┌─────────────────────────────────────────────────────────┐
│ Step 4: ToolBase.execute() —— 实际执行                   │
│   在沙箱中执行,超时保护,输出截断                         │
└─────────────────────────────────────────────────────────┘

10.2 沙箱执行

// 工具在沙箱中执行,隔离宿主环境
SandboxConfig sandbox = SandboxConfig.builder()
    .type(SandboxType.DOCKER)       // LOCAL / DOCKER / E2B
    .image("agentscope-sandbox:latest")
    .workspacePath("/workspace")
    .timeout(Duration.ofSeconds(30))
    .memoryLimit("512m")
    .cpuLimit(1.0)
    .build();

十一、工具与事件系统的集成

11.1 工具调用事件

每次工具调用都会产生对应的事件:

agent.streamEvents(userMsg, ctx)
    .doOnNext(event -> {
        switch (event.getType()) {
            case TOOL_CALL_START -> {
                ToolCallStartEvent e = (ToolCallStartEvent) event;
                System.out.println("🔧 调用工具: " + e.getToolCallName());
                System.out.println("   参数: " + e.getParameters());
            }
            case TOOL_CALL_END -> {
                ToolCallEndEvent e = (ToolCallEndEvent) event;
                System.out.println("✅ 工具完成: " + e.getToolCallName());
                System.out.println("   耗时: " + e.getDuration() + "ms");
            }
            case TOOL_RESULT -> {
                ToolResultEvent e = (ToolResultEvent) event;
                System.out.println("📋 结果: " + truncate(e.getContent(), 200));
            }
        }
    })
    .subscribe();

11.2 事件序列

ToolCallStartEvent (工具名、参数)
    │
    ├── [如果 ASK] → PermissionRequestEvent → 等待 → PermissionResponseEvent
    │
    ├── [执行中...] 
    │
    └── ToolCallEndEvent (耗时、状态)
         └── ToolResultEvent (执行结果)

十二、完整实战:构建多工具业务 Agent

12.1 场景描述

构建一个电商客服 Agent:

  • 可查询订单、追踪物流
  • 可申请退款(需人工审批)
  • 可查询天气(辅助推荐)
  • 不能执行系统命令

12.2 完整代码

public class EcommerceAgentDemo {
    
    public static void main(String[] args) {
        
        // === 1. 定义业务工具 ===
        Toolkit toolkit = new Toolkit();
        
        // 订单工具
        toolkit.registerTool(new Object() {
            @Tool(name = "query_order", description = "查询订单详情")
            public String queryOrder(
                    @ToolParam(name = "order_id", description = "订单号") String orderId,
                    RuntimeContext ctx) {
                return orderService.getOrder(ctx.getUserId(), orderId).toJson();
            }
            
            @Tool(name = "track_logistics", description = "追踪物流状态")
            public String trackLogistics(
                    @ToolParam(name = "order_id", description = "订单号") String orderId) {
                return logisticsService.track(orderId).toJson();
            }
        });
        
        // 退款工具(外部工具,需前端审批)
        toolkit.registerTool(new Object() {
            @Tool(name = "request_refund", description = "申请退款")
            public String requestRefund(
                    @ToolParam(name = "order_id", description = "订单号") String orderId,
                    @ToolParam(name = "reason", description = "退款原因") String reason,
                    RuntimeContext ctx) {
                // 标记为 externalTool,触发 HITL 审批
                return "REFUND_PENDING_APPROVAL";
            }
        });
        
        // 天气工具
        toolkit.registerTool(new WeatherTools());
        
        // === 2. 配置工具过滤 ===
        ToolsConfig toolFilter = ToolsConfig.builder()
            .allow("query_order", "track_logistics", "request_refund", "get_weather")
            .deny("bash", "write_file", "edit_file")  // 禁止危险操作
            .build();
        
        // === 3. 配置权限 ===
        PermissionContextState permCtx = PermissionContextState.builder()
            .mode(PermissionMode.DEFAULT)
            .addAllowRule("query_order", PermissionRule.allow("query_order"))
            .addAllowRule("track_logistics", PermissionRule.allow("track_logistics"))
            .addAllowRule("get_weather", PermissionRule.allow("get_weather"))
            .addAskRule("request_refund", PermissionRule.ask("request_refund"))
            .build();
        
        // === 4. 构建 Agent ===
        HarnessAgent agent = HarnessAgent.builder()
            .name("ecommerce-cs")
            .sysPrompt("""
                你是电商客服助手。你可以:
                - 查询订单详情
                - 追踪物流状态
                - 申请退款(需要用户确认)
                - 查询天气
                你不能执行任何系统命令或修改文件。
                """)
            .model("dashscope:qwen-plus")
            .toolkit(toolkit)
            .toolFilter(toolFilter)
            .permissionContext(permCtx)
            .middleware(new OtelTracingMiddleware())
            .middleware(new AuditMiddleware())
            .build();
        
        // === 5. 流式调用 ===
        RuntimeContext rt = RuntimeContext.builder()
            .sessionId("session-001")
            .userId("user-alice")
            .build();
        
        agent.streamEvents(
            new UserMessage("帮我查一下订单 ORD-2024-001 的物流状态"),
            rt
        )
        .doOnNext(event -> {
            if (event instanceof TextBlockDeltaEvent delta) {
                System.out.print(delta.getDelta());
            }
            if (event instanceof ToolCallStartEvent toolStart) {
                System.out.println("\n🔧 [" + toolStart.getToolCallName() + "]");
            }
            if (event instanceof PermissionRequestEvent permReq) {
                System.out.println("\n⚠️ 需要审批: " + permReq.getToolName());
            }
        })
        .blockLast();
    }
}

12.3 执行效果


用户: 帮我查一下订单 ORD-2024-001 的物流状态

🔧 [track_logistics]
Agent: 您的订单 ORD-2024-001 的物流状态如下:

📦 当前状态:运输中
🚚 承运商:顺丰速运
📍 当前位置:杭州转运中心
⏰ 预计送达:2026-08-09 14:00

物流轨迹:
- 08-07 08:30 到达杭州转运中心
- 08-06 22:15 从上海仓库发出
- 08-06 18:00 商家已发货

如需进一步帮助,请随时告诉我。

十三、从 1.x 到 2.0 的工具系统演进

13.1 对比总结

维度1.x2.0
工具定义继承 Tool 抽象类@Tool 注解 + 反射
Schema 生成手动编写或半自动全自动生成
工具管理简单列表Toolkit + ToolGroup
动态激活不支持ToolGroup 动态切换
权限管控PermissionEngine 六步决策
沙箱执行LOCAL / DOCKER / E2B
MCP 集成tools.json 声明式
工具过滤硬编码ToolsConfig 配置化
批处理串行并发执行
事件追踪ToolCallStart/End/Result
前端工具externalTool 机制

13.2 迁移示例

1.x 写法:

// 1.x: 继承抽象类,手动实现
public class WeatherTool extends Tool {
    @Override
    public String getName() { return "get_weather"; }
    
    @Override
    public String getDescription() { return "获取天气"; }
    
    @Override
    public Map<String, Object> getParameterSchema() {
        // 手动编写 JSON Schema...
    }
    
    @Override
    public String execute(Map<String, Object> params) {
        return weatherApi.query((String) params.get("city"));
    }
}

2.0 写法:

// 2.0: 注解驱动,零样板代码
public class WeatherTools {
    @Tool(name = "get_weather", description = "获取天气")
    public String getWeather(
            @ToolParam(name = "city", description = "城市名") String city) {
        return weatherApi.query(city);
    }
}

十四、设计哲学与最佳实践

14.1 核心设计原则

原则体现
注解驱动 > 继承@Tool 比继承 Tool 类更轻量、更 Java 化
自动 > 手动JSON Schema 自动生成,无需手写
配置 > 代码tools.json 声明 MCP,toolFilter 配置过滤
安全不可绕过ToolBase.isSafe() 在权限系统之前执行
模型自主Agent 自己决定调用哪个工具、何时调用
响应式原生同步/异步/流式全覆盖

14.2 最佳实践

  1. 工具描述要精确:LLM 依赖 description 决定何时调用,模糊描述会导致误调用
  2. 参数描述要具体:包含示例值、取值范围、格式要求
  3. 单一职责:每个工具只做一件事,避免"万能工具"
  4. 错误信息要有用:返回的错误信息应指导 LLM 如何修正
  5. 输出要截断:避免超长输出撑爆上下文
  6. 敏感操作加 ASK:删除、修改、支付等操作必须人工确认
  7. 使用 ToolGroup 管理可见性:避免 20+ 工具全部暴露给模型

14.3 工具描述编写指南

// ❌ 差的描述
@Tool(name = "search", description = "搜索")

// ✅ 好的描述
@Tool(name = "search_orders", 
      description = "根据订单号、用户ID或时间范围搜索订单。" +
                    "返回订单列表(最多20条)。" +
                    "如果用户只提供了模糊信息,先用此工具确认具体订单。")

十五、与其他构建块的协作关系

┌─────────────────────────────────────────────────────────────────┐
│                        Agent 层                                   │
│   ReAct 循环:Reasoning → Acting → Observation → Reasoning      │
└──────────────────────────────┬──────────────────────────────────┘
                               │ 决定调用工具
                               ▼
┌─────────────────────────────────────────────────────────────────┐
│                     Middleware 层                                 │
│   onActing: 追踪 / 限流 / 审计 / 参数校验                        │
└──────────────────────────────┬──────────────────────────────────┘
                               │
                               ▼
┌─────────────────────────────────────────────────────────────────┐
│                     Permission 层                                 │
│   PermissionEngine: DENY → ASK → ALLOW → Mode → 兜底            │
└──────────────────────────────┬──────────────────────────────────┘
                               │ ALLOW
                               ▼
┌─────────────────────────────────────────────────────────────────┐
│                       Tool 层                                     │
│   Toolkit → ToolBase.execute() → 沙箱执行 → 返回结果             │
└──────────────────────────────┬──────────────────────────────────┘
                               │
                               ▼
┌─────────────────────────────────────────────────────────────────┐
│                      Event 层                                     │
│   ToolCallStartEvent → ToolCallEndEvent → ToolResultEvent        │
└──────────────────────────────┬──────────────────────────────────┘
                               │
                               ▼
┌─────────────────────────────────────────────────────────────────┐
│                     Message 层                                    │
│   ToolUseBlock (ASSISTANT) → ToolResultBlock (TOOL)             │
│   写入 AgentState,参与上下文压缩                                  │
└─────────────────────────────────────────────────────────────────┘

十六、结语

AgentScope Java 2.0 的 Tool 构建块,用注解驱动将工具定义简化到极致,用自动 Schema 生成消除了手写 JSON 的繁琐,用 Toolkit + ToolGroup 实现了灵活的工具编排,用 MCP 协议打通了外部工具生态,用权限系统 + 沙箱守住了安全底线。
它的核心价值在于:

让"给 Agent 加一个能力"这件事,从"写一个类 + 配一堆 Schema + 处理一堆异常",变成"加一个注解"。

对于 Java 开发者而言,这套设计完美契合了 Spring 生态的注解驱动传统——@Tool 之于 AgentScope,就像 @RestController 之于 Spring MVC:一个注解,开启一个世界。

工具定义了智能体"能做什么",权限定义了"允许做什么",事件定义了"正在做什么"。三者合一,构成了一个既能做事、又受约束、还可观测的智能体执行体系。

Logo

小龙虾开发者社区是 CSDN 旗下专注 OpenClaw 生态的官方阵地,聚焦技能开发、插件实践与部署教程,为开发者提供可直接落地的方案、工具与交流平台,助力高效构建与落地 AI 应用

更多推荐