mcpField
S
swarm

swarm

github.com/langchain-aiエージェントワークフロー1.3k8.9k 回インストール3 日前に更新
リポジトリ

swarm について

Swarm は、独立した項目を並列処理に振り分け、結果をテーブルに集約するスキルです。ファイルやレコードをまとめて処理するエージェント向けで、フィルタリング、再試行、集計をテーブル操作で行えます。

主な機能

  1. 01ファイル、パターン、レコードからテーブルを作成
  2. 02テンプレート化した処理を行ごとに振り分け
  3. 03スキーマで構造化出力を指定
  4. 04バッチサイズと並列数を調整
  5. 05行を絞り込んで未完了分を再試行
  6. 06テーブル行の取得と集計

活用シーン

  1. 01多数のレコードの分類や情報抽出
  2. 02サブエージェントによるファイルの個別レビュー
  3. 03未完了の行だけを再処理
  4. 04JavaScript による処理結果の集計

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/langchain-ai/langchain-skills --skill swarm

インストール後、Claude Code で/swarmを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

scripts/
batching.ts
executor.ts
filter.ts
index.ts
interpolate.ts
table.ts
types.ts
utils.ts

詳細

Swarm

独立した多数の項目を並列処理します。create はテーブルハンドルを作成し、 run は各行に処理を振り分け、結果を統合してテーブルに戻します。1 行が 1 つの作業単位です。Swarm がバッチ処理を自動で行います。

フロー

  1. 作成。 ファイル、glob パターン、または解析済みレコードをソースとして、テーブルを作成します。項目ごとに 1 行です。ハンドルを返します。
  2. 実行。 instruction テンプレートを各行に振り分けます。結果はテーブルに統合して戻されます。{ completed, failed, skipped, failures } を返します。
  3. 集計。 rows() と通常の JS を使って、件数のカウント、フィルタリング、要約を行います。集計のために追加のサブエージェントを起動しないでください。
  4. 再試行。 filter: { column: "<col>", exists: false } を指定して再実行し、失敗した行だけを再処理します。

ソースの選択

glob / filePaths — 1 ファイルにつき 1 行です。各ファイルが独立した作業単位である場合に使用します。各行には { id, file } が設定されます。サブエージェントは {file} プレースホルダーを使ってファイルを自分で読み取ります。

tasks — 作成済みのレコードを直接渡します。データがファイル内(JSONL、CSV、JSON 配列)にある場合に使用します。まず eval 内でファイルを読み込んで解析してから、レコードを渡します。1 レコードにつき 1 行です。複数の項目を 1 行にまとめないでください。

小さなファイル(約 500 行未満)の場合は、1 つのブロック内で解析と作成を行います。

const { create } = await import("@/skills/swarm");
const raw = await tools.readFile({ file_path: "/data.jsonl" });
const records = raw.trim().split("\n").map(l => JSON.parse(l));
const table = await create({ tasks: records });
console.log(table);

大きなファイルの場合は、切り捨てを避けるため、500 行ずつ読み込みます。

const { create } = await import("@/skills/swarm");
let records = [];
let offset = 0;
while (true) {
  const chunk = await tools.readFile({ file_path: "/data.txt", offset, limit: 500 });
  const lines = chunk.split("\n").filter(l => l.trim());
  for (const l of lines) { records.push({ id: `r${records.length}`, text: l }); }
  if (lines.length < 500) break;
  offset += 500;
}
const table = await create({ tasks: records });
console.log(table);

ファイルが大きすぎて 1 回の eval 呼び出しで解析と振り分けを行えない場合は、2 つのブロックに分けます。インポートが必要なのは、swarm 関数を呼び出すブロックだけです。

// eval 1: parse only — no swarm import needed
const raw = await tools.readFile({ file_path: "/data.jsonl" });
globalThis.records = raw.trim().split("\n").map(l => JSON.parse(l));
console.log(`Parsed ${globalThis.records.length} records`);
// eval 2: create and dispatch
const { create, run } = await import("@/skills/swarm");
const table = await create({ tasks: globalThis.records });
const result = await run(table.id, {
  instruction: "Classify {text}",
  responseSchema: {
    type: "object",
    properties: { label: { type: "string" } },
    required: ["label"],
  },
});
console.log(result);

filePaths: ["/data.jsonl"] を渡すと、ファイルを指すテーブルが 1 行 作成されます。ファイル内のレコードごとに 1 行が作成されるわけではありません。

subagentType を使用する場合

分類、抽出、ラベル付け、または構造化出力を使った単一のモデル呼び出しで十分なタスクでは、subagentType を省略します。これがデフォルトで、大幅に低コストかつ高速です。各処理の振り分けは、ツールも反復処理も伴わない、モデルへの直接呼び出しです。

ツール、ファイルアクセス、または複数ステップの推論が必要なタスクでは、subagentType を設定します。各処理の振り分けでは、指定されたサブエージェントによるエージェントループ全体が実行されます。

// Direct model call — classification, no tools needed
await run(table.id, {
  instruction: "Classify {text}",
  responseSchema: { type: "object", properties: { label: { type: "string" } }, required: ["label"] },
});

// Subagent — needs to read files and reason over multiple steps
await run(table.id, {
  subagentType: "reviewer",
  instruction: "Review {file} for security issues.",
  responseSchema: { type: "object", properties: { finding: { type: "string" } }, required: ["finding"] },
});

指示とコンテキスト

instruction は、{column} プレースホルダーを含む項目ごとのテンプレートです。プレースホルダーはフレームワークによって解決されます。列名は生のテンプレート構文としてではなく、併記された値への参照としてプロンプトに表示されます。作業を行うのはサブエージェントです。項目を自分で JS で処理し、結果を行に書き込まないでください。

context は、すべてのサブエージェントプロンプトの先頭に追加される自由形式の文章です。ドメイン用語、分類ルール、例など、共有する背景情報に使用します。

const { create, run } = await import("@/skills/swarm");

const table = await create({ glob: "src/**/*.ts" });
const r = await run(table.id, {
  subagentType: "reviewer",
  instruction: "Review {file} for security issues. List findings or write 'no issues'.",
  context: "TypeScript Express backend using Prisma ORM. Focus on injection, auth bypass, path traversal.",
  responseSchema: {
    type: "object",
    properties: { review: { type: "string" } },
    required: ["review"],
  },
});
console.log(r);
// → { completed: 45, failed: 2, skipped: 0, failures: [...] }

構造化出力

responseSchema は必須です。スキーマのプロパティは各行のトップレベル列になり、サブエージェントが返せる内容を制約します。

const { run } = await import("@/skills/swarm");
await run(table.id, {
  instruction: "Classify: {text}",
  responseSchema: {
    type: "object",
    properties: {
      sentiment: { type: "string", enum: ["positive", "negative", "neutral"] },
    },
    required: ["sentiment"],
  },
});
// Row after: { id: "r1", text: "...", sentiment: "positive" }

バッチ処理

デフォルトでは、swarm は処理の振り分けの合計が 10 回未満になるよう、自動でバッチ処理します。小さなテーブル(行数 ≤10)では、各行に個別のサブエージェント呼び出しが行われます。より大きなテーブルでは、行が自動でグループ化されます。

batchSize を設定して、グループ化を制御します。

  • 数値 — すべての行に共通のバッチサイズです。batchSize: 1 では行ごとの振り分けが強制され、batchSize: 20 では 20 件ずつグループ化されます。
  • 関数 — (row, rowCount) => number。各行に適用するバッチサイズを返します。同じバッチサイズの行はまとめてからチャンクに分割されます。一部の行は単独で処理し、残りはバッチ処理するように混在させられます。
const { create, run } = await import("@/skills/swarm");
const table = await create({ tasks: items });

// Complex items get individual attention; simple ones batch together
await run(table.id, {
  instruction: "Analyze {text}",
  responseSchema: {
    type: "object",
    properties: { analysis: { type: "string" } },
    required: ["analysis"],
  },
  batchSize: (row) => (row.token_count > 1000 ? 1 : 10),
});

評価後のバッチサイズは [1, 50] の範囲に制限されます。

集計

run() の後は、rows() と通常の JS を使用します。追加のサブエージェントは不要です。

const { rows } = await import("@/skills/swarm");
const data = await rows(table.id, { columns: ["sentiment"] });
const counts = {};
data.forEach(r => { counts[r.sentiment] = (counts[r.sentiment] || 0) + 1 });
console.log(counts);
// → { positive: 120, negative: 45, neutral: 35 }

パスの連結

run はテーブルをその場で更新します。呼び出しを連結して、列を追加していきます。

const { create, run } = await import("@/skills/swarm");
const table = await create({ tasks: interviews });
await run(table.id, {
  instruction: "Classify sentiment of {text}",
  responseSchema: {
    type: "object",
    properties: { sentiment: { type: "string", enum: ["positive", "negative", "neutral"] } },
    required: ["sentiment"],
  },
});
await run(table.id, {
  filter: { column: "sentiment", equals: "negative" },
  instruction: "Summarize why {text} had negative sentiment.",
  responseSchema: {
    type: "object",
    properties: { summary: { type: "string" } },
    required: ["summary"],
  },
});

アクションのみのタスク

サブエージェントがデータを返すのではなく、ファイルの書き込みや修正の適用などのアクションを実行する場合は、ステータスまたはマーカーフィールドを含むシンプルなスキーマを使用します。再試行時も exists: false フィルターを使用できます。

const { create, run } = await import("@/skills/swarm");
const fixedSchema = {
  type: "object",
  properties: { fixed: { type: "string" } },
  required: ["fixed"],
};
const table = await create({ glob: "src/**/*.ts" });
await run(table.id, {
  subagentType: "fixer",
  instruction: "Add missing JSDoc to all exported functions in {file}.",
  responseSchema: fixedSchema,
});
// retry any that failed
await run(table.id, {
  subagentType: "fixer",
  instruction: "Add missing JSDoc to all exported functions in {file}.",
  responseSchema: fixedSchema,
  filter: { column: "fixed", exists: false },
});

フィルタリング

{ column: "status", equals: "done" }
{ column: "status", notEquals: "done" }
{ column: "category", in: ["A", "B"] }
{ column: "result", exists: false }      // not yet processed
{ and: [filter1, filter2] }
{ or: [filter1, filter2] }

技術メモ

  • swarm 関数を呼び出すブロックでのみ、@/skills/swarm をインポートしてください。 ファイルの読み込み、解析、globalThis への保存などのデータ準備には、 インポートは不要です。使用するものだけを分割代入してください。例:{ create}、{ run}、 { create, run} など。
  • コンソール出力は約 5 KB に制限されています。 生のファイル内容は決してログに出力せず、 件数と短いサンプルだけを出力してください。
  • eval 内の readFile は、生の内容を返します。行番号の プレフィックスは付きません。 1 回の呼び出しで要求できるのは最大 500 行です。500 行を 超えるファイルは、offset を増やしながらループしてください。
  • ファイルからテーブルを作成するときは、eval 内で読み込んでください。 サンドボックス内で 読み込まれたデータはサンドボックス内にとどまり、エージェントのコンテキストウィンドウには入りません。
  • .swarm/ に直接書き込まないでください。 必ず create() を使用してください。
  • サブエージェントが必要とする情報はすべて、instruction と context に含めてください。 サブエージェントからエージェントのコンテキストは参照できません。
  • 行 ID は一意である必要があります。 重複する ID を生成するソースは create() に拒否されます。tasks の場合は呼び出し側で一意性を保証してください。glob / filePaths の場合は、親ディレクトリによって ID が自動的に区別されます。
  • 不明な列がある場合は、即座にエラーになります。 instruction が {foo} を参照しているにもかかわらず、 一致する行に foo がなければ、run() はサブエージェントがディスパッチされる前にエラーをスローします。

API リファレンス

create(source)

テーブルを作成します。ハンドル { id, count, columns } を返します。

ソース説明
{ glob: "src/**/*.ts" } または { glob: ["src/**/*.ts", "lib/**/*.ts"] }1 つ以上のパターンでファイルを照合します。列:id、file
{ filePaths: ["a.ts", "b.ts"] }明示的なファイルリストです。列:id、file
{ tasks: [{ id: "t1", text: "..." }] }カスタム行です。各行に id が必要です
run(tableId, options)

行に対して作業をディスパッチします。{ completed, failed, skipped, failures } を返します。

オプションデフォルト説明
instruction(必須){column} プレースホルダーを含むテンプレート
responseSchema(必須)JSON Schema(type: "object")です。プロパティが行の列になります
context—各サブエージェントのプロンプトの先頭に追加する文章
filter—一致する行のみをディスパッチします
subagentType—ディスパッチ先のサブエージェント名です。指定すると、エージェントの完全なループを実行します。省略すると、モデルを直接呼び出します
batchSize自動数値、または (row, rowCount) => number です。自動設定ではディスパッチ数は最大 10 です。1 は行ごと、関数は行ごとのサイズ指定です
concurrency10同時に実行するサブエージェントの最大数です(1~10 に制限されます)
rows(tableId, options?)

行を取得します。内容の確認や JavaScript による集計に使用します。

オプション説明
filter一致する行のみを返します
columns指定した列に絞り込みます
limit返される行の最大数

コメント