一、项目释义
当下主流LLM推理引擎,例如vLLM、TensorRT-LLM,设计目标是通用性优先。一套代码要兼容几十款显卡、多种模型结构、多卡分布式、五花八门量化格式。为了适配各种场景,代码里大量if分支、抽象封装层、动态shape逻辑,会带来额外开销,很难把单卡硬件性能压榨到极限。
这个项目选择完全相反的路线:高性能单GPU推理,只适配选定的GPU型号与指定模型权重文件。不再做全硬件、全模型兼容,砍掉所有为通用性准备的冗余逻辑,聚焦在单张GPU上,为指定模型做深度定制优化。
整套引擎从零使用C++20 + CUDA开发,原生支持Dense、MoE两类Transformer架构,支持文本、图片、多图、视频混合多模态输入。对外提供两套交互入口:本地命令行一次性推理;兼容OpenAI、Anthropic协议的HTTP服务接口,支持流式输出、工具调用、token用量统计。
引擎设计约束:进程启动时仅加载一个模型,权重全程驻留显存;最大并发请求数量在启动阶段固定,范围1~8路,请求队列采用FIFO。
项目使用自定义模型工件文件,工件内部打包模型配置、编码量化权重、算子绑定参数、多模态前端资源。支持的工件版本为V3;旧版V2工件可以本地原地升级,不需要重新下载权重。同时支持用户自行编写转换脚本,把原始模型权重导出为本引擎的工件格式。
支持的模型工件清单:
| 模型 | 权重类型 | 工件文件 |
|---|---|---|
| Qwen3.6-27B | groupwise-int | qwen3_6_27b.ninfer |
| Qwen3.6-27B | nvfp4 | qwen3_6_27b_nvfp4.ninfer |
| Qwen3.8-27B | groupwise-int | qwen3_8_27b.ninfer |
| Qwen3.8-27B | nvfp4 | qwen3_8_27b_nvfp4.ninfer |
| Qwen3.6-35B-A3B | groupwise-int | qwen3_6_35b_a3b.ninfer |
二、行业技术知识点
1. Blackwell架构NVFP4量化
目标GPU搭载Blackwell架构,硬件原生支持NVFP4 4bit浮点计算。和传统INT4整数量化对比,NVFP4保留浮点指数,大模型权重压缩时精度损失更小。引擎手写CUDA算子,原生支持NVFP4权重加载、反量化与矩阵计算,无需上层框架格式转换。
引擎同时支持BF16、INT8、FP8、K8V4多种KV缓存存储格式。
2. MTP推测解码 + DFlash增强推测解码
MTP(多候选推测解码),原理是先用轻量Draft头并行生成多个候选token,批量送入主模型一次性验证,匹配成功直接输出,失败则截断回退重生成。普通MTP支持1~5个draft token窗口;35B-A3B模型额外支持DFlash增强推测解码,draft窗口上限提升至15。
DFlash可以加速多模态Prefill之后的文本解码阶段,不参与图像编码加速。
3. 分层KV缓存 + 精确前缀缓存复用
KV缓存分为两层存储:GPU显存设备缓存、主机锁页内存缓存。
前缀检查点(prefix checkpoint)保存完整prompt对应的KV缓存+模型状态快照。新请求到来时,检索前缀哈希表,命中则直接复用已计算好的KV,跳过重复prefill,长文档RAG场景收益巨大。
当显存资源紧张,调度器评估恢复开销,自动把冷门前缀缓存从GPU显存迁移到主机锁页内存;再次访问时拷贝回显存。
4. Chunked Prefill 分块预填充 + CUDA Graph 捕获Decode图
超长prompt不会一次性全部送入GPU计算,拆分为固定大小分块逐块prefill,防止单次计算显存溢出。
Decode阶段使用CUDA Graph捕获完整算子序列,推理时直接提交Graph,消除反复kernel launch带来CPU-GPU调度开销,是高并发吞吐的核心优化手段。引擎使用精确批次CUDA Graph解码。
5. 工件打包格式设计
自定义V3工件文件,把模型配置、量化权重、前端资源打包在单个二进制文件,方便分发与版本管理。权重提前按照CUDA算子最优内存排布存储,减少推理时的内存转置拷贝。
三、架构设计思路
整体架构划分为4大模块:工件解析与权重加载模块、CUDA算子内核模块、KV缓存与资源调度模块、前端服务模块
- 工件解析与权重加载模块
读取自定义二进制工件,解析模型结构、量化参数、权重数据。进程启动阶段一次性将权重反量化、重排内存布局,拷贝到GPU显存,运行阶段权重常驻显存。支持本地升级旧版本工件。 - CUDA算子内核模块
手写CUDA Kernel,专门针对sm_120a架构优化。编译阶段强制校验GPU架构,非sm_120a直接编译失败。算子包含多头因果注意力、LayerNorm、FFN、NVFP4/FP8/groupwise-int量化矩阵乘、MTP验证算子、图像视频编解码算子。不依赖cuBLAS等通用矩阵库,针对模型固定shape特化,减少通用库额外开销。 - KV缓存与资源调度模块
全局共享KV内存池,所有并发请求共用这块显存空间。调度器负责:
- 追踪每个请求KV占用大小;
- 设备KV与主机锁页KV之间的数据迁移;
- 前缀缓存哈希查找、LRU淘汰、快照管理;
- 请求准入控制,最大并发1~8路。
KV池容量在进程启动时确定,运行期间无法动态扩容。
- 前端服务模块
两套入口:本地CLI一次性推理;HTTP服务,实现OpenAI Chat Completions、Anthropic消息协议,支持SSE流式输出、token计数、工具调用。引擎只返回解析后的工具调用结构,不会执行工具代码。图片、视频输入依赖FFmpeg库做视频帧解码。
四、核心代码实现原理(源码详细解读)
4.1 CMake构建脚本,GPU架构强校验
项目使用CMake+Ninja构建,强制C++20标准。编译脚本增加CUDA架构硬校验,只允许sm_120a:
#CMake片段:限制CUDA架构if(NOT CMAKE_CUDA_ARCHITECTURES STREQUAL"120a")message(FATAL_ERROR"Engine only support sm_120a GPU architecture. Other arch not allowed.")endif()# 构建预设定义include(CMakePresets)#release预设:关闭测试与benchmark,只编译推理主程序#dev预设:开启单元测试、性能基准,自动查找本地Python环境构建两个预设:
release:生产版本,关闭测试与benchmark;dev:开发调试版本,开启测试与性能基准,自动检索Python解释器。
重要特性:项目没有install安装目标,编译产物只能在build目录直接运行,不做系统级安装部署。Python权重转换脚本独立于C++编译流程;HBM探测工具拥有独立编译命令。
4.2 V3工件文件解析核心C++代码
工件是二进制文件,使用mmap内存映射方式加载,避免一次性大文件读入内存。文件头部保存元信息,包含配置偏移、权重偏移、文件版本标识:
// 工件头部结构体定义structArtifactHeader{uint32_tmagic;uint32_tversion;uint64_tconfig_offset;uint64_tweight_offset;uint64_tweight_size;uint64_tresource_offset;uint64_tresource_size;};// 加载工件完整函数#include<fcntl.h>#include<unistd.h>#include<sys/mman.h>#include<cstdint>#include<string>structModelArtifact{void*config_ptr;uint8_t*weights_ptr;size_t weight_bytes;};ModelArtifactload_artifact(conststd::string&artifact_path){intfd=open(artifact_path.c_str(),O_RDONLY);if(fd<0){throwstd::runtime_error("open artifact file failed");}off_t file_sz=lseek(fd,0,SEEK_END);lseek(fd,0,SEEK_SET);void*mapped=mmap(nullptr,file_sz,PROT_READ,MAP_SHARED,fd,0);if(mapped==MAP_FAILED){close(fd);throwstd::runtime_error("mmap artifact failed");}ArtifactHeader*hdr=reinterpret_cast<ArtifactHeader*>(mapped);if(hdr->version!=3){munmap(mapped,file_sz);close(fd);throwstd::runtime_error("only support v3 artifact");}ModelArtifact art;art.config_ptr=static_cast<uint8_t*>(mapped)+hdr->config_offset;art.weights_ptr=static_cast<uint8_t*>(mapped)+hdr->weight_offset;art.weight_bytes=hdr->weight_size;returnart;}加载后,将art.weights_ptr指向的量化权重,通过cudaMemcpy一次性拷贝到GPU显存,拷贝完成后根据量化类型,在CUDA kernel内部实时做反量化计算。
4.3 KV缓存分层存储结构体 C++源码
区分设备显存Buffer与主机锁页Buffer,每个slot保存token长度与标记,标记区分普通KV与可复用前缀检查点:
#include<cuda_runtime.h>structDeviceBuffer{void*ptr;size_t bytes;~DeviceBuffer(){if(ptr)cudaFree(ptr);}};structHostPinnedBuffer{void*ptr;size_t bytes;~HostPinnedBuffer(){if(ptr)cudaFreeHost(ptr);}};structKVCacheSlot{DeviceBuffer k_dev;DeviceBuffer v_dev;HostPinnedBuffer k_host;HostPinnedBuffer v_host;size_t token_len;boolis_prefix_checkpoint;};调度器维护全局std::unordered_map<uint64_t, KVCacheSlot> prefix_pool,key为prompt前缀哈希值。收到新请求,计算prompt哈希,查找prefix_pool,命中直接复用slot,跳过prefill。显存不足时,调度器调用cudaMemcpyAsync将slot数据在GPU显存与主机锁页内存之间迁移。
4.4 MTP推测解码执行控制逻辑 C++
// MTP推测解码主循环伪实现(项目原生C++逻辑,非伪代码)// draft_tokens:配置的draft token数量,如3// accept_threshold:验证通过逻辑structMTPResult{std::vector<int>accept_tokens;inttruncate_pos;};MTPResultmtp_verify(ModelContext*ctx,conststd::vector<int>&draft_tokens){// 将draft序列打包送入主模型一次性批量验证ctx->submit_draft_batch(draft_tokens);ctx->wait_cuda_graph();std::vector<int>accept;intcut_pos=0;for(;cut_pos<draft_tokens.size();cut_pos++){if(ctx->get_verify_token(cut_pos)==draft_tokens[cut_pos]){accept.push_back(draft_tokens[cut_pos]);}else{break;}}return{accept,cut_pos};}MTP流程:
- 主模型+MTP Draft头并行生成N个候选draft token;
- 打包draft序列送入主模型,使用CUDA Graph批量验证;
- 逐个比对token,收集连续匹配token作为输出;
- 在第一个不匹配位置截断,丢弃后面draft token,主模型重新生成。
4.5 HTTP服务请求处理逻辑(OpenAI接口)
内置HTTP服务,接收JSON请求,解析messages,送入调度器,生成token后SSE流式返回。
// HTTP请求处理核心逻辑voidhandle_chat_completion(HttpRequest&req,HttpResponse&resp,Engine*engine){autochat_req=parse_json_chat(req.body);InferenceTask task;task.messages=chat_req.messages;task.max_new_tokens=chat_req.max_tokens;task.stream=chat_req.stream;// 提交任务到调度器FIFO队列TaskHandle handle=engine->submit_task(task);resp.set_header("Content-Type","text/event-stream");// 流式循环输出SSEwhile(true){autochunk=engine->get_next_chunk(handle);if(chunk.is_finish)break;resp.write_chunk(build_sse_json(chunk));}resp.write_chunk(build_finish_event());}视频输入部分,引擎调用FFmpeg libavformat/libavcodec库,读取视频文件、解码视频帧,送入视觉编码算子。
五、环境配置与运行测试教程
硬件硬性约束
- GPU:目标NVIDIA显卡(sm_120a架构)
- OS:64位Linux,Windows平台不支持
完整软件依赖清单
- CMake ≥ 3.28
- Ninja构建工具
- C++20兼容编译器(GCC / Clang)
- CUDA Toolkit 13.1(官方验证版本,CMake不强制下限,但推荐使用13.1)
- FFmpeg开发库:libavformat、libavcodec、libavutil、libswscale
- libcurl >= 7.85>
可选依赖:Python环境,仅用于权重转换脚本,推理运行不需要Python
编译步骤
cd source_dir#Release正式编译cmake-S.-B build-G Ninja-DCMAKE_BUILD_TYPE=Release cmake--build build-j编译完成,可执行文件位于build/apps/,两个核心程序:
cli-infer:本地一次性CLI推理程序infer-serve:HTTP推理服务程序
模型工件下载
使用HuggingFace CLI下载预打包工件,放置models目录:
hf download 模型仓库标识 qwen3_8_27b_nvfp4.ninfer --local-dir models测试1:本地CLI一次性推理
./build/apps/cli-infer models/qwen3_8_27b_nvfp4.ninfer \--prompt"Explain prefill and decode, then give a concise conclusion."\--max-context32768\--max-new8192\--kv-dtype fp8 \--spec mtp--draft-tokens3\--lm-head-draft输出规则:
- 模型回答内容输出stdout;
- 启动日志、吞吐、时序、MTP验证统计信息输出stderr;
--log-level debug:打印完整启动调试日志;--messages FILE加载结构化对话文件;--vision开启图片/视频多模态输入。
测试2:启动HTTP推理服务,2并发
./build/apps/infer-serve models/qwen3_8_27b_nvfp4.ninfer \ --max-context 240000 \ --kv-capacity 240000 \ --max-concurrency 2 \ --kv-dtype fp8 \ --device-state-slots 2 \ --host-state-slots 8 \ --host-kv-mib 8192 \ --spec mtp --draft-tokens 3 \ --lm-head-draft \ --preserve-thinking参数说明:
max-context:单条请求逻辑最大token上限;kv-capacity:全局KV池总token容量;max-concurrency:最大并发请求数量;device-state-slots:GPU显存保存状态快照数量;host-state-slots:主机内存保存状态快照数量;host-kv-mib:主机锁页KV缓存容量,单位MiB;--preserve-thinking:保留模型内部思考推理内容。
服务启动后监听127.0.0.1:8080。
测试3:调用OpenAI兼容接口
curl[http://127.0.0.1:8080/v1/chat/completions](http://127.0.0.1:8080/v1/chat/completions) \ -H 'Content-Type: application/json' \ -d '{"model":"qwen3.8-27b","messages":[{"role":"user","content":"Reply with one short sentence."}],"max_tokens":64}'Docker容器部署
主机提前安装NVIDIA Container Toolkit
# 构建镜像 docker build--tag llm-single-infer:local.# 启动容器,挂载模型目录,端口映射 docker run--rm \--gpus'"device=0"'\--publish8080:8080\--volume"$PWD/models:/models:ro"\ llm-single-infer:local \ infer-serve/models/qwen3_8_27b_nvfp4.ninfer \--host0.0.0.0\--max-context240000\--kv-capacity240000\--max-concurrency2\--kv-dtype fp8 \--device-state-slots2\--host-state-slots8\--host-kv-mib8192\--spec mtp--draft-tokens3\--lm-head-draft \--preserve-thinking六、落地用途
- 单卡私有化本地部署
小团队、个人本地私有化部署大模型,单卡即可承载27B/35B级别模型,原生支持图文视频多模态,对外提供OpenAI兼容API,业务侧代码几乎不用修改。 - 长文档RAG后端服务
依托前缀缓存复用机制,大量请求共用相同知识库Prompt,大幅降低重复Prefill开销,适合企业知识库、长文档问答场景。 - Blackwell架构底层学习研究
全套CUDA算子、KV缓存调度、MTP推测解码手写实现,没有厚重通用框架封装,适合研究NVFP4量化、CUDA Graph、推测解码、分层KV缓存底层原理。 - 多模态Agent原型快速验证
原生支持图片、多图、视频输入,支持保留模型thinking推理内容,适合本地多模态Agent原型开发。 - 离线Perplexity评估
内置离线因果困惑度打分能力,用于模型效果评估。
七、实测性能数据
全部测试基于目标GPU,测试环境使用INT8 group-64 KV、CUDA Graph、MTP3,每次请求生成8192 token
并发MTP3解码吞吐(tok/s / 候选token接受率)
| 模型配置 | C=1 | C=2 | C=4 | C=8 | C8/C1加速比 |
|---|---|---|---|---|---|
| Qwen3.6-27B groupwise-int | 185.8 / 68.2% | 247.0 / 69.0% | 309.5 / 68.4% | 535.0 / 68.3% | 2.88× |
| Qwen3.6-27B nvfp4 | 202.4 / 69.3% | 399.7 / 71.4% | 699.7 / 69.3% | 1146.9 / 68.6% | 5.67× |
| Qwen3.6-35B-A3B groupwise-int | 642.5 / 68.6% | 907.2 / 66.3% | 1213.5 / 69.6% | 1380.7 / 68.0% | 2.15× |
| Qwen3.8-27B nvfp4 | 143.8 / 48.9% | 267.6 / 48.1% | 461.1 / 45.8% | 766.6 / 46.0% | 5.33× |
单请求Prefill性能(tok/s)
| 模型配置 | 7680 token短Prefill | 260096 token超长Prefill | 结构化MTP3解码 |
|---|---|---|---|
| Qwen3.6-35B-A3B groupwise-int | 17705.4 | 5247.0 | 779.6 |
| Qwen3.6-27B groupwise-int | 3218.1 | 1614.8 | 193.0 |
| Qwen3.6-27B nvfp4 | 11191.5 | 2510.6 | 252.2 |
| Qwen3.8-27B groupwise-int | 3274.7 | 1609.7 | 224.4 |
| Qwen3.8-27B nvfp4 | 8340.4 | 2203.1 | 219.8 |
模型评测结果(0-shot,单样本评测)
| 模型配置 | AIME 2025 | AIME 2026 | GPQA-Diamond | ERQA | RealWorldQA |
|---|---|---|---|---|---|
| Qwen3.6-27B groupwise-int | 86.67% | 93.33% | 86.87% | - | - |
| Qwen3.6-27B NVFP4 | 93.33% | 93.33% | 84.34% | - | - |
| Qwen3.6-35B-A3B groupwise-int | 90.00% | 90.00% | 85.35% | - | - |
| Qwen3.8-27B groupwise-int | 96.67% | 96.67% | 87.37% | 66.25% | 82.22% |
| Qwen3.8-27B NVFP4 | 96.67% | 96.67% | 90.40% | 66.25% | 83.53% |
If you need the complete source code, please add the WeChat number (c17865354792)
八、项目边界与局限
- 单引擎进程只能绑定单张目标GPU,不支持其他显卡型号,无多卡分布式推理;
- 进程启动加载模型,权重常驻显存,运行期间不能动态切换模型;
- 不支持请求抢占、任务优先级QoS调度;
- 没有权重CPU/GPU动态换页能力;
- 引擎只返回解析后的工具调用信息,不会执行任何工具;
- 源码内C++头文件不作为对外SDK,仅能在源码编译目录运行;
- KV池容量、最大并发数量,进程启动后固定,运行阶段不可动态调整;
- 仅对显式实现的模型架构、shape、量化路径提供支持。
Welcome to follow WeChat official account【程序猿编码】