Kiến trúc Module, REST API & Hướng dẫn Mở rộng

Cấu trúc tầng dịch vụ FastAPI, cơ chế quản lý trạng thái lượt chạy đa người dùng và hướng dẫn mở rộng thêm mô hình hoặc cấu trúc Parquet mới.

1.0 (Draft) ✓ Đã chốt giải pháp & mô hình dự báo

Kiến trúc Module Dịch vụ (forecast_demo / Core Service Layer)

Để phục vụ nhiều người dùng truy cập đồng thời mà không phải tính toán lại mô hình trên từng request, tầng dịch vụ (forecast_demo/src/forecast_demo/) được tổ chức thành 6 phân hệ:

Phân hệ (package)Đường dẫnChức năng chính
coresrc/forecast_demo/core/Định nghĩa đường dẫn dữ liệu (paths.py), cấu hình tham số hệ thống, độ nhạy khuyến mãi và các quy tắc dựng khung dòng tương lai (settings.py).
storesrc/forecast_demo/store/Tầng lưu trữ trạng thái bằng SQLite: quản lý danh mục CTKM đã nạp, lịch sử lượt chạy, các hệ số $K$ người dùng đã chỉnh sửa kèm lý do, và trạng thái khóa sổ (DRAFT vs LOCKED).
ingestsrc/forecast_demo/ingest/Đọc tệp Excel CTKM của Trade, kiểm tra hợp lệ từng dòng theo danh mục đóng (mã SKU, tên chuỗi, cơ chế KM, cửa sổ thời gian NTD) và ghi vào kho.
enginesrc/forecast_demo/engine/Chứa skeleton.py (dựng khung dòng cho tháng tương lai $M+1..M+3$), catalog.py (định tuyến mô hình theo cấp gộp model_for_grain), grain.py (gộp nhanh 16 cấp hạt từ Parquet cache) và forecast.py (hợp nhất $\text{Base} \times (1 + \sum K)$).
apisrc/forecast_demo/api/Cung cấp các REST API endpoints qua FastAPI cho giao diện web hoặc hệ thống bên ngoài tích hợp.
clisrc/forecast_demo/cli/Cung cấp công cụ dòng lệnh forecast-demo để vận hành tự động qua cronjob/pipeline.

Cơ chế Bộ nhớ đệm Parquet (Decomposed Parquet Cache) Cho Đa Người Dùng

Một thách thức lớn của hệ thống dự báo đa người dùng là phép phân rã Shapley và suy luận Foundation Model tốn nhiều thời gian tính toán nếu chạy trực tiếp trên mỗi thao tác lọc của người dùng. Module giải quyết triệt để bằng Bộ nhớ đệm Hạt Dòng Đã Phân Rã:

  1. Ở bước warm / train, hệ thống tính sẵn dự báo và đóng góp của từng khe hệ số cho mọi mô hình và lưu xuống:
    data/cache/h{horizon}/decomposed_{model_slug}.parquet
  2. Mỗi dòng trong tệp Parquet này mang đầy đủ các khóa định danh chưa mã hóa (store_code, product_code, warehouse_key, subinv_key, chain_v1, brand_name, supplier_name, area2, area3, channel_l1, channel_l2) cùng giá trị dự báo và 6 thành phần phân rã.
  3. Khi nhiều người dùng cùng lúc chuyển đổi qua lại giữa 16 cấp gộp hoặc 8 mô hình, hoặc sửa một hệ số $K$ trên màn hình, tầng engine/grain.py chỉ thực hiện một phép group_by().agg(pl.sum()) của Polars trên tệp Parquet trong bộ nhớ — thời gian phản hồi chỉ mất vài chục mili-giây.

Đặc tả REST API Endpoints (FastAPI) & Giao diện Dòng lệnh (CLI)

Danh mục REST API Endpoints (forecast_demo/src/forecast_demo/api/app.py)

Máy chủ dịch vụ khởi chạy mặc định tại http://127.0.0.1:8000 (qua lệnh make serve hoặc uv run forecast-demo serve). Toàn bộ tính toán suy luận nặng đã được chuẩn bị sẵn trong Parquet cache (make warm), do đó các API đều phản hồi đồng bộ với độ trễ thấp:

Phương thức & Đường dẫnTham số (Query / Body)Chức năng & Cấu trúc Phản hồi
GET /api/meta(Không)Trả về cấu hình khởi tạo giao diện: version, kỳ gốc origin_ym, danh sách tầm dự báo horizons (M+1..M+3), mô hình mặc định model_default, độ nhạy khuyến mãi sensitivity, danh sách cơ chế KM mechanics và bộ quy tắc vận hành rules.
GET /api/forecasthorizon: int = 1
sensitivity: float | null
model: str | null
Trả về kết quả dự báo tổng hợp tại tầm horizon: mức nền base_carton (base_source), dự báo mô hình raw_carton, dự báo chốt final_carton, thực tế actual_carton (nếu có), mảng 6 hệ số coefficients, cờ kiểm chứng cộng tính contract_ok (residual_pct) và hiệu ứng khuyến mãi promo.
GET /api/grainshorizon: int = 1
model: str | null
Liệt kê danh sách 16 cấp gộp khả dụng từ mịn tới thô kèm số nhóm thực tế (so_nhom) và mô hình định tuyến tối ưu mặc định (model_for_grain) cho từng cấp gộp.
GET /api/breakdownhorizon: int = 1
grain: str = "sku"
limit: int = 200
model: str | null
Chẻ nhỏ số dự báo theo cấp gộp grain (pair, store, sku_subinv, sku_warehouse, sku_chain, sku, brand, subinv, chain, supplier, warehouse, channel_l2, area3, area2, channel_l1, channel), kèm phép kiểm bảo toàn tổng kiem_qd08_thung.
GET /api/model-reporthorizon: int = 1
grain: str = "sku"
group: str | null
model: str | null
Trả về báo cáo giải thích mô hình chuyên sâu: độ quan trọng đặc trưng (Feature Importance theo Gain), phân nhóm nhân tố và chiều tác động cụ thể lên nhóm group đang chọn.
GET /api/catalog(Không)Trả về danh mục các mô hình đang được phục vụ (slug, label, note, cờ mac_dinh).
POST /api/runsBody RunIn: {horizon, coefficients[], note}Lưu một kịch bản điều chỉnh hệ số $K$ của người dùng vào SQLite ở trạng thái bản nháp (DRAFT), trả về {run_id, trang_thai}.
POST /api/runs/{run_id}/lockBody LockIn: {who: str}Khóa sổ bản dự báo (LOCKED) cho kỳ S&OP kèm tên người phê duyệt; trả mã lỗi 409 nếu kỳ dự báo đã có bản khóa trước đó.
GET /api/runs(Không)Liệt kê lịch sử các lượt lưu và khóa sổ dự báo của các người dùng.
POST /api/importsMultipart file: UploadFileTải tệp Excel CTKM lên bàn chờ (staging), kiểm tra hợp lệ từng dòng và trả về danh sách lỗi xem trước mà chưa ghi đè vào kho chính.
POST /api/imports/{batch_id}/commitPath batch_id: intXác nhận ghi lô CTKM hợp lệ từ bàn chờ vào bảng promo_line chính thức.
POST /api/imports/{batch_id}/cancelPath batch_id: intHủy bỏ lô CTKM đang ở bàn chờ.
GET /api/imports & GET /api/promolimit: int = 200Tra cứu lịch sử các lô nạp CTKM và danh sách các dòng khuyến mãi đang có hiệu lực (is_active = 1).
GET /api/models & POST /api/models/backup(Không)Đối chiếu mã băm SHA-256 của các tệp .joblib trên đĩa với bản lưu trong SQLite và sao lưu mô hình.

Giao diện Dòng lệnh (forecast-demo CLI)

Mọi chức năng của tầng dịch vụ đều có thể gọi trực tiếp qua CLI (forecast_demo/src/forecast_demo/cli/__init__.py) để tích hợp vào pipeline tự động mà không cần mở trình duyệt:

Lệnh CLIÝ nghĩa thực thi
uv run forecast-demo train-models [--rebuild]Đọc tệp Parquet trong data/panel/ và huấn luyện lại các tệp mô hình .joblib cho đủ 3 tầm M+1..M+3 thẳng vào data/models/.
uv run forecast-demo warm [--rebuild]Dựng sẵn khung đặc trưng tương lai và tính trước bộ nhớ đệm phân rã 6 khe (data/cache/h*/decomposed_{model}.parquet) cho mọi mô hình.
uv run forecast-demo forecast --horizon 1 [--model <slug>]In bảng dự báo tổng hợp kèm 6 hệ số $K$ và kết quả kiểm tra cộng tính ra terminal.
uv run forecast-demo breakdown --horizon 1 --grain <slug> [--limit 15]Chẻ dự báo theo cấp gộp bất kỳ (đặt --grain '?' để in danh sách 16 cấp gộp) và kiểm tra độ lệch tổng.
uv run forecast-demo ingest <path.xlsx> [--write]Kiểm tra hợp lệ tệp Excel CTKM (thêm --write để ghi thẳng vào SQLite).
uv run forecast-demo backup / uv run forecast-demo checkSao lưu tệp .joblib kèm SHA-256 vào SQLite và kiểm tra tính toàn vẹn.
uv run forecast-demo serve --host 127.0.0.1 --port 8000Khởi chạy máy chủ web FastAPI.

Hướng dẫn Mở rộng Dành cho Developers

Thêm một Mô hình Dự báo Mới vào Hệ thống

  1. Triển khai thuật toán tại model_lab:
    • Nếu là mô hình chuỗi thời gian / Empirical-Bayes cấp SKU: thêm hàm dự báo vào model_lab/src/model_lab/models/frontier.py hoặc chronos2_exp.py.
    • Đăng ký khóa định danh (slug) và tên hiển thị đầy đủ vào FULL_NAMES trong model_lab/src/model_lab/models/catalog.py.
  2. Định tuyến Cấp gộp (tùy chọn):
    • Cập nhật ánh xạ model_for_grain trong forecast_demo/src/forecast_demo/engine/catalog.py nếu mô hình mới đạt WMAPE tốt nhất ở một cấp gộp cụ thể.
  3. Kiểm định:
    • Chạy kiểm thử cuốn chiếu và holdout trong model_lab, sau đó chạy uv run pytest để đảm bảo mô hình tuân thủ hợp đồng đầu ra.

Thêm Cột Đặc trưng Mới vào Hợp đồng Parquet DWH

Khi DWH bổ sung bảng hoặc cột mới cần đưa vào tệp Parquet chuẩn:

  1. Cập nhật câu truy vấn forecast_pipeline/sql/full_dwh.sql.
  2. Khai báo tên cột, nhóm (group), cấp hạt (grain), quy tắc cộng (aggregation), kiểu dữ liệu Polars (dtype) và mô tả vào đúng vị trí tương ứng trong forecast_pipeline/src/forecast_pipeline/export/columns.py (build_full_dwh.py sẽ tự động kiểm tra đối xứng thứ tự cột và dừng ngay nếu lệch).
  3. Chạy lại make parquet-ml-full-download và make parquet-ml-processing.

Lộ trình Tách Cấu hình Schema Parquet Động (Dynamic Parquet Adapter — Phiên bản tiếp theo)

  • Ở Version 1 (hiện tại): Schema Parquet đầu vào được cố định theo DWH Đại Thuận (build_full_dwh_columns.py).
  • Ở Version 2 (lộ trình mở rộng): Tầng đọc Parquet sẽ bổ sung một tệp cấu hình ánh xạ cột (schema_mapping.yaml) cho phép gắn bất kỳ tệp Parquet của doanh nghiệp/kho dữ liệu khác vào bằng cách khai báo cột nào đóng vai trò là entity_id, item_id, date_key, target_qty, và danh sách các cột exogenous_features.