Mọi chuỗi kỹ năng trong CV và JD đều được quy về một mã skill_id trước khi so khớp. Nhờ đó khoảng trống (gap) so với JD nối thẳng được sang học phần của lõi học thích ứng, không cần bước dịch nào.
Bảng skills + skill_aliases thu nhỏ (bản thật import từ ESCO nhánh ICT). Thêm alias tại chỗ để thấy hàng đợi unmapped ở mục 2 giảm.
Bản thật: PyMuPDF bóc chữ → Sonnet 5 trả JSON → map 3 tầng (tên/alias → cosine bge-m3 ≥ 0,85 → unmapped). Demo: tầng 3 mô phỏng bằng độ giống chuỗi Jaro–Winkler trên tên và alias.
Bộ quy tắc R0–R10 tất định. Bản thật cộng thêm score_llm (rubric 4 mục): score_final = 0,5·score_rule + 0,5·score_llm. Demo chỉ có phần rule.
① crawler theo lịch · ② agent tìm web theo yêu cầu · ③ Recruiter nhập. Cùng một pipeline: parse → extract → map skill → embed → dedupe. Trùng khi content_hash bằng nhau, hoặc cùng công ty/career trong 30 ngày, cosine ≥ 0,95 và title trigram ≥ 0,8.
Recruiter chọn JD, hệ thống xếp hạng: recruiter_score = match + 0,1·(mock/10), tie-break theo lần hoạt động gần nhất. Cùng công thức match ở mục 5.
Mỗi skill có cᵢ = 0 trong lần so khớp ở mục 5 được tra sang học phần chứa skill đó. Bỏ qua nếu học phần đã có trong roadmap hoặc đang có đề xuất pending (UNIQUE partial index).