前言:Agent 的"眼睛"难题

2026 年了,AI Agent 已经能用 Llama、Qwen、DeepSeek 这些纯文本模型写代码、做推理、聊天对话,表现相当不错。但 Agent 活在一个充满图像的世界里——它需要看截图、读营养标签、识别物体、提取图中文字。**视觉能力不是锦上添花,是刚需。**

问题在于:绝大多数本地视觉模型的教程都默认你有一块 24GB 显存的 NVIDIA 显卡。如果你用的是 Jetson Orin(7.4GB 统一内存,ARM64 架构),那就是完全不同的故事了。

我的设备

配置项 参数
设备 NVIDIA Jetson Orin nano super
内存 7.4G统一内存(CPU,GPU共享)
CUDA 12.6,算力8.7
系统 Ubuntu 22.04(ARM64)
PyTorch 2.5.0
网络环境 国内,只能访问百度/清华源等

折腾之路:四次失败

尝试一:Ollama 视觉模型 ❌

Jetson 上本来就装了 Ollama,里面还有 `llava-phi3:3.8b` 和 `qwen2.5vl:3b` 两个视觉模型。能用是能用,但:

- Ollama 的二进制文件没有编译 CUDA 支持,纯 CPU 推理
- `llava-phi3` 中文输出是乱码
- `qwen2.5vl:3b` 倒是准确,但一张图要 60 秒

bash
# 验证 Ollama 有没有 CUDA:
ldd $(which ollama) | grep cuda
# 输出为空——没链接任何 CUDA 库

CPU 跑到 100%,GPU 全程看戏,这谁受得了。

尝试二:从源码编译 llama.cpp + CUDA ❌

这是最"正统"的做法:克隆 llama.cpp 源码,用 CMake 开启 CUDA,编译出带 GPU 加速的 server。

bash
git clone https://github.com/ggerganov/llama.cpp.git
cd llama.cpp
cmake -B build -DGGML_CUDA=ON -DCMAKE_CUDA_ARCHITECTURES=87
cmake --build build -j4 --target llama-server

然后噩梦开始了。llama.cpp 里有 184 个 CUDA kernel 文件,每个都要在 ARM64 的 CPU 上跑 nvcc 编译。模板实例化(`fattn-tile-instance-*`)产生了大量变体,每个编译 15-30 秒。22 分钟后,300+ 目标文件只编完了 127 个,CPU 全程 95%。

Jetson 的 ARM CPU 跑编译本来就是弱项,再加上 CUDA kernel 的海量模板实例,这个方案的编译时间直接劝退。杀掉了。

尝试三:moondream ❌

装上 `moondream` Python 包,一调用发现——1.2.2 版本已经变成纯云端 API 了(`CloudVL`),本地推理接口被砍了。此路不通。

---

尝试四:transformers 5.9 + Qwen2-VL ❌

最新版 `transformers==5.9.0` 需要 PyTorch ≥ 2.6,因为引入了 `torch.distributed.tensor.device_mesh`。Jetson 自带的 PyTorch 是 2.5.0,不兼容。import 直接报错。

最终方案:Florence-2 + PyTorch 原生 CUDA ✅

为什么是 Florence-2

[Florence-2](https://huggingface.co/microsoft/Florence-2-base) 是微软出的超轻量视觉模型:

- 0.23B 参数,比很多"小模型"还小一个数量级
- 支持 OCR、图像描述、物体检测等多种任务
- 模型文件只有 445MB,下载快、加载快
- 在 Jetson 的 7.4GB 内存里只占 0.5GB 显存

核心经验:降级 transformers 到与 PyTorch 2.5 兼容的版本,并使用国内镜像加速下载。

安装步骤

# 1. 修复 numpy 版本冲突(PyTorch 2.5 需要 numpy 1.x)
pip install "numpy<2" --force-reinstall

# 2. 安装兼容版的 transformers(清华源加速)
pip install -i https://pypi.tuna.tsinghua.edu.cn/simple "transformers==4.45.0"

# 3. 安装依赖
pip install einops timm accelerate pillow -i https://pypi.tuna.tsinghua.edu.cn/simple

完整脚本

#!/usr/bin/env python3
"""Florence-2 CUDA 识图 —— Jetson 原生 GPU 加速"""

import sys, os, time

# 国内用户使用 HF 镜像站,否则下载模型会很慢
os.environ["HF_ENDPOINT"] = "https://hf-mirror.com"

import torch
from transformers import AutoProcessor, AutoModelForCausalLM
from PIL import Image

MODEL_ID = "microsoft/Florence-2-base"

def load_model():
    """加载模型到 GPU"""
    print("⏳ 正在加载 Florence-2-base 到 GPU...", flush=True)
    t0 = time.time()
    model = AutoModelForCausalLM.from_pretrained(
        MODEL_ID,
        torch_dtype=torch.float16,   # 半精度,省显存
        trust_remote_code=True        # Florence-2 需要
    ).to("cuda")
    processor = AutoProcessor.from_pretrained(MODEL_ID, trust_remote_code=True)
    mem = torch.cuda.memory_allocated() / 1e9
    print(f"✅ 加载完成,耗时 {time.time()-t0:.1f}s,占用显存 {mem:.1f}GB", flush=True)
    return model, processor

def run(image_path, task, model, processor):
    """执行推理"""
    img = Image.open(image_path).convert("RGB")
    inputs = processor(text=task, images=img, return_tensors="pt").to("cuda", torch.float16)

    t0 = time.time()
    with torch.no_grad():
        gen = model.generate(
            input_ids=inputs["input_ids"],
            pixel_values=inputs["pixel_values"],
            max_new_tokens=1024,
            num_beams=3,
            do_sample=False
        )
    text = processor.batch_decode(gen, skip_special_tokens=False)[0]
    result = processor.post_process_generation(
        text, task=task, image_size=(img.width, img.height)
    )
    print(f"⚡ 推理耗时: {time.time()-t0:.2f}s", flush=True)
    return result


if __name__ == "__main__":
    if len(sys.argv) < 2:
        print("用法: python3 vision_cuda.py <图片路径> [任务]")
        print("任务选项:")
        print("  ocr     - 提取图中所有文字(支持中文)")
        print("  desc    - 详细描述图片内容")
        print("  detail  - 超详细描述")
        print("  obj     - 检测图中物体")
        sys.exit(1)

    path = sys.argv[1]
    task_arg = sys.argv[2] if len(sys.argv) > 2 else "ocr"

    TASKS = {
        "ocr":    "<OCR>",
        "desc":   "<DETAILED_CAPTION>",
        "detail": "<MORE_DETAILED_CAPTION>",
        "obj":    "<OD>",
    }

    if task_arg not in TASKS:
        print(f"未知任务: {task_arg},可选: {list(TASKS.keys())}")
        sys.exit(1)

    model, processor = load_model()
    result = run(path, TASKS[task_arg], model, processor)
    print(f"\n📷 识别结果:\n{result.get(TASKS[task_arg], str(result))}")

使用示例

# OCR 提取文字(中文公告、菜单、营养标签等)
python3 vision_cuda.py 营养标签.jpg ocr

# 描述图片内容
python3 vision_cuda.py 风景照.jpg desc

# 检测图中的物体
python3 vision_cuda.py 街道.jpg obj

---

性能对比

指标 Ollama(CPU) Florence-2(CUDA)
推理耗时 60秒 1秒
GPU显存 0GB(GPU闲置) 0.5GB
OCR准确率 中文乱码,不稳定 准确
模型大小 2.9GB 445MB

60 倍提速。 总占用不到 1GB 存储,在 Jetson Orin 上跑得游刃有余。

---

实测效果

> 输入:一张砖地上趴着小蜥蜴的照片

人物 耗时 结果
OCR 0.88s 图中无文字,返回为空
详细描述 1.3s “一只小蜥蜴蹲在砖路上,周围散落着枯叶“

局限与展望

1. 图像描述是英文的。 Florence-2 的 caption 输出是英文。如果需要中文描述,可以加一个翻译环节,或者换用 `Qwen2-VL-2B`(需要约 4GB 显存)。
2. 不支持多轮对话。这是一个 CLI 工具,不能像 GPT-4V 那样对图片进行多轮问答。如果需要这个能力,需要更大的 VLM 模型。
3. OCR 中文支持良好。 虽然描述是英文,但 OCR 提取中文文字的效果很扎实。

---

踩坑总结

1. ARM64 + CUDA 兼容性差。预编译的二进制文件几乎不包含 ARM64 CUDA 版本。从源码编译又极慢——Jetson 的 ARM CPU 编译 CUDA kernel 是灾难级的。
2. 版本匹配是关键。永远要根据 PyTorch 版本选择 transformers 版本。Jetson 的 PyTorch 2.5 → transformers 4.45 是安全组合。
3. 小模型是 Jetson 的好朋友。 7.4GB 统一内存要同时跑系统和模型,0.23B 的 Florence-2 只占 0.5GB,剩下的 6.9GB 留给 Agent 随便用。
4. 国内用户记得配镜像。HuggingFace 用 `hf-mirror.com`,pip 用清华源 `pypi.tuna.tsinghua.edu.cn`,不然下模型能等到天荒地老。

最后

这一趟折腾下来,最大的感受是:在资源受限的设备上,选对模型比写出好代码更重要。Florence-2 这种专门为边缘设备设计的轻量模型,比硬塞一个 7B 的大模型明智得多。

如果你也在 Jetson 上跑 AI Agent,需要视觉能力,希望这篇文章能让你少走弯路。

Jetson Orin 上原创,用一只砖地上的蜥蜴测试通过。 🦎

Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐