Files
duocthu/docs/rag-chat.md
T
VuQuangBao 454edfa492 Document the 2 known RAG gaps instead of leaving them unwritten
Weight-based dosing and multi-drug comparison were measured live and
recorded as fixtures (known_gaps.jsonl) but never showed up in the
canonical docs describing chat capabilities.
2026-08-25 17:31:16 +07:00

4.4 KiB

Pipeline RAG và chat

Loại chính: Explanation
Đối tượng: backend/RAG engineer

Một lượt hỏi diễn ra thế nào

  1. Browser gửi message tới Next.js BFF /api/chat.
  2. BFF tạo/chuyển correlation ID và gọi POST /v1/rag/query.
  3. Query understanding xác định scope, intent, drug candidates, thuộc tính, route và dữ kiện lâm sàng còn thiếu.
  4. Deterministic guard chặn câu ngoài phạm vi hoặc yêu cầu làm rõ trước retrieval.
  5. Router chọn đường drug + section, overview similarity hoặc condition → drug.
  6. Retrieval lấy chunks, hydrate context và tạo evidence có provenance.
  7. Evidence policy quyết định đủ bằng chứng, cần xem PDF hay phải abstain.
  8. Generator tạo claims có source IDs khi generation được bật.
  9. Validator kiểm tra citation, con số, semantic support và completeness; có repair có giới hạn, sau đó fail closed nếu vẫn sai.
  10. Backend ghi trace/hội thoại, trả decision/reason/answer/citations; BFF map sang DTO UI.

Retrieval routes

Khi drug và section đã rõ, filter payload theo drug_id + section_key được ưu tiên để tránh chunk gần nghĩa của thuốc khác. Similarity search dùng cho overview hoặc khi section chưa rõ. Rerank mặc định tắt và chỉ áp dụng trên đường similarity/overview, không áp dụng route section chính xác.

Câu hỏi condition → drug thử keyword trước, chỉ fallback dense khi không có candidate keyword. Candidate phải tiếp tục được kiểm tra indication và safety; retrieval match không được biến thành khuyến cáo điều trị.

Decision

Decision Ý nghĩa
answerable có answer đã vượt qua các cổng kiểm tra
clarify thiếu dữ kiện; có thể kèm quick replies
verify_pdf đã có evidence nhưng nguồn bảng/công thức cần đối chiếu PDF
abstain không phát hành nội dung chuyên môn cho lượt này

Conversation state

Conversation turns được lưu PostgreSQL theo conversation_id và dùng lại trong multi-turn. Store hoạt động fail-open để lỗi history không làm sập toàn bộ query. Một phần state chống clarify loop nằm trong process; đây chưa phải state phân tán bền vững giữa nhiều replica. Circuit breaker dừng chuỗi clarify không hội tụ.

Lịch sử truy vấn & duyệt chuyên luận

conversation_id là session id sinh phía client và giữ trong localStorage của apps/web (không phải server session — hệ thống chưa có auth). GET /v1/rag/history liệt kê lại các truy vấn cũ của đúng session đó cho Sidebar, để bấm lại một câu hỏi cũ; answer prose không được lưu nên đây là re-run, không phải replay.

response_mode: "monograph" là lối đi song song với hỏi-đáp AI: bỏ qua generation/grounding, cho người dùng tự chọn section rồi đọc verbatim qua GET /v1/rag/sections + /section-text. Hữu ích khi cần đối chiếu nguyên văn thay vì câu trả lời tổng hợp.

Output cho UI

Response mang business trace_id, correlation_id, otel_trace_id, decision, reason, answer, resolved drug, citations, blocks, answer plan, candidate assessments, quick replies và disclaimer cố định. Citation giữ chunk, printed page, physical page, source crop/attachment và thông tin drug/section/source document.

Giới hạn đã biết

Hai năng lực dưới đây chưa có code path, đo trực tiếp qua live query (không suy đoán) và ghi lại làm fixture tại apps/ai-service/evals/known_gaps.jsonl để tái kiểm chứng thay vì chỉ dựa trên tuyên bố:

  • Tính liều theo cân nặng. rag/calculators.py::body_surface_area_m2() tồn tại nhưng không được agent.py gọi trên đường xử lý thật — hỏi liều theo cân nặng vẫn quay lại hỏi tuổi thay vì tính ra số.
  • So sánh nhiều thuốc. Không có turn_type hay đường xử lý riêng cho so sánh thuộc tính giữa 2+ thuốc; đường 2-thuốc duy nhất hiện có (agent.py::_interaction) chỉ xử lý tương tác thuốc-thuốc, không tổng quát hoá được. Hệ thống trả lời trung thực "chưa đủ cơ sở" thay vì bịa bảng so sánh.