mirror of
https://github.com/shareAI-lab/analysis_claude_code.git
synced 2026-03-22 10:25:41 +08:00
110 lines
3.6 KiB
Markdown
110 lines
3.6 KiB
Markdown
# s08: Background Tasks (后台任务)
|
|
|
|
`s01 > s02 > s03 > s04 > s05 > s06 | s07 > [ s08 ] s09 > s10 > s11 > s12`
|
|
|
|
> *"慢操作丢后台, agent 继续想下一步"* -- 后台线程跑命令, 完成后注入通知。
|
|
|
|
## 问题
|
|
|
|
有些命令要跑好几分钟: `npm install`、`pytest`、`docker 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 用线程安全的通知队列追踪任务。
|
|
|
|
```python
|
|
class BackgroundManager:
|
|
def __init__(self):
|
|
self.tasks = {}
|
|
self._notification_queue = []
|
|
self._lock = threading.Lock()
|
|
```
|
|
|
|
2. `run()` 启动守护线程, 立即返回。
|
|
|
|
```python
|
|
def run(self, command: str) -> str:
|
|
task_id = str(uuid.uuid4())[:8]
|
|
self.tasks[task_id] = {"status": "running", "command": command}
|
|
thread = threading.Thread(
|
|
target=self._execute, args=(task_id, command), daemon=True)
|
|
thread.start()
|
|
return f"Background task {task_id} started"
|
|
```
|
|
|
|
3. 子进程完成后, 结果进入通知队列。
|
|
|
|
```python
|
|
def _execute(self, task_id, command):
|
|
try:
|
|
r = subprocess.run(command, shell=True, cwd=WORKDIR,
|
|
capture_output=True, text=True, timeout=300)
|
|
output = (r.stdout + r.stderr).strip()[:50000]
|
|
except subprocess.TimeoutExpired:
|
|
output = "Error: Timeout (300s)"
|
|
with self._lock:
|
|
self._notification_queue.append({
|
|
"task_id": task_id, "result": output[:500]})
|
|
```
|
|
|
|
4. 每次 LLM 调用前排空通知队列。
|
|
|
|
```python
|
|
def agent_loop(messages: list):
|
|
while True:
|
|
notifs = BG.drain_notifications()
|
|
if notifs:
|
|
notif_text = "\n".join(
|
|
f"[bg:{n['task_id']}] {n['result']}" for n in notifs)
|
|
messages.append({"role": "user",
|
|
"content": f"<background-results>\n{notif_text}\n"
|
|
f"</background-results>"})
|
|
messages.append({"role": "assistant",
|
|
"content": "Noted background results."})
|
|
response = client.messages.create(...)
|
|
```
|
|
|
|
循环保持单线程。只有子进程 I/O 被并行化。
|
|
|
|
## 相对 s07 的变更
|
|
|
|
| 组件 | 之前 (s07) | 之后 (s08) |
|
|
|----------------|------------------|------------------------------------|
|
|
| Tools | 8 | 6 (基础 + background_run + check) |
|
|
| 执行方式 | 仅阻塞 | 阻塞 + 后台线程 |
|
|
| 通知机制 | 无 | 每轮排空的队列 |
|
|
| 并发 | 无 | 守护线程 |
|
|
|
|
## 试一试
|
|
|
|
```sh
|
|
cd learn-claude-code
|
|
python agents/s08_background_tasks.py
|
|
```
|
|
|
|
试试这些 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`
|