Phase 7: Hoàn thiện Modular RAG Backend với FastAPI và Đa LLM Provider
This commit is contained in:
88
doc/00.AGENT_ARCHITECTURE_MAP.md
Normal file
88
doc/00.AGENT_ARCHITECTURE_MAP.md
Normal file
@@ -0,0 +1,88 @@
|
||||
# 🧭 AGENT ARCHITECTURE MAP (LIVING DOCUMENT)
|
||||
*Đây là tài liệu dẫn đường dành riêng cho các AI Agent tương lai và lập trình viên bảo trì. Không quét toàn bộ code, hãy đọc file này trước.*
|
||||
|
||||
**Lần cập nhật cuối:** Phase 6 (Hoàn thiện Semantic Chunking & Vector Indexing)
|
||||
**Trạng thái Dự án:** Đã hoàn thành Ingestion, Extraction, Chunking & Indexing. Chuẩn bị bước vào Phase 7 (RAG Search & Chat API).
|
||||
|
||||
---
|
||||
|
||||
## 1. Bản Đồ Kiến Trúc Lõi (Core Architecture Patterns)
|
||||
|
||||
### A. Tầng Ingestion (Thu thập dữ liệu) - Mẫu Modular Provider Pattern
|
||||
- **Mục tiêu:** Tách biệt lõi hệ thống khỏi nền tảng lưu trữ (SharePoint, Google Drive, v.v.).
|
||||
- **Interface gốc:** `ingestion/providers/base_provider.py` (Bắt buộc phải implement `fetch_changes` và `download_file`).
|
||||
- **Implement hiện tại:** `ingestion/providers/sharepoint_provider.py`. Nó bọc lại `GraphClient` và tự động xử lý thuật toán phân trang (pagination) để lấy dữ liệu Delta.
|
||||
- **Nếu cần thêm nguồn dữ liệu mới (ví dụ: NAS, Google Drive):** Chỉ cần tạo một class mới kế thừa `BaseStorageProvider`. Lõi hệ thống không cần biết về API của nguồn đó.
|
||||
|
||||
### B. Tầng Extraction (Xử lý chữ & Ảnh) - Mẫu Distributed VLM Pattern
|
||||
- **Lịch sử:** Đã từng dùng PaddleOCR + VietOCR nhưng gặp lỗi "Rụng dấu" và "Ảo giác" do cắt ảnh sai.
|
||||
- **Kiến trúc hiện tại:** Hệ thống đóng vai trò như một **VLM Client**.
|
||||
- **Cách hoạt động:** `extraction/ocr_service.py` render file PDF thành ảnh (DPI=86), nén Base64 và bắn POST Request sang một Server LLM khác trong mạng LAN (chạy `llama.cpp` với model `Vintern-3B`).
|
||||
- **Lợi ích:** Giải phóng hoàn toàn RAM cho máy chủ RAG, loại bỏ các thư viện AI nặng nền (Torch, Paddle). Lấy được Markdown nguyên bản, không gãy vỡ layout bảng biểu.
|
||||
|
||||
### C. Tầng Chunking & Vector DB (Semantic Indexing)
|
||||
- **Chunking:** `chunking/markdown_chunker.py` chia nhỏ văn bản bằng Markdown Rules (nhận biết Header `#`, duy trì overlap chống đứt gãy ngữ cảnh), tự động theo dõi `page_from`, `page_to` chuẩn xác.
|
||||
- **Embedding:** Dùng thư viện `sentence-transformers` với model `keepitreal/vietnamese-sbert` chạy Local/Offline. Tạo ra Vector 768 chiều chuyên biệt cho Tiếng Việt.
|
||||
- **Database:** `indexing/vector_store.py` cấu hình OpenSearch với thuật toán `k-NN HNSW`. Index mặc định là `poc_sharepoint_docs` hoặc `sharepoint_docs`.
|
||||
|
||||
### D. Tầng Cấu hình (Decoupled Configuration)
|
||||
- Toàn bộ thông số hệ thống, đặc biệt là IP máy chủ VLM, Token của SharePoint đều nằm trong `.env`.
|
||||
- Mã nguồn load cấu hình thông qua `core/config.py`.
|
||||
- **Tuyệt đối KHÔNG hardcode URL, Token hay Password trong code.**
|
||||
|
||||
---
|
||||
|
||||
## 2. Bản Đồ File & Thư Mục Quan Trọng
|
||||
|
||||
```text
|
||||
📁 poc_system/
|
||||
├── 📁 core/
|
||||
│ ├── config.py # ⚙️ Trái tim cấu hình (Load từ .env)
|
||||
│ └── models.py # 🧩 Định nghĩa Data Classes (OCRPageResult, v.v.)
|
||||
├── 📁 ingestion/
|
||||
│ ├── sync.py # 🔄 Bộ điều phối đồng bộ (Đang chuẩn bị ghép với BaseStorageProvider)
|
||||
│ ├── graph_client.py # 🌐 Microsoft Graph API Client (Bọc Auth)
|
||||
│ └── 📁 providers/ # 🔌 Nơi chứa các plugin kết nối dữ liệu
|
||||
│ ├── base_provider.py
|
||||
│ └── sharepoint_provider.py
|
||||
├── 📁 extraction/
|
||||
│ └── ocr_service.py # 👁️ VLM Client (Chuyển ảnh -> Text Markdown qua LAN)
|
||||
├── .env # 🔑 Chìa khoá và địa chỉ mạng (KHÔNG commit file này)
|
||||
└── test_modular_architecture.py # 🧪 Script kiểm tra nhanh kết nối các module
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. Lịch Sử Các Lỗi Khét Tiếng & Cách Xử Lý (Known Gotchas)
|
||||
1. **Lỗi 401 Unauthorized khi tải file từ SharePoint:**
|
||||
- *Nguyên nhân:* Microsoft chặn download trực tiếp bằng `@microsoft.graph.downloadUrl` nếu dùng App-Only Token.
|
||||
- *Giải pháp:* Dùng endpoint `.../items/{item_id}/content` kèm Bearer Token (Đã cài đặt trong `graph_client.py`).
|
||||
|
||||
2. **Lỗi 500 Internal Server Error từ Llama.cpp VLM:**
|
||||
- *Nguyên nhân:* Bức ảnh ném vào VLM có độ phân giải quá cao (Matrix 2.0) làm tràn Context Window (ví dụ: Token ảnh > 4096).
|
||||
- *Giải pháp:* Hạ `Matrix` xuống `1.2`, hoặc khởi chạy Server Llama.cpp với `-c 8192`. Bắt buộc phải có file `--mmproj`.
|
||||
|
||||
3. **Lỗi Rụng dấu / Ảo giác của VietOCR:**
|
||||
- *Nguyên nhân:* PaddleOCR bắt khung quá khít, làm cụt phần đuôi của các chữ tiếng Việt có dấu. Mô hình `vgg_seq2seq` tự nội suy ra từ tiếng Anh linh tinh.
|
||||
- *Giải pháp triệt để:* Đã loại bỏ hoàn toàn VietOCR, chuyển sang dùng VLM (Vintern-3B).
|
||||
|
||||
4. **Lỗi UTF-8 Surrogate (\udcc3) trong Terminal WSL:**
|
||||
- *Hiện tượng:* Câu hỏi đầu tiên đúng, nhưng từ câu thứ 2 bị lỗi mã hóa khi dùng `input()`.
|
||||
- *Nguyên nhân:* Do sự không đồng nhất giữa `sys.stdin` và bộ đệm Terminal sau khi in lượng lớn dữ liệu từ LLM.
|
||||
- *Giải pháp:* Sử dụng `sys.stdin.buffer.readline()` để đọc dữ liệu thô (Bytes) và tự decode bằng UTF-8. Đây là giải pháp cho môi trường CLI, khi lên Web API (FastAPI) sẽ không bị ảnh hưởng.
|
||||
|
||||
---
|
||||
|
||||
## 4. Nhiệm Vụ Tiếp Theo (Dành cho Lập Trình Viên/AI Agent)
|
||||
- [ ] **Phase 7:** Bọc thành API Backend bằng FastAPI.
|
||||
|
||||
---
|
||||
|
||||
## 5. Tiêu chuẩn Lập trình & Môi trường (Coding Standards)
|
||||
|
||||
### A. Quản lý Mã hóa (Encoding)
|
||||
- **Quy tắc vàng:** Luôn sử dụng `encoding='utf-8'` trong mọi lệnh `open()`. Tuyệt đối không dựa dẫm vào encoding mặc định của hệ điều hành.
|
||||
- **Môi trường:** Hệ thống được thiết kế để chạy trong môi trường UTF-8. Trong Docker hoặc WSL, luôn đảm bảo biến môi trường `PYTHONIOENCODING=utf-8` được thiết lập. Điều này giúp hệ thống tương thích 100% với các ký tự Tiếng Việt từ LLM mà không cần hack code.
|
||||
|
||||
### B. Mẫu Provider (Provider Pattern)
|
||||
- Mọi kết nối tới dịch vụ bên thứ ba (Storage, LLM) phải thông qua Interface/BaseClass để đảm bảo tính "Cắm rút" (Pluggable).
|
||||
243
doc/1.phan-tich-kien-truc-tra-cuu-sharepoint.md
Normal file
243
doc/1.phan-tich-kien-truc-tra-cuu-sharepoint.md
Normal file
@@ -0,0 +1,243 @@
|
||||
# Kiến trúc và định hướng xây dựng hệ thống tra cứu tài liệu scan SharePoint
|
||||
|
||||
## 1. Mục tiêu tổng thể
|
||||
Hệ thống nhằm giải quyết ba vấn đề cốt lõi trong doanh nghiệp:
|
||||
1. **Biến kho tài liệu scan trên SharePoint thành dữ liệu có thể tìm kiếm theo ngữ nghĩa**.
|
||||
2. **Tìm nhanh → đúng tài liệu → đúng vị trí trong tài liệu**.
|
||||
3. **Giữ nguyên tính kiểm soát, phân quyền và tuân thủ (compliance)** của Microsoft 365.
|
||||
|
||||
Hệ thống không thay thế SharePoint, mà **tăng cường khả năng tra cứu và hiểu nội dung**.
|
||||
|
||||
---
|
||||
|
||||
## 2. Nguyên tắc thiết kế
|
||||
|
||||
### 2.1. Không lock-in
|
||||
- Ưu tiên **Open Source** cho lõi xử lý.
|
||||
- Có thể thay OCR / embedding / LLM trong tương lai.
|
||||
|
||||
### 2.2. File gốc là "nguồn chân lý"
|
||||
- File **luôn ở SharePoint**.
|
||||
- Hệ thống chỉ lưu **nội dung trích xuất + metadata + index**.
|
||||
|
||||
### 2.3. Permission-aware từ đầu
|
||||
- Không index kiểu "public rồi filter sau".
|
||||
- Mỗi kết quả search phải map được tới **ACL tương ứng trên SharePoint**.
|
||||
|
||||
---
|
||||
|
||||
## 3. Kiến trúc tổng thể (Logical Architecture)
|
||||
|
||||
```
|
||||
SharePoint (Files, PDFs scan)
|
||||
│
|
||||
▼
|
||||
Ingestion & Sync Layer (tự viết – vibecode)
|
||||
│
|
||||
├── Fetch file
|
||||
├── Fetch metadata & permissions
|
||||
└── Versioning
|
||||
▼
|
||||
Extraction Layer
|
||||
│
|
||||
├── OCR (scan PDF)
|
||||
└── MarkItDown (→ Markdown)
|
||||
▼
|
||||
Normalization & Enrichment
|
||||
│
|
||||
├── Chunking
|
||||
├── Metadata mapping
|
||||
└── Page / section anchoring
|
||||
▼
|
||||
Index Layer (OpenSearch)
|
||||
│
|
||||
├── Full-text index
|
||||
├── Vector index
|
||||
└── Metadata filter
|
||||
▼
|
||||
Search / Chat UI
|
||||
└── Click → mở đúng file SharePoint
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. Thành phần chi tiết và trách nhiệm
|
||||
|
||||
### 4.1. Ingestion Layer (then chốt nhất)
|
||||
|
||||
**Nhiệm vụ**:
|
||||
- Kết nối SharePoint bằng Microsoft Graph API.
|
||||
- Theo dõi thay đổi file (delta query / webhook).
|
||||
- Tải file + metadata.
|
||||
|
||||
**Metadata bắt buộc**:
|
||||
- site_id
|
||||
- drive_id / library
|
||||
- file_id
|
||||
- file_name
|
||||
- file_url (mở trực tiếp trên SharePoint)
|
||||
- created_by, modified_by
|
||||
- created_at, modified_at
|
||||
- permission_groups / users
|
||||
|
||||
> Lưu ý: permission cần map thành dạng filter-friendly (list group/user IDs).
|
||||
|
||||
---
|
||||
|
||||
### 4.2. Extraction Layer
|
||||
|
||||
#### OCR
|
||||
- Scan PDF thường là image → cần OCR.
|
||||
- Định hướng:
|
||||
- Tesseract / PaddleOCR cho local.
|
||||
- Có thể thay bằng model mới sau.
|
||||
|
||||
#### MarkItDown
|
||||
- Chuyển output OCR → Markdown sạch.
|
||||
- Ưu điểm:
|
||||
- Giữ cấu trúc
|
||||
- Thuận lợi cho chunk & embedding
|
||||
|
||||
Output cần lưu:
|
||||
```json
|
||||
{
|
||||
"file_id": "...",
|
||||
"page": 12,
|
||||
"content_md": "## Điều 3...",
|
||||
"bbox_hint": "page=12"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 4.3. Normalization & Chunking
|
||||
|
||||
**Mục tiêu**: mỗi đơn vị index phải vừa đủ nhỏ để search chính xác, vừa đủ lớn để có ngữ cảnh.
|
||||
|
||||
Chiến lược chunk:
|
||||
- Ưu tiên theo:
|
||||
1. Heading (##, ###)
|
||||
2. Trang (page)
|
||||
3. Đoạn văn
|
||||
|
||||
Mỗi chunk gồm:
|
||||
- chunk_id
|
||||
- text
|
||||
- file_id
|
||||
- page_from / page_to
|
||||
- sharepoint_url_with_anchor
|
||||
|
||||
---
|
||||
|
||||
### 4.4. Index Layer (OpenSearch)
|
||||
|
||||
**Hai loại index song song**:
|
||||
|
||||
1. **Full-text index**
|
||||
- Phục vụ search truyền thống
|
||||
- Có highlight
|
||||
|
||||
2. **Vector index**
|
||||
- Phục vụ semantic search
|
||||
- Dùng embedding OSS (bge, e5, etc.)
|
||||
|
||||
**Schema gợi ý**:
|
||||
|
||||
```json
|
||||
{
|
||||
"chunk_id": "...",
|
||||
"text": "...",
|
||||
"embedding": [ ... ],
|
||||
"file_id": "...",
|
||||
"file_name": "...",
|
||||
"sharepoint_url": "...",
|
||||
"page_from": 10,
|
||||
"page_to": 11,
|
||||
"site_id": "...",
|
||||
"permissions": ["groupA", "userB"],
|
||||
"updated_at": "..."
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. Search & UX định hướng
|
||||
|
||||
### 5.1. Search mode
|
||||
- Keyword search
|
||||
- Semantic search
|
||||
- Hybrid (khuyên dùng)
|
||||
|
||||
### 5.2. Kết quả search bắt buộc có
|
||||
- Trích đoạn nội dung
|
||||
- Tên file
|
||||
- Thư mục / site
|
||||
- Trang (page)
|
||||
- Link mở đúng file
|
||||
|
||||
### 5.3. UX nguyên tắc
|
||||
- Tìm ≤ 3s
|
||||
- Click ≤ 1 lần để mở file
|
||||
- Người dùng **không cần biết file nằm ở đâu**
|
||||
|
||||
---
|
||||
|
||||
## 6. Vibecode: nên tập trung viết gì?
|
||||
|
||||
✅ NÊN tự viết:
|
||||
- SharePoint ingestion & sync
|
||||
- Permission mapping
|
||||
- Metadata chuẩn hóa
|
||||
- UI search phù hợp nghiệp vụ
|
||||
|
||||
❌ KHÔNG nên tự viết:
|
||||
- OCR engine
|
||||
- Search engine
|
||||
- Vector index
|
||||
|
||||
---
|
||||
|
||||
## 7. Lộ trình triển khai thực tế
|
||||
|
||||
### Phase 1 – PoC (2–4 tuần)
|
||||
- Lấy 1 site SharePoint
|
||||
- OCR + MarkItDown
|
||||
- Full-text search
|
||||
|
||||
### Phase 2 – Semantic search
|
||||
- Chunking
|
||||
- Embedding
|
||||
- Vector search
|
||||
|
||||
### Phase 3 – Permission & scale
|
||||
- ACL filtering
|
||||
- Delta sync
|
||||
- Monitoring
|
||||
|
||||
---
|
||||
|
||||
## 8. Tương tác AI agent trong tương lai
|
||||
|
||||
Hệ thống này có thể:
|
||||
- Gắn Chat UI (RAG)
|
||||
- Tóm tắt tài liệu
|
||||
- So sánh nhiều file
|
||||
- Trả lời câu hỏi trích dẫn rõ nguồn
|
||||
|
||||
---
|
||||
|
||||
## 9. Kết luận
|
||||
|
||||
Bài toán của bạn **không mới nhưng rất ít hệ thống làm đúng**.
|
||||
|
||||
Việc kết hợp:
|
||||
- SharePoint (nguồn tin cậy)
|
||||
- MarkItDown (chuẩn hóa nội dung)
|
||||
- OpenSearch (index & search)
|
||||
- Vibecode (điều phối thông minh)
|
||||
|
||||
là **hướng kiến trúc bền vững, mở rộng được nhiều năm**.
|
||||
|
||||
---
|
||||
|
||||
*Tài liệu này được thiết kế để AI agent hoặc dev khác có thể đọc và triển khai tiếp mà không cần giải thích lại.*
|
||||
@@ -0,0 +1,220 @@
|
||||
# 10.Appendix-Document-Type-Classification-and-Processing-Strategy.md
|
||||
|
||||
> **Phụ lục chiến lược phân loại & xử lý tài liệu** cho toàn bộ hệ thống SharePoint → Search → RAG.
|
||||
>
|
||||
> ⚠️ **Nguyên tắc sử dụng**
|
||||
> - Đây là **phụ lục độc lập**, không chỉnh sửa các file 1–9.
|
||||
> - Được coi là **luật xử lý file của hệ thống**.
|
||||
> - Mọi pipeline hiện tại và mở rộng trong tương lai **PHẢI tuân theo phụ lục này**.
|
||||
> - Mục tiêu: an toàn, mở rộng được, không xử lý sai loại tài liệu.
|
||||
|
||||
---
|
||||
|
||||
## 1. Mục tiêu của phụ lục
|
||||
|
||||
Phụ lục này nhằm:
|
||||
|
||||
- Chuẩn hoá **cách hệ thống hiểu và xử lý từng loại file**
|
||||
- Ngăn việc:
|
||||
- OCR / MarkItDown bừa bãi
|
||||
- Đưa bản vẽ kỹ thuật vào RAG
|
||||
- Xử lý sai Excel/dữ liệu bảng
|
||||
- Tạo **luồng ngoại lệ có kiểm soát** cho file mới hoặc hiếm gặp
|
||||
|
||||
---
|
||||
|
||||
## 2. Nguyên tắc cốt lõi (BẮT BUỘC)
|
||||
|
||||
1. **Không có "one-size-fits-all" cho tài liệu**
|
||||
2. **Phân loại file xảy ra TRƯỚC OCR và MarkItDown**
|
||||
3. **Extension là rule đầu, KHÔNG phải rule cuối**
|
||||
4. **Tài liệu không có giá trị ngôn ngữ → không RAG**
|
||||
5. **File lạ vẫn được ingest, nhưng xử lý an toàn**
|
||||
|
||||
---
|
||||
|
||||
## 3. Document Classification Engine (DCE)
|
||||
|
||||
### 3.1 Vai trò
|
||||
|
||||
DCE chịu trách nhiệm quyết định **file đi vào pipeline nào**.
|
||||
|
||||
Nếu chưa quyết định được → file **KHÔNG được xử lý sâu hơn**.
|
||||
|
||||
---
|
||||
|
||||
### 3.2 Input của DCE
|
||||
|
||||
- Extension (vd: `.pdf`, `.dwg`, `.xlsx`)
|
||||
- MIME type
|
||||
- File size
|
||||
- Header bytes (chống giả extension)
|
||||
- Với PDF:
|
||||
- Có text layer hay không
|
||||
- Pattern nhanh (drawing vs text)
|
||||
|
||||
---
|
||||
|
||||
### 3.3 Output của DCE (bắt buộc)
|
||||
|
||||
```json
|
||||
{
|
||||
"doc_type": "textual_document | technical_drawing | structured_data | binary_unsupported",
|
||||
"processing_policy": "text_pipeline | metadata_only | table_pipeline | skip",
|
||||
"confidence": 0.95,
|
||||
"reason": "PDF detected as engineering drawing based on layout"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. Các nhóm tài liệu và chiến lược xử lý
|
||||
|
||||
## 4.1 Nhóm A – Textual Documents (Tài liệu ngôn ngữ)
|
||||
|
||||
### Ví dụ
|
||||
- PDF văn bản (scan hoặc text)
|
||||
- DOCX, PPTX
|
||||
- PDF quy định, hợp đồng
|
||||
|
||||
### Xử lý
|
||||
- ✅ OCR (nếu scan)
|
||||
- ✅ MarkItDown
|
||||
- ✅ Chunking
|
||||
- ✅ Search
|
||||
- ✅ RAG Chat
|
||||
|
||||
### Ghi chú
|
||||
- Đây là **nguồn chính cho RAG**
|
||||
|
||||
---
|
||||
|
||||
## 4.2 Nhóm B – Technical Drawings (Bản vẽ kỹ thuật)
|
||||
|
||||
### Ví dụ
|
||||
- PDF bản vẽ kỹ thuật
|
||||
- DWG / DXF / IFC
|
||||
|
||||
### Xử lý
|
||||
- ✅ Metadata indexing
|
||||
- ✅ Thumbnail / preview (nếu có)
|
||||
- ✅ OCR giới hạn title block (tuỳ chọn)
|
||||
|
||||
### KHÔNG làm
|
||||
- ❌ OCR toàn bộ
|
||||
- ❌ MarkItDown
|
||||
- ❌ RAG
|
||||
|
||||
### Lý do
|
||||
- Nội dung chính là hình học, không phải ngôn ngữ
|
||||
- RAG sẽ dễ hallucinate và gây rủi ro nghiệp vụ
|
||||
|
||||
---
|
||||
|
||||
## 4.3 Nhóm C – Structured Data Documents (Dữ liệu bảng)
|
||||
|
||||
### Ví dụ
|
||||
- Excel (XLSX)
|
||||
- CSV
|
||||
|
||||
### Sub-case 1: Excel có mô tả nghiệp vụ
|
||||
|
||||
- ✅ Trích xuất giới hạn
|
||||
- ✅ Convert sang Markdown có kiểm soát
|
||||
- ✅ Search
|
||||
- ⚠️ RAG chỉ áp dụng phần text
|
||||
|
||||
### Sub-case 2: Excel số liệu / danh sách lớn
|
||||
|
||||
- ✅ Extract header + key columns
|
||||
- ✅ Index theo field
|
||||
- ❌ MarkItDown toàn file
|
||||
- ❌ OCR
|
||||
- ❌ RAG ngôn ngữ tự do
|
||||
|
||||
---
|
||||
|
||||
## 4.4 Nhóm D – Binary / Unsupported Documents
|
||||
|
||||
### Ví dụ
|
||||
- `.acad`, `.psd`, `.step`, `.zip`
|
||||
|
||||
### Xử lý
|
||||
- ✅ Metadata-only ingestion
|
||||
- ✅ Search theo tên / project
|
||||
- ❌ Không OCR
|
||||
- ❌ Không convert
|
||||
- ❌ Không RAG
|
||||
|
||||
---
|
||||
|
||||
## 5. Luồng xử lý ngoại lệ (Exception Flow)
|
||||
|
||||
### 5.1 Khi nào kích hoạt
|
||||
|
||||
- Extension chưa có rule
|
||||
- MIME / header không khớp extension
|
||||
- File có pattern bất thường
|
||||
|
||||
---
|
||||
|
||||
### 5.2 Luồng chi tiết
|
||||
|
||||
```text
|
||||
File mới
|
||||
↓
|
||||
Basic metadata ingest
|
||||
↓
|
||||
DCE classify = UNKNOWN
|
||||
↓
|
||||
Flag: Pending Classification
|
||||
↓
|
||||
Rule-based auto guess (nếu có)
|
||||
↓
|
||||
Manual admin review (hiếm)
|
||||
↓
|
||||
Update classification rule
|
||||
↓
|
||||
Optionally re-process file
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 5.3 Nguyên tắc an toàn
|
||||
|
||||
- ❌ Không OCR file chưa rõ loại
|
||||
- ❌ Không cho RAG đọc file pending
|
||||
- ✅ Vẫn search được theo metadata
|
||||
|
||||
---
|
||||
|
||||
## 6. Tác động tới Search & RAG
|
||||
|
||||
- Search
|
||||
- Phải tôn trọng `processing_policy`
|
||||
- RAG
|
||||
- Chỉ dùng `textual_document`
|
||||
- Skip toàn bộ nhóm B, C(subcase 2), D
|
||||
|
||||
---
|
||||
|
||||
## 7. Lợi ích dài hạn của chiến lược này
|
||||
|
||||
- ✅ Không phá pipeline khi có file mới
|
||||
- ✅ An toàn AI (no hallucination)
|
||||
- ✅ Tối ưu chi phí OCR
|
||||
- ✅ Mở rộng không cần sửa core
|
||||
- ✅ Dễ audit
|
||||
|
||||
---
|
||||
|
||||
## 8. Kết luận phụ lục
|
||||
|
||||
- Phân loại tài liệu là **điểm quyết định sống còn** của hệ thống
|
||||
- Extension là **điểm bắt đầu**, không phải kết luận
|
||||
- OCR và MarkItDown **là công cụ, không phải mục tiêu**
|
||||
- RAG chỉ dùng khi **có giá trị ngôn ngữ thật**
|
||||
|
||||
---
|
||||
|
||||
*Phụ lục này là tài liệu tham chiếu nền tảng khi mở rộng hoặc audit toàn hệ thống.*
|
||||
193
doc/11.Appendix-PDF-Inspection-and-TextLayer-Detection.md
Normal file
193
doc/11.Appendix-PDF-Inspection-and-TextLayer-Detection.md
Normal file
@@ -0,0 +1,193 @@
|
||||
# 11.Appendix-PDF-Inspection-and-TextLayer-Detection.md
|
||||
|
||||
> **Phụ lục chiến lược nhận diện PDF (text-based vs scan vs drawing)**.
|
||||
>
|
||||
> ⚠️ Phụ lục này **KHÔNG chỉnh sửa** các file 1–10.
|
||||
> Mục tiêu: **chuẩn hoá cách hệ thống hiểu PDF trước khi quyết định OCR / MarkItDown**.
|
||||
>
|
||||
> Đây là phụ lục then chốt để **không xử lý OCR sai loại PDF**, đặc biệt trong môi trường có nhiều bản vẽ kỹ thuật.
|
||||
|
||||
---
|
||||
|
||||
## 1. Vì sao cần inspection PDF riêng?
|
||||
|
||||
Trong hệ thống doanh nghiệp, `.pdf` là extension **dễ gây hiểu nhầm nhất**:
|
||||
|
||||
- PDF có thể là:
|
||||
- Văn bản thuần (text layer)
|
||||
- Scan ảnh (image-only)
|
||||
- Bản vẽ kỹ thuật (vector + text rải rác)
|
||||
|
||||
⚠️ **Không được quyết định OCR chỉ dựa trên việc "là PDF"**.
|
||||
|
||||
---
|
||||
|
||||
## 2. Ba loại PDF cần phân biệt (BẮT BUỘC)
|
||||
|
||||
### 2.1 PDF loại 1 – Text-based PDF
|
||||
|
||||
**Đặc điểm**
|
||||
- Có text layer thật
|
||||
- Có thể select/copy text
|
||||
- Thường sinh ra từ Word, InDesign, LaTeX
|
||||
|
||||
**Xử lý**
|
||||
- ❌ Không OCR
|
||||
- ✅ Đưa thẳng vào MarkItDown
|
||||
|
||||
---
|
||||
|
||||
### 2.2 PDF loại 2 – Scan / Image-based PDF
|
||||
|
||||
**Đặc điểm**
|
||||
- Không có text layer
|
||||
- Toàn bộ là ảnh
|
||||
- Scan từ giấy
|
||||
|
||||
**Xử lý**
|
||||
- ✅ OCR là BẮT BUỘC
|
||||
- ✅ OCR page-wise
|
||||
- ✅ Sau OCR mới đưa vào MarkItDown
|
||||
|
||||
---
|
||||
|
||||
### 2.3 PDF loại 3 – Technical Drawing PDF
|
||||
|
||||
**Đặc điểm**
|
||||
- Nội dung chính là hình vẽ kỹ thuật
|
||||
- Text rải rác (ký hiệu, mã số)
|
||||
- Có thể có vector + text layer
|
||||
|
||||
**Xử lý**
|
||||
- ❌ Không OCR toàn bộ
|
||||
- ❌ Không MarkItDown
|
||||
- ✅ Metadata-only indexing
|
||||
- ✅ OCR giới hạn (title block) nếu cần
|
||||
|
||||
---
|
||||
|
||||
## 3. PDF Inspection Flow (Luồng quyết định)
|
||||
|
||||
```text
|
||||
PDF file
|
||||
↓
|
||||
Quick inspection
|
||||
├─ Has text layer?
|
||||
├─ Text density?
|
||||
├─ Page structure?
|
||||
↓
|
||||
Classify:
|
||||
- TEXT_PDF
|
||||
- SCAN_PDF
|
||||
- DRAWING_PDF
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. Heuristics xác định Text-based PDF
|
||||
|
||||
Một PDF được coi là **TEXT_PDF** khi:
|
||||
|
||||
- Có text layer trên >70% số trang
|
||||
- Text density đủ lớn (nhiều hơn nhãn/ký hiệu)
|
||||
- Không có layout dạng drawing
|
||||
|
||||
✅ Ví dụ tiêu biểu
|
||||
- Quy định
|
||||
- Hợp đồng
|
||||
- Hướng dẫn
|
||||
|
||||
---
|
||||
|
||||
## 5. Heuristics xác định Scan PDF
|
||||
|
||||
Một PDF được coi là **SCAN_PDF** khi:
|
||||
|
||||
- Không có text layer
|
||||
- Page rendering = image
|
||||
- OCR text length = 0 trước OCR
|
||||
|
||||
✅ Đây là target chính của OCR tiếng Việt
|
||||
|
||||
---
|
||||
|
||||
## 6. Heuristics xác định Drawing PDF (RẤT QUAN TRỌNG)
|
||||
|
||||
Một PDF bị coi là **DRAWING_PDF** khi:
|
||||
|
||||
- Text layer rất ít nhưng:
|
||||
- Có vector shapes
|
||||
- Có line dày đặc
|
||||
- Page ratio lớn (A1, A0)
|
||||
- Text xuất hiện chủ yếu ở:
|
||||
- Title block
|
||||
- Legend
|
||||
|
||||
⚠️ Thoả các dấu hiệu trên → **KHÔNG đưa vào OCR/MarkItDown dù có text layer**.
|
||||
|
||||
---
|
||||
|
||||
## 7. Vì sao Drawing PDF KHÔNG được OCR đại trà
|
||||
|
||||
- OCR sinh rất nhiều noise
|
||||
- Text không mang ý nghĩa ngôn ngữ
|
||||
- RAG dễ hallucinate nguy hiểm
|
||||
|
||||
✅ Nguyên tắc:
|
||||
> **Drawing PDF chỉ để TRA CỨU, không để ĐỌC bằng AI**.
|
||||
|
||||
---
|
||||
|
||||
## 8. Quyết định xử lý theo loại PDF
|
||||
|
||||
| PDF Type | OCR | MarkItDown | Search | RAG |
|
||||
|--------|-----|------------|--------|-----|
|
||||
| TEXT_PDF | ❌ | ✅ | ✅ | ✅ |
|
||||
| SCAN_PDF | ✅ | ✅ | ✅ | ✅ |
|
||||
| DRAWING_PDF | ❌ (limited) | ❌ | ✅ (metadata) | ❌ |
|
||||
|
||||
---
|
||||
|
||||
## 9. OCR Scope áp dụng cho PDF
|
||||
|
||||
### Chỉ OCR khi:
|
||||
- Classified = SCAN_PDF
|
||||
|
||||
### OCR giới hạn khi:
|
||||
- Classified = DRAWING_PDF
|
||||
- Mục tiêu: title, revision, project code
|
||||
|
||||
---
|
||||
|
||||
## 10. Logging & Audit bắt buộc
|
||||
|
||||
Mỗi PDF phải có log:
|
||||
|
||||
```json
|
||||
{
|
||||
"pdf_type": "SCAN_PDF",
|
||||
"decision_reason": "No text layer detected",
|
||||
"ocr_applied": true
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 11. Lợi ích kiến trúc
|
||||
|
||||
- ✅ Không OCR sai PDF
|
||||
- ✅ Không đưa bản vẽ vào RAG
|
||||
- ✅ Giảm chi phí OCR
|
||||
- ✅ Tránh hallucination nguy hiểm
|
||||
|
||||
---
|
||||
|
||||
## 12. Kết luận phụ lục
|
||||
|
||||
- PDF inspection là **bước bắt buộc trước OCR**
|
||||
- TEXT ≠ SCAN ≠ DRAWING
|
||||
- OCR và MarkItDown chỉ là công cụ, **không phải đích đến**
|
||||
|
||||
---
|
||||
|
||||
*Phụ lục này là nền tảng để thiết kế bước tích hợp OCR trong hệ thống.*
|
||||
213
doc/12.Appendix-OCR-Integration-Strategy-and-Flow.md
Normal file
213
doc/12.Appendix-OCR-Integration-Strategy-and-Flow.md
Normal file
@@ -0,0 +1,213 @@
|
||||
# 12.Appendix-OCR-Integration-Strategy-and-Flow.md
|
||||
|
||||
> **Phụ lục tích hợp OCR – Giải pháp khả thi, rõ ràng, triển khai được ngay** cho hệ thống SharePoint → Search → RAG.
|
||||
>
|
||||
> ⚠️ Nguyên tắc của file này:
|
||||
> - **Đứng độc lập**: có thể load lại trong session khác và tiếp tục thảo luận
|
||||
> - **Chọn MỘT giải pháp chính** (không liệt kê mơ hồ nhiều hướng)
|
||||
> - **Open‑source, on‑prem friendly**, không lock‑in
|
||||
> - Thiết kế **mở để nâng cấp** về sau (fine‑tune / cloud nếu cần)
|
||||
|
||||
---
|
||||
|
||||
## 1. Tóm tắt nhanh quyết định (Executive Summary)
|
||||
|
||||
### Giải pháp OCR được chọn
|
||||
|
||||
> ✅ **PaddleOCR (Detection) + VietOCR (Recognition)** – triển khai on‑prem
|
||||
|
||||
### Vì sao chọn giải pháp này?
|
||||
|
||||
- Phù hợp **99% tài liệu tiếng Việt có dấu**
|
||||
- Đã được cộng đồng Việt Nam sử dụng thực tế
|
||||
- Hoàn toàn **open‑source**
|
||||
- Không phụ thuộc cloud / API bên ngoài
|
||||
- Dễ audit, dễ debug, dễ fine‑tune
|
||||
|
||||
➡️ Đây là giải pháp **khả thi nhất cho phase PoC → Pilot → Production**.
|
||||
|
||||
---
|
||||
|
||||
## 2. Vị trí của OCR trong toàn pipeline (nhắc lại để neo tư duy)
|
||||
|
||||
```text
|
||||
File Ingestion
|
||||
↓
|
||||
Document Classification (file 10)
|
||||
↓
|
||||
PDF Inspection (file 11)
|
||||
↓
|
||||
IF SCAN_PDF
|
||||
→ OCR Layer (file này)
|
||||
↓
|
||||
Normalized Text (page-wise)
|
||||
↓
|
||||
MarkItDown
|
||||
↓
|
||||
Chunking → Search → RAG
|
||||
```
|
||||
|
||||
⚠️ OCR **KHÔNG** đứng độc lập, mà **chỉ là 1 stage có điều kiện**.
|
||||
|
||||
---
|
||||
|
||||
## 3. OCR Integration – Phạm vi áp dụng
|
||||
|
||||
OCR **CHỈ được gọi khi**:
|
||||
|
||||
- `doc_type = textual_document`
|
||||
- `pdf_type = SCAN_PDF`
|
||||
|
||||
OCR **KHÔNG được gọi khi**:
|
||||
|
||||
- Drawing PDF
|
||||
- Binary / CAD / Excel số liệu
|
||||
- File pending classification
|
||||
|
||||
---
|
||||
|
||||
## 4. Kiến trúc OCR chi tiết (Logical Architecture)
|
||||
|
||||
```text
|
||||
OCR Service (microservice)
|
||||
├── Detector: PaddleOCR (DB / SAST)
|
||||
├── Recognizer: VietOCR (Transformer)
|
||||
├── Preprocess:
|
||||
│ - Deskew
|
||||
│ - Binarization
|
||||
│ - Resize
|
||||
├── Output:
|
||||
│ - text
|
||||
│ - page
|
||||
│ - confidence
|
||||
```
|
||||
|
||||
➡️ OCR được đóng gói dưới dạng **service riêng**, không embed cứng vào ingestion.
|
||||
|
||||
---
|
||||
## 1. Tại Sao Lại Là Phân Tán VLM (Vision-Language Model)?
|
||||
|
||||
Trong giai đoạn đầu của PoC, chúng ta đã thử nghiệm kiến trúc cũ: **PaddleOCR** (để bóc khung chữ) kết hợp với **VietOCR** (để dịch tiếng Việt).
|
||||
Tuy nhiên, phương pháp này đã bộc lộ những điểm yếu chí mạng:
|
||||
- **PaddleOCR** cực kỳ yếu trong việc nhận diện dấu tiếng Việt (rụng dấu tả tơi).
|
||||
- **VietOCR (vgg_seq2seq)** bị lỗi "Ảo giác" (Hallucination) sinh ra chữ tiếng Anh rác khi bị cắt ảnh không chuẩn xác.
|
||||
- Quy trình `Cắt ảnh (Crop) -> Dịch -> Ghép lại` làm đứt gãy cấu trúc tự nhiên (Layout) của văn bản.
|
||||
|
||||
Vì vậy, kiến trúc đã được nâng cấp lên chuẩn **Enterprise Distributed AI**:
|
||||
- Sử dụng mô hình **Vintern-3B** (Vision-Language Model) chạy trên một máy chủ chuyên dụng trong mạng LAN thông qua `llama.cpp` server.
|
||||
- Hệ thống RAG (WSL) chỉ đóng vai trò là một VLM Client: Gửi ảnh sang máy chủ LAN và nhận về nguyên văn Markdown chuẩn xác, giữ nguyên cấu trúc bảng biểu, tiêu đề, và không bao giờ rớt dấu.
|
||||
|
||||
---
|
||||
|
||||
## 2. Distributed VLM Integration Flow (Kiến trúc phân tán)
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant P as Pipeline (sync.py)
|
||||
participant DCE as Classification (DCE)
|
||||
participant OS as OCR Service (Client)
|
||||
participant LAN as VLM Server (10.202.50.3)
|
||||
participant DB as Vector DB (OpenSearch)
|
||||
|
||||
P->>DCE: Gửi PDF/Image
|
||||
DCE-->>P: file_type = "image/scanned_pdf"
|
||||
P->>OS: process_bytes(pdf_bytes)
|
||||
|
||||
rect rgb(20, 50, 100)
|
||||
note right of OS: VLM Client Logic
|
||||
OS->>OS: Render trang PDF thành Ảnh (DPI=86)
|
||||
OS->>OS: Encode Ảnh sang Base64
|
||||
OS->>LAN: POST /v1/chat/completions (Base64 + Prompt)
|
||||
end
|
||||
|
||||
rect rgb(80, 20, 20)
|
||||
note right of LAN: GPU/CPU Heavy Lifting
|
||||
LAN->>LAN: Chạy InternVL2 / Vintern-3B
|
||||
LAN->>LAN: Trích xuất toàn bộ Text và Bảng biểu
|
||||
LAN-->>OS: Trả về văn bản chuẩn Markdown
|
||||
end
|
||||
|
||||
OS-->>P: List[OCRPageResult(text, confidence)]
|
||||
|
||||
P->>P: Chunking (Semantic)
|
||||
P->>DB: Indexing
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 3. Kiến Trúc Modular Data Provider
|
||||
|
||||
Để hệ thống hoàn chỉnh ở mức độ cao cấp, chúng tôi đã tái cấu trúc (Refactor) lại tầng Ingestion:
|
||||
1. **BaseStorageProvider:** Interface trừu tượng hoá việc lấy dữ liệu `fetch_changes()` và tải dữ liệu `download_file()`.
|
||||
2. **SharePointProvider:** Kế thừa từ BaseStorageProvider, đóng gói toàn bộ logic Graph API.
|
||||
3. Trong tương lai, chỉ cần viết thêm `GoogleDriveProvider`, `LocalDriveProvider` hoặc `S3Provider` là hệ thống RAG có thể nuốt mọi nguồn dữ liệu mà không cần sửa đổi Core logic.
|
||||
|
||||
---
|
||||
|
||||
## 4. Tách Biệt Cấu Hình (Decoupled Configuration)
|
||||
|
||||
Các thông số siêu nặng của VLM đã được tách biệt hoàn toàn khỏi mã nguồn:
|
||||
- Thông số kết nối mạng LAN: `VLM_ENDPOINT`
|
||||
- Thông số tinh chỉnh: `VLM_TEMPERATURE`, `VLM_MAX_TOKENS`
|
||||
Tất cả được quản lý qua `core/config.py` và file `.env`. Việc đổi máy chủ AI giờ đây chỉ mất 1 giây thay đổi biến môi trường.
|
||||
|
||||
---
|
||||
|
||||
## 5. Confidence Handling (rất quan trọng cho RAG)
|
||||
|
||||
### Nguyên tắc
|
||||
|
||||
- OCR < threshold → **KHÔNG đưa vào RAG**
|
||||
- OCR < threshold → vẫn search keyword + metadata
|
||||
|
||||
### Threshold gợi ý
|
||||
|
||||
- `confidence ≥ 0.90` → OK cho RAG
|
||||
- `0.80 – 0.90` → Search only
|
||||
- `< 0.80` → Flag review
|
||||
|
||||
---
|
||||
|
||||
## 10. Logging & Audit OCR
|
||||
|
||||
Mỗi OCR job phải log:
|
||||
|
||||
```json
|
||||
{
|
||||
"file_id": "...",
|
||||
"page": 5,
|
||||
"ocr_engine": "PaddleOCR+VietOCR",
|
||||
"confidence": 0.91
|
||||
}
|
||||
```
|
||||
|
||||
➡️ Phục vụ:
|
||||
- audit
|
||||
- debug
|
||||
- cải tiến model
|
||||
|
||||
---
|
||||
|
||||
## 11. Mở rộng tương lai (NHƯNG KHÔNG LÀM NGAY)
|
||||
|
||||
✅ Đã được thiết kế sẵn, **không lock‑in**:
|
||||
|
||||
- Fine‑tune VietOCR theo domain
|
||||
- Thêm GPU để tăng tốc
|
||||
- Thay recognition engine nếu cần
|
||||
- Thêm OCR cloud fallback (optional)
|
||||
|
||||
➡️ **Không phá pipeline hiện tại**.
|
||||
|
||||
---
|
||||
|
||||
## 12. Tóm tắt quyết định kỹ thuật
|
||||
|
||||
- OCR là **service có điều kiện**, không phải default
|
||||
- PaddleOCR + VietOCR là **giải pháp chính**
|
||||
- On‑prem, open‑source, audit‑friendly
|
||||
- Sẵn sàng cho PoC → Production
|
||||
|
||||
---
|
||||
|
||||
*Phụ lục này là tài liệu chốt cách tích hợp OCR cho toàn hệ thống.*
|
||||
193
doc/13.PoC-Implementation-Checklist.md
Normal file
193
doc/13.PoC-Implementation-Checklist.md
Normal file
@@ -0,0 +1,193 @@
|
||||
# 13.PoC-Implementation-Checklist.md
|
||||
|
||||
> **Checklist triển khai PoC (Proof of Concept)** cho hệ thống tra cứu tài liệu SharePoint → Search → RAG Chat.
|
||||
>
|
||||
> ⚠️ Nguyên tắc của checklist này:
|
||||
> - Dựa **100% trên các quyết định đã chốt trong file 1–12**
|
||||
> - Dùng để **triển khai PoC thật**, không phải tài liệu lý thuyết
|
||||
> - Checklist theo thứ tự **chuẩn kỹ thuật**, làm xong mục trước mới sang mục sau
|
||||
> - Có thể dùng cho: Tech Lead, Dev, Vendor, AI Agent
|
||||
|
||||
---
|
||||
|
||||
## 0. Phạm vi PoC (BẮT BUỘC CHỐT TRƯỚC KHI LÀM)
|
||||
|
||||
### ✅ Mục tiêu PoC
|
||||
- Tra cứu tài liệu nội bộ (SharePoint)
|
||||
- Hỗ trợ **search + RAG chat**
|
||||
- Đúng quyền người dùng
|
||||
- Ưu tiên **tài liệu tiếng Việt**
|
||||
|
||||
### ❌ Ngoài phạm vi PoC
|
||||
- Fine‑tune OCR
|
||||
- Phân tích bản vẽ kỹ thuật bằng AI
|
||||
- Multi‑tenant phức tạp
|
||||
|
||||
---
|
||||
|
||||
## 1. Chuẩn bị môi trường
|
||||
|
||||
- [ ] Tenant SharePoint test
|
||||
- [ ] App Registration (Graph API – app‑only)
|
||||
- [ ] Server PoC (CPU ≥ 16 cores, RAM ≥ 32GB)
|
||||
- [ ] Docker / Container runtime
|
||||
- [ ] OpenSearch cluster (dev size)
|
||||
|
||||
---
|
||||
|
||||
## 2. Ingestion – SharePoint
|
||||
|
||||
- [ ] Kết nối Graph API thành công
|
||||
- [ ] Lấy được site / library metadata
|
||||
- [ ] Delta query hoạt động
|
||||
- [ ] Persist delta token
|
||||
- [ ] Detect create / update / delete file
|
||||
|
||||
---
|
||||
|
||||
## 3. Document Classification Engine (File 10)
|
||||
|
||||
- [ ] Parse extension + MIME type
|
||||
- [ ] Header byte validation (chống giả extension)
|
||||
- [ ] Gán `doc_type`
|
||||
- [ ] Gán `processing_policy`
|
||||
- [ ] Log lý do classify
|
||||
|
||||
---
|
||||
|
||||
## 4. PDF Inspection (File 11)
|
||||
|
||||
- [ ] Detect text layer PDF
|
||||
- [ ] Calculate text density
|
||||
- [ ] Detect vector / drawing layout
|
||||
- [ ] Classify: TEXT_PDF / SCAN_PDF / DRAWING_PDF
|
||||
- [ ] Log quyết định inspection
|
||||
|
||||
---
|
||||
|
||||
## 5. OCR Integration (File 12)
|
||||
|
||||
### 5.1 Điều kiện gọi OCR
|
||||
- [ ] Chỉ OCR khi `SCAN_PDF`
|
||||
- [ ] Skip DRAWING_PDF
|
||||
- [ ] Skip non‑textual documents
|
||||
|
||||
### 5.2 OCR Service
|
||||
- [ ] PaddleOCR detector chạy ổn định
|
||||
- [ ] VietOCR recognizer nhận tiếng Việt có dấu
|
||||
- [ ] OCR page‑wise
|
||||
- [ ] OCR chạy được trên CPU
|
||||
|
||||
### 5.3 OCR Output
|
||||
- [ ] Có page number
|
||||
- [ ] Có text
|
||||
- [ ] Có confidence
|
||||
- [ ] OCR output chuẩn JSON contract
|
||||
|
||||
---
|
||||
|
||||
## 6. MarkItDown & Normalization
|
||||
|
||||
- [ ] Nhận text từ OCR hoặc text‑PDF
|
||||
- [ ] Convert sang Markdown
|
||||
- [ ] Giữ heading / paragraph / list
|
||||
- [ ] Gắn page marker
|
||||
|
||||
---
|
||||
|
||||
## 7. Chunking
|
||||
|
||||
- [ ] Chunk theo heading / page
|
||||
- [ ] Token size phù hợp cho search & RAG
|
||||
- [ ] Gắn metadata: file_id, page, URL
|
||||
|
||||
---
|
||||
|
||||
## 8. Index & Search (OpenSearch)
|
||||
|
||||
- [ ] Mapping chunk‑first
|
||||
- [ ] Index text field
|
||||
- [ ] Index metadata field
|
||||
- [ ] Index ACL
|
||||
- [ ] Index embedding (nếu dùng)
|
||||
|
||||
---
|
||||
|
||||
## 9. Permission Enforcement
|
||||
|
||||
- [ ] Resolve user identity
|
||||
- [ ] Resolve group membership
|
||||
- [ ] Filter search theo ACL
|
||||
- [ ] Không lộ file user không có quyền
|
||||
|
||||
---
|
||||
|
||||
## 10. Search Experience
|
||||
|
||||
- [ ] Keyword search hoạt động
|
||||
- [ ] Search trả đúng file & page
|
||||
- [ ] Highlight nội dung
|
||||
- [ ] Click mở file gốc
|
||||
|
||||
---
|
||||
|
||||
## 11. RAG Chat (File 5)
|
||||
|
||||
### 11.1 Điều kiện vào RAG
|
||||
- [ ] Có kết quả search
|
||||
- [ ] OCR confidence đạt threshold
|
||||
|
||||
### 11.2 Prompt & Answer
|
||||
- [ ] System prompt chặt (no hallucination)
|
||||
- [ ] Chỉ dùng context search
|
||||
- [ ] Trả câu trả lời + citation
|
||||
|
||||
### 11.3 Fallback
|
||||
- [ ] Không có dữ liệu → trả lời chuẩn
|
||||
|
||||
---
|
||||
|
||||
## 12. Logging & Audit
|
||||
|
||||
- [ ] Log ingestion
|
||||
- [ ] Log OCR
|
||||
- [ ] Log search query
|
||||
- [ ] Log RAG answer + context
|
||||
|
||||
---
|
||||
|
||||
## 13. User Validation (PoC Acceptance)
|
||||
|
||||
- [ ] User tìm được tài liệu mong muốn
|
||||
- [ ] User hiểu citation
|
||||
- [ ] AI không trả lời bịa
|
||||
- [ ] UX dễ sử dụng
|
||||
|
||||
---
|
||||
|
||||
## 14. KPI PoC (Đủ/Không đủ)
|
||||
|
||||
- [ ] Search latency < 3s
|
||||
- [ ] OCR Vietnamese readable
|
||||
- [ ] RAG trả lời đúng phạm vi
|
||||
- [ ] Không lộ quyền
|
||||
|
||||
---
|
||||
|
||||
## 15. Quyết định sau PoC
|
||||
|
||||
- [ ] Go Pilot
|
||||
- [ ] Điều chỉnh OCR threshold
|
||||
- [ ] Thêm loại document
|
||||
- [ ] Fine‑tune sau (nếu cần)
|
||||
|
||||
---
|
||||
|
||||
## Kết luận Checklist
|
||||
|
||||
- Checklist này hoàn thành → PoC **đã thành công về mặt kỹ thuật**
|
||||
- Chưa hoàn thành → **không nên lên production**
|
||||
|
||||
---
|
||||
|
||||
*Tài liệu này là checklist thực thi, không phải tài liệu mô tả.*
|
||||
194
doc/14.Project-Bridge-Context-for-New-Chat.md
Normal file
194
doc/14.Project-Bridge-Context-for-New-Chat.md
Normal file
@@ -0,0 +1,194 @@
|
||||
# 14.Project-Bridge-Context-for-New-Chat.md
|
||||
|
||||
> Mục tiêu file này: **cầu nối ngữ cảnh** để mở New Chat và tiếp tục dự án mà **không cần attach lại toàn bộ 13 file**.
|
||||
>
|
||||
> ⚠️ Lưu ý quan trọng:
|
||||
> - File này là **bản tóm lược có cấu trúc**, **KHÔNG thay thế** hoàn toàn cho các file 1–13.
|
||||
> - Dùng khi giới hạn số file đính kèm thấp.
|
||||
> - Nếu cần chi tiết kỹ thuật sâu cho một mô-đun, vẫn nên attach thêm file gốc liên quan.
|
||||
|
||||
---
|
||||
|
||||
## 1. Dự án đang làm là gì?
|
||||
|
||||
Xây dựng hệ thống tra cứu tài liệu nội bộ theo pipeline:
|
||||
|
||||
```text
|
||||
SharePoint → Ingestion → Document Classification → PDF Inspection → OCR (có điều kiện) → MarkItDown → Chunking → Search → RAG Chat
|
||||
```
|
||||
|
||||
Mục tiêu:
|
||||
- Tra cứu nhanh nội dung tài liệu công ty lưu trong SharePoint
|
||||
- Tìm đúng file, đúng trang, đúng quyền truy cập
|
||||
- Hỗ trợ Search và RAG Chat có dẫn nguồn
|
||||
|
||||
---
|
||||
|
||||
## 2. Các quyết định kiến trúc đã CHỐT (không thay đổi)
|
||||
|
||||
### 2.1 Phân loại tài liệu là bắt buộc trước xử lý
|
||||
- Không có one-size-fits-all cho mọi file
|
||||
- Mỗi file phải đi qua **Document Classification Engine (DCE)** trước
|
||||
|
||||
### 2.2 PDF phải được inspect trước OCR
|
||||
PDF được chia thành 3 loại:
|
||||
- `TEXT_PDF` → không OCR, đưa thẳng vào MarkItDown
|
||||
- `SCAN_PDF` → OCR bắt buộc, page-wise
|
||||
- `DRAWING_PDF` → không OCR đại trà, không MarkItDown, không RAG
|
||||
|
||||
### 2.3 Bản vẽ kỹ thuật / CAD / binary không đi vào RAG
|
||||
- DWG/DXF/IFC/CAD/Binary → metadata search only
|
||||
- Drawing PDF → metadata + optional title-block OCR, không RAG
|
||||
|
||||
### 2.4 OCR chính thức được chọn
|
||||
- **PaddleOCR (Detection) + VietOCR (Recognition)**
|
||||
- On-prem, open-source, không lock-in cloud
|
||||
- OCR chỉ gọi khi:
|
||||
- `doc_type = textual_document`
|
||||
- `pdf_type = SCAN_PDF`
|
||||
|
||||
### 2.5 RAG là tầng sau Search, có điều kiện
|
||||
- Search-first, LLM-second
|
||||
- Không có context tốt → không trả lời
|
||||
- Trả lời phải có citation
|
||||
- OCR confidence thấp → không đưa vào RAG
|
||||
|
||||
---
|
||||
|
||||
## 3. Các file gốc đã tồn tại trước đó
|
||||
|
||||
### Nhóm kiến trúc lõi
|
||||
1. Kiến trúc tổng thể
|
||||
2. SharePoint ingestion playbook
|
||||
3. Extraction & normalization playbook
|
||||
4. OpenSearch index & search playbook
|
||||
5. RAG chat application playbook
|
||||
6. Operations / monitoring / governance playbook
|
||||
|
||||
### Nhóm review & điều phối
|
||||
7. Review / double-check / gap analysis
|
||||
8. End-to-end processing flows bullets
|
||||
|
||||
### Nhóm phụ lục kỹ thuật quan trọng
|
||||
9. Appendix – Vietnamese OCR strategy
|
||||
10. Appendix – Document type classification and processing strategy
|
||||
11. Appendix – PDF inspection and text-layer detection
|
||||
12. Appendix – OCR integration strategy and flow
|
||||
13. PoC implementation checklist
|
||||
|
||||
---
|
||||
|
||||
## 4. Trạng thái hiện tại của dự án
|
||||
|
||||
- Đã chốt kiến trúc end-to-end
|
||||
- Đã chốt luật xử lý tài liệu
|
||||
- Đã chốt chiến lược OCR tiếng Việt
|
||||
- Đã có checklist PoC chi tiết
|
||||
- Đang chuyển sang giai đoạn **bắt tay triển khai PoC thật**
|
||||
|
||||
Trọng tâm hiện tại:
|
||||
> Tạo / dùng **SharePoint Team Site test** làm nguồn dữ liệu đầu vào cho PoC.
|
||||
|
||||
---
|
||||
|
||||
## 5. Site SharePoint test dự kiến / khuyến nghị
|
||||
|
||||
### Loại site
|
||||
- **Team site**
|
||||
- Privacy: Private
|
||||
|
||||
### Tên gợi ý
|
||||
- `SP-RAG-Test`
|
||||
|
||||
### Cấu trúc thư mục test khuyến nghị
|
||||
```text
|
||||
/Documents
|
||||
/01-PDF-Text
|
||||
/02-PDF-Scan
|
||||
/03-PDF-Drawing
|
||||
/04-DOCX
|
||||
/05-XLSX-Textual
|
||||
/06-XLSX-Structured
|
||||
/07-CAD-Binary
|
||||
/99-Pending-Classification
|
||||
```
|
||||
|
||||
### ACL test
|
||||
- Có ít nhất 1 thư mục/folder restricted để test permission filtering
|
||||
|
||||
---
|
||||
|
||||
## 6. Thứ tự triển khai PoC đã chốt
|
||||
|
||||
1. Tạo SharePoint site test
|
||||
2. Upload bộ dữ liệu test nhỏ nhưng đủ loại
|
||||
3. Kiểm tra quyền truy cập khác nhau giữa user
|
||||
4. Bắt đầu ingestion
|
||||
5. Chạy document classification
|
||||
6. Chạy PDF inspection
|
||||
7. Chỉ OCR cho SCAN_PDF
|
||||
8. MarkItDown / normalization / chunking
|
||||
9. Index vào OpenSearch
|
||||
10. Bật search
|
||||
11. Chỉ bật RAG sau khi search + ACL + citation ổn
|
||||
|
||||
---
|
||||
|
||||
## 7. Các ngưỡng / guardrails đã chốt
|
||||
|
||||
### OCR confidence
|
||||
- `>= 0.90` → có thể dùng cho RAG
|
||||
- `0.80 – 0.90` → search only
|
||||
- `< 0.80` → flag review
|
||||
|
||||
### Không được làm
|
||||
- Không OCR drawing PDF đại trà
|
||||
- Không đưa CAD/binary vào RAG
|
||||
- Không bỏ qua bước classification/PDF inspection
|
||||
- Không để AI tự thay đổi kiến trúc đã chốt
|
||||
|
||||
---
|
||||
|
||||
## 8. Khi mở New Chat, AI cần tuân thủ gì?
|
||||
|
||||
### Bắt buộc
|
||||
1. Không thay đổi các quyết định đã chốt ở trên
|
||||
2. Không đề xuất đi ngược các guardrails
|
||||
3. Nếu mở rộng thì chỉ tạo phụ lục mới hoặc ghi rõ là đề xuất mở rộng
|
||||
4. Tiếp tục đúng ngữ cảnh: **từ SharePoint site test → PoC triển khai**
|
||||
|
||||
### Câu mở đầu gợi ý cho New Chat
|
||||
```text
|
||||
Tôi đang tiếp tục dự án SharePoint → Search → RAG.
|
||||
Hãy coi file bridge context này là source of truth tạm thời.
|
||||
Mục tiêu hiện tại: dùng SharePoint site test làm input cho PoC và đi tiếp đúng theo roadmap đã chốt.
|
||||
Không thay đổi kiến trúc, không nhảy bước.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 9. Gợi ý attach file khi chỉ được add ít file
|
||||
|
||||
### Tối thiểu nên attach
|
||||
1. **File bridge này**
|
||||
2. `10.Appendix-Document-Type-Classification-and-Processing-Strategy.md`
|
||||
3. `13.PoC-Implementation-Checklist.md`
|
||||
|
||||
### Nếu cần đi sâu OCR
|
||||
Thay file 13 hoặc attach tiếp ở lượt sau:
|
||||
- `11.Appendix-PDF-Inspection-and-TextLayer-Detection.md`
|
||||
- `12.Appendix-OCR-Integration-Strategy-and-Flow.md`
|
||||
|
||||
---
|
||||
|
||||
## 10. Mục tiêu thảo luận tiếp theo sau khi mở New Chat
|
||||
|
||||
Một trong các hướng sau:
|
||||
- Chuẩn bị dataset test cho SharePoint site
|
||||
- Map SharePoint site test vào PoC pipeline
|
||||
- Lập execution plan theo checklist PoC
|
||||
- Bắt đầu dựng skeleton triển khai kỹ thuật
|
||||
|
||||
---
|
||||
|
||||
*Kết thúc file bridge. Đây là file cầu nối ngữ cảnh, tối ưu cho trường hợp giới hạn số file đính kèm.*
|
||||
264
doc/2.sharepoint-ingestion-playbook.md
Normal file
264
doc/2.sharepoint-ingestion-playbook.md
Normal file
@@ -0,0 +1,264 @@
|
||||
# SharePoint Ingestion – Tài liệu triển khai tuần tự (Reusable)
|
||||
|
||||
> Mục tiêu tài liệu: **Có thể nạp lại bất kỳ lúc nào để tiếp tục đúng hướng**. Viết theo kiểu **triển khai được ngay**, tránh phụ thuộc ngữ cảnh hội thoại.
|
||||
|
||||
---
|
||||
|
||||
## Mục lục
|
||||
1. Phạm vi & Mục tiêu
|
||||
2. Nguyên tắc thiết kế
|
||||
3. Luồng xử lý tổng thể (End-to-End Flow)
|
||||
4. Sequence Diagram (Mô tả tuần tự)
|
||||
5. Thiết kế Ingestion Service
|
||||
6. Delta Sync & State Management
|
||||
7. Permission Flattening (ACL)
|
||||
8. Download & File Lifecycle
|
||||
9. Orchestration, Retry, Idempotency
|
||||
10. Thiết kế CSDL (Schema)
|
||||
11. Internal APIs (Spec)
|
||||
12. Observability & Ops
|
||||
13. Roadmap thực thi
|
||||
|
||||
---
|
||||
|
||||
## 1. Phạm vi & Mục tiêu
|
||||
- Ingest tài liệu từ **SharePoint Online (Microsoft 365)** bằng **Microsoft Graph API**.
|
||||
- Phát hiện thay đổi bằng **Delta Query**.
|
||||
- Thu thập **metadata + quyền truy cập**.
|
||||
- Đưa file hợp lệ vào pipeline xử lý (OCR/MarkItDown ở phase sau).
|
||||
- Đảm bảo **permission-aware ngay từ ingestion**.
|
||||
|
||||
---
|
||||
|
||||
## 2. Nguyên tắc thiết kế
|
||||
- **App-only authentication** (service-to-service).
|
||||
- **Delta-first**: không full scan lặp lại.
|
||||
- **Permission-first**: flatten ACL khi ingest.
|
||||
- **Idempotent**: chạy nhiều lần cho cùng version → kết quả giống nhau.
|
||||
- **File gốc là nguồn chân lý** (chỉ lưu bản trích xuất + index).
|
||||
|
||||
---
|
||||
|
||||
## 3. Luồng xử lý tổng thể (End-to-End)
|
||||
|
||||
```text
|
||||
[Scheduler]
|
||||
↓
|
||||
[List Configured Sites]
|
||||
↓
|
||||
[List Drives / Libraries]
|
||||
↓
|
||||
[Delta Query Items]
|
||||
↓
|
||||
[For each Changed Item]
|
||||
├─ Fetch Metadata
|
||||
├─ Fetch Permissions (ACL)
|
||||
├─ Decide Eligibility (whitelist extension/size)
|
||||
├─ Enqueue Processing Job
|
||||
└─ Persist State (deltaToken, etag)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. Sequence Diagram (Mô tả tuần tự)
|
||||
|
||||
```text
|
||||
Scheduler
|
||||
|
|
||||
| trigger
|
||||
v
|
||||
Ingestion Service
|
||||
|
|
||||
| GET sites/drives
|
||||
v
|
||||
Microsoft Graph
|
||||
|
|
||||
| 200 OK (sites/drives)
|
||||
v
|
||||
Ingestion Service
|
||||
|
|
||||
| GET delta(items, token)
|
||||
v
|
||||
Microsoft Graph
|
||||
|
|
||||
| items[] + deltaToken
|
||||
v
|
||||
Ingestion Service
|
||||
|
|
||||
| For item changed:
|
||||
| - GET item metadata
|
||||
| - GET item permissions
|
||||
| - Persist ingest record
|
||||
| - Push job to Queue
|
||||
v
|
||||
Queue / Pipeline
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. Thiết kế Ingestion Service
|
||||
|
||||
### 5.1 Thành phần
|
||||
- **Auth Module**: OAuth2 client-credentials + certificate.
|
||||
- **Site/Drive Scanner**: liệt kê phạm vi được cấu hình.
|
||||
- **Delta Engine**: quản lý deltaToken.
|
||||
- **Metadata Collector**: chuẩn hóa metadata.
|
||||
- **ACL Collector**: flatten permission.
|
||||
- **Job Producer**: đẩy sự kiện sang pipeline.
|
||||
|
||||
### 5.2 Công nghệ gợi ý
|
||||
- Backend: Python (FastAPI) hoặc Node.js
|
||||
- Queue: Azure Service Bus / RabbitMQ / Redis
|
||||
- Storage state: PostgreSQL hoặc CosmosDB (metadata)
|
||||
|
||||
---
|
||||
|
||||
## 6. Delta Sync & State Management
|
||||
|
||||
### 6.1 Delta Token
|
||||
- Mỗi **drive/library** có một `delta_token` riêng.
|
||||
- Lưu bền vững (DB), không lưu memory.
|
||||
|
||||
### 6.2 Logic
|
||||
```text
|
||||
If first_run:
|
||||
call delta without token → snapshot + token
|
||||
Else:
|
||||
call delta with token → changes only
|
||||
```
|
||||
|
||||
### 6.3 Event Handling
|
||||
| Event | Hành động |
|
||||
|------|----------|
|
||||
| Created | Full ingest |
|
||||
| Updated | Re-ingest (new version) |
|
||||
| Deleted | Soft-delete index |
|
||||
|
||||
---
|
||||
|
||||
## 7. Permission Flattening (ACL)
|
||||
|
||||
### 7.1 Nguyên tắc
|
||||
- Thu thập **users + groups** ngay khi ingest.
|
||||
- Expand nested groups **tại ingestion time**.
|
||||
|
||||
### 7.2 Schema ACL
|
||||
```json
|
||||
{
|
||||
"users": ["aad-user-id"],
|
||||
"groups": ["aad-group-id"],
|
||||
"inherited": true
|
||||
}
|
||||
```
|
||||
|
||||
### 7.3 Tối ưu
|
||||
- Cache membership group.
|
||||
- Refresh định kỳ (daily/weekly).
|
||||
|
||||
---
|
||||
|
||||
## 8. Download & File Lifecycle
|
||||
|
||||
### 8.1 Eligibility Rules
|
||||
- Whitelist: pdf, docx, pptx, image.
|
||||
- Size limit (ví dụ ≤ 100MB).
|
||||
|
||||
### 8.2 Lifecycle
|
||||
```text
|
||||
Download → Process (OCR/MD) → Persist result → Delete local file
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 9. Orchestration, Retry, Idempotency
|
||||
|
||||
### 9.1 Idempotency Key
|
||||
- `(site_id, drive_id, item_id, etag)`
|
||||
|
||||
### 9.2 Retry Strategy
|
||||
| Error | Strategy |
|
||||
|------|----------|
|
||||
| 429 | Exponential backoff |
|
||||
| Timeout | Retry N lần |
|
||||
| Permission denied | Log + skip |
|
||||
|
||||
---
|
||||
|
||||
## 10. Thiết kế CSDL (Schema)
|
||||
|
||||
### 10.1 Bảng `ingest_state`
|
||||
```sql
|
||||
site_id TEXT
|
||||
drive_id TEXT
|
||||
delta_token TEXT
|
||||
updated_at TIMESTAMP
|
||||
PRIMARY KEY (site_id, drive_id)
|
||||
```
|
||||
|
||||
### 10.2 Bảng `files`
|
||||
```sql
|
||||
item_id TEXT
|
||||
site_id TEXT
|
||||
drive_id TEXT
|
||||
file_name TEXT
|
||||
etag TEXT
|
||||
version TEXT
|
||||
status TEXT
|
||||
last_processed_at TIMESTAMP
|
||||
PRIMARY KEY (item_id)
|
||||
```
|
||||
|
||||
### 10.3 Bảng `permissions`
|
||||
```sql
|
||||
item_id TEXT
|
||||
principal_type TEXT -- user|group
|
||||
principal_id TEXT
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 11. Internal APIs (Spec)
|
||||
|
||||
### POST /ingest/run
|
||||
- Trigger ingestion cycle.
|
||||
|
||||
### POST /ingest/item
|
||||
- Input: `{ site_id, drive_id, item_id }`
|
||||
- Output: job_id
|
||||
|
||||
### GET /ingest/state
|
||||
- Trả về deltaToken, health.
|
||||
|
||||
---
|
||||
|
||||
## 12. Observability & Ops
|
||||
|
||||
### Logs (per item)
|
||||
```json
|
||||
{ "item_id": "...", "step": "permission", "status": "ok" }
|
||||
```
|
||||
|
||||
### Metrics
|
||||
- Files/min
|
||||
- OCR queue length
|
||||
- Error rate
|
||||
|
||||
---
|
||||
|
||||
## 13. Roadmap thực thi
|
||||
|
||||
### Step 1 (Tuần 1–2)
|
||||
- Auth + list sites/drives
|
||||
- Delta sync cơ bản
|
||||
|
||||
### Step 2 (Tuần 3)
|
||||
- Metadata + ACL flatten
|
||||
- Queue integration
|
||||
|
||||
### Step 3 (Tuần 4)
|
||||
- Observability
|
||||
- Hardening & scale
|
||||
|
||||
---
|
||||
|
||||
*Kết thúc tài liệu ingestion. Có thể tiếp tục với Extraction/OCR hoặc Index/Search ở file tiếp theo.*
|
||||
241
doc/3.extraction-markdown-normalization-playbook.md
Normal file
241
doc/3.extraction-markdown-normalization-playbook.md
Normal file
@@ -0,0 +1,241 @@
|
||||
# Extraction & Normalization – OCR + MarkItDown Playbook (Reusable)
|
||||
|
||||
> Tài liệu này nối tiếp **SharePoint Ingestion Playbook**. Mục tiêu: biến file ingest thành **Markdown sạch, có cấu trúc, có thể search – RAG – truy vết trang gốc**. Viết để **tái sử dụng lâu dài**, không phụ thuộc session.
|
||||
|
||||
---
|
||||
|
||||
## Mục lục
|
||||
1. Vị trí của Extraction trong kiến trúc
|
||||
2. Nguyên tắc thiết kế
|
||||
3. Luồng xử lý tổng thể
|
||||
4. Phân loại tài liệu & chiến lược xử lý
|
||||
5. OCR Strategy cho tài liệu scan
|
||||
6. MarkItDown – tích hợp & cấu hình
|
||||
7. Page Mapping & Anchoring (đi tới đúng trang)
|
||||
8. Normalization & Cleanup
|
||||
9. Chunking Strategy (chuẩn cho Search & RAG)
|
||||
10. Output Contract (interface dữ liệu)
|
||||
11. Error handling & Retry
|
||||
12. Performance & Scale
|
||||
13. Checklist triển khai
|
||||
|
||||
---
|
||||
|
||||
## 1. Vị trí của Extraction trong kiến trúc
|
||||
|
||||
```text
|
||||
Ingestion (file + metadata + ACL)
|
||||
│
|
||||
▼
|
||||
Extraction Layer (OCR + MarkItDown)
|
||||
│
|
||||
▼
|
||||
Normalization & Chunking
|
||||
│
|
||||
▼
|
||||
Index / Search / RAG
|
||||
```
|
||||
|
||||
Extraction **không biết Search**, **không biết User**, chỉ biết:
|
||||
- Input: file + metadata
|
||||
- Output: Markdown + page mapping + structural hints
|
||||
|
||||
---
|
||||
|
||||
## 2. Nguyên tắc thiết kế
|
||||
|
||||
1. **Deterministic**: cùng file + version → output giống nhau
|
||||
2. **Lossless về nội dung**: ưu tiên giữ text hơn làm đẹp
|
||||
3. **Trang là đơn vị neo (anchor)** – đặc biệt với PDF
|
||||
4. **Tách OCR khỏi Markdown** (để thay engine sau này)
|
||||
5. **Không embed business logic** vào bước này
|
||||
|
||||
---
|
||||
|
||||
## 3. Luồng xử lý tổng thể
|
||||
|
||||
```text
|
||||
[Receive File Job]
|
||||
↓
|
||||
[Detect File Type]
|
||||
↓
|
||||
[If Scan → OCR]
|
||||
↓
|
||||
[MarkItDown Convert → Markdown]
|
||||
↓
|
||||
[Normalize Markdown]
|
||||
↓
|
||||
[Split by Page / Heading]
|
||||
↓
|
||||
[Emit Document Units]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. Phân loại tài liệu & chiến lược xử lý
|
||||
|
||||
| Loại | Dấu hiệu | Chiến lược |
|
||||
|----|--------|-----------|
|
||||
| PDF scan | Không có text layer | OCR → MD |
|
||||
| PDF text | Có selectable text | Direct → MD |
|
||||
| DOCX | Word | Direct → MD |
|
||||
| PPTX | Slide | Slide-wise MD |
|
||||
| Image | jpg/png | OCR → MD |
|
||||
|
||||
✅ Phân loại phải tự động, **không dựa vào extension duy nhất**.
|
||||
|
||||
---
|
||||
|
||||
## 5. OCR Strategy
|
||||
|
||||
### 5.1 Khi nào OCR?
|
||||
- PDF không có text layer
|
||||
- Image-based document
|
||||
|
||||
### 5.2 Output OCR yêu cầu tối thiểu
|
||||
```json
|
||||
{
|
||||
"page": 5,
|
||||
"text": "Nội dung nhận dạng...",
|
||||
"confidence": 0.92
|
||||
}
|
||||
```
|
||||
|
||||
### 5.3 Nguyên tắc
|
||||
- OCR **theo từng trang**
|
||||
- Không gộp toàn file thành một blob text
|
||||
|
||||
---
|
||||
|
||||
## 6. MarkItDown – tích hợp & cấu hình
|
||||
|
||||
### 6.1 Vai trò
|
||||
- Biến input (PDF/DOCX/image) thành **Markdown có cấu trúc**
|
||||
|
||||
### 6.2 Mode sử dụng
|
||||
- Input: file path hoặc stream
|
||||
- Output: Markdown + page breaks
|
||||
|
||||
### 6.3 Quy ước page break (rất quan trọng)
|
||||
```markdown
|
||||
<!-- page:1 -->
|
||||
# Trang 1
|
||||
...
|
||||
<!-- page:2 -->
|
||||
# Trang 2
|
||||
```
|
||||
|
||||
➡️ Page marker này là **khóa để click mở đúng trang PDF**.
|
||||
|
||||
---
|
||||
|
||||
## 7. Page Mapping & Anchoring
|
||||
|
||||
### 7.1 Mục tiêu
|
||||
- Người dùng search → click → mở **đúng trang, đúng vị trí**
|
||||
|
||||
### 7.2 Cách làm
|
||||
- Mỗi block Markdown phải mang theo:
|
||||
```json
|
||||
{
|
||||
"file_id": "...",
|
||||
"page_from": 3,
|
||||
"page_to": 4,
|
||||
"sharepoint_url": "...?page=3"
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. Normalization & Cleanup
|
||||
|
||||
### 8.1 Những việc NÊN làm
|
||||
- Remove header/footer lặp
|
||||
- Strip ký tự OCR rác
|
||||
- Normalize whitespace
|
||||
- Chuẩn hóa heading
|
||||
|
||||
### 8.2 Những việc KHÔNG NÊN làm
|
||||
- Rewrite nội dung
|
||||
- Tóm tắt
|
||||
- Suy diễn
|
||||
|
||||
➡️ Bước này **không dùng LLM**.
|
||||
|
||||
---
|
||||
|
||||
## 9. Chunking Strategy
|
||||
|
||||
### 9.1 Thứ tự ưu tiên
|
||||
1. Heading (##, ###)
|
||||
2. Trang PDF
|
||||
3. Đoạn văn
|
||||
|
||||
### 9.2 Kích thước gợi ý
|
||||
- 300–800 tokens
|
||||
- Không cắt giữa câu
|
||||
|
||||
### 9.3 Schema chunk
|
||||
```json
|
||||
{
|
||||
"chunk_id": "uuid",
|
||||
"text": "...",
|
||||
"file_id": "...",
|
||||
"page_from": 5,
|
||||
"page_to": 6,
|
||||
"section": "Điều 3",
|
||||
"source_url": "..."
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 10. Output Contract
|
||||
|
||||
### 10.1 Đầu ra cho Index Layer
|
||||
```json
|
||||
{
|
||||
"file_id": "...",
|
||||
"chunks": [ ... ],
|
||||
"metadata": { ... }
|
||||
}
|
||||
```
|
||||
|
||||
### 10.2 Tính chất
|
||||
- Self-contained
|
||||
- Không cần gọi lại SharePoint
|
||||
- Có thể re-index lại từ output này
|
||||
|
||||
---
|
||||
|
||||
## 11. Error handling & Retry
|
||||
|
||||
| Lỗi | Xử lý |
|
||||
|---|------|
|
||||
| OCR fail | Retry / flag manual |
|
||||
| File corrupt | Log + skip |
|
||||
| MarkItDown error | Retry with fallback |
|
||||
|
||||
Mỗi file có **processing status riêng**.
|
||||
|
||||
---
|
||||
|
||||
## 12. Performance & Scale
|
||||
|
||||
- OCR là bottleneck → async
|
||||
- 1 file lớn = nhiều page jobs
|
||||
- Scale theo số trang, không theo số file
|
||||
|
||||
---
|
||||
|
||||
## 13. Checklist triển khai
|
||||
|
||||
✅ Detect scan vs text
|
||||
✅ OCR page-wise
|
||||
✅ Page marker trong Markdown
|
||||
✅ Chunk có page mapping
|
||||
✅ Output contract rõ ràng
|
||||
|
||||
---
|
||||
|
||||
*Kết thúc Extraction & Normalization Playbook. File này nối trực tiếp sang Index/Search.*
|
||||
246
doc/4.OpenSearch-Index-Search-Playbook.md
Normal file
246
doc/4.OpenSearch-Index-Search-Playbook.md
Normal file
@@ -0,0 +1,246 @@
|
||||
# 4.OpenSearch-Index-Search-Playbook.md
|
||||
|
||||
> Tài liệu này kế thừa trực tiếp các file trước (1–3). Mục tiêu: thiết kế **Index & Search Layer** đảm bảo tra cứu nhanh, đúng quyền, hỗ trợ full‑text, semantic search và RAG về sau. Nội dung viết để **tái sử dụng lâu dài**, có thể nạp lại để tiếp tục triển khai.
|
||||
|
||||
---
|
||||
|
||||
## Mục lục
|
||||
1. Vai trò của Index/Search trong pipeline
|
||||
2. Nguyên tắc thiết kế
|
||||
3. Kiến trúc logical của Search Layer
|
||||
4. Thiết kế Index (mapping chi tiết)
|
||||
5. ACL‑aware indexing & filtering
|
||||
6. Full‑text Search
|
||||
7. Vector & Semantic Search
|
||||
8. Hybrid Search (khuyến nghị)
|
||||
9. Highlight, Ranking & Relevance tuning
|
||||
10. Query contract (API level)
|
||||
11. Performance & Scale
|
||||
12. Lifecycle management (update/delete)
|
||||
13. Checklist triển khai
|
||||
|
||||
---
|
||||
|
||||
## 1. Vai trò của Index/Search trong pipeline
|
||||
|
||||
```text
|
||||
Extraction & Chunking
|
||||
│
|
||||
▼
|
||||
Index Layer (OpenSearch)
|
||||
│
|
||||
▼
|
||||
Search UI / Chat (RAG)
|
||||
```
|
||||
|
||||
Index/Search chịu trách nhiệm:
|
||||
- Lưu trữ **chunk nội dung + metadata + ACL**
|
||||
- Trả kết quả **nhanh, chính xác, đúng quyền**
|
||||
- Cho phép search theo **từ khóa lẫn ngữ nghĩa**
|
||||
|
||||
---
|
||||
|
||||
## 2. Nguyên tắc thiết kế
|
||||
|
||||
1. **Chunk‑first, không file‑first**
|
||||
2. **Permission filter ở query time nhưng dữ liệu đã chuẩn hóa từ ingestion**
|
||||
3. **Hybrid search mặc định** (keyword + vector)
|
||||
4. **Index schema ổn định**, embedding thay đổi được
|
||||
5. **Re‑index được từ output Extraction mà không cần SharePoint**
|
||||
|
||||
---
|
||||
|
||||
## 3. Kiến trúc logical của Search Layer
|
||||
|
||||
```text
|
||||
OpenSearch Cluster
|
||||
├── text index
|
||||
├── vector index (hoặc combined)
|
||||
├── analyzer (vi, en)
|
||||
└── ACL filter
|
||||
```
|
||||
|
||||
Có thể:
|
||||
- Dùng **1 index combined** (text + vector)
|
||||
- Hoặc **2 index song song** (đơn giản giai đoạn đầu: 1 index)
|
||||
|
||||
---
|
||||
|
||||
## 4. Thiết kế Index (Mapping)
|
||||
|
||||
### 4.1 Document unit
|
||||
Mỗi document trong index = **1 chunk**.
|
||||
|
||||
### 4.2 Mapping gợi ý
|
||||
|
||||
```json
|
||||
{
|
||||
"mappings": {
|
||||
"properties": {
|
||||
"chunk_id": { "type": "keyword" },
|
||||
"file_id": { "type": "keyword" },
|
||||
"file_name": { "type": "text" },
|
||||
"text": {
|
||||
"type": "text",
|
||||
"analyzer": "standard",
|
||||
"search_analyzer": "standard"
|
||||
},
|
||||
"embedding": {
|
||||
"type": "knn_vector",
|
||||
"dimension": 768
|
||||
},
|
||||
"site_id": { "type": "keyword" },
|
||||
"page_from": { "type": "integer" },
|
||||
"page_to": { "type": "integer" },
|
||||
"source_url": { "type": "keyword" },
|
||||
"permissions": { "type": "keyword" },
|
||||
"updated_at": { "type": "date" }
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. ACL‑aware Indexing & Filtering
|
||||
|
||||
### 5.1 Nguyên tắc
|
||||
- Không index public rồi filter payload
|
||||
- Mỗi chunk mang theo **list principal IDs** (user/group)
|
||||
|
||||
### 5.2 Filter tại query
|
||||
```json
|
||||
{
|
||||
"terms": {
|
||||
"permissions": ["current_user_id", "group_id_1"]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. Full‑text Search
|
||||
|
||||
Sử dụng khi:
|
||||
- Tìm chính xác điều khoản, mã số, tên riêng
|
||||
|
||||
Ví dụ query:
|
||||
```json
|
||||
{
|
||||
"match": {
|
||||
"text": "hợp đồng lao động không xác định thời hạn"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. Vector & Semantic Search
|
||||
|
||||
Sử dụng khi:
|
||||
- Câu hỏi tự nhiên
|
||||
- Nội dung diễn đạt khác từ khóa
|
||||
|
||||
```json
|
||||
{
|
||||
"knn": {
|
||||
"embedding": {
|
||||
"vector": [ ... ],
|
||||
"k": 10
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. Hybrid Search (Khuyến nghị mặc định)
|
||||
|
||||
```json
|
||||
{
|
||||
"bool": {
|
||||
"must": [
|
||||
{
|
||||
"match": { "text": "chấm dứt hợp đồng" }
|
||||
}
|
||||
],
|
||||
"should": [
|
||||
{
|
||||
"knn": {
|
||||
"embedding": {
|
||||
"vector": [ ... ],
|
||||
"k": 10
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Score cuối = combine(keyword_score, semantic_score)
|
||||
|
||||
---
|
||||
|
||||
## 9. Highlight, Ranking & Relevance
|
||||
|
||||
### 9.1 Highlight
|
||||
- Highlight ở field `text`
|
||||
- Trả snippet cho UI
|
||||
|
||||
### 9.2 Ranking hints
|
||||
- Boost theo:
|
||||
- page proximity
|
||||
- recency (updated_at)
|
||||
- heading match
|
||||
|
||||
---
|
||||
|
||||
## 10. Query Contract (API nội bộ)
|
||||
|
||||
### POST /search
|
||||
Input:
|
||||
```json
|
||||
{ "query": "...", "user_id": "...", "groups": ["..."] }
|
||||
```
|
||||
|
||||
Output:
|
||||
```json
|
||||
{
|
||||
"results": [
|
||||
{ "file_name": "...", "page": 5, "snippet": "...", "url": "..." }
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 11. Performance & Scale
|
||||
|
||||
- Index theo chunk, không theo file
|
||||
- Shard theo dữ liệu, không theo tenant sớm
|
||||
- Cache query phổ biến
|
||||
|
||||
---
|
||||
|
||||
## 12. Lifecycle Management
|
||||
|
||||
| Event | Action |
|
||||
|------|-------|
|
||||
| File update | Delete chunks cũ → index lại |
|
||||
| File delete | Soft delete hoặc remove |
|
||||
| Re‑embedding | Update `embedding` field |
|
||||
|
||||
---
|
||||
|
||||
## 13. Checklist triển khai
|
||||
|
||||
✅ Mapping ổn định
|
||||
✅ ACL filter hoạt động
|
||||
✅ Hybrid search default
|
||||
✅ Highlight trả đúng trang
|
||||
✅ Re‑index không cần SharePoint
|
||||
|
||||
---
|
||||
|
||||
*Kết thúc Index & Search Playbook. File tiếp theo sẽ là RAG / Chat Layer.*
|
||||
242
doc/5.RAG-Chat-Application-Playbook.md
Normal file
242
doc/5.RAG-Chat-Application-Playbook.md
Normal file
@@ -0,0 +1,242 @@
|
||||
# 5.RAG-Chat-Application-Playbook.md
|
||||
|
||||
> Tài liệu này mô tả **tầng RAG Chat** xây dựng trên Search (file 4). Mục tiêu là:
|
||||
> - Giúp **AI trả lời đúng – có dẫn chứng – không hallucinate**
|
||||
> - Giúp **người dùng cuối dễ hiểu, dễ tin, dễ dùng**
|
||||
> - Có thể dùng làm **tài liệu tham khảo khi soạn Hướng dẫn sử dụng (User Guide)**
|
||||
>
|
||||
> File được viết để **AI agent đọc là triển khai được**, **con người đọc là hiểu và sử dụng được**.
|
||||
|
||||
---
|
||||
|
||||
## Mục lục
|
||||
1. RAG Chat là gì trong hệ thống này?
|
||||
2. Nguyên tắc thiết kế RAG Chat
|
||||
3. Kiến trúc tổng thể RAG Chat
|
||||
4. Vai trò của Search trong RAG
|
||||
5. Luồng xử lý câu hỏi (End‑to‑End)
|
||||
6. Prompt Strategy (Quan trọng nhất)
|
||||
7. Context Assembly & Citation
|
||||
8. Tránh Hallucination & Guardrails
|
||||
9. Trải nghiệm người dùng (UX Guidelines)
|
||||
10. Các chế độ Chat khuyến nghị
|
||||
11. Permission propagation
|
||||
12. Logging & Explainability
|
||||
13. Checklist triển khai & Checklist hướng dẫn sử dụng
|
||||
|
||||
---
|
||||
|
||||
## 1. RAG Chat là gì trong hệ thống này?
|
||||
|
||||
**RAG (Retrieval‑Augmented Generation)** = AI **KHÔNG tự nghĩ**, mà:
|
||||
1. Tìm dữ liệu liên quan trong hệ thống Search
|
||||
2. Chỉ dùng dữ liệu đó để trả lời
|
||||
3. Luôn nói rõ **lấy thông tin từ đâu**
|
||||
|
||||
Trong hệ thống này:
|
||||
- ❌ Chat **không** thay thế Search
|
||||
- ✅ Chat **dựa hoàn toàn trên Search**
|
||||
|
||||
---
|
||||
|
||||
## 2. Nguyên tắc thiết kế RAG Chat
|
||||
|
||||
1. **Search‑first, LLM‑second**
|
||||
2. **Không có dữ liệu → không trả lời**
|
||||
3. **Trả lời = Nội dung + Dẫn chứng**
|
||||
4. **Ngôn ngữ rõ ràng, không học thuật thừa**
|
||||
5. **Người dùng luôn có thể click mở tài liệu gốc**
|
||||
|
||||
---
|
||||
|
||||
## 3. Kiến trúc tổng thể RAG Chat
|
||||
|
||||
```text
|
||||
User Question
|
||||
│
|
||||
▼
|
||||
Query Understanding
|
||||
│
|
||||
▼
|
||||
Search Layer (OpenSearch)
|
||||
│
|
||||
├─ Top K chunks (ACL‑aware)
|
||||
▼
|
||||
Context Assembly
|
||||
│
|
||||
▼
|
||||
LLM (Answer generation)
|
||||
│
|
||||
▼
|
||||
Answer + Citations
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. Vai trò của Search trong RAG
|
||||
|
||||
Search quyết định:
|
||||
- AI **được phép biết gì**
|
||||
- AI **không được phép bịa gì**
|
||||
|
||||
Quy tắc:
|
||||
- LLM **chỉ được dùng context do Search trả về**
|
||||
- Không cho LLM truy cập internet / training data
|
||||
|
||||
---
|
||||
|
||||
## 5. Luồng xử lý câu hỏi (End‑to‑End)
|
||||
|
||||
```text
|
||||
[User hỏi]
|
||||
↓
|
||||
[Normalize câu hỏi]
|
||||
↓
|
||||
[Hybrid Search (keyword + vector)]
|
||||
↓
|
||||
[Lọc theo permission user]
|
||||
↓
|
||||
[Chọn top K chunks]
|
||||
↓
|
||||
[Build context + citation map]
|
||||
↓
|
||||
[LLM sinh câu trả lời]
|
||||
↓
|
||||
[Trả lời + link tài liệu]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. Prompt Strategy (Rất quan trọng)
|
||||
|
||||
### 6.1 System Prompt (bắt buộc)
|
||||
|
||||
```text
|
||||
Bạn là trợ lý tra cứu tài liệu nội bộ.
|
||||
Bạn CHỈ được trả lời dựa trên thông tin được cung cấp trong CONTEXT.
|
||||
Nếu CONTEXT không đủ, hãy trả lời:
|
||||
"Tôi không tìm thấy thông tin trong các tài liệu hiện có."
|
||||
Mỗi câu trả lời phải kèm theo nguồn trích dẫn.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 6.2 User Prompt Template
|
||||
|
||||
```text
|
||||
CÂU HỎI:
|
||||
{{user_question}}
|
||||
|
||||
CONTEXT:
|
||||
{{retrieved_chunks}}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
### 6.3 Output Format (khuyến nghị)
|
||||
|
||||
```text
|
||||
TRẢ LỜI NGẮN GỌN:
|
||||
...
|
||||
|
||||
CHI TIẾT:
|
||||
...
|
||||
|
||||
NGUỒN THAM KHẢO:
|
||||
- Tài liệu A – trang 5
|
||||
- Tài liệu B – trang 12
|
||||
```
|
||||
|
||||
➡️ Format này **rất phù hợp để đưa vào User Guide**.
|
||||
|
||||
---
|
||||
|
||||
## 7. Context Assembly & Citation
|
||||
|
||||
### 7.1 Context Assembly
|
||||
- Giữ đúng thứ tự logic
|
||||
- Không quá dài (token budget)
|
||||
- Mỗi chunk có ID và nguồn
|
||||
|
||||
### 7.2 Citation Object
|
||||
|
||||
```json
|
||||
{
|
||||
"chunk_id": "...",
|
||||
"file_name": "...",
|
||||
"page": 7,
|
||||
"url": "..."
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. Tránh Hallucination & Guardrails
|
||||
|
||||
✅ BẮT BUỘC:
|
||||
- Nếu không có chunk phù hợp → không trả lời
|
||||
- Không "suy luận thêm" ngoài context
|
||||
|
||||
✅ Câu trả lời chuẩn khi không đủ dữ liệu:
|
||||
> "Hiện tại tôi không tìm thấy thông tin trong các tài liệu nội bộ để trả lời câu hỏi này."
|
||||
|
||||
---
|
||||
|
||||
## 9. Trải nghiệm người dùng (UX Guidelines)
|
||||
|
||||
### 9.1 Người dùng nên cảm nhận gì?
|
||||
- AI **đáng tin**
|
||||
- Nói **giống đồng nghiệp biết tài liệu**, không giống chatbot chung chung
|
||||
|
||||
### 9.2 UX khuyến nghị
|
||||
- Mỗi đoạn trả lời có nút "Mở tài liệu"
|
||||
- Highlight đoạn liên quan trong PDF
|
||||
|
||||
---
|
||||
|
||||
## 10. Các chế độ Chat khuyến nghị
|
||||
|
||||
| Mode | Mô tả | Đối tượng |
|
||||
|----|------|----------|
|
||||
| Tra cứu nhanh | Trả lời ngắn + link | Nhân viên |
|
||||
| Giải thích | Có diễn giải | Đào tạo |
|
||||
| So sánh | So nhiều tài liệu | Quản lý |
|
||||
|
||||
---
|
||||
|
||||
## 11. Permission Propagation
|
||||
|
||||
Nguyên tắc:
|
||||
- Chat **không trả về thứ Search không trả**
|
||||
- Không lộ tên file tồn tại nếu user không có quyền
|
||||
|
||||
---
|
||||
|
||||
## 12. Logging & Explainability
|
||||
|
||||
Lưu lại:
|
||||
- Question
|
||||
- Retrieved chunks
|
||||
- Answer
|
||||
- Citation
|
||||
|
||||
➡️ Phục vụ audit, cải tiến prompt, training nội bộ
|
||||
|
||||
---
|
||||
|
||||
## 13. Checklist triển khai & Checklist hướng dẫn sử dụng
|
||||
|
||||
### 13.1 Checklist kỹ thuật
|
||||
✅ Search trước Chat
|
||||
✅ Prompt chặt chẽ
|
||||
✅ Citation bắt buộc
|
||||
✅ Permission end‑to‑end
|
||||
|
||||
### 13.2 Checklist cho User Guide
|
||||
✅ Giải thích AI làm gì / không làm gì
|
||||
✅ Hướng dẫn đọc citation
|
||||
✅ Cách phản hồi khi AI không tìm thấy dữ liệu
|
||||
|
||||
---
|
||||
|
||||
*Kết thúc RAG Chat Playbook. Đây là tầng trên cùng của hệ thống.*
|
||||
241
doc/6.Operations-Monitoring-Governance-Playbook.md
Normal file
241
doc/6.Operations-Monitoring-Governance-Playbook.md
Normal file
@@ -0,0 +1,241 @@
|
||||
# 6.Operations-Monitoring-Governance-Playbook.md
|
||||
|
||||
> Tài liệu này mô tả **cách vận hành, giám sát và kiểm soát** toàn bộ hệ thống SharePoint → Search → RAG Chat trong môi trường doanh nghiệp.
|
||||
> Đây là tài liệu **rất quan trọng sau PoC**, đảm bảo hệ thống **bền vững, an toàn, có thể mở rộng và được tin cậy lâu dài**.
|
||||
>
|
||||
> File được viết để:
|
||||
> - IT / Ops / Security đọc là hiểu
|
||||
> - AI agent đọc là biết cách triển khai monitoring
|
||||
> - Là nền tảng cho **quy trình vận hành & governance nội bộ**
|
||||
|
||||
---
|
||||
|
||||
## Mục lục
|
||||
1. Mục tiêu Operations & Governance
|
||||
2. Nguyên tắc vận hành
|
||||
3. Tổng quan các tầng cần giám sát
|
||||
4. Monitoring chi tiết theo từng tầng
|
||||
5. KPI & Quality Metrics
|
||||
6. Alerting & Incident Response
|
||||
7. Logging & Audit Trail
|
||||
8. Data Governance & Compliance
|
||||
9. Model / Prompt Governance
|
||||
10. User Feedback Loop
|
||||
11. Backup, Rollback & Disaster Recovery
|
||||
12. Phân quyền vận hành (Ops Roles)
|
||||
13. Checklist vận hành định kỳ
|
||||
|
||||
---
|
||||
|
||||
## 1. Mục tiêu Operations & Governance
|
||||
|
||||
Hệ thống không chỉ cần "chạy được", mà phải:
|
||||
- ✅ Ổn định
|
||||
- ✅ Đúng dữ liệu
|
||||
- ✅ Đúng quyền
|
||||
- ✅ Truy vết được
|
||||
- ✅ Giải thích được
|
||||
|
||||
Mục tiêu cuối cùng:
|
||||
> **Người dùng tin – IT kiểm soát – Ban lãnh đạo yên tâm**
|
||||
|
||||
---
|
||||
|
||||
## 2. Nguyên tắc vận hành
|
||||
|
||||
1. **Fail rõ ràng, không fail im lặng**
|
||||
2. **Mỗi tài liệu đều có lifecycle**
|
||||
3. **Mỗi câu trả lời đều có log & nguồn**
|
||||
4. **AI không được vượt quyền dữ liệu**
|
||||
5. **Có thể rollback bất kỳ tầng nào**
|
||||
|
||||
---
|
||||
|
||||
## 3. Tổng quan các tầng cần giám sát
|
||||
|
||||
```text
|
||||
[SharePoint]
|
||||
↓
|
||||
[Ingestion]
|
||||
↓
|
||||
[Extraction / OCR]
|
||||
↓
|
||||
[Index / Search]
|
||||
↓
|
||||
[RAG Chat]
|
||||
```
|
||||
|
||||
Mỗi tầng phải có:
|
||||
- Health check
|
||||
- Metric
|
||||
- Log
|
||||
|
||||
---
|
||||
|
||||
## 4. Monitoring chi tiết theo từng tầng
|
||||
|
||||
### 4.1 Ingestion Layer
|
||||
|
||||
**Theo dõi:**
|
||||
- Số file quét / phút
|
||||
- Delta sync success rate
|
||||
- File fail theo loại lỗi
|
||||
|
||||
**Cảnh báo khi:**
|
||||
- Delta token không cập nhật > N giờ
|
||||
- Lỗi permission tăng đột biến
|
||||
|
||||
---
|
||||
|
||||
### 4.2 Extraction / OCR Layer
|
||||
|
||||
**Theo dõi:**
|
||||
- Thời gian OCR / trang
|
||||
- OCR failure rate
|
||||
- Queue length
|
||||
|
||||
**Cảnh báo khi:**
|
||||
- OCR latency vượt ngưỡng
|
||||
- OCR fail liên tục cùng 1 file type
|
||||
|
||||
---
|
||||
|
||||
### 4.3 Index / Search Layer
|
||||
|
||||
**Theo dõi:**
|
||||
- Query latency (p50/p95)
|
||||
- Index size
|
||||
- Search error rate
|
||||
|
||||
**Cảnh báo khi:**
|
||||
- Query > SLA
|
||||
- Index out-of-sync
|
||||
|
||||
---
|
||||
|
||||
### 4.4 RAG Chat Layer
|
||||
|
||||
**Theo dõi:**
|
||||
- Số câu hỏi / ngày
|
||||
- % câu trả lời "không tìm thấy dữ liệu"
|
||||
- Thời gian phản hồi
|
||||
|
||||
**Cảnh báo khi:**
|
||||
- Error LLM
|
||||
- Citation missing
|
||||
|
||||
---
|
||||
|
||||
## 5. KPI & Quality Metrics
|
||||
|
||||
### 5.1 KPI kỹ thuật
|
||||
- Ingestion success rate ≥ 99%
|
||||
- OCR success rate ≥ 95%
|
||||
- Search latency ≤ 3s
|
||||
|
||||
### 5.2 KPI người dùng
|
||||
- Query có kết quả hữu ích ≥ X%
|
||||
- Click vào tài liệu gốc ≥ Y%
|
||||
|
||||
---
|
||||
|
||||
## 6. Alerting & Incident Response
|
||||
|
||||
### 6.1 Nguyên tắc
|
||||
- Alert phải **actionable**
|
||||
- Có owner rõ ràng
|
||||
|
||||
### 6.2 Incident Flow
|
||||
```text
|
||||
Detect → Triage → Mitigate → Root cause → Post-mortem
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. Logging & Audit Trail
|
||||
|
||||
### 7.1 Log bắt buộc
|
||||
- Ingestion log (file-level)
|
||||
- Search log (query-level)
|
||||
- Chat log (question, context, answer, citation)
|
||||
|
||||
### 7.2 Audit sử dụng khi:
|
||||
- Khiếu nại kết quả AI
|
||||
- Compliance / kiểm toán
|
||||
|
||||
---
|
||||
|
||||
## 8. Data Governance & Compliance
|
||||
|
||||
### 8.1 Nguyên tắc dữ liệu
|
||||
- File gốc không rời SharePoint
|
||||
- Không lưu dữ liệu ngoài phạm vi cho phép
|
||||
|
||||
### 8.2 Retention
|
||||
- Metadata & log theo chính sách công ty
|
||||
- Cho phép purge theo yêu cầu
|
||||
|
||||
---
|
||||
|
||||
## 9. Model / Prompt Governance
|
||||
|
||||
### 9.1 Versioning
|
||||
- Prompt phải có version
|
||||
- Model phải có version
|
||||
|
||||
### 9.2 Thay đổi phải:
|
||||
- Có test
|
||||
- Có rollback plan
|
||||
|
||||
---
|
||||
|
||||
## 10. User Feedback Loop
|
||||
|
||||
### 10.1 Thu thập feedback
|
||||
- Nút "Câu trả lời hữu ích / không hữu ích"
|
||||
- Comment ngắn
|
||||
|
||||
### 10.2 Sử dụng feedback để:
|
||||
- Điều chỉnh prompt
|
||||
- Điều chỉnh search ranking
|
||||
|
||||
---
|
||||
|
||||
## 11. Backup, Rollback & DR
|
||||
|
||||
- Backup index định kỳ
|
||||
- Có thể rebuild index từ Extraction output
|
||||
- DR plan cho:
|
||||
- OpenSearch
|
||||
- Metadata DB
|
||||
|
||||
---
|
||||
|
||||
## 12. Phân quyền vận hành (Ops Roles)
|
||||
|
||||
| Role | Trách nhiệm |
|
||||
|----|-------------|
|
||||
| System Admin | Hạ tầng |
|
||||
| Data Admin | Ingestion/Search |
|
||||
| AI Admin | Prompt/Model |
|
||||
| Auditor | Log/Compliance |
|
||||
|
||||
---
|
||||
|
||||
## 13. Checklist vận hành định kỳ
|
||||
|
||||
### Hàng ngày
|
||||
✅ Ingestion health
|
||||
✅ OCR queue
|
||||
|
||||
### Hàng tuần
|
||||
✅ Re-index test
|
||||
✅ Permission sync
|
||||
|
||||
### Hàng tháng
|
||||
✅ Prompt review
|
||||
✅ Compliance review
|
||||
|
||||
---
|
||||
|
||||
*Kết thúc Operations & Governance Playbook. Đây là file hoàn thiện hệ thống ở mức enterprise.*
|
||||
130
doc/8.EndToEnd-Processing-Flows-Bullets.md
Normal file
130
doc/8.EndToEnd-Processing-Flows-Bullets.md
Normal file
@@ -0,0 +1,130 @@
|
||||
# 8.EndToEnd-Processing-Flows-Bullets.md
|
||||
|
||||
> File này liệt kê **TOÀN BỘ các luồng xử lý cần thiết** để triển khai và mở rộng hệ thống.
|
||||
> Dạng **gạch đầu dòng**, dùng như **bản đồ tư duy kỹ thuật**, hoặc checklist khi mở rộng.
|
||||
|
||||
---
|
||||
|
||||
## A. Luồng Ingestion
|
||||
|
||||
- Load config site / library
|
||||
- Authenticate Graph (app-only)
|
||||
- First full delta snapshot
|
||||
- Persist delta token
|
||||
- Poll delta định kỳ
|
||||
- Detect create / update / delete
|
||||
- Fetch metadata
|
||||
- Fetch & flatten permissions
|
||||
- Decide eligible file
|
||||
- Emit job downstream
|
||||
|
||||
---
|
||||
|
||||
## B. Luồng Permission
|
||||
|
||||
- Resolve direct users
|
||||
- Resolve AAD groups
|
||||
- Expand nested groups
|
||||
- Cache membership
|
||||
- Attach ACL to file/chunk
|
||||
|
||||
---
|
||||
|
||||
## C. Luồng Extraction
|
||||
|
||||
- Receive file job
|
||||
- Detect file type
|
||||
- Detect scan vs text PDF
|
||||
- OCR per page (if needed)
|
||||
- Convert to Markdown
|
||||
- Insert page markers
|
||||
- Normalize text
|
||||
- Remove noise
|
||||
|
||||
---
|
||||
|
||||
## D. Luồng Chunking
|
||||
|
||||
- Split by heading
|
||||
- Split by page
|
||||
- Validate token length
|
||||
- Attach page range
|
||||
- Attach source URL
|
||||
|
||||
---
|
||||
|
||||
## E. Luồng Indexing
|
||||
|
||||
- Validate mapping version
|
||||
- Generate embedding
|
||||
- Attach ACL
|
||||
- Index chunk
|
||||
- Remove old chunks (on update)
|
||||
|
||||
---
|
||||
|
||||
## F. Luồng Search
|
||||
|
||||
- Receive query
|
||||
- Resolve user identity
|
||||
- Resolve user groups
|
||||
- Hybrid search
|
||||
- Apply ACL filter
|
||||
- Score & rank
|
||||
- Highlight text
|
||||
- Return results
|
||||
|
||||
---
|
||||
|
||||
## G. Luồng RAG Chat
|
||||
|
||||
- Receive question
|
||||
- Decide Search vs Chat
|
||||
- Retrieve top K chunks
|
||||
- Build context
|
||||
- Enforce token budget
|
||||
- Generate answer
|
||||
- Attach citations
|
||||
- Return answer
|
||||
|
||||
---
|
||||
|
||||
## H. Luồng Feedback
|
||||
|
||||
- Collect user feedback
|
||||
- Store feedback
|
||||
- Aggregate metrics
|
||||
- Feed prompt tuning
|
||||
- Feed ranking tuning
|
||||
|
||||
---
|
||||
|
||||
## I. Luồng Ops & Monitoring
|
||||
|
||||
- Health check all services
|
||||
- Collect metrics
|
||||
- Trigger alerts
|
||||
- Incident handling
|
||||
- Post-mortem
|
||||
|
||||
---
|
||||
|
||||
## J. Luồng Governance & Change
|
||||
|
||||
- Prompt version change
|
||||
- Model version change
|
||||
- Embedding change
|
||||
- Re-index strategy
|
||||
- Rollback
|
||||
|
||||
---
|
||||
|
||||
## Cách sử dụng file này
|
||||
|
||||
- Dùng làm checklist triển khai
|
||||
- Dùng để chia task cho AI agent
|
||||
- Dùng làm reference mở rộng hệ thống
|
||||
|
||||
---
|
||||
|
||||
*File này intentionally không chi tiết – nó là xương sống logic cho mọi mở rộng sau này.*
|
||||
163
doc/9.Appendix-Vietnamese-OCR-Strategy.md
Normal file
163
doc/9.Appendix-Vietnamese-OCR-Strategy.md
Normal file
@@ -0,0 +1,163 @@
|
||||
# 9.Appendix-Vietnamese-OCR-Strategy.md
|
||||
|
||||
> **Phụ lục chiến lược OCR Tiếng Việt** cho toàn bộ hệ thống SharePoint → Search → RAG.
|
||||
>
|
||||
> ⚠️ **LƯU Ý QUAN TRỌNG**
|
||||
> - File này là **phụ lục độc lập**, **KHÔNG chỉnh sửa** các file 1–6.
|
||||
> - Dùng để:
|
||||
> - Thống nhất nhận thức kỹ thuật về OCR tiếng Việt
|
||||
> - Làm tài liệu tham chiếu khi triển khai / audit / mở rộng
|
||||
> - Tránh tranh luận lại từ đầu khi đổi AI agent hoặc dev
|
||||
|
||||
---
|
||||
|
||||
## 1. Khẳng định phạm vi ngôn ngữ
|
||||
|
||||
- **~99% tài liệu là Tiếng Việt (có dấu)**
|
||||
- Chủ yếu: văn bản hành chính, hợp đồng, quy định, scan nhiều đời
|
||||
- Yêu cầu:
|
||||
- Giữ **đúng dấu tiếng Việt**
|
||||
- Chấp nhận được với search ngữ nghĩa & RAG
|
||||
|
||||
➡️ OCR tiếng Việt được coi là **constraint nền**, không phải optional.
|
||||
|
||||
---
|
||||
|
||||
## 2. Vì sao OCR tiếng Việt khó hơn OCR tiếng Anh?
|
||||
|
||||
- Tiếng Việt có:
|
||||
- Dấu thanh (sắc, huyền, hỏi, ngã, nặng)
|
||||
- Dấu phụ (â, ê, ô, ă, ơ, ư, đ)
|
||||
- Sai dấu = **đổi nghĩa hoàn toàn**
|
||||
- Các engine OCR chung thường:
|
||||
- Nhận đúng chữ cái
|
||||
- **Sai hoặc rơi dấu** trong scan mờ
|
||||
|
||||
Nghiên cứu về Vietnamese Document Recognition chỉ ra đây là vấn đề cố hữu nhiều năm citeturn12search39.
|
||||
|
||||
---
|
||||
|
||||
## 3. Đánh giá các engine OCR phổ biến cho tiếng Việt (2025–2026)
|
||||
|
||||
### 3.1 Tesseract (vie.traineddata)
|
||||
|
||||
- ✅ Dễ triển khai, chạy CPU
|
||||
- ❌ Độ chính xác dấu **không ổn định** với scan thực tế
|
||||
- ❌ Không phù hợp cho văn bản pháp lý, hợp đồng
|
||||
|
||||
Kết luận: **KHÔNG đủ** làm engine chính cho hệ thống này citeturn12search43turn12search44.
|
||||
|
||||
---
|
||||
|
||||
### 3.2 EasyOCR
|
||||
|
||||
- ✅ Setup nhanh
|
||||
- ❌ Nhận dạng tiếng Việt chỉ ở mức trung bình
|
||||
- ❌ Không tối ưu cho tài liệu nhiều trang
|
||||
|
||||
Kết luận: chỉ dùng thử nghiệm, **không dùng production** cho tiếng Việt.
|
||||
|
||||
---
|
||||
|
||||
### 3.3 PaddleOCR (base model)
|
||||
|
||||
- ✅ Text detection rất tốt
|
||||
- ✅ Xử lý layout, xoay, nghiêng tốt
|
||||
- ❌ Text recognition tiếng Việt **chưa tối ưu nếu dùng model mặc định**
|
||||
|
||||
Được đánh giá cao hơn Tesseract nhưng cần **nâng cấp recognition** citeturn12search43turn12search46.
|
||||
|
||||
---
|
||||
|
||||
### 3.4 PaddleOCR + VietOCR (Khuyến nghị chính)
|
||||
|
||||
**Cấu hình thực tế được cộng đồng Việt Nam sử dụng nhiều nhất**:
|
||||
|
||||
```
|
||||
Text Detection : PaddleOCR (DB / SAST)
|
||||
Text Recognition : VietOCR (Transformer, tiếng Việt có dấu)
|
||||
```
|
||||
|
||||
Ưu điểm:
|
||||
- ✅ Nhận dạng tiếng Việt có dấu **tốt nhất trong open‑source**
|
||||
- ✅ Chạy on‑prem
|
||||
- ✅ Có thể fine‑tune theo domain
|
||||
|
||||
Đây là pipeline được dùng trong nhiều dự án OCR tiếng Việt thực tế citeturn12search36turn12search41.
|
||||
|
||||
---
|
||||
|
||||
### 3.5 Fine‑tuned PaddleOCR cho tiếng Việt (Advanced)
|
||||
|
||||
- Fine‑tune detection + recognition bằng dataset tiếng Việt
|
||||
- Có thể đạt độ chính xác rất cao cho từng domain (hành chính, y tế…)
|
||||
|
||||
Nghiên cứu và repo gần đây cho thấy hiệu quả rõ rệt khi fine‑tune PaddleOCR cho VN citeturn12search52turn12search54.
|
||||
|
||||
⚠️ Tuy nhiên:
|
||||
- Tốn effort huấn luyện
|
||||
- **KHÔNG cần làm ngay ở phase đầu**
|
||||
|
||||
---
|
||||
|
||||
## 4. Mức độ chính xác thực tế có thể kỳ vọng
|
||||
|
||||
| Chất lượng scan | OCR tiếng Việt tốt |
|
||||
|---|---|
|
||||
| Scan rõ, font chuẩn | 97–99% |
|
||||
| Scan nhiều đời | 90–95% |
|
||||
| Scan rất xấu | Không OCR nào cứu hoàn toàn |
|
||||
|
||||
➡️ Vì vậy hệ thống **không được phụ thuộc 100% vào OCR**.
|
||||
|
||||
---
|
||||
|
||||
## 5. OCR Tiếng Việt trong kiến trúc hiện tại (đã được tính trước)
|
||||
|
||||
Kiến trúc hệ thống **không giả định OCR hoàn hảo**:
|
||||
|
||||
| Vấn đề OCR | Cách kiến trúc xử lý |
|
||||
|---|---|
|
||||
| Sai 1 từ | Chunk nhỏ, search vẫn trúng |
|
||||
| Sai dấu | Search hybrid + semantic |
|
||||
| OCR fail | File bị đánh cờ, không đưa vào RAG |
|
||||
| OCR kém | Người dùng mở file gốc |
|
||||
|
||||
➡️ Đây là **thiết kế có chủ đích**, không phải workaround.
|
||||
|
||||
---
|
||||
|
||||
## 6. Chiến lược triển khai OCR tiếng Việt theo phase
|
||||
|
||||
### Phase 1 – An toàn, triển khai nhanh
|
||||
- PaddleOCR (Detection) + VietOCR (Recognition)
|
||||
- OCR page‑wise
|
||||
- Lưu confidence theo trang
|
||||
|
||||
### Phase 2 – Tối ưu dần
|
||||
- Tune preprocessing (deskew, binarization)
|
||||
- Dictionary post‑process tiếng Việt
|
||||
|
||||
### Phase 3 – Khi thực sự cần
|
||||
- Fine‑tune PaddleOCR/VietOCR theo domain
|
||||
|
||||
---
|
||||
|
||||
## 7. Nguyên tắc vận hành bắt buộc
|
||||
|
||||
- OCR < threshold → **KHÔNG đưa vào RAG Chat**
|
||||
- OCR output luôn link về file gốc
|
||||
- OCR có log & audit
|
||||
|
||||
---
|
||||
|
||||
## 8. Kết luận phụ lục
|
||||
|
||||
- ✅ OCR tiếng Việt **đã được tính đến từ đầu**
|
||||
- ✅ Có giải pháp **đủ tốt cho production**
|
||||
- ❌ Không có OCR tiếng Việt "100% đúng cho mọi trường hợp"
|
||||
- ✅ Kiến trúc đã được thiết kế để **chịu sai có kiểm soát**
|
||||
|
||||
---
|
||||
|
||||
*Phụ lục này dùng để tham chiếu lâu dài khi nói về OCR tiếng Việt trong hệ thống.*
|
||||
371
doc/Entra-Graph-AppOnly-Checklist-and-Test-Notes.md
Normal file
371
doc/Entra-Graph-AppOnly-Checklist-and-Test-Notes.md
Normal file
@@ -0,0 +1,371 @@
|
||||
# Ghi chú tránh lặp lại sai sót — Entra App + Microsoft Graph app-only cho SharePoint Ingestion
|
||||
|
||||
## 1) Tóm tắt sự cố đã gặp
|
||||
|
||||
### Hiện tượng
|
||||
- Lấy token **thành công** bằng `client_credentials`.
|
||||
- Token có các claim hợp lệ kiểu app-only:
|
||||
- `aud = https://graph.microsoft.com`
|
||||
- `idtyp = app`
|
||||
- Nhưng gọi các API Graph như:
|
||||
- `GET /sites/{hostname}`
|
||||
- `GET /sites/{hostname}:/{server-relative-path}`
|
||||
đều bị **401 Unauthorized**.
|
||||
|
||||
### Nguyên nhân gốc
|
||||
App Registration đã được cấp **Delegated permissions** thay vì **Application permissions**.
|
||||
|
||||
Cụ thể lúc xảy ra lỗi, app đang có kiểu quyền như:
|
||||
- `Files.Read.All` → **Delegated**
|
||||
- `Sites.Read.All` → **Delegated**
|
||||
- `User.Read` → **Delegated**
|
||||
|
||||
Trong khi luồng đang dùng là:
|
||||
- **OAuth 2.0 client credentials flow**
|
||||
- **app-only / daemon / service-to-service**
|
||||
- **không có user đăng nhập interactive**
|
||||
|
||||
=> Kết quả: token app-only **không có `roles`**, nên Microsoft Graph không chấp nhận token cho các API cần application permissions.
|
||||
|
||||
---
|
||||
|
||||
## 2) Bài học rút ra (phải kiểm tra trước khi test Graph)
|
||||
|
||||
### Quy tắc số 1
|
||||
Nếu dùng **client credentials flow** thì **bắt buộc** phải cấp quyền ở dạng:
|
||||
- **Microsoft Graph → Application permissions**
|
||||
|
||||
**Không dùng Delegated permissions** cho bài toán ingestion app-only.
|
||||
|
||||
### Quy tắc số 2
|
||||
Sau khi sửa permission trong Entra App:
|
||||
1. Bấm **Grant admin consent**
|
||||
2. Lấy **token mới hoàn toàn**
|
||||
3. Decode token và **kiểm tra `roles`** trước khi gọi Graph
|
||||
|
||||
### Quy tắc số 3
|
||||
Nếu token app-only **không có `roles`**, thì **không test Graph tiếp**.
|
||||
Phải quay lại kiểm tra:
|
||||
- Permission type có phải **Application** không
|
||||
- Có phải **Microsoft Graph** không
|
||||
- Đã **Grant admin consent** chưa
|
||||
- Có cần đợi propagation vài phút không
|
||||
|
||||
---
|
||||
|
||||
## 3) Cấu hình đúng cho PoC hiện tại
|
||||
|
||||
### Tối thiểu cần có trong Entra App
|
||||
#### Microsoft Graph → Application permissions
|
||||
- `Sites.Read.All`
|
||||
- `Files.Read.All`
|
||||
|
||||
### Không cần cho app-only ingestion hiện tại
|
||||
- `User.Read` (Delegated)
|
||||
- Interactive login
|
||||
- Redirect URI cho user login
|
||||
|
||||
---
|
||||
|
||||
## 4) Checklist fail-fast trước khi test Graph
|
||||
|
||||
## Checklist nhanh
|
||||
- [ ] App dùng **client credentials flow**
|
||||
- [ ] API permissions nằm dưới **Microsoft Graph**
|
||||
- [ ] Permission type là **Application**
|
||||
- [ ] Có `Sites.Read.All`
|
||||
- [ ] Có `Files.Read.All`
|
||||
- [ ] Đã **Grant admin consent**
|
||||
- [ ] Đã lấy **token mới** sau khi sửa permission
|
||||
- [ ] Token decode ra có `roles`
|
||||
- [ ] `roles` chứa ít nhất:
|
||||
- `Sites.Read.All`
|
||||
- `Files.Read.All`
|
||||
|
||||
Nếu **một trong các dòng trên fail**, không chạy tiếp phần test Graph site/drive.
|
||||
|
||||
---
|
||||
|
||||
## 5) Script test hoàn chỉnh (đã thêm guard để tránh lặp lỗi)
|
||||
|
||||
> Script này làm đúng 4 việc:
|
||||
> 1. Lấy token mới
|
||||
> 2. Decode token
|
||||
> 3. **Kiểm tra `roles` trước**
|
||||
> 4. Chỉ khi roles đúng mới test Graph site endpoints
|
||||
|
||||
```powershell
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
# ==========================================
|
||||
# Điền thông tin tại đây
|
||||
# ==========================================
|
||||
$TenantId = "<TENANT_ID_GUID>"
|
||||
$ClientId = "<CLIENT_ID_GUID>"
|
||||
$ClientSecret = "<CLIENT_SECRET_VALUE>"
|
||||
$SharePointHost = "285pdg.sharepoint.com"
|
||||
$SitePath = "/sites/poc_system"
|
||||
# ==========================================
|
||||
|
||||
function Get-GraphToken {
|
||||
param(
|
||||
[string]$TenantId,
|
||||
[string]$ClientId,
|
||||
[string]$ClientSecret
|
||||
)
|
||||
|
||||
$tokenUrl = "https://login.microsoftonline.com/" + $TenantId + "/oauth2/v2.0/token"
|
||||
|
||||
$body = @{
|
||||
client_id = $ClientId
|
||||
client_secret = $ClientSecret
|
||||
scope = "https://graph.microsoft.com/.default"
|
||||
grant_type = "client_credentials"
|
||||
}
|
||||
|
||||
return Invoke-RestMethod `
|
||||
-Method Post `
|
||||
-Uri $tokenUrl `
|
||||
-ContentType "application/x-www-form-urlencoded" `
|
||||
-Body $body
|
||||
}
|
||||
|
||||
function Decode-JwtPayload {
|
||||
param([string]$Jwt)
|
||||
|
||||
$parts = $Jwt.Split('.')
|
||||
if ($parts.Length -lt 2) {
|
||||
throw "JWT không hợp lệ."
|
||||
}
|
||||
|
||||
$payload = $parts[1]
|
||||
|
||||
switch ($payload.Length % 4) {
|
||||
2 { $payload += '==' }
|
||||
3 { $payload += '=' }
|
||||
}
|
||||
|
||||
$payload = $payload.Replace('-', '+').Replace('_', '/')
|
||||
$bytes = [System.Convert]::FromBase64String($payload)
|
||||
$json = [System.Text.Encoding]::UTF8.GetString($bytes)
|
||||
|
||||
return $json | ConvertFrom-Json
|
||||
}
|
||||
|
||||
function Invoke-GraphGet {
|
||||
param(
|
||||
[string]$Url,
|
||||
[string]$AccessToken,
|
||||
[string]$Label
|
||||
)
|
||||
|
||||
Write-Host ""
|
||||
Write-Host ("=== " + $Label + " ===") -ForegroundColor Cyan
|
||||
Write-Host $Url -ForegroundColor DarkGray
|
||||
|
||||
$headers = @{
|
||||
Authorization = "Bearer " + $AccessToken
|
||||
}
|
||||
|
||||
try {
|
||||
$resp = Invoke-WebRequest `
|
||||
-Method Get `
|
||||
-Uri $Url `
|
||||
-Headers $headers `
|
||||
-UseBasicParsing
|
||||
|
||||
Write-Host "OK" -ForegroundColor Green
|
||||
Write-Host ("HTTP " + [int]$resp.StatusCode) -ForegroundColor Green
|
||||
|
||||
if ($resp.Content) {
|
||||
$json = $resp.Content | ConvertFrom-Json
|
||||
$json | ConvertTo-Json -Depth 10
|
||||
return $json
|
||||
}
|
||||
|
||||
return $null
|
||||
}
|
||||
catch {
|
||||
Write-Host "FAILED" -ForegroundColor Red
|
||||
Write-Host $_.Exception.Message -ForegroundColor Red
|
||||
|
||||
if ($_.Exception.Response -ne $null) {
|
||||
$resp = $_.Exception.Response
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "Status code:" -ForegroundColor Yellow
|
||||
try {
|
||||
Write-Host ([int]$resp.StatusCode)
|
||||
}
|
||||
catch {
|
||||
Write-Host "Không đọc được StatusCode"
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "WWW-Authenticate:" -ForegroundColor Yellow
|
||||
try {
|
||||
Write-Host $resp.Headers["WWW-Authenticate"]
|
||||
}
|
||||
catch {
|
||||
Write-Host "Không có WWW-Authenticate header"
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "Response body:" -ForegroundColor Yellow
|
||||
try {
|
||||
$stream = $resp.GetResponseStream()
|
||||
$reader = New-Object System.IO.StreamReader($stream)
|
||||
$bodyText = $reader.ReadToEnd()
|
||||
Write-Host $bodyText
|
||||
}
|
||||
catch {
|
||||
Write-Host "Không đọc được response detail."
|
||||
}
|
||||
}
|
||||
|
||||
return $null
|
||||
}
|
||||
}
|
||||
|
||||
# =======================================================
|
||||
# 1) Lấy token mới
|
||||
# =======================================================
|
||||
$tokenResponse = Get-GraphToken `
|
||||
-TenantId $TenantId `
|
||||
-ClientId $ClientId `
|
||||
-ClientSecret $ClientSecret
|
||||
|
||||
$accessToken = $tokenResponse.access_token
|
||||
|
||||
Write-Host "TOKEN OK" -ForegroundColor Green
|
||||
Write-Host ("token_type : " + $tokenResponse.token_type)
|
||||
Write-Host ("expires_in : " + $tokenResponse.expires_in)
|
||||
|
||||
# =======================================================
|
||||
# 2) Decode token + kiểm tra claims quan trọng
|
||||
# =======================================================
|
||||
$claims = Decode-JwtPayload -Jwt $accessToken
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "=== TOKEN CLAIMS ===" -ForegroundColor Cyan
|
||||
Write-Host ("aud : " + $claims.aud)
|
||||
Write-Host ("appid : " + $claims.appid)
|
||||
|
||||
if ($claims.PSObject.Properties.Name -contains "idtyp") {
|
||||
Write-Host ("idtyp : " + $claims.idtyp)
|
||||
}
|
||||
|
||||
$roles = @()
|
||||
if ($claims.PSObject.Properties.Name -contains "roles") {
|
||||
$roles = @($claims.roles)
|
||||
Write-Host "roles:" -ForegroundColor Yellow
|
||||
$roles | ForEach-Object { Write-Host (" - " + $_) }
|
||||
}
|
||||
else {
|
||||
Write-Host "roles: <KHÔNG CÓ>" -ForegroundColor Red
|
||||
}
|
||||
|
||||
# =======================================================
|
||||
# 3) Guard bắt buộc: nếu không có roles đúng thì stop luôn
|
||||
# =======================================================
|
||||
$hasSitesRead = $roles -contains "Sites.Read.All"
|
||||
$hasFilesRead = $roles -contains "Files.Read.All"
|
||||
|
||||
if (-not $hasSitesRead) {
|
||||
Write-Host ""
|
||||
Write-Host "STOP: Token chưa có role 'Sites.Read.All'." -ForegroundColor Red
|
||||
Write-Host "=> Kiểm tra lại Microsoft Graph -> Application permissions -> Sites.Read.All -> Grant admin consent." -ForegroundColor Yellow
|
||||
return
|
||||
}
|
||||
|
||||
if (-not $hasFilesRead) {
|
||||
Write-Host ""
|
||||
Write-Host "WARNING: Token chưa có role 'Files.Read.All'." -ForegroundColor Yellow
|
||||
Write-Host "=> Site test có thể pass, nhưng drive/delta về sau sẽ fail." -ForegroundColor Yellow
|
||||
}
|
||||
|
||||
# =======================================================
|
||||
# 4) TEST 1 - GET /sites/{hostname}
|
||||
# =======================================================
|
||||
$rootByHostUrl = "https://graph.microsoft.com/v1.0/sites/" + $SharePointHost + "?`$select=id,webUrl"
|
||||
$rootSite = Invoke-GraphGet `
|
||||
-Url $rootByHostUrl `
|
||||
-AccessToken $accessToken `
|
||||
-Label "TEST 1 - GET /sites/{hostname}"
|
||||
|
||||
# =======================================================
|
||||
# 5) TEST 2 - GET /sites/{hostname}:/{server-relative-path}
|
||||
# =======================================================
|
||||
$siteRef = $SharePointHost + ":" + $SitePath
|
||||
$resolveSiteUrl = "https://graph.microsoft.com/v1.0/sites/" + $siteRef + "?`$select=id,displayName,webUrl"
|
||||
$resolvedSite = Invoke-GraphGet `
|
||||
-Url $resolveSiteUrl `
|
||||
-AccessToken $accessToken `
|
||||
-Label "TEST 2 - GET /sites/{hostname}:/{server-relative-path}"
|
||||
|
||||
# =======================================================
|
||||
# 6) Summary
|
||||
# =======================================================
|
||||
Write-Host ""
|
||||
Write-Host "=== SUMMARY ===" -ForegroundColor Cyan
|
||||
|
||||
if ($null -ne $rootSite) {
|
||||
Write-Host "TEST 1: PASS" -ForegroundColor Green
|
||||
}
|
||||
else {
|
||||
Write-Host "TEST 1: FAIL" -ForegroundColor Red
|
||||
}
|
||||
|
||||
if ($null -ne $resolvedSite) {
|
||||
Write-Host "TEST 2: PASS" -ForegroundColor Green
|
||||
}
|
||||
else {
|
||||
Write-Host "TEST 2: FAIL" -ForegroundColor Red
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6) Kỳ vọng đúng sau khi sửa quyền
|
||||
|
||||
### Token claim đúng
|
||||
```text
|
||||
aud : https://graph.microsoft.com
|
||||
appid : <app-id>
|
||||
idtyp : app
|
||||
roles:
|
||||
- Sites.Read.All
|
||||
- Files.Read.All
|
||||
```
|
||||
|
||||
### Test site đúng
|
||||
- `TEST 1 - GET /sites/{hostname}` → PASS
|
||||
- `TEST 2 - GET /sites/{hostname}:/{server-relative-path}` → PASS
|
||||
|
||||
---
|
||||
|
||||
## 7) Ghi chú vận hành nội bộ
|
||||
|
||||
### Khi nào được đi tiếp sang ingestion skeleton?
|
||||
Chỉ khi đạt đủ 3 điều kiện:
|
||||
1. Token có `roles`
|
||||
2. `TEST 1` pass
|
||||
3. `TEST 2` pass
|
||||
|
||||
### Nếu token vẫn không có `roles`
|
||||
- Kiểm tra lại **Type** của permission có phải **Application** không
|
||||
- Kiểm tra lại permission có nằm dưới **Microsoft Graph** không
|
||||
- Kiểm tra đã bấm **Grant admin consent** chưa
|
||||
- Đợi vài phút rồi lấy **token mới** lần nữa
|
||||
|
||||
---
|
||||
|
||||
## 8) Tên lỗi nội bộ để nhớ
|
||||
|
||||
> **Sai lầm đã gặp:**
|
||||
> “Dùng `client_credentials` nhưng lại cấp **Delegated permissions** trong App Registration.”
|
||||
|
||||
### Cách nhớ nhanh
|
||||
- **App-only** → **Application permissions**
|
||||
- **Có user login** → **Delegated permissions**
|
||||
|
||||
Reference in New Issue
Block a user