在 Jetson AGX Orin 上部署 TensorRT Edge-LLM:从 Qwen FP16 到 VS Code Agent
记录在 x86 CPU-only 主机上导出 Qwen 模型、在 Jetson AGX Orin 上构建 TensorRT engine、扩展到 32K 上下文、启动 OpenAI 兼容服务,并与 Ollama Gemma4 做真实速度对比。
在 Jetson AGX Orin 上部署 TensorRT Edge-LLM:从 Qwen FP16 到 VS Code Agent
这次实践的目标不是简单把一个模型“跑起来”,而是验证一条可以长期使用的本地推理链路:
Hugging Face checkpoint
│
▼
x86 Ubuntu CPU-only 主机导出 ONNX
│
▼
Jetson AGX Orin 本机构建 TensorRT engine
│
▼
TensorRT Edge-LLM C++ runtime
│
▼
OpenAI-compatible server
│
▼
VS Code Chat / Agent
最终测试了三种路线:
- Qwen3-8B-FP16 + TensorRT Edge-LLM;
- Qwen2.5-Coder-14B-Instruct-FP16 + TensorRT Edge-LLM;
- Gemma4 8B Q4_K_M + Ollama,作为速度参照。
先给结论:Qwen3-8B FP16 的真实 Decode 速度约为 10.8 tokens/s,Qwen2.5-Coder-14B FP16 约为 5.7 tokens/s,Gemma4 Q4_K_M 约为 30.66 tokens/s。TensorRT Edge-LLM 的优势主要在于 TensorRT 优化、原生 C++ runtime、可控的 engine 和服务链路,而不是让 FP16 模型超过 4-bit 模型的纯速度。
一、实际环境
Jetson 侧没有预先假定软件版本,而是先检查系统:
cat /etc/nv_tegra_release
nvcc --version
dpkg-query -W nvidia-jetpack nvidia-l4t-core 2>/dev/null
dpkg -l | grep -Ei 'tensorrt|nvinfer'
python3 --version
cmake --version
gcc --version
git --version
free -h
df -h /
nvpmodel -q
sudo jetson_clocks --show
本次推理设备的环境为:
| 项目 | 实际版本或状态 |
|---|---|
| 设备 | Jetson AGX Orin Developer Kit 64GB |
| CPU 架构 | aarch64 |
| JetPack | 6.2 |
| L4T | R36.4.3 |
| Ubuntu | 22.04.5 LTS |
| Kernel | 5.15.148-tegra |
| CUDA Toolkit | 12.6 |
| TensorRT | 10.3.0 |
| Python | 3.10 |
| GCC | 11.4 |
| CMake | 3.22 |
| TensorRT Edge-LLM | v0.10.0 |
| Git commit | 71dd1bae032e70771265917ec74d3ff4cad07a10 |
| Power mode | MAXN |
Jetson 使用统一内存,主要监控工具是:
tegrastats --interval 1000
性能测试前可以锁定频率:
sudo jetson_clocks
nvpmodel -q
二、整体部署策略
这次选择 TensorRT Edge-LLM v0.10.0,没有为了安装它升级 JetPack、CUDA 或 TensorRT,也没有切换到早期的 TensorRT-LLM Jetson 分支。
export 和 engine build 分开进行:
- x86 主机负责 checkpoint 到 ONNX 的导出;
- Jetson 负责加载 ONNX、调用 TensorRT 和 Edge-LLM plugin 构建 engine;
- 最终运行时主要依赖 engine、tokenizer、chat template 和 plugin。
官方资料:
三、x86 CPU-only 主机完成 export
导出阶段不需要 NVIDIA GPU。CPU-only 主机可以运行 exporter,只是速度较慢、内存占用较高。
以 FP16 模型为例:
cd /path/to/TensorRT-Edge-LLM-export
source .venv/bin/activate
export HF_HUB_OFFLINE=1
export TMPDIR=/path/to/large-disk/tmp
mkdir -p "$TMPDIR"
set -o pipefail
time tensorrt-edgellm-export \
/path/to/models/Qwen3-8B-FP16 \
/path/to/models/Qwen3-8B-FP16/onnx \
2>&1 | tee /path/to/models/Qwen3-8B-FP16/export.log
echo "export_status=${PIPESTATUS[0]}"
Qwen2.5-Coder-14B-Instruct-FP16 使用同样的 export 方式,只需替换输入和输出目录。
成功的 onnx/llm 目录至少应包含:
onnx/llm/
├── config.json
├── embedding.safetensors
├── model.onnx
├── model.onnx.data
├── processed_chat_template.json
├── tokenizer.json
└── tokenizer_config.json
model.onnx.data 是 ONNX external data 权重文件,不能只复制 model.onnx。如果在另一台机器上构建 engine,复制整个 onnx/llm 目录即可。
四、Jetson 侧编译
cd /home/wooley/TensorRT-Edge-LLM
export TRT_PACKAGE_DIR=/usr
export CUDA_CTK_VERSION=12.6
export ENABLE_CUTE_DSL=ALL
export CMAKE_BUILD_PARALLEL_LEVEL=8
cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build --config Release -j8
关键产物为:
build/libNvInfer_edgellm_plugin.so
build/examples/llm/llm_build
build/examples/llm/llm_inference
build/examples/llm/llm_bench
如果需要 server,还要编译 pybind runtime:
source .torch-jetpack62-venv/bin/activate
python experimental/server/setup_pybind.py build_ext --inplace
五、构建 TensorRT engine
Qwen3-8B FP16:
./build/examples/llm/llm_build \
--onnxDir /home/wooley/models/Qwen3-8B-FP16/onnx/llm \
--engineDir /home/wooley/models/Qwen3-8B-FP16/engine \
--maxBatchSize 1 \
--maxInputLen 4096 \
--maxKVCacheCapacity 8192 \
2>&1 | tee logs/qwen3_8b_fp16_engine_build.log
Qwen2.5-Coder-14B 的 8K 输入版本:
./build/examples/llm/llm_build \
--onnxDir /home/wooley/models/Qwen2.5-Coder-14B-Instruct-FP16/onnx/llm \
--engineDir /home/wooley/models/Qwen2.5-Coder-14B-Instruct-FP16/engine-8k \
--maxBatchSize 1 \
--maxInputLen 8192 \
--maxKVCacheCapacity 16384 \
2>&1 | tee logs/qwen25_coder_14b_fp16_engine_build_8k.log
为了给 VS Code Agent 更大的工作区上下文,又构建了 32K 总上下文版本:
./build/examples/llm/llm_build \
--onnxDir /home/wooley/models/Qwen2.5-Coder-14B-Instruct-FP16/onnx/llm \
--engineDir /home/wooley/models/Qwen2.5-Coder-14B-Instruct-FP16/engine-32k \
--maxBatchSize 1 \
--maxInputLen 32256 \
--maxKVCacheCapacity 32768 \
2>&1 | tee logs/qwen25_coder_14b_fp16_engine_build_32k.log
这表示:
32256 输入 tokens + 512 输出 tokens = 32768 总上下文
模型的 max_position_embeddings 是 32768,因此不能同时使用 32768 输入 tokens 和额外的生成空间。
构建时的 OOM
14B engine build 的 CPU 内存需求比运行时高很多。一次构建曾被 Linux OOM killer 终止,增加本地 NVMe swap 后成功:
sudo fallocate -l 64G /swapfile-edgellm
sudo chmod 600 /swapfile-edgellm
sudo mkswap /swapfile-edgellm
sudo swapon /swapfile-edgellm
free -h
swapon --show
swap 主要服务于 build 阶段。正常推理时不应依赖 swap,否则延迟会明显恶化。
六、C++ runtime 推理
使用统一的测试输入:
{
"batch_size": 1,
"temperature": 0.7,
"top_p": 0.8,
"top_k": 20,
"max_generate_length": 256,
"apply_chat_template": true,
"enable_thinking": false,
"requests": [
{
"messages": [
{
"role": "user",
"content": "请用简洁但专业的语言解释蒙特卡洛树搜索的基本原理,以及它为什么适合围棋程序。"
}
]
}
]
}
真实推理测试使用 llm_inference,而不是只看带 --profile 的层级 profiling:
export LD_LIBRARY_PATH=/usr/local/cuda/lib64:/usr/lib/aarch64-linux-gnu:$LD_LIBRARY_PATH
export EDGELLM_PLUGIN_PATH=/home/wooley/TensorRT-Edge-LLM/build/libNvInfer_edgellm_plugin.so
./build/examples/llm/llm_inference \
--engineDir /home/wooley/models/Qwen3-8B-FP16/engine \
--inputFile /home/wooley/models/Qwen3-8B-AWQ/input_cn.json \
--outputFile /home/wooley/models/Qwen3-8B-FP16/output_cn.json \
--warmup 10 \
--dumpProfile \
--profileOutputFile /home/wooley/models/Qwen3-8B-FP16/profile_cn.json \
2>&1 | tee logs/qwen3_8b_fp16_inference.log
14B 测试只需把 --engineDir 换成 engine-32k。
七、真实速度对比
测试结果如下:
| 模型 | 输入 tokens | 输出 tokens | Prefill | Decode | 峰值统一内存 |
|---|---|---|---|---|---|
| Qwen3-8B FP16 + Edge-LLM | 35 | 256 | 335.4 tok/s | 10.8 tok/s | 14.59 GB |
| Qwen2.5-Coder-14B FP16 + Edge-LLM | 52 | 256 | 251.1 tok/s | 5.7 tok/s | 24.75 GB |
| Gemma4 8B Q4_K_M + Ollama | 33 | 256 | 183.3 tok/s | 30.66 tok/s | Ollama 显示约 3.9 GB |
Qwen 两个模型使用的是相同中文文字,但 tokenizer 不同,所以输入 token 数不同。三者都生成了 256 tokens,因此 Decode 对比更可靠。
Gemma4 的测试在另一台 Jetson Orin 上进行,Ollama 显示它是 GGUF、Q4_K_M、8B,并且 100% 使用 GPU。因此这个结果是工程参考,不是完全相同软件环境下的实验室对照。
结论很清楚:
- Gemma4 4-bit 的 Decode 约是 Qwen3-8B FP16 的 2.8 倍;
- Qwen3-8B FP16 约是 Qwen2.5-Coder-14B FP16 的 1.9 倍;
- 14B 的优势是代码能力和模型容量,不是速度;
- 量化格式、模型规模、kernel 和上下文长度对 Orin 速度影响很大。
八、启动 OpenAI-compatible server
cd /home/wooley/TensorRT-Edge-LLM
source .torch-jetpack62-venv/bin/activate
export LD_LIBRARY_PATH=/usr/local/cuda/lib64:/usr/lib/aarch64-linux-gnu:$LD_LIBRARY_PATH
export EDGELLM_PLUGIN_PATH=/home/wooley/TensorRT-Edge-LLM/build/libNvInfer_edgellm_plugin.so
python -m experimental.server \
--model /home/wooley/models/Qwen2.5-Coder-14B-Instruct-FP16/engine-32k \
--host 0.0.0.0 \
--port 8001
检查服务:
curl http://127.0.0.1:8001/health
curl http://127.0.0.1:8001/v1/models
当前返回的模型 ID 是 engine-32k。
九、VS Code Custom Endpoint
VS Code 配置如下:
{
"name": "TensorRT Edge-LLM",
"vendor": "customendpoint",
"apiType": "chat-completions",
"models": [
{
"id": "engine-32k",
"name": "Qwen2.5-Coder-14B-Instruct-FP16",
"url": "http://JETSON_HOST:8001/v1/chat/completions",
"toolCalling": true,
"vision": false,
"contextWindow": 32768,
"maxInputTokens": 32256,
"maxOutputTokens": 512
}
]
}
JETSON_HOST 替换成 Jetson 的局域网地址。maxInputTokens 不能填写 128000,因为 UI 配置不会扩展 engine 的真实上下文。
十、Tool calling 的问题
第一次从 VS Code 发送带工具的请求时,server 返回:
transformers is required for tool-aware chat templates.
在 server venv 中安装仓库需要的 Transformers 和新版 Pillow:
source /home/wooley/TensorRT-Edge-LLM/.torch-jetpack62-venv/bin/activate
python -m pip install \
--no-cache-dir \
--retries 10 \
--timeout 120 \
-i https://pypi.tuna.tsinghua.edu.cn/simple \
"transformers==5.14.1" \
"Pillow>=10.0.0"
仅安装 Transformers 仍可能失败,因为 Jetson 系统自带的旧 Pillow 缺少 PIL.Image.Resampling,导致 AutoProcessor 导入失败。安装完成后必须重启 server。
随后 VS Code 又出现了:
No lowest priority node found
这个错误发生在 VS Code Copilot 客户端内部,不是 Jetson 返回的错误。server 日志显示请求已经是 200 OK。
Agent 模式会把大量工具的名称、描述、参数 JSON Schema、MCP 工具和扩展工具一起注入上下文。32K engine 能解决模型本身的上下文限制,但不能无限容纳所有工具定义、工作区内容、对话历史和输出空间。
处理方式是:
- 在 VS Code 工具配置中关闭不需要的 MCP 和扩展工具;
- 只保留文件读取、文件编辑、终端和代码搜索;
- 为本地模型建立一个只包含少量工具的 custom agent;
- 更新 VS Code 和 Copilot 扩展;
- 普通聊天测试时临时关闭
toolCalling。
这个客户端异常也有公开记录:VS Code Issue #322299。
十一、32K engine 的速度和内存代价
只把 engine 最大容量从 16K 提高到 32K,不会让短 prompt 立刻慢四倍。真正影响速度的是实际使用的 KV cache 长度:
- 2K~4K 上下文通常与 8K engine 接近;
- 8K 上下文开始增加 Prefill 时间;
- 16K~32K 上下文会明显增加 Prefill 时间,Decode 也会随着 KV 读取量增加而下降;
- 最大容量增加本身主要增加内存占用,实际长上下文才会明显增加计算量。
Qwen2.5-Coder-14B 从 16K KV 容量扩展到 32K,KV cache 预计增加约 3GB。64GB AGX Orin 可以承受,但仍应观察统一内存、温度、功耗和长时间稳定性。
十二、最终判断
Qwen3-8B FP16 链路已经稳定跑通,适合作为 Edge-LLM 的基础模型和质量基线。Qwen2.5-Coder-14B FP16 的 32K engine 适合复杂代码上下文,但约 5.7 tok/s 的 Decode 速度会让交互明显变慢。
如果目标是最快的日常本地聊天,4-bit Ollama 模型更有优势;如果目标是研究 TensorRT engine、保持 FP16 质量、使用原生 C++ runtime,TensorRT Edge-LLM 更合适。
对于 VS Code Agent,最现实的方案是使用 8B 模型负责快速交互,14B 模型负责复杂代码理解,并严格限制工具列表,避免把 32K 上下文消耗在工具 Schema 上。后续还应继续验证长上下文、连续多轮工具调用、异常恢复和热稳定性。
Conversation
正在读取留言…