【从0到1构建一个ClaudeAgent】规划与和谐-TodoWrite [复制链接]
发表于 6 天前 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
这段代码引入了一个非常关键的概念:“自我反思与状态管理”
之前的 Agent 只是单纯的“听指令 -> 干活”,轻易干着干着就忘了初志,大概在复杂的使掷中迷失方向。TodoManager 就像是给 Agent 装了一个“记事本”和“监工”。
Java 实当代码
  1. public class AgentWithTodo {
  2.     private static final Path WORKDIR = Paths.get(System.getProperty("user.dir"));
  3.    
  4.     // --- 1. 状态管理:TodoManager ---
  5.    
  6.     // 任务状态枚举
  7.     public enum TaskStatus {
  8.         PENDING("pending"), IN_PROGRESS("in_progress"), COMPLETED("completed");
  9.         public final String label;
  10.         TaskStatus(String label) { this.label = label; }
  11.         public static TaskStatus fromLabel(String s) {
  12.             for (TaskStatus ts : values()) if (ts.label.equals(s)) return ts;
  13.             return PENDING;
  14.         }
  15.     }
  16.     // 任务实体
  17.     public static class TodoItem {
  18.         public String id;
  19.         public String text;
  20.         public TaskStatus status;
  21.         public TodoItem(String id, String text, String status) {
  22.             this.id = id; this.text = text; this.status = TaskStatus.fromLabel(status);
  23.         }
  24.     }
  25.     // 管理器类
  26.     public static class TodoManager {
  27.         private List<TodoItem> items = new ArrayList<>();
  28.         public String update(List<Map<String, Object>> newItems) throws Exception {
  29.             if (newItems.size() > 20) throw new Exception("Max 20 todos allowed");
  30.             List<TodoItem> validated = new ArrayList<>();
  31.             int inProgressCount = 0;
  32.             for (int i = 0; i < newItems.size(); i++) {
  33.                 Map<String, Object> item = newItems.get(i);
  34.                 String text = (String) item.getOrDefault("text", "");
  35.                 String statusStr = (String) item.getOrDefault("status", "pending");
  36.                 String id = String.valueOf(item.getOrDefault("id", String.valueOf(i + 1)));
  37.                 if (text.trim().isEmpty()) throw new Exception("Item " + id + ": text required");
  38.                
  39.                 TaskStatus status = TaskStatus.fromLabel(statusStr.toLowerCase());
  40.                 if (status == TaskStatus.IN_PROGRESS) inProgressCount++;
  41.                 validated.add(new TodoItem(id, text.trim(), status.label));
  42.             }
  43.             if (inProgressCount > 1) throw new Exception("Only one task can be in_progress at a time");
  44.             this.items = validated;
  45.             return render();
  46.         }
  47.         public String render() {
  48.             if (items.isEmpty()) return "No todos.";
  49.             StringBuilder sb = new StringBuilder();
  50.             for (TodoItem item : items) {
  51.                 String marker = item.status == TaskStatus.PENDING ? "[ ]" :
  52.                                 item.status == TaskStatus.IN_PROGRESS ? "[>]" : "[x]";
  53.                 sb.append(String.format("%s #%s: %s%n", marker, item.id, item.text));
  54.             }
  55.             long done = items.stream().filter(i -> i.status == TaskStatus.COMPLETED).count();
  56.             sb.append(String.format("%n(%d/%d completed)", done, items.size()));
  57.             return sb.toString();
  58.         }
  59.     }
  60.     private static final TodoManager TODO_MANAGER = new TodoManager();
  61.     // --- 2. 工具定义与分发 ---
  62.     public enum ToolType {
  63.         BASH("bash"), READ_FILE("read_file"), WRITE_FILE("write_file"),
  64.         EDIT_FILE("edit_file"), TODO("todo");  // 新增 todo 工具
  65.         public final String name;
  66.         ToolType(String name) { this.name = name; }
  67.     }
  68.     private static final Map<String, ToolExecutor> TOOL_HANDLERS = new HashMap<>();
  69.     static {
  70.         // ... 省略已有的工具注册
  71.         
  72.         // 注册 Todo 工具
  73.         TOOL_HANDLERS.put(ToolType.TODO.name, args -> {
  74.             @SuppressWarnings("unchecked")
  75.             List<Map<String, Object>> items = (List<Map<String, Object>>) args.get("items");
  76.             return TODO_MANAGER.update(items);
  77.         });
  78.     }
  79.     // --- 3. 核心循环 ---
  80.     public static void agentLoop(List<Map<String, Object>> messages) {
  81.         int roundsSinceTodo = 0;  // 新增:跟踪轮数
  82.         while (true) {
  83.             // ... 省略相同的 LLM 调用、消息追加、停止检查逻辑
  84.             
  85.             // 3. 执行工具
  86.             List<Map<String, Object>> toolResults = new ArrayList<>();
  87.             List<Map<String, Object>> content = (List<Map<String, Object>>) response.get("content");
  88.             boolean usedTodo = false;  // 新增:标记是否使用了 todo 工具
  89.             for (Map<String, Object> block : content) {
  90.                 if ("tool_use".equals(block.get("type"))) {
  91.                     // ... 省略相同的工具调用逻辑
  92.                     String toolName = (String) block.get("name");
  93.                     // ... 执行工具
  94.                     
  95.                     if (toolName.equals("todo")) usedTodo = true;  // 标记 todo 使用
  96.                 }
  97.             }
  98.             // 4. 监工逻辑 (Nag Reminder)
  99.             roundsSinceTodo = usedTodo ? 0 : roundsSinceTodo + 1;
  100.             
  101.             if (roundsSinceTodo >= 3) {  // 关键:超过3轮没更新就提醒
  102.                 Map<String, Object> nag = new HashMap<>();
  103.                 nag.put("type", "text");
  104.                 nag.put("text", "<reminder>Update your todos.</reminder>");
  105.                 toolResults.add(0, nag); // 插入到结果列表最前面
  106.                 System.out.println(">>> 监工提醒:更新待办列表!");
  107.             }
  108.             // 5. 回传结果
  109.             // ... 省略相同的回传逻辑
  110.         }
  111.     }
  112.     // --- 4. 工具实现 (简化版) ---
  113.     // ... 省略已有的工具实现
  114. }
复制代码
状态管理:TodoManager 类

为Agent引入长期影象和工作进度追踪本领,让Agent能"记取"本身的使命列表和工作状态。
  1. // 任务状态枚举
  2. public enum TaskStatus {
  3.     PENDING("pending"),
  4.     IN_PROGRESS("in_progress"),
  5.     COMPLETED("completed");
  6.     // 状态枚举:明确定义三种状态
  7.     // 状态驱动:Agent根据状态决定下一步操作
  8. }
复制代码
  1. // 任务实体 - 数据结构
  2. public static class TodoItem {
  3.     public String id;          // 唯一标识
  4.     public String text;        // 任务描述
  5.     public TaskStatus status;  // 状态
  6.     // 结构化的任务表示
  7.     // 为LLM提供清晰的上下文
  8. }
复制代码
  1. // TodoManager - 核心状态管理
  2. public class TodoManager {
  3.     private List<TodoItem> items = new ArrayList<>();  // 状态存储
  4.     public String update(List<Map<String, Object>> newItems) throws Exception {
  5.         if (newItems.size() > 20) throw new Exception("Max 20 todos allowed");
  6.         // 业务规则1:限制任务数量,防止滥用
  7.         
  8.         int inProgressCount = 0;
  9.         List<TodoItem> validated = new ArrayList<>();
  10.         for (int i = 0; i < newItems.size(); i++) {
  11.             Map<String, Object> item = newItems.get(i);
  12.             String text = (String) item.getOrDefault("text", "");
  13.             String statusStr = (String) item.getOrDefault("status", "pending");
  14.             String id = String.valueOf(item.getOrDefault("id", String.valueOf(i + 1)));
  15.             
  16.             if (text.trim().isEmpty()) throw new Exception("Item " + id + ": text required");
  17.             // 业务规则2:任务文本必填
  18.             
  19.             TaskStatus status = TaskStatus.fromLabel(statusStr.toLowerCase());
  20.             if (status == TaskStatus.IN_PROGRESS) inProgressCount++;
  21.             // 业务规则3:跟踪进行中任务数量
  22.         }
  23.         if (inProgressCount > 1) throw new Exception("Only one task can be in_progress at a time");
  24.         // 业务规则4:一次只能进行一个任务,聚焦执行
  25.         
  26.         this.items = validated;  // 原子性更新
  27.         return render();  // 返回可视化表示
  28.     }
  29.     public String render() {
  30.         if (items.isEmpty()) return "No todos.";
  31.         StringBuilder sb = new StringBuilder();
  32.         for (TodoItem item : items) {
  33.             String marker = item.status == TaskStatus.PENDING ? "[ ]" :
  34.                            item.status == TaskStatus.IN_PROGRESS ? "[>]" : "[x]";
  35.             sb.append(String.format("%s #%s: %s%n", marker, item.id, item.text));
  36.             // 可视化格式:[ ] 待办, [>] 进行中, [x] 已完成
  37.         }
  38.         
  39.         long done = items.stream().filter(i -> i.status == TaskStatus.COMPLETED).count();
  40.         sb.append(String.format("%n(%d/%d completed)", done, items.size()));
  41.         // 进度统计:为LLM提供进度反馈
  42.         return sb.toString();
  43.     }
  44. }
复制代码

  • 状态长期化:Agent有了"影象",不再是完全无状态的
  • 布局化表现:用面向对象的方式管理使命状态
  • 业务束缚:通过校验规则确保状态同等性
  • 可视化输出:为LLM提供人类可读的进度展示
Todo工具集成
  1. // 在工具枚举中新增
  2. TODO("todo");  // 扩展工具集,添加状态管理工具
  3. // 注册Todo工具实现
  4. TOOL_HANDLERS.put(ToolType.TODO.name, args -> {
  5.     @SuppressWarnings("unchecked")
  6.     List<Map<String, Object>> items = (List<Map<String, Object>>) args.get("items");
  7.     return TODO_MANAGER.update(items);
  8.     // 状态更新工具:让LLM能操作任务状态
  9.     // 接受LLM传入的任务列表,更新内部状态
  10. });
复制代码

  • 状态使用作为工具:将状态管理抽象为工具调用
  • 双向通讯:LLM可以通过工具更新状态,也能获取状态
  • 同一接口:与其他工具使用雷同的调用模式
监工逻辑(Nag Reminder)
  1. // 在agentLoop中新增
  2. int roundsSinceTodo = 0;  // 计数器:记录多少轮没使用todo工具
  3. boolean usedTodo = false; // 标记当前轮是否使用了todo
  4. // 执行工具时记录
  5. if (toolName.equals("todo")) usedTodo = true;
  6. // 每轮结束后的监工检查
  7. roundsSinceTodo = usedTodo ? 0 : roundsSinceTodo + 1;  // 重置或递增
  8. if (roundsSinceTodo >= 3) {  // 如果超过3轮没更新待办
  9.     Map<String, Object> nag = new HashMap<>();
  10.     nag.put("type", "text");
  11.     nag.put("text", "<reminder>Update your todos.</reminder>");
  12.     toolResults.add(0, nag); // 插入到结果列表最前面
  13.    
  14.     System.out.println(">>> 监工提醒:更新待办列表!");
  15.     // 强制提醒:防止LLM忘记更新状态
  16. }
复制代码

  • 防忘记机制:LLM大概会忘记更新状态,须要外部提示
  • 渐进式提示:容忍短期忘记,高出阈值再干预
  • 布局化提示:使用特别标签,让LLM辨认这是体系提示
  • 优先级:插入到结果列表最前面,确保LLM先看到
架构演进与代价

从 AgentWithTools 到 AgentWithTodo 的升级
维度AgentWithToolsAgentWithTodo状态管理无状态有状态(TodoManager)进度追踪不支持支持使命进度管理长期影象不支持支持使命列表影象监视机制无有监工提示使命管理工具级项目级
免责声明:如果侵犯了您的权益,请联系站长及时删除侵权内容,谢谢合作!qidao123.com:ToB企服之家,中国第一个企服评测及软件市场,开放入驻,技术点评得现金.
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表