MVP này phục vụ phần chatbot của dự án: upload tài liệu môn học, tự động extract text, chunk, embedding, lưu SQLite, hỏi đáp theo tài liệu, trích dẫn nguồn và từ chối câu hỏi ngoài phạm vi.
- Upload và index
PDF,DOCX,PPTX,TXT,MD. - Tách tài liệu thành chunks có metadata môn học, chương, file, trang/slide.
- Embedding mặc định sử dụng
BAAI/bge-m3, có fallback đọc model từ cache khi mất mạng. - Có thể đổi sang
local-hash-v1hoặctext-embedding-3-small. - Chat theo phiên, lưu lịch sử hội thoại trong SQLite.
- Trả lời có nguồn tham chiếu.
- Nếu không tìm thấy context đủ liên quan, bot trả lời:
Tôi chưa tìm thấy thông tin này trong tài liệu đã cung cấp.
D:\CHATBOT
├── app/
│ └── streamlit_app.py
├── src/
│ ├── config.py
│ ├── document_loader.py
│ ├── chunker.py
│ ├── embeddings.py
│ ├── rag_pipeline.py
│ ├── storage.py
│ └── text_utils.py
├── data/
│ ├── raw/
│ ├── processed/
│ └── db/
├── experiments/
├── reports/
├── tests/
├── requirements.txt
└── .env.example
cd D:\CHATBOT
python -m venv .venv
.\.venv\Scripts\Activate.ps1
pip install -r requirements.txt
streamlit run app\streamlit_app.pyNếu chưa có API key, app vẫn chạy ở chế độ offline. Chất lượng retrieval sẽ tốt hơn khi dùng embedding model chuyên dụng.
cd D:\CHATBOT
python -m pip install -r requirements.txt
python -m uvicorn app.main:app --host 127.0.0.1 --port 8000 --reloadAPI docs tự động:
http://127.0.0.1:8000/docs
Các endpoint chính:
GET /api/health
GET /api/documents
GET /api/subjects
POST /api/documents
DELETE /api/documents/{document_id}
GET /api/sessions
POST /api/sessions
GET /api/sessions/{session_id}/messages
POST /api/chat
GET /api/benchmarks
GET /api/benchmarks/{run_id}
POST /api/benchmarks/run
POST /api/benchmark-jobs
GET /api/benchmark-jobs
GET /api/benchmark-jobs/{job_id}
GET /api/dashboard/summary
GET /api/dashboard/comparison
GET /api/evaluation/capabilities
Ví dụ upload tài liệu từ frontend Java cần gửi multipart/form-data:
file=<PDF/DOCX/PPTX/TXT/MD>
subject=Môn học demo
chapter=Chương 1
Ví dụ body khi chat:
{
"session_id": "optional-session-id",
"question": "RAG là gì?",
"subject": "Software Testing"
}Response chat trả về:
{
"session_id": "...",
"answer": "...",
"sources": [],
"retrieved": []
}File mẫu gọi API bằng Java nằm ở:
examples/JavaApiClient.java
Test set nằm tại data/test_set.csv. Mỗi dòng sử dụng các cột:
question,expected_answer,expected_source,expected_page,subject,is_out_of_scope,category
Chạy benchmark bằng dòng lệnh:
python experiments\run_benchmark.py --test-set data\test_set.csvHoặc gọi API:
POST /api/benchmarks/run
Content-Type: application/json
{
"test_set_path": "data/test_set.csv"
}Kết quả gồm:
answer_token_f1: độ trùng khớp token với ground truth.source_hit_rate: tỷ lệ lấy đúng tài liệu nguồn.page_hit_rate: tỷ lệ lấy đúng trang tài liệu.refusal_accuracy: tỷ lệ từ chối đúng câu ngoài tài liệu.average_top_retrieval_score: điểm retrieval trung bình.average_latency_ms: thời gian phản hồi trung bình.faithfulness_proxy: tỷ lệ token câu trả lời được hỗ trợ bởi context.answer_relevancy_proxy: mức trùng khớp với ground truth.context_precision_proxy: tỷ lệ chunks có chứa thông tin ground truth.context_recall_proxy: tỷ lệ thông tin ground truth xuất hiện trong context.
Bốn metric có hậu tố _proxy là đánh giá local không sử dụng LLM judge và không
phải RAGAS chính thức.
Retrieval mặc định sử dụng hybrid search: cosine similarity từ embedding kết hợp
keyword matching. Trọng số semantic được cấu hình bằng SEMANTIC_WEIGHT.
Chạy sweep để tìm cấu hình retrieval tốt nhất:
python experiments\run_retrieval_sweep.pyKết quả tổng hợp được lưu tại reports/retrieval_sweep.csv.
Index và benchmark bằng bge-m3:
python experiments\index_documents.py --embedding-provider sentence-transformers --embedding-model BAAI/bge-m3
python experiments\run_benchmark.py --embedding-provider sentence-transformers --embedding-model BAAI/bge-m3
python experiments\run_retrieval_sweep.py --embedding-provider sentence-transformers --embedding-model BAAI/bge-m3Chi tiết kết quả được lưu trong SQLite và xuất ra reports/benchmark_<run_id>.csv.
Fine-tuning được tách khỏi dependencies chatbot để tránh làm môi trường chạy API quá nặng.
Đầu tiên, hoàn thiện data/test_set.csv với tối thiểu 50 cặp câu hỏi và câu trả lời. Sau đó tạo dataset:
python experiments\prepare_finetuning_data.py --source data\test_set.csvKết quả:
data/finetuning/train.jsonl
data/finetuning/validation.jsonl
data/finetuning/dataset_summary.json
Kiểm tra cấu hình và dataset mà chưa train:
python experiments\train_lora.py --dry-runCài dependencies fine-tuning:
python -m pip install -r requirements-finetuning.txtChạy LoRA/QLoRA:
python experiments\train_lora.py --config experiments\lora_config.jsonCấu hình mặc định sử dụng Qwen/Qwen2.5-1.5B-Instruct cho cả hai baseline. QLoRA cần CUDA GPU và bitsandbytes; cấu hình hiện tại dùng NF4 4-bit để chạy trên GPU 4 GB. Nếu không có GPU, không chạy benchmark chính thức vì thời gian LoRA/inference trên CPU không phù hợp.
API hỗ trợ frontend:
POST /api/finetuning/prepare
GET /api/finetuning/status
The locked research corpus is data/corpus/triethoc_mac_lenin.pdf; versioned
train, validation, test, and robustness data live in
data/research/triethoc-v1. The official adapter path is
models/qwen2.5-1.5b-triethoc-lora-v1. The older models/qwen-rag-lora
artifact remains unverified and is not selected by runtime.
BASE_RAG uses Qwen2.5-1.5B base plus BGE-M3 retrieval.
FINE_TUNED_ONLY uses the same base plus LoRA without retrieval context.
OpenAI is only the official RAGAS judge through
POST /api/evaluation/ragas/batch.
Backend mặc định dùng RAG + Qwen LoRA nếu adapter tồn tại, và tự fallback về
extractive answer nếu model không load được.
GET /api/model/status
Các chế độ generation qua biến môi trường:
GENERATION_PROVIDER=auto
# auto | lora | extractive | openaiBenchmark riêng từng chế độ:
python experiments\run_benchmark.py --generation-provider extractive
python experiments\run_benchmark.py --generation-provider lora
python experiments\run_benchmark.py --generation-provider lora --mode finetuned_onlyVì benchmark LoRA trên CPU chạy lâu, frontend nên dùng:
POST /api/benchmark-jobs
Content-Type: application/json
{
"test_set_path": "data/test_set.csv",
"mode": "rag",
"generation_provider": "lora"
}Sau đó polling GET /api/benchmark-jobs/{job_id} cho đến khi trạng thái là
completed hoặc failed. Dữ liệu biểu đồ tổng hợp lấy từ
GET /api/dashboard/summary.
Body tạo dataset:
{
"source_csv": "data/test_set.csv",
"validation_ratio": 0.2,
"seed": 42
}Tạo file .env hoặc set biến môi trường:
$env:OPENAI_API_KEY="sk-..."
$env:OPENAI_CHAT_MODEL="gpt-4o-mini"
$env:EMBEDDING_PROVIDER="openai"
$env:EMBEDDING_MODEL="text-embedding-3-small"
streamlit run app\streamlit_app.pypip install sentence-transformers
$env:EMBEDDING_PROVIDER="sentence-transformers"
$env:EMBEDDING_MODEL="BAAI/bge-m3"
streamlit run app\streamlit_app.py- Upload 3-5 tài liệu của một môn học.
- Hỏi câu có trong tài liệu để kiểm tra citation.
- Hỏi câu ngoài tài liệu để kiểm tra cơ chế từ chối.
- Chụp màn hình tab Chat và tab Tài liệu cho báo cáo.