前言

本文记录一次使用 TensorRT-LLM + Triton Server 部署 Llama-3.2-1B-Instruct 的完整过程。目标是将 HuggingFace 格式模型转换为 TensorRT-LLM engine,然后通过 Triton Inference Server 对外提供 HTTP 推理服务。

整个流程涉及三个终端:

  • 终端 1:使用 TensorRT-LLM 容器完成 checkpoint 转换和 engine 构建
  • 终端 2:使用 Triton Server 容器准备 model repository 并启动服务
  • 终端 3:在宿主机测试 Triton HTTP 接口

最终完成的效果是:模型被转换为 INT8 weight-only engine,并通过 Triton HTTP 端口 8010 提供推理服务。本文同时记录了 engine 构建参数过大导致 OOM、fill_template.py 重复执行报错、gpt_model_path 未正确替换和端口占用等问题的排查过程。


核心结论

这次部署过程中最关键的结论有四个:

  1. 不要直接使用默认 trtllm-build 参数。默认构建出的 engine 可能具有很大的 maxBatchSizemaxSequenceLenmaxNumTokens,低显存 GPU 容易在 Triton 加载阶段 OOM。
  2. RTX 4060 单卡环境应主动构建小规格 engine。本文使用 max_batch_size=1max_seq_len=640max_num_tokens=512
  3. fill_template.py 替换的是模板变量名,不一定是最终 config.pbtxt 字段名。例如最终字段是 gpt_model_path,但填充时要传 engine_dir:${ENGINE_DIR}
  4. 不要对已经填充过的 config.pbtxt 重复执行 fill_template.py。更稳妥的做法是每次重新拷贝模板,再统一填充。

环境说明

项目版本 / 规格
GPUNVIDIA GeForce RTX 4060
TensorRT-LLM 镜像nvcr.io/nvidia/tensorrt-llm/release:1.1.0
Triton Server 镜像nvcr.io/nvidia/tritonserver:25.12-trtllm-python-py3
模型Llama-3.2-1B-Instruct
模型原始大小约 2.4GB
engine 输出大小约 2GB
Triton HTTP 端口8010
Triton gRPC 端口8011
Triton metrics 端口8012
项目路径/home/minge/my_repo/tensorrt-llm-study

注意:RTX 4060 显存有限,不建议使用 trtllm-build 默认参数。默认 engine 可能出现 maxBatchSize=2048maxSequenceLen=131072maxNumTokens=8192,容易导致 Triton 加载阶段显存 OOM。本文使用小规格 engine:max_batch_size=1max_seq_len=640max_num_tokens=512


项目目录说明

/home/minge/my_repo/tensorrt-llm-study/
├── llm-model/
│   └── Llama-3.2-1B-Instruct/     # HuggingFace 格式模型
│       ├── model.safetensors      # 模型权重 (~2.4GB)
│       ├── tokenizer.json         # tokenizer 文件
│       ├── config.json            # 模型配置
│       └── generation_config.json
└── trtllm-output/                 # 输出目录
    ├── llama32_1b_int8wo_ckpt/    # TensorRT-LLM checkpoint
    ├── llama32_1b_int8wo_engine_b1_s640/  # 最终 engine
    │   ├── config.json            # engine 配置
    │   └── rank0.engine           # engine 文件 (~2GB)
    └── triton_model_repo/         # Triton model repository
        ├── ensemble/              # ensemble 模型
        ├── preprocessing/         # 预处理模型
        ├── tensorrt_llm/          # TensorRT-LLM 模型
        ├── postprocessing/        # 后处理模型
        └── tensorrt_llm_bls/      # BLS 模型

整体流程概览

本文流程可以分为以下步骤:

  1. 准备阶段:拉取 Docker 镜像、下载模型
  2. 终端 1:启动 TensorRT-LLM 容器、转换 checkpoint、构建 engine
  3. 终端 2:启动 Triton Server 容器、准备 model repository、启动服务
  4. 终端 3:测试 Triton HTTP 接口

流程图:

[HuggingFace 模型]
       ▼ convert_checkpoint.py
[TensorRT-LLM checkpoint]
       ▼ trtllm-build
[TensorRT engine]
       ▼ fill_template.py + Triton config
[Triton model repository]
       ▼ tritonserver
[Triton 推理服务]

终端 1:构建 TensorRT-LLM Engine

1. 拉取 TensorRT-LLM 镜像

在宿主机执行:

docker pull nvcr.io/nvidia/tensorrt-llm/release:1.1.0

2. 准备模型目录

如果模型已在 /home/minge/my_repo/tensorrt-llm-study/llm-model/Llama-3.2-1B-Instruct 目录中,可跳过本步。

如果没有模型,在宿主机执行:

cd /home/minge/my_repo/tensorrt-llm-study/llm-model

git lfs install
git clone https://www.modelscope.cn/LLM-Research/Llama-3.2-1B-Instruct.git

本示例使用 ModelScope 国内镜像源,下载速度更快。也可使用 HuggingFace 源。

3. 启动 TensorRT-LLM 容器

在宿主机执行:

docker run --rm \
  -it \
  --ipc=host \
  --ulimit memlock=-1 \
  --ulimit stack=67108864 \
  --gpus=all \
  -v /home/minge/my_repo/tensorrt-llm-study/llm-model/Llama-3.2-1B-Instruct:/models/Llama-3.2-1B-Instruct:ro \
  -v /home/minge/my_repo/tensorrt-llm-study/trtllm-output:/trtllm-output \
  nvcr.io/nvidia/tensorrt-llm/release:1.1.0

参数说明:

  • --ipc=host:共享宿主机 IPC namespace,提升共享内存性能
  • --ulimit memlock=-1:允许锁定任意大小内存,避免 CUDA 内存分配失败
  • --ulimit stack=67108864:设置栈大小为 64MB
  • -v ...:ro:模型目录以只读模式挂载,防止误操作修改
  • -v /home/minge/my_repo/tensorrt-llm-study/trtllm-output:/trtllm-output:输出目录挂载,engine 将写入此目录

4. 转换 checkpoint

进入容器后,执行:

cd /app/tensorrt_llm/examples/models/core/llama

python convert_checkpoint.py \
  --model_dir /models/Llama-3.2-1B-Instruct \
  --output_dir /trtllm-output/llama32_1b_int8wo_ckpt \
  --dtype float16 \
  --use_weight_only \
  --weight_only_precision int8 \
  --tp_size 1

成功输出:

Total time of reading and converting: 8.440 s
Total time of saving checkpoint: 1.780 s
Total time of converting checkpoints: 00:00:10

参数说明:

  • --dtype float16:模型权重精度为 FP16
  • --use_weight_only:启用 weight-only 量化
  • --weight_only_precision int8:量化精度为 INT8
  • --tp_size 1:Tensor Parallel size 为 1(单 GPU)

5. 构建小规格 Engine

执行:

trtllm-build \
  --checkpoint_dir /trtllm-output/llama32_1b_int8wo_ckpt \
  --output_dir /trtllm-output/llama32_1b_int8wo_engine_b1_s640 \
  --gemm_plugin auto \
  --max_batch_size 1 \
  --max_input_len 512 \
  --max_seq_len 640 \
  --max_num_tokens 512 \
  --opt_num_tokens 128

成功输出:

[04/29/2026-11:04:07] [TRT-LLM] [I] Total time of building Unnamed Network 0: 00:00:31
[04/29/2026-11:04:07] [TRT] [I] Serialized 27 bytes of code generator cache.
[04/29/2026-11:04:07] [TRT] [I] Serialized 134685 bytes of compilation cache.
[04/29/2026-11:04:07] [TRT] [I] Serialized 12 timing cache entries
[04/29/2026-11:04:07] [TRT-LLM] [I] Timing cache serialized to model.cache
[04/29/2026-11:04:07] [TRT-LLM] [I] Build phase peak memory: 10421.96 MB, children: 6296.07 MB
[04/29/2026-11:04:08] [TRT-LLM] [I] Serializing engine to /trtllm-output/llama32_1b_int8wo_engine_b1_s640/rank0.engine...
[04/29/2026-11:04:09] [TRT-LLM] [I] Engine serialized. Total time: 00:00:01
[04/29/2026-11:04:09] [TRT-LLM] [I] Total time of building all engines: 00:00:34

构建参数说明:

参数说明
--max_batch_size1最大批大小,影响 KV cache 预分配
--max_input_len512最大输入序列长度
--max_seq_len640最大总序列长度(输入 + 输出)
--max_num_tokens512最大 token 数,影响运行时显存占用
--opt_num_tokens128优化目标 token 数

这些参数直接影响 engine 运行时的显存占用。RTX 4060 显存有限,不建议使用默认参数。

6. 检查 Engine 文件

ls -lh /trtllm-output/llama32_1b_int8wo_engine_b1_s640

应看到:

-rw-r--r-- 1 root root 7680 config.json
-rw-r--r-- 1 root root 2062328900 rank0.engine

检查 engine 参数:

cat /trtllm-output/llama32_1b_int8wo_engine_b1_s640/config.json | grep -E "max_batch_size|max_seq_len|max_num_tokens|max_input_len"

应看到:

"max_input_len": 512,
"max_seq_len": 640,
"max_batch_size": 1,
"max_num_tokens": 512,

终端 2:启动 Triton Server 并生成 Model Repository

1. 拉取 Triton Server 镜像

在宿主机执行:

docker pull nvcr.io/nvidia/tritonserver:25.12-trtllm-python-py3

2. 启动 Triton Server 容器

在宿主机执行:

docker run --rm \
  -it \
  --name=trt_llm \
  --gpus=all \
  --net=host \
  --shm-size=2g \
  --ulimit memlock=-1 \
  --ulimit stack=67108864 \
  -v /home/minge/my_repo/tensorrt-llm-study/llm-model/Llama-3.2-1B-Instruct:/Llama-3.2-1B-Instruct \
  -v /home/minge/my_repo/tensorrt-llm-study/trtllm-output:/trtllm-output \
  nvcr.io/nvidia/tritonserver:25.12-trtllm-python-py3

参数说明:

  • --net=host:使用宿主机网络,容器直接访问宿主机端口
  • --shm-size=2g:共享内存 2GB,CUDA 和 Triton 需要足够的共享内存

3. 创建 setup_triton_repo.sh 脚本

进入容器后,创建脚本:

cd /app/tools
touch setup_triton_repo.sh
vim setup_triton_repo.sh

i 进入插入模式,粘贴以下脚本内容:

#!/usr/bin/env bash
set -euo pipefail

ENGINE_DIR=${ENGINE_DIR:-/trtllm-output/llama32_1b_int8wo_engine_b1_s640}
TOKENIZER_DIR=${TOKENIZER_DIR:-/Llama-3.2-1B-Instruct}
MODEL_REPO=${MODEL_REPO:-/trtllm-output/triton_model_repo}
TEMPLATE_DIR=${TEMPLATE_DIR:-/app/all_models/inflight_batcher_llm}
FILL_TEMPLATE_SCRIPT=${FILL_TEMPLATE_SCRIPT:-/app/tools/fill_template.py}

echo "ENGINE_DIR=${ENGINE_DIR}"
echo "TOKENIZER_DIR=${TOKENIZER_DIR}"
echo "MODEL_REPO=${MODEL_REPO}"
echo "TEMPLATE_DIR=${TEMPLATE_DIR}"
echo "FILL_TEMPLATE_SCRIPT=${FILL_TEMPLATE_SCRIPT}"

echo
echo "== Check paths =="
test -d "${ENGINE_DIR}" || { echo "ERROR: ENGINE_DIR not found: ${ENGINE_DIR}"; exit 1; }
test -f "${ENGINE_DIR}/rank0.engine" || { echo "ERROR: rank0.engine not found in ${ENGINE_DIR}"; exit 1; }
test -f "${ENGINE_DIR}/config.json" || { echo "ERROR: config.json not found in ${ENGINE_DIR}"; exit 1; }
test -d "${TOKENIZER_DIR}" || { echo "ERROR: TOKENIZER_DIR not found: ${TOKENIZER_DIR}"; exit 1; }
test -d "${TEMPLATE_DIR}" || { echo "ERROR: TEMPLATE_DIR not found: ${TEMPLATE_DIR}"; exit 1; }
test -f "${FILL_TEMPLATE_SCRIPT}" || { echo "ERROR: fill_template.py not found: ${FILL_TEMPLATE_SCRIPT}"; exit 1; }

echo
echo "== Recreate model repository =="
rm -rf "${MODEL_REPO}"
mkdir -p "${MODEL_REPO}"
cp -r "${TEMPLATE_DIR}"/* "${MODEL_REPO}/"

echo
echo "== Fill ensemble config =="
python3 "${FILL_TEMPLATE_SCRIPT}" \
  -i "${MODEL_REPO}/ensemble/config.pbtxt" \
  "triton_max_batch_size:1,logits_datatype:TYPE_FP32"

echo
echo "== Fill preprocessing config =="
python3 "${FILL_TEMPLATE_SCRIPT}" \
  -i "${MODEL_REPO}/preprocessing/config.pbtxt" \
  "tokenizer_dir:${TOKENIZER_DIR},triton_max_batch_size:1,preprocessing_instance_count:1,add_special_tokens:true,multimodal_model_path:,engine_dir:${ENGINE_DIR},max_num_images:0"

echo
echo "== Fill tensorrt_llm config =="
python3 "${FILL_TEMPLATE_SCRIPT}" \
  -i "${MODEL_REPO}/tensorrt_llm/config.pbtxt" \
  "triton_backend:tensorrtllm,triton_max_batch_size:1,decoupled_mode:false,engine_dir:${ENGINE_DIR},max_queue_delay_microseconds:0,batching_strategy:inflight_fused_batching,max_queue_size:0,encoder_input_features_data_type:TYPE_FP16,logits_datatype:TYPE_FP32,prompt_embedding_table_data_type:TYPE_FP16,max_beam_width:1,encoder_engine_dir:,max_tokens_in_paged_kv_cache:1024,max_attention_window_size:,sink_token_length:,batch_scheduler_policy:guaranteed_no_evict,kv_cache_free_gpu_mem_fraction:0.2,cross_kv_cache_fraction:,kv_cache_host_memory_bytes:0,kv_cache_onboard_blocks:true,exclude_input_in_output:false,cancellation_check_period_ms:100,stats_check_period_ms:100,iter_stats_max_iterations:1000,request_stats_max_iterations:0,enable_kv_cache_reuse:false,normalize_log_probs:true,enable_chunked_context:false,gpu_device_ids:0,participant_ids:0,num_nodes:1,lora_cache_optimal_adapter_size:8,lora_cache_max_adapter_size:64,lora_cache_gpu_memory_fraction:0.0,lora_cache_host_memory_bytes:0,lora_prefetch_dir:,decoding_mode:,lookahead_window_size:,lookahead_ngram_size:,lookahead_verification_set_size:,medusa_choices:,eagle_choices:,gpu_weights_percent:,enable_context_fmha_fp32_acc:false,multi_block_mode:false,cuda_graph_mode:false,cuda_graph_cache_size:0,speculative_decoding_fast_logits:false,tokenizer_dir:${TOKENIZER_DIR},guided_decoding_backend:,xgrammar_tokenizer_info_path:"


echo
echo "== Fill postprocessing config =="
python3 "${FILL_TEMPLATE_SCRIPT}" \
  -i "${MODEL_REPO}/postprocessing/config.pbtxt" \
  "tokenizer_dir:${TOKENIZER_DIR},triton_max_batch_size:1,postprocessing_instance_count:1,skip_special_tokens:true"

echo
echo "== Fill tensorrt_llm_bls config =="
python3 "${FILL_TEMPLATE_SCRIPT}" \
  -i "${MODEL_REPO}/tensorrt_llm_bls/config.pbtxt" \
  "triton_max_batch_size:1,decoupled_mode:false,bls_instance_count:1,logits_datatype:TYPE_FP32,prompt_embedding_table_data_type:TYPE_FP16,accumulate_tokens:false,tensorrt_llm_model_name:tensorrt_llm,tensorrt_llm_draft_model_name:,multimodal_encoders_name:"

echo
echo "== Check unresolved template variables =="
UNRESOLVED=$(grep -R '\${' -n "${MODEL_REPO}"/*/config.pbtxt || true)

if echo "${UNRESOLVED}" | grep -v 'enable_trt_overlap' | grep -q '\${'; then
  echo "ERROR: unresolved template variables found:"
  echo "${UNRESOLVED}" | grep -v 'enable_trt_overlap'
  exit 1
else
  echo "OK: no active unresolved template variables."
fi

echo
echo "== Check gpt_model_path =="
grep -n -A3 -B2 "gpt_model_path" "${MODEL_REPO}/tensorrt_llm/config.pbtxt"

echo
echo "== Check tokenizer_dir =="
grep -R -n -A3 -B2 "tokenizer_dir" \
  "${MODEL_REPO}/preprocessing/config.pbtxt" \
  "${MODEL_REPO}/postprocessing/config.pbtxt" || true

echo
echo "== Done =="
echo "Model repository is ready: ${MODEL_REPO}"

粘贴完成后,按 Esc,输入 :wq,回车保存退出。

4. 给脚本执行权限

chmod +x /app/tools/setup_triton_repo.sh

5. 检查脚本语法

bash -n /app/tools/setup_triton_repo.sh

没有输出说明语法正常。

6. 执行脚本生成 model repository

/app/tools/setup_triton_repo.sh

成功时应看到:

OK: no active unresolved template variables.

并且 gpt_model_path 应是:

string_value: "/trtllm-output/llama32_1b_int8wo_engine_b1_s640"

tokenizer_dir 应是:

string_value: "/Llama-3.2-1B-Instruct"

这里尤其要确认 gpt_model_path。如果它仍然是 ${engine_dir},Triton 启动时会认为模型路径为空,并报 gpt_model_path is not specified

7. 启动 Triton Server

tritonserver \
  --model-repository=/trtllm-output/triton_model_repo \
  --http-port=8010 \
  --grpc-port=8011 \
  --metrics-port=8012

成功时应看到:

Started HTTPService at 0.0.0.0:8010
Started GRPCInferenceService at 0.0.0.0:8011
Started Metrics Service at 0.0.0.0:8012

模型表中应看到:

tensorrt_llm | 1 | READY
ensemble     | 1 | READY

如果看到以下警告,可以忽略:

Unable to get power usage for GPU 0
Unable to get energy consumption for GPU 0

终端 3:测试 Triton 服务

另开宿主机终端执行。

1. 检查 Triton 服务 Ready

curl -s localhost:8010/v2/health/ready

2. 检查模型 Ready

curl -s localhost:8010/v2/models/tensorrt_llm/ready
curl -s localhost:8010/v2/models/ensemble/ready

3. 推理测试

curl -s -X POST localhost:8010/v2/models/ensemble/generate \
  -H "Content-Type: application/json" \
  -d '{
    "text_input": "<|begin_of_text|><|start_header_id|>user<|end_header_id|>\n\n请用三句话解释 TensorRT-LLM 的作用。<|eot_id|><|start_header_id|>assistant<|end_header_id|>\n\n",
    "max_tokens": 96,
    "bad_words": "",
    "stop_words": ""
  }'

如果返回中包含 text_output,说明 Triton Server 部署成功。


关键知识点

1. TensorRT-LLM 的作用

TensorRT-LLM 是 NVIDIA 推出的 LLM 推理优化库,核心功能包括:

  • 量化:将 FP16/FP32 权重压缩为 INT8/INT4,减少显存和带宽需求
  • Kernel Fusion:合并多个 GPU 操作为单一 kernel,减少 kernel launch 开销
  • 优化 Attention:使用 Flash Attention、Paged Attention 等高效实现
  • KV Cache 管理:优化缓存策略,支持更长的序列和更高的 batch size

2. checkpoint 和 engine 的区别

  • checkpoint:TensorRT-LLM 中间格式,包含量化后的权重和配置,由 convert_checkpoint.py 生成
  • engine:TensorRT 最终优化产物,可直接用于推理,由 trtllm-build 构建

流程:HuggingFace 模型 → checkpoint → engine

3. weight-only int8 量化

Weight-only quantization (W8A16) 只量化权重,激活值保持 FP16:

  • 权重从 FP16 (2 bytes) → INT8 (1 byte),显存占用减半
  • 推理时权重反量化为 FP16 进行计算
  • 适合显存受限场景,精度损失较小

4. Triton Model Repository 结构

Triton model repository 包含多个模型组件:

目录作用
ensemble组合多个模型形成完整推理流水线
preprocessing文本 → token IDs,加载 tokenizer
tensorrt_llm执行 engine 推理
postprocessingtoken IDs → 文本,解码输出
tensorrt_llm_blsBusiness Logic Script,处理复杂推理逻辑

5. fill_template.py 的作用

fill_template.py 用于填充 Triton config.pbtxt 模板中的变量:

  • 模板文件包含 ${variable_name} 占位符
  • fill_template.py 接收 key:value 参数,替换对应占位符
  • 注意:参数名和模板变量名可能不一致(如 engine_dir 对应 ${engine_dir},但最终写入 gpt_model_path 字段)。这一点是本文最容易踩坑的地方。

6. max_batch_size / max_seq_len / max_num_tokens 与显存的关系

这三个参数直接影响 engine 运行时显存占用:

  • max_batch_size:最大并发请求数,影响 KV cache 预分配
  • max_seq_len:最大序列长度,决定单请求 KV cache 大小
  • max_num_tokens:最大 token 数,影响运行时显存峰值

公式(简化):KV cache 显存 ≈ max_batch_size × max_seq_len × hidden_size × num_layers × 2

低显存 GPU 需降低这些参数,否则 Triton 加载 engine 时可能 OOM。


踩坑记录

问题一:fill_template.py 报 key xxx does not exist

现象

执行 fill_template.py 时报错:

key xxx does not exist

原因

对已经填充过的 config.pbtxt 又重复执行了 fill_template.py。模板变量已被替换,再次执行时找不到对应 key。

解决

重新执行脚本,它会先删除旧 model repository,再重新拷贝模板并填充:

/app/tools/setup_triton_repo.sh

验证

检查 config.pbtxt,不应有未替换的 ${...} 变量:

grep -R '\${' /trtllm-output/triton_model_repo/*/config.pbtxt

问题二:Triton 加载时报 gpt_model_path is not specified

现象

启动 Triton 后出现:

gpt_model_path is not specified
Both encoder and decoder model paths are empty

原因

tensorrt_llm/config.pbtxtgpt_model_path 没有被正确替换。

关键点:在 fill_template.py 命令里应该写 engine_dir:${ENGINE_DIR},不要写 gpt_model_path:${ENGINE_DIR}

虽然最终 config.pbtxt 中的字段名是 gpt_model_path,但模板占位符是 ${engine_dir}

解决

检查填充结果:

grep -n -A3 -B2 "gpt_model_path" \
  /trtllm-output/triton_model_repo/tensorrt_llm/config.pbtxt

正确结果应是:

string_value: "/trtllm-output/llama32_1b_int8wo_engine_b1_s640"

如果不对,重新执行脚本:

/app/tools/setup_triton_repo.sh

验证

启动 Triton 后检查日志,应看到:

tensorrt_llm | 1 | READY

问题三:Triton 报 cudaMallocAsync ... out of memory

现象

启动 Triton 加载 engine 时报:

cudaMallocAsync ... out of memory

或 Triton 进程直接被 kill。

原因

engine 构建规格过大(使用了 trtllm-build 默认参数)。默认参数可能是:

maxBatchSize: 2048
maxSequenceLen: 131072
maxNumTokens: 8192

这些值远超低显存 GPU 的承受能力。

解决

重新构建小规格 engine:

trtllm-build \
  --checkpoint_dir /trtllm-output/llama32_1b_int8wo_ckpt \
  --output_dir /trtllm-output/llama32_1b_int8wo_engine_b1_s640 \
  --gemm_plugin auto \
  --max_batch_size 1 \
  --max_input_len 512 \
  --max_seq_len 640 \
  --max_num_tokens 512 \
  --opt_num_tokens 128

验证

检查 engine config.json

cat /trtllm-output/llama32_1b_int8wo_engine_b1_s640/config.json | grep -E "max_batch_size|max_seq_len|max_num_tokens"

应看到:

"max_batch_size": 1,
"max_seq_len": 640,
"max_num_tokens": 512,

问题四:Socket '0.0.0.0:8000' already in use

现象

启动 Triton 时报:

Socket '0.0.0.0:8000' already in use

原因

默认 8000 端口被占用(可能之前启动的 Triton 进程未清理)。

解决

方法一:杀掉旧进程

pkill -f tritonserver || true
pkill -f launch_triton_server.py || true
pkill -f mpirun || true

方法二:使用其他端口(本文采用)

tritonserver \
  --model-repository=/trtllm-output/triton_model_repo \
  --http-port=8010 \
  --grpc-port=8011 \
  --metrics-port=8012

验证

启动后检查端口:

curl -s localhost:8010/v2/health/ready

最终命令汇总

终端 1:构建 Engine

# 拉取镜像
docker pull nvcr.io/nvidia/tensorrt-llm/release:1.1.0

# 启动容器
docker run --rm -it --ipc=host --ulimit memlock=-1 --ulimit stack=67108864 --gpus=all \
  -v /home/minge/my_repo/tensorrt-llm-study/llm-model/Llama-3.2-1B-Instruct:/models/Llama-3.2-1B-Instruct:ro \
  -v /home/minge/my_repo/tensorrt-llm-study/trtllm-output:/trtllm-output \
  nvcr.io/nvidia/tensorrt-llm/release:1.1.0

# 容器内:转换 checkpoint
python /app/tensorrt_llm/examples/models/core/llama/convert_checkpoint.py \
  --model_dir /models/Llama-3.2-1B-Instruct \
  --output_dir /trtllm-output/llama32_1b_int8wo_ckpt \
  --dtype float16 --use_weight_only --weight_only_precision int8 --tp_size 1

# 容器内:构建 engine
trtllm-build \
  --checkpoint_dir /trtllm-output/llama32_1b_int8wo_ckpt \
  --output_dir /trtllm-output/llama32_1b_int8wo_engine_b1_s640 \
  --gemm_plugin auto \
  --max_batch_size 1 --max_input_len 512 --max_seq_len 640 --max_num_tokens 512 --opt_num_tokens 128

终端 2:启动 Triton

# 拉取镜像
docker pull nvcr.io/nvidia/tritonserver:25.12-trtllm-python-py3

# 启动容器
docker run --rm -it --name=trt_llm --gpus=all --net=host --shm-size=2g \
  --ulimit memlock=-1 --ulimit stack=67108864 \
  -v /home/minge/my_repo/tensorrt-llm-study/llm-model/Llama-3.2-1B-Instruct:/Llama-3.2-1B-Instruct \
  -v /home/minge/my_repo/tensorrt-llm-study/trtllm-output:/trtllm-output \
  nvcr.io/nvidia/tritonserver:25.12-trtllm-python-py3

# 容器内:执行 setup_triton_repo.sh(脚本内容见上文)
/app/tools/setup_triton_repo.sh

# 容器内:启动 Triton
tritonserver --model-repository=/trtllm-output/triton_model_repo --http-port=8010 --grpc-port=8011 --metrics-port=8012

终端 3:测试服务

curl -s localhost:8010/v2/health/ready
curl -s localhost:8010/v2/models/ensemble/ready

curl -s -X POST localhost:8010/v2/models/ensemble/generate \
  -H "Content-Type: application/json" \
  -d '{"text_input": "<|begin_of_text|><|start_header_id|>user<|end_header_id|>\n\n请用三句话解释 TensorRT-LLM 的作用。<|eot_id|><|start_header_id|>assistant<|end_header_id|>\n\n", "max_tokens": 96, "bad_words": "", "stop_words": ""}'

总结

本文完整记录了 TensorRT-LLM + Triton Server 部署 Llama-3.2-1B-Instruct 的流程:

  1. 使用 convert_checkpoint.py 将 HuggingFace 模型转换为 TensorRT-LLM checkpoint
  2. 使用 trtllm-build 构建小规格 engine(适配低显存 GPU)
  3. 使用 Triton Server + fill_template.py 部署推理服务
  4. 通过 HTTP 接口测试推理

关键经验:

  • 低显存 GPU 必须主动限制 max_batch_sizemax_seq_lenmax_num_tokens
  • fill_template.py 的参数名要和模板变量名一致,而不是和最终字段名一致。
  • Triton model repository 中的 ensemblepreprocessingtensorrt_llmpostprocessingtensorrt_llm_bls 需要协同工作。
  • 如果 Triton 日志中仍然出现旧 engine 的大参数,要优先检查 gpt_model_path 是否指向了新 engine。

后续可尝试:

  • 更大模型(如 Llama-3.1-8B)的多 GPU 部署
  • INT4 量化进一步压缩显存
  • 动态 batching 提升吞吐量
  • Kubernetes 上部署 Triton 集群