第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 本章小结
本章我们学习了:
- 工具组
- 创建和管理工具组 - 动态激活/停用 - 元工具自主管理
- 预设参数
- 隐藏敏感信息 - 自动注入固定值
- 执行上下文
- ToolExecutionContext - 传递业务对象给工具
- 工具挂起
- ToolSuspendException - 等待外部处理
- 高级特性
- Schema Only 工具 - 内置工具
下一章 → 第9章 MCP协议集成