Cube hoạt động như thế nào?

    Theo dõi một câu hỏi cụ thể từ người dùng, qua LLM và Cube, xuống database và trở lại, để xác định việc mà từng thành phần đảm nhận.

    Trần Ngọc Đăng KhôiChương mở đầu15 phút đọc
    Mục lục chương
      Ý chính của chươngLLM chỉ làm hai việc: hiểu câu hỏi và diễn đạt câu trả lời. LLM không viết SQL. Toàn bộ phần ở giữa do Cube thực hiện bằng code tất định: cùng một query JSON của cùng một người hỏi luôn cho cùng một câu SQL và cùng một con số.
      00.1

      LLM tham gia ở bước nào?

      LLM đứng ở hai đầu của chuỗi xử lý. Cube và database ở giữa không dùng LLM.

      Toàn bộ chương dùng chung một ví dụ: bảng orders gồm 10 đơn hàng của hai shop A và B, ngày hiện tại là 23/10/2026, người hỏi là nhân viên shop A.

      Cube tiếp nhận một yêu cầu có dạng “cho số X, chia theo Y” dưới dạng query JSON, tự viết SQL, chạy SQL trên database rồi trả kết quả. Khi người dùng hỏi bằng tiếng Việt, cần thêm một LLM ở phía trước để chuyển câu hỏi thành query JSON đó. Mỗi trường trong query JSON là tên một member do Cube công bố, ví dụ orders.revenue.

      1. Người dùngNhập câu hỏi“Doanh thu tháng 10 ở Hà Nội?”
      2. LLMHiểu câu hỏi, chọn memberCâu tiếng Việt → Cube query JSON
      3. CubeKiểm tra, thêm quyền, viết SQLJSON → SQL, không có LLM
      4. DatabaseChạy SQLTrả về các dòng số liệu
      5. LLMViết câu trả lờiSố liệu → câu tiếng Việt (tuỳ chọn)
      Hình 1Năm bước của chuỗi xử lý, đọc từ trái sang phải. Hai điểm tô đặc là hai vị trí duy nhất có LLM.
      Điểm mấu chốtLLM chỉ làm hai việc: hiểu câu hỏi và diễn đạt câu trả lời. LLM không viết SQL mà chỉ chọn tên từ một danh sách do Cube cung cấp. Phần giữa là code chạy cố định: cùng một JSON của cùng một người hỏi luôn cho cùng một câu SQL và cùng một con số.

      Bản thân Cube (bản open source) không chứa LLM. LLM nằm trong ứng dụng hoặc agent đặt phía trước, ví dụ một chatbot dùng Claude, hoặc trong tính năng AI của Cube Cloud. Cách làm trong cả hai trường hợp giống nhau: đọc danh sách member của Cube, sau đó sinh query JSON.

      00.2

      Một câu hỏi qua bảy bước

      Từ câu hỏi tiếng Việt đến query JSON, từ query JSON đến SQL, rồi từ số liệu trở lại câu trả lời.

      Hình 2 cho phép chọn một trong ba câu hỏi và đi qua từng bước. Mỗi bước ghi rõ thành phần thực hiện, công việc, đoạn code chạy ở bước đó và output của đoạn code.

      Câu hỏi (người hỏi: nhân viên shop A, ngày 23/10/2026)
        Hình 2Bảy bước của một câu hỏi. Chọn câu hỏi phía trên, chọn bước bằng các chấm số hoặc hai nút Trước, Tiếp.

        Hai bước cần chú ý nhất là bước 3 và bước 4. Ở bước 3, đầu ra duy nhất của LLM là một query JSON. Ở bước 4, Cube xác thực token, đưa payload của token vào securityContext, sau đó hàm queryRewrite trong file cube.js thêm filter shop_id vào query. LLM không thấy điều kiện này và không thể gỡ bỏ điều kiện đó.

        Ghi nhớTừ bước 4 trở đi không còn LLM. Nếu LLM bịa ra một member không tồn tại, Cube trả lỗi thay vì âm thầm trả về số sai.
        Đọc sâuToàn bộ code server ghép lại (bước 2 → 7 trong một file)

        Đoạn code dưới đây gộp các bước 2 đến 7 vào một route /api/ask. Model và tên biến giữ nguyên như trong các bước ở Hình 2.

        
            
        00.3

        File YAML là từ điển

        File YAML nối tên dễ hiểu với cột thật trong database. Cả LLM lẫn SQL compiler của Cube đều đọc từ file này.

        File YAML (data model) do developer viết tay. File này có vai trò như một cuốn từ điển: nối tên dễ hiểu như doanh thu, thành phố với cột thật trong database. Đây là phần cốt lõi của semantic layer. Mỗi measure là một con số cần tính; mỗi dimension là một góc nhìn để chia nhóm hoặc lọc. Khối measures và dimensions trong file liệt kê đầy đủ các member mà cube cung cấp.

        Cube đọc YAML theo năm bước, khi khởi động hoặc mỗi khi file được lưu ở dev mode.

        1Tìm fileMọi file .yml trong thư mục model/
        2ParseYAML → object: danh sách cube, mỗi cube có measures, dimensions, joins
        3Thay template{CUBE} → alias của cube hiện tại; {shops} → alias của cube shops
        4Kiểm traTên trùng, sai type, join tới cube không tồn tại → báo lỗi
        5Giữ trong bộ nhớDùng cho hai việc: trả /v1/meta (LLM đọc) và viết SQL
        Hình 3Năm bước Cube đọc data model.

        Bước 5 giải thích vì sao một file phục vụ được hai đối tượng. Endpoint /v1/meta trả danh sách member kèm title và description để LLM đọc; SQL compiler dùng sql và type của cùng member đó để viết câu truy vấn. Member khai báo public: false không xuất hiện trong /v1/meta nhưng vẫn được dùng bên trong Cube, ví dụ để phân quyền.

        Hình 4File model/cubes/orders.yml. Chọn một dòng để xem ý nghĩa của dòng đó, cách Cube sử dụng và kết quả chuyển đổi tương ứng.
        Ghi nhớTitle và description không ảnh hưởng SQL, nhưng quyết định LLM chọn đúng member và điền đúng giá trị filter, ví dụ “đã huỷ” thành cancelled.
        00.4

        Thực hành: Cube xử lý một query JSON

        Khi đã có query JSON, Cube tra YAML, viết SQL, chạy database và lưu kết quả. Phần này không có LLM.

        Hình 5 bỏ qua LLM và bắt đầu từ query JSON do frontend gửi tới. Chọn các nút ở ô 1; ba ô còn lại thay đổi theo. Ô 2 tô màu những dòng YAML mà SQL compiler đang dùng. Ô 3 hiển thị bảng orders với 10 đơn của hai shop.

        1Frontend gửi query
        Chỉ số (measure)
        Chia theo (dimension)
        Người hỏi (đăng nhập)
        JSON gửi cho Cube
        
                  
        2Cube tra YAML và viết SQL
        YAML (rút gọn), dòng đang dùng tô hồng
        
                    SQL do Cube sinh ra
                    
        
                    

        Dòng tô xanh lục là điều kiện Cube tự thêm từ thông tin đăng nhập.

        3Database chạy SQL
        Bảng orders (10 đơn)

        4Cube trả kết quả
        JSON trả về
        
                  
        Cube lưu kết quả (cache)

        Khi một câu hỏi đã gửi trước đó được gửi lại, Cube trả kết quả đã lưu mà không truy vấn database.

        Hình 5Mô phỏng gồm bốn ô: query JSON → YAML và SQL → database → kết quả, kèm nhật ký cache.

        Ô 3 cho thấy tác dụng của filter shop_id: các dòng gạch mờ thuộc shop còn lại bị loại trước khi tính, các dòng giữ lại được gom theo màu rồi tính trong từng nhóm. Nhật ký cache cho thấy khi cùng một câu hỏi được gửi lại, Cube trả kết quả đã lưu mà không chạy SQL. Theo đoạn code ở bước 6 của mục 00.2, trước khi dùng cache Cube so sánh refresh key đã lưu với refresh key hiện tại để xác định dữ liệu nguồn đã thay đổi hay chưa.

        Ghi nhớCùng query JSON và cùng người hỏi thì cùng một câu SQL. Cache chỉ bỏ qua bước chạy database, không làm thay đổi kết quả.
        Chương tiếp theo01 · Fundamentals→