Khởi tạo VectorStoreIndex kết nối với PostgreSQL
Bước đầu tiên là thiết lập kết nối giữa LlamaIndex và PostgreSQL đã được chuẩn bị sẵn trong các phần trước, nơi dữ liệu vector đã được lưu trữ.
Mục đích là tạo một đối tượng VectorStoreIndex để LlamaIndex có thể truy xuất và quản lý các node văn bản đã được embedding vào cơ sở dữ liệu mà không cần tải toàn bộ vào bộ nhớ RAM.
Đảm bảo thư mục dữ liệu /opt/rag_data đã tồn tại và chứa file vector_store.json (tạo ở Phần 4).
Đầu tiên, hãy tạo file Python để khởi tạo index với tên rag_query.py tại thư mục /opt/rag_app.
File này sẽ chứa cấu hình kết nối PostgreSQL thông qua PGVectorVectorStore và ánh xạ nó vào VectorStoreIndex.
cat > /opt/rag_app/rag_query.py
Thay thế your_secure_password bằng mật khẩu PostgreSQL thực tế của bạn. Tham số embedding_dim phải khớp với chiều của vector embedding đã tạo ở Phần 4 (thường là 1536 cho các model phổ biến).
Chạy lệnh sau để xác minh việc kết nối và đếm số lượng node:
cd /opt/rag_app && python rag_query.py
Kết quả mong đợi: In ra thông báo thành công và số lượng node (ví dụ: Total nodes in index: 15), chứng tỏ LlamaIndex đã đọc được cấu trúc dữ liệu từ PostgreSQL mà không cần file JSON.
Cấu hình QueryEngine để thực hiện tìm kiếm ngữ nghĩa
Sau khi có index, ta cần một cơ chế để biến câu hỏi của người dùng thành truy vấn vector và tìm kiếm trong PostgreSQL.
Sử dụng QueryEngine là cách tiêu chuẩn để thực hiện truy vấn ngữ nghĩa (semantic search) trên VectorStoreIndex.
Chúng ta sẽ mở rộng file rag_query.py để thêm logic tạo QueryEngine và định nghĩa hàm xử lý câu hỏi.
cat > /opt/rag_app/rag_query.py
Lưu ý quan trọng: Tham số embedding_dim trong PGVectorVectorStore và model trong HuggingFaceEmbedding phải khớp chính xác với cấu hình đã dùng ở Phần 4. Nếu dùng BAAI/bge-small-en-v1.5, chiều là 384.
Chạy script để kiểm tra khả năng truy vấn:
cd /opt/rag_app && python rag_query.py
Kết quả mong đợi: Script in ra câu trả lời tóm tắt dựa trên nội dung dữ liệu đã upload, kèm theo danh sách các đoạn văn bản nguồn (source_nodes) đã được tìm thấy trong PostgreSQL.
Tối ưu hóa tham số số lượng kết quả trả về (top_k)
Mặc định, QueryEngine thường trả về số lượng node cố định. Trong môi trường RAG thực tế, việc điều chỉnh top_k là cần thiết để cân bằng giữa độ chính xác và tốc độ phản hồi.
Tham số similarity_top_k trong VectorIndexRetriever kiểm soát số lượng vector tương tự nhất được lấy từ PostgreSQL để đưa vào ngữ cảnh cho LLM.
Chúng ta sẽ cấu hình lại QueryEngine để sử dụng Retriever với tham số similarity_top_k=3, nghĩa là chỉ lấy 3 đoạn văn bản liên quan nhất.
cat > /opt/rag_app/rag_query.py
Việc giảm top_k xuống 3 giúp giảm lượng token gửi cho LLM, tiết kiệm chi phí và tăng tốc độ phản hồi, đồng thời giảm nhiễu từ các đoạn văn không liên quan.
Chạy lệnh để kiểm tra hiệu quả của tham số mới:
cd /opt/rag_app && python rag_query.py
Kết quả mong đợi: Chỉ có đúng 3 dòng Nodes đã chọn được in ra, và câu trả lời chỉ dựa trên nội dung của 3 đoạn này.
Xử lý kết quả trả về và định dạng câu trả lời cho người dùng
Trong ứng dụng thực tế, output thô từ response thường chưa đủ đẹp. Cần tách biệt phần câu trả lời và phần trích dẫn nguồn (citation) để người dùng kiểm chứng.
Đối tượng Response của LlamaIndex chứa thuộc tính text (câu trả lời) và source_nodes (dữ liệu gốc).
Bây giờ, ta sẽ viết một hàm format_response để tạo ra định dạng đầu ra chuẩn: Câu trả lời đi kèm với số thứ tự nguồn tham chiếu.
cat > /opt/rag_app/rag_query.py 150 else node.text
output += f"{i+1}. {meta_str}: {text_preview}\n"
else:
output += "\n(Lưu ý: Không tìm thấy thông tin liên quan trong cơ sở dữ liệu)\n"
return output
def run_query(query_str: str):
print(f"Người dùng hỏi: {query_str}")
response = query_engine.query(query_str)
return format_response(response)
if __name__ == "__main__":
# Test với câu hỏi cụ thể
final_output = run_query("Cách tối ưu PostgreSQL?")
print("\n" + "="*50)
print(final_output)
print("="*50)
EOF
Hàm format_response sẽ duyệt qua source_nodes, trích xuất metadata (như tên file, trang) và cắt ngắn văn bản để hiển thị gọn gàng.
Chạy lệnh để xem định dạng đầu ra hoàn chỉnh:
cd /opt/rag_app && python rag_query.py
Kết quả mong đợi: Một câu trả lời có cấu trúc rõ ràng, phần "Nguồn tham khảo" liệt kê số thứ tự, tên file và trích đoạn nội dung, giúp người dùng dễ dàng xác minh thông tin.
Điều hướng series:
Mục lục: Series: Triển khai Database AI với LlamaIndex và PostgreSQL trên Ubuntu 24.04
« Phần 4: Xử lý dữ liệu và tạo vector index với LlamaIndex
Phần 6: Tối ưu hóa hiệu năng và xử lý sự cố phổ biến »