夜雨聆风学习资料网

ARTICLE · 1060591

《手搓 PIH》01|一切皆可插件,为什么还要从零造一个推理框架?

《手搓 PIH》01|一切皆可插件,为什么还要从零造一个推理框架?

“一切皆可插件”听起来像一句激进的架构口号:模型可以替换,CUDA backend 可以替换,量化、通信、显存扩展和服务接口也都可以按需装配。服务器部署哪个模型,就只安装与这个模型、这台机器和这项服务有关的能力。

这个想法受到 DeepSeek Harness 的启发。这里的 Harness 不是一种新的推理算法。在软件工程中,Harness 通常指负责组织、配置和驱动一组组件的承载层。放到 PIH 中,它定义插件怎样连接、以什么顺序启动、共享哪些能力,以及失败后如何收回资源,但不把模型计算、设备执行和服务协议全部实现一遍。它更接近推理系统的装配与运行框架:重点不在亲自完成每项计算,而在让一组可替换部件按照确定规则协同工作。

沿着这个边界继续推演,问题就出现了:如果具体能力都能从 Harness 外部接入,一个推理系统能否不再以“尽可能多地内置能力”为前提,而是只装配一次部署真正需要的模型、平台与功能?

今天要部署大模型,vLLM、SGLang、TensorRT-LLM 已经提供了成熟方案。它们支持大量模型、硬件平台、量化格式与并行策略,也经过了真实生产环境的长期打磨。仅仅为了让模型生成 token,没有必要再造一个推理框架。

于是有了 PIH:Plugin-first Inference Harness。它既是一次从零理解 LLM 推理全栈的工程实践,也是对插件化推理架构的一次探索。

从零实现的价值不在于重复已有接口

成熟框架把大部分复杂性封装在稳定接口之后。用户提交模型路径与服务参数,框架便会处理权重加载、显存分配、请求调度、KV Cache 和 kernel 执行。这种封装是框架价值的一部分,却也使许多关键机制不再直接可见。

一次生成究竟怎样发生?Checkpoint 中的 tensor 如何变成设备上的权重?Prefill 和 Decode 为什么需要不同的执行方式?KV Cache 如何改变 Attention 的数据依赖?多个请求怎样共享 GPU,又怎样避免彼此拖累?一个架构专用 kernel 最终如何进入某次模型执行?

这些问题无法只靠阅读接口文档获得完整答案。只有把数据结构、资源生命周期和执行路径真正连接起来,推理系统才会从一组名词变成可以解释的工程对象。

PIH 因此不从兼容接口或完整功能列表起步,而是从一条最小执行链开始:装载插件,读取权重,建立运行时状态,完成 Prefill 与 Decode,再逐步加入 KV Cache、连续批处理、量化、多卡通信和在线服务。每增加一层,都会暴露下一层必须解决的约束。

从零实现的意义,在于把成熟框架封装起来的权重加载、调度和执行过程重新走一遍。

通用框架为覆盖范围保留更多实现

vLLM 等通用框架面对的是一个开放问题:用户可能带来不同模型、GPU、量化格式、并行方式和服务配置。为了让这些组合开箱即用,框架必须保留较宽的模型覆盖、硬件适配和兼容路径。

这种“更宽”不是缺点,而是通用性的成本。一个发行版本能够应对的场景越多,其中包含的实现分支、可选依赖与运行时判断通常也越多。

但模型进入服务器之后,问题往往已经从开放变成确定。假设一台机器只运行 Qwen3-0.6B,使用 RTX 4090 D 单卡并通过 HTTP 提供服务,那么实际需要的能力很明确:Linux 平台、CUDA Backend、Qwen 模型实现、SM89 Kernel Pack、权重存储、显存管理、调度与执行组件,以及 HTTP 服务接口。

这个部署不需要 DeepSeek 模型实现,不需要 NCCL,也不需要为 SM90 编译的 kernel。如果没有启用量化、CUDA Graph 或 host spill,它们同样不必进入发行物。

PIH 关注的正是确定场景下的精确装配:不让一套安装包预先代表所有可能性,而让每次部署只携带已经选择的能力。

轻量首先是部署闭包更小

这里的“轻量”需要说得准确。

删除未使用的模型插件,可以缩小构建和安装范围;排除 NCCL,可以减少单卡服务的动态依赖;只交付 SM89 Kernel Pack,可以避免把其他架构的二进制带到目标机器;不装载未启用的功能,也会减少启动阶段需要识别和初始化的组件。

因此,PIH 所说的轻量,首先体现在三个地方:发行物只包含必要能力,动态依赖与装载路径更短,故障排查所涉及的组件范围更明确。它描述的是系统的交付与装配方式。

这和推理速度不是同一件事。单个 token 的延迟主要受模型计算量、kernel 实现、调度策略、批处理方式和硬件带宽影响;模型权重与 KV Cache 占用也不会因为插件变少而自然消失。精确裁剪可以去掉无关代码,却不能代替热路径优化。

换句话说,PIH 试图先让部署中“有什么、为什么存在”变得清楚,再在这组确定的组件上讨论性能。插件化提供的是边界,不是免费的吞吐率。

“一切皆可插件”不等于一切都是动态库

如果把每个算子、每层 Transformer,甚至调度器里的队列节点都做成插件,系统很快会被 ABI、间接调用和组合关系淹没。插件数量增加了,部署却没有因此更清晰。

PIH 对插件边界的判断标准,是一项能力是否具有独立部署价值。

十类粗粒度插件通过 Microkernel 建立的能力图协作,而不是彼此直接读取内部对象:

                    Deployment Lock
                           │
                           ▼
               pih-worker / Microkernel
                           │
          Plugin Loader + Capability Registry
                           │
       ┌───────────────────┼───────────────────┐
       │                   │                   │
  环境与制品          计算与资源           模型与服务
  Platform            Backend              Model
  Storage             Execution            Kernel Pack
                      Memory               Surface
                      Transport            Health

这张图表达的是能力边界,不是请求依次经过的十个步骤。Microkernel 根据 Lock 装载插件,把它们提供和依赖的能力连接成图;一次具体推理只会进入当前路径需要的组件。

按照这个标准,PIH 目前划分了几类粗粒度插件。Platform 负责操作系统、驱动和设备发现等平台接入;Storage 负责经过校验的模型制品访问,使权重从哪里读取、读取的是哪个版本不再由模型代码自行决定。

Backend 把 CUDA、CPU 等设备执行能力交给上层,Execution 决定请求怎样进入执行流程,Memory 管理显存、主机内存以及可能启用的 host spill,Transport 提供 NCCL 等跨设备通信能力。四者分别处理“在哪里计算”“怎样组织计算”“资源怎样分配”和“数据怎样跨设备移动”,避免模型插件同时承担设备管理、调度与通信协议。

Model 封装具体模型架构及其权重解释方式,Kernel Pack 提供与 GPU 架构匹配的高性能 kernel。二者分开以后,同一个模型可以选择不同硬件实现,同一套设备能力也可以服务多个模型。量化和 CUDA Graph 这类能力,则可以根据部署需要进入对应的模型、执行或 Kernel Pack 闭包。

Surface 位于推理链路外侧,把内部能力转换成 HTTP、OpenAI 兼容 API 或其他服务接口;Health 提供就绪状态与运行健康信息,但不参与模型计算。这样,换一种对外协议不需要改动模型,增加健康检查也不会进入推理热路径。

这些角色不是固定的进程划分,而是部署时可选择的能力边界。它们都有明确的依赖、资源归属和生命周期,适合独立构建、替换或从发行物中移除。

插件化还缩小了定制优化的影响范围。实际部署很少完全标准化:同一个模型放到不同 GPU、显存容量和网络拓扑上,可能需要不同的 kernel、内存策略、通信方式或调度路径。有些优化甚至只服务于一类服务器上的一个固定模型。

在覆盖大量场景的通用框架中,这类改动往往会进入共享执行路径,因此需要同时考虑其他模型、硬件和功能组合。PIH 可以为特定模型与服务器组合提供独立的 Model、Execution、Memory、Transport 或 Kernel Pack 插件,再由单独的 Deployment Lock 选择。只要公共能力契约保持不变,定制代码就不会进入其他部署闭包,相应的构建、测试和故障范围也被限制在这组插件之内。

这并不意味着插件可以不受约束地修改。公共 C ABI、能力契约或 Microkernel 一旦改变,仍可能影响多个插件。插件化真正改变的是影响范围:一次面向特定服务器的优化,不必默认成为整个框架和所有部署共同承担的改动。

插件内部则不必继续拆碎。RMSNorm、RoPE、Attention 与 MLP 可以保留为普通 C++ 类型和直接调用,关键路径也可以采用针对模型与硬件优化的执行计划。

因此,“一切皆可插件”更准确的含义是:系统中的能力都可以被声明、选择和组合,但只有需要独立构建、裁剪或替换的能力,才成为物理插件。PIH 采用的是粗粒度物理插件与细粒度能力接口,而不是动态库越多越好。

Profile 和 Lock 把部署选择固定下来

插件化系统还需要解决一个问题:谁来决定最终装载哪些插件?如果 worker 启动后扫描目录,再临时寻找“看起来兼容”的组件,同一份配置可能在不同机器上得到不同结果,也很难解释实际运行的是哪组实现。

PIH 把这条路径分为四步:

Deployment Profile
        ↓
Resolver 解析模型、平台与功能需求
        ↓
Deployment Lock 固定版本、绑定与资源预算
        ↓
pih-worker 装载精确插件闭包

Deployment Profile 描述意图:在哪类机器上运行哪个模型,使用几张 GPU,是否启用量化或 host spill,需要什么服务接口。Resolver 根据受信的候选集合解析依赖与能力绑定,并生成 Deployment Lock。

Lock 不是另一份偏好配置,而是一次解析后的确定结果。它记录插件版本、Kernel Pack、能力绑定和资源预算。生产 worker 只消费 Lock,不在启动时重新做选择。

worker 内部保留一个很小的 Microkernel。它不理解 DeepSeek,也不实现 CUDA 或 HTTP;它只负责校验 Lock、装载能力、管理生命周期,并在启动失败时按相反顺序释放已经获得的资源。模型计算、硬件执行和服务接口分别由插件提供。

这样一来,“这台服务器运行了什么”不再需要从安装目录和启动日志中猜测,而可以由一份确定的 Lock 直接回答。

插件架构最终仍要回到推理主链

架构图可以把系统画得很整齐,但推理框架真正困难的地方,都发生在数据与资源开始流动之后。

模型插件要读懂 Safetensors 和模型配置,把 checkpoint 中的 tensor 映射成运行时权重;执行组件要实现 RMSNorm、RoPE、Attention 与 MLP,并区分 Prefill 和 Decode 的计算特征;KV Cache 要同时处理容量、位置与生命周期;调度器还要在吞吐、延迟和显存压力之间作出取舍。

量化不只是把权重换成更少的 bit。它同时涉及制品格式、缩放参数、kernel 支持和数值误差。多卡也不只是加入 NCCL:rank 的建立、通信顺序、资源归属和失败传播都会改变系统边界。MoE 与 host spill 则进一步把路由、带宽和内存层级带入执行过程。

PIH 系列会沿着这条主链逐层展开。先构造最小 Microkernel 和第一个插件,再进入权重加载、Transformer 计算、KV Cache、调度、量化、CUDA kernel、多卡通信与服务化。插件架构不是覆盖在这些技术之上的包装层;它必须能够承载这些能力,同时不把它们重新耦合成一个不可裁剪的整体。

PIH 目前能做到什么

PIH 目前仍是 developer preview,但已经不只是架构草图。原生 Worker、C ABI 能力图和 Kernel Pack 已形成可构建的部署链路:Qwen3-0.6B 面向 RTX 4090 D 与 H100 PCIe;DeepSeek V4-0731 设计了一条面向单张 RTX 4090 D、依赖主机内存分页的实验路径;DeepSeek V4.1 则面向 B300 多卡。这里完成的是代码与构建接线,目标硬件上的端到端运行、数值和性能仍待验证。默认发行不再构建旧的 _pih 单体运行时,Python 包只保留 HTTP 客户端和主机诊断。

这些进展说明插件边界已经进入真实模型、CUDA、NCCL 和服务代码,却还不能推出生产可用。尤其是 4090 D 上的 DeepSeek V4-0731 路径,解决的是显存放不下完整权重时怎样借助主机内存继续执行,并不意味着已经获得可用的生成速度。PIH 现在适合用来讨论架构、阅读实现和理解推理链路,还不是 vLLM 的成熟替代品。

项目代码与后续实现会持续更新在 GitHub:GuiminChen/pih。如果你也在研究 LLM 推理、插件系统或精确部署,可以从架构讨论、实际部署需求和具体实现参与进来。

下一篇从最小 Microkernel 开始。先不加载真实模型,只让 worker 按照 Lock 找到第一个插件,完成能力绑定、启动与资源回收。推理框架的第一步,不是生成 token,而是让系统知道自己由什么组成。

相关学习资料