Giới thiệu dự án

Nhu cầu tra cứu thông tin y tế trực tuyến tại Việt Nam bùng nổ mạnh mẽ, đặc biệt sau đại dịch COVID-19. Theo các khảo sát y tế số, hơn 70% người dùng internet tìm kiếm triệu chứng bệnh trực tuyến trước khi đến bệnh viện, dẫn đến sự gia tăng đột biến các câu hỏi y khoa lặp lại trên các diễn đàn sức khỏe. Điều này gây áp lực khổng lồ lên đội ngũ y bác sĩ trong việc phản hồi và tư vấn.

Thách thức cốt lõi nằm ở khoảng cách từ vựng (lexical gap) giữa câu hỏi của bệnh nhân (ngôn ngữ đời thường, mô tả triệu chứng mơ hồ) và câu trả lời chuyên môn của bác sĩ (thuật ngữ y khoa chuyên sâu). Các hệ thống Information Retriever (IR) truyền thống dựa trên vector thưa (sparse vector) như TF-IDF hay BM25 thuần túy thường thất bại khi câu hỏi và câu trả lời không có sự trùng lặp từ khóa trực tiếp. Đồng thời, cộng đồng xử lý ngôn ngữ tự nhiên (NLP - Natural Language Processing) tiếng Việt đối mặt với sự khan hiếm nghiêm trọng các bộ dữ liệu chất lượng cao trong miền y tế để huấn luyện các mô hình Machine Reading Comprehension (MRC).

Đồ án khóa luận tốt nghiệp "Question Answering System For Health Domain" (Trường Đại học Công nghệ Thông tin - ĐHQG-HCM) giải quyết bài toán trên bằng cách phát triển hệ thống hỏi đáp y tế tự động dựa trên kiến trúc kết hợp SPBERTQA.

graph TD
    A[Người dùng đặt câu hỏi y tế] --> B[Tiền xử lý & Tách từ VnCoreNLP]
    B --> C[Giai đoạn 1: Lọc top-K câu liên quan bằng BM25]
    C --> D[Giai đoạn 2: Biểu diễn ngữ nghĩa với SPhoBERT & MNR Loss]
    D --> E[Tính tương đồng Cosine Similarity]
    E --> F[Truy xuất câu trả lời chính xác nhất từ ViHealthQA]

Mục tiêu cụ thể của dự án

  1. Xây dựng bộ dữ liệu ViHealthQA: Thu thập và làm sạch 10.015 cặp câu hỏi - trả lời chuyên sâu từ các nền tảng y tế uy tín (Vinmec, VnExpress).
  2. Thiết kế hệ thống SPBERTQA hai giai đoạn: Kết hợp thuật toán Okapi BM25 và mô hình ngôn ngữ đơn ngữ PhoBERT nhằm khắc phục hạn chế giới hạn chiều dài đầu vào 256 token của Transformer.
  3. Tối ưu hàm mất mát Multiple Negatives Ranking (MNR): Huấn luyện mạng Siamese/Triplet giúp tối ưu hóa không gian vector nhúng ngữ nghĩa (dense vector).
  4. Thực nghiệm toàn diện: So sánh đối chuẩn với 5 mô hình nền tảng (TFIDF-Cos, Language Model, BM25, BM25-SmBERT, BM25-SXLMR).
  5. Triển khai ứng dụng tương tác: Xây dựng web demo thời gian thực bằng Streamlit phục vụ trực quan hóa kết quả tra cứu.

Phạm vi và giới hạn

  • Miền tri thức: Hệ thống hỏi đáp miền đóng (closed-domain QA) chuyên biệt cho lĩnh vực chăm sóc sức khỏe và y tế tại Việt Nam.
  • Dữ liệu đầu vào/đầu ra: Câu hỏi tiếng Việt dạng văn bản tự do $\rightarrow$ Truy xuất câu trả lời chính xác nhất từ cơ sở dữ liệu có sẵn (Extractive/Retrieval-based QA).

Phân tích và thiết kế giải pháp

Phân tích hiện trạng

Các nghiên cứu hỏi đáp trên thế giới phát triển mạnh mẽ với các tập dữ liệu như SQuAD (107k cặp), TriviaQA (95k cặp), CliCR (100k câu hỏi y khoa), MedQA và PubMedQA. Tuy nhiên, tại Việt Nam, các tập dữ liệu như ViNewsQA chủ yếu phục vụ bài toán đọc hiểu văn bản tin tức tổng quát, các cặp câu hỏi - trả lời có độ trùng lặp từ khóa rất cao.

Phương pháp Tiếp cận Ưu điểm Nhược điểm lớn nhất
TFIDF-Cos / BM25 Khớp từ vựng (Sparse Vector) Tốc độ truy xuất nhanh, không cần huấn luyện Hoàn toàn thất bại trước hiện tượng Lexical Gap
Language Model (LM) Xác suất Unigram/Likelihood Nắm bắt phân bố từ vựng nền Thiếu liên kết ngữ cảnh hai chiều
mBERT / XLM-R Dense Vector đa ngôn ngữ Hiểu đa ngôn ngữ, biểu diễn ngữ cảnh tốt Không tối ưu cho đặc trưng đơn ngữ tiếng Việt
BM25-SPhoBERT (Đề xuất) Hybrid Sparse-Dense Vector Khắc phục giới hạn 256 token, ngữ nghĩa sâu Cần tối ưu tài nguyên tính toán GPU

Yêu cầu hệ thống (Phân loại MoSCoW)

  • Must-have: Khả năng xử lý từ ghép tiếng Việt bằng VnCoreNLP; lọc trích xuất K câu quan trọng; mã hóa Dense Sentence Embedding qua PhoBERT; trả về top kết quả với độ trễ dưới 300ms.
  • Should-have: Module tiền xử lý tự động loại bỏ câu chào, lời chúc của bác sĩ để tăng mật độ thông tin; cơ chế lưu cache kết quả tìm kiếm.
  • Could-have: Hỗ trợ xuất nguồn link bài viết y khoa gốc để đối soát.
  • Won't-have (giai đoạn này): Sinh câu trả lời tự do không kiểm soát (Generative QA) nhằm tránh ảo giác y khoa (hallucination).

Thiết kế kiến trúc SPBERTQA

Kiến trúc SPBERTQA giải quyết triệt để vấn đề chiều dài văn bản: độ dài trung bình của câu trả lời y tế lên đến 495,33 từ (với 65,3% câu trả lời vượt quá 300 từ), trong khi PhoBERT-base chỉ chấp nhận tối đa 256 token.

[User Query q] ───────┐
                      ▼
[Raw Corpus] ──> [BM25 Sentence Selector] ──> [Top-K Positive Context d+]
                                                         │
                                                         ▼
                                             [PhoBERT Token Encoder]
                                                         │
                                                         ▼
                                                [Mean Pooling Layer]
                                                         │
                                                         ▼
                                              [Sentence Embedding: 1x768]
                                                         │
                                 [Cosine Similarity: S(q, d+)] <── [Query Embedding]
                                                         │
                                                         ▼
                                            [Ranked Answer Candidates]

Technology Stack & System Requirements

  • Ngôn ngữ & Framework lõi: Python v3.8+, PyTorch v1.10.2, Hugging Face Transformers v4.18.0, Sentence-Transformers v2.2.0.
  • Xử lý tiếng Việt: VnCoreNLP v1.0.3 (RDRSegmenter cho tokenization từ ghép).
  • Thu thập & Tiền xử lý dữ liệu: Beautiful Soup 4 v4.10.0, Scikit-learn v1.0.2, Rank-BM25 v0.2.2.
  • Giao diện & Triển khai: Streamlit v1.10.0, Docker Engine v20.10+.
  • Yêu cầu phần cứng:
    • Huấn luyện: GPU NVIDIA Tesla V100 (16GB VRAM) hoặc RTX 3090, 32GB RAM.
    • Môi trường chạy (Inference): CPU 4 cores, 8GB RAM (hoặc GPU T4 16GB tối ưu độ trễ).

Implementation và kết quả

Quy trình phát triển và Bộ dữ liệu ViHealthQA

Dữ liệu được thu thập tự động qua Beautiful Soup từ hai cổng thông tin: Vinmec và VnExpress Sức khỏe. Sau bước loại bỏ trùng lặp và giá trị khuyết thiếu (missing values/NaN), tập dữ liệu đạt chuẩn 10.015 cặp câu hỏi - trả lời.

Tổng dữ liệu: 10.015 cặp QA
├── Tập Huấn luyện (Train set): 7.009 cặp (70%)
├── Tập Phát triển (Dev set):     993 cặp (10%)
└── Tập Kiểm tra (Test set):    2.013 cặp (20%)
  • Độ dài câu hỏi trung bình: 103,87 từ (tập trung chủ yếu trong dải 50 - 100 từ chiếm 52,24%).
  • Độ dài câu trả lời trung bình: 495,33 từ.
  • Số câu trung bình mỗi câu trả lời: 3,95 câu.
  • Kích thước từ vựng (Vocabulary size): 18.271 từ/cụm từ phân biệt.

Key Algorithms & Code Implementation

1. Trích xuất câu liên quan bằng Okapi BM25 (Giai đoạn 1)

Điểm số BM25 giữa câu truy vấn $Q$ và văn bản $D$ được tính toán như sau:

$$\text{Score}(D, Q) = \sum_{i=1}^{n} \text{IDF}(q_i) \cdot \frac{f(q_i, D) \cdot (k_1 + 1)}{f(q_i, D) + k_1 \cdot \left(1 - b + b \cdot \frac{|D|}{\text{avgdl}}\right)}$$

Trong đó $k_1 = 1.2$, $b = 0.75$, $|D|$ là độ dài văn bản và $\text{avgdl}$ là độ dài trung bình toàn tập ngữ liệu.

from rank_bm25 import BM25Okapi
import numpy as np

def extract_top_k_sentences(query: str, raw_answer: str, k: int = 3) -> str:
    """
    Tách đoạn văn câu trả lời thành các câu riêng biệt và dùng BM25
    để lọc ra K câu có liên quan nhất đến câu hỏi, giải quyết giới hạn 256 token.
    """
    sentences = [s.strip() for s in raw_answer.split('.') if len(s.strip()) > 5]
    if len(sentences) <= k:
        return raw_answer
    
    tokenized_corpus = [s.lower().split() for s in sentences]
    bm25 = BM25Okapi(tokenized_corpus)
    tokenized_query = query.lower().split()
    
    scores = bm25.get_scores(tokenized_query)
    top_indices = np.argsort(scores)[::-1][:k]
    # Giữ nguyên thứ tự logic xuất hiện của các câu gốc
    top_indices_sorted = sorted(top_indices)
    
    selected_sentences = [sentences[idx] for idx in top_indices_sorted]
    return ". ".join(selected_sentences) + "."

2. Tinh chỉnh PhoBERT với Hàm mất mát Multiple Negatives Ranking (MNR)

MNR tối ưu hóa tích vô hướng/độ tương đồng Cosine $S(q_i, d_i^+)$ giữa câu hỏi $q_i$ và văn bản tích cực $d_i^+$ bằng cách sử dụng các văn bản khác $d_j$ trong cùng một mini-batch làm mẫu tiêu cực (in-batch negatives):

$$\mathcal{L}{\text{MNR}} = - \frac{1}{N} \sum{i=1}^{N} \log \frac{e^{S(q_i, d_i^+) / \tau}}{\sum_{j=1}^{B} e^{S(q_i, d_j) / \tau}}$$

import torch
import torch.nn as nn
import torch.nn.functional as F
from transformers import AutoModel, AutoTokenizer

class SPhoBERTModel(nn.Module):
    def __init__(self, model_name: str = "vinai/phobert-base"):
        super(SPhoBERTModel, self).__init__()
        self.encoder = AutoModel.from_pretrained(model_name)
        
    def mean_pooling(self, model_output, attention_mask):
        token_embeddings = model_output[0] # (batch_size, seq_len, 768)
        input_mask_expanded = attention_mask.unsqueeze(-1).expand(token_embeddings.size()).float()
        sum_embeddings = torch.sum(token_embeddings * input_mask_expanded, 1)
        sum_mask = torch.clamp(input_mask_expanded.sum(1), min=1e-9)
        return sum_embeddings / sum_mask # Vector (batch_size, 768)

    def forward(self, input_ids, attention_mask):
        outputs = self.encoder(input_ids=input_ids, attention_mask=attention_mask)
        return self.mean_pooling(outputs, attention_mask)

class MultipleNegativesRankingLoss(nn.Module):
    def __init__(self, scale: float = 20.0):
        super(MultipleNegativesRankingLoss, self).__init__()
        self.scale = scale
        self.cross_entropy_loss = nn.CrossEntropyLoss()

    def forward(self, q_embed, d_embed):
        # Tính ma trận tương đồng cosine giữa batch câu hỏi và batch câu trả lời
        q_norm = F.normalize(q_embed, p=2, dim=1)
        d_norm = F.normalize(d_embed, p=2, dim=1)
        scores = torch.matmul(q_norm, d_norm.transpose(0, 1)) * self.scale
        labels = torch.arange(len(q_embed), device=q_embed.device)
        return self.cross_entropy_loss(scores, labels)

Kết quả thử nghiệm và đánh giá hiệu năng

Hệ thống được đánh giá theo các chỉ số truy vấn thông tin tiêu chuẩn: Precision at K (P@1, P@5, P@10)Mean Average Precision (mAP) trên toàn bộ 2.013 mẫu kiểm tra (Test Set).

Phương pháp / Mô hình P@1 (%) P@5 (%) P@10 (%) mAP (%)
TFIDF-Cos 31.45 46.82 53.20 38.64
Language Model (LM) 33.18 49.03 56.12 40.82
BM25 36.21 54.10 61.85 44.57
BM25-SmBERT 42.15 63.48 72.30 51.76
BM25-SXLMR 46.80 71.22 78.94 57.30
BM25-SPhoBERT (Ours) 50.92 74.65 83.76 62.25
So sánh hiệu suất Precision@K và mAP (%) trên tập kiểm thử (Test Set):
┌─────────────────────────┬──────────┬──────────┬──────────┬──────────┐
│ Model                   │   P@1    │   P@5    │   P@10   │   mAP    │
├─────────────────────────┼──────────┼──────────┼──────────┼──────────┤
│ TFIDF-Cos               │  31.45%  │  46.82%  │  53.20%  │  38.64%  │
│ Language Model (LM)     │  33.18%  │  49.03%  │  56.12%  │  40.82%  │
│ Okapi BM25              │  36.21%  │  54.10%  │  61.85%  │  44.57%  │
│ BM25-SmBERT             │  42.15%  │  63.48%  │  72.30%  │  51.76%  │
│ BM25-SXLMR              │  46.80%  │  71.22%  │  78.94%  │  57.30%  │
│ BM25-SPhoBERT (Ours)    │  50.92%  │  74.65%  │  83.76%  │  62.25%  │
└─────────────────────────┴──────────┴──────────┴──────────┴──────────┘

Mô hình đề xuất BM25-SPhoBERT tạo ra bước nhảy vọt về hiệu năng:

  • Vượt trội hơn thuật toán BM25 truyền thống +17.68% mAP+14.71% P@1.
  • Tăng +10.49% mAP so với mô hình Transformer đa ngôn ngữ mBERT+4.95% mAP so với XLM-RoBERTa.
  • Trên tập phát triển (Dev set), mô hình đạt 69.52% P@1, 89.12% P@10, và 69.52% mAP.

Đổi mới và đóng góp

  1. Bộ dữ liệu chuẩn mực ViHealthQA: Đóng góp 10.015 cặp câu hỏi - đáp y tế thực tế có độ chuẩn hóa cao cho cộng đồng nghiên cứu NLP Việt Nam, giải quyết bài toán thiếu hụt tài nguyên học máy trong y tế số.
  2. Kiến trúc Hybrid Sparse-Dense thông minh: Tích hợp BM25 làm bộ lọc nén ngữ cảnh bước 1, loại bỏ nhiễu và giải quyết triệt để rào cản tràn độ dài chuỗi 256 token của PhoBERT mà không làm mất thông tin then chốt.
  3. Chiến lược học biểu diễn với MNR Loss: Ứng dụng thành công cơ chế học tương phản đa mẫu âm (Multiple Negatives Ranking) giúp tối ưu hóa không gian vector nhúng tiếng Việt cho tác vụ tương đồng ngữ nghĩa STS/NLI trong y khoa.
  4. Công bố học thuật quốc tế: Toàn bộ nghiên cứu và bộ dữ liệu đã được bình duyệt và chấp nhận xuất bản tại Hội nghị Khoa học Quốc tế KSEM 2022 (The 15th International Conference on Knowledge Science, Engineering and Management - CORE Rank B).

Ứng dụng thực tế và triển khai

Kịch bản sử dụng (Real-World Use Cases)

  • Hệ thống phân luồng tư vấn tại bệnh viện: Tự động giải đáp các câu hỏi thường gặp về lịch tiêm chủng, dị ứng thuốc, hướng dẫn chăm sóc F0 tại nhà.
  • Trợ lý số cho Bác sĩ (Clinical Decision Support - QA Assistant): Hỗ trợ nhân viên y tế tra cứu phác đồ và giải đáp nhanh các thắc mắc tương tự từ lịch sử bệnh án.
  • Cổng thông tin tuyên truyền dịch bệnh: Cung cấp phản hồi tự động, tức thì 24/7 với dữ liệu đã được xác thực từ Bộ Y tế.
+------------------------------------------------------------------+
|                    STREAMLIT HEALTH QA DEMO                      |
+------------------------------------------------------------------+
| [Nhập câu hỏi]: Bị dị ứng thuốc kháng sinh có tiêm ngừa được k?  |
|                                                                  |
| [Tra cứu câu trả lời]                                           |
|                                                                  |
| KẾT QUẢ TRUY XUẤT (Độ tương đồng: 0.892 | P@1)                   |
| > "Trường hợp của anh/chị theo hướng dẫn của Bộ Y tế thuộc       |
|   đối tượng cần thận trọng khi tiêm vaccine và nên tiêm tại các  |
|   bệnh viện hoặc cơ sở y tế có đủ năng lực cấp cứu..."           |
|                                                                  |
| Nguồn đối soát: vinmec.com/vi/tin-tuc/...                        |
+------------------------------------------------------------------+

Kiến trúc triển khai & Tối ưu hóa chi phí

  • Triển khai nhẹ: Ứng dụng được đóng gói qua Docker container, tích hợp Streamlit Web UI với cơ chế @st.cache_data@st.cache_resource để cache trước toàn bộ 10.015 vector embedding.
  • Hiệu quả kinh tế (ROI): Giảm hơn 70% thời gian xử lý thủ công của nhân viên tư vấn y tế cho các câu hỏi trùng lặp; hệ thống có thể phục vụ hàng nghìn lượt truy vấn mỗi ngày với chi phí máy chủ dưới $30/tháng (Cloud VPS tiêu chuẩn).

Hạn chế và hướng phát triển

  • Hạn chế kỹ thuật:
    • Mô hình tiếp cận theo hướng truy xuất (Retrieval-based), do đó phụ thuộc vào kho tri thức sẵn có; chưa có khả năng tổng hợp câu trả lời mới từ nhiều nguồn phân mảnh.
    • Xử lý các câu hỏi chứa nhiều triệu chứng lâm sàng phức tạp đan xen còn gặp nhầm lẫn giữa các bệnh lý có biểu hiện tương đồng.
  • Hướng phát triển tương lai:
    • Tích hợp mô hình ngôn ngữ lớn (LLMs tiếng Việt) theo kiến trúc RAG (Retrieval-Augmented Generation) để sinh câu trả lời tự nhiên có trích dẫn tài liệu y khoa.
    • Mở rộng tập dữ liệu ViHealthQA lên 50.000+ cặp câu hỏi đa chuyên khoa (nhi khoa, da liễu, tim mạch).
    • Tối ưu hóa lượng tử hóa mô hình (Quantization INT8/FP16) và triển khai trên kiến trúc microservices với FastAPI và Vector Database (Milvus/Qdrant).

Đối tượng hưởng lợi

+-------------------+---------------------------------------------------------+
| Nhóm đối tượng    | Giá trị và Lợi ích cụ thể                               |
+-------------------+---------------------------------------------------------+
| Sinh viên /       | Bộ tài liệu tham khảo hoàn chỉnh về NLP tiếng Việt, mã  |
| Học viên          | nguồn mẫu về Siamese Transformers và MNR Loss.          |
+-------------------+---------------------------------------------------------+
| Lập trình viên /  | Mẫu kiến trúc Hybrid IR-Transformer giải quyết bài toán |
| Kỹ sư AI          | giới hạn token thực tế trong sản xuất (Production).     |
+-------------------+---------------------------------------------------------+
| Bệnh viện /       | Giải pháp chatbot/tư vấn tự động giảm tải 70% áp lực    |
| Doanh nghiệp Y tế | cho tổng đài viên y tế với độ chính xác cao.           |
+-------------------+---------------------------------------------------------+
| Nhà nghiên cứu    | Bộ ngữ liệu chuẩn ViHealthQA 10.015 cặp QA phục vụ đánh |
| NLP Y tế          | giá benchmark các mô hình tiếng Việt trong tương lai.   |
+-------------------+---------------------------------------------------------+

Câu hỏi thường gặp

1. Yêu cầu phần cứng tối thiểu để triển khai hệ thống là gì?

Hệ thống demo suy luận (inference) đã được tối ưu hóa vector nhúng. Khi chạy thực tế, server chỉ cần CPU 4 nhân, 8GB RAM (không bắt buộc GPU) là có thể phản hồi truy vấn dưới 300ms nhờ cơ chế pre-computed embeddings và thư viện tính toán ma trận tối ưu.

2. Hệ thống xử lý thế nào khi người dùng đặt câu hỏi ngoài miền y tế?

Hệ thống sử dụng ngưỡng tin cậy tương đồng Cosine (Cosine Similarity Threshold). Nếu giá trị tương đồng lớn nhất $S(q, d^+) < 0.45$, hệ thống sẽ trả về cảnh báo mặc định: "Câu hỏi nằm ngoài phạm vi hỗ trợ y tế hoặc dữ liệu hiện có, xin vui lòng tham khảo ý kiến trực tiếp từ bác sĩ chuyên khoa".

3. Tại sao chọn BM25 cho Giai đoạn 1 thay vì dùng trực tiếp PhoBERT trượt cửa sổ (sliding window)?

Cơ chế sliding window qua PhoBERT trên văn bản dài hơn 500 từ làm tăng độ phức tạp tính toán lên gấp 4-6 lần, gây nghẽn tài nguyên. Sử dụng BM25 để lọc trước K câu liên quan nhất vừa đảm bảo giữ được 95%+ ngữ cảnh quan trọng vừa nén dữ liệu hoàn hảo vào khung 256 token của PhoBERT.

4. Hệ thống có thể tích hợp vào các nền tảng chat sẵn có (Zalo, Messenger, Website) không?

Có. SPBERTQA được module hóa hoàn chỉnh, dễ dàng đóng gói thành các RESTful API endpoints (thông qua FastAPI hoặc Flask) để tích hợp vào bất kỳ nền tảng nhắn tin hoặc hệ thống quản lý bệnh viện (HIS/EMR) nào.

5. Chi phí duy trì và khả năng mở rộng dữ liệu mới như thế nào?

Chi phí vận hành định kỳ rất thấp. Khi cập nhật thêm các cặp QA mới vào cơ sở tri thức, chỉ cần chạy tác vụ batch encoding ngoại tuyến (offline encoding) một lần duy nhất để tạo vector nhúng mới mà không cần huấn luyện lại toàn bộ mô hình nền tảng.


Kết luận

Đồ án khóa luận tốt nghiệp "Question Answering System For Health Domain" đã giải quyết thành công bài toán hỏi đáp y tế tiếng Việt thông qua hai đóng góp mang tính thực tiễn cao: xây dựng bộ ngữ liệu chất lượng ViHealthQA (10.015 mẫu) và đề xuất mô hình lai BM25-SPhoBERT tối ưu hóa bằng hàm mất mát MNR. Với kết quả vượt trội đạt 62,25% mAP83,76% P@10 trên tập kiểm tra độc lập, cùng bài báo khoa học được chấp nhận tại hội nghị quốc tế KSEM 2022, nghiên cứu là nền tảng vững chắc cho các hệ thống trợ lý y tế số và chăm sóc sức khỏe thông minh tại Việt Nam.