每次都要主 Agent 分配任务太累。
所以引入了自主智能体的概念,使智能体能够:
- 工作-空闲循环:智能体在工作完成时自动进入空闲状态
- 任务自动认领:空闲时扫描任务板,自动认领无人认领的任务
- 身份重新注入:在上下文压缩后重新注入智能体身份信息
- 自动资源管理:空闲超时自动关机,释放资源
关键洞察:扫描看板,认领任务。队友自己扫描任务板并认领任务,无需主 Agent 逐个分配。
Java实现代码
java
public class AutonomousAgentsSystem {
// --- 新增配置 ---
private static final Path TASKS_DIR = WORKDIR.resolve(".tasks"); // 任务存储目录
private static final int POLL_INTERVAL = 5; // 空闲轮询间隔(秒)
private static final int IDLE_TIMEOUT = 60; // 空闲超时(秒)
private static final Object claimLock = new Object(); // 任务认领锁
// --- 新增:任务板扫描 ---
/**
* 扫描无人认领的任务
*/
private static List<Map<String, Object>> scanUnclaimedTasks() {
try {
Files.createDirectories(TASKS_DIR);
List<Map<String, Object>> unclaimed = new ArrayList<>();
Files.list(TASKS_DIR)
.filter(p -> p.getFileName().toString().startsWith("task_"))
.filter(p -> p.getFileName().toString().endsWith(".json"))
.sorted()
.forEach(p -> {
try {
String content = Files.readString(p);
Type type = new TypeToken<Map<String, Object>>(){}.getType();
Map<String, Object> task = gson.fromJson(content, type);
// 检查是否可认领
String status = (String) task.get("status");
String owner = (String) task.get("owner");
@SuppressWarnings("unchecked")
List<Integer> blockedBy = (List<Integer>) task.get("blockedBy");
if ("pending".equals(status) &&
(owner == null || owner.isEmpty()) &&
(blockedBy == null || blockedBy.isEmpty())) {
unclaimed.add(task);
}
// 可认领条件:状态为pending、无所有者、无阻塞依赖
// 有序扫描:按文件名排序,确保公平性
} catch (IOException e) {
// 忽略读取错误
}
});
return unclaimed;
} catch (IOException e) {
return new ArrayList<>();
}
}
/**
* 认领任务
*/
private static String claimTask(int taskId, String owner) {
synchronized (claimLock) { // 同步锁防止并发认领
Path taskPath = TASKS_DIR.resolve("task_" + taskId + ".json");
if (!Files.exists(taskPath)) {
return "Error: Task " + taskId + " not found";
}
try {
String content = Files.readString(taskPath);
Type type = new TypeToken<Map<String, Object>>(){}.getType();
Map<String, Object> task = gson.fromJson(content, type);
// 更新任务信息
task.put("owner", owner);
task.put("status", "in_progress");
// 原子性更新:确保任务不会被多个智能体同时认领
// 状态转换:pending → in_progress
Files.writeString(taskPath, gson.toJson(task));
return String.format("Claimed task #%d for %s", taskId, owner);
} catch (IOException e) {
return "Error: " + e.getMessage();
}
}
}
// --- 新增:身份重新注入 ---
/**
* 创建身份块(用于上下文压缩后重新注入身份)
*/
private static Map<String, Object> makeIdentityBlock(String name, String role, String teamName) {
return Map.of(
"role", "user",
"content", String.format(
"<identity>You are '%s', role: %s, team: %s. Continue your work.</identity>",
name, role, teamName
)
);
// 身份持久化:即使上下文被压缩,也能重新注入身份
// 结构化标记:<identity>标签明确标识身份信息
}
// --- 新增:团队成员工具 ---
private String executeTeammateTool(String sender, String toolName, Map<String, Object> args) {
try {
switch (toolName) {
// ... 原有的工具处理 ...
case "idle":
// idle 工具在工作循环中特殊处理
return "Entering idle phase. Will poll for new tasks.";
// 主动空闲:智能体主动表示完成当前工作
case "claim_task":
int taskId = ((Number) args.get("task_id")).intValue();
return claimTask(taskId, sender);
// 主动认领:智能体主动认领指定任务
}
} catch (Exception e) {
return "Error: " + e.getMessage();
}
}
// --- 新增:团队成员工具定义 ---
private List<Map<String, Object>> getTeammateTools() {
List<Map<String, Object>> tools = new ArrayList<>();
// 新增 idle 工具
tools.add(createToolSpec("idle",
"Signal that you have no more work. Enters idle polling phase.",
Map.of(),
List.of()));
// 无参数工具:简单的状态转换工具
// 新增 claim_task 工具
tools.add(createToolSpec("claim_task",
"Claim a task from the task board by ID.",
Map.of("task_id", Map.of("type", "integer")),
List.of("task_id")));
// 主动工作:智能体可以主动选择任务
return tools;
}
// --- 新增:团队成员主循环(工作-空闲循环)---
private void teammateLoop(String name, String role, String prompt, AtomicBoolean stopFlag) {
@SuppressWarnings("unchecked")
String teamName = (String) TEAM_MANAGER.config.get("team_name");
String systemPrompt = String.format(
"You are '%s', role: %s, team: %s, at %s. " +
"Use idle tool when you have no more work. You will auto-claim new tasks.",
name, role, teamName, WORKDIR
);
// 增强系统提示:包含空闲行为和自动认领机制
List<Map<String, Object>> messages = new ArrayList<>();
messages.add(Map.of("role", "user", "content", prompt));
while (!stopFlag.get()) { // 外层循环支持工作-空闲循环
// --- 工作阶段 ---
TEAM_MANAGER.setStatus(name, "working");
boolean completedWorkPhase = false;
for (int i = 0; i < 50 && !stopFlag.get(); i++) {
try {
// ... 检查邮箱、调用LLM、执行工具等逻辑 ...
boolean idleRequested = false;
for (Map<String, Object> block : content) {
if ("tool_use".equals(block.get("type"))) {
String toolName = (String) block.get("name");
if ("idle".equals(toolName)) {
idleRequested = true; // 标记空闲请求
break;
}
}
}
if (idleRequested) {
completedWorkPhase = true;
break; // 退出工作阶段,进入空闲阶段
}
} catch (Exception e) {
System.err.printf("[%s] Error: %s%n", name, e.getMessage());
break;
}
}
if (!completedWorkPhase) {
// 没有明确进入空闲,可能是因为错误
TEAM_MANAGER.setStatus(name, "idle");
return;
}
// --- 空闲阶段 ---
TEAM_MANAGER.setStatus(name, "idle");
boolean resume = false;
int maxPolls = IDLE_TIMEOUT / Math.max(POLL_INTERVAL, 1);
for (int pollCount = 0; pollCount < maxPolls && !stopFlag.get(); pollCount++) {
try {
Thread.sleep(POLL_INTERVAL * 1000L); // 周期性轮询
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
break;
}
// 检查邮箱
List<Map<String, Object>> inbox = BUS.readInbox(name);
if (!inbox.isEmpty()) {
for (Map<String, Object> msg : inbox) {
if ("shutdown_request".equals(msg.get("type"))) {
TEAM_MANAGER.setStatus(name, "shutdown");
return;
}
messages.add(Map.of("role", "user", "content", gson.toJson(msg)));
}
resume = true; // 有消息,恢复工作
break;
}
// 扫描无人认领的任务
List<Map<String, Object>> unclaimed = scanUnclaimedTasks();
if (!unclaimed.isEmpty()) {
Map<String, Object> task = unclaimed.get(0);
int taskId = ((Number) task.get("id")).intValue();
// 自动认领任务
claimTask(taskId, name);
// 创建任务提示
String taskSubject = (String) task.get("subject");
String taskDesc = (String) task.get("description");
if (taskDesc == null) taskDesc = "";
String taskPrompt = String.format(
"<auto-claimed>Task #%d: %s%n%s</auto-claimed>",
taskId, taskSubject, taskDesc
);
// 如果消息历史太短,重新注入身份
if (messages.size() <= 3) {
messages.add(0, makeIdentityBlock(name, role, teamName));
messages.add(1, Map.of("role", "assistant",
"content", "I am " + name + ". Continuing."));
// 身份恢复:确保智能体知道自己的身份
}
messages.add(Map.of("role", "user", "content", taskPrompt));
messages.add(Map.of("role", "assistant",
"content", "Claimed task #" + taskId + ". Working on it."));
// 自动对话:模拟智能体认领任务并开始工作
resume = true; // 有任务,恢复工作
break;
}
}
if (!resume) {
// 空闲超时,自动关机
TEAM_MANAGER.setStatus(name, "shutdown");
return;
}
// 重新进入工作阶段
}
}
// --- 新增:主程序的特殊命令 ---
public static void main(String[] args) {
// ... 初始化代码 ...
while (true) {
System.out.print("\n\033[36ms11 >> \033[0m");
String userInput = scanner.nextLine().trim();
if (userInput.isEmpty() || "exit".equalsIgnoreCase(userInput) ||
"q".equalsIgnoreCase(userInput)) {
break;
}
// 特殊命令
if ("/team".equals(userInput)) {
System.out.println("\n" + TEAM_MANAGER.listAll());
continue;
}
if ("/inbox".equals(userInput)) {
List<Map<String, Object>> inbox = BUS.readInbox("lead");
if (inbox.isEmpty()) {
System.out.println("\nLeader's inbox is empty.");
} else {
System.out.println("\nLeader's inbox:");
System.out.println(gson.toJson(inbox));
}
continue;
}
if ("/tasks".equals(userInput)) {
try {
Files.createDirectories(TASKS_DIR);
Files.list(TASKS_DIR)
.filter(p -> p.getFileName().toString().startsWith("task_"))
.filter(p -> p.getFileName().toString().endsWith(".json"))
.sorted()
.forEach(p -> {
try {
String content = Files.readString(p);
Type type = new TypeToken<Map<String, Object>>(){}.getType();
Map<String, Object> task = gson.fromJson(content, type);
String status = (String) task.get("status");
String marker = switch(status) {
case "pending" -> "[ ]";
case "in_progress" -> "[>]";
case "completed" -> "[x]";
default -> "[?]";
};
int id = ((Number) task.get("id")).intValue();
String subject = (String) task.get("subject");
String owner = (String) task.get("owner");
String ownerStr = (owner != null && !owner.isEmpty()) ?
" @" + owner : "";
System.out.printf(" %s #%d: %s%s%n", marker, id, subject, ownerStr);
// 可视化任务板:清晰显示任务状态和所有者
} catch (IOException e) {
// 忽略错误
}
});
} catch (IOException e) {
System.out.println("Error reading tasks: " + e.getMessage());
}
continue;
}
// ... 正常处理用户输入 ...
}
}
}
自主性架构:工作-空闲循环
核心思想 :从被动响应式智能体升级为主动、自驱动、可持续运行的自主智能体 ,引入工作-空闲循环机制 ,让智能体能够自主管理自己的工作生命周期,实现"无人值守"的持续运行。
java
// 自主运行参数配置
private static final int POLL_INTERVAL = 5; // 空闲轮询间隔(秒)
private static final int IDLE_TIMEOUT = 60; // 空闲超时(秒)
// 智能调度:5秒轮询平衡响应性和资源消耗
// 自动清理:60秒无工作自动关机,释放资源
// 可持续运行:支持长时间无人值守运行
- 状态机演进:从简单的working/idle状态升级为完整的工作-空闲循环
- 自主调度:智能体自己决定何时工作、何时空闲
- 资源优化:空闲时降低资源消耗,有工作时快速响应
- 可持续性:支持7x24小时持续运行
任务板系统与自动认领
java
/**
* 扫描无人认领的任务
*/
private static List<Map<String, Object>> scanUnclaimedTasks() {
List<Map<String, Object>> unclaimed = new ArrayList<>();
Files.list(TASKS_DIR)
.filter(p -> p.getFileName().toString().startsWith("task_"))
.filter(p -> p.getFileName().toString().endsWith(".json"))
.sorted() // 公平性:按ID顺序扫描
.forEach(p -> {
Map<String, Object> task = gson.fromJson(content, type);
String status = (String) task.get("status");
String owner = (String) task.get("owner");
@SuppressWarnings("unchecked")
List<Integer> blockedBy = (List<Integer>) task.get("blockedBy");
if ("pending".equals(status) &&
(owner == null || owner.isEmpty()) &&
(blockedBy == null || blockedBy.isEmpty())) {
unclaimed.add(task);
}
// 智能筛选:只扫描可执行的任务
// 无阻塞:不认领有依赖阻塞的任务
// 无所有者:不认领已有所有者的任务
});
}
- 任务市场:任务板作为智能体间的任务协调机制
- 公平竞争:所有智能体平等扫描和认领任务
- 依赖感知:自动识别有依赖阻塞的任务
- 负载均衡:空闲智能体自动认领任务,实现自动负载均衡
原子性任务认领机制
java
/**
* 认领任务
*/
private static String claimTask(int taskId, String owner) {
synchronized (claimLock) { // 关键:同步锁防止并发认领
Path taskPath = TASKS_DIR.resolve("task_" + taskId + ".json");
String content = Files.readString(taskPath);
Map<String, Object> task = gson.fromJson(content, type);
// 更新任务信息
task.put("owner", owner);
task.put("status", "in_progress");
// 原子性操作:防止多个智能体同时认领同一个任务
// 状态转换:确保pending → in_progress的原子性
Files.writeString(taskPath, gson.toJson(task));
return String.format("Claimed task #%d for %s", taskId, owner);
}
}
- 并发安全:同步锁确保多智能体环境下的数据一致性
- 原子操作:读取-修改-写入的原子性,防止竞态条件
- 状态管理:明确的任务状态生命周期管理
- 所有者标记:明确任务归属,避免重复工作
主动空闲工具与状态转换
java
// idle 工具定义
tools.add(createToolSpec("idle",
"Signal that you have no more work. Enters idle polling phase.",
Map.of(),
List.of()));
// 主动决策:智能体主动决定进入空闲状态
// 语义清晰:工具名明确表示行为
// 无参数:简单的状态转换工具
// 在teammateLoop中处理idle
boolean idleRequested = false;
for (Map<String, Object> block : content) {
if ("tool_use".equals(block.get("type"))) {
String toolName = (String) block.get("name");
if ("idle".equals(toolName)) {
idleRequested = true; // 标记空闲请求
break;
}
}
}
if (idleRequested) {
completedWorkPhase = true;
break; // 退出工作阶段,进入空闲阶段
}
// 工作完成检测:智能体主动表示工作完成
// 状态转换:从working状态转换到idle状态
// 控制权转移:智能体自主控制工作节奏
- 主动决策:智能体可以主动决定何时完成工作
- 状态管理:明确的工作-空闲状态转换
- 资源优化:完成工作后主动释放计算资源
- 可预测性:明确的工作完成信号
周期性轮询与自动发现
java
// --- 空闲阶段 ---
TEAM_MANAGER.setStatus(name, "idle");
boolean resume = false;
int maxPolls = IDLE_TIMEOUT / Math.max(POLL_INTERVAL, 1);
for (int pollCount = 0; pollCount < maxPolls && !stopFlag.get(); pollCount++) {
try {
Thread.sleep(POLL_INTERVAL * 1000L); // 周期性轮询
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
break;
}
// 检查邮箱
List<Map<String, Object>> inbox = BUS.readInbox(name);
if (!inbox.isEmpty()) {
// 有消息,恢复工作
resume = true;
break;
}
// 扫描无人认领的任务
List<Map<String, Object>> unclaimed = scanUnclaimedTasks();
if (!unclaimed.isEmpty()) {
// 自动认领并恢复工作
resume = true;
break;
}
}
// 周期性检查:定期检查新工作
// 多源触发:邮箱消息或任务板都可以触发恢复工作
// 超时机制:长时间无工作自动关机
- 事件驱动:邮箱消息和任务板任务都是触发事件
- 资源节约:轮询间隔避免CPU过度消耗
- 多源响应:响应多种类型的工作触发
- 自动恢复:发现工作后自动恢复工作状态
自动任务认领与上下文重建
java
// 自动认领任务
claimTask(taskId, name);
// 创建任务提示
String taskPrompt = String.format(
"<auto-claimed>Task #%d: %s%n%s</auto-claimed>",
taskId, taskSubject, taskDesc
);
// 如果消息历史太短,重新注入身份
if (messages.size() <= 3) {
messages.add(0, makeIdentityBlock(name, role, teamName));
messages.add(1, Map.of("role", "assistant",
"content", "I am " + name + ". Continuing."));
// 身份恢复:确保智能体在长时间空闲后仍然知道自己的身份
// 上下文重建:重建被压缩的上下文
}
messages.add(Map.of("role", "user", "content", taskPrompt));
messages.add(Map.of("role", "assistant",
"content", "Claimed task #" + taskId + ". Working on it."));
// 自动对话:模拟智能体认领任务并开始工作
// 工作流保持:保持对话的自然流畅
- 自动接单:智能体自动认领并开始处理任务
- 身份持久:即使上下文被压缩,也能重建身份
- 工作流连续:保持工作对话的自然连续性
- 自动初始化:为新任务自动初始化工作上下文
命令行管理与可视化监控
java
// 特殊命令
if ("/team".equals(userInput)) {
System.out.println("\n" + TEAM_MANAGER.listAll());
continue;
}
if ("/inbox".equals(userInput)) {
// 查看邮箱
continue;
}
if ("/tasks".equals(userInput)) {
// 可视化任务板
System.out.printf(" %s #%d: %s%s%n", marker, id, subject, ownerStr);
continue;
}
// 运维友好:提供方便的管理命令
// 实时监控:随时查看团队状态和任务进度
// 可视化:清晰的图表化展示
// 调试支持:便于问题诊断和系统监控
- 运维界面:为人类管理员提供方便的管理接口
- 实时监控:随时掌握系统运行状态
- 可视化:直观的任务状态展示
- 调试支持:便于问题定位和系统优化
架构演进与价值
从 TeamProtocolsSystem 到 AutonomousAgentsSystem 的升级:
| 维度 | TeamProtocolsSystem | AutonomousAgentsSystem |
|---|---|---|
| 运行模式 | 被动响应 | 主动自主 |
| 工作调度 | 人工分配 | 自动认领 |
| 生命周期 | 单次运行 | 持续循环 |
| 资源管理 | 静态分配 | 动态优化 |
| 人机交互 | 频繁交互 | 无人值守 |