CHƯƠNG 3: Xây dựng hệ thống trình bày
3.3. Xây dựng lõi back-end
Ở phần này sẽ đề cập đến việc xây dựng lõi cho ứng dụng bao gồm từ việc xây dựng vector database, truy xuất dữ liệu, hệ thống API, mô hình ngôn ngữ lớn. Cơ chế hoạt động ở phía server.
Đối với backend ta sẽ cần thiết kế 2 module chính là Langchain RAG để xử lý tác vụ hỏi đáp và FastAPI để tương tác với người dùng ở giao diện website front-end. Từ câu hỏi người dùng sẽ được đi qua lớp embedding rồi đưa qua retriever để tìm tài liệu liên quan. Tại phía website của người dùng sẽ có một tùy chọn tài liệu tham khảo cung cấp 2 lựa chọn
là “Bách khoa toàn thư Wikipedia” và “Trường đại học Nguyễn Tất Thành”. Người dùng sẽ chọn nguồn từ trường thì phía backend sẽ dùng retriever Qdrant để tìm kiếm và ngược lại thì sẽ dùng retriever Wikipedia được cung cấp sẵn bởi Langchain để truy xuất từ Internet. Cụ thể sẽ có sơ đồ như sau:
43 Hình 3.12: : Sơ đồ hoạt động của backend
Ta sẽ tiến hành đi vào chi tiết cách xây dựng các phần của hệ thống này. Bắt đầu từ việc xây dựng vector database trước.
3.3.1. Xây dựng vector database
Bên cạnh các công nghệ vector database đang nổi như Weaviate, Chroma và FAISS thì Qdrant là một công nghệ mã nguồn mở tuyệt vời khi có thể triển khai dễ dàng trên môi trường Docker chỉ với 1 dòng lệnh và quan trọng hơn hết là đội ngũ phát triển cung cấp cloud miễn phí 1GB lưu trữ vĩnh viễn cho database, một con số quá dư dả cho việc lưu trữ
dữ liệu văn bản.
Hình 3.13: Qdrant vector database
44 Công nghệ này được viết bằng Rust, cho phép tìm kiếm liên quan thông qua vector embedding và model dùng để tạo ra các embedding này có thể được tích hợp thông qua kho mô hình khổng lồ của Huggingface, việc kết nối và cài đặt vô cùng đơn giản như việc thực hiện setup một server non-SQL, khi setup trên cloud ta sẽ cần lưu ý 2 giá trị quan trọng đó chính là Endpoint URL và API Key của để truy cập vào clusters.
Hình 3.14: Cấu hình Qdrant Vector Database Một cluster giống như một table trong SQL, ta cần lưu lại 2 cấu hình này để có thể truy cập vào thực hiện CRUD (Create – Read – Update - Delete) trên cluster thông qua Qdrant
Client Library được tích hợp trong Langchain. Cuối cùng ta sẽ tạo một file Jupyter Notebook trên Google Colab tên VECTOR_DATABASE_CREATE.ipynb để thực hiện việc đẩy toàn bộ các chunks của sổ tay sinh viên đã xử lý và encode thông qua model embedding mã đã đề cập trước đó là sentence-transformers/paraphrase-multilingual-
mpnet-base-v2 lên cluster. Lúc này ta đã có thể thực hiện truy xuất theo mức độ liên quan
trên dữ liệu database như một Retriver, tuy nhiên nếu dừng lại ở đây mô hình sẽ gặp hiện tượng đôi lúc sẽ không lấy được đúng nội dung cần tìm vì sự phân tán quá lớn của dữ liệu.
Ta sẽ cần áp dụng một số kĩ thuật Retriver nâng cao để đảm bảo hệ thống luôn lấy ra được đoạn chunk liên quan nhất.
3.3.2. Xây dựng Retriver
45
Để tạo ra một Retriever có khả năng trích xuất được phần văn bản có liên quan nhất đến câu hỏi truy vấn ta cần thực hiện nó qua một bộ lọc bao gồm 2 lớp tìm kiếm có cấu trúc như sau:
Hình 3.15: Cấu trúc Retriver nâng cao kèm bộ lọc Rerank
Bộ lọc này sẽ áp dụng trên cả 2 miền là NTTU và miền Wikipedia. Đầu tiên, ở bộ lọc đầu
sẽ lọc ra top-k các văn bản liên quan nhất (ở đây top-k = 15). Tiếp tục, các văn bản liên quan nhất này sẽ được tái xếp hạng (re-rank) lại bằng một mô hình phân loại văn bản (text
classification) khác. Mô hình này sẽ tính toán điểm số tương đồng lại một lần nữa để đảm
bảo rằng văn bản lấy ra là có điểm khác biệt thấp nhất đến câu truy vấn, đầu ra của re- ranker là một văn bản duy nhất. Việc dùng một mô hình thứ 2 để kiểm chứng lại sẽ giúp tăng độ chính xác của hệ thống tìm kiếm thông tin, nó giống như việc kiểm chứng thông tin từ nhiều nguồn, việc này trong thực tế chứng minh rằng nó có hiệu quả trong hầu hết các trường hợp. Và mô hình ta sử dụng ở đây làm re-ranker là amberoad/bert- multilingual-passage-reranking-msmarco, đây là một mô hình có hỗ trợ tiếng Việt và
đạt được đánh giá tốt trên HuggingFace.
Hình 3.16: Mô hình BERT Re-ranker
46 Trong thực tế có một số phương pháp được áp dụng phổ biến như kết hợp điểm số BM25 hoặc TF-IDF song song với việc tính toán qua embedding rồi nhập bảng xếp hạng lại làm một, nhưng sau khi kiểm nghiệm thực tế tôi nhận thấy rằng phương pháp bộ lọc qua 2 mô hình ngôn ngữ lớn sẽ có hiệu quả vượt trội hơn, theo suy đoán có lẽ vì nếu tính độ liên quan theo tần suất xuất hiện của từ vựng thì sẽ không hiệu quả bằng việc tính toán dựa trên vector đặc trưng, thứ vốn biểu diễn về mặt ngữ nghĩa cho từ và đoạn văn đó. Phương pháp này sẽ tốn nhiều tài nguyên tính toán hơn tuy nhiên bù lại kết quả truy xuất sẽ cải thiện đáng kể.
Để có thể tích hợp được lớp re-ranker này trên Langchain ta cần viết thêm một lớp Custom Retriever kế thừa lớp RetrieverVectorStore để có thể nhúng vào retriever của 2 miền data NTTU và Wikipedia. Vậy là chúng ta đã xong việc xây dựng hệ thống truy xuất thông tin
từ truy vấn, tiếp theo ta sẽ tiến hành lựa chọn pretrained model cho mô hình ngôn ngữ.