GPU_GUARD_MONOREPO/docs/superpowers/specs/2026-05-04-vehicle-damage-inspection-skill-design.md
2026-05-20 21:39:12 +08:00

25 KiB
Raw Blame History

汽车环车视频旧伤检测 Skill 设计

日期2026-05-04 状态Draft 范围:新增一个业务级 compute-entry Skill用于从环车视频中抽帧、检测漆面旧伤、定位标注损伤区域并筛选最佳证据帧。 部署约束:生产形态是 Windows 安装包,本设计必须遵守后端 dataDir、bundled skills 复制、可写目录和托盘运行时边界。

1. 背景与目标

RZYX_AI_MONOREPO 当前以 NetaClaw Skill Runtime 为核心承载可扩展业务能力。Skill 已支持 SKILL.mdskill.config.yaml、skill scoped secrets、execute_skill 和 stdin/stdout JSON 协议。

本设计新增一个独立业务 Skill汽车环车视频旧伤检测。它不依赖旧 AI_flow 后端的 BaseSkill、LangChain tool、Midway service 注入或旧 progress emitter而是按新项目 Skill Runtime 的 compute-entry 机制实现。

目标:

  • 输入一个环车视频文件,输出结构化旧伤检测结果。
  • 自动抽帧并保留每帧时间戳。
  • 分批调用多模态模型识别车身漆面旧伤。
  • 对候选损伤调用支持 grounding/bbox 的视觉模型定位区域。
  • 在图片上绘制标注框,筛选每处损伤的最佳证据帧。
  • 所有模型、API Key、API URL、workspace 根目录等运行配置都从 skill.config.yaml env/schema 或输入参数读取,不在代码里硬编码密钥。
  • Windows 安装包生产环境下,所有运行产物只能写入后端 dataDir 下的可写目录,不能写入安装目录、源码目录或 bundled skill 原始目录。

非目标:

  • 第一版不做前端专用结果卡片。
  • 第一版不做实时进度推送。
  • 第一版不训练 YOLO/SAM 等专用模型。
  • 第一版不生成正式检测报告 PDF/HTML。
  • 第一版不做人工复核工作流。

2. 总体形态

采用 一个对外大 Skill + 内部模块化流水线 的结构。

Agent 只调用一次:

{
  "name": "vehicle-damage-inspection",
  "input": {
    "videoUrl": "/upload/20260504/car.mp4",
    "fps": 3,
    "topN": 1
  }
}

Skill 内部固定按协议执行:

输入视频
  -> frame_extractor      抽帧
  -> damage_detector      环车旧伤候选检测
  -> damage_grounding     损伤 bbox 定位和画框
  -> best_frame_selector  去重和最佳帧筛选
  -> 输出最终 JSON

选择大 Skill 的原因:

  • 视频旧伤检测是垂直业务流程,不是通用 Agent 工具。
  • 让 Agent 连续调用四个 Skill 并传递 taskId 会增加失败点。
  • 固定流水线更稳定,便于测试、重跑和后续替换局部模块。
  • 内部模块保持独立,未来仍可拆出单独 Skill。

3. Skill 目录结构

参考 packages/backend/skills/minimax-pdf 的组织方式,但本 Skill 以 compute-entry 为主,额外保留 make.sh 方便人工调试。

packages/backend/skills/vehicle-damage-inspection/
├── SKILL.md
├── skill.config.yaml
├── README.md
├── prompts/
│   ├── damage_detect.md
│   ├── grounding.md
│   ├── dedup.md
│   └── best_frame.md
└── scripts/
    ├── index.cjs
    ├── make.sh
    ├── setup.ps1
    └── lib/
        ├── workspace.cjs
        ├── frame_extractor.cjs
        ├── vision_client.cjs
        ├── damage_detector.cjs
        ├── damage_grounding.cjs
        ├── best_frame_selector.cjs
        ├── image_marker.cjs
        └── json_utils.cjs

职责边界:

文件 职责
SKILL.md 面向 Agent 的能力说明、触发场景、输入输出摘要
skill.config.yaml runtime、entrypoint、依赖、env、接口 schema
scripts/index.cjs stdin/stdout JSON 入口,编排完整流水线
scripts/make.sh Git Bash / POSIX 本地 check/run/demo 调试入口
scripts/setup.ps1 Windows 安装器 setup 入口;当前 installer 在 win32 下使用 powershell -File 执行 setup
workspace.cjs 创建 task workspace、读写 JSON、解析 /upload/ 路径
frame_extractor.cjs ffmpeg/ffprobe 抽帧与视频元信息
vision_client.cjs OpenAI-compatible vision API 调用、重试、JSON/bbox 解析
damage_detector.cjs 分批读取帧,识别候选旧伤
damage_grounding.cjs 读取候选旧伤,找邻近帧,调用 grounding 模型
image_marker.cjs 用 sharp 绘制 bbox 和标签
best_frame_selector.cjs 损伤去重、最佳帧模型筛选、启发式兜底

4. skill.config.yaml

第一版使用 Node runtime避免 Python venv 要求;依赖通过 skill 的 dependencies.node.packages 声明。生产 Windows 安装包应在打包或安装阶段预置 Node 依赖,不把现场 npm install 作为正常运行路径;setup 只作为安装/修复入口。

runtime: node
entrypoint: scripts/index.cjs
timeout: 900000

dependencies:
  system:
    - name: ffmpeg
      check: "ffmpeg -version"
    - name: ffprobe
      check: "ffprobe -version"
    - name: node
      check: "node --version"
  node:
    packages:
      - axios
      - sharp
      - fluent-ffmpeg
      - "@ffmpeg-installer/ffmpeg"
      - "@ffprobe-installer/ffprobe"

setup:
  posix: scripts/make.sh fix
  win32: scripts/setup.ps1

env:
  - name: ARK_API_KEY
    required: true
    description: 火山方舟/豆包 OpenAI-compatible API Key
  - name: ARK_API_URL
    required: false
    default: https://ark.cn-beijing.volces.com/api/v3/chat/completions
    description: OpenAI-compatible chat completions endpoint
  - name: DAMAGE_DETECT_MODEL
    required: true
    default: doubao-seed-2-0-pro-260215
    description: 用于环车旧伤候选检测的多模态模型 ID
  - name: DAMAGE_GROUNDING_MODEL
    required: true
    default: doubao-seed-2-0-pro-260215
    description: 支持 bbox/grounding 输出的视觉模型 ID当前默认豆包模型已支持 bbox 和定位
  - name: BEST_FRAME_MODEL
    required: false
    default: doubao-seed-2-0-pro-260215
    description: 用于损伤去重和最佳帧筛选的模型 ID未配置时复用 DAMAGE_DETECT_MODEL
  - name: RZYX_AI_WORKSPACE_ROOT
    required: false
    description: 检测产物 workspace 根目录;生产环境由宿主注入,默认应为 dataDir/workspace/vehicle-damage-inspection
  - name: RZYX_AI_UPLOAD_ROOT
    required: false
    description: 后端 /upload 路径对应的本地 uploads 根目录;生产环境由宿主注入,默认应为 dataDir/uploads
  - name: RZYX_AI_DATA_DIR
    required: false
    description: 后端运行时 dataDir由 Windows 安装包/runtime 注入skill 可据此推导 workspace/uploads 默认路径

interface:
  input:
    videoUrl:
      type: string
      required: true
      description: 视频本地路径或 /upload/... 路径;第一版不支持 http(s) URL
    taskId:
      type: string
      required: false
      description: 可选任务 ID未传则自动生成
    fps:
      type: number
      required: false
      default: "3"
      description: 抽帧帧率
    quality:
      type: number
      required: false
      default: "90"
      description: 输出 JPG 质量,范围 1-100
    batchSize:
      type: number
      required: false
      default: "12"
      description: 每批发送给检测模型的帧数
    concurrency:
      type: number
      required: false
      default: "2"
      description: 多模态 API 并发数
    groundingWindow:
      type: number
      required: false
      default: "1.5"
      description: 每个损伤时间点前后取帧窗口,单位秒
    topN:
      type: number
      required: false
      default: "1"
      description: 每处损伤返回的最佳证据帧数量
    mode:
      type: string
      required: false
      default: full
      description: full | frames-only | detect-only用于调试或重跑部分流程
  output:
    success:
      type: boolean
    taskId:
      type: string
    workspacePath:
      type: string
    summary:
      type: object
    damages:
      type: array
    artifacts:
      type: object

模型配置原则:

  • 代码不写死 API Key、模型 ID 或业务密钥。
  • skill.config.yaml env 是模型和密钥 schema 的单一来源。宿主需要把 skill.config.yaml 中的 env 声明同步到 NetaClawSkillEntity.envSchema,这样管理页、默认模型和 SkillSecretService.resolveEnv() 使用同一份配置;不要要求在 SKILL.md metadata.env 中重复声明。
  • 当前默认模型为 doubao-seed-2-0-pro-260215。该豆包模型支持多模态理解、bbox 和定位能力,因此第一版可同时作为候选旧伤检测、损伤 grounding 和最佳帧筛选模型使用。
  • DAMAGE_DETECT_MODEL 负责从视频帧中识别候选旧伤,默认 doubao-seed-2-0-pro-260215
  • DAMAGE_GROUNDING_MODEL 负责输出 bbox默认 doubao-seed-2-0-pro-260215;它应返回 <bbox>x1 y1 x2 y2</bbox> 或等价结构化定位。
  • BEST_FRAME_MODEL 可选,未配置时复用检测模型。
  • 所有模型调用使用同一个 ARK_API_URLARK_API_KEY。第一版用一个豆包模型即可跑通;后续如需要按阶段切换模型,再通过 env 覆盖模型 ID。

运行目录配置原则:

  • 生产环境必须由宿主运行时注入 RZYX_AI_DATA_DIR,并由 Skill 推导:
    • RZYX_AI_WORKSPACE_ROOT = {RZYX_AI_DATA_DIR}/workspace/vehicle-damage-inspection
    • RZYX_AI_UPLOAD_ROOT = {RZYX_AI_DATA_DIR}/uploads
  • 管理端仍允许用 skill secrets 覆盖这些路径,但默认不要求用户手填。
  • 开发态没有 RZYX_AI_DATA_DIR 时,才允许 fallback 到 skill 目录下 .workspace

5. 输入输出协议

5.1 输入

scripts/index.cjs 从 stdin 读取 JSON

{
  "videoUrl": "/upload/20260504/car.mp4",
  "taskId": "optional-task-id",
  "fps": 3,
  "quality": 90,
  "batchSize": 12,
  "concurrency": 2,
  "groundingWindow": 1.5,
  "topN": 1,
  "mode": "full"
}

5.2 输出

stdout 只输出一个 JSON 对象:

{
  "success": true,
  "taskId": "20260504-abc",
  "workspacePath": "C:/ProgramData/RZYX-AI/data/workspace/vehicle-damage-inspection/20260504-abc",
  "summary": {
    "duration": 42.3,
    "resolution": "1920x1080",
    "frameCount": 127,
    "candidateDamageCount": 5,
    "mergedDamageCount": 3,
    "bestFrameCount": 3
  },
  "damages": [
    {
      "id": "dmg_001",
      "part": "左前门",
      "type": "划痕",
      "severity": "轻微",
      "description": "左前门中部可见细长白色划痕",
      "timestamps": [12.4, 12.7],
      "bestFrames": [
        {
          "timestamp": 12.4,
          "path": "C:/.../marked_frames/dmg_001_12.40s.jpg",
          "relativePath": "marked_frames/dmg_001_12.40s.jpg",
          "bbox": { "x1": 120, "y1": 340, "x2": 280, "y2": 390 }
        }
      ]
    }
  ],
  "artifacts": {
    "videoInfo": "video_info.json",
    "damageCandidates": "damage_candidates.json",
    "damageAnnotations": "damage_annotations.json",
    "bestFrames": "best_frames.json"
  }
}

失败时:

{
  "success": false,
  "error": "视频文件不存在: ...",
  "taskId": "..."
}

stderr 可输出人类可读日志,但不能输出最终 JSON以免 SkillExecutorService 解析 stdout 失败。

6. Workspace 协议

每次运行创建或复用一个 task workspace

workspace/{taskId}/
├── source/
│   └── input.mp4
├── frames/
│   └── frame_000001_0.33s.jpg
├── marked_frames/
│   └── dmg_001_12.40s.jpg
├── video_info.json
├── damage_candidates.json
├── damage_annotations.json
├── best_frames.json
└── run_summary.json

生产环境 workspace 根目录必须位于后端 dataDir 下:

{dataDir}/workspace/vehicle-damage-inspection/{taskId}/

Windows 安装包场景下,后端 dataDir 解析顺序由 comm/data-dir.ts 决定:外部 config.yamldata.dirNETA_DATA_DIR、pkg 模式 <exe-dir>/data。本 Skill 不直接 import 后端 pDataPath(),而是通过宿主注入的 env 使用该目录。

开发态 fallback

packages/backend/skills/vehicle-damage-inspection/.workspace

该 fallback 仅用于本地调试。生产运行如果既没有 RZYX_AI_DATA_DIR,也没有 RZYX_AI_WORKSPACE_ROOTSkill 应返回配置错误,而不是默默写入 skill 目录。

/upload/... 路径解析策略:

  • 如果 videoUrl 是存在的本地路径,直接使用。
  • 如果 videoUrl 匹配 /upload/<relative>,生产环境使用 RZYX_AI_UPLOAD_ROOT/<relative> 解析。
  • 开发态未配置 RZYX_AI_UPLOAD_ROOT 时,可从 RZYX_AI_DATA_DIR/uploadsRZYX_AI_WORKSPACE_ROOT/../../uploads 推导;生产环境不能依赖推导。
  • 第一版明确不支持 http(s) URL。遇到 http(s) 输入时返回 success:false 和明确错误;如果后续要支持远程 URL必须新增下载模块把视频下载到 source/input.mp4,并实现协议白名单、大小限制、超时、重定向限制和审计日志。

6.1 Windows 安装包运行时约束

Windows 安装包部署时,后端 backend.exe、托盘程序、配置文件和 bundled skills 都在安装目录附近;真正可写的业务数据必须在 dataDir。

本 Skill 需要遵守以下约束:

  • bundled skill 目录只作为模板来源。首次启动时,后端会把 bundled skills 复制到 {dataDir}/skills;运行时加载和执行的是 {dataDir}/skills/vehicle-damage-inspection
  • Skill 代码、prompt、脚本可以位于 {dataDir}/skills/...,但检测产物不得写入该目录,避免升级、重装、依赖安装或清理时误删业务数据。
  • workspace、下载视频副本、抽帧图片、标注图片、JSON artifact 都写入 {dataDir}/workspace/vehicle-damage-inspection/{taskId}
  • 上传视频来源优先解析为 {dataDir}/uploads/...
  • 日志只写 stderr 或 {dataDir}/logs 下由宿主管理的日志,不在安装目录创建日志。
  • 如需清理过期 workspace应按 dataDir 下的 workspace mtime/manifest 执行,不扫描 skill 代码目录。
  • sharpfluent-ffmpeg@ffmpeg-installer/ffmpeg@ffprobe-installer/ffprobe 等运行依赖应在打包或安装阶段准备好。生产运行时不依赖联网执行 npm installsetup.ps1 只用于安装器或人工修复。

6.2 宿主运行时需要补充的 env 注入

当前 SkillExecutorService 只注入 env 白名单和 skill secrets。为减少 Windows 安装包配置成本,宿主应在执行 compute-entry skill 时额外注入:

RZYX_AI_DATA_DIR={pDataPath()}
RZYX_AI_WORKSPACE_ROOT={pDataPath()}/workspace/vehicle-damage-inspection
RZYX_AI_UPLOAD_ROOT={pUploadPath()}

这些不是密钥,不应要求管理员在 Skill secrets 中手动配置。Skill secrets 只负责模型 API Key、模型 ID 和可选覆盖项。

如果暂时不改 SkillExecutorServiceMVP 实现必须把 RZYX_AI_WORKSPACE_ROOTRZYX_AI_UPLOAD_ROOT 标记为部署必填配置,并在 Windows 安装文档里写清楚。

7. 流水线设计

7.1 抽帧

frame_extractor.cjs 负责:

  • 检查视频存在。
  • 用 ffprobe 获取 duration、fps、分辨率、视频流信息。
  • 用 ffmpeg 按 fps 抽帧到 frames/
  • 文件名包含序号和时间戳。
  • 写出 video_info.json

抽帧输出:

{
  "videoPath": "...",
  "videoInfo": {
    "duration": 42.3,
    "videoFps": 29.97,
    "resolution": "1920x1080",
    "extractFps": 3,
    "extractedFrames": 127
  },
  "frames": [
    {
      "index": 0,
      "timestamp": 0,
      "relativePath": "frames/frame_000001_0.00s.jpg",
      "path": "..."
    }
  ]
}

第一版不做复杂视频质量过滤。可以保留轻量重复帧/模糊帧过滤接口,但默认关闭,避免误删证据帧。

7.2 环车旧伤候选检测

damage_detector.cjs 负责:

  • 读取 video_info.jsonframes/
  • batchSize 分批组装多模态请求。
  • 每张图前插入时间戳文本。
  • 调用 DAMAGE_DETECT_MODEL
  • 要求模型只返回 JSON。
  • 合并各批结果并写出 damage_candidates.json

检测 prompt 重点:

  • 只检测车身漆面/外观旧伤:划痕、凹陷、掉漆、裂纹、锈蚀等。
  • 反光、污渍、阴影、压缩噪声不应直接判定为损伤。
  • 不确定结果标记 confidence: "low"uncertain: true
  • 输出位置、类型、严重程度、时间点和证据描述。

候选输出:

{
  "totalFrames": 127,
  "batches": [
    {
      "batch": 1,
      "frameStart": 0,
      "frameEnd": 11,
      "status": "success"
    }
  ],
  "candidates": [
    {
      "id": "cand_001",
      "timestamp": 12.4,
      "part": "左前门",
      "type": "划痕",
      "severity": "轻微",
      "description": "左前门中部可见细长白色划痕",
      "confidence": "medium"
    }
  ]
}

并发控制:

  • 默认 concurrency=2,避免视觉模型请求体过大导致限流。
  • 对 429/TooManyRequests 做指数退避重试。
  • API 请求超时默认 10 分钟。

7.3 损伤定位标注

damage_grounding.cjs 负责:

  • 读取 damage_candidates.jsonvideo_info.json
  • 对每个 candidate 取 timestamp ± groundingWindow 的帧。
  • 调用 DAMAGE_GROUNDING_MODEL
  • 解析 bbox。
  • image_marker.cjs 画红框和标签。
  • 写出 damage_annotations.json

bbox 坐标约定:

  • 模型输出优先使用 0-1000 归一化坐标。
  • 内部统一转换为图片像素坐标后画框。
  • 输出 JSON 同时保存 normalized 和 pixel 坐标。

标注输出:

{
  "annotations": [
    {
      "candidateId": "cand_001",
      "damageId": "dmg_001",
      "part": "左前门",
      "type": "划痕",
      "severity": "轻微",
      "markedFrames": [
        {
          "timestamp": 12.4,
          "sourceRelativePath": "frames/frame_000038_12.40s.jpg",
          "markedRelativePath": "marked_frames/dmg_001_12.40s.jpg",
          "bbox": {
            "normalized": { "x1": 120, "y1": 315, "x2": 280, "y2": 380 },
            "pixel": { "x1": 230, "y1": 340, "x2": 538, "y2": 410 }
          },
          "groundingRaw": "<bbox>120 315 280 380</bbox>"
        }
      ]
    }
  ]
}

如果 grounding 模型未返回 bbox

  • 仍复制原图到 marked_frames/
  • bbox 为空。
  • 标记 groundingStatus: "no_bbox",后续最佳帧筛选降低评分。

7.4 最佳帧筛选

best_frame_selector.cjs 负责:

  • 读取 damage_annotations.json
  • 对候选损伤做去重合并。
  • 对每处损伤的标注帧选择最佳 topN
  • 写出 best_frames.json 和最终 summary。

去重策略:

  • 第一优先:调用 BEST_FRAME_MODEL,输入候选损伤摘要,让模型输出合并分组。
  • 兜底:位置文本相似、损伤类型一致、时间相近的候选合并。
  • 去重后生成稳定 dmg_001dmg_002 编号。

最佳帧策略:

  • 如果某处损伤候选独立帧数小于等于 3按启发式评分选择每个时间点最好的标注版本。
  • 如果候选帧较多,调用模型选择 topN * 3 候选,再按原始时间戳去重,最终保留 topN
  • 模型失败时使用启发式评分。
  • 第一版实现必须真实接入 BEST_FRAME_MODEL 的去重/筛选调用,不能只保留 env 而完全不用;启发式逻辑只作为失败兜底和少量候选快速路径。

启发式评分因素:

  • 有 bbox 的帧优先。
  • bbox 面积适中优先。
  • bbox 不贴边优先。
  • 同一时间戳只保留评分最高的标注版本。

8. 错误处理

场景 行为
输入视频不存在 返回 success:false,不创建后续 artifact
输入 http(s) URL 第一版返回 success:false,提示仅支持本地路径和 /upload/...
ffmpeg/ffprobe 缺失 make.sh check 报错;运行时返回可诊断错误
抽帧为空 返回失败,提示视频无法抽帧
模型配置缺失 返回失败,明确指出缺少 env 名称
生产环境缺少 dataDir/workspace/upload 运行目录 返回失败,提示宿主未注入 RZYX_AI_DATA_DIR 或必要路径
某批检测失败 记录 batch error继续处理其他批次
全部检测批次失败 返回失败,保留 video_info.json 和错误摘要
未发现损伤 返回 success:truedamageCount 为 0
grounding 部分失败 保留无 bbox 标注帧,后续筛选降权
best frame 模型失败 使用启发式兜底
stdout JSON 生成异常 index.cjs 捕获后输出标准失败 JSON

9. 与 Agent Runtime 的关系

本 Skill 通过当前 Skill Runtime 执行:

Agent -> execute_skill({ name, input })
  -> SkillExecutorService
  -> node scripts/index.cjs
  -> stdout JSON
  -> tool_result

ToolResolver 只需要在 Agent 绑定了 vehicle-damage-inspection 且工具治理允许 execute_skill 时注入执行工具。Agent 不需要看到内部四个模块,也不需要调用 bash

为适配 Windows 安装包生产形态,SkillExecutorService 需要在执行该 Skill 时提供运行时目录 env。该改动属于宿主能力补强不改变 execute_skill 对 Agent 暴露的 schema。

第一版不修改 SkillExecutorService 的流式协议。由于视频检测耗时较长,后续可以扩展:

  • 子进程 stderr 输出 JSONL progress。
  • SkillExecutorService 识别 progress 事件并转成 tool_result_streamed
  • 前端对 execute_skill 增加视频检测进度展示。

该扩展不阻塞 MVP。

10. 测试策略

10.1 单元测试

优先测试纯函数和模块边界:

  • parseJSON():兼容 markdown code fence 和文本包裹 JSON。
  • parseBboxes():解析 <bbox>x1 y1 x2 y2</bbox>
  • workspace:创建 task、写读 JSON、路径安全。
  • syncSkillConfigEnvSchema():从 skill.config.yaml env 同步默认模型和密钥 schema 到 DB而不是依赖 SKILL.md metadata.env
  • best_frame_selector:去重兜底、启发式评分、同时间戳去重。
  • image_marker:给一张 fixture 图片画框,确认输出文件存在。

10.2 集成测试

使用小型测试视频:

  • make.sh check 验证依赖。
  • make.sh run --video fixtures/car.mp4 --mode frames-only 验证抽帧。
  • mock vision_client 验证完整流水线不依赖真实 API。
  • 有真实模型配置时,手动运行完整视频检测。

10.3 验收标准

MVP 完成的判断:

  • 后端 skill loader 能识别该 Skill 为 compute-entry
  • Agent 绑定该 Skill 后能通过 execute_skill 调起。
  • 输入视频后能生成 video_info.jsondamage_candidates.jsondamage_annotations.jsonbest_frames.json
  • 有损伤视频能输出至少一张红框标注图。
  • 无损伤视频能返回 success:true 且损伤数为 0。
  • 未配置模型密钥时返回明确错误,不出现硬编码密钥。

11. 实施顺序

  1. 补强 Skill 配置加载:从 skill.config.yaml env 同步 envSchema,确保默认模型和管理页一致。
  2. 创建 Skill 目录、SKILL.mdskill.config.yamlREADME.md
  3. 补强 SkillExecutorService:注入 RZYX_AI_DATA_DIRRZYX_AI_WORKSPACE_ROOTRZYX_AI_UPLOAD_ROOT 这三个非密钥运行时 env。
  4. 实现 scripts/index.cjs stdin/stdout 协议和统一错误包装。
  5. 实现 workspace 和路径解析,生产路径固定落在 dataDir 下,并明确拒绝 http(s) URL。
  6. 实现 ffmpeg 抽帧。
  7. 实现 vision client、prompt 文件和模型配置读取。
  8. 实现候选损伤检测。
  9. 实现 grounding 和图片标注。
  10. 实现 BEST_FRAME_MODEL 参与的去重/最佳帧筛选,以及启发式兜底。
  11. 增加 make.sh check/run/demo 和 Windows setup.ps1
  12. 增加必要测试或 mock 验证脚本。
  13. 用 pkg/Windows 安装包路径模拟验证:确认 workspace/uploads/logs 都不写入安装目录或 skill 代码目录。
  14. 在技能管理页配置模型 env secrets 后进行真实视频手测。

12. 风险与后续扩展

12.1 主要风险

  • 多模态模型容易把反光、污渍、阴影误判为旧伤。
  • 一次发送过多帧会降低模型注意力并增加请求失败概率。
  • grounding 模型能力不稳定时bbox 可能偏移或为空。
  • 长视频会导致抽帧和模型调用成本高。
  • 当前 execute_skill 不支持流式进度,用户体验可能是长时间等待。

12.2 缓解策略

  • 默认低 fps 和小 batch。
  • prompt 明确要求不确定就标记 uncertain不强行报损伤。
  • 对 bbox 失败保留原图和状态,避免流程中断。
  • 保留 mode 参数支持分阶段调试。
  • 输出完整 artifact方便人工复核和后续重跑。

12.3 后续扩展

  • 增加 progress JSONL 协议。
  • 增加前端专用结果卡片。
  • 增加人工复核和修正 bbox。
  • 增加报告生成 Skill 或复用文档生成 Skill。
  • 累积标注数据后训练专用漆面损伤检测模型。