mirror of
https://github.com/shareAI-lab/analysis_claude_code.git
synced 2026-03-22 02:15:42 +08:00
Comprehensive rewrite establishing the harness engineering narrative across the entire repository. README (EN/ZH/JA): added "The Model IS the Agent" manifesto with historical proof (DQN, OpenAI Five, AlphaStar, Tencent Jueyu), "What an Agent Is NOT" critique, harness engineer role definition, "Why Claude Code" as masterclass in harness design, and universe vision. Consistent framing: model = driver, harness = vehicle. docs (36 files, 3 languages): injected one-line "Harness layer" callout after the motto in every session document (s01-s12). agents (13 Python files): added harness framing comment before each module docstring. skills/agent-philosophy.md: full rewrite aligned with harness narrative.
110 lines
3.9 KiB
Markdown
110 lines
3.9 KiB
Markdown
# s08: Background Tasks
|
|
|
|
`s01 > s02 > s03 > s04 > s05 > s06 | s07 > [ s08 ] s09 > s10 > s11 > s12`
|
|
|
|
> *"遅い操作はバックグラウンドへ、エージェントは次を考え続ける"* -- デーモンスレッドがコマンド実行、完了後に通知を注入。
|
|
>
|
|
> **Harness 層**: バックグラウンド実行 -- モデルが考え続ける間、Harness が待つ。
|
|
|
|
## 問題
|
|
|
|
一部のコマンドは数分かかる: `npm install`、`pytest`、`docker build`。ブロッキングループでは、モデルはサブプロセスの完了を待って座っている。ユーザーが「依存関係をインストールして、その間にconfigファイルを作って」と言っても、エージェントは並列ではなく逐次的に処理する。
|
|
|
|
## 解決策
|
|
|
|
```
|
|
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からの変更点
|
|
|
|
| Component | Before (s07) | After (s08) |
|
|
|----------------|------------------|----------------------------|
|
|
| Tools | 8 | 6 (base + background_run + check)|
|
|
| Execution | Blocking only | Blocking + background threads|
|
|
| Notification | None | Queue drained per loop |
|
|
| Concurrency | None | Daemon threads |
|
|
|
|
## 試してみる
|
|
|
|
```sh
|
|
cd learn-claude-code
|
|
python agents/s08_background_tasks.py
|
|
```
|
|
|
|
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`
|