Add read-only production runtime audit

This commit is contained in:
2026-08-17 11:17:40 +07:00
parent 057d4ed9dc
commit a1de4715a4
106 changed files with 6869 additions and 1782 deletions
+101
View File
@@ -0,0 +1,101 @@
# HTTP API và decision reference
> Loại chính: Reference
> Backend local thường dùng: `http://localhost:8079`
## System endpoints
| Method | Path | Mục đích |
|---|---|---|
| GET | `/health` | process health |
| GET | `/ready` | runtime readiness |
| GET | `/metrics` | Prometheus metrics; có thể yêu cầu Bearer token |
## `POST /v1/rag/query`
Request:
| Field | Kiểu | Ràng buộc |
|---|---|---|
| `query` | string | bắt buộc, 14000 ký tự |
| `subject_scope` | enum | `human`, `non_human`, `unknown` |
| `intent` | enum | `fact_lookup`, `recommendation`, `unknown` |
| `conversation_id` | string/null | tối đa 128 ký tự |
| `response_mode` | enum | `ai` (mặc định, trả lời tổng hợp có generation) hoặc `monograph` (duyệt chuyên luận thô, xem `GET /v1/rag/sections` + `/section-text`) |
Response:
| Field | Ý nghĩa |
|---|---|
| `trace_id`, `correlation_id`, `otel_trace_id` | các định danh quan sát |
| `decision`, `reason` | kết quả policy và mã nguyên nhân |
| `answer`, `resolved_drug_id` | nội dung và thuốc đã resolve |
| `citations` | provenance evidence |
| `generated` | có dùng generator hay không |
| `quick_replies`, `blocks` | cấu trúc UI/claim |
| `answer_mode`, `answer_plan` | metadata trình bày |
| `candidate_assessments` | đánh giá candidate |
| `disclaimer` | cảnh báo cố định từ backend |
Citation có `chunk_id`, printed-page range, `physical_page`, `block_id`, `bbox`,
`source_crop`, `attachment`, `evidence_text`, drug, section và source document.
## `GET /v1/rag/history`
Feature-List #25. `conversation_id` bắt buộc (tối đa 128 ký tự) — không có auth
trong hệ thống nên endpoint chỉ trả về đúng conversation được truyền vào,
không có nghĩa "list toàn bộ"; rỗng/không truyền → trả `items: []`. Tối đa 50
dòng, mới nhất trước. Mỗi dòng là một truy vấn cũ (`trace_id`, `query`,
`decision`, `reason`, `resolved_drug_id`, `created_at`) để UI cho người dùng
bấm lại — **không** replay lại answer prose, vì answer không được lưu, chỉ
lưu trace.
## `GET /v1/rag/sections?drug_id=...`
Feature-List #4. Danh sách section thật có của một thuốc (không phải danh sách
cố định — đo trên corpus dao động 719 section/thuốc), mỗi phần tử có
`section_key` + `section_title`. Không LLM, đọc thẳng payload đã index;
`drug_id` không resolve được trả `sections: []`, không phải 404.
## `GET /v1/rag/section-text?drug_id=...&section_key=...`
Feature-List #23. Text verbatim của một section, dùng cho `response_mode:
"monograph"` — không generation/entailment nên không cần validate. Trả
`parts[]` theo đúng thứ tự sách gốc; mỗi phần có `is_quarantined``true`
nghĩa là phần đó là bảng/công thức bị quarantine, `text` khi đó là câu mô tả
của chunker ("bảng, trang N...") chứ không phải nội dung bảng, và UI không
được hiển thị như một trích dẫn verbatim thật.
## Endpoint khác
- `GET /v1/rag/suggest?q=...`: trả `suggestions` autocomplete.
- `POST /v1/rag/feedback`: nhận UUID `trace_id`, rating `helpful` hoặc
`not_helpful`, comment tối đa 2000 ký tự và `conversation_id` tối đa 128 ký tự.
Browser gọi BFF `/api/chat`. BFF dùng `API_GATEWAY_URL`, fallback `AI_SERVICE_URL`,
sau đó `http://localhost:8000`, và map snake_case backend sang shared TypeScript DTO.
## Decision và reason
| Decision | Hành vi |
|---|---|
| `answerable` | hiển thị answer đã kiểm chứng |
| `clarify` | hỏi thêm thông tin, dùng quick replies nếu có |
| `verify_pdf` | hiển thị nguồn và yêu cầu đối chiếu PDF |
| `abstain` | không phát hành answer chuyên môn |
| Nhóm reason | Ví dụ |
|---|---|
| resolve/input | `drug_not_resolved`, `drug_resolution_ambiguous`, `missing_query_or_drug`, `missing_indication` |
| scope/intent | `recommendation_out_of_scope`, `out_of_scope_non_human`, `subject_scope_unknown`, `query_intent_unknown`, `out_of_scope` |
| clarify | `no_drug`, `missing_attribute`, `missing_population`, `missing_pediatric_age_or_weight`, `needs_more_info`, `ambiguous_condition` |
| retrieval | `query_embedding_unavailable`, `insufficient_retrieval_score`, `no_indication_match`, `no_interaction_evidence`, `parent_hydration_failed` |
| provenance | `missing_provenance`, `missing_printed_page_provenance` |
| provider/budget | `provider_unavailable`, `understanding_provider_unavailable`, `request_budget_exhausted`, `malformed_output` |
| grounding | `evidence_insufficient`, `ungrounded_number`, `invalid_citation`, `uncited_claim`, `unsupported_claim`, `unsupported_drug`, `incomplete_answer` |
| circuit/relation | `clarify_loop_exhausted`, `unsupported_reverse_relation` |
| fallback | `generation_unavailable` |
Reason code là contract giữa backend, BFF và metric. Không collapse provider hoặc
grounding error thành “không có dữ liệu”.