AgentScope 2.0:8. Tool —— 工具系统架构与生产级实践深度解析
目录:
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/Skill | io.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 是工具系统的编排中心,负责:
- 注册所有工具(Java 工具 + MCP 工具)
- 生成工具描述列表(JSON Schema)
- 根据 toolFilter 过滤可见工具
- 分发工具调用请求
- 管理工具生命周期
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 | 标准输入输出 | 本地进程 |
| sse | Server-Sent Events | HTTP 长连接 |
| ws | WebSocket | 双向实时通信 |
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.x | 2.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 最佳实践
- 工具描述要精确:LLM 依赖 description 决定何时调用,模糊描述会导致误调用
- 参数描述要具体:包含示例值、取值范围、格式要求
- 单一职责:每个工具只做一件事,避免"万能工具"
- 错误信息要有用:返回的错误信息应指导 LLM 如何修正
- 输出要截断:避免超长输出撑爆上下文
- 敏感操作加 ASK:删除、修改、支付等操作必须人工确认
- 使用 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:一个注解,开启一个世界。
工具定义了智能体"能做什么",权限定义了"允许做什么",事件定义了"正在做什么"。三者合一,构成了一个既能做事、又受约束、还可观测的智能体执行体系。
更多推荐



所有评论(0)