mirror of
https://gitee.com/mateos/mateclaw.git
synced 2026-09-13 19:23:42 +08:00
feat(agent): add multi-agent delegation tool for agent-to-agent collaboration
This commit is contained in:
parent
9c56b9830a
commit
2c3d805521
@ -0,0 +1,130 @@
|
||||
package vip.mate.tool.builtin;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.ai.tool.annotation.Tool;
|
||||
import org.springframework.ai.tool.annotation.ToolParam;
|
||||
import org.springframework.stereotype.Component;
|
||||
import vip.mate.agent.AgentService;
|
||||
import vip.mate.agent.model.AgentEntity;
|
||||
import vip.mate.agent.repository.AgentMapper;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 内置工具:Agent 委派
|
||||
* <p>
|
||||
* 允许当前 Agent 将子任务委派给另一个 Agent 执行,实现多 Agent 协作。
|
||||
* 被委派的 Agent 在独立会话中运行,结果作为工具观察返回给调用方。
|
||||
*
|
||||
* @author MateClaw Team
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class DelegateAgentTool {
|
||||
|
||||
private static final int MAX_DELEGATION_DEPTH = 3;
|
||||
private static final int MAX_RESULT_LENGTH = 4000;
|
||||
|
||||
private final AgentService agentService;
|
||||
private final AgentMapper agentMapper;
|
||||
|
||||
@Tool(description = """
|
||||
委派任务给另一个 Agent 执行,实现多 Agent 协作。
|
||||
当前任务需要特定领域的 Agent 协助时使用此工具。
|
||||
目标 Agent 将在独立会话中执行任务,返回其最终回复。
|
||||
注意:需提供完整的任务上下文,目标 Agent 无法看到当前对话历史。""")
|
||||
public String delegateToAgent(
|
||||
@ToolParam(description = "目标 Agent 的名称(精确匹配)") String agentName,
|
||||
@ToolParam(description = "要委派的任务描述,必须包含完整上下文信息") String task) {
|
||||
|
||||
// 1. 参数校验
|
||||
if (agentName == null || agentName.isBlank()) {
|
||||
return "[错误] 请指定目标 Agent 名称。" + availableAgentsHint();
|
||||
}
|
||||
if (task == null || task.isBlank()) {
|
||||
return "[错误] 请提供任务描述。";
|
||||
}
|
||||
|
||||
// 2. 递归深度检查
|
||||
int depth = DelegationContext.currentDepth();
|
||||
if (depth >= MAX_DELEGATION_DEPTH) {
|
||||
return "[错误] 委派层级已达上限(" + MAX_DELEGATION_DEPTH + " 层),无法继续委派,请直接处理任务。";
|
||||
}
|
||||
|
||||
// 3. 按名称查找目标 Agent
|
||||
AgentEntity target = agentMapper.selectOne(
|
||||
new LambdaQueryWrapper<AgentEntity>()
|
||||
.eq(AgentEntity::getName, agentName.trim())
|
||||
.eq(AgentEntity::getEnabled, true));
|
||||
|
||||
if (target == null) {
|
||||
return "[错误] 未找到名为「" + agentName + "」的已启用 Agent。" + availableAgentsHint();
|
||||
}
|
||||
|
||||
// 4. 在独立会话中执行
|
||||
String tempConversationId = "delegate-" + UUID.randomUUID();
|
||||
log.info("Agent 委派: depth={}, target={}({}), task={}",
|
||||
depth + 1, target.getName(), target.getId(),
|
||||
task.length() > 100 ? task.substring(0, 100) + "..." : task);
|
||||
|
||||
DelegationContext.enter();
|
||||
try {
|
||||
String result = agentService.chat(target.getId(), task, tempConversationId);
|
||||
String truncated = truncate(result, MAX_RESULT_LENGTH);
|
||||
return "[Agent「" + target.getName() + "」的回复]\n\n" + truncated;
|
||||
} catch (Exception e) {
|
||||
log.error("Agent 委派执行失败: target={}, error={}", target.getName(), e.getMessage(), e);
|
||||
return "[错误] Agent「" + target.getName() + "」执行失败: " + e.getMessage();
|
||||
} finally {
|
||||
DelegationContext.exit();
|
||||
}
|
||||
}
|
||||
|
||||
@Tool(description = "列出所有可用的 Agent(已启用),包括名称、类型和描述。用于在委派前了解有哪些 Agent 可以协助。")
|
||||
public String listAvailableAgents() {
|
||||
List<AgentEntity> agents = agentMapper.selectList(
|
||||
new LambdaQueryWrapper<AgentEntity>()
|
||||
.eq(AgentEntity::getEnabled, true)
|
||||
.orderByAsc(AgentEntity::getName));
|
||||
|
||||
if (agents.isEmpty()) {
|
||||
return "当前没有可用的 Agent。";
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder("可用 Agent 列表:\n\n");
|
||||
for (AgentEntity agent : agents) {
|
||||
sb.append("- **").append(agent.getName()).append("**");
|
||||
sb.append(" (").append(agent.getAgentType()).append(")");
|
||||
if (agent.getDescription() != null && !agent.getDescription().isBlank()) {
|
||||
sb.append(" — ").append(agent.getDescription());
|
||||
}
|
||||
sb.append("\n");
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private String availableAgentsHint() {
|
||||
List<AgentEntity> agents = agentMapper.selectList(
|
||||
new LambdaQueryWrapper<AgentEntity>()
|
||||
.eq(AgentEntity::getEnabled, true)
|
||||
.select(AgentEntity::getName));
|
||||
if (agents.isEmpty()) {
|
||||
return "";
|
||||
}
|
||||
String names = agents.stream()
|
||||
.map(AgentEntity::getName)
|
||||
.collect(Collectors.joining("、"));
|
||||
return "\n可用 Agent: " + names;
|
||||
}
|
||||
|
||||
private static String truncate(String text, int maxLength) {
|
||||
if (text == null) return "";
|
||||
if (text.length() <= maxLength) return text;
|
||||
return text.substring(0, maxLength) + "\n\n... [结果已截断,原文共 " + text.length() + " 字符]";
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,36 @@
|
||||
package vip.mate.tool.builtin;
|
||||
|
||||
/**
|
||||
* 跟踪 Agent 委派调用深度,防止无限递归。
|
||||
* <p>
|
||||
* 使用 ThreadLocal 存储当前线程的委派层级。
|
||||
* 每次 {@link DelegateAgentTool} 发起委派时 +1,返回后 -1。
|
||||
*
|
||||
* @author MateClaw Team
|
||||
*/
|
||||
public final class DelegationContext {
|
||||
|
||||
private static final ThreadLocal<Integer> DEPTH = ThreadLocal.withInitial(() -> 0);
|
||||
|
||||
private DelegationContext() {}
|
||||
|
||||
/** 获取当前委派深度(0 = 顶层调用) */
|
||||
public static int currentDepth() {
|
||||
return DEPTH.get();
|
||||
}
|
||||
|
||||
/** 进入下一层委派 */
|
||||
public static void enter() {
|
||||
DEPTH.set(DEPTH.get() + 1);
|
||||
}
|
||||
|
||||
/** 退出当前委派层 */
|
||||
public static void exit() {
|
||||
int current = DEPTH.get();
|
||||
if (current <= 1) {
|
||||
DEPTH.remove();
|
||||
} else {
|
||||
DEPTH.set(current - 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -329,6 +329,11 @@ MERGE INTO mate_tool (id, name, display_name, description, tool_type, bean_name,
|
||||
KEY (id)
|
||||
VALUES (1000000013, 'MateClawDocTool', 'MateClaw Docs', 'Read built-in MateClaw project documentation. action=list to list docs, action=read to read specific doc.', 'builtin', 'mateClawDocTool', '📚', TRUE, TRUE, NOW(), NOW(), 0);
|
||||
|
||||
-- Built-in tool: Agent Delegation (Multi-Agent Collaboration)
|
||||
MERGE INTO mate_tool (id, name, display_name, description, tool_type, bean_name, icon, enabled, builtin, create_time, update_time, deleted)
|
||||
KEY (id)
|
||||
VALUES (1000000014, 'DelegateAgentTool', 'Agent Delegation', 'Delegate tasks to other Agents for multi-agent collaboration. Call target Agent by name, run in isolated session and return result.', 'builtin', 'delegateAgentTool', '🤝', TRUE, TRUE, NOW(), NOW(), 0);
|
||||
|
||||
-- Example MCP Server: Filesystem (see MateClaw docs mcpServers.filesystem)
|
||||
MERGE INTO mate_mcp_server (
|
||||
id, name, description, transport, url, headers_json, command, args_json, env_json, cwd,
|
||||
|
||||
@ -331,6 +331,11 @@ INSERT INTO mate_tool (id, name, display_name, description, tool_type, bean_name
|
||||
VALUES (1000000013, 'MateClawDocTool', 'MateClaw Docs', 'Read built-in MateClaw project documentation. action=list to list docs, action=read to read specific doc.', 'builtin', 'mateClawDocTool', '📚', TRUE, TRUE, NOW(), NOW(), 0)
|
||||
ON DUPLICATE KEY UPDATE name=VALUES(name), display_name=VALUES(display_name), description=VALUES(description), tool_type=VALUES(tool_type), bean_name=VALUES(bean_name), icon=VALUES(icon), enabled=VALUES(enabled), builtin=VALUES(builtin), update_time=VALUES(update_time), deleted=VALUES(deleted);
|
||||
|
||||
-- Built-in tool: Agent Delegation (Multi-Agent Collaboration)
|
||||
INSERT INTO mate_tool (id, name, display_name, description, tool_type, bean_name, icon, enabled, builtin, create_time, update_time, deleted)
|
||||
VALUES (1000000014, 'DelegateAgentTool', 'Agent Delegation', 'Delegate tasks to other Agents for multi-agent collaboration. Call target Agent by name, run in isolated session and return result.', 'builtin', 'delegateAgentTool', '🤝', TRUE, TRUE, NOW(), NOW(), 0)
|
||||
ON DUPLICATE KEY UPDATE name=VALUES(name), display_name=VALUES(display_name), description=VALUES(description), tool_type=VALUES(tool_type), bean_name=VALUES(bean_name), icon=VALUES(icon), enabled=VALUES(enabled), builtin=VALUES(builtin), update_time=VALUES(update_time), deleted=VALUES(deleted);
|
||||
|
||||
-- Example MCP Server: Filesystem (see MateClaw docs mcpServers.filesystem)
|
||||
INSERT INTO mate_mcp_server (id, name, description, transport, url, headers_json, command, args_json, env_json, cwd,
|
||||
enabled, connect_timeout_seconds, read_timeout_seconds, last_status, last_error,
|
||||
|
||||
@ -331,6 +331,11 @@ INSERT INTO mate_tool (id, name, display_name, description, tool_type, bean_name
|
||||
VALUES (1000000013, 'MateClawDocTool', 'MateClaw 文档', '读取 MateClaw 内置项目文档。action=list 列出所有文档,action=read 读取指定文档内容(如 zh/config.md)。', 'builtin', 'mateClawDocTool', '📚', TRUE, TRUE, NOW(), NOW(), 0)
|
||||
ON DUPLICATE KEY UPDATE name=VALUES(name), display_name=VALUES(display_name), description=VALUES(description), tool_type=VALUES(tool_type), bean_name=VALUES(bean_name), icon=VALUES(icon), enabled=VALUES(enabled), builtin=VALUES(builtin), update_time=VALUES(update_time), deleted=VALUES(deleted);
|
||||
|
||||
-- 内置工具:Agent 委派(多 Agent 协作)
|
||||
INSERT INTO mate_tool (id, name, display_name, description, tool_type, bean_name, icon, enabled, builtin, create_time, update_time, deleted)
|
||||
VALUES (1000000014, 'DelegateAgentTool', 'Agent 委派', '委派任务给其他 Agent 执行,实现多 Agent 协作。支持按名称调用目标 Agent,在独立会话中运行并返回结果。', 'builtin', 'delegateAgentTool', '🤝', TRUE, TRUE, NOW(), NOW(), 0)
|
||||
ON DUPLICATE KEY UPDATE name=VALUES(name), display_name=VALUES(display_name), description=VALUES(description), tool_type=VALUES(tool_type), bean_name=VALUES(bean_name), icon=VALUES(icon), enabled=VALUES(enabled), builtin=VALUES(builtin), update_time=VALUES(update_time), deleted=VALUES(deleted);
|
||||
|
||||
-- 示例 MCP Server:Filesystem(参考 MateClaw 文档中的 mcpServers.filesystem)
|
||||
INSERT INTO mate_mcp_server (
|
||||
id, name, description, transport, url, headers_json, command, args_json, env_json, cwd,
|
||||
|
||||
@ -329,6 +329,11 @@ MERGE INTO mate_tool (id, name, display_name, description, tool_type, bean_name,
|
||||
KEY (id)
|
||||
VALUES (1000000013, 'MateClawDocTool', 'MateClaw 文档', '读取 MateClaw 内置项目文档。action=list 列出所有文档,action=read 读取指定文档内容(如 zh/config.md)。', 'builtin', 'mateClawDocTool', '📚', TRUE, TRUE, NOW(), NOW(), 0);
|
||||
|
||||
-- 内置工具:Agent 委派(多 Agent 协作)
|
||||
MERGE INTO mate_tool (id, name, display_name, description, tool_type, bean_name, icon, enabled, builtin, create_time, update_time, deleted)
|
||||
KEY (id)
|
||||
VALUES (1000000014, 'DelegateAgentTool', 'Agent 委派', '委派任务给其他 Agent 执行,实现多 Agent 协作。支持按名称调用目标 Agent,在独立会话中运行并返回结果。', 'builtin', 'delegateAgentTool', '🤝', TRUE, TRUE, NOW(), NOW(), 0);
|
||||
|
||||
-- 示例 MCP Server:Filesystem(参考 MateClaw 文档中的 mcpServers.filesystem)
|
||||
MERGE INTO mate_mcp_server (
|
||||
id, name, description, transport, url, headers_json, command, args_json, env_json, cwd,
|
||||
|
||||
@ -45,3 +45,7 @@ ON DUPLICATE KEY UPDATE name=VALUES(name), display_name=VALUES(display_name), de
|
||||
INSERT INTO mate_tool (id, name, display_name, description, tool_type, bean_name, icon, enabled, builtin, create_time, update_time, deleted)
|
||||
VALUES (1000000011, 'WorkspaceMemoryTool', '工作区记忆', '读写数据库中的工作区 Markdown 文档,用于维护 PROFILE.md、MEMORY.md 和 memory/YYYY-MM-DD.md 等持久记忆。', 'builtin', 'workspaceMemoryTool', '🧠', TRUE, TRUE, NOW(), NOW(), 0)
|
||||
ON DUPLICATE KEY UPDATE name=VALUES(name), display_name=VALUES(display_name), description=VALUES(description), tool_type=VALUES(tool_type), bean_name=VALUES(bean_name), icon=VALUES(icon), builtin=VALUES(builtin), update_time=NOW();
|
||||
|
||||
INSERT INTO mate_tool (id, name, display_name, description, tool_type, bean_name, icon, enabled, builtin, create_time, update_time, deleted)
|
||||
VALUES (1000000014, 'DelegateAgentTool', 'Agent 委派', '委派任务给其他 Agent 执行,实现多 Agent 协作。支持按名称调用目标 Agent,在独立会话中运行并返回结果。', 'builtin', 'delegateAgentTool', '🤝', TRUE, TRUE, NOW(), NOW(), 0)
|
||||
ON DUPLICATE KEY UPDATE name=VALUES(name), display_name=VALUES(display_name), description=VALUES(description), tool_type=VALUES(tool_type), bean_name=VALUES(bean_name), icon=VALUES(icon), builtin=VALUES(builtin), update_time=NOW();
|
||||
|
||||
@ -48,3 +48,7 @@ VALUES (1000000010, 'DocumentExtractTool', '文档文本提取', '从 PDF、Word
|
||||
MERGE INTO mate_tool (id, name, display_name, description, tool_type, bean_name, icon, enabled, builtin, create_time, update_time, deleted)
|
||||
KEY (id)
|
||||
VALUES (1000000011, 'WorkspaceMemoryTool', '工作区记忆', '读写数据库中的工作区 Markdown 文档,用于维护 PROFILE.md、MEMORY.md 和 memory/YYYY-MM-DD.md 等持久记忆。', 'builtin', 'workspaceMemoryTool', '🧠', TRUE, TRUE, NOW(), NOW(), 0);
|
||||
|
||||
MERGE INTO mate_tool (id, name, display_name, description, tool_type, bean_name, icon, enabled, builtin, create_time, update_time, deleted)
|
||||
KEY (id)
|
||||
VALUES (1000000014, 'DelegateAgentTool', 'Agent 委派', '委派任务给其他 Agent 执行,实现多 Agent 协作。支持按名称调用目标 Agent,在独立会话中运行并返回结果。', 'builtin', 'delegateAgentTool', '🤝', TRUE, TRUE, NOW(), NOW(), 0);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user