Learn Claude Code
s08

后台任务

并发

Background Threads + Notifications

37 LOC6 个工具BackgroundManager + notification queue
Run slow operations in the background; the agent keeps thinking ahead

s01 > s02 > s03 > s04 > s05 > s06 | s07 > [ s08 ] s09 > s10 > s11 > s12

"慢操作丢后台, agent 继续想下一步" -- 后台线程跑命令, 完成后注入通知。

Harness 层: 后台执行 -- 模型继续思考, harness 负责等待。

问题

有些命令要跑好几分钟: npm installpytestdocker build。阻塞式循环下模型只能干等。用户说 "装依赖, 顺便建个配置文件", 智能体却只能一个一个来。

解决方案

Main thread                Background thread
+-----------------+        +-----------------+
| agent loop      |        | subprocess runs |
| ...             |        | ...             |
| [LLM call] <---+------- | enqueue(result) |
|  ^drain queue   |        +-----------------+
+-----------------+

Timeline:
Agent --[spawn A]--[spawn B]--[other work]----
             |          |
             v          v
          [A runs]   [B runs]      (parallel)
             |          |
             +-- results injected before next LLM call --+

工作原理

  1. BackgroundManager 用通知队列追踪任务。
class BackgroundManager {
  constructor() {
    this.tasks = {};
    this.notificationQueue = [];
  }
}
  1. run() 启动后台执行, 立即返回。
run(command: string): string {
  const taskId = randomUUID().slice(0, 8);
  this.tasks[taskId] = { status: "running", command };
  setTimeout(() => this.execute(taskId, command), 0);
  return `Background task ${taskId} started`;
}
  1. 子进程完成后, 结果进入通知队列。
execute(taskId: string, command: string) {
  const result = spawnSync(command, {
    shell: true,
    cwd: WORKDIR,
    encoding: "utf8",
    timeout: 300_000,
  });
  const output = `${result.stdout ?? ""}${result.stderr ?? ""}`.trim();
  this.tasks[taskId].status = "completed";
  this.notificationQueue.push({
    task_id: taskId,
    result: output.slice(0, 500),
  });
}
  1. 每次 LLM 调用前排空通知队列。
async function agentLoop(messages: ChatMessage[]) {
  while (true) {
    const notifications = BG.drainNotifications();
    if (notifications.length) {
      const notifText = notifications.map((n) => `[bg:${n.task_id}] ${n.result}`).join("\n");
      messages.push({ role: "user", content: "<background-results>\n" + notifText + "\n</background-results>" });
      messages.push({ role: "assistant", content: "Noted background results." });
    }
    const response = await client.messages.create({ ... });

循环保持单线程。只有子进程 I/O 被并行化。

相对 s07 的变更

组件之前 (s07)之后 (s08)
Tools86 (基础 + background_run + check)
执行方式仅阻塞阻塞 + 后台线程
通知机制每轮排空的队列
并发守护线程

试一试

cd learn-claude-code-typescript
npx tsx agents/s08_background_tasks.ts

试试这些 prompt (英文 prompt 对 LLM 效果更好, 也可以用中文):

  1. Run "sleep 5 && echo done" in the background, then create a file while it runs
  2. Start 3 background tasks: "sleep 2", "sleep 4", "sleep 6". Check their status.
  3. Run pytest in the background and keep working on other things