Siam East · datawarehouse."Orasa" · สร้าง 07/10/2569 · datawarehouse."Orasa" (203.150.148.186) · โหลดจาก item code _CATEGORIES_COMPLETED.xlsx
Orasa (Ai)
แพลตฟอร์ม ML ของ Siam East ที่ตอบได้หลายเรื่อง — ความรู้แยกเป็น 6 หมวด (Knowledge Domain) แต่ละ skill อยู่ในหมวดของตัวเองบน core เดียวกัน · skill แรกคือ Item Code Search: ค้นได้ทั้งรหัส · part number · คำอธิบาย · ความหมาย และเรียนรู้จากการใช้งานจริง
Next Step · รอข้อมูลจากพนักงาน SE แล้ว Train
ตัดสิน 10 ต.ค. 2026 (ที่รัก) — Orasa ใช้เฉพาะใน Siam East · model ที่เทรนเรียนภาษาที่คน SE ใช้เรียกสินค้าเท่านั้น · ยังไม่เทรนตอนนี้ เพราะ log ก่อน 9 ต.ค. 09:10 เป็นการทดลอง (is_test) — ต้องรอให้พนักงาน SE ใช้งานจริงก่อน
| ขั้น | ทำอะไร | เริ่มเมื่อ | สถานะ |
|---|---|---|---|
| 1 · Deploy ให้พนักงาน SE ใช้ | IT SE ดึง main ขึ้น docker + รัน sql/007, sql/008 · แจก extension ให้ Sales / จัดซื้อ | ที่รัก add IT SE เข้า GitHub | ⏳ รอ |
| 2 · สะสมข้อมูลจริง | ทุกการค้น → เลือก ลง interaction_log (is_test = false) · ดูยอดที่ GET /api/learning/stats | หลัง deploy | ⏳ รอ |
| 3 · ชุดสอบ held-out | แยกคำค้นจริง 100 คำ (ไม่ใช้สอน) ไว้วัดทุก model | มีการค้นจริง ~300 ครั้ง | ⏳ รอ |
| 4 · Train Ranker (ชั้น 3) | LightGBM LambdaMART จากคู่ เลือก / ถูกข้าม · ขึ้นเป็น candidate รัน shadow ก่อน active | มีการเลือก ~1,500 ครั้ง | ⏳ รอ |
| 5 · Fine-tune bge-m3 (ชั้น 4) | คู่ (คำค้น, item ที่เลือก) + hard negative → model ของ SE · ขนาด ~2 GB รัน CPU ใน docker ของ IT ได้ | มีคู่ ~1,000–2,000 คู่ และ Ranker ใช้งานแล้ว | ⏳ รอ |
- •✅ 30 ต.ค. 2569 · IT Admin ของ SE deploy Search API 0.2.0 เรียบร้อย — สร้าง / ปิด / ออก token ใหม่ / ดูการใช้งานล่าสุด ได้เองบน SE server (คู่มือ Orasa_Deploy_SE_IT_Admin_API0.2.0_2026-10-30 ใน Source files ข้อ 5)
- •✅ 1 คน = 1 token — IT เป็นคนสร้างและส่งให้พนักงานเอง token ของ SE ไม่ผ่านทีม DV · ทุกคำค้นบันทึกตามชื่อผู้ใช้ใน interaction_log
- •⏳ IT ออก token ให้พนักงาน SE ที่จะใช้ (Sales / จัดซื้อ / Admin) แล้วติดตั้ง extension 0.7.0 ในเครื่อง
- •⏳ ติดตามด้วย `api.users list` (คอลัมน์ "ใช้ล่าสุด") และ /api/learning/stats — พอมีการค้นจริงต่อเนื่อง จึงเริ่มเทรน Ranker
ไม่เทรน LLM ให้จำ item ทั้ง 16,572 ตัว — LLM แต่งรหัสที่ไม่มีจริงได้ และ item เปลี่ยนทุกวัน · ค้นจาก DB เหมือนเดิม ให้ model ช่วยเข้าใจคำค้นและจัดลำดับเท่านั้น
สรุป
Orasa (Ai) ไม่ใช่ ML ที่ตอบได้เรื่องเดียว — เป็นแพลตฟอร์มที่ความรู้แยกเป็นหมวด และเพิ่ม skill ใหม่ได้โดยไม่แก้ core ทุก skill ใช้ตารางกลางร่วมกัน (skill · model_registry · interaction_log · embedding · knowledge) จึงได้ข้อมูลเทรนจากการใช้งานจริงเหมือนกันหมด Skill แรก — Item Code Search: ข้อมูลใน Excel เป็นบรรทัดขายจริง ไม่ใช่ master สินค้า จึงแยกเป็น master สินค้า (item) กับประวัติการขาย (sales_line) แล้วผูกกับรหัสอ้างอิง Brand / Product / Category
- •Knowledge แยก 6 หมวด: product · sales · purchase · asset · service · document — ทุก skill / ความรู้ / vector ติด domain_code ค้นและเทรนในหมวดของตัวเอง
- •ใช้ได้ 2 ทาง: Web App (React + FastAPI) และ Floating widget (Chrome/Edge extension · Alt+O) ลอยบนทุก Web App แล้ว Copy / Insert Item Code
- •Item Code 20 ตัวอักษร = Brand 2 + Product 2 + "-" + Model/Spec 15 — ถอดเป็นคอลัมน์ได้ตรง ๆ
- •รหัส Product 2 หลักไม่ได้มีความหมายเดียวทุก Brand (69 รหัสมีชื่อต่างกันตาม Brand) → ต้องมีตารางคู่ Brand+Product
- •ตาราง interaction_log คือหัวใจของ ML — ไม่มีข้อมูลการค้นจริง ก็ไม่มีอะไรให้โมเดลเรียน
- •สร้างแล้วใน datawarehouse schema "Orasa": item 16,572 · sales_line 74,121 · search_term 52,692 · pg_trgm ติดตั้งแล้ว · pgvector 0.8.6 ลงแล้ว (IT 07/10) · embedding ด้วย bge-m3 ครบ 16,572 item + HNSW index แล้ว (ดู Item Search 8)
A. Knowledge Domains
ความรู้แยกหมวด — แต่ละหมวดประกาศว่าเรียนจาก schema ไหนของ datawarehouse
| Domain | ความรู้ | เรียนจาก | Skill |
|---|---|---|---|
| product | สินค้า · Item Code · Brand · Product · หมวด | Orasa | Item Code Search ✅ · Item Code Suggest |
| sales | ประวัติขาย · ราคา · ลูกค้า | Orasa · CRM | Price Suggest · Customer Cross-sell |
| purchase | ใบสั่งซื้อ · supplier | Purchase | Purchase Anomaly |
| asset | ทรัพย์สิน · ซ่อมบำรุง · ticket / job | AssetManagement | Asset Maintenance |
| service | งานบริการหน้างาน | se_connex | — (เพิ่มได้โดยไม่แก้ core) |
| document | คู่มือ · spec · datasheet | ไฟล์เอกสาร | Document Q&A |
B. Skills
skill = ความสามารถหนึ่งเรื่องของ Orasa · ทุกตัวทำตามสัญญาเดียวกัน predict / train / evaluate
| Skill | Domain | สถานะ | ทำอะไร |
|---|---|---|---|
| item_search | product | ✅ ใช้งาน | ค้นหา Item Code จากรหัส / part no / คำอธิบาย / ความหมาย |
| item_code_suggest | product | วางแผน | เสนอ Brand / Product / หมวด ให้สินค้าใหม่ |
| price_suggest | sales | วางแผน | เสนอราคาจากประวัติขาย |
| cross_sell | sales | วางแผน | ลูกค้ารายนี้น่าจะซื้ออะไรต่อ |
| purchase_anomaly | purchase | วางแผน | จับ PO ผิดปกติ |
| asset_maintenance | asset | วางแผน | ทำนายการซ่อมบำรุง |
| doc_qa | document | วางแผน | ถามตอบจากคู่มือ / spec สินค้า |
กติกา: 1 skill = 1 โฟลเดอร์ · skill ไม่อ่าน table ของ skill อื่นตรง ๆ · log ที่เดียว (interaction_log) · โมเดลใหม่ต้องชนะตัวเดิมก่อน active · สิทธิ์ราย domain
Item Search 1 · ข้อมูลที่ได้รับ
| Sheet | แถว | เนื้อหา |
|---|---|---|
| PRODUCTSยกเว้น GF | 74,121 | บรรทัดขาย 2018–2026 · 13,964 Item Code · invoice / SO / qty / revenue / หมวด |
| GF GRUNDFOS | 8,328 | Item GF 2,608 ตัว · Part Number · Customer Code · หมวด PUMP ทั้งหมด |
| MASTER 4 digits item code | 933 | รหัส Brand 2 หลัก + Product 2 หลัก พร้อมชื่อ |
| Master R1 4di w categ | 534 | คู่ Brand+Product → Category + กลุ่มสินค้า (1=PUMP, 2=VALVE, 3=Consumable, 4=Process Equipment, 7=Power, 9=Service) |
| Master SO CODE | 268 | โครงสร้างเลข Sale Order (ประเภทขาย · กลุ่ม · location · ปี · product · พนักงาน · running) |
Item Search 2 · โครงสร้าง Item Code
| ตำแหน่ง | ความหมาย | ตัวอย่าง |
|---|---|---|
| ตัวที่ 1–2 | Brand | TD = TOMOE DECANTER |
| ตัวที่ 3–4 | Product | SP = SPARE PART |
| ตัวที่ 5 | ขีดคั่น | - |
| ตัวที่ 6–20 | Model / Spec / Part (เติม X ให้ครบ) | STSTS1303ABPTM9 · ELPAPERXXXXXXXX |
ตัวอย่างเต็ม: TDSP-STSTS1303ABPTM9 = TOMOE DECANTER · SPARE PART · STSTS1303ABPTM9
Item Search 3 · Table Design (ทั้ง schema Orasa)
แบ่ง 4 กลุ่ม: รหัสอ้างอิง (ref_*) · สินค้าและการขาย · ชั้นค้นหา · platform core (ทุก skill ใช้ร่วม)
| Table | Key | คอลัมน์หลัก | ที่มา |
|---|---|---|---|
| ref_brand | brand_code (2) | brand_name | MASTER 4 digits |
| ref_product_type | product_code (2) | product_name | MASTER 4 digits |
| ref_category | category_id | category_name · product_group_no (1–9) | Master R1 (ล้างชื่อซ้ำแล้ว) |
| ref_brand_product | brand_code + product_code | product_name_local · category_id · source (master / inferred) | Master R1 + คู่ที่พบในการขาย |
| item | item_code | brand_code · product_code · model_spec · part_number · description · detail · unit · product_group · status · code_valid | PRODUCTS + GF (1 แถวต่อ item) |
| sales_line | line_id | item_code · invoice_no · invoice_date · sale_order_no · qty · revenue · unit | PRODUCTS (74,121 แถว) |
| item_customer | item_code + customer_code | first_seen | GF GRUNDFOS |
| item_search_term | term_id | item_code · term · term_type (code / part_no / model / synonym / customer_word) | สร้างจาก item + เพิ่มจากการใช้งาน |
| embedding | entity_type + entity_id + model_name | domain_code · vector · text_hash | vector ของทุก entity แยก domain (ใช้ร่วมทุก skill) |
| interaction_log | log_id | skill_code · query · shown · chosen_ref · action · model_id | ทุก request ของทุก skill (ข้อมูลเทรน ML) |
| knowledge_domain | domain_code | product · sales · purchase · asset · service · document | ความรู้แยกหมวด |
| skill | skill_code | domain_code · status | Orasa ตอบได้หลายเรื่อง — item_search คือ skill แรก |
| model_registry | model_id | skill_code · version · metrics · status | active ได้ทีละตัวต่อ skill |
| knowledge | knowledge_id | domain_code · kind · content | chunk เอกสาร · กฎ · FAQ |
Item Search 4 · Relation
| จาก | ไป | ชนิด | ผ่าน |
|---|---|---|---|
| ref_brand_product | ref_brand | N : 1 | brand_code |
| ref_brand_product | ref_product_type | N : 1 | product_code |
| ref_brand_product | ref_category | N : 1 | category_id |
| item | ref_brand_product | N : 1 | brand_code + product_code |
| sales_line | item | N : 1 | item_code |
| item_customer | item | N : 1 | item_code |
| item_search_term | item | N : 1 | item_code |
| skill / embedding / knowledge | knowledge_domain | N : 1 | domain_code |
| interaction_log | skill · model_registry | N : 1 | skill_code · model_id |
ref_brand_product คือจุดที่ตัดสินหมวดของ item — item ชี้ไปที่คู่ (brand_code, product_code) แทนที่จะผูกหมวดกับ Product อย่างเดียว
Item Search 5 · Smart Search ทำงานอย่างไร
ค้นทุกชั้นพร้อมกัน แล้วรวมคะแนนเรียงผลเดียว
| ชั้น | วิธี | ตัวอย่างที่ค้นเจอ |
|---|---|---|
| 1 · ตรงตัว | รหัส / part number แบบตัดขีด-ช่องว่าง, ค้นบางส่วนได้ | "99884046" → GFSP-KIT99884046ROTA |
| 2 · สะกดใกล้เคียง | pg_trgm บน description + search_term | "filtr papr" → FILTER PAPER |
| 3 · ความหมาย | embedding (domain product) → pgvector | "ใบกรอง" → FILTER PAPER · "ซ่อมเครื่องแยกกาก" → REPAIR WORK FOR PTM340V |
| 4 · กรองตามรหัส | จับ Brand/Product จากคำค้น | "grundfos pump" → GF + PS ก่อน |
| 5 · เรียงผล | คะแนนความตรง + จำนวน order + ขายล่าสุด → ภายหลังใช้ Ranker จาก interaction_log | item ที่ขายบ่อยและล่าสุดขึ้นก่อน |
Item Search 6 · ML ที่จะสร้าง
- •โมเดล 1 · Ranker — เรียนจาก interaction_log ว่าคำค้นแบบนี้ ผู้ใช้เลือก item ไหน (learning-to-rank) แล้วใช้เรียงผลแทนสูตรตายตัว
- •โมเดล 2 · Classifier — รับคำอธิบายสินค้าใหม่ แล้วเสนอ Brand / Product / Category / Item Code ที่ควรเป็น ช่วยคนตั้งรหัสใหม่ให้ถูกโครงสร้าง
- •เริ่มเทรนได้ทันทีด้วยข้อมูลที่มี: คู่ (คำอธิบาย → item_code) 13,964 item + Part Number GF 2,608 ตัว เป็นชุดตั้งต้น ก่อนมี interaction_log จริง
- •วัดผล: เปอร์เซ็นต์ที่ item ที่ถูกอยู่อันดับ 1 และใน 5 อันดับแรก (Hit@1 / Hit@5) จากชุดทดสอบที่แยกไว้
Item Search 7 · คุณภาพข้อมูลที่ต้องจัดการ
| เรื่อง | จำนวน | ข้อเสนอ |
|---|---|---|
| หมวด = REVIEW - NOT IN MASTER | 4,083 แถว | เก็บไว้ status = review รอคนยืนยัน |
| คู่ Brand+Product ไม่มีใน Master R1 | 422 / 538 คู่ | เติม ref_brand_product ด้วย source = inferred |
| ชื่อหมวดซ้ำต่างตัวพิมพ์ | PROCESS EQUIPMENT / Process Equipment | รวมเป็นหมวดเดียวใน ref_category |
| product_group ค่าแปลก | ps · 0 · EA · 99 · DM (9 แถว) | แก้ให้ตรงชุด IM / PP / SB / PS / ... |
| Item Code ไม่ครบ 20 ตัว | 23 แถว | code_valid = false รอแก้ |
| Item เดียวอยู่หลายหมวด | 9 item | เลือกหมวดเดียวหลังตรวจ |
| ชื่อลูกค้าในชีตหลัก | ว่าง 100% | ใช้ลูกค้าได้เฉพาะ GF — ถ้าต้องการ ต้องดึงจาก invoice ใน SE DB |
Item Search 8 · Model ที่ใช้
เลือก 7 ต.ค. 2026 จากการวัดกับสินค้าจริงของ SE ด้วยคำค้นไทย + อังกฤษ 16 คำ (ถูก = คำอธิบายของผลอันดับ 1 มีคำอังกฤษที่ตรง) · ลงทะเบียนใน "Orasa".model_registry (model_id 1, active)
| ส่วน | Model | รายละเอียด | ผลวัด |
|---|---|---|---|
| Embedding (ใช้งานอยู่) | bge-m3 · 1,024 มิติ · Ollama บน M6 (version 790764642607) | ข้อความ = description | category · ครบ 16,572 item (domain product) · index HNSW embedding_hnsw_bge_m3 · ค้น ~16 ms | ชุดทดสอบ 4,432 item: ถูกอันดับ 1 10/16 · P@5 0.49 — ทั้ง 16,572 item: 7/16 |
| Embedding (ไม่เลือก) | granite-embedding:278m · 768 มิติ (ตัวที่ Angela ใช้) | ไม่รองรับภาษาไทย — "ใบกรอง" ได้น้ำยาถูพื้น · "วาล์วกันกลับ" ได้ใบมีด | ชุดทดสอบเดียวกัน: ถูกอันดับ 1 4/16 · P@5 0.26 |
| ข้อความที่ embed | description | category (ตัด brand / product ออก) | ชื่อ product อย่าง "OUTSOURCE service Check/Repair/Report" ดึงคำค้น "วาล์วกันกลับ" ไปหางานบริการ | ทั้ง 16,572 item: desc+category 7/16 · desc+brand+product+category 6/16 · desc อย่างเดียว 5/16 |
| Classifier | ยังไม่เทรน — แผน: TF-IDF char n-gram + Logistic Regression | เสนอ Brand / Product / Category ให้สินค้าใหม่ | รอที่รักตัดสินคำถาม 4 ข้อ |
| Ranker | ยังไม่เทรน — แผน: LightGBM LambdaRank | เรียงผลจากทุกชั้นด้วยข้อมูล interaction_log | ต้องมีการค้นจริงก่อน — ดู Item Search 9 ชั้น 3 |
vector อย่างเดียวยังถูกอันดับ 1 ไม่ถึงครึ่ง เพราะใน 16,572 item มีงานบริการ / ค่าแรงปนเยอะ — Smart Search จึงต้องใช้ทุกชั้นร่วมกัน (รหัส · trigram · คำพ้องไทย→อังกฤษ ใน item_search_term · vector) แล้วให้ Ranker เรียนจาก interaction_log
Item Search 9 · Orasa เก่งขึ้นจากการใช้งาน
ออกแบบ 9 ต.ค. 2026 (ที่รัก: "เมื่อมีคนใช้เรื่อยๆ Orasa จะเก่งขึ้นได้ยังไง") — ทุกครั้งที่มีคนค้นแล้วเลือก = ครูสอน Orasa หนึ่งครั้ง · ทุกการค้นถูกบันทึกใน "Orasa".interaction_log (คำค้น · 10 อันดับที่โชว์ · ตัวที่เลือก · copy / insert / ไม่เจอ) · การค้นก่อน 9 ต.ค. 09:10 เป็นการทดลอง ติดป้าย is_test ไม่นำมาเรียน
| ชั้น | เรียนจากอะไร | ทำงานอย่างไร | สถานะ |
|---|---|---|---|
| 1 · จำทันที | คนที่ค้นคำเดียวกันแล้วเลือก item ไหน (copy / insert) + ปุ่ม "ไม่เจอที่ต้องการ?" ให้พิมพ์รหัสที่ถูก (นับ 2 เท่า) | ช่องค้นที่ 5 ชื่อ learned อ่าน interaction_log ตรงๆ — การค้นครั้งถัดไปใช้ได้เลย ไม่ต้องรอ cron · จางลงเองถ้าไม่มีใครเลือก (90 วัน) · widget ขึ้น ★ "คนค้นคำนี้เลือกตัวนี้" | ✅ ทำแล้ว 9 ต.ค. (widget 0.4.0 · sql/007) — ทดสอบ: item อันดับ 30 สอนครั้งเดียวขึ้นอันดับ 1 · eval 19 คำยัง 17/19 |
| 2 · เรียนคำพ้องเอง | ค้นคำไทยไม่เจอ แล้วพิมพ์ใหม่เป็นอังกฤษแล้วเลือกได้ (เช่น "ใบกรอง" → "FILTER") | คู่ที่ ≥ 3 คนทำเหมือนกัน เข้าคิวให้ admin กด ✓ แล้วลง synonym (source = learned) | ✅ ทำแล้ว 10 ต.ค. (widget 0.5.0 · sql/008) — รอมีการใช้งานจริง |
| 3 · Ranker เรียนน้ำหนักเอง | ตัวที่เลือก = ถูก · ตัวที่โชว์อยู่เหนือแต่ถูกข้าม = ผิด | LightGBM LambdaMART แทนสูตรมือ 50/40/10 — feature: คะแนนทั้ง 5 ช่อง · ขายดี · ประวัติผู้ใช้ · หน้าเว็บที่กรอก · สลับอันดับ 2–3 บางครั้งแก้ position bias | เริ่มเมื่อมีการเลือก ~1,500 ครั้ง |
| 4 · Fine-tune embedding | คู่ (คำค้น, item ที่เลือก) + ตัวที่ถูกข้ามเป็น hard negative | สอน bge-m3 ให้เข้าใจภาษา SE แล้ว embed สินค้าใหม่ทั้งชุด เทียบกับตัวเดิมบนชุดสอบ | รายเดือน ทำทีหลัง |
ด่านกันพังทุกชั้น: ชุดสอบ held-out จาก log จริง (แยกไว้ไม่ใช้สอน) · โมเดลใหม่เข้า model_registry เป็น candidate รัน shadow คู่ตัวเดิม ขึ้น active เมื่อชนะเท่านั้น ย้อนกลับได้ทันที · 1 คนนับ 1 เสียงต่อวันต่อ item กันคนเดียวลากผล · ตัวเลขดูความก้าวหน้า: GET /api/learning/stats → อัตราการเลือก · อันดับเฉลี่ยของตัวที่เลือก · อัตรา "ไม่เจอ" + Hit@1 บนชุดสอบ
Open questions
- 1.แถวที่หมวดยังเป็น "REVIEW - NOT IN MASTER" (4,083 แถว) และรหัสผิดรูป (23 แถว) — เก็บไว้แบบ status = review หรือคัดออก?
- 2.คู่ Brand+Product ที่ขายจริงแต่ไม่มีใน Master R1 (422 จาก 538 คู่) — เติมเข้า ref_brand_product โดยติด source = inferred ได้ไหม?
- 3.หลัง Product แล้ว domain / skill ไหนควรทำต่อเป็นอันดับ 2 (Sales · Purchase · Asset · Document)?