แผนการนำเข้าข้อมูล (Data Ingestion Plan)
อ้างอิง TOR: ข้อ 4.5.1 (จัดทำแผนการนำเข้าข้อมูล) และข้อ 7.2.4 (เอกสารส่งมอบงวดที่ 2) ประกอบภาคผนวก ก ข้อ 4.6–4.8 และภาคผนวก ข.1 ฉบับ: 1.0 — วันที่ 3 ตุลาคม พ.ศ. 2569
แผนนี้อธิบายกระบวนการนำเข้าเอกสารเข้าสู่ฐานองค์ความรู้ตามที่ implement จริงในระบบ (
src/server/ingestion/*,src/domain/ingestion/*) สถานะความครอบคลุมล่าสุดที่วัดจากฐานข้อมูลดูได้ที่/documents/ingestion-report(สร้างอัตโนมัติด้วยnpm run report:ingestion) และแบบสดที่/admin/knowledge-base
1. วัตถุประสงค์และขอบเขต
- นำเข้าพระไตรปิฎกและอรรถกถาแปล ฉบับมหามกุฏราชวิทยาลัย 91 เล่ม (ภาคผนวก ข.1: พระวินัยปิฎก เล่ม 1–10, พระสุตตันตปิฎก เล่ม 11–74, พระอภิธรรมปิฎก เล่ม 75–91) และเอกสารประกอบ (ฎีกา ตำราร่วมสมัย ธรรมะพ่อแม่ครูอาจารย์)
- ทุก chunk ต้องมี metadata ครบพอสร้าง Citation รูปแบบมาตรฐานและตรวจสอบย้อนกลับถึงเล่ม/ข้อ/หน้าได้ (ก.3.6.3, ก.4.8.3)
- ห้ามตัดตอนเนื้อหาพระไตรปิฎกกลางข้อ (ก.4.6.2, ก.4.8.2)
- ป้องกันคำสั่งแฝงในเอกสาร (indirect prompt injection) ก่อนเข้าดัชนี (ก.4.4.1)
- ปรับดัชนีได้อัตโนมัติผ่าน pipeline โดยไม่ต้อง redeploy (4.5.3, ก.4.7.3, ก.6.3.2)
แนวทางตาม TOR ภาคผนวก ข: ระยะแรกใช้พระไตรปิฎกฉบับออนไลน์ แล้วสลับเป็นฉบับ มมร. 91 เล่มเมื่อมหาวิทยาลัยส่งมอบไฟล์ (หรือเมื่อเว็บไซต์คลังปัญญา Dhammaverse พร้อมเป็นแหล่งข้อมูล)
2. รูปแบบไฟล์ที่รองรับ (Parsers)
ตัวแยกวิเคราะห์อยู่ที่ src/server/ingestion/parsers/index.ts (parseFile เลือกตามนามสกุลไฟล์) ขนาดไฟล์อัปโหลดสูงสุด 20MB (MAX_UPLOAD_BYTES ใน src/application/ingestion/kb-admin.ts)
| นามสกุล | MIME | ไลบรารี | พฤติกรรม |
|---|---|---|---|
.pdf | application/pdf | unpdf (extractText, แยกหน้า) | ดึงข้อความรายหน้าแล้วต่อกัน; ถ้าไม่มีชั้นข้อความเลยคืนคำเตือน “PDF ไม่มีชั้นข้อความ (อาจเป็นไฟล์สแกน ต้อง OCR ก่อนนำเข้า)” และงานล้มเหลวพร้อมข้อความนี้ |
.docx | application/vnd.openxmlformats-officedocument.wordprocessingml.document | mammoth.extractRawText | ข้อความล้วน + คำเตือนของ mammoth (สูงสุด 5 รายการ) |
.xml (TEI) | application/xml | fast-xml-parser (preserveOrder) | <div type="volume" n> → เล่ม, <div type="item" n> → ข้อ, <pb n> → หน้า แปลงเป็น marker [เล่ม N][ข้อ N][หน้า N]; <pb> กลางข้อสร้าง marker ข้อเดิมหน้าใหม่ (ChunkingPolicy รวมเป็น chunk เดียวและเก็บหน้าเริ่ม–หน้าจบ); ข้าม <note> และ <teiHeader>; ถ้าไม่พบ <div type="item"> นำเข้าแบบข้อความทั่วไปพร้อมคำเตือน |
.txt, .md | text/plain, text/markdown | อ่าน UTF-8 (ตัด BOM) | ไฟล์ seed .md ถูกตัด frontmatter ด้วย stripFrontmatter() ก่อนนำเข้า |
นามสกุลอื่นถูกปฏิเสธด้วยข้อความ “ไม่รองรับไฟล์ชนิด .xxx (รองรับ PDF, TXT, TEI-XML, DOCX)” ไฟล์ตัวอย่างสำหรับทดสอบทั้ง 4 ชนิดอยู่ที่ tests/fixtures/kb/ (รวม no-text.pdf สำหรับกรณีไฟล์สแกน)
3. ขั้นตอนของ Pipeline
ไฟล์หลัก: src/server/ingestion/pipeline.ts
flowchart LR
U["อัปโหลด / seed / reindex"] --> J["IngestionJob + IngestionJobItem (queued)"]
J --> P1["parse<br/>parseFile + stripFrontmatter"]
P1 --> P2["sanitize<br/>sanitizeText"]
P2 --> UW["unwrapLines<br/>(tipitaka/atthakatha)"]
UW --> P3["chunk<br/>chunkText → ChunkingPolicy"]
P3 --> P4["embed<br/>pseudo-embedding 512 มิติ"]
P4 --> P5["index<br/>transaction Chunk + reindexDocument"]
P5 --> D["done (status indexed)"]
P1 -. error .-> F["failed + errorMsg"]
P3 -. error .-> F
Stage (IngestionJobItem.stage) | การทำงาน |
|---|---|
queued | สร้างงานด้วย createJob(type, requestedBy, docs) ชนิด ingest / reindex_all / reindex_selected / delete |
parse | อ่านไฟล์ต้นฉบับจาก sourceFile (ใต้ STORAGE_DIR ค่าเริ่มต้น storage/uploads หรือ seed/knowledge/) แล้วแยกข้อความ |
sanitize | sanitizeText() (หัวข้อ 7) และนับ removedLines |
chunk | ข้อความพระไตรปิฎกออนไลน์ที่ตัดบรรทัดกลางประโยคถูกต่อกลับด้วย unwrapLines() (ใช้ความกว้างบรรทัด p90) แล้วแบ่งด้วย chunkText() → chunkDocument(); ไฟล์ที่ marker ซ้ำหลายบล็อก (อรรถกถา/ฉบับแปลที่ผูกกับข้อเดียวกัน) แยกแต่ละบล็อกเป็น chunk ที่อ้างข้อเดียวกัน; ไม่มีเนื้อหา → ล้มเหลว “ไม่พบเนื้อหาที่นำเข้าได้ในไฟล์” |
embed | คำนวณ pseudo-embedding 512 มิติ (feature hashing FNV-1a, ปัดทศนิยม 4 ตำแหน่ง) เก็บเป็น JSON ใน Chunk.embedding เป็น cache |
index | ใน transaction เดียว: chunk ที่ลำดับและเนื้อหาเหมือนเดิม คง id เดิม (อัปเดตเฉพาะ metadata) เพื่อไม่ให้ Citation ในประวัติและ expectedRefs ของชุดทดสอบหลุด; ลบเฉพาะ chunk ที่เนื้อหาเปลี่ยน (พร้อม Citation ที่อ้างถึง) แล้วสร้างใหม่; ตั้งเอกสารเป็น indexed พร้อม chunkCount, sanitizedLines; อัปเดตดัชนีในหน่วยความจำด้วย reindexDocument() |
done / failed | บันทึก chunkCount, durationMs หรือ errorMsg |
Job runner: งานถูกต่อคิวแบบ promise chain ใน process เดียว (enqueueJob) ประมวลผลทีละ item; item ที่ล้มเหลวไม่หยุดทั้งงาน สถานะงานสุดท้ายเป็น completed (ไม่มีล้มเหลว), partial (สำเร็จบางส่วน) หรือ failed (ล้มเหลวทั้งหมด) และเมื่อมีรายการล้มเหลวระบบส่งแจ้งเตือนชนิด ingestion_failed (บันทึก AlertEmailLog หรือส่ง SMTP) — ใน Production ใช้ BullMQ + worker แยก (ingestion service ใน Helm chart)
การลบ: งานชนิด delete ถอดเอกสารออกจากดัชนีค้นหาและตั้งสถานะ deleted + deletedAt (soft delete) เอกสารที่ถูกลบแล้วไม่สามารถนำเข้า/ทำดัชนีซ้ำได้
4. นโยบายการแบ่ง Chunk (Chunking Policy)
ไฟล์: src/domain/ingestion/chunking-policy.ts (pure TypeScript ทดสอบใน tests/unit/chunking-policy.test.ts)
ค่าคงที่ (CHUNKING) | ค่า | ความหมาย |
|---|---|---|
oversizedTokens | 3,000 | เกินค่านี้ติดธง oversized แต่ ไม่แบ่ง ข้อพระไตรปิฎก |
targetTokens | 400 | ขนาดเป้าหมายของ semantic chunk |
minTokensForTopicCut | 120 | ต้องสะสมอย่างน้อยเท่านี้ก่อนตัดเพราะหัวข้อเปลี่ยน |
topicShiftCosine | 0.35 | cosine ระหว่างย่อหน้าติดกันต่ำกว่านี้ = หัวข้อเปลี่ยน |
maxHeadingChars | 200 | ข้อความก่อน marker แรกที่สั้นกว่านี้ใช้เป็นหัวข้อของ chunk แรก |
การประมาณโทเคน: ceil(จำนวนอักขระ / 3) (เหมาะกับภาษาไทย deterministic)
4.1 โหมด marker (docType tipitaka และ atthakatha)
- ค้นหา marker
[เล่ม N][ข้อ N][หน้า N](รองรับเลขไทย ๐–๙ และหน้าเว้นว่าง) - 1 ข้อ = 1 chunk: block ติดกันที่เป็น (เล่ม, ข้อ) เดียวกันถูกรวม — ข้อที่คร่อมหลายหน้าเก็บ
page(หน้าแรก) และpageEnd(หน้าสุดท้าย) - หน้า 0 หรือไม่มีหน้า →
page = null - บรรทัดหัวข้อ Markdown ท้าย block กลายเป็น
headingของข้อถัดไป - ข้อความนำหน้า marker แรกที่ยาวเกิน 200 อักขระเป็น chunk ของตัวเอง (
item = null) - ถ้าเอกสารประเภทนี้ไม่มี marker เลย ใช้โหมด semantic แทน
4.2 โหมด semantic (docType อื่น)
- แยก section ตามหัวข้อ Markdown (heading เป็นลำดับชั้น
ก > ข) - แยกย่อหน้า → ย่อหน้าที่ยาวเกิน 400 tokens แบ่งตามประโยค (
Intl.Segmenter("th", sentence)) → วรรค → อักขระ ตามลำดับ - สะสมหน่วยจนเกิน 400 tokens หรือ ตัดเมื่อหัวข้อเปลี่ยน (cosine ของ pseudo-embedding < 0.35 และสะสม ≥120 tokens) — ไม่ได้ตัดตามจำนวนโทเคนล้วน
4.3 สถิติขนาด chunk ปัจจุบัน
จากฐานข้อมูลสาธิต ณ วันที่จัดทำ (อ่านแบบ read-only): chunk ทั้งหมด 777 รายการ, ติดธง oversized 5 รายการ, ขนาดสูงสุด 17,848 tokens (ข้อพระไตรปิฎกที่ยาวมาก ยังคงเป็น chunk เดียวตาม ก.4.6.2) — ตัวเลขทางการที่สร้างอัตโนมัติอยู่ใน /documents/ingestion-report
เมื่อส่ง chunk ยาวมากเป็นบริบทให้ LLM ระบบย่อเฉพาะตอนสร้าง prompt (bestWindow() เลือกช่วงที่ตรงคำถามมากที่สุด 2,400 อักขระสำหรับถาม-ตอบ / 4,500 สำหรับ Dhamma Talk) ส่วนดัชนีและ Citation ยังอ้างข้อเต็ม
5. Metadata และรูปแบบ Citation
5.1 ฟิลด์ metadata (KnowledgeDocument / Chunk)
| ฟิลด์ | ระดับ | ตัวอย่าง | หมายเหตุ |
|---|---|---|---|
title | เอกสาร | มงคลสูตร | บังคับ |
docType | เอกสาร | tipitaka | tipitaka | atthakatha | tika | contemporary | teacher_dhamma (DOC_TYPES) |
edition | เอกสาร | ไทย, บาลี, มมร., English (Sujato, CC0) | ใช้ในวงเล็บของ citation |
pitaka | เอกสาร | vinaya | sutta | abhidhamma | |
nikaya, sutta | เอกสาร | ขุททกนิกาย ขุททกปาฐะ / มงคลสูตร | |
volume | เอกสาร/chunk | 25 | เล่มของฉบับที่นำเข้า (ฉบับหลวง 45 เล่ม สำหรับข้อมูลออนไลน์) |
mbuVolume | เอกสาร | 39 | เล่มในฉบับ มมร. 91 เล่ม — ใช้คำนวณ coverage ภาคผนวก ข |
abbreviation | เอกสาร | ขุ.ขุ. | ตัวย่อคัมภีร์สำหรับ citation |
item, page, pageEnd, heading | chunk | 5 / 3 / 3 | จาก marker |
paliAliases | เอกสาร/chunk | maṅgala|mangala sutta | คำบาลี/อังกฤษ ช่วยค้นข้ามภาษา (น้ำหนักสูงใน BM25) |
precedenceScore | เอกสาร | 1.0 | 0–2 ปรับได้ใน admin |
sourceType, sourceFile, sourceUrl, sourceNote | เอกสาร | seed / online / upload | ที่มาและหมายเหตุสิทธิ์ |
oversized, tokenCount | chunk |
5.2 รูปแบบ Citation
สร้างโดย formatCitationLabel() ใน src/domain/ai/citation.ts:
{abbreviation} ({edition}) {volume}/{item}/{page}
ตัวอย่าง: ขุ.ขุ. (ไทย) 25/5/3
- ส่วนท้ายที่ไม่มีค่าถูกตัด (ไม่มีหน้า →
25/5); ส่วนกลางที่ไม่มีค่าแสดง- - ไม่มี
abbreviationใช้titleแทน - LLM อ้างด้วย
[[cite:<chunkId>]]หรือ[[cite:<n>]]แล้วโหนดoutputGuardrailแปลงเป็น label และตัดการอ้างที่ไม่อยู่ในรายการอ้างอิง
5.3 ประเภทเอกสารและลำดับความสำคัญ (Precedence)
ค่าเริ่มต้นใน DEFAULT_PRECEDENCE (src/domain/retrieval/relevance-scoring.ts) ใช้คูณคะแนนหลัง rerank (ก.4.8.3(3)):
| docType | ความหมาย | precedence เริ่มต้น |
|---|---|---|
tipitaka | พระไตรปิฎก | 1.0 |
atthakatha | อรรถกถา | 0.9 |
tika | ฎีกา | 0.8 |
contemporary | ตำรา/พระนิพนธ์ร่วมสมัย | 0.7 |
teacher_dhamma | ธรรมะพ่อแม่ครูอาจารย์ | 0.6 |
ผู้ดูแลปรับรายเอกสารได้ (0–2) ที่ /admin/knowledge-base → แก้ metadata (PATCH /api/admin/knowledge-base/[id]) ระบบอัปเดตดัชนีในหน่วยความจำทันทีและบันทึก audit before/after
6. รูปแบบ marker และไฟล์ต้นฉบับ
ไฟล์ seed ทุกไฟล์ใน seed/knowledge/ เป็น Markdown ที่มี frontmatter บรรทัดเดียวต่อคีย์ (รายละเอียดใน scripts/data/README.md):
---
title: "มงคลสูตร"
docType: tipitaka
edition: "ไทย"
pitaka: sutta
nikaya: "ขุททกนิกาย ขุททกปาฐะ"
sutta: "มงคลสูตร"
volume: 25
mbuVolume: 39
abbreviation: "ขุ.ขุ."
sourceUrl: "https://84000.org/tipitaka/read/byitem.php?book=25&item=5"
sourceNote: "..."
paliAliases: "maṅgala|mangala sutta|..."
---
[เล่ม 25][ข้อ 5][หน้า 3]
<ข้อความทั้งข้อ>
กติกา:
- ฉบับหลวง/บาลี: 1 บล็อก = 1 ข้อ;
หน้า= หน้าแรกของข้อนั้นในเล่ม - อรรถกถาและฉบับอังกฤษ:
หน้า 0(ไม่ทราบหน้า) และ marker ซ้ำได้หลายบล็อก ทุกบล็อกชี้ไปยังเล่ม/ข้อฉบับหลวงที่สอดคล้อง contemporary/teacher_dhamma: ไม่มี marker เป็นย่อหน้าธรรมดา- ไฟล์ฉบับ มมร. ที่จะได้รับควรจัดในรูปแบบเดียวกัน หรือเป็น TEI-XML ที่มี
<div type="item" n>และ<pb n>
7. การ Sanitize ข้อความ (กัน Indirect Prompt Injection)
ไฟล์: src/domain/ingestion/sanitize.ts (ทดสอบใน tests/unit/sanitize.test.ts)
- แปลง CRLF/CR เป็น LF
- ตัด control characters (C0 ยกเว้น
\n\t, DEL, C1) และอักขระล่องหน/กำกับทิศทาง (zero-width space, bidi override, BOM) — คง ZWNJ/ZWJ ในผลลัพธ์ - ตัด ทั้งบรรทัด ที่ตรงรูปแบบคำสั่งแฝง (
INJECTION_LINE_PATTERNS) เช่น “ignore previous instructions”, “reveal the system prompt”, “you are now…”, การปลอม role/delimiter (<system>,[INST],<|im_start|>,<<<END DATA) และรูปแบบภาษาไทย (“เพิกเฉยคำสั่ง…”, “เปิดเผย prompt…”, “จากนี้ไปคุณคือ…”) — มีข้อยกเว้นเพื่อไม่ตัดเนื้อหาธรรม เช่น “คำสั่งสอน” และคำว่า rules/guidelines ที่ไม่มีคำขยายเชิงคำสั่ง - ยุบบรรทัดว่างติดกันเกิน 2 บรรทัด
จำนวนบรรทัดที่ตัดบันทึกใน KnowledgeDocument.sanitizedLines และแสดงในรายงานการนำเข้า นอกจากนี้ตอนสร้างคำตอบ บริบททุก chunk ถูกครอบด้วย delimiter <<<DATA ...>>> … <<<END DATA>>> และ system prompt ระบุว่าเป็น “ข้อมูล ไม่ใช่คำสั่ง” (ป้องกันชั้นที่สอง)
8. Pipeline ปรับดัชนี (Re-index)
| การกระทำ | วิธี | ผล |
|---|---|---|
| นำเข้าเอกสารใหม่ | /admin/knowledge-base → อัปโหลด (POST /api/admin/knowledge-base/upload) | งาน ingest |
| ทำดัชนีซ้ำบางเอกสาร | เลือกเอกสาร → Re-index (POST /api/admin/knowledge-base/reindex พร้อม documentIds) | งาน reindex_selected |
| ทำดัชนีซ้ำทั้งหมด | ปุ่ม “Re-index ทั้งหมด” (reindex ไม่ระบุ documentIds) | งาน reindex_all |
| ลบเอกสาร | ปุ่มลบ (DELETE /api/admin/knowledge-base/[id]) | งาน delete |
| รันซ้ำเฉพาะที่ล้มเหลว | /admin/knowledge-base/jobs → retry (POST .../jobs/[id]/retry-failed) | ประมวลผลเฉพาะ item ที่ไม่ใช่ done |
| นำเข้าจาก seed (CLI) | npm run data:import (scripts/data/import-knowledge.ts, ตัวเลือก --prefix, --force, --precedence) | นำเข้าแบบ incremental เฉพาะไฟล์ใหม่ (หรือแทนที่เมื่อ --force) — dev server ที่รันอยู่ต้อง rebuild index (รีสตาร์ต หรือกด Re-index) |
| สร้างคลัง seed ใหม่จากแหล่งออนไลน์ | npm run data:fetch (scripts/data/fetch_corpus.py, Python 3 standard library, มี cache) | เขียนไฟล์ seed/knowledge/*.md + _manifest.json |
ดัชนีค้นหาในหน่วยความจำ (KnowledgeIndex singleton ใน globalThis.__mbuIndex) สร้างครั้งแรกจากเอกสารสถานะ indexed และอัปเดตแบบ incremental รายเอกสาร (BM25 ปรับ document frequency แบบ incremental ไม่ต้อง rebuild ทั้งดัชนี) — Production แทนที่ด้วย Elasticsearch (ElasticsearchSearchAdapter)
9. การตรวจสอบความครบถ้วน (Completeness Verification)
| ระดับ | วิธีตรวจ | หลักฐาน |
|---|---|---|
| ไฟล์ → เอกสาร | ทุกไฟล์มีระเบียน KnowledgeDocument สถานะ indexed; เทียบจำนวนไฟล์ใน seed/knowledge/_manifest.json กับจำนวนเอกสาร | /documents/ingestion-report |
| เอกสาร → chunk | KnowledgeDocument.chunkCount เท่ากับจำนวนแถวใน Chunk; ไม่มีเอกสาร pending/failed ค้าง | การ์ด coverage ที่ /admin/knowledge-base, GET /api/admin/knowledge-base/coverage |
| ข้อ → chunk | จำนวน marker ข้อในไฟล์ต้นฉบับ (ฉบับหลวง/บาลี) ≈ จำนวน chunk ของเอกสาร (marker ซ้ำของข้อเดียวกันถูกรวม) | ตรวจได้จาก /admin/knowledge-base/[id] (รายการ chunk พร้อมเล่ม/ข้อ/หน้า) |
| เล่ม → 91 เล่ม | นับ mbuVolume ที่ไม่ซ้ำของเอกสารที่ทำดัชนีแล้ว เทียบ 91 เล่ม แยกตามปิฎก และเทียบเป้า 20% ของงวดที่ 2 (TOR_PHASE2_TARGET_PERCENT) | src/application/ingestion/coverage.ts |
| ฉบับหลวง 45 เล่ม | นับ volume ของเอกสารพระไตรปิฎกที่ไม่ใช่ฉบับ มมร. | coverage report (ส่วน royal) |
| คุณภาพการค้นคืน | Recall@5 ของชุด RET-1/2/3 (300 คำถามที่สร้างจากข้อความจริงในคลัง) | /admin/evaluation, /documents/baseline-evaluation-report |
| ความถูกต้องของเนื้อหา | สุ่มเปิดเนื้อหาเต็มผ่าน Citation Modal เทียบต้นฉบับ (sourceUrl) | ขั้นตอน UAT กับผู้เชี่ยวชาญของมหาวิทยาลัย |
10. สถานะคลังข้อมูลปัจจุบัน (ฉบับออนไลน์ระยะแรก)
นับจากไฟล์ใน seed/knowledge/ ณ วันที่จัดทำเอกสาร (ไม่รวม _manifest.json):
| รายการ | จำนวน |
|---|---|
| ไฟล์เอกสาร | 169 |
— tipitaka (ไทย 138, บาลี 6, English Sujato CC0 7) | 151 |
— atthakatha (ฉบับ มมร.) | 4 |
— contemporary (นวโกวาท ฉบับ มมร. พ.ศ. ๒๕๑๓) | 11 |
— teacher_dhamma (เว็บไซต์ มมร.) | 3 |
| เอกสารแยกตามปิฎก: วินัย / สุตตันตะ / อภิธรรม | 13 / 131 / 7 |
| เล่มฉบับหลวงที่มีข้อมูล | 1, 4, 10, 11, 12, 16, 17, 19, 20, 25, 34, 35 (12 เล่ม บางข้อ) |
เล่มฉบับ มมร. ที่ระบุใน metadata (mbuVolume) | 6, 14, 16, 34, 39, 40 (6 จาก 91 เล่ม) |
| บล็อก marker ข้อในไฟล์ | 721 |
| ขนาดข้อความรวม | ประมาณ 0.97 ล้านอักขระ (ไฟล์รวม 3.0 MB) |
| ตัวย่อคัมภีร์ที่ใช้ | 24 ค่า (เช่น วิ.มหา., วิ.ม., ที.ม., ม.มู., สํ.นิ., องฺ.ติก., ขุ.ขุ., ขุ.ธ., อภิ.สํ., อภิ.วิ., DN 22, SN 56.11) |
แหล่งข้อมูลและสิทธิ์ (จาก scripts/data/README.md): พระไตรปิฎกฉบับหลวงและบาลีฉบับสยามรัฐจาก 84000.org, อรรถกถาแปลฉบับ มมร. จาก 84000.org, คำแปลอังกฤษของภิกษุสุชาโต (CC0) จาก SuttaCentral, นวโกวาท (สาธารณสมบัติ) จากวิกิซอร์ซ และเนื้อหาจากเว็บไซต์ www.mbu.ac.th
ความครอบคลุมเทียบ 91 เล่มที่วัดจากฐานข้อมูลจริงอยู่ที่
/documents/ingestion-report(สถานะ ณ การสร้างรายงานล่าสุด: 6 จาก 91 เล่ม = 6.6% ซึ่ง ยังต่ำกว่าเป้าหมาย ≥20% ของงวดที่ 2 ตาม TOR 7.2.5 — ข้อ 7.2.5, 4.5.2, ข.1 จึงมีสถานะ partial ในหน้า/tor)
11. แผนนำเข้าพระไตรปิฎกและอรรถกถาฉบับ มมร. 91 เล่ม
| ระยะ | กิจกรรม | ผลผลิต | เกณฑ์สำเร็จ |
|---|---|---|---|
| 0 (ดำเนินการแล้ว) | ใช้ฉบับออนไลน์บางส่วน + อรรถกถา มมร. จาก 84000.org เพื่อพัฒนา/ทดสอบ pipeline และชุด RET-1..3 | คลัง seed 169 เอกสาร | pipeline ผ่านชุดทดสอบ tests/api/knowledge-base.test.ts |
| 1 | รับไฟล์ต้นฉบับ 91 เล่มจากมหาวิทยาลัย (ต้องการ: PDF ที่มีชั้นข้อความ, DOCX, หรือ TEI-XML) และทำบัญชีไฟล์ (เล่ม/ปิฎก/จำนวนหน้า/checksum) | ทะเบียนไฟล์ | ครบ 91 เล่ม |
| 2 | ตรวจคุณภาพไฟล์: PDF มีชั้นข้อความหรือไม่ (ระบบแจ้ง “ไม่มีชั้นข้อความ” อัตโนมัติ), การเข้ารหัสอักษรไทย/บาลี, ตำแหน่งเลขข้อ/หน้า | รายงานคุณภาพไฟล์ | ระบุไฟล์ที่ต้อง OCR |
| 3 | แปลงเป็นรูปแบบมี marker [เล่ม N][ข้อ N][หน้า N] หรือ TEI <div type="item">/<pb> (สคริปต์แปลงเฉพาะรูปแบบไฟล์ที่ได้รับ) ตั้ง metadata edition = มมร., mbuVolume, abbreviation | ไฟล์พร้อมนำเข้า | สุ่มตรวจ 5% ของข้อต่อเล่ม |
| 4 | นำเข้าทีละปิฎกผ่าน /admin/knowledge-base หรือสคริปต์; งวด 2 อย่างน้อย 19 เล่ม (≥20%), งวด 3 ครบ 91 เล่ม | งานนำเข้า (IngestionJob) | ไม่มี item ล้มเหลวค้าง |
| 5 | สลับแหล่งข้อมูล: ตั้ง precedence ฉบับ มมร. ให้สูงกว่าฉบับออนไลน์ หรือลบเอกสารฉบับออนไลน์ที่ซ้ำ (งาน delete) และปรับ expectedRefs ของชุด RET ให้อ้างฉบับ มมร. | ดัชนีฉบับ มมร. | Recall@5 ≥80% ทั้ง 3 ชุด |
| 6 | เมื่อเว็บไซต์ Dhammaverse พร้อม: เชื่อมเป็นแหล่งข้อมูล (sourceType = online, sourceUrl) ให้ Citation Modal ลิงก์ไปยังหน้าคลังปัญญา | ลิงก์ย้อนกลับ | ตรวจลิงก์ครบ |
| 7 | ออกรายงาน npm run report:ingestion ทุกครั้งที่นำเข้าเป็นชุด และแนบในรายงานงวด | /documents/ingestion-report | coverage ตามเป้า |
12. ความเสี่ยงและมาตรการ
| ความเสี่ยง | ผลกระทบ | มาตรการ |
|---|---|---|
| ไฟล์ 91 เล่มเป็นภาพสแกน (ไม่มีชั้นข้อความ) | นำเข้าไม่ได้/ข้อความผิด | parser ตรวจและแจ้งเตือนอัตโนมัติ; ทำ OCR ภาษาไทย-บาลีนอกระบบ (เช่น Tesseract tha) แล้วตรวจทานโดยผู้เชี่ยวชาญก่อนนำเข้า; จัดลำดับเล่มที่มีไฟล์ข้อความก่อน — ระบบสาธิตยังไม่มีขั้น OCR ในตัว |
| อักษรบาลี (นิคหิต/พินทุ) เข้ารหัสต่างกัน | ค้นไม่เจอ | normalizeText ใน tokenizer + char n-gram ใน pseudo-embedding + paliAliases + พจนานุกรม synonym |
| เลขข้อ/หน้าในต้นฉบับไม่สม่ำเสมอ | Citation ผิด | ตรวจ marker ก่อนนำเข้า, สุ่มตรวจผ่าน Citation Modal |
| ข้อยาวมาก (oversized) | บริบทเกินเพดานโทเคน | ไม่แบ่งข้อในดัชนี; ย่อเฉพาะตอนสร้าง prompt (bestWindow) + fitContext |
| คำสั่งแฝงในเอกสาร | AI ถูกชักนำ | sanitize + delimiter + guardrail |
| ไฟล์ซ้ำระหว่างฉบับออนไลน์กับฉบับ มมร. | ผลค้นซ้ำซ้อน | precedence/ลบฉบับออนไลน์เมื่อสลับ |
| ดัชนีในหน่วยความจำของระบบสาธิตจำกัดด้วย RAM ของเครื่องเดียว | รองรับ 91 เล่มได้ช้า | Production ใช้ Elasticsearch + bge-m3 ตาม Solution Architecture |