是不一样的 發表於 2026-4-19 09:00:00

【从0到1构建一个ClaudeAgent】协作-自主Agent

<p>每次都要主 Agent 分配任务太累。</p>
<p>所以引入了<strong>自主智能体</strong>的概念,使智能体能够:</p>
<ol>
<li><strong>工作-空闲循环</strong>:智能体在工作完成时自动进入空闲状态</li>
<li><strong>任务自动认领</strong>:空闲时扫描任务板,自动认领无人认领的任务</li>
<li><strong>身份重新注入</strong>:在上下文压缩后重新注入智能体身份信息</li>
<li><strong>自动资源管理</strong>:空闲超时自动关机,释放资源</li>
</ol>
<p><strong>关键洞察</strong>:扫描看板,认领任务。队友自己扫描任务板并认领任务,无需主 Agent 逐个分配。</p>
<h2 id="java实现代码">Java实现代码</h2>
<pre><code class="language-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&lt;Map&lt;String, Object&gt;&gt; scanUnclaimedTasks() {
      try {
            Files.createDirectories(TASKS_DIR);
            
            List&lt;Map&lt;String, Object&gt;&gt; unclaimed = new ArrayList&lt;&gt;();
            Files.list(TASKS_DIR)
                .filter(p -&gt; p.getFileName().toString().startsWith("task_"))
                .filter(p -&gt; p.getFileName().toString().endsWith(".json"))
                .sorted()
                .forEach(p -&gt; {
                  try {
                        String content = Files.readString(p);
                        Type type = new TypeToken&lt;Map&lt;String, Object&gt;&gt;(){}.getType();
                        Map&lt;String, Object&gt; task = gson.fromJson(content, type);
                        
                        // 检查是否可认领
                        String status = (String) task.get("status");
                        String owner = (String) task.get("owner");
                        @SuppressWarnings("unchecked")
                        List&lt;Integer&gt; blockedBy = (List&lt;Integer&gt;) task.get("blockedBy");
                        
                        if ("pending".equals(status) &amp;&amp;
                            (owner == null || owner.isEmpty()) &amp;&amp;
                            (blockedBy == null || blockedBy.isEmpty())) {
                            unclaimed.add(task);
                        }
                        // 可认领条件:状态为pending、无所有者、无阻塞依赖
                        // 有序扫描:按文件名排序,确保公平性
                  } catch (IOException e) {
                        // 忽略读取错误
                  }
                });
            
            return unclaimed;
      } catch (IOException e) {
            return new ArrayList&lt;&gt;();
      }
    }
   
    /**
   * 认领任务
   */
    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&lt;Map&lt;String, Object&gt;&gt;(){}.getType();
                Map&lt;String, Object&gt; 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&lt;String, Object&gt; makeIdentityBlock(String name, String role, String teamName) {
      return Map.of(
            "role", "user",
            "content", String.format(
                "&lt;identity&gt;You are '%s', role: %s, team: %s. Continue your work.&lt;/identity&gt;",
                name, role, teamName
            )
      );
      // 身份持久化:即使上下文被压缩,也能重新注入身份
      // 结构化标记:&lt;identity&gt;标签明确标识身份信息
    }
   
    // --- 新增:团队成员工具 ---
    private String executeTeammateTool(String sender, String toolName, Map&lt;String, Object&gt; 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&lt;Map&lt;String, Object&gt;&gt; getTeammateTools() {
      List&lt;Map&lt;String, Object&gt;&gt; tools = new ArrayList&lt;&gt;();
      
      // 新增 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&lt;Map&lt;String, Object&gt;&gt; messages = new ArrayList&lt;&gt;();
      messages.add(Map.of("role", "user", "content", prompt));
      
      while (!stopFlag.get()) {// 外层循环支持工作-空闲循环
            // --- 工作阶段 ---
            TEAM_MANAGER.setStatus(name, "working");
            
            boolean completedWorkPhase = false;
            for (int i = 0; i &lt; 50 &amp;&amp; !stopFlag.get(); i++) {
                try {
                  // ... 检查邮箱、调用LLM、执行工具等逻辑 ...
                  
                  boolean idleRequested = false;
                  for (Map&lt;String, Object&gt; 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 &lt; maxPolls &amp;&amp; !stopFlag.get(); pollCount++) {
                try {
                  Thread.sleep(POLL_INTERVAL * 1000L);// 周期性轮询
                } catch (InterruptedException e) {
                  Thread.currentThread().interrupt();
                  break;
                }
               
                // 检查邮箱
                List&lt;Map&lt;String, Object&gt;&gt; inbox = BUS.readInbox(name);
                if (!inbox.isEmpty()) {
                  for (Map&lt;String, Object&gt; 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&lt;Map&lt;String, Object&gt;&gt; unclaimed = scanUnclaimedTasks();
                if (!unclaimed.isEmpty()) {
                  Map&lt;String, Object&gt; 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(
                        "&lt;auto-claimed&gt;Task #%d: %s%n%s&lt;/auto-claimed&gt;",
                        taskId, taskSubject, taskDesc
                  );
                  
                  // 如果消息历史太短,重新注入身份
                  if (messages.size() &lt;= 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 &gt;&gt; \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&lt;Map&lt;String, Object&gt;&gt; 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 -&gt; p.getFileName().toString().startsWith("task_"))
                        .filter(p -&gt; p.getFileName().toString().endsWith(".json"))
                        .sorted()
                        .forEach(p -&gt; {
                            try {
                              String content = Files.readString(p);
                              Type type = new TypeToken&lt;Map&lt;String, Object&gt;&gt;(){}.getType();
                              Map&lt;String, Object&gt; task = gson.fromJson(content, type);
                              
                              String status = (String) task.get("status");
                              String marker = switch(status) {
                                    case "pending" -&gt; "[ ]";
                                    case "in_progress" -&gt; "[&gt;]";
                                    case "completed" -&gt; "";
                                    default -&gt; "[?]";
                              };
                              
                              int id = ((Number) task.get("id")).intValue();
                              String subject = (String) task.get("subject");
                              String owner = (String) task.get("owner");
                              String ownerStr = (owner != null &amp;&amp; !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;
            }
            
            // ... 正常处理用户输入 ...
      }
    }
}
</code></pre>
<h2 id="自主性架构工作-空闲循环">自主性架构:工作-空闲循环</h2>
<p><strong>核心思想</strong>:从被动响应式智能体升级为<strong>主动、自驱动、可持续运行的自主智能体</strong>,引入<strong>工作-空闲循环机制</strong>,让智能体能够<strong>自主管理自己的工作生命周期</strong>,实现"无人值守"的持续运行。</p>
<pre><code class="language-java">// 自主运行参数配置
private static final int POLL_INTERVAL = 5;      // 空闲轮询间隔(秒)
private static final int IDLE_TIMEOUT = 60;      // 空闲超时(秒)
// 智能调度:5秒轮询平衡响应性和资源消耗
// 自动清理:60秒无工作自动关机,释放资源
// 可持续运行:支持长时间无人值守运行
</code></pre>
<ul>
<li><strong>状态机演进</strong>:从简单的working/idle状态升级为完整的工作-空闲循环</li>
<li><strong>自主调度</strong>:智能体自己决定何时工作、何时空闲</li>
<li><strong>资源优化</strong>:空闲时降低资源消耗,有工作时快速响应</li>
<li><strong>可持续性</strong>:支持7x24小时持续运行</li>
</ul>
<h2 id="任务板系统与自动认领">任务板系统与自动认领</h2>
<pre><code class="language-java">/**
* 扫描无人认领的任务
*/
private static List&lt;Map&lt;String, Object&gt;&gt; scanUnclaimedTasks() {
    List&lt;Map&lt;String, Object&gt;&gt; unclaimed = new ArrayList&lt;&gt;();
    Files.list(TASKS_DIR)
      .filter(p -&gt; p.getFileName().toString().startsWith("task_"))
      .filter(p -&gt; p.getFileName().toString().endsWith(".json"))
      .sorted()// 公平性:按ID顺序扫描
      .forEach(p -&gt; {
            Map&lt;String, Object&gt; task = gson.fromJson(content, type);
            
            String status = (String) task.get("status");
            String owner = (String) task.get("owner");
            @SuppressWarnings("unchecked")
            List&lt;Integer&gt; blockedBy = (List&lt;Integer&gt;) task.get("blockedBy");
            
            if ("pending".equals(status) &amp;&amp;
                (owner == null || owner.isEmpty()) &amp;&amp;
                (blockedBy == null || blockedBy.isEmpty())) {
                unclaimed.add(task);
            }
            // 智能筛选:只扫描可执行的任务
            // 无阻塞:不认领有依赖阻塞的任务
            // 无所有者:不认领已有所有者的任务
      });
}
</code></pre>
<ul>
<li><strong>任务市场</strong>:任务板作为智能体间的任务协调机制</li>
<li><strong>公平竞争</strong>:所有智能体平等扫描和认领任务</li>
<li><strong>依赖感知</strong>:自动识别有依赖阻塞的任务</li>
<li><strong>负载均衡</strong>:空闲智能体自动认领任务,实现自动负载均衡</li>
</ul>
<h2 id="原子性任务认领机制">原子性任务认领机制</h2>
<pre><code class="language-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&lt;String, Object&gt; 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);
    }
}
</code></pre>
<ul>
<li><strong>并发安全</strong>:同步锁确保多智能体环境下的数据一致性</li>
<li><strong>原子操作</strong>:读取-修改-写入的原子性,防止竞态条件</li>
<li><strong>状态管理</strong>:明确的任务状态生命周期管理</li>
<li><strong>所有者标记</strong>:明确任务归属,避免重复工作</li>
</ul>
<h2 id="主动空闲工具与状态转换">主动空闲工具与状态转换</h2>
<pre><code class="language-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&lt;String, Object&gt; 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状态
// 控制权转移:智能体自主控制工作节奏
</code></pre>
<ul>
<li><strong>主动决策</strong>:智能体可以主动决定何时完成工作</li>
<li><strong>状态管理</strong>:明确的工作-空闲状态转换</li>
<li><strong>资源优化</strong>:完成工作后主动释放计算资源</li>
<li><strong>可预测性</strong>:明确的工作完成信号</li>
</ul>
<h2 id="周期性轮询与自动发现">周期性轮询与自动发现</h2>
<pre><code class="language-java">// --- 空闲阶段 ---
TEAM_MANAGER.setStatus(name, "idle");

boolean resume = false;
int maxPolls = IDLE_TIMEOUT / Math.max(POLL_INTERVAL, 1);

for (int pollCount = 0; pollCount &lt; maxPolls &amp;&amp; !stopFlag.get(); pollCount++) {
    try {
      Thread.sleep(POLL_INTERVAL * 1000L);// 周期性轮询
    } catch (InterruptedException e) {
      Thread.currentThread().interrupt();
      break;
    }
   
    // 检查邮箱
    List&lt;Map&lt;String, Object&gt;&gt; inbox = BUS.readInbox(name);
    if (!inbox.isEmpty()) {
      // 有消息,恢复工作
      resume = true;
      break;
    }
   
    // 扫描无人认领的任务
    List&lt;Map&lt;String, Object&gt;&gt; unclaimed = scanUnclaimedTasks();
    if (!unclaimed.isEmpty()) {
      // 自动认领并恢复工作
      resume = true;
      break;
    }
}
// 周期性检查:定期检查新工作
// 多源触发:邮箱消息或任务板都可以触发恢复工作
// 超时机制:长时间无工作自动关机
</code></pre>
<ul>
<li><strong>事件驱动</strong>:邮箱消息和任务板任务都是触发事件</li>
<li><strong>资源节约</strong>:轮询间隔避免CPU过度消耗</li>
<li><strong>多源响应</strong>:响应多种类型的工作触发</li>
<li><strong>自动恢复</strong>:发现工作后自动恢复工作状态</li>
</ul>
<h2 id="自动任务认领与上下文重建">自动任务认领与上下文重建</h2>
<pre><code class="language-java">// 自动认领任务
claimTask(taskId, name);

// 创建任务提示
String taskPrompt = String.format(
    "&lt;auto-claimed&gt;Task #%d: %s%n%s&lt;/auto-claimed&gt;",
    taskId, taskSubject, taskDesc
);

// 如果消息历史太短,重新注入身份
if (messages.size() &lt;= 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."));
// 自动对话:模拟智能体认领任务并开始工作
// 工作流保持:保持对话的自然流畅
</code></pre>
<ul>
<li><strong>自动接单</strong>:智能体自动认领并开始处理任务</li>
<li><strong>身份持久</strong>:即使上下文被压缩,也能重建身份</li>
<li><strong>工作流连续</strong>:保持工作对话的自然连续性</li>
<li><strong>自动初始化</strong>:为新任务自动初始化工作上下文</li>
</ul>
<h2 id="命令行管理与可视化监控">命令行管理与可视化监控</h2>
<pre><code class="language-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;
}
// 运维友好:提供方便的管理命令
// 实时监控:随时查看团队状态和任务进度
// 可视化:清晰的图表化展示
// 调试支持:便于问题诊断和系统监控
</code></pre>
<ul>
<li><strong>运维界面</strong>:为人类管理员提供方便的管理接口</li>
<li><strong>实时监控</strong>:随时掌握系统运行状态</li>
<li><strong>可视化</strong>:直观的任务状态展示</li>
<li><strong>调试支持</strong>:便于问题定位和系统优化</li>
</ul>
<h2 id="架构演进与价值">架构演进与价值</h2>
<p><strong>从 TeamProtocolsSystem 到 AutonomousAgentsSystem 的升级</strong>:</p>
<table>
<thead>
<tr>
<th>维度</th>
<th>TeamProtocolsSystem</th>
<th>AutonomousAgentsSystem</th>
</tr>
</thead>
<tbody>
<tr>
<td>运行模式</td>
<td>被动响应</td>
<td>主动自主</td>
</tr>
<tr>
<td>工作调度</td>
<td>人工分配</td>
<td>自动认领</td>
</tr>
<tr>
<td>生命周期</td>
<td>单次运行</td>
<td>持续循环</td>
</tr>
<tr>
<td>资源管理</td>
<td>静态分配</td>
<td>动态优化</td>
</tr>
<tr>
<td>人机交互</td>
<td>频繁交互</td>
<td>无人值守</td>
</tr>
</tbody>
</table>


</div>
<div id="MySignature" role="contentinfo">
    <p>本文来自在线网站:seven的菜鸟成长之路,作者:seven,转载请注明原文链接:www.seven97.top</p><br><br>
来源:https://www.cnblogs.com/sevencoding/p/19821594
頁: [1]
查看完整版本: 【从0到1构建一个ClaudeAgent】协作-自主Agent