|
| 1 | +# exo 源码架构分析 — Hippo 集成参考 |
| 2 | + |
| 3 | +**分析日期**: 2026-04-19 |
| 4 | +**版本**: exo v0.3.69 |
| 5 | +**License**: Apache 2.0 ✅ |
| 6 | +**语言**: Python + Rust(网络层) |
| 7 | + |
| 8 | +--- |
| 9 | + |
| 10 | +## 核心架构 |
| 11 | + |
| 12 | +``` |
| 13 | +exo master (协调器) |
| 14 | +├── placement.py — 分片调度策略 |
| 15 | +├── placement_utils.py — 按内存比例分配层 |
| 16 | +└── topology.py — 网络拓扑管理 |
| 17 | +
|
| 18 | +exo worker (工作节点) |
| 19 | +├── runner/llm_inference/ — 推理执行 |
| 20 | +│ ├── runner.py — Runner 生命周期 |
| 21 | +│ └── batch_generator.py — 批量生成 |
| 22 | +├── engines/mlx/ — MLX 引擎 |
| 23 | +│ ├── auto_parallel.py — 自动并行 |
| 24 | +│ ├── cache.py — KV cache |
| 25 | +│ └── generator/ — 生成器 |
| 26 | +└── plan.py — 执行计划 |
| 27 | +
|
| 28 | +exo routing (通信) |
| 29 | +├── router.py — 消息路由 |
| 30 | +├── event_router.py — 事件分发 |
| 31 | +└── topics.py — 发布/订阅 |
| 32 | +
|
| 33 | +exo api (对外接口) |
| 34 | +├── adapters/chat_completions.py — OpenAI 兼容 |
| 35 | +├── adapters/ollama.py — Ollama 兼容 |
| 36 | +└── adapters/claude.py — Claude API 兼容 |
| 37 | +
|
| 38 | +rust/networking (底层通信) |
| 39 | +├── discovery.rs — mDNS/swarm 发现 |
| 40 | +└── swarm.rs — P2P 通信 |
| 41 | +``` |
| 42 | + |
| 43 | +## 分片策略(placement_utils.py) |
| 44 | + |
| 45 | +**核心函数**: `allocate_layers_proportionally()` |
| 46 | + |
| 47 | +```python |
| 48 | +# 按可用内存比例分配模型层 |
| 49 | +def allocate_layers_proportionally( |
| 50 | + total_layers: int, |
| 51 | + memory_fractions: list[float], # 每台机器的内存占比 |
| 52 | +) -> list[int]: # 每台机器分配的层数 |
| 53 | +``` |
| 54 | + |
| 55 | +**示例**(双 M4 16GB 跑 Qwen3-35B 48层): |
| 56 | +- M4 #1: 13GB / 26GB = 50% → 24 层 |
| 57 | +- M4 #2: 13GB / 26GB = 50% → 24 层 |
| 58 | + |
| 59 | +**分片类型**: |
| 60 | +- `PipelineShardMetadata` — Pipeline 并行(逐层传递 hidden state) |
| 61 | +- `TensorShardMetadata` — Tensor 并行(层内切分矩阵) |
| 62 | +- `CfgShardMetadata` — 条件推理(MoE 专家分发) |
| 63 | + |
| 64 | +## 关键设计决策 |
| 65 | + |
| 66 | +### 1. Pipeline Parallelism(默认) |
| 67 | +- 每个 Worker 负责连续的层 |
| 68 | +- Hidden state 通过网络传递到下一个 Worker |
| 69 | +- 简单、延迟可预测、适合家庭网络 |
| 70 | + |
| 71 | +### 2. Ring 通信(MLX) |
| 72 | +- `MlxRingInstance` — MLX ring backend 分布式 |
| 73 | +- 利用 `mx.distributed` 的 send/recv |
| 74 | +- 需要 `MLX_RANK` + `MLX_HOSTFILE` |
| 75 | + |
| 76 | +### 3. JAGGR 通信(自定义) |
| 77 | +- `MlxJacclInstance` — exo 自定义的集合通信 |
| 78 | +- 比 ring 更灵活,支持 RDMA |
| 79 | +- Rust 实现,性能更好 |
| 80 | + |
| 81 | +### 4. 设备发现 |
| 82 | +- mDNS(和 Hippo 一样) |
| 83 | +- + Bootstrap peers(手动指定) |
| 84 | +- + Swarm 协议(P2P 扩散) |
| 85 | + |
| 86 | +## Hippo 可借鉴的部分 |
| 87 | + |
| 88 | +| 组件 | exo 实现 | Hippo 应该 | |
| 89 | +|------|---------|-----------| |
| 90 | +| 分片策略 | `allocate_layers_proportionally` | 直接借鉴,简单有效 | |
| 91 | +| Pipeline 调度 | Runner + Event 系统 | 简化版,用 asyncio | |
| 92 | +| 设备发现 | mDNS + Rust swarm | 已有(Phase 0) | |
| 93 | +| MLX 分布式 | ring/jaccl | 借鉴 ring 接口 | |
| 94 | +| API 兼容 | OpenAI/Ollama/Claude | 已有(Phase 0) | |
| 95 | + |
| 96 | +## Hippo 不应该依赖的部分 |
| 97 | + |
| 98 | +| 组件 | 原因 | |
| 99 | +|------|------| |
| 100 | +| exo 的 Rust 网络层 | 太重,Hippo 用 Python aiohttp 足够 | |
| 101 | +| exo 的完整 API 层 | Hippo 已有自己的 | |
| 102 | +| exo 的 election 机制 | 家庭场景不需要选主 | |
| 103 | +| exo 的 image pipeline | Hippo 专注 LLM | |
| 104 | + |
| 105 | +## 集成策略 |
| 106 | + |
| 107 | +**不 import exo**,而是借鉴核心算法 + 可选进程级集成: |
| 108 | + |
| 109 | +```python |
| 110 | +# 借鉴算法(Hippo 自己实现) |
| 111 | +class PipelineScheduler: |
| 112 | + def allocate_layers(self, total_layers, workers): |
| 113 | + # 源自 exo 的 allocate_layers_proportionally |
| 114 | + memory_fractions = [w.memory / total for w in workers] |
| 115 | + return allocate_layers_proportionally(total_layers, memory_fractions) |
| 116 | + |
| 117 | +# 可选集成(进程级,不 import) |
| 118 | +class ExoBackend(InferenceBackend): |
| 119 | + async def start(self): |
| 120 | + self._process = subprocess.Popen(["exo", ...]) |
| 121 | + async def generate(self, prompt): |
| 122 | + # 通过 HTTP API 调用 exo |
| 123 | + async with aiohttp.ClientSession() as session: |
| 124 | + resp = await session.post("http://localhost:8000/v1/chat/completions", ...) |
| 125 | +``` |
| 126 | + |
| 127 | +--- |
| 128 | + |
| 129 | +**结论**: exo 的核心分片算法(~200行)值得直接借鉴。 |
| 130 | +完整集成用进程级(subprocess + HTTP),不深度依赖。 |
0 commit comments