Tuesday, April 7, 2026

RAG vs. CAG: Giải quyết "điểm mù" của AI với Google Gen AI, pgvector & marker-pdf

RAG vs. CAG, explained visually for AI engineers

RAG (Retrieval-Augmented Generation) đã thay đổi hoàn toàn cách chúng ta xây dựng các hệ thống AI dựa trên dữ liệu thực tế. Tuy nhiên, nếu bạn đã từng đưa hệ thống AI lên môi trường production, bạn sẽ nhanh chóng nhận ra một điểm yếu cố hữu:

Mỗi khi có một truy vấn mới, model thường xuyên phải truy xuất và đọc lại cùng một ngữ cảnh (context) từ Vector Database. Điều này gây ra 3 vấn đề lớn: đắt đỏ (tốn token), dư thừa và chậm trễ (high latency).

Đây là lúc CAG (Cache-Augmented Generation) xuất hiện. Bằng cách kết hợp khéo léo giữa RAG và CAG, bạn có thể tạo ra một hệ thống vừa thông minh, vừa siêu tốc độ.


1. Bản chất của RAG và CAG là gì?

  • RAG (Truy xuất truyền thống): Truy vấn -> Tìm kiếm top-K chunks từ DB -> Nhồi chunks vào prompt -> Gửi cho LLM đọc lại từ đầu.

  • CAG (Sử dụng bộ nhớ đệm): Cho phép model "ghi nhớ" các thông tin cố định bằng cách lưu chúng trực tiếp vào bộ nhớ Key-Value (KV memory) của LLM. Lần sau hỏi, model dùng luôn cache mà không cần đọc lại ngữ cảnh.

2. So sánh RAG vs. CAG (Pros & Cons)

Tiêu chíRAG (Retrieval-Augmented)CAG (Cache-Augmented)
Bản chấtTìm kiếm dữ liệu mới cho mỗi câu hỏi.Lưu trước dữ liệu vào bộ nhớ của LLM.
Tốc độ (Latency)Chậm hơn (Mất thời gian Query DB + LLM đọc lại).Cực nhanh (LLM đã có sẵn ngữ cảnh).
Chi phí TokenTốn phí input token cho mỗi lần query.Rẻ hơn đáng kể (phí cache hit cực thấp).
Điểm yếu (Cons)Latency cao, dễ retrieve sai đoạn văn (hallucination).Giới hạn bởi Context Window. Không thể cache dữ liệu thay đổi liên tục.

3. Use Cases: Chọn lọc những gì bạn Cache

Nguyên tắc vàng: Không cache mọi thứ. Bạn cần phân tách dữ liệu thành 2 luồng:

  • 🟢 Dữ liệu "Lạnh" (Cold Data) -> Dùng CAG: Sổ tay nhân viên, chính sách công ty, API Documentation, System Instructions dài.

  • 🔵 Dữ liệu "Nóng" (Hot Data) -> Dùng RAG: Lịch sử chat của user, trạng thái đơn hàng, dữ liệu real-time cập nhật từng phút.


4. Giải pháp Tối ưu: Kiến trúc RAG + CAG (Hybrid) với Modern Tech Stack

Để xây dựng một hệ thống production-ready, chúng ta sẽ kết hợp RAG và CAG bằng một Tech Stack hiện đại:

  1. marker-pdf: Chuyển đổi các file PDF phức tạp (chứa bảng biểu, định dạng khó) thành Markdown siêu sạch — định dạng mà LLM hiểu tốt nhất. Đây là nguồn cho Dữ liệu tĩnh (CAG).

  2. Google Gen AI (google-genai): Sử dụng Gemini 1.5 với tính năng Context Caching API bản địa để lưu trữ Markdown tĩnh này.

  3. PostgreSQL 16 + pgvector: Đóng vai trò là Vector Database mạnh mẽ để lưu trữ và truy xuất siêu tốc các sự kiện, lịch sử tương tác động của người dùng (RAG).

💻 Python Code: Optimized Hybrid RAG + CAG

Dưới đây là mã nguồn đã được tối ưu hóa cho môi trường thực tế, xử lý triệt để các vấn đề về SDK logic, format dữ liệu vector và hiệu năng.

Cài đặt: pip install google-genai psycopg2-binary marker-pdf

import os
import psycopg2
import json
from google import genai
from google.genai import types
from marker.converters.pdf import PdfConverter

# Khởi tạo Client theo SDK mới của Google
client = genai.Client(api_key=os.environ.get("GEMINI_API_KEY"))
MODEL_NAME = "models/gemini-1.5-flash"

# ==========================================
# PHẦN 1: CAG (COLD DATA - DỮ LIỆU TĨNH)
# ==========================================
def create_cag_from_pdf(pdf_path: str):
    print(f"[*] Đang sử dụng marker-pdf bóc tách Markdown: {pdf_path}")
    
    # Khởi tạo converter (Lưu ý: marker-pdf chạy tốt nhất trên GPU)
    converter = PdfConverter()
    rendered = converter(pdf_path)
    markdown_text = rendered.markdown
    
    print("[*] Đang khởi tạo Google Gemini Context Cache...")
    # LƯU Ý QUAN TRỌNG: system_instruction được đóng gói cứng vào Cache
    # Việc này giúp LLM tiền xử lý (pre-process) luôn chỉ dẫn, giảm tối đa độ trễ.
    cache = client.caches.create(
        model=MODEL_NAME,
        config=types.CreateCacheConfig(
            display_name="HR_Policy_2024",
            contents=[types.Content(parts=[types.Part(text=markdown_text)], role="user")],
            system_instruction="Bạn là trợ lý nhân sự chuyên nghiệp. Hãy sử dụng quy định công ty trong ngữ cảnh được cung cấp để giải đáp thắc mắc.",
            ttl="3600s" # Tự động hủy sau 1 giờ
        )
    )
    return cache

# ==========================================
# PHẦN 2: RAG (HOT DATA - DỮ LIỆU BIẾN ĐỘNG)
# ==========================================
def retrieve_dynamic_data(query: str, user_id: str) -> str:
    # 1. Embedding câu hỏi
    embedding_response = client.models.embed_content(
        model="text-embedding-004",
        contents=query
    )
    query_vector = embedding_response.embeddings[0].values

    # 2. Kết nối PostgreSQL 16 (pgvector)
    try:
        conn = psycopg2.connect("dbname=ragdb user=postgres password=secret host=localhost")
        cur = conn.cursor()
        
        # CHUẨN HÓA VECTOR: pgvector yêu cầu chuỗi định dạng [0.1, 0.2, ...]
        query_vector_str = f"[{','.join(map(str, query_vector))}]"
        
        # Truy vấn kết hợp: Lọc cứng theo user_id trước, sau đó tính khoảng cách Cosine (<=>)
        cur.execute("""
            SELECT content 
            FROM user_interactions 
            WHERE user_id = %s 
            ORDER BY embedding <=> %s::vector 
            LIMIT 3;
        """, (user_id, query_vector_str))
        
        rows = cur.fetchall()
        cur.close()
        conn.close()
        
        return "\n".join([r[0] for r in rows]) if rows else "Không tìm thấy dữ liệu cá nhân."
    except Exception as e:
        return f"Lỗi truy xuất RAG: {str(e)}"

# ==========================================
# PHẦN 3: HYBRID GENERATION (KẾT HỢP RAG & CAG)
# ==========================================
def ask_ai_assistant(user_query: str, user_id: str, cache_obj):
    # Lấy thông tin cá nhân của user (RAG)
    dynamic_context = retrieve_dynamic_data(user_query, user_id)
    
    # Tạo prompt kết hợp - Tách bạch rõ ràng dữ liệu để tránh nhầm lẫn
    prompt = f"""
THÔNG TIN CÁ NHÂN NHÂN VIÊN (Dữ liệu động):
{dynamic_context}

YÊU CẦU CỦA NHÂN VIÊN:
{user_query}
"""

    print("[*] Đang thực thi Hybrid Reasoning (CAG + RAG)...")
    response = client.models.generate_content(
        model=MODEL_NAME,
        contents=prompt,
        config=types.GenerateContentConfig(
            cached_content=cache_obj.name, # Kích hoạt CAG qua Cache ID
            temperature=0.1, # Giảm độ sáng tạo, bắt buộc tuân thủ đúng quy định HR
            max_output_tokens=1000
        )
    )
    return response.text

# ==========================================
# LUỒNG VẬN HÀNH THỰC TẾ
# ==========================================
if __name__ == "__main__":
    # BƯỚC 1: Tạo Cache (Chỉ làm 1 lần khi server start hoặc file update)
    # Thực tế: Nên lưu `policy_cache.name` vào DB để tái sử dụng
    policy_cache = create_cag_from_pdf("hr_handbook_2024.pdf")
    
    # BƯỚC 2: Nhận câu hỏi từ User
    uid = "employee_007"
    q = "Tôi còn 5 ngày phép, muốn nghỉ từ thứ 4 đến thứ 6 tuần này. Có vi phạm quy định báo trước của công ty không?"
    
    # BƯỚC 3: Trả lời siêu tốc
    result = ask_ai_assistant(q, uid, policy_cache)
    
    print("-" * 30)
    print(f"👤 USER: {q}")
    print(f"🤖 AI:\n{result}")


Tại sao Kiến trúc này là "vũ khí tối thượng"?

Đoạn code trên không chỉ là ví dụ minh họa mà đã giải quyết những bài toán hóc búa nhất khi làm hệ thống RAG thực tế:

  1. Chất lượng Context tuyệt đối (marker-pdf): RAG truyền thống thường "gãy" khi parse file PDF chứa bảng biểu pháp lý, nhân sự. Việc bóc tách sạch sẽ bằng mô hình deep-learning của marker-pdf đảm bảo LLM không bị "mù" định dạng.

  2. Tối ưu TTFT (Time-To-First-Token) cực đỉnh: Bằng cách đưa system_instruction trực tiếp vào hàm create_cache, Gemini sẽ tiền xử lý toàn bộ luật lệ. Model trả lời gần như tức thì và bạn chỉ tốn 1 phần nhỏ phí token so với việc gửi đi gửi lại hàng chục ngàn từ mỗi lần.

  3. Khắc phục lỗi Multi-tenancy với pgvector: Các hệ thống In-memory Vector DB thường gặp khó khi lọc dữ liệu theo user. SQL thuần của Postgres (WHERE user_id = %s) lọc dữ liệu người dùng cực kỳ an toàn trước khi tính khoảng cách không gian (Cosine Distance).

  4. Kiểm soát Hallucination: Việc set temperature=0.1 kết hợp với prompt tách bạch rõ (Dữ liệu động vs Câu hỏi) ép LLM trở thành một cỗ máy suy luận logic nghiêm ngặt dựa trên Cache thay vì "sáng tác" thêm.


🎯 Lời kết

Kiến trúc Hybrid RAG + CAG chính là tương lai của các hệ thống AI cấp doanh nghiệp. Thay vì bắt LLM của bạn đóng vai một "người mắc bệnh mất trí nhớ ngắn hạn" phải đọc lại nội quy công ty 10,000 lần một ngày, hãy lưu nó vào Cache.

Giữ RAG cho những gì đang di chuyển, và dùng CAG cho những gì đứng yên.

👉 Còn bạn thì sao? Đã đến lúc nâng cấp hệ thống RAG của bạn bằng Prompt Caching chưa?

Content Rating