AI Companion 视觉功能开发记录:问题与解决方案汇总

从零添加物品识别、模型选型迭代、显存优化到 VLM 场景理解的完整技术深度文

· 36 min read

AI Companion 视觉功能开发记录:问题与解决方案汇总

项目:C:\Users\Ren\Desktop\Projects\AI-Companion 范围:从零添加物品识别 → 模型选型迭代 → 显存/内存优化 → VLM 场景理解 整理时间:2026-07-23


目录

  1. 环境与构建类问题
  2. CUDA / onnxruntime GPU 加速问题
  3. 模型选型迭代
  4. Windows 平台专属坑
  5. VLM 输出质量问题
  6. 显存与内存超售问题
  7. 许可证问题
  8. 最终架构与性能总账

1. 环境与构建类问题

1.1 Tauri/Cargo 构建缓存路径失效

现象:重新启动 npm run dev 时构建失败:

failed to read plugin permissions: failed to read file
'\\?\C:\Users\Ren\Desktop\AI-Companion\desktop\src-tauri\target\debug\build\
tauri-4625cfe41f501dc7\out\permissions\app\autogenerated\commands\app_hide.toml':
The system cannot find the path specified. (os error 3)

原因:Cargo 增量构建缓存里固化了旧的项目路径(C:\Users\Ren\Desktop\AI-Companion,缺少 Projects 一级目录),项目文件夹曾经被移动过,缓存里的绝对路径和当前路径对不上。

解决:清空构建缓存,全量重编译。

cd desktop/src-tauri
cargo clean   # 清掉 4.2GiB 过期缓存
cd ..
npm run dev   # 全量重新编译(约 2~4 分钟,之后走增量构建)

教训:项目目录搬过家之后,Rust/Cargo 的 target/ 目录必须清空重建,不能指望增量编译自愈。


2. CUDA / onnxruntime GPU 加速问题

2.1 onnxruntime-gpu 版本与本机 CUDA 运行库不匹配

现象:物品检测模型一直在用 CPU,日志里有:

[E:onnxruntime:Default, provider_bridge_ort.cc:1744 onnxruntime::TryGetProviderInfo_CUDA]
C:\a\_work\1\s\onnxruntime\core\session\provider_bridge_ort.cc:1426
onnxruntime::ProviderLibrary::Get [ONNXRuntimeError] : 1 : FAIL :
LoadLibrary failed with error 126 "" when trying to load
"...\venv\Lib\site-packages\onnxruntime\capi\onnxruntime_providers_cuda.dll"

[W:onnxruntime:Default, onnxruntime_pybind_state.cc:870
onnxruntime::python::CreateExecutionProviderInstance] Failed to create
CUDAExecutionProvider.

根因排查

检查项结果
nvidia-smiRTX 4060 Laptop GPU,驱动 610.74 —— 硬件没问题
ort.get_available_providers()列出了 CUDAExecutionProvider,说明 DLL 存在但加载失败
项目原有 requirements.txtonnxruntime-gpu==1.18.0(对应 CUDA 11.8 + cuDNN 8 构建)
venv 里实际装的 NVIDIA 包nvidia-cudnn-cu12==9.*(CUDA 12 + cuDNN 9)—— 版本对不上

解决步骤

第一步:升级 onnxruntime-gpu 到匹配 CUDA 12 + cuDNN 9 的版本,并补装缺失的运行库:

pip install -U "onnxruntime-gpu==1.20.1" \
    nvidia-cuda-runtime-cu12 nvidia-cufft-cu12 nvidia-curand-cu12

第二步(关键,仅升级版本还不够):仅升级后依然报同样的错,因为 pip 装的 NVIDIA DLL 在 venv/Lib/site-packages/nvidia/*/bin/ 下,Windows 系统 PATH 里没有这些路径,onnxruntime 的 C++ 层找不到它们。

# config.py — 在 AppConfig.__post_init__ 里注册
@staticmethod
def _register_cuda_dlls():
    import glob
    import sysconfig
    site_packages = sysconfig.get_paths()["purelib"]
    bin_dirs = glob.glob(os.path.join(site_packages, "nvidia", "*", "bin"))
    for bin_dir in bin_dirs:
        try:
            os.add_dll_directory(bin_dir)   # Python 3.8+ 的正规注册方式
        except OSError:
            pass
    # 关键点:仅 add_dll_directory 不够!
    # onnxruntime 的 CUDA provider 是通过 PATH 环境变量解析依赖 DLL 的,
    # 必须同时把这些目录前置到 PATH
    if bin_dirs:
        os.environ["PATH"] = os.pathsep.join(bin_dirs) \
            + os.pathsep + os.environ.get("PATH", "")

验证结果

providers in use: ['CUDAExecutionProvider', 'CPUExecutionProvider']
avg inference: 47.1ms   # 之前 CPU 是 64.3ms

教训

  1. onnxruntime-gpu 的版本必须和实际安装的 CUDA/cuDNN 运行库主版本严格匹配,报错信息本身不会直接告诉你”版本不匹配”,只会说 LoadLibrary failed with error 126(错误 126 = 找不到指定的模块,通常是依赖链上某个 DLL 缺失或版本不对)。
  2. Windows 下 pip 装的 NVIDIA 运行库包(nvidia-cuda-runtime-cu12 等)只是把 DLL 放进 site-packages,不会自动加入系统可搜索路径,必须代码里手动注册(os.add_dll_directory + PATH 双保险)。

2.2 那条 “Memcpy nodes” 警告是否需要处理

现象

2026-07-23 15:28:05 [W:onnxruntime, transformer_memcpy.cc:74
onnxruntime::MemcpyTransformer::ApplyImpl] 4 Memcpy nodes are added to
the graph main_graph for CUDAExecutionProvider. It might have negative
impact on performance (including unable to run CUDA graph).

排查方法:没有直接假设”这是问题”,而是拆解各环节实测耗时:

# 预处理(letterbox + 浮点转换,CPU)
t0 = time.time()
for _ in range(N):
    lb, scale, px, py = det._letterbox(img)
    blob = cv2.cvtColor(lb, cv2.COLOR_BGR2RGB).astype(np.float32) / 255.0
    blob = blob.transpose(2, 0, 1)[None]
pre_ms = (time.time() - t0) / N * 1000

# 纯 session.run(Memcpy 开销就在这里面)
t0 = time.time()
for _ in range(N):
    det._session.run(None, {det._input_name: blob})
run_ms = (time.time() - t0) / N * 1000

结论

环节耗时
预处理4.5ms
session.run(含 Memcpy)9.6ms
后处理(NMS + 坐标映射)2.4ms
完整单帧16.6ms

在 0.3 秒推理间隔下,这条管线只占约 5% 的单核时间片,Memcpy 的实际损耗估计在 1~2ms。结论:不处理,属于”学术性提醒”,真到瓶颈那天再考虑用 onnxsim 简化图或换 TensorRT EP。

教训:ORT 的性能警告不代表”必须优化”,先拆解耗时量化影响,再决定是否值得处理。


3. 模型选型迭代

这是整个会话里变化最大的一块,经历了 5 轮迭代:

3.1 物品检测模型迭代表

轮次模型mAP (COCO)单帧耗时(GPU)显存占用许可证备注
1YOLOv8n37.3~17ms~300MBAGPL-3.0初版,够用但类别受限
2YOLOv8m50.2~30ms~600MBAGPL-3.0精度提升明显
3YOLOv8l52.9~37ms~1GBAGPL-3.0用户主动要求”更牛的”
4RF-DETR Large56.5~42ms~1.5GBApache 2.0Transformer 端到端,DINOv2 backbone,NMS-free
5RF-DETR Nano48.414.5ms323MBApache 2.0显存吃紧后的最终选择:比 v8n 精度更高、更快、更省,且无 AGPL

关键决策点:第 4→5 轮不是”降级”,而是发现自从 VLM 场景层接管语义理解后,实时检测层的职责收窄为”画框 + 报清单”,不再需要 Large 档的精度,RF-DETR Nano 在这个新定位下反而是全面最优解(比同代 YOLOv8n 各项指标都更好)。

3.2 为什么放弃 YOLOE(开放词汇方案)

用户曾提出想用清华的 YOLOE 突破 COCO 80 类限制(认出眼镜、耳机、充电器等)。技术方案已经写好(export_yoloe.py,见下),但中途改变方向:

# export_yoloe.py(未采用,仅记录方案)
from ultralytics import YOLOE

VOCAB = [
    ("eyeglasses", "眼镜"), ("earbuds", "耳塞耳机"),
    ("charger", "充电器"), ("medicine bottle", "药瓶"),
    # ... 约110个自定义词表
]

model = YOLOE("yoloe-11l-seg.pt")
names = [en for en, _ in VOCAB]
model.set_classes(names, model.get_text_pe(names))  # 文本嵌入烘焙进模型
path = model.export(format="onnx", imgsz=640)         # 导出后即普通ONNX,无文本编码器负担

放弃原因

  1. 许可证问题:YOLOE 基于 ultralytics 代码库构建,仓库是 AGPL-3.0,权重同样受限。腾讯 YOLO-World 是 GPL-3.0,同样是传染性协议。
  2. 需求被 VLM 覆盖:讨论 RT-DETR/RF-DETR 路线时确认,“认出更多种类物品”这个需求可以由后续加入的 VLM 场景层(Qwen3.5)更好地解决——VLM 是真正的开放词汇,且不需要预先烘焙词表。

3.3 场景理解模型迭代表(VLM)

轮次模型量化模型体积mmproj显存(稳态)快照延迟
1Qwen3.5-4BQ4_K_M2.74GBF16 (0.67GB)~4.5GB~3s
2Qwen3.5-2BQ4_K_M1.28GBF16 (0.67GB)~2.2GB~2.6s

切换原因:4B 版本导致整机显存超售、卡顿(详见第 6 节)。2B 版本经实测在”粗粒度空间关系+状态判断”这类任务上质量无明显下降。

为什么选 Qwen3.5 而非其他 VLM

  • 2026 年 3 月发布,Apache 2.0(对比 Ultralytics 生态的 AGPL)
  • 明确针对空间感知优化:2D/3D grounding,符合”球在床头还是床底”这类判断需求
  • 已知限制:Ollama 目前无法运行其视觉部分(mmproj 文件是独立架构),必须用 llama.cpp 系后端 —— 这也是选择 llama-server 而非 Ollama 的直接原因

4. Windows 平台专属坑

4.1 CreateProcess 无法解析带正斜杠的相对路径

现象

WARNING:scene:llama-server 启动失败: [WinError 2] The system cannot find the file specified

而文件路径 llama/llama-server.exeos.path.exists() 检查是存在的。

根因:Python 里 subprocess.Popen([exe, ...]) 传入相对路径(用正斜杠 llama/llama-server.exe)时,Windows 的 CreateProcess API 在某些工作目录组合下无法正确解析。

解决

# scene_watcher.py
def _spawn_server(self) -> bool:
    # CreateProcess 对带正斜杠的相对路径不可靠,统一转绝对路径
    exe, model, mmproj = (os.path.abspath(p) for p in (
        self.cfg.llama_server_exe, self.cfg.model_path,
        self.cfg.mmproj_path))
    if not all(os.path.exists(p) for p in (exe, model, mmproj)):
        ...

教训:Windows 下用 subprocess 启动子进程,涉及文件路径的参数一律转成 os.path.abspath() 再传入,不要依赖相对路径 + 当前工作目录的隐式解析。

4.2 控制台编码导致的 UnicodeEncodeError

现象:Python 脚本正常执行完,但打印结果时报错:

File "...\encodings\cp1252.py", line 19, in encode
    return codecs.charmap_encode(input,self.errors,encoding_table)[0]
UnicodeEncodeError: 'charmap' codec can't encode characters in position 0-2: character maps to <undefined>

根因:Windows 中文系统默认控制台代码页是 cp1252/GBK,Python 打印中文字符(如物品的中文标签”公交车”)时,标准输出流按系统默认编码而非 UTF-8 编码,遇到无法表示的字符就报错。这个问题在项目原有代码里已经被感知到并处理过(chat_assistant.py 开头有 sys.stdout.reconfigure),但零散的测试脚本没有这个保护。

解决(测试脚本层面):

import sys
sys.stdout.reconfigure(encoding="utf-8", errors="replace")

或者在 shell 层面设置环境变量:

PYTHONIOENCODING=utf-8 python script.py

或者更可靠的方式——把结果写入文件而不是打印到控制台:

open(os.path.expandvars(r'%TEMP%\result.txt'), 'w', encoding='utf-8').write(text)

教训:这个项目频繁遇到这个问题是因为终端环境(Git Bash + Windows 中文系统)的输出编码链路复杂,最稳妥的调试方式是把结果写文件再读取,而不是依赖控制台直接打印中文。


5. VLM 输出质量问题

5.1 Qwen3.5 的思考模式吃光输出 token,content 为空

现象:第一次调用 VLM 做结构化场景输出时:

// 期望得到类似这样的 JSON
{"scene": "...", "objects": [...]}

// 实际得到
"场景快照失败: Expecting value: line 1 column 1 (char 0)"

进一步排查发现响应体里根本没有有效的 content 字段:

# 排查用的最小复现脚本
body = json.load(urllib.request.urlopen(req, timeout=60))
msg = body['choices'][0]['message']
print({'content': msg.get('content', '')[:300],
       'reasoning': (msg.get('reasoning_content') or '')[:150]})

# 输出:
# {
#   "content": "",
#   "reasoning": "用户要求用一句话描述画面。\n\n1. **观察画面主体**:\n   * 画面中心是一辆蓝白相间的公交车..."
# }

根因:Qwen3.5 默认开启”思考模式”(reasoning),会把所有生成的 token 都用来做内部推理链(reasoning_content 字段),而不是输出到 content 字段。场景快照这种需要低延迟结构化输出的任务完全用不上这个思考过程,反而导致 max_tokens 被推理过程耗尽,最终答案字段是空的。

解决:请求体里显式关闭思考模式。

payload = {
    "messages": [...],
    "response_format": {"type": "json_schema", "json_schema": {...}},
    # 关键一行:关闭 Qwen3.5 的思考模式
    "chat_template_kwargs": {"enable_thinking": False},
    "temperature": 0.2,
    "max_tokens": 512,
}

修复后验证

latency: 5.3s   # 关闭思考模式前 8.5s,还拿不到有效内容
{
 "scene": "在一条城市街道上,一辆蓝色的电动巴士停在路边...",
 "objects": [...]
}

教训:新一代推理模型(Qwen3.5 这类)默认可能开启思考链,如果任务是需要即时结构化输出而不需要”深度思考”,一定要显式关闭,否则会遇到”接口调用成功但内容为空”的诡异现象——报错信息(JSON 解析失败)和真正原因(思考模式吃掉了输出)离得很远,排查时需要先看原始响应体的完整字段,而不是只看解析报错。

5.2 让 VLM 承认”不知道”,防止状态判断幻觉

设计原则(来自用户的工程建议,采纳):VLM 在状态判断上有个典型失败模式——它不会说”看不清”,它会挑一个听起来合理的答案硬猜。解决方式是在 schema 和 prompt 里都显式留一个合法的”不确定”选项:

_PROMPT = """...
- state: 状态(如 打开/合上/亮着/空的/翻到一半),看不清就填 "unknown",不要猜
..."""

在自由问答(详查功能)里同样加上:

"text": "仔细观察这张摄像头画面,回答问题。看不清的部分如实说看不清,不要编造。用户的问题:" + question

实测验证(真实场景,画面里只能看到人的后脑勺):

主人可能刚做过什么:
从画面中只能看到一个人的后脑勺,无法看清其面部或具体动作。
因此,无法判断主人是否刚刚做过什么,也无法推断出房间主人的身份或性别。

模型确实按指示承认了信息不足,而不是编造一个”看起来合理”的答案。

教训:约束模型输出格式(json_schema)解决的是”格式对不对”,约束模型如实表达不确定性需要额外在 prompt 里明确给出”拒绝回答”的合法出口,两者不能互相替代。


6. 显存与内存超售问题(本会话最大的一次故障排查)

6.1 现象

用户报告:“我现在打开软件我都懵逼了,太卡了”,同时观察到 CPU 负荷高、内存占用大,而独立显卡显存”不多”。

6.2 诊断过程

没有直接猜测,而是先测量

nvidia-smi --query-gpu=memory.used,memory.total --format=csv
# 6458 MiB, 8188 MiB   —— 显存已用去 79%

账面推算(配置叠加前):

组件显存占用
RF-DETR Large(物品检测)~1.5GB
Qwen3.5-4B + mmproj + 8K上下文KV cache~4.5GB
人脸检测/情绪识别模型数百MB
Windows 桌面合成器/WebView数百MB~1GB
合计超过 8GB 物理显存

根本机制:显存超售后,NVIDIA 驱动会把显存内容换页到系统内存(Windows 的 WDDM 机制),每次 GPU 访问这部分数据都要走 PCIe 总线搬运——这直接表现为:

  • CPU 忙(驱动层数据搬运的开销算在 CPU 时间里)
  • 系统内存占用暴涨(被换出的显存内容占用了内存)
  • 整机卡顿(连桌面合成都要抢显存带宽)

6.3 解决:三处同时降档,重新做显存预算

# config.py 改动对比

# 改动前
model_path: str = "models/rfdetr-large.onnx"     # ~1.5GB
ctx_size: int = 8192                              # llama-server 上下文
max_side: int = 896                               # VLM 输入图像边长

# 改动后
model_path: str = "models/yolov8n.onnx"          # ~300MB(临时方案,后续换RF-DETR Nano)
ctx_size: int = 2048              # 场景问答约1K token,8K纯属浪费KV显存
max_side: int = 640               # 快照延迟 5s -> 3s,计算缓冲更小
# sidecar_server.py
PREVIEW_FPS = 15PREVIEW_FPS = 10   # 降低JPEG编码CPU负载

第一轮优化验证

VRAM total: 7652 MiB   # 仍然偏高但不再持续增长

6.4 进一步排查:llama-server 为什么”直接吃 3GB 内存”

用户追问这个具体现象,没有停留在”降配置”层面,而是深挖了 Windows 内存管理机制:

用工作集(Working Set)vs 私有内存(Private Memory)拆解

Get-Process llama-server | Select-Object `
  @{n='工作集_MB(含mmap)';e={[int]($_.WorkingSet64/1MB)}}, `
  @{n='私有内存_MB(真占用)';e={[int]($_.PrivateMemorySize64/1MB)}}

实测结果(两行分别是父子进程):

指标数值
工作集281MB / 6023MB
私有内存1248MB / 8102MB

三层机制解释

  1. 模型文件 mmap(约3.4GB):llama.cpp 用 mmap 而非 malloc+read 加载 GGUF 文件,读过的文件页留在进程工作集里被系统统计进”内存占用”,但这是文件背书的干净页,内存紧张时 Windows 可以零代价直接丢弃(不需要写换页文件)。
  2. WDDM 显存后备(真正的负担):Windows 的 GPU 内存模型要求显存内容必须可以被换出到系统内存,所以 GPU 上占用的每一字节显存,系统内存里都要同步预留等量的”提交额度”(commit)。这是 Windows 平台特有的开销,Linux 没有这个机制。
  3. CUDA 上下文和锁页缓冲区(几百MB)。

结论--no-mmap 参数反而更糟(会让第1项从”可丢弃”变成”真实堆内存”),真正能动的杠杆只有缩小模型本身——mmap 和 WDDM 后备都跟着模型体积线性变化。

6.5 最终解决方案:模型双降档

优化前优化后收益
实时检测YOLOv8n (AGPL, 300MB)RF-DETR Nano (Apache, 323MB)mAP 37.3→48.4,速度 17ms→14.5ms
VLM场景理解Qwen3.5-4B (~4.5GB显存)Qwen3.5-2B (~2.2GB显存)显存/内存/延迟均减半

最终实测

VRAM total: 3651 MiB          # 从最初的 6458MiB 降到 3651MiB
llama-server RAM: 1844MB       # 从最初的 ~6GB 工作集降到 1.8GB
场景快照完成: 2.6s              # 从最初的 8.5s(含思考模式bug) 降到 2.6s

不再出现 WDDM 换页,桌面恢复流畅。

教训

  1. 排查”卡顿”类问题时,“降低设置”是表面解法,真正定位根因需要拆解每个组件的资源占用做加法验证,而不是凭感觉调参数。
  2. Windows 上 GPU 相关的内存问题,工作集(Working Set)和私有内存(Private Memory)是完全不同的两个概念,任务管理器默认显示的”内存”经常是工作集,容易造成误判”内存泄漏”的错觉。
  3. 多个 GPU 密集型服务共享一张显卡时,必须提前做”显存预算”(列出每个组件的占用清单加总),而不是等到用满了才发现超售。

7. 许可证问题

贯穿整个模型选型过程的一条隐藏主线:

模型/生态许可证对商业化的影响
YOLOv8 系列(Ultralytics)AGPL-3.0闭源商用需要购买 Ultralytics 商业授权,否则必须开源整个应用
YOLOE(清华,基于Ultralytics构建)AGPL-3.0同上限制
YOLO-World(腾讯)GPL-3.0同样是传染性协议
RF-DETR(Roboflow)Apache 2.0可自由闭源商用
Qwen3.5(阿里)Apache 2.0可自由闭源商用

决策依据:项目的 PRODUCT.md 里有商业化意图,因此在功能等价或更优的情况下,优先选择 Apache 2.0 许可证的模型。这也是从 YOLOv8l 切换到 RF-DETR、放弃 YOLOE 方案的重要原因之一(不是唯一原因,YOLOE 被放弃主要还是因为需求被 VLM 场景层覆盖了)。

教训:技术选型不能只看精度/速度指标,涉及最终会商业分发的项目,许可证条款要作为选型的硬性筛选条件之一,而且要留意”看似衍生但许可证可能不同”的情况(如 RF-DETR 虽然架构上是 DETR 系但许可证是 Apache,YOLOE 虽然是新模型但因为基于 ultralytics 代码库构建而继承了 AGPL)。


8. 最终架构与性能总账

8.1 三层视觉管线分工

摄像头帧 ──┬── 人脸线(原有,未改动)
           │     MediaPipe BlazeFace → SFace/YuNet → 身份 + HSEmotion → 表情
           │     职责:这是谁、什么表情(VLM 无法替代 embedding 比对)

           ├── RF-DETR Nano(实时检测层)
           │     职责:UI 摄像头预览的实时物品框 + 物品清单
           │     10Hz级别,14.5ms/帧,323MB显存

           └── SceneWatcher(VLM场景层,事件驱动)
                 帧差状态机(absdiff,CPU几乎零开销)
                     → 画面变化后稳定1秒 → 截帧(640px)
                     → llama-server(Qwen3.5-2B + mmproj)
                     → json_schema强制输出 + unknown逃生舱
                     → 场景状态JSON(空间关系 + 物体状态)
                 职责:检测框无法表达的"球在床下面""行李箱开着"
                 另有 ask() 方法供"详查":用户问视觉问题时,
                     高分辨率(896px)自由文本回答,只注入当轮对话

8.2 对话注入的三层标注

[视觉] 面前是: J, 表情: Happy,周围物品: 笔记本电脑×2、椅子
[场景] 一个凌乱的卧室,床上堆满了衣物...;门在画面左侧(关闭)
[场景详查] (仅当用户问视觉相关问题时才会出现,高分辨率详细描述)

8.3 全流程性能/资源总账(RTX 4060 Laptop, 8GB VRAM)

组件型号精度/质量延迟显存许可证
人脸检测MediaPipe BlazeFace-实时数十MBApache 2.0
人脸识别OpenCV SFace+YuNet-实时数十MBApache 2.0
情绪识别HSEmotion (EfficientNet-B0)8类实时数十MBMIT
实时物品检测RF-DETR NanomAP 48.414.5ms323MBApache 2.0
场景理解VLMQwen3.5-2B Q4_K_M-2.6s/次(事件驱动)~2.2GBApache 2.0
系统整体稳态~3.65GB / 8GB全栈无AGPL

8.4 关键配置文件改动摘要

# config.py 核心配置(最终版)

@dataclass
class ObjectDetectionConfig:
    model_path: str = "models/rfdetr-nano.onnx"
    conf_threshold: float = 0.45
    interval: float = 0.15

@dataclass
class SceneConfig:
    llama_server_exe: str = "llama/llama-server.exe"
    model_path: str = "models/Qwen3.5-2B-Q4_K_M.gguf"
    mmproj_path: str = "models/Qwen3.5-2B-mmproj-F16.gguf"
    port: int = 8090
    ctx_size: int = 2048
    diff_ratio: float = 0.02
    diff_pixel_delta: int = 28
    stable_secs: float = 1.0
    min_snapshot_gap: float = 8.0
    max_side: int = 640

附:全部 Git 提交记录(本会话)

0c9397b Add on-demand detailed scene inspection ([场景详查])
202d228 Swap to Qwen3.5-2B + RF-DETR Nano: half the footprint, AGPL-free stack
3ca741d Rebalance VRAM budget: lightweight realtime tier, slimmer VLM footprint
a08f65e Add VLM scene understanding layer (Qwen3.5-4B via llama-server)
6546cd5 Switch object detection to RF-DETR Large 2026 (Transformer, NMS-free)
55b9449 Add object detection to the vision pipeline (YOLOv8, GPU-accelerated)
b40bb6b chore: ignore .claude/ and .code-review-graph/ directories
fac96c2 chore: ignore entire .claude/ directory in gitignore

核心经验总结(Top 5)

  1. onnxruntime-gpu 的 CUDA provider 加载失败,报错信息(LoadLibrary error 126)不会告诉你真正原因——需要交叉核对 pip 安装的 NVIDIA 运行库版本与 onnxruntime-gpu 编译时依赖的版本是否匹配,且 Windows 下 pip 装的 DLL 不在系统 PATH,必须手动 os.add_dll_directory + PATH 双重注册。

  2. 新一代大模型的”思考模式”可能默默吃光结构化输出的 token 预算——接口报错是”JSON 解析失败”,但真正原因在完全不同的地方(reasoning_content 字段而非报错本身)。排查这类问题要看完整原始响应体,不能只看报错堆栈。

  3. “卡顿”类问题不要靠感觉调参数,先做资源占用加法核算——列出每个 GPU/内存消费组件的清单和预估占用,加总后再判断是否超售,比一个个”试着调小”更快定位根因。

  4. Windows 下工作集(Working Set)≠ 真实内存占用——任务管理器/Get-Process默认显示的内存数字里混杂了可被系统零代价回收的内存映射文件页(mmap),排查内存问题要用 PrivateMemorySize64 而非 WorkingSet64 判断”真实”占用。

  5. 模型选型的评估维度要包括许可证,尤其是商业化项目——AGPL/GPL 的传染性协议会限制闭源分发,而且不能只看”这个模型是谁发布的”,还要看它的代码库谱系(比如 YOLOE 虽然是清华的新工作,但因为基于 Ultralytics 代码库构建而继承了 AGPL)。