# Xisom Edge AI Box & Runtime > Nền tảng AI biên công nghiệp cho phân tích dự đoán, phát hiện bất thường và tối ưu vận hành theo thời gian thực. > Full documentation corpus. Source: https://xisom-docs.pages.dev/vi/ --- ## Tổng quan sản phẩm > Xisom Edge AI Box & Runtime là gì, dành cho ai, và cách nó hòa nhập vào hệ thống công nghiệp của bạn. **Xisom Edge AI Box** là một thiết bị biên công nghiệp kèm runtime, mang khả năng suy luận AI thời gian thực xuống ngay sàn nhà máy của bạn — không cần vòng truy vấn lên đám mây. ### Năng lực cốt lõi - **Suy luận thời gian thực** — mô hình ONNX với thực thi TensorRT, CUDA hoặc CPU để phù hợp phần cứng của bạn. - **Thu nhận dữ liệu luồng** — kết nối các nguồn đầu vào OPC-UA, MQTT và CSV. - **Ghi kết quả ra ngoài** — gửi dự đoán và điểm đặt (setpoint) tới PLC, broker và tệp. - **Vòng đời mô hình** — tải lên, ghép cặp với một datasource, và kích hoạt. - **Khả năng quan sát** — bảng điều khiển tích hợp về độ trễ, thông lượng và execution provider. - **Triển khai được tăng cường bảo mật** — cài đặt offline air-gapped, container không chạy root, RBAC, nhật ký kiểm toán. ### Dành cho ai - **Kỹ sư nhà máy** tự động hóa kiểm tra chất lượng và bảo trì dự đoán. - **Nhà tích hợp hệ thống** kết nối mô hình AI vào hệ thống SCADA/MES hiện có. - **Đội OT/IT** cần suy luận tại chỗ mà không để lộ dữ liệu ra đám mây. ### Kiến trúc tổng quan ```mermaid flowchart LR Sensors[PLC / Sensors] --> Gateway[Datasource Gateway] Gateway --> Runtime[Inference Runtime] Runtime --> Bus[Event Bus / SignalR] Bus --> UI[Web Dashboard] Bus --> Mes[MES / Historian] ``` ### Tiếp theo - Thử [Bắt đầu nhanh](/vi/install-deploy/quickstart/) (≈15 phút) - Cài đặt trên hộp biên với [Cài đặt từ gói offline](/vi/install-deploy/offline-bundle-install/) - Xem [Use Cases](/use-cases/) --- ## Cài đặt từ gói offline > Cài đặt Xisom Edge AI Box tại hiện trường air-gapped từ gói phát hành offline — nạp image, chạy trình cài đặt, đặt secret, khởi động stack và kiểm tra tình trạng. Đây là cách được khuyến nghị để cài đặt tại hiện trường biên của khách hàng khi **không có internet, không truy cập registry, và không build image trên hộp**. Bạn cài đặt mọi thứ từ một **gói phát hành** tự chứa, được phân phối trên thiết bị USB. **Khi nào dùng trang này** Dùng gói offline cho các hộp biên sản xuất tại nhà máy hoặc hiện trường OT. Để đánh giá nhanh trên laptop có internet, [Bắt đầu nhanh](/vi/install-deploy/quickstart/) nhanh hơn. ### Bạn nhận được gì Một gói phát hành là một thư mục duy nhất, được đặt tên theo cấu hình phần cứng và phiên bản (ví dụ `amd64-cpu-v1.5.0`). Chọn gói khớp với phần cứng của bạn: | Cấu hình gói | Dùng khi hộp có… | |----------------|---------------------------| | `amd64-cpu` | CPU x86_64, không GPU — suy luận chỉ trên CPU | | `amd64-gpu` | CPU x86_64 + NVIDIA GPU — tăng tốc TensorRT | | `jetson` | Module biên NVIDIA Jetson (arm64 / L4T) | Bên trong gói: - amd64-cpu-v1.5.0/ - images/ - amd64-cpu-v1.5.0.images.tar.zst ba image dịch vụ, đã nén - manifest.txt tag image + checksum - compose/ - docker-compose.release.yml stack dựa trên image (không có bước build) - .env.template placeholder cho cổng + secret - models/ - predictive_maintenance.onnx mô hình mẫu demo (trọng số ngẫu nhiên) - install.sh - update.sh - uninstall.sh - README.txt tờ hướng dẫn một trang cho người vận hành **Mô hình mẫu chỉ là demo** Mô hình đi kèm có trọng số ngẫu nhiên — các dự đoán của nó vô nghĩa cho đến khi bạn thay bằng mô hình đã huấn luyện của mình. Xem bước 5 của [runbook cài đặt](#runbook-cài-đặt). ### Trước khi bắt đầu Hộp đích phải có sẵn những thứ sau (chúng đi kèm trong image OS golden — trình cài đặt **kiểm tra** chúng và dừng lại nếu thiếu bất kỳ thứ gì; nó không cài giúp bạn): - Docker Engine 20.10 trở lên, kèm plugin `docker compose` v2 - `zstd` và `openssl` - **NVIDIA Container Toolkit** — chỉ với gói GPU và Jetson Cài đặt trên một **hộp đích sạch**. Stack phát hành tái sử dụng cùng tên container, volume và cổng host như stack phát triển — chạy nó trên hộp đã có Xisom đang chạy sẽ gây xung đột. ### Runbook cài đặt 1. ### Sao chép gói vào hộp Sao chép toàn bộ thư mục gói từ thiết bị USB của bạn sang hộp đích, sau đó mở một terminal trong đó: ```bash cd amd64-cpu-v1.5.0/ ``` 2. ### Chạy trình cài đặt Trình cài đặt tự phát hiện cấu hình phần cứng, nạp các image container, sinh secret, khởi động stack và chờ đến khi khỏe mạnh. ```bash sudo ./install.sh ``` Để ép một cấu hình cụ thể, hoặc để cài đặt thêm dịch vụ khởi động cùng máy: ```bash sudo ./install.sh --profile amd64-cpu # ép cấu hình sudo ./install.sh --with-systemd # đồng thời khởi động khi boot ``` Bên dưới, `install.sh` chạy các bước này theo thứ tự: 1. **Preflight** — kiểm tra Docker, GPU toolkit (GPU/Jetson) và đĩa. 2. **Xác minh** checksum của kho lưu image (phát hiện media hỏng hoặc bị giả mạo). 3. **Nạp image** — `docker load` từ kho lưu đi kèm (không pull, không build). 4. **Sinh secret** — tạo secret ký JWT và mật khẩu admin ngay trên hộp rồi ghi vào tệp `.env` được bảo vệ (chế độ `600`). Không secret nào được đóng gói sẵn trong gói. 5. **Khởi động stack** — `docker compose up -d`. 6. **Cổng tình trạng** — chờ cả ba dịch vụ báo cáo khỏe mạnh. 7. **Khởi tạo admin** và **in URL bảng điều khiển + mật khẩu admin một lần duy nhất**. 3. ### Lưu mật khẩu admin **Chỉ in một lần** Trình cài đặt in URL bảng điều khiển và mật khẩu admin được sinh ra **một lần duy nhất** ở cuối lượt chạy. Sao chép ngay vào trình quản lý mật khẩu của bạn — nó không được lưu ở bất kỳ nơi nào bạn có thể đọc lại. 4. ### Xác nhận secret đã được ghi Trình cài đặt sinh secret ký JWT tự động. Bình thường bạn không bao giờ động đến nó, nhưng bạn có thể xác nhận tệp `.env` được bảo vệ tồn tại: ```bash ls -l .env # kỳ vọng chế độ -rw------- (600) ``` Nếu bạn từng cần cung cấp giá trị của riêng mình (ví dụ chính sách quản lý secret của doanh nghiệp), hãy sửa `.env` trước lần `up` đầu tiên và đặt một giá trị ngẫu nhiên mạnh: ```ini # .env (placeholder — sinh một giá trị ngẫu nhiên mạnh, không tái sử dụng) AIBOARD_JWT_SECRET=your-strong-random-jwt-secret ``` 5. ### Thay mô hình demo Gói đi kèm một mô hình demo với trọng số ngẫu nhiên. Thay nó bằng mô hình `predictive_maintenance.onnx` đã huấn luyện của bạn để các dự đoán có ý nghĩa: - **Trước lần cài đầu tiên:** ghi đè `models/predictive_maintenance.onnx` trong gói, sau đó chạy `install.sh`. - **Sau khi cài:** đặt mô hình của bạn vào volume model-data tại `/data/models` và khởi động lại dịch vụ suy luận. Bạn cũng có thể tải mô hình lên sau từ bảng điều khiển — xem [Triển khai mô hình](/configure/models/). 6. ### Kiểm tra tình trạng Xác nhận cả ba dịch vụ đều khỏe mạnh: ```bash docker compose -f compose/docker-compose.release.yml ps ``` Kỳ vọng ba container ở trạng thái `healthy`. Sau đó mở URL bảng điều khiển mà trình cài đặt đã in và đăng nhập bằng tài khoản admin. **Lần chạy GPU đầu tiên chậm** Trên cấu hình GPU và Jetson, dịch vụ suy luận có thể ở trạng thái `unhealthy` trong 2–3 phút khi boot lần đầu vì đang biên dịch engine TensorRT. Điều này là bình thường — hãy chờ, rồi kiểm tra lại `ps`. ### Vận hành ngày-2 **Cập nhật** Triển khai một gói mới hơn. Việc cập nhật chụp snapshot cơ sở dữ liệu trước để bạn có đường rollback. ```bash sudo ./update.sh ``` **Mang .env đang chạy của bạn sang gói mới** `update.sh` đọc `.env` từ thư mục gói — nó giữ secret theo từng lần triển khai, các cổng và tham chiếu image. Một gói vừa tải về không có gì cả, nên hãy sao chép `.env` của bản cài hiện tại sang thư mục gói mới trước khi chạy cập nhật, nếu không nó sẽ hủy bỏ. Snapshot trước-cập-nhật chỉ bao gồm **cơ sở dữ liệu** (không gồm mô hình đã tải lên hay bộ nhớ đệm TensorRT). Hãy sao lưu các volume đó riêng nếu bạn cần rollback mô hình. **Gỡ cài đặt** ```bash ./uninstall.sh # dừng stack, GIỮ toàn bộ dữ liệu ./uninstall.sh --purge # đồng thời xóa mô hình + cơ sở dữ liệu (có lời nhắc xác nhận) ``` ### Nếu có gì đó sai | Triệu chứng | Ý nghĩa | |---------|--------------| | `Bundle manifest missing` | Bạn chạy trình cài đặt từ thư mục nguồn, không phải gói đã lắp ráp. Dùng thư mục gói bạn đã sao chép từ USB. | | `Architecture mismatch` | Sai cấu hình gói cho CPU của hộp này. Dùng cấu hình khớp. | | `NVIDIA toolkit not wired in` | Gói GPU/Jetson trên một hộp không có container toolkit. Dùng gói `amd64-cpu`, hoặc sửa stack GPU trên image OS. | | Suy luận kẹt ở `unhealthy` | Biên dịch TensorRT lần đầu (GPU) mất 2–3 phút — hãy chờ. Nếu không, kiểm tra log suy luận. | | Archive checksum mismatch | Media USB hỏng hoặc bị giả mạo. Sao chép lại gói và thử lại. | Xem runbook [Khắc phục sự cố](/vi/troubleshooting/) đầy đủ để tra cứu các bản sửa theo triệu chứng. ### Bước tiếp theo - [Kết nối một datasource đầu vào](/vi/configure/input-datasources/) — Truyền dữ liệu cảm biến vào runtime. - [Triển khai một mô hình](/configure/models/) — Tải lên và kích hoạt mô hình đã huấn luyện của bạn. - [Suy luận đầu tiên của bạn](/vi/install-deploy/first-inference/) — Khởi tạo một mô hình và xem dự đoán trực tiếp. --- ## Bắt đầu nhanh > Chạy lần suy luận đầu tiên trên Xisom Edge AI Box trong 15 phút. Hướng dẫn này dựng stack demo trên laptop bằng Docker Compose. Không cần phần cứng biên. ### Yêu cầu - Docker 24+ và Docker Compose v2 - 8 GB RAM, 10 GB ổ đĩa trống - (Tùy chọn) NVIDIA GPU + driver để tăng tốc TensorRT ### 1. Tải stack demo ```bash git clone https://github.com/xisom/edge-demo.git cd edge-demo docker compose pull ``` ### 2. Khởi động runtime ```bash docker compose up -d docker compose ps ``` Mở `http://localhost:8080` — bảng điều khiển web. ### 3. Gửi suy luận mẫu ```bash curl -X POST http://localhost:8080/api/inference \ -H 'Content-Type: application/json' \ -d '{"model": "demo-anomaly", "payload": {"temp": 78.4, "rpm": 1450}}' ``` Bạn sẽ thấy kết quả dự đoán và ô độ trễ trên dashboard cập nhật. ### 4. Bước tiếp theo - [Thiết lập phần cứng](/vi/install-deploy/hardware-setup/) - [Suy luận đầu tiên](/vi/install-deploy/first-inference/) - [Kết nối nguồn dữ liệu đầu vào](/vi/configure/input-datasources/) --- ## Thiết lập phần cứng > Chuẩn bị Xisom Edge AI Box, chọn chế độ execution-provider và kết nối vào mạng của bạn. Chuẩn bị hộp, chọn cách chạy suy luận (GPU so với CPU), và đấu nối vào mạng nhà máy của bạn trước khi cài phần mềm. ### Phần cứng được hỗ trợ | Cấp | CPU | GPU | RAM | Chế độ suy luận | |------|-----|-----|-----|----------------| | Lite | x86_64 8 nhân | — | 16 GB | Chỉ CPU | | Pro | x86_64 8 nhân | NVIDIA T4 / A2 | 32 GB | Sẵn sàng TensorRT | | Max | x86_64 16 nhân | NVIDIA L4 / A10 | 64 GB | Đa mô hình | | Edge | NVIDIA Jetson (Orin / Xavier) | tích hợp | 16–32 GB | TensorRT trên L4T (arm64) | ### Điều kiện tiên quyết cho GPU biên Nếu hộp có NVIDIA GPU (cấp Pro, Max, hoặc Jetson), image của hệ điều hành phải có sẵn những thứ sau trước khi bạn cài Xisom: - Một **driver NVIDIA** tương thích cho GPU. - **NVIDIA Container Toolkit**, để container có thể truy cập GPU. - Với module Jetson: một image nền **L4T (arm64)** đã tích hợp sẵn toolkit. Trên một hộp chỉ-CPU (Lite) bạn không cần bất kỳ thứ nào ở trên — suy luận chạy trên CPU. ### Các chế độ execution-provider Runtime suy luận chọn một **execution provider** khớp với phần cứng của bạn. Bạn chọn cấu hình phù hợp khi cài đặt (xem [Cài đặt từ gói offline](/vi/install-deploy/offline-bundle-install/)). **TensorRT (GPU)** **Hiệu năng tốt nhất.** Dùng NVIDIA GPU với tăng tốc TensorRT cho độ trễ suy luận thấp nhất. Có trên cấp Pro, Max và Jetson. - Cần driver NVIDIA + Container Toolkit trên host. - Lần chạy đầu tiên biên dịch một engine TensorRT — kỳ vọng 2–3 phút khởi động trước khi dịch vụ suy luận báo cáo khỏe mạnh. **CUDA (GPU)** **Tăng tốc GPU mà không biên dịch engine TensorRT.** Chạy mô hình trên GPU qua CUDA. Một lựa chọn dự phòng tốt khi một mô hình không tương thích TensorRT, hoặc để tránh độ trễ biên dịch lần chạy đầu. - Cần driver NVIDIA + Container Toolkit trên host. **CPU** **Không cần GPU.** Suy luận chạy hoàn toàn trên CPU. Dùng cấu hình cài đặt `amd64-cpu` trên hộp cấp Lite hoặc bất cứ nơi nào không có GPU. - Tính di động cao nhất, độ trễ cao hơn các chế độ GPU. Chọn chế độ GPU khớp với mô hình của bạn. Nếu một hộp GPU bất ngờ tụt xuống CPU, bảng điều khiển hiển thị execution provider đang hoạt động để bạn phát hiện. Xem [Giám sát](/operate/monitoring/). ### Yêu cầu về mạng - Một cổng LAN cho quản lý (bảng điều khiển + API). - Một cổng thứ hai tùy chọn cho mạng OT nơi cảm biến và PLC của bạn nằm. - HTTPS đi ra tới máy chủ license và cập nhật của bạn, nếu có dùng (danh sách cho phép có thể cấu hình). Hiện trường air-gapped cài đặt từ [gói offline](/vi/install-deploy/offline-bundle-install/) và không cần truy cập đi ra. ### Lần boot đầu tiên 1. Cắm nguồn và cả hai cổng mạng. 2. Truy cập `https://your-device-ip` (thay bằng IP quản lý của hộp). 3. Đăng nhập bằng tài khoản admin được tạo trong lúc cài. 4. Tiếp tục đến [Kết nối một datasource đầu vào](/vi/configure/input-datasources/). ### Nếu có gì đó sai - Hộp GPU tụt xuống CPU, hoặc kẹt ở `unhealthy` khi boot lần đầu — xem runbook [Khắc phục sự cố](/vi/troubleshooting/). ### Bước tiếp theo - [Cài đặt từ gói offline](/vi/install-deploy/offline-bundle-install/) — Runbook cài đặt air-gapped, có thể giao qua USB. - [Kết nối một datasource](/vi/configure/input-datasources/) — Truyền dữ liệu cảm biến và quy trình vào. --- ## Suy luận đầu tiên của bạn > Khởi tạo một mô hình, bật một datasource, và xem các dự đoán trực tiếp hiện ra trên bảng điều khiển. Sau khi cài, hãy chạy một vòng đầu-cuối: **khởi tạo một mô hình → bật một datasource → xem dự đoán**. Đây là cách nhanh nhất để xác nhận runtime đang hoạt động. Mỗi bước bên dưới có một hướng dẫn riêng nếu bạn muốn chi tiết đầy đủ. Trang này là phần đi qua đường-thuận-lợi. 1. ### Đăng nhập Mở URL bảng điều khiển được in trong lúc cài và đăng nhập bằng tài khoản admin của bạn. 2. ### Tải lên một mô hình Vào **Models** và tải lên mô hình ONNX của bạn. Ghi lại **window size** và **feature count** của nó — chúng phải khớp với datasource bạn ghép cặp. Xem [Triển khai mô hình](/configure/models/) để biết định dạng và phiên bản. 3. ### Thêm một datasource đầu vào Vào **Datasources → Input** và thêm một nguồn — ví dụ một topic MQTT hoặc một endpoint OPC-UA. Ánh xạ mỗi thẻ cảm biến (tag) tới một kênh đầu vào của mô hình, và đặt **window size** khớp với mô hình. Xem [Kết nối Datasource đầu vào](/vi/configure/input-datasources/) để biết phần đi qua đầy đủ theo từng giao thức. 4. ### Ghép cặp mô hình với datasource Trên datasource, ghép cặp mô hình bạn đã tải lên. Nền tảng chạy một kiểm tra tương thích — `window size × feature count` phải khớp ở cả hai phía. Nếu không đạt, hãy điều chỉnh window size của datasource hoặc tạo lại mô hình. 5. ### Bật, rồi bắt đầu truyền Bật **Enable** trên hàng datasource. Việc bật xác thực cấu hình, nạp mô hình đã ghép cặp, và kết nối adapter — nhưng nó **không** bắt đầu truyền dữ liệu ngay. Bấm **Start** để bắt đầu suy luận. **Enable và Start là hai bước** Enable chuẩn bị runtime (nạp mô hình, kết nối nguồn). Start bắt đầu luồng dữ liệu. Chỉ một datasource đầu vào được bật tại một thời điểm — bật một nguồn mới sẽ tắt nguồn trước đó. 6. ### Theo dõi dự đoán Mở **Dashboard**. Trong khoảng 20 giây (sau khi cửa sổ mẫu đầu tiên đến nơi) thẻ dự đoán cập nhật theo thời gian thực, và các thẻ cảm biến hiển thị số đọc trực tiếp. ### Kiểm tra kết quả Khung giám sát hiển thị độ trễ (p50 / p95 / p99), thông lượng, tỷ lệ lỗi, và execution provider đang hoạt động. Xem [Giám sát](/operate/monitoring/) để đọc các KPI. ### Nếu có gì đó sai - Ghép cặp bị từ chối, datasource không bật được, hoặc không có dự đoán nào xuất hiện — xem runbook [Khắc phục sự cố](/vi/troubleshooting/). ### Bước tiếp theo - [Gửi kết quả ra ngoài](/vi/configure/output-datasources/) — Ghi dự đoán ngược về một PLC hoặc broker. - [Giám sát runtime](/operate/monitoring/) — Độ trễ, thông lượng và độ trôi (drift). --- ## Kết nối Datasource đầu vào > Truyền dữ liệu cảm biến và quy trình vào runtime Xisom — thêm một nguồn OPC-UA, MQTT hoặc CSV, ánh xạ tag, ghép cặp mô hình, bật và bắt đầu suy luận. Một **datasource đầu vào** là một nguồn dữ liệu cảm biến logic — một endpoint OPC-UA, một nhóm topic MQTT, một tệp phát lại CSV, v.v. Mỗi nguồn là một adapter có kiểu với thiết lập kết nối và danh sách tag riêng. Bạn ánh xạ các tag của nó tới các kênh đầu vào của mô hình, rồi bật nó để bắt đầu suy luận. ### Các nguồn đầu vào được hỗ trợ - **OPC-UA** — đăng ký các tag từ bất kỳ máy chủ tuân thủ nào. - **MQTT** — tự mang broker của bạn, hỗ trợ TLS. - **CSV** — phát lại dữ liệu đã ghi từ một tệp (rất phù hợp để thử nghiệm). - **PLC** — Modbus TCP và các giao thức công nghiệp khác. **Một đầu vào được bật tại một thời điểm** Tối đa **một** datasource đầu vào có thể được bật tại bất kỳ thời điểm nào. Bật một nguồn mới sẽ tự động tắt nguồn trước đó. Điều này giữ runtime gắn với một luồng duy nhất, có thể dự đoán được. ### Đi qua: thêm một nguồn và bắt đầu suy luận 1. ### Mở trang Datasources Trong bảng điều khiển, vào **Datasources → Input**, rồi bấm **+ Create**. 2. ### Chọn loại adapter và điền kết nối Chọn loại nguồn. Biểu mẫu thích ứng theo giao thức bạn chọn — điền vào endpoint, thông tin xác thực, và bất kỳ trường đặc thù giao thức nào. Các trường bí mật (mật khẩu, token) bị che thành `***` sau khi lưu. **OPC-UA** | Trường | Ví dụ | |-------|---------| | Endpoint | `opc.tcp://your-opcua-host:4840/factory/line1` | | Security policy | `None` (hoặc một profile `Basic256Sha256` với chứng chỉ) | | Authentication | `Anonymous` (hoặc tên người dùng/mật khẩu) | Các tag được tham chiếu bằng **NodeId**, ví dụ `ns=2;i=2` (dạng số) hoặc `ns=2;s=Temperature` (dạng chuỗi). **MQTT** | Trường | Ví dụ | |-------|---------| | Broker URL | `mqtt://your-broker-host:1883` (hoặc `mqtts://` cho TLS) | | Topic | `factory/line1/temp` | | JSON path | `value` (trích số đọc dạng số từ tin nhắn) | | Username / password | tùy chọn (bị che khi lưu) | **CSV** | Trường | Ví dụ | |-------|---------| | File | một tập dữ liệu đã ghi để phát lại | | Columns | các cột cảm biến để đưa vào làm kênh | CSV chỉ dùng để phát lại — hữu ích để thử một mô hình mà không cần kết nối nhà máy trực tiếp. 3. ### Ánh xạ tag tới kênh của mô hình Liệt kê các tag bạn muốn truyền và gán mỗi tag tới một **kênh đầu vào** được đánh số (`0`, `1`, `2`, …). Mỗi kênh đưa vào một đầu vào của mô hình. Đặt **window size** — bao nhiêu mẫu liên tiếp mô hình tiêu thụ mỗi lần dự đoán — để khớp với mô hình bạn sẽ ghép cặp. **Ánh xạ kênh phải đầy đủ** Cung cấp đúng một tag cho mỗi kênh, không để trống chỗ nào. Việc xác thực sẽ từ chối bật nếu bất kỳ kênh nào chưa được ánh xạ hoặc bị điền quá. Các tag dạng chuỗi (ví dụ trạng thái `RUN`/`STOP`) không thể dùng làm đặc trưng dạng số — hãy bỏ qua chúng khi định nghĩa kênh. 4. ### Lưu và ghép cặp một mô hình Lưu datasource. Sau đó ghép cặp nó với một mô hình bạn đã tải lên dưới **Models**. Nền tảng chạy một kiểm tra tương thích — `window size × feature count` phải khớp ở cả hai phía — và từ chối ghép cặp nếu chúng khác nhau. 5. ### Bật, rồi bắt đầu Bật **Enable** trên hàng. Việc này xác thực cấu hình, nạp mô hình đã ghép cặp, và kết nối adapter. Cái bắt tay kết nối (OPC-UA / MQTT / Modbus) xảy ra ở đây, nên một sự cố mạng hoặc thông tin xác thực sẽ lộ ra ngay và quay hàng về lại **Disabled** kèm một thông báo lỗi. Bật **không** tự khởi động truyền — bấm **Start** để bắt đầu suy luận. ### Kiểm tra kết nối trước Trước khi bật, dùng **Test Connection** trên nguồn. Nó xác minh các giá trị biểu mẫu trực tiếp chạm tới được endpoint, để bạn phát hiện sai host hay thông tin xác thực trước khi đấu nối tag. ### Giới hạn tốc độ và đệm Mỗi datasource có giới hạn tốc độ độc lập và một bộ đệm có giới hạn. Khi một nguồn sản sinh nhanh hơn mức runtime tiêu thụ, backpressure được báo cáo lên bảng điều khiển để bạn phát hiện tình trạng quá tải. ### Nếu có gì đó sai | Triệu chứng | Nguyên nhân khả dĩ | |---------|--------------| | Bật thất bại với `model_not_paired` | Hãy ghép cặp một mô hình với datasource trước. | | Bật bị quay lại khi kết nối | Endpoint không truy cập được, sai thông tin xác thực, hoặc tường lửa — xác minh bằng **Test Connection**. | | Hàng báo Enabled nhưng không có dự đoán | Theo thiết kế — bấm **Start** để bắt đầu truyền. | | Ghép cặp bị từ chối | `window size × feature count` không khớp giữa mô hình và datasource. | Xem runbook [Khắc phục sự cố](/vi/troubleshooting/) để biết thêm. ### Bước tiếp theo - [Gửi kết quả ra ngoài](/vi/configure/output-datasources/) — Ghi dự đoán ngược về một PLC, broker hoặc tệp. - [Triển khai một mô hình](/configure/models/) — Tải lên, ghép cặp và kích hoạt mô hình. --- ## Datasource đầu ra > Ghi dự đoán và điểm đặt (setpoint) ngược về các hệ thống bên ngoài — cấu hình một đầu ra OPC-UA, MQTT hoặc Modbus và xác minh bằng một lần ghi thử. Một **datasource đầu ra** ghi dữ liệu ra một hệ thống bên ngoài — một PLC, broker, hoặc ứng dụng điều khiển. Khác với datasource đầu vào, đầu ra không có mô hình hay ánh xạ tag: chúng nhận một payload JSON và chuyển nó tới đích. **Ghi thử ở thời điểm hiện tại** Datasource đầu ra hiện hỗ trợ **ghi thử theo yêu cầu** — mỗi lần ghi được gửi riêng lẻ để bạn có thể xác minh kết nối và địa chỉ. Các đường ghi sản xuất theo lịch, theo lô là một cải tiến trong tương lai. ### Các đầu ra được hỗ trợ | Giao thức | Khả năng | |----------|------------| | OPC-UA | Ghi vào một node (đồng bộ) | | MQTT | Publish tới một topic (QoS / retain có thể cấu hình) | | Modbus TCP | Ghi vào holding register hoặc coil | ### Cấu hình một đầu ra 1. ### Tạo đầu ra Vào **Datasources → Output**, bấm **+ Create**, và chọn giao thức. 2. ### Điền cấu hình kết nối Mỗi giao thức có các trường riêng. Các trường bí mật bị che thành `***` sau khi lưu. **OPC-UA** ```json { "endpoint": "opc.tcp://your-plc-host:4840", "securityPolicy": "None", "authentication": "Anonymous" } ``` **MQTT** ```json { "brokerUrl": "mqtt://your-broker-host:1883", "topic": "devices/plc/setpoint", "qos": 1, "retain": false, "username": "your-username", "password": "your-password" } ``` **Modbus TCP** ```json { "host": "your-plc-host", "port": 502, "slaveId": 1, "defaultCoilAddress": 1000, "defaultRegisterAddress": 40001 } ``` Địa chỉ theo quy ước Modicon (coil từ `1`, holding register từ `40001`). 3. ### Lưu và bật Lưu đầu ra, rồi bật nó. Một đầu ra phải được **bật** trước khi nó chấp nhận một lần ghi thử. ### Gửi một lần ghi thử Mở chi tiết của đầu ra, tìm hành động **Test Write**, nhập một payload JSON, và gửi đi. Kết quả hiển thị thành công hoặc lỗi giao thức mà đích trả về. **OPC-UA** Ghi một node duy nhất: ```json { "nodeId": "ns=2;s=Temperature", "value": 42.5 } ``` **MQTT** Publish một payload: ```json { "setpoint": 65.0, "mode": "heating" } ``` **Modbus** Ghi một hoặc nhiều register: ```json { "addresses": [ { "address": 1000, "value": 100 }, { "address": 1002, "value": 250 } ] } ``` Một lần ghi thành công trả về kết quả thành công; một lỗi giao thức trả về một thông báo như `OPC UA: node not found` hoặc `Modbus: address out of range`. ### Nếu có gì đó sai | Triệu chứng | Nguyên nhân khả dĩ | |---------|--------------| | `Connection timeout` | Đích không truy cập được — kiểm tra đường mạng, host và cổng (MQTT `1883`, Modbus `502`). | | Lỗi datasource bị tắt | Bật đầu ra trước khi gửi một lần ghi thử. | | `Node not found` (OPC-UA) | Kiểm tra định dạng NodeId và rằng node tồn tại trên máy chủ. | | Địa chỉ ngoài phạm vi (Modbus) | Ở trong dải Modicon (coil `1+`, holding register `40001+`). | | `Admin only` (403) | Lệnh ghi thử cần một tài khoản admin. | Xem runbook [Khắc phục sự cố](/vi/troubleshooting/) để biết thêm. ### Bước tiếp theo - [Kết nối một đầu vào](/vi/configure/input-datasources/) — Truyền dữ liệu cảm biến vào để dẫn động suy luận. - [Giám sát runtime](/operate/monitoring/) — Độ trễ, thông lượng và các KPI. --- ## Khắc phục sự cố > Runbook ưu tiên triệu chứng để chẩn đoán và sửa các sự cố thường gặp của Xisom Edge AI Box. Tìm triệu chứng của bạn trong bảng, nhảy tới bản sửa. Mọi trang runbook đều theo cùng một dạng: **Triệu chứng → Xác nhận → Sửa → Phòng ngừa**. ### Tìm triệu chứng của bạn | Nếu bạn thấy… | Đi tới | |---|---| | GPU đã cài nhưng suy luận chạy trên CPU; log hiện `CUDA failure 500: named symbol not found` | [Không dùng GPU — CUDA error 500](/vi/troubleshooting/gpu-cuda-error-500/) | | Container suy luận thoát/khởi động lại khi GPU bị ép buộc và GPU host hỏng | [Không dùng GPU — CUDA error 500](/vi/troubleshooting/gpu-cuda-error-500/) | | GPU host hoạt động, nhưng provider hiển thị một cấp thấp hơn kỳ vọng (ví dụ CUDA thay vì TensorRT, hoặc CPU) | [Chạy trên CPU khi kỳ vọng GPU](/vi/troubleshooting/execution-provider-fallback/) | | Dòng log `Failed to load library libonnxruntime_providers_tensorrt.so` | [Chạy trên CPU khi kỳ vọng GPU](/vi/troubleshooting/execution-provider-fallback/) | | Bật một datasource bị bật ngược về Disabled với `model_not_paired` hoặc `adapter_connect_failed` | [Datasource sập hoặc lỗi](/vi/troubleshooting/datasource-down-or-faulted/) | | Một nguồn OPC-UA / MQTT / CSV đang truyền bị dừng; hàng hiện chỉ báo lỗi / banner đỏ | [Datasource sập hoặc lỗi](/vi/troubleshooting/datasource-down-or-faulted/) | | Datasource ở trạng thái Enabled nhưng không có dự đoán nào xuất hiện | [Datasource sập hoặc lỗi](/vi/troubleshooting/datasource-down-or-faulted/) | | **Settings → About** tô màu hổ phách cho phiên bản frontend / backend | [Lệch phiên bản frontend / backend](/vi/troubleshooting/version-drift-fe-be/) | | Phiên bản đọc là `0.0.0-dev…` hoặc kết thúc bằng `-dirty` | [Lệch phiên bản frontend / backend](/vi/troubleshooting/version-drift-fe-be/) | | Đĩa đầy lên; tệp cơ sở dữ liệu lớn hơn nhiều so với dữ liệu nó chứa; xóa hàng không làm nó co lại | [Đĩa đầy / cơ sở dữ liệu phình không giới hạn](/vi/troubleshooting/sqlite-retention-disk/) | | Một container hiện `unhealthy` trong `docker ps` nhưng ứng dụng vẫn phục vụ tốt | [Container bị đánh dấu unhealthy nhưng dịch vụ vẫn chạy](/vi/troubleshooting/healthcheck-ipv6-false-negative/) | Stack đã triển khai dùng tệp compose phát hành. Các lệnh trong những trang này được viết cho các container đang chạy (`aiboard-inference-real`, `aiboard-backend-real`, `aiboard-frontend-real`) qua `docker compose -f docker-compose.release.yml …`. --- ## Không dùng GPU — CUDA error 500 > Container suy luận ghi log "CUDA failure 500" và tụt xuống CPU dù đã cài GPU. ### Triệu chứng Hộp có một NVIDIA GPU, nhưng suy luận chạy trên CPU. Log container suy luận hiện: ``` CUDA failure 500: named symbol not found ... resolved to CPU only ``` Trong bảng điều khiển, thẻ **Python Inference** hiển thị CPU (fallback) thay vì `TensorRT` hoặc `CUDA`. Khi bật ép buộc GPU nghiêm ngặt, container thay vào đó thoát và liên tục khởi động lại. Việc `nvidia-smi` báo cáo GPU của bạn hiện diện **không** có nghĩa là tính toán CUDA hoạt động. Lớp quản lý (`nvidia-smi`) và driver tính toán là hai thứ khác nhau — driver tính toán mới là cái đã hỏng ở đây. ### Xác nhận Phép thử quyết định là mẫu tính toán của chính NVIDIA. Chạy nó trên host: ```bash docker run --rm --gpus all nvcr.io/nvidia/k8s/cuda-sample:vectoradd-cuda12.5.0 ``` - **Host khỏe mạnh** → in `Test PASSED`. - **Host hỏng** → `Failed to allocate device vector A (error code named symbol not found)!` Nếu các GPU được liệt kê bởi `nvidia-smi -L` nhưng mẫu này thất bại, GPU không dùng được để tính toán trong container. Vấn đề nằm ở stack GPU của host, không phải image Xisom. Bạn cũng có thể xác nhận fallback trong log của container đang chạy: ```bash docker compose -f docker-compose.release.yml logs inference | grep -E "CUDA failure 500|resolved to CPU" ``` ### Sửa Đây là một sự cố tính toán GPU ở cấp host trên lớp driver nền tảng, nên bản sửa nằm trên host — không phải trong stack Xisom. 1. Cập nhật **driver NVIDIA GPU** trên host lên một bản hiện hành có hỗ trợ tính toán CUDA đầy đủ. Trên host Windows + WSL2, cũng chạy `wsl --update` rồi `wsl --shutdown` sau đó. Chỉ cập nhật Docker / nền tảng container **không** sửa được điều này. Lỗi tính toán nằm ở lớp driver GPU bên dưới container runtime. Một bản cập nhật nền tảng thậm chí có thể đặt lại thiết lập GPU passthrough và làm mọi thứ tệ hơn. 2. Đấu nối lại container runtime với driver vừa làm mới: ```bash sudo nvidia-ctk runtime configure --runtime=docker sudo systemctl restart docker ``` 3. Chạy lại mẫu tính toán cho đến khi nó in `Test PASSED`: ```bash docker run --rm --gpus all nvcr.io/nvidia/k8s/cuda-sample:vectoradd-cuda12.5.0 ``` 4. Khởi động lại container suy luận và xác nhận nó đã nhận GPU. Không cần thay đổi cấu hình — chế độ thực thi mặc định tự chọn provider tốt nhất hiện có: ```bash docker compose -f docker-compose.release.yml restart inference docker compose -f docker-compose.release.yml logs inference | grep "EP enabled" # kỳ vọng: "TensorRT EP enabled" hoặc "CUDA EP enabled" ``` #### Trong khi host vẫn còn hỏng Hãy chạy gọn gàng trên CPU thay vì vật lộn với bước dò GPU. Đặt `EXECUTION_MODE=cpu` (hoặc `FORCE_CPU=1`) trên dịch vụ suy luận và khởi động lại. Hộp tiếp tục dự đoán trên CPU cho đến khi driver được sửa. **Đừng** bật ép buộc GPU nghiêm ngặt (`STRICT_EP=1`) với một chế độ GPU trên một host hỏng — nó sẽ đúng đắn từ chối khởi động thay vì âm thầm chạy trên CPU, điều ngược lại với mong muốn của bạn trong lúc xử lý tạm. ### Phòng ngừa - **Làm cho việc âm thầm tụt xuống CPU trở nên ồn ào ở nơi GPU là bắt buộc.** Trên các hộp *phải* chạy GPU, hãy ghim provider và bật ép buộc nghiêm ngặt (`EXECUTION_MODE=cuda` + `STRICT_EP=1`) để một thư viện GPU bị thiếu làm container thất bại lúc khởi động thay vì âm thầm tụt xuống CPU. - **Coi mẫu tính toán là cổng nghiệm thu** sau bất kỳ cập nhật driver-GPU hoặc host nào — `nvidia-smi` qua được không phải bằng chứng đủ rằng suy luận sẽ dùng GPU. - **Lần chạy đầu chậm, không phải bị kẹt.** Ở lần khởi động GPU đầu tiên engine được biên dịch và đệm (2–3 phút). Các lần khởi động lại sau đó nhanh. Đừng nhầm cửa sổ khởi động dài với lỗi ở trên. ### Liên quan - [Execution provider tụt xuống CPU](/vi/troubleshooting/execution-provider-fallback/) — khi GPU host vẫn ổn nhưng provider vẫn rớt một cấp. - [Thiết lập phần cứng](/vi/install-deploy/hardware-setup/) — các cấp GPU được hỗ trợ. - [Khả năng quan sát & Cảnh báo](/operate/monitoring/) — nơi provider đang hoạt động được hiển thị. --- ## Chạy trên CPU khi kỳ vọng GPU > Suy luận tụt xuống một execution provider thấp hơn (TensorRT → CUDA → CPU) dù GPU vẫn hoạt động. ### Triệu chứng GPU host vẫn hoạt động (mẫu tính toán CUDA qua được), nhưng suy luận chậm hơn kỳ vọng và thẻ **Python Inference** hiển thị một cấp thấp hơn so với cấu hình bạn đã chuẩn bị: - Bạn kỳ vọng TensorRT nhưng thấy CUDA, hoặc - Bạn kỳ vọng một provider GPU nhưng thấy CPU (fallback) hoặc CPU. Log container suy luận thường chứa một dòng trông có vẻ vô hại như: ``` Failed to load library libonnxruntime_providers_tensorrt.so ``` Đây là chuỗi provider tụt từng cấp một: **TensorRT → CUDA → CPU**. Trang này dành cho khi GPU host khỏe mạnh nhưng provider vẫn rớt một cấp. Nếu container ghi log `CUDA failure 500`, bản thân GPU đã hỏng — hãy xem [Không dùng GPU — CUDA error 500](/vi/troubleshooting/gpu-cuda-error-500/) trước. ### Xác nhận Kiểm tra provider nào dịch vụ đang chạy thực sự đã khởi tạo: ```bash docker compose -f docker-compose.release.yml logs inference | grep -E "Active EP|EP enabled|resolved to" ``` - `TensorRT EP enabled` → cấp cao nhất, không cần làm gì. - `CUDA EP enabled` trong khi bạn kỳ vọng TensorRT → provider TensorRT đã bị bỏ (thiếu thư viện parser native). - `resolved to CPU only` trong khi GPU vẫn hoạt động → cả hai provider GPU đã bị bỏ. Chế độ thực thi mặc định là `auto`, vốn được *thiết kế* để suy giảm một cách nhẹ nhàng thay vì thất bại. Cái lưới an toàn đó cũng chính là cái che giấu một thư viện GPU bị thiếu — một hộp đã suy giảm vẫn chạy tiếp, chỉ là chậm hơn. ### Sửa 1. Quyết định xem hộp có **phải** chạy GPU hay không. Nếu GPU là bắt buộc, hãy làm cho việc fallback trở nên ồn ào để khoảng cách hiện rõ thay vì âm thầm — ghim provider và bật ép buộc nghiêm ngặt trên dịch vụ suy luận: ``` EXECUTION_MODE=tensorrt # hoặc: cuda STRICT_EP=1 ``` Khởi động lại inference. Container giờ sẽ từ chối khởi động (thay vì suy giảm) nếu provider được yêu cầu không có sẵn — biến một sự chậm lại âm thầm thành một lỗi khởi động rõ ràng để bạn có thể xử lý. 2. Nếu cấp được yêu cầu là **TensorRT** và nó bị bỏ, thư viện parser native của provider TensorRT bị thiếu khỏi image. Hãy dùng một profile image suy luận có hỗ trợ GPU (TensorRT) cho hộp này thay vì profile CPU. Xác nhận cấp image khớp với cấp phần cứng của bạn trước khi triển khai lại. 3. Khởi động lại và xác nhận lại provider đang hoạt động: ```bash docker compose -f docker-compose.release.yml restart inference docker compose -f docker-compose.release.yml logs inference | grep "EP enabled" ``` ### Phòng ngừa - **Khớp profile image với phần cứng.** Image suy luận có các profile CPU, TensorRT và Jetson. Triển khai profile CPU trên một hộp GPU sẽ giới hạn bạn ở CPU theo cấu trúc — không có provider GPU nào trong image đó để tụt *từ* đó. - **Ghim + nghiêm ngặt trên các hộp bắt buộc GPU.** `EXECUTION_MODE=auto` là mặc định đúng cho các đội máy hỗn hợp, nhưng trên một hộp phải dùng GPU, `EXECUTION_MODE=` + `STRICT_EP=1` biến một sự suy giảm vô hình thành một lỗi khởi động fail-fast. - **Theo dõi chip provider sau mỗi lần triển khai.** Thẻ Python Inference của bảng điều khiển phản ánh provider trực tiếp; hãy coi một sự tụt cấp ở đó là một lỗi triển khai, không phải biến động bình thường. ### Liên quan - [Không dùng GPU — CUDA error 500](/vi/troubleshooting/gpu-cuda-error-500/) — khi lớp tính toán GPU host thực sự hỏng. - [Thiết lập phần cứng](/vi/install-deploy/hardware-setup/) — cấp GPU nào ánh xạ tới profile image nào. - [Khả năng quan sát & Cảnh báo](/operate/monitoring/) — đọc provider đang hoạt động và độ trễ. --- ## Datasource sập hoặc lỗi > Một datasource OPC-UA / MQTT / CSV ngừng truyền, hoặc một hàng hiện chỉ báo lỗi. ### Triệu chứng Một trong hai tình huống: - **Bật thất bại.** Bật **Enable** trên một hàng datasource đầu vào bị bật ngược về **Disabled** và hiện một mã lỗi như `model_not_paired` hoặc `adapter_connect_failed`. - **Một nguồn đang chạy bị lỗi giữa chừng.** Một datasource trước đó đang truyền ngừng sản sinh dự đoán; hàng hiện chỉ báo lỗi và một banner đỏ xuất hiện. Bên dưới, runtime đã rớt về trạng thái lỗi rồi nhàn rỗi (idle). Bật một datasource **không** bắt đầu truyền. Nó chuẩn bị runtime (nạp mô hình, kết nối adapter). Bạn bấm **Start** để bắt đầu suy luận. Một hàng đang Enabled nhưng không dự đoán thường chỉ đang chờ Start — đó là theo thiết kế. ### Xác nhận Xác định giai đoạn nào đã thất bại. - **Đọc mã lỗi trên hàng.** Mã đặt tên trực tiếp cho bước đã thất bại: - `model_not_paired` → datasource chưa được gán mô hình. - `adapter_connect_failed` → kết nối giao thức (bắt tay OPC-UA / kết nối broker MQTT / dò Modbus) thất bại — hầu như luôn là vấn đề mạng hoặc endpoint. - **Kiểm tra log backend** để xem lần thử kết nối và lý do lỗi: ```bash docker compose -f docker-compose.release.yml logs backend | grep -iE "datasource|adapter|fault|enable" ``` - **Một lỗi giữa chừng** đến từ một lỗi đọc trên nguồn trực tiếp (một tag ngừng phản hồi). Khi điều đó xảy ra runtime tháo dỡ về một trạng thái idle sạch: mô hình được gỡ nạp và adapter được tháo gắn. **Phục hồi không tự động** — nguồn phải được bật lại từ đầu. ### Sửa 1. **`model_not_paired`** — gán một mô hình cho datasource trước, rồi Enable lại. Một datasource phải được ghép cặp với một mô hình trước khi nó có thể chạy. 2. **`adapter_connect_failed`** — runtime không thể tới được nguồn. Việc Enable đã quay hàng về Disabled một cách gọn gàng, nên hãy sửa kết nối và thử lại: - Xác minh địa chỉ endpoint, cổng, và thông tin xác thực trong cấu hình datasource. - Xác nhận hộp có khả năng tới được mạng tới máy chủ OPC-UA / broker MQTT / thiết bị. - Với một nguồn CSV, xác nhận đường dẫn tệp và rằng tệp tồn tại và đọc được. - Dùng **Test Connection** của biểu mẫu với các giá trị *hiện tại*, rồi Enable lại. 3. **Một nguồn đã lỗi giữa chừng** đã được tháo dỡ về idle — mô hình đã được gỡ nạp và adapter tháo gắn. Hãy thiết lập lại nó đầy đủ: - Sửa vấn đề nguồn nền (kết nối lại cảm biến / khôi phục tag / sửa mạng). - **Enable** lại datasource (việc này nạp lại mô hình và kết nối lại adapter). - Bấm **Start** để tiếp tục truyền. Chỉ một datasource đầu vào được Enabled tại một thời điểm. Bật nguồn B sẽ tự động tắt nguồn A. Nếu một nguồn bạn kỳ vọng đang chạy lại hiện Disabled, hãy kiểm tra xem việc bật một nguồn khác có tắt nó đi không. ### Phòng ngừa - **Ghép cặp mô hình và ánh xạ tất cả kênh trước khi đưa vào hoạt động.** Hầu hết các lỗi Enable là xác thực tiền-khởi-động: thiếu ghép cặp mô hình hoặc ánh xạ tag-tới-kênh chưa hoàn chỉnh (chỗ trống hoặc điền quá). Hoàn thành những việc này một lần và Enable thành công ngay lần đầu. - **Ổn định nguồn trước Start.** Một endpoint OPC-UA chập chờn hoặc broker gián đoạn sẽ làm lỗi luồng và buộc phải re-enable đầy đủ. Xác nhận một kết nối ổn định bằng Test Connection trước khi bấm Start. - **Kỳ vọng luồng hai bước.** Enable chuẩn bị; Start truyền. Đưa điều này vào quy trình vận hành tránh các phiếu "nó đã enabled nhưng không có gì xảy ra". ### Liên quan - [Kết nối Datasource](/vi/configure/input-datasources/) — loại adapter, cấu hình kết nối, ánh xạ tag. - [Suy luận đầu tiên của bạn](/vi/install-deploy/first-inference/) — luồng nạp và chạy mô hình. --- ## Lệch phiên bản frontend / backend > Bảng About tô màu hổ phách cho sự lệch phiên bản giữa frontend và backend. ### Triệu chứng Trong **Settings → About**, phiên bản frontend và phiên bản backend được hiển thị cạnh nhau và hàng được tô màu **hổ phách** vì chúng khác nhau, ví dụ: - Frontend `v1.5.0` so với backend `v1.5.0-1-gabc1234`, hoặc - Frontend `v1.5.0` so với backend `v1.4.0`. Bảng tô sáng sự lệch một cách có chủ ý — đó là bộ phát hiện trôi (drift) tích hợp. Hai phiên bản được kỳ vọng khớp nhau trên một hộp được triển khai đúng. ### Xác nhận Đọc trực tiếp phiên bản mà backend báo cáo và so với những gì bảng About hiển thị cho frontend: ```bash curl -s http://localhost:5000/api/system/health | jq '{version, commit, buildTime}' ``` Có hai nguyên nhân thường gặp: 1. **Một tab trình duyệt cũ.** Bundle frontend được nướng vào lúc build, nên một tab cũ vẫn hiển thị phiên bản nó được nạp với, ngay cả sau khi triển khai lại. 2. **Một container được triển khai lại mà không có cái kia.** Một image backend mới được triển khai nhưng image frontend (hoặc ngược lại) không được build lại — nên chúng thực sự chạy các phiên bản khác nhau. Một chuỗi phiên bản chứa các commit thêm sau tag (`...-1-gabc1234`) nghĩa là container đó được build từ một commit *sau* tag phát hành — nó đi trước bản build có tag sạch. ### Sửa 1. **Trước tiên, loại trừ một tab cũ** — đó là nguyên nhân rẻ nhất. Hard-refresh trình duyệt (tải lại bỏ qua cache). Nếu frontend và backend giờ khớp nhau, bạn đã xong; không có gì thực sự sai với việc triển khai. 2. **Nếu chúng vẫn khác, hãy triển khai lại để cả hai image cùng phiên bản.** Build lại và đưa stack lên cùng nhau để frontend và backend được build từ cùng một bản phát hành: ```bash docker compose -f docker-compose.release.yml up -d ``` 3. **Xác minh chúng khớp nhau.** Tải lại **Settings → About** — phần tô màu hổ phách sẽ biến mất. Xác nhận phiên bản backend nữa: ```bash curl -s http://localhost:5000/api/system/health | jq .version ``` Đừng ship một bản build mà phiên bản đọc là `0.0.0-dev...` hoặc kết thúc bằng `-dirty`. Cái đầu nghĩa là không có bản phát hành nào được gắn tag cho build đó; cái thứ hai nghĩa là nó mang các chỉnh sửa cục bộ chưa commit. Cả hai đều không tái lập được — hãy triển khai một bản phát hành được đánh phiên bản đúng cách. ### Phòng ngừa - **Triển khai frontend và backend cùng nhau.** Cả hai image mang một phiên bản được nướng vào lúc build; triển khai chúng như một bộ khớp từ một bản phát hành giữ cho bảng About màu xanh. - **Hard-refresh sau mỗi lần triển khai.** Các tab trình duyệt giữ bundle cũ cho đến khi tải lại. Một lần hard refresh nhanh sau mỗi lần triển khai tránh các báo cáo trôi sai. - **Dùng bảng About làm kiểm tra sau-triển-khai.** Coi nó là bước nghiệm thu cuối cùng — nếu nó màu hổ phách, việc triển khai chưa hoàn tất. ### Liên quan - [Release Notes](/release-notes/) — những gì đã ship trong mỗi phiên bản. - [Khả năng quan sát & Cảnh báo](/operate/monitoring/) — tình trạng runtime cùng với phiên bản. --- ## Đĩa đầy / cơ sở dữ liệu phình không giới hạn > Cơ sở dữ liệu quan sát phình lớn vượt xa dữ liệu thực và làm đầy đĩa. ### Triệu chứng Hộp cạn đĩa, và tệp cơ sở dữ liệu quan sát lớn khổng lồ so với lượng dữ liệu nó đáng ra phải chứa — ví dụ hàng chục GB trên đĩa trong khi chỉ ~1 GB dự đoán thực sự được giữ lại. Xóa hàng cũ (hoặc rút ngắn thời gian giữ) **không** làm tệp co lại. Nguyên nhân: các hàng cũ được xóa theo lịch, nhưng trên một cơ sở dữ liệu được tạo không có auto-vacuum gia tăng, các trang đã giải phóng được giữ trong một free-list nội bộ và không bao giờ được trả lại cho hệ điều hành. Tệp duy trì ở mức đỉnh-cao-nước mãi mãi. ### Xác nhận Kiểm tra kích thước tệp cơ sở dữ liệu bên trong container backend so với kích thước trực tiếp kỳ vọng: ```bash docker compose -f docker-compose.release.yml exec backend \ sh -c 'ls -lh /data/aiboard.db' ``` Nếu tệp lớn gấp nhiều lần khối lượng dữ liệu mà cửa sổ giữ lại của bạn đáng ra phải chứa (một tệp nhiều GB cho vài ngày dự đoán), bạn bị phình free-list. Một đợt ghi tốc độ cao duy nhất có thể làm tệp phình vượt xa kích thước trạng thái-ổn-định. ### Sửa Các bản phát hành hiện tại tự thu hồi không gian sau mỗi đợt quét giữ lại, nên một hộp khỏe mạnh tự sửa. Một cơ sở dữ liệu đã phình **trước khi** hành vi đó có mặt cần một lần thu hồi một-lần. 1. **Dừng backend** để cơ sở dữ liệu không bị ghi trong lúc thu hồi: ```bash docker compose -f docker-compose.release.yml stop backend ``` 2. **Chạy lần thu hồi một-lần** trên tệp cơ sở dữ liệu. Việc này chuyển tệp sang auto-vacuum gia tăng và nén nó lại, trả các trang free-list về OS: ```bash docker compose -f docker-compose.release.yml run --rm --entrypoint sh backend -c \ 'sqlite3 /data/aiboard.db "PRAGMA auto_vacuum=INCREMENTAL; VACUUM;"' ``` 3. **Xác minh** tệp đã co lại và dữ liệu nguyên vẹn: ```bash docker compose -f docker-compose.release.yml run --rm --entrypoint sh backend -c \ 'ls -lh /data/aiboard.db; sqlite3 /data/aiboard.db "PRAGMA integrity_check;"' # kỳ vọng một tệp nhỏ hơn nhiều và: ok ``` 4. **Khởi động backend** lại: ```bash docker compose -f docker-compose.release.yml start backend ``` Lần thu hồi một-lần chỉ cần cho một cơ sở dữ liệu đã phình trước khi việc thu hồi tự động có mặt. Các bản triển khai mới được tạo có khả năng co lại và tự giữ mình gọn gàng sau mỗi đợt quét giữ lại. ### Phòng ngừa - **Giữ thời gian lưu có giới hạn.** Cửa sổ giữ lại (`InferenceObservability:RetentionDays`, mặc định 3 ngày) xóa các hàng dự đoán cũ theo lịch; việc thu hồi sau-xóa trả các trang đã giải phóng về đĩa để tệp giữ gọn nhẹ. - **Giới hạn số hàng làm chốt chặn đợt bùng phát.** `InferenceObservability:MaxRows` (mặc định 5.000.000) cắt về N hàng mới nhất ngay cả trong cửa sổ thời gian, nên một đột biến tốc độ cao bất ngờ không thể làm đầy đĩa trước khi đợt quét theo thời gian chạy. Hạ nó xuống nếu hộp của bạn có đĩa hạn chế. - **Cẩn thận với thử nghiệm thông lượng/stub.** Các đợt ghi tốc độ cao (ví dụ kiểm tra thông lượng đường ống cảm biến) là cái làm phình tệp ngay từ đầu. Tránh để một thử nghiệm tốc độ cao chạy đối với lưu trữ bền vững trên một hộp sản xuất. ### Liên quan - [Khả năng quan sát & Cảnh báo](/operate/monitoring/) — cơ sở dữ liệu quan sát lưu trữ những gì. --- ## Container bị đánh dấu unhealthy nhưng dịch vụ vẫn chạy > Một container báo cáo unhealthy trong khi nó phục vụ lưu lượng vẫn tốt — một âm tính giả của health-probe. ### Triệu chứng Một container — thường là frontend — hiện unhealthy trong `docker ps`, nhưng ứng dụng vẫn tới được và phục vụ bình thường trong trình duyệt. Probe tình trạng ghi log "connection refused" dù dịch vụ vẫn lên. Nguyên nhân: probe nhắm tới `localhost`, vốn phân giải thành **cả** IPv6 (`::1`) và IPv4 (`127.0.0.1`). Công cụ probe thử IPv6 trước, nhưng máy chủ bên trong container chỉ lắng nghe trên IPv4 — nên lần thử IPv6 bị từ chối và probe báo cáo sai rằng container đã sập. ### Xác nhận Kiểm tra tình trạng được báo cáo của container so với khả năng tới được thực tế của nó: ```bash docker ps --format '{{.Names}}\t{{.Status}}' | grep aiboard ``` Nếu một container đọc là `(unhealthy)` nhưng ứng dụng phản hồi khi bạn truy cập trực tiếp trên IPv4, đó là âm tính giả này: ```bash # từ bên trong container — IPv4 một cách tường minh docker compose -f docker-compose.release.yml exec frontend \ sh -c 'wget -qO- http://127.0.0.1:8080/ >/dev/null && echo "IPv4 OK"' ``` Nếu `IPv4 OK` in ra, dịch vụ khỏe mạnh và chỉ có probe là sai. ### Sửa Các image hiện tại đã probe IPv4 một cách tường minh, nên một hộp khỏe mạnh sẽ không gặp điều này. Nếu bạn vẫn thấy nó trên một image cũ: 1. **Xác nhận dịch vụ thực sự đang phục vụ** (kiểm tra IPv4 ở trên in `IPv4 OK`). Nếu có, không cần hành động ứng dụng nào — container vẫn khỏe mạnh. 2. **Cập nhật lên một image phát hành hiện tại**, nơi health probe nhắm tới `127.0.0.1` trực tiếp và âm tính giả biến mất: ```bash docker compose -f docker-compose.release.yml up -d ``` 3. **Kiểm tra lại** trạng thái được xóa: ```bash docker ps --format '{{.Names}}\t{{.Status}}' | grep aiboard ``` Vì probe mới là cái đã sai (không phải dịch vụ), một container phụ thuộc đang chờ tình trạng của container này có thể bị giữ lại dù mọi thứ thực sự đang phục vụ. Hãy sửa probe thay vì tắt healthcheck. ### Phòng ngừa - **Probe đúng địa chỉ mà máy chủ thực sự bind.** Health probe nên nhắm tới `127.0.0.1` một cách tường minh khi máy chủ chỉ lắng nghe trên IPv4, để việc phân giải tên không thể gửi probe tới một địa chỉ IPv6 chưa được bind. - **Phân biệt lỗi probe với lỗi dịch vụ.** Trước khi phản ứng với một trạng thái `unhealthy`, hãy xác nhận bằng một yêu cầu IPv4 trực tiếp. Một ứng dụng xanh sau một probe đỏ là một lỗi probe, không phải một sự cố ngừng hoạt động. ### Liên quan - [Khả năng quan sát & Cảnh báo](/operate/monitoring/) — diễn giải các tín hiệu tình trạng và trạng thái. --- ## Tham chiếu API > API REST và gRPC do Xisom runtime cung cấp. Tất cả endpoint HTTP được version dưới `/api/v1/` và yêu cầu bearer token. Dịch vụ gRPC chạy trên cổng `50051`. ### Xác thực ```http Authorization: Bearer ``` Lấy token tại trang **Admin → API Keys** hoặc qua `/api/v1/auth/token`. ### Suy luận **POST** `/api/v1/inference` **GET** `/api/v1/inference/{id}` ### Models **GET** `/api/v1/models` **POST** `/api/v1/models` **POST** `/api/v1/models/{name}/promote` ### OpenAPI Spec OpenAPI đầy đủ được công bố tại `/api/v1/openapi.json` trên mỗi thiết bị đang chạy.