duck-llm:一种基于 1×RTX 5090 + 32×N100 的异构 LLM 推理系统

“个人娱乐项目”。

没有 NVLink,没有 InfiniBand,只有一台工作机、32 台 Intel N100 小机器——低功耗、4 个 E-core(Alder Lake-N,Gracemont 系)、6W TDP、单通道内存、只有 AVX2,本来更像评测节点或 mini PC,而不是推理集群——和以太网。

最终结果:DeepSeek-V3.2(685B 参数,含 MTP head)decode 吞吐达到 16.171 tok/s104857601是质数吗,2037 tokens 输出,MTP1 接受率 89.0%)。


这是什么

这套系统的出发点不是“我要做一个 LLM 推理系统”,而是一批已经存在的机器——32 台 Intel N100 小盒子,原先用来做在线评测(OJ)节点——能不能硬趟出一条跑大模型的路。

到 2026 年 4 月,这条路的终点数字是:当被问到 104857601是质数吗 时,系统以 16.171 tok/s 的速度连续输出 2037 tokens 回答,运行 DeepSeek-V3.2(685B 参数,含 MTP head),在一台 i9-13900K + RTX 5090 的主机和 32 台 N100 之间,通过以太网协作完成。


一句话介绍该系统

把注意力计算放在单张 RTX 5090 上,把 MoE/FFN 专家层分散发到 32 台 N100 上跑 fp9 GEMV,中间通过 DPDK 用户态网络通信,JudgeDuck-OS 作为远端 kernel launch runtime。这套分工被称为 AFD(Attention-FeedForward Disaggregation)


阅读导航

报告分为 Part I(系统搭建)Part II(优化与结果) 两部分,共 12 章。每章可以独立阅读,但建议按顺序读完 Part I 再进入 Part II。

Part I:系统搭建

标题一句话摘要
1设计目标与硬件约束硬件从哪来、为什么凑在一起、约束如何推导出分离架构
2系统总览四层架构:Python 模型主线 → Rust 编排 → C++ DPDK → JudgeDuck-OS 远端执行
3单核 MLP fp9 起点fp9 格式的动机、位布局设计和第一次进入真实路径
4JudgeDuck-OS 作为 runtime从“一次评测一个 ELF”到“低延迟远端 kernel launcher”的五处改造
5DPDK 与“一鸭三吃”通信栈被数据逼出来的演化路线:socket → async → sendmmsg → DPDK

Part II:优化与结果

标题一句话摘要
6模型接入路径Qwen3 → Qwen3.5 → DeepSeek-V3.2,三条路线的结构差异和共性
7decode 固定成本压缩static KV cache → flash attention 2 → flattened decode → CUDA Graph → Triton fp8 → V3.2 decode context
8fp9 扩展到完整远端路径MoE 接入、sub-128 解锁、same-ELF SMP、prefill、weight cache、persistent judge
9MTP1 dual-lane overlap不加第二组鸭子,把 GPU 和 duck 两条流水线叠起来跑
10方法学roofline 测量、breakdown 分析、forced-cold 验证——不靠感觉靠测量
11最终配置与最终结果多 testcase overview + 代表性 case 详情 + 贡献分解
12负结果、反直觉与未完成项不成立的优化路径、与直觉相反的发现,以及还没做完的事

结果口径说明

首页所列结果来自两组代表性 testcase(02-prime-2k05-long-input-1),均为 2026-04-08 补跑的完整 case 档案,含 per-token 逐字延迟 CSV 和 TPOT 图。所有 7 组 case 的 prompt、output、逐 token CSV、TPOT 图和 stdout/stderr 日志均完整归档,见 测试档案页。更详细的口径和限制条件见第 11 章。


速查

硬件规模

项目数值
在役 duck 数32 × Intel N100(4 核,32 GB DDR4-3200)
host GPU1 × NVIDIA RTX 5090(32 GB GDDR7)
host NIC4 × Intel E810-C 25GbE
网络拓扑4 个隔离广播域,每组 8 duck

代表性 testcase 结果(DeepSeek-V3.2,2026-04-08 补跑)

当前已跑过 7 组完整 testcase,以下选两条最有代表性的。所有 7 组 case 的 prompt、output、逐 token CSV、TPOT 图和原始日志均完整归档,见 测试档案页

指标02-prime-2k(短 prompt 长输出)05-long-input-1(长 prompt 中等输出)
input_len111481
output_len2037567
TTFT0.861 s74.499 s
prefill12.775 tok/s19.880 tok/s
TPOT0.062 s0.070 s
decode16.171 tok/s14.206 tok/s

02-prime-2k (质数查询 prompt,长输出)

input(11 tokens)

<|begin▁of▁sentence|><|User|>104857601是质数吗<|Assistant|><think>
output(2037 tokens)
我们被问到:“104857601是质数吗?” 我们需要检查这个数字是否是质数。注意:1048576 = 2^20。实际上,2^20 = 1048576。所以 104857601 = 1048576 * 100 + 1?不完全是:104857601 可能等于 2^20 * 100 + 1?2^20 = 1,048,576。乘以100得到104,857,600,然后加1得到104,857,601。所以 104857601 = 100 * 2^20 + 1。但这不是一个标准形式。也许它与费马数或梅森数有关?2^20 + 1?2^20 + 1 = 1048577,但我们的数字是104857601,它更大。也许它是 2^20 * 100 + 1 = 2^20 * (100) + 1。或者可能是 2^20 * 100 + 1。但100是10^2。所以它是 2^20 * 10^2 + 1 = (2^10 * 10)^2 + 1?2^10=1024,乘以10=10240,平方=104857600,然后加1得到104857601。所以 104857601 = (10240)^2 + 1。所以它是形式为 n^2+1,其中 n=10240。所以问题是:n^2+1 是质数吗?对于 n=10240,我们需要检查 10240^2+1 是否是质数。

注意:n^2+1 形式的数可以是质数,但并非总是。对于 n=1, 1^2+1=2 是质数;n=2, 4+1=5;n=4, 16+1=17;n=6, 36+1=37;n=10, 100+1=101;等等。但 n=10240 可能很大。我们需要测试 104857601 的素性。

我们可以尝试用一些小的质数进行试除。首先,计算平方根:sqrt(104857601) ≈ 10240.0?实际上,因为 10240^2 = 104857600,所以 sqrt(104857601) = sqrt(10240^2+1) ≈ 10240.0000488。所以我们需要测试所有小于等于 10241 的质数。但 10241 大约是 10000,所以我们需要测试最多 10000 左右的质数。这可行,但手工做很繁琐。也许我们可以找到一些模条件。

注意:104857601 是奇数,所以不能被2整除。数字和:1+0+4+8+5+7+6+0+1 = 32,不能被3整除,所以不能被3整除。除以5?以01结尾,所以不能被5整除。除以7?104857601 ÷ 7?我们来计算。

我们可以使用模运算。或者注意到这个数字可能与已知的质数有关。也许它是 2^25 + 1?2^25 = 33554432,乘以3?不对。

让我们因式分解 n^2+1。对于偶数 n,n^2+1 是奇数,并且可能有一些代数因式分解吗?在整数中,n^2+1 是不可约的,除非 n 是某些特定值。但我们需要检查是否有质因数。

我们可以尝试检查小质数。从 p=7 开始。

检查除以7:104857601 mod 7。计算:7*14979657 = 104857599?实际上,7*14979657 = 7*15000000 = 105000000,减去 7*20343 = 142401,所以 105000000 - 142401 = 104857599。所以 104857601 - 104857599 = 2,所以余数为2。所以不能被7整除。

下一个质数:11。104857601 mod 11。我们可以交替求和:数字交替符号和:1-0+4-8+5-7+6-0+1 = (1+4+5+6+1) - (0+8+7+0) = 17 - 15 = 2。所以余数为2 mod 11?实际上,如果交替和是2,那么原数 mod 11 等于 2 mod 11。所以不能被11整除。

13:104857601 mod 13。计算:13 * 8065970 =?也许更快:104857601 ÷ 13。13*8065970 = 13*8000000=104000000,13*65970=857610,总和 104857610,太大了9。所以 13*8065969 = 104857610 - 13 = 104857597?实际上,104857610 - 13 = 104857597。所以 104857601 - 104857597 = 4,所以余数为4。不能被13整除。

17:104857601 mod 17。计算:17 * 6168094 =?17*6000000=102000000,17*168094= 2857598,总和 102000000+2857598=104857598。所以 104857601 - 104857598 = 3,余数3。

19:104857601 mod 19。19*5518821 =?19*5500000=104500000,19*18821=357599,总和 104500000+357599=104857599。所以余数2。

23:104857601 mod 23。23*4559026 =?23*4559026:23*4500000=103500000,23*59026=1357598,总和 103500000+1357598=104857598。余数3。

29:104857601 mod 29。29*3615786 =?29*3615786:29*3600000=104400000,29*15786=457794,总和 104400000+457794=104857794,太大了193。所以尝试 29*3615785 = 104857794 - 29 = 104857765,仍然大于164?104857601 - 104857765 = -164,所以 29*3615785 太大了。实际上,104857601 ÷ 29 ≈ 3615786.24,所以 29*3615786 = 如上计算 104857794?我们算错了。重新计算:29 * 3615786。更好的方法:使用模运算。104857601 ÷ 29。29 * 3615786:计算 30*3615786 = 108473580,减去 3615786 = 104857794。所以确实是 104857794。所以 29*3615786 = 104857794,比104857601大193。所以 29*3615785 = 104857794 - 29 = 104857765,仍然大164。29*3615784 = 104857765 - 29 = 104857736,大135。29*3615783 = 104857736 - 29 = 104857707,大106。29*3615782 = 104857707 - 29 = 104857678,大77。29*3615781 = 104857678 - 29 = 104857649,大48。29*3615780 = 104857649 - 29 = 104857620,大19。29*3615779 = 104857620 - 29 = 104857591。所以 29*3615779 = 104857591。然后 104857601 - 104857591 = 10,所以余数10。不能被29整除。

31:104857601 mod 31。31*3382503 =?31*3382503:31*3300000=102300000,31*82503=2557593,总和 102300000+2557593=104857593。所以 104857601 - 104857593 = 8,余数8。

37:104857601 mod 37。37*2833989 =?37*2833989:37*2800000=103600000,37*33989=1257593,总和 103600000+1257593=104857593。余数8。

41:104857601 mod 41。41*2557502 =?41*2557502:41*2500000=102500000,41*57502=2357582,总和 102500000+2357582=104857582。余数19。

43:104857601 mod 43。43*2438544 =?43*2438544:43*2400000=103200000,43*38544=1657392,总和 103200000+1657392=104857392。余数209?104857601-104857392=209。209除以43=4*43=172,余数37。所以余数37?实际上,209 mod 43 = 209 - 4*43 = 209-172=37。所以原数 mod 43 = 37。

47:104857601 mod 47。47*2231012 =?47*2231012:47*2200000=103400000,47*31012=1457564,总和 103400000+1457564=104857564。余数37。

53:

05-long-input-1 (包含本项目技术报告的长 prompt)

input(1481 tokens)
<|begin▁of▁sentence|><|User|>你觉得这个项目真的能做到吗?为什么?

duck-llm:一种基于 1×RTX 5090 + 32×N100 的异构 LLM 推理系统
“个人娱乐项目”。

没有 NVLink,没有 InfiniBand,只有一台工作机、32 台 Intel N100 小机器——低功耗、4 个 E-core(Alder Lake-N,Gracemont 系)、6W TDP、单通道内存、只有 AVX2,本来更像评测节点或 mini PC,而不是推理集群——和以太网。

最终结果:DeepSeek-V3.2(685B 参数,含 MTP head)decode 吞吐达到 15.301 tok/s,MTP1 接受率 87.1%。

这是什么
这套系统的出发点不是“我要做一个 LLM 推理系统”,而是一批已经存在的机器——32 台 Intel N100 小盒子,原先用来做在线评测(OJ)节点——能不能硬趟出一条跑大模型的路。

到 2026 年 3 月底,这条路的终点数字是:15.301 tok/s,运行 DeepSeek-V3.2(685B 参数,含 MTP head),在一台 i9-13900K + RTX 5090 的主机和 32 台 N100 之间,通过以太网协作完成。

一句话介绍该系统
把注意力计算放在单张 RTX 5090 上,把 MoE/FFN 专家层分散发到 32 台 N100 上跑 fp9 GEMV,中间通过 DPDK 用户态网络通信,JudgeDuck-OS 作为远端 kernel launch runtime。这套分工被称为 AFD(Attention-FeedForward Disaggregation)。

阅读导航
报告分为 Part I(系统搭建) 和 Part II(优化与结果) 两部分,共 12 章。每章可以独立阅读,但建议按顺序读完 Part I 再进入 Part II。

Part I:系统搭建
章	标题	一句话摘要
1	设计目标与硬件约束	硬件从哪来、为什么凑在一起、约束如何推导出分离架构
2	系统总览	四层架构:Python 模型主线 → Rust 编排 → C++ DPDK → JudgeDuck-OS 远端执行
3	单核 MLP fp9 起点	fp9 格式的动机、位布局设计和第一次进入真实路径
4	JudgeDuck-OS 作为 runtime	从“一次评测一个 ELF”到“低延迟远端 kernel launcher”的五处改造
5	DPDK 与“一鸭三吃”	通信栈被数据逼出来的演化路线:socket → async → sendmmsg → DPDK
Part II:优化与结果
章	标题	一句话摘要
6	模型接入路径	Qwen3 → Qwen3.5 → DeepSeek-V3.2,三条路线的结构差异和共性
7	decode 固定成本压缩	static KV cache → flash attention 2 → flattened decode → CUDA Graph → Triton fp8 → V3.2 decode context
8	fp9 扩展到完整远端路径	MoE 接入、sub-128 解锁、same-ELF SMP、prefill、weight cache、persistent judge
9	MTP1 dual-lane overlap	不加第二组鸭子,把 GPU 和 duck 两条流水线叠起来跑
10	方法学	roofline 测量、breakdown 分析、forced-cold 验证——不靠感觉靠测量
11	最终配置与最终结果	1024 token 长跑:15.301 tok/s,accept=1 共 891/1023,各项贡献分解
12	负结果、反直觉与未完成项	不成立的优化路径、与直觉相反的发现,以及还没做完的事
结果口径说明
首页所列结果来自一次 1024 token 单 prompt 长跑(prompt:104857601是质数吗),max_model_len=2048。

这是当前最佳工程路径的终点数字,不是标准 benchmark 汇总。更详细的口径和限制条件见第 11 章。

速查
硬件规模
项目	数值
在役 duck 数	32 × Intel N100(4 核,32 GB DDR4-3200)
host GPU	1 × NVIDIA RTX 5090(32 GB GDDR7)
host NIC	4 × Intel E810-C 25GbE
网络拓扑	4 个隔离广播域,每组 8 duck

最终结果(DeepSeek-V3.2,真实长跑)
同一轮 1024 token 长跑证据包(prompt:104857601是质数吗,max_model_len=2048)。

指标	数值
decode 吞吐	15.301 tok/s
TTFT	0.857 s
TPOT	65 ms
MTP1 accept=1	891 / 1023 ≈ 87.1%

关键机制指标(V3.2 真实系统内部)
这些是解释“为什么最终结果成立”的局部指标,不是端到端吞吐。

指标	数值	来源
persistent judge_gap	418µs → 78µs	第 8 章
dual-lane overlap ratio	~0.434(549 step 均值)	第 9 章
duck 侧参数吞吐	15.0~15.7 Gparam/s	第 11 章
跨模型里程碑
证明同一套系统架构能在不同模型上跑通。

模型	改动	指标	来源
Qwen3-30B-A3B tp24	flattened runtime + CUDA Graph	18 → 24 tok/s	第 7 章
Qwen3.5-35B-A3B tp16	flattened decode	24.2 → 37.9 tok/s	第 7 章
专项 bench / 方法学
以下不是最终系统吞吐,而是内核级或方法学专项测量。

指标	数值	来源
fp9 single-core kernel	~5.4 Gparam/s	第 8 章
MoE fp9 hot (4-core methodology breakdown, wall)	~20.30 GB/s	第 10 章

关键 commit
commit	说明
ab33e9e	fp9: prune dead common paths and land final 64/128 kernels
d32c6fe	deepseek_v32: land MTP1 two-lane online path and trace-ready runtime
279d749	Enable persistent fp9 judge by default for decode forward
e553d30	Fix DeepSeek V3.2 flattened active_len and add critical tests
项目代码
duck-llm:模型加载、host runtime、GPU/duck 协同、FP8/FP9 路径、DPDK 集成
JudgeDuck-OS:远端 kernel launch runtime、same-ELF SMP、persistent judge 会话
<|Assistant|><think>
output(567 tokens)
我们被问到:“你觉得这个项目真的能做到吗?为什么?” 关于一个名为“duck-llm”的项目,它描述了一种基于1×RTX 5090 + 32×N100的异构LLM推理系统。这是一个个人娱乐项目。他们声称在没有NVLink和InfiniBand的情况下,只有一台工作机和32台Intel N100小机器,通过以太网,最终实现了DeepSeek-V3.2(685B参数)的解码吞吐达到15.301 tok/s,MTP1接受率87.1%。

问题:我们是否相信这个项目真的能做到?为什么?

我们需要分析这个项目的可行性。首先,项目描述了一个非常规的硬件设置:一个强大的GPU(RTX 5090,假设是未来的GPU,但可能是模拟或假设)和许多低功耗的小型PC(N100)。它们通过以太网连接,没有高速互连。他们声称通过将注意力计算放在GPU上,将MoE/FFN专家层分散到N100上运行fp9 GEMV,实现了不错的性能。

关键点:
- 模型是DeepSeek-V3.2,有685B参数,是一个混合专家模型(MoE)。MoE模型只有一部分专家在每层被激活,因此可能适合将专家分散到多个设备上。
- 他们使用了32台N100,每台有4个E-core(Gracemont),6W TDP,单通道内存,只有AVX2。这些是低功耗、低性能的CPU。
- 他们使用了DPDK进行用户态网络通信,以及一个自定义的远端内核启动运行时(JudgeDuck-OS)。
- 报告了15.301 tok/s的解码吞吐,TTFT为0.857秒,TPOT为65毫秒。

我们需要考虑这个性能数字是否合理。15.3 tok/s对于685B模型来说,如果是在单个GPU上(即使是RTX 5090),也是不可能的,因为内存带宽和计算限制。但是,这里他们使用了32个额外的低功耗CPU节点来帮助计算MoE层。

在MoE模型中,前馈层(FFN)是专家层,通常只有少数专家被激活(例如,DeepSeek-V3.2可能使用MoE,每层有多个专家,但每个token只路由到少数专家)。因此,对于每个token,只需要计算一部分参数。如果他们将专家分布到不同的N100节点上,那么每个节点只需要计算一部分。但是,他们需要为每个token传输激活值到相应的专家节点,然后返回结果。这引入了网络开销。

他们声称使用了fp9格式(自定义的9位浮点)来减少数据传输和计算。N100只支持AVX2,因此

关键机制指标(V3.2 真实系统内部)

这些是解释“为什么最终结果成立”的局部指标,不是端到端吞吐。

指标数值来源
persistent judge_gap418µs → 78µs第 8 章
dual-lane overlap ratio~0.434(549 step 均值)第 9 章
duck 侧参数吞吐15.0~15.7 Gparam/s第 11 章

跨模型里程碑

证明同一套系统架构能在不同模型上跑通。

模型改动指标来源
Qwen3-30B-A3B tp24flattened runtime + CUDA Graph18 → 24 tok/s第 7 章
Qwen3.5-35B-A3B tp16flattened decode24.2 → 37.9 tok/s第 7 章

专项 bench / 方法学

以下不是最终系统吞吐,而是内核级或方法学专项测量。

指标数值来源
fp9 single-core kernel~5.4 Gparam/s第 8 章
MoE fp9 hot (4-core methodology breakdown, wall)~20.30 GB/s第 10 章

关键 commit

commit说明
ab33e9efp9: prune dead common paths and land final 64/128 kernels
d32c6fedeepseek_v32: land MTP1 two-lane online path and trace-ready runtime
279d749Enable persistent fp9 judge by default for decode forward
e553d30Fix DeepSeek V3.2 flattened active_len and add critical tests

项目代码

  • duck-llm:模型加载、host runtime、GPU/duck 协同、FP8/FP9 路径、DPDK 集成
  • JudgeDuck-OS:远端 kernel launch runtime、same-ELF SMP、persistent judge 会话

外部资源


继续阅读


最后修改:2026-04-12。


项目声明 / Project Disclaimer

本项目为作者以个人身份、利用业余时间推进的个人娱乐项目;除非另有明确说明,它与作者的任何雇主、客户、学校、单位或其他组织均无合作、雇佣、委托、赞助或背书关系,也不代表任何该等主体的立场。除普通个人捐赠外,本项目未获得任何资金支持。

This project is a personal hobby project developed by the author in a personal capacity and in personal time. Unless explicitly stated otherwise, it has no collaboration, employment, commission, sponsorship, endorsement, or institutional affiliation with any employer, client, school, partner organization, or other entity, and it does not represent any such party's views. No funding was received for this project except ordinary personal donations.

许可 / License

除非另有说明,本页原创文字、本站原创图片与本站原创图表采用 CC BY-NC-ND 4.0 发布。
转载时请保留原文标题、署名“JudgeDuck AI”、发布日期与原始链接;禁止商业转载、改写、摘编、翻译或基于原文创作演绎作品。

第三方商标、外部链接内容,以及文中另有标注的材料,不在上述许可范围内。

Unless otherwise noted, the original text, original images, and original figures on this page are licensed under the Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License.