
先交代一下这套方案的适用场景我在不少项目里都碰到过这种尴尬情况——代码仓库、依赖源全部在内网之外训练服务器本身没有任何公网出口或者说出口被防火墙卡得死死的直接 git clone GitHub 上的仓库等了十分钟还是 0 bytes。这种情况下想编译 TensorRT-LLM不提前把离线资源包准备好现场就是寸步难行。本文以 TensorRT-LLM V1.1.0rc0 为例从联网机器上准备源码和依赖再到内网服务器上完整编译把整个过程和踩过的坑都摊开来讲。这套路径不是我拍脑袋想出来的而是反复折腾之后沉淀下来的。如果你所在的环境正好是“能联网开发机 不能联网的 GPU 服务器”这种经典组合那这篇文章基本就是为你的场景写的。我会尽量把每一步的“为什么这么做”也讲清楚遇到问题的时候你自己也能顺着逻辑去排查而不是只会粘贴命令。1. 项目概述与整体设计思路1.1 为什么离线编译 TensorRT-LLM 这么麻烦TensorRT-LLM 不是一个普通的 Python 包pip install 一下就完事那种。它是一个偏向底层的高性能推理框架核心的 C 代码需要通过源码编译而且编译过程依赖非常密集依赖 TensorRT 本身的 SDK包括头文件和库文件最好是专用版本的 TensorRT依赖 NVIDIA 自家的一堆子模块比如 cutlass、cub、pybind11这些默认从 GitHub 拉依赖三方的构建工具CMake、Ninja、gcc 版本都有隐性要求还有一堆 Python 侧依赖比如 nvidia-modelopt、onnx、transformers 等分门别类散落在 PyPI 和 GitHub release 里。换句话说TensorRT-LLM 的构建系统默认假设“你有网”而且是“访问 GitHub 毫无压力”的网络环境。一旦这个假设不成立问题就从“写代码”变成了“如何去搞到一整套构建闭环的依赖”。这也是为什么很多人卡在第一步就放弃了——不是编译不会而是依赖凑不齐。1.2 整体方案的选型逻辑与前置条件在面对“无 GitHub 访问权限”的服务器时核心思路只有一个把所有需要外网获取的资源提前在一台联网机器上收集完毕然后以离线资源包的形式拷贝进内网服务器。整个工作流可以拆成四段获取核心源码TensorRT-LLM 的完整源码以 tar 包形式准备获取全部依赖源码构建过程中会自动下载的 cpp 依赖以及 Python 侧依赖 wheel 包传输与布局将资源包通过 U 盘、内网共享盘或 scp 方式传到目标服务器并按要求摆放目录内网编译在服务器上关掉所有联网拉取逻辑强制使用本地依赖完成 Release 编译。这套方案选型上的最大优势是不需要在服务器上额外搭建什么本地 PyPI 服务器或者 Git 代理整个操作是“一次性拷贝”的因此对服务器的侵入性最低。只要照着清单做服务器上不需要外网权限也能得到一个功能完整的编译产物。前置条件方面目标服务器上需要具备能够正常支撑编译的硬件和基础软件环境。硬件上建议至少 32GB 内存编译大 target 时内存不足会直接 OOMCUDA 版本以 12.x 为佳TensorRT-LLM V1.1.0rc0 对 CUDA 12 的支持比较成熟。系统方面建议 Ubuntu 20.04/22.04 或者兼容的发行版并准备好 Python 3.10 左右的环境。后面我会专门开一节讲怎么逐一确认这些条件。2. 构建环境准备离线环境检查清单2.1 第一关硬件与驱动、CUDA、容器运行时很多人一上来就急着下载源码结果编译到一半报了一堆跟 CUDA 相关的错误回头才发现基础环境根本没对齐。在开始离线资源包准备之前务必先在服务器上确认三件事GPU 驱动执行nvidia-smi需要能看到显卡信息。如果提示command not found多半是驱动没装或者 PATH 没配好。CUDA Toolkit执行nvcc --version确认 nvcc 存在且版本符合预期。注意nvidia-smi显示的驱动版本对应的 CUDA 版本和nvcc对应的 CUDA Toolkit 版本不是一回事。容器运行时可选如果计划在 Docker 里编译提前确认docker run --gpus all nvidia/cuda:12.3.2-devel-ubuntu22.04这类命令能正常拉起 GPU 容器。TensorRT-LLM 的编译对 CUDA 版本是敏感的。V1.1.0rc0 这个版本官方在文档里通常标注推荐 CUDA 12.x我实测在 CUDA 12.3/12.4 下编译没有遇到兼容性问题。如果你服务器上装的是 CUDA 11.x也不是完全不能用但可能要手动指定更多编译参数少走弯路的话直接对齐到 12.x 更好。注意不要只看nvidia-smi顶部的 “CUDA Version” 就以为 Toolkit 装好了。驱动自带的 CUDA runtime 和编译需要的 CUDA Toolkit 是两码事。编译时 nvcc 找不到后面一切免谈。另外如果服务器属于那种重启后驱动就丢的环境编译前先要把驱动环境确认好否则 TensorRT-LLM 里的 CUDA extension 在 build 阶段就会挂掉。这种问题在离线环境下排查起来尤其痛苦因为没法随便装个东西来测试所以前置检查别偷懒。2.2 第二关Python 环境和 pip 离线包机制TensorRT-LLM 的构建与运行都离不开 Python 侧依赖。V1.1.0rc0 时期官方推荐 Python 3.10我自己测试用 Python 3.10.12 比较稳妥。服务器上可能有多个 Python 版本建议用虚拟环境隔离避免污染系统环境也方便后续删除。离线环境下pip 默认是没法连 PyPI 的。两个典型疑点需要注意如果服务器上配了内网 PyPI 源那直接用pip install xxx是可行的不需要走离线 wheel如果没有内网源就必须用pip download在联网机器上把依赖全部拉成.whl文件再内网里pip install --no-index --find-links./wheels安装。--find-links这个参数在离线安装中非常重要它可以让 pip 只从指定目录查找包而不是去连默认的 PyPI 索引。另外TensorRT-LLM 某些 Python 依赖可能是从 GitHub release 直接下载的这类包在pip download的时候可能因为找不到对应源而失败需要人为指定--extra-index-url或者直接手动下载对应 wheel 放进目录。Python 环境这事宁可提前多装一个版本也不要指望 Python 3.8 硬扛。部分新版依赖比如 nvidia-modelopt对 Python 版本有下限要求Python 太老会直接拒绝安装到时候再折腾环境就更费时间了。2.3 第三关系统工具链gcc、cmake、ninjaTensorRT-LLM 的源码编译主要依赖三样东西C 编译器、CMake 构建工具、Ninja 构建系统。gcc/g建议版本在 9.4 以上Ubuntu 22.04 自带的 gcc 11 可以满足Ubuntu 20.04 默认 gcc 9.4 勉强够用但某些新特性可能踩坑。CMake官方构建脚本对 CMake 的最低版本有一定要求3.24 或更高版本更保险。Ninja至少 1.10 以上建议直接用 apt 安装。由于服务器无外网apt 源也可能不可用。因此这些基础工具要在准备阶段一并确认。如果服务器自带的是旧版 CMake千万别想着内网在线升级直接在联网机器上下载好对应架构的 CMake 二进制包拷进去解压覆盖即可。CMake 官方有提供打包好的cmake-*-linux-x86_64.tar.gz不需要自己编译非常方便。同样的思路也适用于 NinjaGitHub 上有官方 release 的ninja-linux.zip下载下来解压后把ninja放到/usr/local/bin就完事。这个操作看起来简单但能省下很多现场折腾时间。3. 在联网机器上准备离线资源包3.1 获取 TensorRT-LLM 源码的多种方式先说核心源码。在联网机器上直接git clone https://github.com/NVIDIA/TensorRT-LLM.git通常会因为网络原因失败。对于 GitHub 仓库访问不顺畅的场景我有几个比较实用的替代方案镜像站点推荐国内有不少 GitHub 仓库的镜像服务比直接 clone 要可靠。比如git clone https://gitee.com/mirrors/TensorRT-LLM.git国内访问码云Gitee的体验就顺畅很多。需要注意镜像仓库可能不同步更新clone 时要确认 tag 或分支是否包含 V1.1.0rc0。代理式下载站点市面上存在一些 GitHub 文件下载加速服务比如https://ghproxy.com/https://github.com/...可以直接把 release 的 tar 包地址拼在后面下载。这类服务时好时坏如果某个不可用就换下一个。直接下载 tar 包在 GitHub 仓库页面选择对应 tag下载Source code (tar.gz)。只要浏览器能打开 release 页面这个方法就不需要 git 协议有时反而最简单。我实际操作时优先推荐镜像站点或者直接下载 tar 包因为不需要额外的 git 认证和权限配置。在联网机器上拉取源码时最好是连同 submodule 一起拉全。如果直接下载 tar.gzTensorRT-LLM 里面的一些子模块引用并不会自动包含后面要留意。3.2 收集精简版 TensorRT 库与插件TensorRT-LLM 本身不是一个完整的推理引擎它是架构在 TensorRT 之上的“加速层”。因此编译它必须要 TensorRT 本体尤其是头文件和libnvinfer.so等动态库。在联网机器上需要从 NVIDIA 官网下载 TensorRT 的 tar 包。V1.1.0rc0 对应的 TensorRT 版本建议看官方文档通常要求 TensorRT 10.x 或指定版本。下载时选择TensorRT .tar package而不是 .deb 包因为 tar 包更方便复制到任意位置使用离线环境下控制力更强。下载完成后解压出来的目录结构类似TensorRT-10.0.1.6/ ├── include/ # 头文件编译时会用到 ├── lib/ ├── bin/ └── python/我会把这个整个目录保留在一个固定路径比如/opt/TensorRT-10.0.1.6然后通过设置环境变量TRT_ROOT来让构建脚本找到它。后面讲解编译配置时再展开讲这个变量怎么用。3.3 批量收集 pip 依赖pip download 的正确用法TensorRT-LLM 的 Python 侧依赖很多最省事的方法是在联网机器上用一个干净的虚拟环境让 pip 根据requirements.txt批量下载所有依赖到指定目录。先进入源码目录看看有没有现成的 requirements 文件比如cd TensorRT-LLM cat requirements.txt然后执行pip download -r requirements.txt \ --dest ./offline_wheels \ --only-binary:all: \ --platform manylinux2014_x86_64 \ --python-version 310 \ --implementation cp \ --abi cp310这里的参数含义值得说一下--only-binary:all:只下载二进制 wheel不下载源码 tar避免离线安装时再触发本地编译这能省大量时间--platform、--python-version、--implementation、--abi限定目标平台和 Python 版本保证下载的 wheel 能在内网服务器上安装。如果不加这些pip download 默认会下载当前机器对应的包可能到服务器上装不了。当然如果联网机器和目标服务器都是同架构同 Python 版本也可以不加--platform等参数直接pip download -r requirements.txt -d wheels更省心。但一旦跨平台或跨版本这套限定参数就很关键。3.4 第三方源码依赖cutlass、cub、glog、gflags 等的手动归集这是最容易被忽视的一环。TensorRT-LLM 构建时CMake 会自动拉取一部分 GitHub 上开源的 C 依赖。由于服务器无法访问 GitHub这部分必须在联网机器上手动下载。典型的依赖包括但不限于NVIDIA/cutlassTensorRT-LLM 的核心 GEMM 实现依赖版本要严格匹配NVIDIA/cubCUDA 并行原语库google/glog、google/gflags日志和命令行参数库pybind11Python 与 C 绑定的关键依赖也可能在 pip 依赖之外被构建系统自动拉取NVIDIA/cuda-python这个有对应的 PyPI 包也可能通过 CMake 直接拉取。下载这些依赖时尽量下载 release tar 包并记录版本号。TensorRT-LLM 源码中的cpp/cmake或cmake目录里通常有详细清单可以去翻CMakeLists.txt里用到的FetchContent能看到各种GIT_REPOSITORY和GIT_TAG照着这些地址把 tar 包逐个下载下来。下载完成之后建议用统一目录维护offline_deps/ ├── cutlass/ ├── cub/ ├── glog/ ├── gflags/ └── pybind11/然后在后面的编译阶段通过设置 CMake 参数让构建系统优先使用这些本地目录而不是去 GitHub 远程拉取。4. 服务器上的完整编译实践4.1 目录结构设计与解压资源包传输到服务器后第一步不是立刻编译而是先把目录结构规划好。我的习惯是建立一个~/trtllm_build根目录内部划分清楚~/trtllm_build/ ├── TensorRT-LLM/ # 源码根目录 ├── TensorRT-10.0.1.6/ # TensorRT SDK ├── wheels/ # Python wheel 包 └── deps/ # C 第三方依赖源码解压时要注意文件权限尤其是 tar 包中可能包含符号链接解压到普通用户目录还是系统目录要提前决定。我一般放在当前用户目录下避免sudo带来的所有权混乱反正编译产物最终以库文件和 Python 扩展的形式输出。解压命令没什么特殊就普通的tar -xzf。解压后建议挨个看一眼目录内容是否完整特别是 TensorRT-LLM 源码里有没有cpp/、tensorrt_llm/、examples/这些关键目录缺了说明 source 包不完整别等编译失败才发现。4.2 编译前的关键配置显式指定路径 vs 依赖自动下载这一步是离线编译成功与否的分水岭。TensorRT-LLM 默认的构建脚本会自动去 GitHub 拉取相关依赖离线环境必须强制它走本地。我建议直接通过环境变量和 CMake 参数双重指定。先在服务器上设置环境变量export TRT_ROOT~/trtllm_build/TensorRT-10.0.1.6 export CMAKE_PREFIX_PATH$TRT_ROOT:$CMAKE_PREFIX_PATH export LD_LIBRARY_PATH$TRT_ROOT/lib:$LD_LIBRARY_PATH接着在源码根目录下创建一个构建目录并进入cd ~/trtllm_build/TensorRT-LLM python3 scripts/build_wheel.py \ --trt_root $TRT_ROOT \ --cuda_home /usr/local/cuda \ --python_bindings \ --clean这里build_wheel.py是官方提供的一键构建脚本。离线环境里还需要额外设置让 CMake 的FetchContent使用本地源这通常可以通过在CMakeLists.txt里修改或加-D参数实现。比较省事的方式是在联网机器上已经把依赖解压好并放到指定路径然后在脚本参数里追加--cuda_architectures 80;86;89;90来控制 GPU 架构同时把CMAKE_FIND_USE_SYSTEM_PACKAGE_REGISTRYOFF等参数传进去避免去外部查找包。4.3 Release 版编译完整过程编译这一步最容易出问题但也是最机械的。官方脚本本质上是调用了 CMake 和 Ninja我们把它拆开看逐步执行会更加可控。第一步准备 CMake 配置。手动建一个 build 目录在里面执行cd ~/trtllm_build/TensorRT-LLM/cpp mkdir -p build cd build cmake .. \ -DCMAKE_BUILD_TYPERelease \ -DCMAKE_INSTALL_PREFIX~/trtllm_build/install \ -DTRT_ROOT$TRT_ROOT \ -DCMAKE_CUDA_COMPILER/usr/local/cuda/bin/nvcc \ -DCMAKE_MAKE_PROGRAMninja \ -DFETCHCONTENT_SOURCE_DIR_CUTLASS~/trtllm_build/deps/cutlass \ -DFETCHCONTENT_SOURCE_DIR_CUB~/trtllm_build/deps/cub \ -DFETCHCONTENT_SOURCE_DIR_GOOGLETEST~/trtllm_build/deps/googletest \ -DFETCHCONTENT_SOURCE_DIR_PYBIND11~/trtllm_build/deps/pybind11这里最关键的是FETCHCONTENT_SOURCE_DIR_*这组参数。CMake 的 FetchContent 模块允许指定“不要下载直接用我给你这个目录”只要这里指向的本地源码目录里的内容和它要拉取的版本一致就能完美绕开 GitHub 访问。第二步执行编译。Ninja 的并行度建议根据服务器内存和 CPU 核数调整不要盲目开满。我用的是ninja -j 16-j 16是比较保守的选择。如果服务器是 64 核 CPU想快一点开-j 32也没问题但内存不够 32GB 时建议低于 16否则 OOM 突然中断反而更浪费时间。第三步打包。编译完成后把产物打包成 wheelcd ~/trtllm_build/TensorRT-LLM python3 scripts/build_wheel.py --trt_root $TRT_ROOT --python_bindings --clean这一步会在源码根目录的build目录生成一个.whl文件这个 whl 就是最终的 Python 安装包。整个过程如果顺利CPU 编译阶段大约半小时到一个小时取决于服务器配置。4.4 编译产物验证与运行时依赖检查编译完成后先不要急着部署模型先做一次基础验证确保产物能用。在同一个 Python 虚拟环境里安装刚刚生成的 wheelpip install --no-index --find-links./wheels tensorrt_llm-*.whl这里--find-links很重要因为安装时还会解析依赖如果没有内网 PyPI 源必须让 pip 只从本地 wheels 目录里找。安装完成后执行一个最小化验证import tensorrt_llm print(tensorrt_llm.__version__)如果能够正常输出版本号说明基础绑定没有问题。然后再去跑一个简单的推理示例比如examples/gpt下的小模型看 TensorRT engine 能不能正常 build 和运行。这一步能提前暴露诸如libnvinfer.so版本不兼容、CUDA runtime 找不到之类的运行时问题。运行时依赖检查用ldd也可以帮忙看ldd /path/to/tensorrt_llm/*.so | grep not found只要有任何一个 “not found”说明动态库依赖没有闭环需要回到 TensorRT 库路径或者 CUDA 库路径上补环境变量。5. 踩坑记录与问题排查实录5.1 问题 1CMake 仍然在尝试访问 GitHub症状编译刚开始没几分钟终端里出现类似Fetching content from https://github.com/NVIDIA/cutlass.git这就说明FETCHCONTENT_SOURCE_DIR_*没有生效或者指定的目录是空的。我的排查经验是先去确认本地依赖目录里源码的真伪ls ~/trtllm_build/deps/cutlass如果目录为空或者里面是下载了一半的临时文件CMake 就会认为资源不可用转头继续走 GitHub。这个问题的解决办法是重新在联网机器上下载完整个依赖目录确认有CMakeLists.txt和头文件再传回来。还有一种情况是FETCHCONTENT_SOURCE_DIR_*的命名不匹配。CMake 要求变量名是FETCHCONTENT_SOURCE_DIR_NAME其中NAME要和FetchContent_Declare里声明的名字完全一致拼写差一个字母都不行。建议先去CMakeLists.txt里精确搜索FetchContent_Declare看看每个依赖的确切名字。5.2 问题 2pip 安装时提示找不到某些包离线安装 wheel 时最容易遇到的就是ERROR: Could not find a version that satisfies the requirement xxx。这种事多半是因为 requirements 里有些包的依赖特别高或特别低而pip download阶段没有把这个间接依赖完整带下来。我习惯的做法是对着错误信息里的包名回到联网机器上单独补下pip download xxx版本号 -d ./offline_wheels然后把新的 wheel 传到服务器再重新执行安装。更保险一点在第一次执行pip download时我就用--no-deps关闭依赖解析改成手动维护一个完整的依赖列表避免 pip 因为某些包缺少源码包而中断。5.3 问题 3CMake 找不到 TensorRT 库TRT_ROOT没设置好是最常见的原因。在编译前的 shell 里执行echo $TRT_ROOT ls $TRT_ROOT/lib/libnvinfer.so如果环境变量为空或者路径不存在CMake 的find_package(TensorRT)自然就失败了。还有一点容易忽略libnvinfer.so本身可能是一个符号链接指向具体版本号的文件。如果从联网机器拷贝时符号链接没有保留那么即使文件存在CMake 也可能判定库不可用。所以拷贝 TensorRT 目录时要保留符号链接cp -a TensorRT-10.0.1.6/ ~/trtllm_build/-a参数可以保留符号链接和属性这个小细节能避免很多摸不着头脑的问题。5.4 问题 4编译慢、内存不足TensorRT-LLM 的 C 代码量很大编译过程对 CPU 和内存都有明显压力。如果机器内存只有 16GBninja -j 32几乎必挂。我在一台 24 核 64GB 的服务器上试过-j 16大概需要 45 分钟-j 8要一个多小时但没有 OOM 风险。如果编译过程中途因为内存被杀掉可以分两步先减少并行度比如-j 4再检查是不是 swap 空间太小适当增加 swap 能让编译继续推进。另外CUDA 架构参数CMAKE_CUDA_ARCHITECTURES不要设置太多比如把80;86;89;90这种大批量一次跑完每次编译的 .o 文件数量会爆炸。如果服务器是 A100只写80或90就行没必要为了“未来可能迁移”提前编所有架构那个对时间和内存的消耗成倍增长不划算。5.5 离线编译常见问题速查表现象常见原因处理办法CMake 去 GitHub 拉依赖FETCHCONTENT_SOURCE_DIR_* 未生效或路径为空核查变量命名确认本地目录内容nvcc 找不到CUDA Toolkit 未安装或 PATH 未配置确认/usr/local/cuda/bin/nvcc存在配置 PATH找不到 libnvinfer.soTRT_ROOT 未设置或符号链接丢失设置 TRT_ROOT用cp -a拷贝 TensorRT 目录pip 安装依赖失败requirements 下载不完整按包名单点下载补齐 wheel编译 OOM并行度过高、架构列表过宽降低-j精简 CUDA_ARCHITECTURES增加 swapwheel 导入报版本错误TensorRT 版本不匹配核对官方要求的 TensorRT 版本和构建参数运行时缺libcudart.soLD_LIBRARY_PATH 未包含 CUDA lib导出/usr/local/cuda/lib64或编译时-DCMAKE_CUDA_COMPILER指定正确 nvcc这个表里的每一条我都在实际项目中撞到过尤其是符号链接丢失和 FETCHCONTENT 变量拼写这两个问题排查时间占了整个离线编译时间的一半以上。把这两点做好整体流程可以顺很多。6. 最后分享两个实用心得离线编译 TensorRT-LLM本质上就是一次“依赖闭环”的工程管理。与其到服务器上才临场发挥不如在联网机器上就把依赖目录整理成标准结构传输过去后几乎不需要调试。第一个小技巧在联网机器上做完pip download之后用pip install --no-index --find-links./offline_wheels --dry-run模拟一遍安装能提前发现依赖缺失问题而不用等到内网环境里才发现。--dry-run只解析依赖不实际安装非常节省时间。第二个小技巧编译时如果遇到来历不明的报错先看是不是TRT_ROOT下的符号链接丢了。TensorRT 的 tar 包里符号链接非常多一旦用普通cp而不是cp -a拷贝链接全都会断成普通文件CMake 检查时会出现各种离奇错误。这种问题表面看起来像环境问题实际上就是文件复制方式不对。以上是基于我多次实际操作的经验总结。每个项目环境多少有些差异但梳理依赖、离线归集、本地编译、逐步验证这条主线是通用的。只要把离线资源包准备充分编译环境认真核对TensorRT-LLM 在无 GitHub 权限的服务器上成功跑起来只是时间问题。