惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Security Archives - TechRepublic
Security Archives - TechRepublic
Project Zero
Project Zero
K
Kaspersky official blog
G
Google Developers Blog
T
Threat Research - Cisco Blogs
T
The Blog of Author Tim Ferriss
Cyberwarzone
Cyberwarzone
Y
Y Combinator Blog
Recorded Future
Recorded Future
Blog — PlanetScale
Blog — PlanetScale
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
Cisco Talos Blog
Cisco Talos Blog
Latest news
Latest news
Microsoft Security Blog
Microsoft Security Blog
H
Help Net Security
S
Schneier on Security
P
Palo Alto Networks Blog
H
Hacker News: Front Page
N
News and Events Feed by Topic
N
Netflix TechBlog - Medium
博客园 - Franky
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
SecWiki News
SecWiki News
Cloudbric
Cloudbric
TaoSecurity Blog
TaoSecurity Blog
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
The Hacker News
The Hacker News
C
Check Point Blog
L
LangChain Blog
腾讯CDC
小众软件
小众软件
T
Tenable Blog
Google DeepMind News
Google DeepMind News
GbyAI
GbyAI
L
LINUX DO - 最新话题
A
About on SuperTechFans
Google Online Security Blog
Google Online Security Blog
C
Cisco Blogs
Recent Announcements
Recent Announcements
Hacker News: Ask HN
Hacker News: Ask HN
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Vercel News
Vercel News
雷峰网
雷峰网
美团技术团队
D
DataBreaches.Net
Martin Fowler
Martin Fowler
Help Net Security
Help Net Security
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
F
Full Disclosure
博客园_首页

博客园_首页

Linux实操--组管理、权限管理和定时任务 Java + EasyExcel 实现单个接口导出多个Excel Mem0 源码解析系列(二):提示词工程的深度剖析 Openclaw TaskFlow究竟是什么?和普通Skill技能有什么区别 博文阅读密码验证 - 博客园 嘉立创开源:应该是全网MicroPython教程最多的开发板 Hermes Agent 集成实践:从协议到生产 2026年AI编程工具横评:Cursor、Codex、Claude Code、Zed、Windsurf Java程序员必看的RAG入门教程 2026 AI效率神器:Superpowers + Claude Code 保姆级教程 本地大模型部署全攻略:从 0 到 1 玩转 Ollama 【从0到1构建一个ClaudeAgent】内存管理-上下文压缩 .NET 高级开发 | 设计、实现一个事件总线框架 电子小白入门之NE555 3. WorkBuddy:隐藏玩法,一键召唤专家,让 AI 以"专家身份"给你干活 和AI一起搞事情#3:Claude Teammate 游戏开发翻车实录 【OpenClaw】通过 Nanobot 源码学习架构---(7)Memory C# .NET 周刊|2026年3月3期 我在 Debian 11 上把 K8s 单机搭起来了,过程没你想的那么顺(/opt 目录版) 深度学习进阶(七)Data-efficient Image Transformer CLI+Skill搭建浏览器AI自动化框架,告别一切重复枯燥任务 告别Token账单无底洞:OpenClaw本地部署,重塑企业数据主权的唯一解 FastAPI+Vue:文件分片上传+秒传+断点续传,这坑我帮你踩平了! SBTI 爆火后,我做了个程序员版的 CBTI。。已开源 + 附开发过程 多模态检索开始进入工程期:用 Sentence Transformers 搭建可落地的 Multimodal RAG 100多行代码实现一个最简单的Agent(用ReAct) Claude Code 通关手册(八):推荐 5 个 Hooks,代码质量提升 3 倍 老板:“有人截图了!”。安全部门:“收到,马上查暗水印!” - why技术 技术之外,皆是人间 C#/.NET/.NET Core技术前沿周刊 | 第 69 期(2026年4.01-4.12) Snack JSONPath 项目架构分析 Claude Code Buddy 小析:一个非核心功能,如何体现产品的细节完成度 AI新时代下的图床管理方案-Cloudflare图床+MCP+Skills方案指南 化繁为简:顺丰速运App如何通过 HarmonyOS SDK实现专业级空间测量 从零实现富文本编辑器#13-React非编辑节点的内容渲染 AI开发-python-langchain框架(3-23-OpenAI Functions风格Tool Calling智能助手) .NET + AI 进阶实战:基于类的技能开发 - 打造可治理的 Agent 能力模块 【从0到1构建一个ClaudeAgent】规划与协调-技能 上周热点回顾(4.6-4.12) 电子小白的工具三件套:面包板、杜邦线、万能板 单表五亿数据的查询优化 | Mysql、StarRocks 2. WorkBuddy:从“我是谁”到“帮我干活” C# 如何减少代码运行时间:7 个实战技巧 基于HelixToolkit.SharpDX 渲染3D模型 - 笺上知微 从零开始的双臂具身VLA起源及现阶段发展综述 - SkyXZ 记对 xonsh shell 的使用, 脚本编写, 迁移及调优 - pluvium27 受够了Vibe Coding的失控?换个起点,让AI事半功倍 从开始配置漏洞环境到漏洞复现流程 - 難しい 关于10年工作经验的程序员对OpenClaw的实战经验分享以及看法 - 虚无境 Any metadata 的内存布局 C# .NET 周刊|2026年3月2期 - InCerry 我帮你测过了,测试圈排名第二的 Skill 依然很牛逼 Skill Discovery | 无监督技能发现的经典工作总结 - MoonOut PbootCMS 网站内容数量多导致访问慢?这些实用优化方案帮你提速! - 家兴网络技术工作室 上下文工程是什么?过时了么?一文讲明白! - 一枫说码 网站漏洞怎么发现并修复?一篇实用指南(附完整流程) - 家兴网络技术工作室 开了 TUN 模式还是直连?90% 的人都踩过这个坑 Github日报|2026年04月12日 - AI一族 AScript扩展多种脚本语言 - rockey627 AI 学习笔记:Agent 的记忆机制 你能被装进一个文件里吗?——7 万人把同事"蒸馏"成了 AI - 我没有三颗心脏 Claude Code 通关手册(七):给 AI 装上技能包——Skills 完全指南 - 暮色之狐 在浏览器中快速编辑代码:VSCode Web 集成实践 - Newbe36524 蒸馏自己 skill?基于 Deepseek 的蒸馏器,丐版蒸馏方式,简单便捷 - To_Carpe_Diem Spring AI Aliababa和AgentScope,哪个更好? - 苏三说技术 Etsy 把 1000 个 MySQL 分片迁进 Vitess:425TB 数据背后的真正问题不是性能,而是运维规模 MicroPython LVGL基础知识和概念:底层渲染与性能优化 - FreakStudio 数据库草图算法 Python 潮流周刊#146:CPython 引入 Rust 的进展 - 豌豆花下猫 最小生成树 - mofei1116 红日靶场七:从外网入口、容器逃逸到 AD 接管的完整利用链复盘 - YouDiscovered1t 分享四款开源且实用的 Kafka 管理工具 - 追逐时光者 vLLM 权重加载机制全解析:从挑战到理想架构 LCT 学习笔记 - ACehomoxue Avalonia UI 12.0.0 正式发布:架构演进和性能飞跃 - 张善友 当 AI Agent 把调用链拉长,延迟开始成为一门生意 conhost.exe 无法显示 U+2717 - 145a 太秀了,我把自己蒸馏成了 Skill!已开源 - 程序员鱼皮 ASP.NET Core 内存缓存实战:一篇搞懂该怎么配、怎么避坑 基于 Ghostty 带有分割标签页和为 Claude 编程设计的通知终端 - BugShare AI 焊死入口:教育的“操作系统级”重塑 - 郝hai 初级Java开发工程师使用sql脚本编写代码的过程是简单而且不糊涂 - CoderOilStation Claude Code通关手册(六):MCP协议完全指南 - 暮色之狐 边框灯光环绕动画特效实现指南 - Newbe36524 开源:子木蒸馏版的 SEO 审计工具 seo-audit-skill v1.0 我所理解的Python元模型 【从0到1构建一个ClaudeAgent】规划与协调-TodoWrite - 程序员Seven Claude 和 Codex 在审计 Skill 上性能差异探究 - ACai_sec AScript如何实现中文脚本引擎 - rockey627 【渗透测试】HTB Season10 Garfield 全过程wp - dynasty_chenzi Android 开发者为什么必须掌握 AI 能力?端侧视角下的技术变革 树状数组正确性证明 - AC-wyr 你的 AI 焦虑,可能比 AI 本身更危险——ATM 机没有消灭银行柜员,但恐慌消灭了你的判断力 - 我没有三颗心脏 一个拉胯的分库分表方案有多绝望?整个部门都在救火! - 冰河团队 动态规划入门必学之走方格问题 - Ofnoname PostgREST 与 PostgreSQL 角色权限配置全解析(生产级实践) - SheepDog1998 使用 UEFI 图形输出协议 GOP 在屏幕上显示图像的方法 - 阿源- Claude Code通关手册(五):组建你的AI专家团队,子代理系统 - 暮色之狐 一个程序员到架构师的催婚路之感悟(整整10年后的催婚相亲感悟) - MisterLip 用 Agent Skill 自动生成工作周报 - 赵康
【从0到1构建一个ClaudeAgent】协作-自主Agent
程序员Seven · 2026-04-19 · via 博客园_首页

每次都要主 Agent 分配任务太累。

所以引入了自主智能体的概念,使智能体能够:

  1. 工作-空闲循环:智能体在工作完成时自动进入空闲状态
  2. 任务自动认领:空闲时扫描任务板,自动认领无人认领的任务
  3. 身份重新注入:在上下文压缩后重新注入智能体身份信息
  4. 自动资源管理:空闲超时自动关机,释放资源

关键洞察:扫描看板,认领任务。队友自己扫描任务板并认领任务,无需主 Agent 逐个分配。

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;
            }
            
            // ... 正常处理用户输入 ...
        }
    }
}

自主性架构:工作-空闲循环

核心思想:从被动响应式智能体升级为主动、自驱动、可持续运行的自主智能体,引入工作-空闲循环机制,让智能体能够自主管理自己的工作生命周期,实现"无人值守"的持续运行。

// 自主运行参数配置
private static final int POLL_INTERVAL = 5;      // 空闲轮询间隔(秒)
private static final int IDLE_TIMEOUT = 60;      // 空闲超时(秒)
// 智能调度:5秒轮询平衡响应性和资源消耗
// 自动清理:60秒无工作自动关机,释放资源
// 可持续运行:支持长时间无人值守运行
  • 状态机演进:从简单的working/idle状态升级为完整的工作-空闲循环
  • 自主调度:智能体自己决定何时工作、何时空闲
  • 资源优化:空闲时降低资源消耗,有工作时快速响应
  • 可持续性:支持7x24小时持续运行

任务板系统与自动认领

/**
 * 扫描无人认领的任务
 */
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);
            }
            // 智能筛选:只扫描可执行的任务
            // 无阻塞:不认领有依赖阻塞的任务
            // 无所有者:不认领已有所有者的任务
        });
}
  • 任务市场:任务板作为智能体间的任务协调机制
  • 公平竞争:所有智能体平等扫描和认领任务
  • 依赖感知:自动识别有依赖阻塞的任务
  • 负载均衡:空闲智能体自动认领任务,实现自动负载均衡

原子性任务认领机制

/**
 * 认领任务
 */
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);
    }
}
  • 并发安全:同步锁确保多智能体环境下的数据一致性
  • 原子操作:读取-修改-写入的原子性,防止竞态条件
  • 状态管理:明确的任务状态生命周期管理
  • 所有者标记:明确任务归属,避免重复工作

主动空闲工具与状态转换

// 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状态
// 控制权转移:智能体自主控制工作节奏
  • 主动决策:智能体可以主动决定何时完成工作
  • 状态管理:明确的工作-空闲状态转换
  • 资源优化:完成工作后主动释放计算资源
  • 可预测性:明确的工作完成信号

周期性轮询与自动发现

// --- 空闲阶段 ---
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过度消耗
  • 多源响应:响应多种类型的工作触发
  • 自动恢复:发现工作后自动恢复工作状态

自动任务认领与上下文重建

// 自动认领任务
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."));
// 自动对话:模拟智能体认领任务并开始工作
// 工作流保持:保持对话的自然流畅
  • 自动接单:智能体自动认领并开始处理任务
  • 身份持久:即使上下文被压缩,也能重建身份
  • 工作流连续:保持工作对话的自然连续性
  • 自动初始化:为新任务自动初始化工作上下文

命令行管理与可视化监控

// 特殊命令
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