parallel-subagent-batch-merge

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

並列サブエージェントのバッチ生成とマルチフォーマットマージ

并行子代理的批量生成与多格式合并

Extracted: 2026-02-11 Context: Claude Code で大量データを並列サブエージェントで生成し、出力を1つのファイルに統合する場面
提取日期: 2026-02-11 场景: 使用Claude Code通过并行子代理生成大量数据,并将输出整合到单个文件的场景

Problem

问题

Claude Code のサブエージェント(Task tool)を大量並列起動すると、以下の問題が発生する:
  1. 出力フォーマットの不統一 — 同じプロンプトでも、エージェントごとに出力構造が異なる
    • 辞書型:
      { "id": { ...data } }
    • リスト+id:
      [{ "id": "...", "data": {...} }]
    • リスト+別名:
      [{ "questionId": "...", "data": {...} }]
  2. 構文エラーの混入
    :=
    、trailing comma 等の JSON 構文エラー
  3. 型の揺れ
    relatedConcepts
    string
    のはずが
    array
    で返る等
  4. コンテンツ重複 — 同じ説明文が複数選択肢にコピーされる
大量并行启动Claude Code子代理(Task工具)时,会出现以下问题:
  1. 输出格式不一致 — 即使使用相同提示词,不同代理的输出结构也不同
    • 字典型:
      { "id": { ...data } }
    • 列表+id:
      [{ "id": "...", "data": {...} }]
    • 列表+别名:
      [{ "questionId": "...", "data": {...} }]
  2. 混入语法错误 — 出现
    :=
    、 trailing comma等JSON语法错误
  3. 类型不一致 — 例如
    relatedConcepts
    应返回
    string
    却返回
    array
  4. 内容重复 — 相同说明文本被复制到多个选项中

Solution

解决方案

1. バッチ分割: ヘルパースクリプトで入力を標準化

1. 批量分割: 使用辅助脚本标准化输入

python
undefined
python
undefined

prepare_batches.py: 入力データを N 件ずつのテキストファイルに分割

prepare_batches.py: 将输入数据分割为每份N条的文本文件

→ 各サブエージェントが1ファイルだけ読めばよい

→ 每个子代理只需读取一个文件即可

batches = [items[i:i+BATCH_SIZE] for i in range(0, len(items), BATCH_SIZE)]

- バッチサイズ 20 が実績あり(コンテキスト窓との兼ね合い)
- 最終バッチは端数になるので注意
batches = [items[i:i+BATCH_SIZE] for i in range(0, len(items), BATCH_SIZE)]

- 经验证,批量大小设为20效果最佳(平衡上下文窗口限制)
- 注意最后一批可能存在数据量不足的情况

2. 並列起動: 全バッチを
run_in_background=true
で同時起動

2. 并行启动: 所有批次通过
run_in_background=true
同时启动

undefined
undefined

21バッチ × Sonnet subagent を同時起動

同时启动21个批次 × Sonnet子代理

for batch in 1..21: Task(subagent_type="general-purpose", model="sonnet", run_in_background=true, prompt=f"Read batch_{batch}.txt ...")

- 出力先を `batch_XX_output.json` で分離(書き込み競合の回避)
- 全エージェント完了後にマージ
for batch in 1..21: Task(subagent_type="general-purpose", model="sonnet", run_in_background=true, prompt=f"Read batch_{batch}.txt ...")

- 输出文件命名为`batch_XX_output.json`以避免写入冲突
- 所有代理执行完成后再进行合并

3. 正規化マージ: 3種フォーマットを統一

3. 规范化合并: 统一3种格式

python
def normalize_batch(batch_data):
    """辞書型・リスト型どちらでも { id: data } に正規化"""
    if isinstance(batch_data, dict):
        return batch_data
    elif isinstance(batch_data, list):
        result = {}
        for item in batch_data:
            qid = item.get("id") or item.get("questionId")
            data = item.get("enhancedExplanation", item)
            result[qid] = data
        return result
python
def normalize_batch(batch_data):
    """将字典型或列表型数据统一格式为 { id: data }"""
    if isinstance(batch_data, dict):
        return batch_data
    elif isinstance(batch_data, list):
        result = {}
        for item in batch_data:
            qid = item.get("id") or item.get("questionId")
            data = item.get("enhancedExplanation", item)
            result[qid] = data
        return result

4. 型修正: 期待する型に強制変換

4. 类型修正: 强制转换为预期类型

python
undefined
python
undefined

relatedConcepts: String? なのに array で返ってきた場合

当relatedConcepts应返回String却返回array时

if isinstance(val, list): val = "".join(val) if val else None
undefined
if isinstance(val, list): val = "".join(val) if val else None
undefined

5. 構文エラー修正: JSON parse 前に既知パターンを置換

5. 语法错误修正: JSON解析前替换已知错误模式

python
raw = raw.replace(':="', ': "')  # := → : のタイポ修正
python
raw = raw.replace(':="', ': "')  # 修正:= → :的拼写错误

6. 品質検証: 重複検出 + 自動修正

6. 质量验证: 重复检测 + 自动修正

python
undefined
python
undefined

contrastTable の point 重複チェック

检查contrastTable的point是否重复

points = [e["point"] for e in contrast_table] if len(set(points)) < len(points): # → 手動で固有テキストに差し替え
undefined
points = [e["point"] for e in contrast_table] if len(set(points)) < len(points): # → 手动替换为唯一文本
undefined

Key Metrics (実績)

关键指标(实际成果)

項目数値
対象データ408問
バッチ数21(20問×20 + 8問×1)
並列エージェント21(全同時起動)
フォーマット種類3種(辞書14 / リスト+id 2 / リスト+questionId 5)
構文エラー1件(batch_21:
:=
型の揺れ8件(batch_21: relatedConcepts が配列)
コンテンツ重複7問(contrastTable point 重複)
最終結果全408問マージ成功、検証 ALL GREEN
项目数值
目标数据408题
批次数21(20题×20 + 8题×1)
并行代理数21(全部同时启动)
格式类型3种(字典14 / 列表+id 2 / 列表+questionId 5)
语法错误1处(batch_21:
:=
类型不一致8处(batch_21: relatedConcepts 返回数组)
内容重复7题(contrastTable point重复)
最终结果全部408题合并成功,验证全部通过

When to Use

适用场景

  • Claude Code で 50件以上 のデータを構造化生成するとき
  • 各項目が 独立 しており並列処理可能なとき
  • 出力が JSON で、スキーマが明確なとき
  • claude-code-self-generation-over-api.md
    の判断で「Claude Code 直接生成」を選択した後の実行パターン
  • 需要用Claude Code结构化生成50条以上数据时
  • 每个项目独立可并行处理时
  • 输出为JSON且schema明确时
  • claude-code-self-generation-over-api.md
    中选择「Claude Code 直接生成」后的执行模式

Gotcha: キー名不統一の検出と正規化

注意事项: 键名不一致的检测与规范化

LLMバッチ生成では、同じフィールドに対してバッチごとに異なるキー名が出力される(例:
choice
/
choiceLabel
/
option
)。
在LLM批量生成时,同一字段可能在不同批次输出不同的键名(例如:
choice
/
choiceLabel
/
option
)。

検出

检测

python
key_sets = set()
for item in data['items']:
    for entry in item.get('nested', []):
        key_sets.add(tuple(sorted(entry.keys())))
print(f'Unique key patterns: {len(key_sets)}')
for ks in sorted(key_sets):
    print(f'  {ks}')
python
key_sets = set()
for item in data['items']:
    for entry in item.get('nested', []):
        key_sets.add(tuple(sorted(entry.keys())))
print(f'Unique key patterns: {len(key_sets)}')
for ks in sorted(key_sets):
    print(f'  {ks}')

正規化

规范化

python
for entry in item.get('nested', []):
    normalized = {}
    normalized['choice'] = entry.get('choice') or entry.get('choiceLabel') or entry.get('option', '')
    normalized['point'] = entry.get('point') or entry.get('reason', '')
    # ...
python
for entry in item.get('nested', []):
    normalized = {}
    normalized['choice'] = entry.get('choice') or entry.get('choiceLabel') or entry.get('option', '')
    normalized['point'] = entry.get('point') or entry.get('reason', '')
    # ...

検証

验证

python
bad = [(item['id'], set(e.keys()))
       for item in data['items']
       for e in item.get('nested', [])
       if set(e.keys()) != EXPECTED_KEYS]
assert not bad, f'Still inconsistent: {bad}'
python
bad = [(item['id'], set(e.keys()))
       for item in data['items']
       for e in item.get('nested', [])
       if set(e.keys()) != EXPECTED_KEYS]
assert not bad, f'Still inconsistent: {bad}'

Anti-patterns

反模式

  • バッチサイズが大きすぎる(50+)→ エージェントのコンテキスト消費で品質低下
  • マージスクリプトが特定フォーマットだけ想定 → 必ず全フォーマットに対応する
  • 検証なしでマージ完了とする →
    validate
    スクリプトを必ず実行
  • 重複エラーを無視する → UIで同じテキストが並ぶと著しく品質低下
  • キー名不統一を見逃す → Swift Codable等の厳格なデコーダで即座にクラッシュ
  • 批处理尺寸过大(50+)→ 代理上下文消耗导致质量下降
  • 合并脚本仅针对特定格式设计 → 必须兼容所有格式
  • 未验证就判定合并完成 → 必须执行
    validate
    脚本
  • 忽略重复错误 → UI中出现重复文本会严重降低质量
  • 忽略键名不一致 → 在Swift Codable等严格解码器中会直接崩溃",