LaiCai Flow guide
YOLO · ONNX · LaiCai Flow

Train a custom object detection model for LaiCai Flow

This guide takes you from raw screenshots to a LaiCai-compatible ONNX model. It uses a real small-object game dataset as the worked example, but the same process applies to app controls, products, icons, tools, and other visible targets.

Tested recipeYOLO26n · 960 px · 17 classes · desktop and Android Agent model contract
Generic game scene with detection boxes around ore, a tree, and a monster
One model can detect multiple related classes in the same scene, such as resources, characters, and object states.
Train a custom object detection model for LaiCai Flow
YouTube

The complete path

  1. CaptureCollect varied frames
  2. LabelDraw tight boxes
  3. MergeKeep class IDs stable
  4. TrainValidate on unseen frames
  5. ExportCreate raw ONNX output
  6. ImportAdd config.json

Before you start

Use object detection when LaiCai must find where an object is on screen. Image classification only answers what an entire image contains and does not return a bounding box.

Should ore, wood, and monsters be in one model?

Usually yes when they appear in the same game or app, use the same screenshot scale, and need to be detected in the same Flow. Separate models only when the scenes are unrelated, the class list becomes very large, or one group needs a different input size or performance target.

01

Prepare useful screenshots

Collect frames from the exact device, resolution, zoom level, and visual quality that LaiCai will see. Diversity matters more than saving many consecutive video frames that look almost identical.

  • Include different positions, sizes, lighting, backgrounds, animation frames, and partial occlusion.
  • Keep difficult examples: tiny objects, edge objects, blur, popups, and visually similar non-targets.
  • Add some background images where none of your target classes appear. Their label files are empty.
  • There is no universal minimum. For a first test, aim for at least 50 varied boxes per class; difficult or similar classes usually need 100–200 or more.
02

Design the class list before labeling

A class should represent one visual decision the Flow needs to make. Keep names short, unique, and stable because the same order is used in YOLO labels, data.yaml, config.json, and the vision.detect class selector.

Treat visually different states as separate classes

If a collected resource still resembles the available resource, label both states, for example Copper and CopperDepleted. Do not expect a confidence threshold alone to reliably separate two real visual states.

Side-by-side comparison of an available copper resource and a depleted resource, each with a separate detection box
Use separate classes when the automation must react differently to the two states.
  • Every visible instance of every target class must be labeled. An unlabeled target is learned as background.
  • Use the same box policy everywhere: tight around the visible object, without large margins.
  • Prefer names such as CopperDepleted or copper_depleted when a labeling tool changes spaces.
03

Label in MakeSense.ai

MakeSense.ai is a free browser-based labeling tool. For LaiCai models, choose Object Detection, use rectangular boxes, and export YOLO annotations.

  1. 1

    Open MakeSense.ai and upload the source images. Keep your original image folder; the exported label ZIP does not replace it.

  2. 2

    Choose Object Detection, not Image Recognition.

  3. 3

    Create the final class list in a fixed order, then draw a rectangle around every target instance.

  4. 4

    Review empty images, missed objects, wrong classes, and loose boxes before export.

  5. 5

    Export Rect annotations as a ZIP package in YOLO format.

04

Build one clean YOLO dataset

Pair each image with a same-named .txt label file. Split by recording session or time range, not by randomly scattering adjacent video frames across train and validation.

Dataset
dataset/
├── images/
│   ├── train/
│   └── val/
├── labels/
│   ├── train/
│   └── val/
└── data.yaml
data.yaml
path: /absolute/path/to/dataset
train: images/train
val: images/val

names:
  0: Copper
  1: CopperDepleted
  2: Wood
  3: Monster

A practical starting split is 80% train and 20% validation. The validation set must contain genuinely unseen scenes.

  • For a new annotation batch, you do not need to upload the old images to MakeSense.ai again.
  • Merge the new images and labels offline, then remap numeric class IDs by class name so the original order stays unchanged.
  • Retrain with the complete old + new dataset. Training only on the new images can make old classes behave like background.
Example YOLO dataset chart showing the number of labeled instances per class and box sizes
Check class counts before training. A class with only a few examples produces unstable metrics even if the overall score looks good.
05

Install Ultralytics and train

The example below uses versions verified with this workflow. A Nano model is the safest starting point for continuous detection. Use 640 px for larger objects and 960 px when important targets are small.

Create an isolated environment
python3 -m venv .venv
source .venv/bin/activate
python -m pip install --upgrade pip
pip install ultralytics==8.4.138 onnx==1.22.0 \
  onnxruntime==1.29.0 onnxslim==0.1.96

Recommended starting parameters

ParameterStarting valueWhy
modelYOLO26nSmall and fast enough for the first iteration.
imgsz960 / 640Use 960 for small targets; use 640 when targets are larger or speed matters more.
epochs200Sets a generous ceiling while early stopping can finish sooner.
patience40Stops after validation has not improved for 40 epochs.
batch8Reduce to 4 or 2 if memory runs out; increase only after measuring.
devicemps / 0 / cpuApple silicon uses mps, NVIDIA uses 0, and any machine can use cpu.
workers4A conservative cross-platform starting point.
seed42Makes dataset and training comparisons easier to reproduce.
close_mosaic15Disables mosaic near the end so final epochs see more natural images.
train.py
from ultralytics import YOLO

model = YOLO("yolo26n.pt")
model.train(
    data="dataset/data.yaml",
    imgsz=960,
    epochs=200,
    patience=40,
    batch=8,
    device="mps",  # NVIDIA: 0 · CPU: "cpu"
    workers=4,
    seed=42,
    close_mosaic=15,
)
06

Validate the model, not just the loss curve

Use the best checkpoint, inspect predictions on unseen screenshots, and review each class separately. A high global score can hide a weak rare class.

  • Precision: how many reported detections are correct.
  • Recall: how many real objects were found.
  • mAP50 and mAP50-95: overall localization and classification quality across thresholds.
  • Confusion matrix: which classes are mistaken for each other or for background.
Example Ultralytics training loss and validation metric curves
Training loss should trend down while validation metrics stabilize. Use the saved best.pt, not automatically the final epoch.
Example normalized confusion matrix for a multi-class game-object detector
Inspect the diagonal and the background row and column. Similar-state classes deserve their own checks.
07

Export a LaiCai-compatible ONNX model

LaiCai imports ONNX, not the training .pt file. Export one static NCHW RGB input, batch 1, float32 or float16, and raw one-to-many predictions so LaiCai can apply confidence filtering and NMS.

export.py
from ultralytics import YOLO

model = YOLO("runs/detect/train/weights/best.pt")
model.export(
    format="onnx",
    imgsz=960,
    batch=1,
    dynamic=False,
    simplify=True,
    nms=None,
)

Package the model directory

Select the directory itself in LaiCai's Model library. The directory must contain config.json and the ONNX file named by modelFile. The class IDs must start at 0 and remain contiguous.

Model directory
game-objects/
├── config.json
└── model.onnx
config.json
{
  "id": "game-objects-v1",
  "name": "Game Objects v1",
  "type": "yolo",
  "modelFile": "model.onnx",
  "outputFormat": "raw_yolo_no_objectness",
  "id2label": {
    "0": "Copper",
    "1": "CopperDepleted",
    "2": "Wood",
    "3": "Monster"
  },
  "label2id": {
    "Copper": 0,
    "CopperDepleted": 1,
    "Wood": 2,
    "Monster": 3
  }
}

Imported with warnings?

If LaiCai says config.json is missing or unreadable, you selected an ONNX file or an incomplete folder. Import the complete model directory and make sure id2label or label2id defines every class.

08

Import and test in LaiCai

Open LaiCai Flow, go to Model library, import the prepared directory, and confirm that the model is marked Compatible before using it in vision.detect.

  • Select the model in Model library and confirm its input, output, output format, and class list.
  • Use Test Current Screen with a class and a reasonable starting threshold such as 0.5.
  • Test both positive frames and negative or confusing frames. A successful inference call is not the same as a detected object.
  • After desktop validation, test the same model separately on Android Agent if the Flow will run on the phone.
V2+

How to improve the next version

Save the original images, YOLO labels, class list, data.yaml, training command, and best.pt together. These files are your reusable dataset source; the exported ONNX file alone is not enough for reliable retraining.

  1. Collect false positives, missed objects, new environments, and new visual states from real runs.
  2. Label only the new images in MakeSense.ai using the final class policy.
  3. Merge old and new data, preserving class IDs by name, then split by session again.
  4. Start the new run from the previous best.pt when the class mapping is compatible, and validate old and new cases.
Never leave visible old classes unlabeled in the new images. They will be treated as background during training.

Common questions

Do I need to re-import all old images into MakeSense.ai?

No. Label the new batch, export it, and merge it with the saved old dataset offline. Re-import old data only when you need to correct old annotations.

Can I simply add one new class?

Yes, but append it after the existing classes and remap the new export by class name. Then retrain on the full dataset so the old classes remain represented.

Why does a model still detect a collected resource?

The two states are visually similar and the model has not learned the distinction. Add a separate depleted-state class or verified hard-negative examples, then retrain and review the confusion matrix.

Should I raise the confidence threshold to fix every false positive?

No. A threshold can trade recall for precision, but it cannot replace missing classes, inconsistent labels, or confusing negative examples.

Official references

The commands and compatibility choices in this guide were checked against the current official documentation and the LaiCai model contract.

Continue in LaiCai Flow

After the model is compatible, use vision.detect to choose a class, threshold, and screen region, then connect the success or failure path to the next Flow action.