refactor: remove debug prints and add logging for todo updates

learn
abel533 1 month ago
parent 1ecef9dc3a
commit 5878af1262
  1. 5
      src/main/java/io/mybatis/learn/s03/S03TodoWrite.java
  2. 10
      src/main/java/io/mybatis/learn/s03/TodoManager.java
  3. 21
      src/main/java/io/mybatis/learn/s08/BackgroundManager.java
  4. 9
      src/main/java/io/mybatis/learn/s08/S08BackgroundTasks.java

@ -85,11 +85,6 @@ public class S03TodoWrite implements CommandLineRunner {
.call() .call()
.content(); .content();
// 每次回复后打印当前 todo 状态
System.out.println("\n--- Todo Status ---");
System.out.println(todoManager.render());
System.out.println("-------------------");
return response; return response;
}); });
} }

@ -1,5 +1,7 @@
package io.mybatis.learn.s03; package io.mybatis.learn.s03;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ai.tool.annotation.Tool; import org.springframework.ai.tool.annotation.Tool;
import org.springframework.ai.tool.annotation.ToolParam; import org.springframework.ai.tool.annotation.ToolParam;
@ -23,6 +25,8 @@ import java.util.List;
*/ */
public class TodoManager { public class TodoManager {
private static final Logger log = LoggerFactory.getLogger(TodoManager.class);
/** /**
* Todo 项数据结构 * Todo 项数据结构
* TIP: 对应 Python todo item 字典 {@code {"id": ..., "text": ..., "status": ...}} * TIP: 对应 Python todo item 字典 {@code {"id": ..., "text": ..., "status": ...}}
@ -73,7 +77,11 @@ public class TodoManager {
} }
this.items = validated; this.items = validated;
return render(); String rendered = render();
if (log.isDebugEnabled()) {
System.out.printf("📋 调用工具 [Todo] 更新 %d 项任务%n%s%n", items.size(), rendered);
}
return rendered;
} }
/** /**

@ -24,7 +24,13 @@ import java.util.stream.Collectors;
* <p> * <p>
* TIP: 对应 Python {@code agents/s08_background_tasks.py} 中的 {@code BackgroundManager} * TIP: 对应 Python {@code agents/s08_background_tasks.py} 中的 {@code BackgroundManager}
* Python 使用 {@code threading.Thread(daemon=True)} * Python 使用 {@code threading.Thread(daemon=True)}
* Java 使用 {@link ExecutorService} + 虚拟线程Java 21 * Java 同样使用 daemon 平台线程而非虚拟线程
* <p>
* 为何不用虚拟线程{@code execute()} 内通过 {@code BufferedReader.lines()} 读取进程输出
* 底层调用 {@code FileInputStream.read0()}native 方法会将虚拟线程
* <b>钉住pin在载体线程carrier thread</b>
* 载体线程池大小 = {@code availableProcessors()}若池耗尽则后续任务只能串行等待
* daemon 平台线程没有此约束可真正并行执行多个阻塞 I/O 任务符合 Python 版行为
* <pre> * <pre>
* Main thread Background thread * Main thread Background thread
* +-----------------+ +-----------------+ * +-----------------+ +-----------------+
@ -42,7 +48,14 @@ public class BackgroundManager {
private final Map<String, TaskInfo> tasks = new ConcurrentHashMap<>(); private final Map<String, TaskInfo> tasks = new ConcurrentHashMap<>();
private final List<Notification> notificationQueue = new CopyOnWriteArrayList<>(); private final List<Notification> notificationQueue = new CopyOnWriteArrayList<>();
private final ExecutorService executor = Executors.newVirtualThreadPerTaskExecutor(); // TIP: 使用 daemon 平台线程而非虚拟线程。
// 读取进程输出时底层会调用 native read0(),虚拟线程遇到 native 方法会被 pin 在载体线程上,
// 导致多个后台任务串行排队。平台线程无此限制,对应 Python 的 threading.Thread(daemon=True)。
private final ExecutorService executor = Executors.newCachedThreadPool(r -> {
Thread t = new Thread(r, "bg-worker");
t.setDaemon(true);
return t;
});
private final String workDir; private final String workDir;
record TaskInfo(String status, String result, String command) { record TaskInfo(String status, String result, String command) {
@ -56,7 +69,9 @@ public class BackgroundManager {
log.info("BackgroundManager 初始化,workDir={}", workDir); log.info("BackgroundManager 初始化,workDir={}", workDir);
} }
@Tool(description = "Run a command in a background thread. Returns task_id immediately without waiting.") @Tool(description = "Run a command in a background thread. Returns task_id immediately without waiting. "
+ "When starting multiple independent background tasks, call this tool for ALL of them "
+ "in a single response (parallel function calls) so they start at the same time.")
public String backgroundRun( public String backgroundRun(
@ToolParam(description = "The shell command to run in background") String command) { @ToolParam(description = "The shell command to run in background") String command) {
String taskId = UUID.randomUUID().toString().substring(0, 8); String taskId = UUID.randomUUID().toString().substring(0, 8);

@ -50,8 +50,15 @@ public class S08BackgroundTasks implements CommandLineRunner {
System.out.println("[Background tasks completed: " + notifs.size() + "]"); System.out.println("[Background tasks completed: " + notifs.size() + "]");
} }
// TIP: 明确要求 LLM 并行调用 backgroundRun,避免逐个调用导致任务串行提交。
// 同时注入当前 OS 信息,让 LLM 选择平台适配的命令(如 Windows 用 timeout /t N /nobreak 替代 sleep N)。
String os = System.getProperty("os.name");
String system = "You are a coding agent at " + workDir String system = "You are a coding agent at " + workDir
+ ". Use backgroundRun for long-running commands." + bgContext; + ". Current OS: " + os + "."
+ " Use backgroundRun for long-running commands."
+ " When starting multiple independent background tasks, issue ALL backgroundRun"
+ " calls in a single parallel batch so they begin simultaneously."
+ bgContext;
ChatClient chatClient = ChatClient.builder(chatModel) ChatClient chatClient = ChatClient.builder(chatModel)
.defaultSystem(system) .defaultSystem(system)

Loading…
Cancel
Save