swarm-tree 以 YAML 樹和 CLI 編排多模型智能體
I drew a tree of AI agents on my phone and then built it: meet swarm-tree
DEV Community 作者 hao li 打造 swarm-tree,讓用戶以 YAML 樹和 CLI 編排由不同模型供應商執行的多層 AI 智能體。葉節點直接處理任務,內部節點會拆分子任務、並行執行子節點,再整合結果。工具只用標準庫,並可用確定性 mock 執行 dry-run,無需 API key 或費用;每次執行亦會輸出完整 JSON 紀錄。
I was sketching an idea on my phone last night: a tree. One circle at the top, three circles under it, and one of those with two circles of its own. Each circle is an AI agent. The top one coordinates, the ones below it do the work, and — here's the part I liked — each circle can run on a different LLM provider. The contrarian analyst on Grok, the researcher on Gemini, the planner on GPT, all coordinated by Claude at the top.
I build a lot of small agent tools, and the orchestration story is usually "one agent, one model, one long prompt." Multi-agent frameworks exist, but they tend to drag in SDKs, servers, and config formats that need their own tutorial. I wanted the thing I drew: a tree, in a YAML file, run from a CLI.
So I built swarm-tree. It's tiny — standard library only, no vendor SDKs, every provider call goes through plain urllib.
How it works
You describe the tree in tree.yaml. Each node has a name, a provider, a model, a role (system prompt), and optional children:
name: orchestrator
provider: anthropic
model: claude-sonnet-4-5
role: You are the top-level coordinator...
children:
- name: grok-agent
provider: xai
model: grok-4
role: You are a contrarian analyst...
- name: gpt-agent
provider: openai
model: gpt-5
role: You are a planner...
children:
- name: code-reviewer
provider: deepseek
model: deepseek-chat
role: You review code diffs...
Then:
swarm-tree run --tree tree.yaml --task "Design a weekend hackathon project"
The semantics are dead simple:
- Leaf nodes make one provider call with (role + task) and return text.
- Internal nodes do three things: ask their provider to split the task into one subtask per child, run all children in parallel, then ask their provider again to merge the child results into a final answer.
After the run you get the finished tree as ASCII art (each node: name, provider/model, status, timing, truncated result), the root's final answer printed out, and a full JSON transcript — every prompt, every raw response, every timing — so the whole run is auditable.
The part I'm proudest of: --dry-run
swarm-tree run --tree tree.yaml --task "..." --dry-run
Dry-run swaps every provider for a deterministic mock. No API keys, no cost, and the whole pipeline — decompose, parallel children, synthesize, transcript — runs exactly like the live path. It's how the 36 unit tests run, and it's how you demo the tool to someone without handing them your API keys.
What I learned building it
Decompose is a parsing problem. I ask the coordinator model for "a numbered list with exactly N items," and then I have to deal with the reality that models don't always comply. There's a small parser that extracts numbered items and a fallback that distributes raw lines when the numbering is off. Robustness lives in the fallback, not the prompt.
Partial transcripts matter more than clean exits. When a child agent fails mid-run, I wanted to still see everything that happened — the decompose call, the sibling results, the exact error. So child records are attached to the tree before threads start, and execute_tree always returns the root record even on failure. Debugging a failed run from its transcript is the whole point of having a transcript.
Five providers is really one client. Anthropic has its own messages API and Gemini has its own generateContent endpoint, but OpenAI, xAI, and DeepSeek all speak the chat-completions wire format. One _build function, one _extract function, urllib underneath. No SDKs means no dependency surprises and no version pinning.
The repo is MIT, the package is swarm-tree on PyPI (well — the dist is built, I'm uploading on my usual drip schedule), and I'd love to hear what tree shapes people actually want to run. The weirdest useful tree wins.
來源:DEV Community · dev.to