拓冰建站拓冰建站
首页 / 资讯中心 / 正文

exo 如何配置并运行 prefill/decode 分离基准测试?instance-links 与 prefill-decode.toml 实战

exo 如何配置并运行 prefill/decode 分离基准测试instance-links 与 prefill-decode.toml 实战【免费下载链接】exoRun frontier AI locally.项目地址: https://gitcode.com/GitHub_Trending/exo8/exo如果你在 exo 集群上想让 prefill提示词处理和 decode逐 token 生成跑在不同机器上并量化这种分离带来的延迟变化仓库里的 bench/prefill_decode_bench.py 就是现成的工具它在集群里启动两个 MLX 实例通过/v1/instance-links接口把一个标记为 Prefill 源、另一个标记为 Decode 目标然后向/bench/chat/completions端点发请求测速。本文围绕一条可照做的路径展开先确认集群与模型就位再配置 bench/prefill-decode.toml 或用命令行参数运行最后核对输出并了解脚本的自动清理行为。原理与边界这个脚本在做什么bench/prefill_decode_bench.py 的模块说明把整个流程交代得很清楚在集群上创建 prefill 实例和 decode 实例并分别等待其就绪调用POST /v1/instance-links请求体为{prefill_instances: [prefill_instance_id], decode_instances: [decode_instance_id]}把两个实例建立链接向 decode 实例发送 chat completion 请求。master 会把请求路由到 decode 实例并打上指向 prefill 实例的prefill_endpoint标记worker 按请求自行判断是否把 prefill 发到远端每完成一轮在finally块中删除该 instance link 并删除两个实例——也就是说脚本结束时集群会恢复到没有这两个实例的状态无需手工清理。判断是否真的走了远端 prefill的阈值在引擎代码里src/exo/worker/engines/mlx/generator/batch_generate.py 定义了REMOTE_PREFILL_MIN_TOKENS 1000未命中缓存的 token 数超过它才会触发远端 prefill。这也是脚本强制--pp必须大于 1000 的原因直接传--pp 512会报错退出pp512 must be 1000 (remote prefill triggers when uncached 1000)测试请求走的是 docs/METHODOLOGY.md 描述的/bench/chat/completions端点与普通 chat completion 有三点不同KV prefix cache 默认关闭每个请求都从冷缓存开始保证 prefill 计时不受先前请求影响EOS token 被 logits processor 屏蔽模型必须正好生成max_tokens个 token避免提前收尾影响 TPS 对比不解析模型输出只拼接原始 token 文本。prompt 长度则是用 tokenizer 的apply_chat_template()做二分搜索把重复的 atom 字符串凑到目标 token 数实际 token 数会作为pp_tokens记录在每条结果里。由于 chat 模板的开销非常小的 pp 可能构造不出精确长度。前置条件一个已在运行的 exo 集群master API 可通过http://host:52415访问基准脚本默认端口 52415可用--host、--port或环境变量EXO_HOST/EXO_PORT覆盖。要测试的模型已存在于集群的模型列表中脚本会先通过GET /models解析模型短名name或 HuggingFace 全名hugging_face_id都不匹配时直接抛Model not found in /models: id。模型不在列表中时加--force-download会让脚本通过POST /models/add从 HuggingFace 添加并触发下载。集群中至少有两个节点上存在该模型的有效 placement。脚本在同模型场景下会挑选两个节点互不相同的 placement 分别作为 prefill 与 decode不满足时退出并打印Need at least two distinct-node MLX placements for the same model.。placement 需要满足--instance-metaring/jaccl/both默认both与--shardingpipeline/tensor/both默认both的过滤条件以及--min-nodes/--max-nodes默认 1/4的节点数范围。运行环境支持uv run python。脚本依赖仓库内的 tools/src/exo_tools 里的ExoClient与 harness 工具函数。先用 --dry-run 确认 placement 选择--dry-run只列出脚本选中或即将选择的 placement 就退出不会创建实例适合在正式跑之前确认uv run python bench/prefill_decode_bench.py \ --model mlx-community/gpt-oss-20b-MXFP4-Q8 \ --pp 4096 --tg 512 \ --instance-meta ring \ --sharding pipeline \ --min-nodes 1 --max-nodes 1 \ --dry-run脚本会打印两行关键日志确认 prefill 与 decode 分别落在哪个节点、哪个 instance id 上下面是脚本日志的格式示例节点名与 id 以你的集群为准PREFILL: ring / nodes[...] (mike) / gpt-oss-20b-MXFP4-Q8 (mlx-community/gpt-oss-20b-MXFP4-Q8) / instance_id... DECODE: ring / nodes[...] (james) / gpt-oss-20b-MXFP4-Q8 (mlx-community/gpt-oss-20b-MXFP4-Q8) / instance_id...如果不指定--prefill-node/--decode-node节点 friendly name可用集群 state 中的nodeIdentities核对脚本自动从同一模型的 placement 里挑两个节点不同的组合只要指定了其中一个另一个侧仍会从全量 placement 里选。配置 prefill-decode.toml仓库自带一份 bench/prefill-decode.toml顶层键作用于整个基准[prefill]与[decode]两节分别设置两侧的 placement 过滤条件instance_meta、sharding、min_nodes、max_nodes以及可选的按侧model。文件头部注释给出的用法就是uv run python bench/prefill_decode_bench.py --config bench/prefill-decode.toml仓库中这份配置的原样内容如下——注意node mike/node james、host james都是作者集群的示例值使用前要替换成你集群的实际节点名与 master 地址# Prefill/Decode disaggregation benchmark config. # # Top-level keys are bench-wide. [prefill] and [decode] sections set per-side # placement filters and (optionally) per-side model. host james port 52415 timeout 7200.0 settle_timeout 60.0 # Workload pp [4096] tg [512] repeat 1 warmup 0 json_out bench/prefill_decode_results.json [prefill] model mlx-community/gpt-oss-20b-MXFP4-Q8 node mike instance_meta ring sharding pipeline min_nodes 1 max_nodes 1 [decode] model mlx-community/gpt-oss-20b-MXFP4-Q8 node james instance_meta ring sharding pipeline min_nodes 1 max_nodes 1各键的实际作用对照 bench/prefill_decode_bench.py 的参数定义host/port/timeout/settle_timeoutAPI 地址、HTTP 超时默认 7200 秒、等待集群产出有效 placement 的最长秒数默认 60 秒0 表示只试一次。集群刚启动、placement 还没稳定时这个等待尤其有用。pp/tgprompt token 提示长度与生成长度支持列表两个列表等长时按 zip 成对执行tandem 模式不等长时自动变成全组合product 模式也可用--all-combinations强制全组合。repeat/warmup每个 (pp, tg) 对的重复次数必须 ≥ 1与预热次数warmup 复用第一个 pp/tg 对不计入结果。json_out逐次运行原始结果的 JSON 输出路径脚本默认值就是bench/prefill_decode_results.json--stdout可改为直接打印。[prefill]/[decode]的model两侧可以不同模型node是节点 friendly nameinstance_meta、sharding、min_nodes、max_nodes只作用于该侧。配置与命令行的关系CLI 参数优先于 toml。脚本先把 toml 里的model、pp、tg注入命令行参数以通过必填校验再把其余顶层键合入参数仅在参数取默认值时生效。所以--pp、--tg、--repeat等直接传在命令行上时会覆盖 toml 里的值不用改文件。运行基准并核对输出一条最短主路径全部用命令行参数uv run python bench/prefill_decode_bench.py \ --host 你的master地址 --port 52415 \ --model mlx-community/gpt-oss-20b-MXFP4-Q8 \ --prefill-node mike --decode-node james \ --pp 4096 --tg 512 --repeat 3 --warmup 1 \ --instance-meta ring --sharding pipeline \ --min-nodes 1 --max-nodes 1 \ --json-out bench/prefill_decode_results.json其中你的master地址、节点名mike/james和模型 id 都是需要按你的集群替换的值模型 id 可用GET /models返回的短名或 HuggingFace 全名。执行过程中按顺序会看到这些日志可作为检查点PREFILL:/DECODE:两行 placement 摘要与--dry-run输出相同Planning 阶段脚本检查各节点磁盘空间、必要时触发模型下载并等待完成。模型已缓存则直接跳过。如果磁盘不足脚本会报错提示Insufficient disk on node_id ... Use --danger-delete-downloads to free space.Creating prefill instance...→Prefill instance ready随后Creating decode instance...→Decode instance readyCreating prefill instance link之后打印Link created: linkId。如果链接没出现在集群 state 里脚本报Link did not appear in state.并退出 phase: disaggregated ... 每个 (pp, tg) 对跑完后打印均值行prompt_tps、gen_tps、prompt_tokens、gen_tokens、peak_memory、avg_elapsed。结束时脚本在finally块中删除 instance link 并删除两个实例等待其从 state 中消失后把逐次运行结果写入--json-out指定的文件。JSON 中每条记录包含elapsed_s、output_text_preview前 200 字符、statsprompt_tps、generation_tps、prompt_tokens、generation_tokens、peak_memory_usage、pp_tokens实际 token 数、phase以及两侧模型、instance id 与节点等元数据。可选分支用 --compare-baseline 对照 decode_alone加--compare-baseline后脚本会多跑基线先跑prefill_alone阶段把请求发到 prefill 模型自身再在正式disaggregated阶段后删除 link 与 prefill 实例跑decode_alonedecode 实例自己完成 prefill最后打印三阶段对照表并计算相对加速比文档示例格式数值以你的运行结果为准──────────────────────────────────────────────────────────────── pp4096 tg512 ──────────────────────────────────────────────────────────────── phase elapsed prompt_tps gen_tps disaggregated 12.34s 331.9 42.10 decode_alone 20.87s 196.1 41.80 prefill_alone 15.02s 272.7 43.00 speedup vs decode_alone: 1.69x speedup vs prefill_alone: 1.22x ────────────────────────────────────────────────────────────────注意该分支会让脚本额外删除 prefill 实例日志会打印Removing link and prefill instance to isolate decode_alone.这是基线测量的必要步骤不带该参数时 prefill 实例会一直存活到脚本收尾。排查与限制找不到 placementNo placement on prefill node .../No placement on decode node ...或No placement found for prefill model id说明过滤条件instance_meta/sharding/节点数范围/指定节点在该侧没有命中。先放宽--instance-meta both --sharding both或先跑--dry-run看脚本实际选中了什么。磁盘不足报错信息里会给出需要多少 GB、现有多少 GB。加--danger-delete-downloads会按从小到大删除节点上已下载的模型腾空间这会真实删除节点上的模型文件只在确认可以丢这些模型时启用。pp 太小的请求不会触发远端 prefill阈值是REMOTE_PREFILL_MIN_TOKENS 1000见 src/exo/worker/engines/mlx/generator/batch_generate.py脚本对pp 1000直接拒绝跑分离场景时保持 pp 在 1000 以上。模型解析失败Model not found in /models时检查模型名是否在GET /models列表里不在列表且可联网时可用--force-download让脚本经POST /models/add拉取。结果数值不要当固定预期上文所有日志与表格均为脚本打印格式或文档示例实际 TPS、耗时、内存以你的硬件与模型为准bench/METHODOLOGY.md 中的 TPS 口径generation_tps (completion_tokens - 1) / gen_span首 token 不计入分子也意味着 tg1 不可用。清理是自动的但幂等性有限脚本结束时删除 link 与实例是收尾动作的一部分若中途被强杀残留实例需要自行通过DELETE /instance/{instance_id}清理。继续深入bench/METHODOLOGY.mdprompt 构造、计时口径、prefix cache 模式与输出格式写分析脚本前值得通读一遍。docs/api.md/instance、/instance/await、/bench/chat/completions等端点的请求与响应说明instance-links 的四个端点GET/POST/v1/instance-links、PUT/DELETE/v1/instance-links/{link_id}在 src/exo/api/main.py 中注册状态结构定义在 src/exo/shared/types/instance_link.py。bench/exo_bench.py 是面向单实例各 placement 配置的通用基准工具与本脚本共用PromptSizer、parse_int_list等工具函数可对照使用。【免费下载链接】exoRun frontier AI locally.项目地址: https://gitcode.com/GitHub_Trending/exo8/exo创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门