环境诊断与错误排查
Diagnostics 只做检查,不会帮你安装任何东西。
属性
| 类别 | 属性 | 类型 | 读写 | 说明 |
|---|---|---|---|---|
| 环境 | supported | bool | 只读 | 这台机器上的运行时是否可用 |
| 环境 | version | String | 只读 | 版本字符串;没装任何运行时包时是空字符串 |
| 能力 | onnx_cpu | bool | 只读 | onnx-cpu 包已装好且硬件在位;缺任何一项都是 false |
| 能力 | onnx_cuda | bool | 只读 | onnx-cuda 包已装好且硬件在位;缺任何一项都是 false |
| 能力 | onnx_directml | bool | 只读 | onnx-directml 包已装好且硬件在位;缺任何一项都是 false |
| 能力 | onnx_openvino | bool | 只读 | onnx-openvino 包已装好且硬件在位;缺任何一项都是 false |
| 能力 | onnx_trt | bool | 只读 | onnx-trt 包已装好且硬件在位;缺任何一项都是 false |
| 能力 | trt_native | bool | 只读 | trt-native 包已装好且硬件在位;缺任何一项都是 false |
| 能力 | paddle_cpu | bool | 只读 | paddle-cpu 包已装好且硬件在位;缺任何一项都是 false |
| 能力 | paddle_gpu | bool | 只读 | paddle-gpu 包已装好且硬件在位;缺任何一项都是 false |
| 能力 | torchscript | bool | 只读 | torchscript 包已装好且硬件在位;缺任何一项都是 false |
| 能力 | rknn | bool | 只读 | rknn 包已装好且硬件在位;缺任何一项都是 false |
读法
先看 supported。如果它是 false,说明这台机器整体没有装好运行时,十个能力位全是 false 也属于这种情况,这时要先安装运行时,然后再考虑怎么选路。
配合 provider_runtime_version(id) 能分辨是缺包还是缺硬件:查得到版本记录,说明包已经装好,问题出在硬件上;报 ProviderMissing,说明包没有装。
示例:
let d = Diagnostics::new();
println!("{} {}", d.supported, d.version);
println!("{} {} {} {}", d.onnx_cpu, d.onnx_cuda, d.onnx_directml, d.onnx_openvino);
println!("{} {} {} {}", d.onnx_trt, d.trt_native, d.paddle_cpu, d.paddle_gpu);
println!("{} {}", d.torchscript, d.rknn);
ProviderIds 常量清单
权威表 COUNT = 18,id 通过常量或函数获取。
| 组 | id |
|---|---|
| 推理 ×12 | onnx-cpu、onnx-cuda、onnx-openvino、onnx-trt-ep、onnx-directml、trt-native、paddle-cpu、paddle-gpu、edge-rknn、tflite、onnx-tflite、torchscript-cpu |
| 依赖资源包 ×2 | cudnn、cuda-libs |
| 工具链包 ×4 | torch、ultralytics、openvino-intel-gpu、openvino-intel-npu |
provider_id_at()
pub fn provider_id_at(index: usize) -> Option<&'static str>
按下标取 id,返回静态字符串。下标越界返回 None。
示例:
let first = darra_ai::providers::provider_id_at(0);
provider_id_is_valid()
pub fn provider_id_is_valid(provider_id: &str) -> bool
校验 id 是否在权威清单里,大小写不敏感。
示例:
let ok = darra_ai::providers::provider_id_is_valid("onnx-cuda");
provider_runtime_version()
pub fn provider_runtime_version(provider_id: &str) -> Result<String, Error>
取已安装包的运行时版本,返回 JSON,缺字段写 null。载荷格式:onnx / trt-engine / openvino / rknn / paddle / torchscript。
示例:
// 返回形如 {"provider":"onnx-cuda","packVersion":"2.3.1","runtimeVersion":"1.18.0"}
let v = darra_ai::providers::provider_runtime_version("onnx-cuda")?;
错误排查方法论
排查时先按「坏在哪里」分成三类:模型与授权、环境与运行时、推理与运行。
一、模型与授权类
怎么判断:probe 和 open 都失败。
排查顺序:
- 先调
probe:路径不对就核对路径,容器文件损坏就换一份完整的模型。
二、环境与运行时类
怎么判断:同一个模型在别的机器上能打开。诊断快照里目标能力位是 false。
排查顺序:
- 先跑一次诊断快照:如果
supported是 false,说明运行时整体不可用。 - 缺 Provider 包就装上对应的运行时包,再试一次。
缺 Provider 包时重试不会自己好。
三、推理与运行类
怎么判断:open 成功之后才出错。同一段代码换一张图,或者降低并发,就好了。
排查顺序:
- 图片读不出来就检查路径、权限和解码。
等待预算耗尽看超时设置就好,不是推理挂死。
诊断 JSON
诊断 JSON 已做去敏处理,结构如下:
{
"schema": 1,
"sdk": { "version": "1.0.0+runtime", "abi": 65536 },
"os": { "name": "windows", "version": "10.0.26100", "arch": "x64" },
"cpu": { "model": "AMD Ryzen 7 9800X3D", "cores": 16 },
"gpus": [ { "model": "NVIDIA RTX 4070", "driver": "560.94", "cudaMax": "12.6" } ],
"providers": [ { "id": "onnx-cpu", "version": "1.0.0", "path": "C:/DARRA/Runtime/onnx-cpu/1.0.0" } ],
"license": null,
"recentErrors": [ { "code": 11, "message": "...", "when": "2026-09-01T10:00:00+08:00" } ]
}
读取契约:schema 总是存在,sdk / os / cpu 采不到写 null。没有独显时 gpus 是 [],没装包时 providers 是 []。
会话元信息 JSON
这是 Session::meta() 的输出。排障时用它核对任务、标签、输入尺寸、实际 Provider 和授权状态:
{
"schema": 1,
"task": "detect",
"labels": ["scratch", "dent"],
"input": { "width": 640, "height": 640 },
"payloadKind": "onnx",
"provider": "onnx-cuda",
"encrypted": true,
"containerFormat": "DARM1",
"license": { "mode": "trial", "trialRemaining": 12 }
}
task 是短名:detect/classify/segment/pose/obb/ocr/anomaly/depth,认不出返回 None。
license 的取值:试用 {mode:"trial", trialRemaining},永久 {mode:"permanent"}。明文会话(encrypted=false)没有 license 键,也没有 containerFormat 键。
下面是长名到短名的对应关系(模型元数据里的任务名映射到结果里的 task):
| 长名(模型元数据) | 短名 |
|---|---|
detection | detect |
classification | classify |
segmentation / instance-segmentation | segment(两种都合并成 segment) |
pose | pose |
obb | obb |
ocr / ocr-text-detection | ocr(两种都合并成 ocr) |
anomaly | anomaly |
depth | depth(一一对应) |
inputSizeSource / input.source 来源标记只有三个取值(各 Provider 相同):
| 标签 | 含义 | 什么时候标 |
|---|---|---|
graph | 模型里真实存在的维度 —— 模型图里确实定义了固定维度 | 探针从模型图里读到了固定维度 |
containerHeader | 喂数据时约定的尺寸 —— 由声明通道给出。模型是动态维时,这个值不代表模型真实形状 | 声明里有尺寸,但模型图是动态维 |
none | 两个来源都没说 | 两个来源都没有 |
完整示例
use darra_ai::Diagnostics;
use darra_ai::Error;
use darra_ai::providers::{provider_id_at, provider_id_is_valid, provider_runtime_version};
fn main() {
let d = Diagnostics::new();
println!("supported={} version={}", d.supported, d.version);
let caps = [("onnx-cpu", d.onnx_cpu), ("onnx-cuda", d.onnx_cuda)];
for (id, capable) in caps {
let pack = match provider_runtime_version(id) {
Ok(v) => v,
Err(Error::ProviderMissing { .. }) => "未装".to_string(),
Err(Error::UnsupportedPlatform { .. }) => "平台不一致".to_string(),
Err(Error::Internal { message, .. }) => format!("id 非法: {message}"),
Err(e) => format!("查版本失败: {}", e.message()),
};
println!("{id} capable={capable} pack={pack}");
}
println!("caps={}{}{}{}{}{}{}{}{}{}",
d.onnx_cpu as u8, d.onnx_cuda as u8, d.onnx_directml as u8,
d.onnx_openvino as u8, d.onnx_trt as u8, d.trt_native as u8,
d.paddle_cpu as u8, d.paddle_gpu as u8, d.torchscript as u8, d.rknn as u8);
let _ = provider_id_at(0);
assert!(provider_id_is_valid("onnx-cuda"));
}