第8章 工具高级特性

第8章 工具高级特性

本章目标:掌握工具组、预设参数、执行上下文等高级特性


8.1 工具组(Tool Group)

8.1.1 工具组的作用

工具组用于按场景管理工具,支持动态激活和停用:

┌─────────────────────────────────────────────────────────────┐
│                       工具组架构                             │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│   ┌───────────────┐  ┌───────────────┐  ┌───────────────┐  │
│   │  数学工具组    │  │  网络工具组    │  │  文件工具组    │  │
│   │  (math_ops)   │  │  (network_ops) │  │  (file_ops)   │  │
│   │  ─────────    │  │  ─────────     │  │  ─────────    │  │
│   │  ✓ 已激活     │  │  ✗ 未激活      │  │  ✗ 未激活     │  │
│   │               │  │                │  │               │  │
│   │  - add        │  │  - http_get    │  │  - read_file  │  │
│   │  - subtract   │  │  - ping        │  │  - write_file │  │
│   │  - multiply   │  │  - dns_lookup  │  │  - list_dir   │  │
│   └───────────────┘  └───────────────┘  └───────────────┘  │
│                                                             │
│   LLM 只能看到已激活工具组中的工具                            │
│                                                             │
└─────────────────────────────────────────────────────────────┘

8.1.2 创建和使用工具组

// ========================================
// 【创建工具组】
// ========================================

Toolkit toolkit = new Toolkit();

// 创建工具组
toolkit.createToolGroup(
        "math_ops",           // 工具组 ID
        "数学运算工具",        // 描述
        true                  // 默认激活状态
);

toolkit.createToolGroup(
        "network_ops",
        "网络操作工具",
        false                 // 默认停用
);

toolkit.createToolGroup(
        "file_ops",
        "文件操作工具",
        false
);

// ========================================
// 【注册工具到工具组】
// ========================================

toolkit.registration()
        .tool(new MathTools())
        .group("math_ops")    // 分配到数学工具组
        .apply();

toolkit.registration()
        .tool(new NetworkTools())
        .group("network_ops")
        .apply();

toolkit.registration()
        .tool(new FileTools())
        .group("file_ops")
        .apply();

// ========================================
// 【动态切换工具组】
// ========================================

// 激活工具组
toolkit.updateToolGroups(List.of("network_ops"), true);

// 停用工具组
toolkit.updateToolGroups(List.of("math_ops"), false);

// 批量操作
toolkit.updateToolGroups(
        List.of("network_ops", "file_ops"), 
        true
);

8.1.3 元工具:智能体自主管理工具组

// ========================================
// 【元工具】
// 让智能体自己决定激活哪些工具组
// ========================================

// 创建带元工具的 Toolkit
Toolkit toolkit = new Toolkit(true);  // true 表示启用元工具

// 创建工具组(默认都不激活)
toolkit.createToolGroup("math_ops", "数学运算", false);
toolkit.createToolGroup("network_ops", "网络操作", false);
toolkit.createToolGroup("file_ops", "文件操作", false);

// 注册工具...

// 智能体会自动获得 reset_equipped_tools 元工具
// 可以根据任务需求自主激活/停用工具组

ReActAgent agent = ReActAgent.builder()
        .name("SmartAssistant")
        .sysPrompt("""
            你是一个智能助手。
            根据用户的任务需求,先使用 reset_equipped_tools 激活需要的工具组,
            然后使用相应的工具完成任务。
            
            可用工具组:
            - math_ops: 数学运算
            - network_ops: 网络操作
            - file_ops: 文件操作
            """)
        .model(model)
        .toolkit(toolkit)
        .build();

// 用户:计算 123 * 456
// 智能体会:
// 1. 调用 reset_equipped_tools 激活 math_ops
// 2. 调用 multiply 工具执行计算

8.2 预设参数

预设参数用于隐藏敏感信息或自动注入固定值:

// ========================================
// 【预设参数示例】
// API Key 不暴露给 LLM
// ========================================

public class EmailTools {
    @Tool(name = "send_email", description = "发送邮件")
    public String sendEmail(
            @ToolParam(name = "to") String to,
            @ToolParam(name = "subject") String subject,
            @ToolParam(name = "body") String body,
            @ToolParam(name = "apiKey") String apiKey  // 敏感参数
    ) {
        return emailService.send(to, subject, body, apiKey);
    }
}

// 注册时预设 apiKey
toolkit.registration()
        .tool(new EmailTools())
        .presetParameters(Map.of(
                "send_email", Map.of(
                        "apiKey", System.getenv("EMAIL_API_KEY")
                )
        ))
        .apply();

// LLM 只会看到 to、subject、body 三个参数
// apiKey 会自动注入,对 LLM 不可见

8.3 工具执行上下文

通过 ToolExecutionContext 传递业务对象给工具:

// ========================================
// 【定义上下文对象】
// ========================================

public class UserContext {
    private final String userId;
    private final String tenantId;
    private final Set<String> permissions;
    
    // getters...
}

public class RequestContext {
    private final String requestId;
    private final String clientIp;
    
    // getters...
}

// ========================================
// 【工具中使用上下文】
// ========================================

public class OrderTools {
    @Tool(name = "get_orders", description = "获取用户订单")
    public List<Order> getOrders(
            @ToolParam(name = "status") String status,
            UserContext userCtx,      // 自动注入,不需要 @ToolParam
            RequestContext reqCtx     // 自动注入
    ) {
        // 使用上下文中的用户信息
        String userId = userCtx.getUserId();
        
        // 记录审计日志
        log.info("Request {} from {} querying orders for user {}", 
                reqCtx.getRequestId(), reqCtx.getClientIp(), userId);
        
        return orderService.findByUserAndStatus(userId, status);
    }
}

// ========================================
// 【创建带上下文的智能体】
// ========================================

// 构建上下文
ToolExecutionContext context = ToolExecutionContext.builder()
        .register(new UserContext("user-123", "tenant-001", Set.of("read", "write")))
        .register(new RequestContext("req-456", "192.168.1.1"))
        .build();

// 创建智能体
ReActAgent agent = ReActAgent.builder()
        .name("OrderAssistant")
        .model(model)
        .toolkit(toolkit)
        .toolExecutionContext(context)
        .build();

8.4 工具挂起(Tool Suspend)

工具挂起允许工具暂停执行,等待外部处理:

import io.agentscope.core.tool.ToolSuspendException;

// ========================================
// 【工具挂起示例】
// 需要外部系统执行的操作
// ========================================

@Tool(name = "execute_payment", description = "执行支付")
public String executePayment(
        @ToolParam(name = "orderId") String orderId,
        @ToolParam(name = "amount") double amount
) {
    // 创建支付请求
    String paymentId = paymentService.createRequest(orderId, amount);
    
    // 抛出挂起异常,等待外部支付系统回调
    throw new ToolSuspendException(
            "payment_pending",           // 挂起类型
            Map.of(                       // 挂起数据
                    "paymentId", paymentId,
                    "orderId", orderId,
                    "amount", amount
            )
    );
}

// ========================================
// 【处理挂起状态】
// ========================================

Msg response = agent.call(userMsg).block();

if (response.getGenerateReason() == GenerateReason.TOOL_SUSPENDED) {
    // 获取挂起的工具信息
    List<ToolUseBlock> suspendedTools = response.getContentBlocks(ToolUseBlock.class);
    
    // 等待外部处理(如支付回调)
    String paymentResult = waitForPaymentCallback();
    
    // 构建工具结果
    Msg toolResult = Msg.builder()
            .role(MsgRole.TOOL)
            .content(suspendedTools.stream()
                    .map(t -> ToolResultBlock.of(t.getId(), t.getName(),
                            TextBlock.builder().text(paymentResult).build()))
                    .toList())
            .build();
    
    // 恢复执行
    response = agent.call(toolResult).block();
}

8.5 Schema Only 工具

仅注册 Schema,不提供实现,由外部执行:

// ========================================
// 【Schema Only 工具】
// 用于外部系统执行的场景
// ========================================

// 定义 Schema
ToolInfo schemaOnlyTool = ToolInfo.builder()
        .name("external_api_call")
        .description("调用外部 API")
        .parameters(Map.of(
                "type", "object",
                "properties", Map.of(
                        "endpoint", Map.of("type", "string"),
                        "method", Map.of("type", "string"),
                        "body", Map.of("type", "object")
                ),
                "required", List.of("endpoint", "method")
        ))
        .build();

// 注册 Schema Only 工具
toolkit.registerSchemaOnlyTool(schemaOnlyTool);

// 执行时需要手动处理
Msg response = agent.call(userMsg).block();

if (response.hasContentBlocks(ToolUseBlock.class)) {
    List<ToolUseBlock> toolCalls = response.getContentBlocks(ToolUseBlock.class);
    
    for (ToolUseBlock tool : toolCalls) {
        if ("external_api_call".equals(tool.getName())) {
            // 手动执行外部 API 调用
            String result = externalApiClient.call(tool.getInput());
            // 构建结果并返回...
        }
    }
}

8.6 内置工具

AgentScope 提供了一些开箱即用的内置工具:

import io.agentscope.core.tool.builtin.ReadFileTool;
import io.agentscope.core.tool.builtin.WriteFileTool;

// ========================================
// 【文件工具】
// ========================================

// 读文件工具(限制在安全目录)
toolkit.registerTool(new ReadFileTool("/safe/workspace"));

// 写文件工具
toolkit.registerTool(new WriteFileTool("/safe/workspace"));

// ========================================
// 【多模态工具】
// ========================================

import io.agentscope.extensions.multimodal.DashScopeMultiModalTool;

// 图像理解工具
toolkit.registerTool(new DashScopeMultiModalTool(
        System.getenv("DASHSCOPE_API_KEY")
));

8.7 本章小结

本章我们学习了:

  1. 工具组

- 创建和管理工具组 - 动态激活/停用 - 元工具自主管理

  1. 预设参数

- 隐藏敏感信息 - 自动注入固定值

  1. 执行上下文

- ToolExecutionContext - 传递业务对象给工具

  1. 工具挂起

- ToolSuspendException - 等待外部处理

  1. 高级特性

- Schema Only 工具 - 内置工具


下一章 → 第9章 MCP协议集成

← 返回目录