# ตั้งค่าเครื่อง (PGX) — ตั้งครั้งแรก และกลับมาใหม่หลังล้างเครื่อง หลักการ: **ทุกขั้นเป็นสคริปต์ที่รันซ้ำได้โดยไม่พัง** ลงใหม่กี่ครั้งก็ใช้ชุดเดิม โครงสร้างการเก็บของ: | อะไร | อยู่ที่ไหน | หลังล้างเครื่อง | |---|---|---| | ระบบ, agent, โปรแกรม Ollama (และ LM Studio/vLLM ในอนาคต) | SSD ในเครื่อง | ต้องลงใหม่ (ด้วยสคริปต์ด้านล่าง) | | ไฟล์โมเดล (`/mnt/models/ollama`) และไฟล์ GGUF (`/mnt/models/gguf`) | USB-C SSD (ext4, label `WXCH-MODELS`) | **อยู่ครบ** แค่ต่อกลับ | | ตัวตนของเครื่อง/ค่ากำหนด/คะแนนในอนาคต | server (VPS) | อยู่ครบ | ## A. ตั้งครั้งแรก (หรือหลังลง OS ใหม่) ทำที่เครื่อง PGX (จอ+คีย์บอร์ด หรือผ่าน terminal ในเว็บถ้า agent ติดตั้งอยู่แล้ว) **1. ติดตั้ง agent** (ได้ token จากคำสั่ง `-add-agent` ที่ server — ดูหัวข้อ B ท้ายหัวข้อ) ``` curl -fsSL https://control.wxch.org/install.sh | sudo WXCH_TOKEN= sh ``` เสร็จแล้วเครื่องขึ้นในหน้าเว็บ ที่เหลือสั่งผ่านเว็บ (Run script / Terminal) ได้ **2. เสียบ USB-C SSD แล้วรันชุด setup** ``` curl -fsSL https://control.wxch.org/setup/run-all.sh | sudo sh ``` ชุดนี้ทำสองขั้น (รันแยกทีละขั้นก็ได้: `.../setup/10-models-disk.sh`, `.../setup/30-ollama.sh`): - `10-models-disk.sh` หาดิสก์ที่ label `WXCH-MODELS` เมาท์ที่ `/mnt/models` (ใส่ใน fstab แบบ `nofail` ถ้าไม่ได้เสียบก็ไม่ทำให้บูตค้าง) สร้างโฟลเดอร์ `ollama/` และ `gguf/` เขียน `/etc/wxch/node.json` - `30-ollama.sh` ติดตั้ง Ollama ลงดิสก์เครื่อง ตั้งให้เก็บโมเดลบน USB-C SSD, ฟังที่ `127.0.0.1` เท่านั้น, ปล่อยหน่วยความจำเมื่อไม่ใช้ 5 นาที **ถ้า USB-C SSD ยังไม่เคยฟอร์แมต (ครั้งแรก):** สคริปต์จะไม่ฟอร์แมตเอง แต่จะแสดงรายชื่อดิสก์และคำสั่งให้ ซึ่ง **ลบข้อมูลในพาร์ทิชันนั้นทั้งหมด** ต้องยืนยันสองชั้น: ``` sudo FORMAT_DEVICE=/dev/sdX1 WXCH_CONFIRM=ERASE sh 10-models-disk.sh ``` (สคริปต์ปฏิเสธถ้าไม่ใช่ดิสก์ USB, ถูกเมาท์อยู่, หรือเป็นดิสก์ระบบ) ถ้าดิสก์เป็น exFAT/NTFS ต้องฟอร์แมตเป็น ext4 ก่อน เพราะ Ollama ต้องใช้สิทธิ์ไฟล์แบบ Unix **3. ใช้งาน** เปิด `https://control.wxch.org` → เลือกเครื่อง → แท็บ **โมเดล**: ดูสถานะเครื่อง, ดาวน์โหลด/นำเข้าจากไฟล์ GGUF, ปล่อยหน่วยความจำ, ลบ ## B. กลับมาหลังล้างเครื่อง (ฟอร์แมตแล้วลงใหม่) 1. ลง DGX OS ใหม่ (USB กู้คืนทางการ) 2. เสียบ USB-C SSD (**ไม่ต้องฟอร์แมต** โมเดลยังอยู่) 3. รันข้อ A.1 (ติดตั้ง agent) และ A.2 (run-all) — เท่านี้ ไม่มีขั้นอื่น 4. เปิดหน้าโมเดล รายการเดิมกลับมาครบ ถ้าลืม token: ที่ server รัน `sudo -u wxch /opt/wxch/wxch-server -config /opt/wxch/config.json -add-agent <ชื่อ>` (ถ้าชื่อเดิมมีอยู่ ลบรายการนั้นออกจาก `config.json` ก่อน แล้วรันใหม่จะได้ token ใหม่) ## C. อัปเกรด agent - ปกติ: หน้า **โมเดล → อัปเดต agent** (agent ดาวน์โหลดตัวใหม่จาก server ตรวจว่ารันได้ แล้วรีสตาร์ทตัวเอง) - ครั้งแรกที่เปลี่ยนจากรุ่นเก่า (ก่อนมีหน้าโมเดล) ต้องรันตัวติดตั้งซ้ำหนึ่งครั้งด้วย token ที่เครื่องมีอยู่แล้ว: ``` sudo sh -c '. /etc/wxch-agent.env; curl -fsSL https://control.wxch.org/install.sh | WXCH_TOKEN=$WXCH_TOKEN sh' ``` ## D. ตรวจเมื่อมีปัญหา | อาการ | ตรวจ | |---|---| | หน้าโมเดลขึ้นว่า Ollama ไม่ตอบ | `systemctl status ollama`, `journalctl -u ollama -n 50` | | ขึ้น "ยังไม่ได้ต่อ SSD" | `lsblk -f` เห็นดิสก์ไหม, `mount | grep models`, รัน `10-models-disk.sh` ซ้ำ | | ดาวน์โหลดไม่เริ่ม | พื้นที่ว่างต้องไม่ต่ำกว่า `min_free_gb` (ค่าเริ่มต้น 10 GB ใน `/etc/wxch/node.json`) | | agent ไม่ขึ้นในเว็บ | `systemctl status wxch-agent`, `journalctl -u wxch-agent -n 50` | ## E. ย้ายโมเดลที่ใช้บ่อยมาไว้ SSD ในเครื่อง ยังไม่ทำในรุ่นนี้ ออกแบบไว้ว่าจะย้าย "ไฟล์โมเดล" ไปไว้ SSD เครื่องแล้วทิ้ง symlink ไว้ที่เดิม (Ollama ตามลิงก์ได้) เพื่อไม่เปลี่ยนวิธีใช้งาน และย้ายกลับได้ ทำหลังจากข้อ A ทดสอบกับเครื่องจริงแล้ว ## E2. Runtime เพิ่มเติม: vLLM และ LM Studio agent รองรับหลาย runtime พร้อมกัน (Ollama, vLLM, LM Studio) โดย **Model Pool ดูหน่วยความจำรวมทุกตัว** (GB10 ใช้หน่วยความจำร่วม CPU/GPU) เมื่อต้องการที่ จะปล่อยโมเดลที่ว่างอยู่ไม่ว่าอยู่ใน runtime ไหน ชื่อโมเดลในการเรียก API: Ollama ใช้แท็ก (`qwen3:14b`), vLLM ใช้ Hugging Face id (`nvidia/Qwen3.8-27B-NVFP4`) ### vLLM (Docker) — `setup/40-vllm.sh` - โมเดลเป็นโฟลเดอร์ Hugging Face ที่ `/mnt/models/vllm//` ดาวน์โหลดจากหน้า Models (ดาวน์โหลดต่อได้เมื่อหลุด, ตรวจขนาดไฟล์, ถ้าเป็น gated ใส่ token ใน `/etc/wxch/hf_token`) - vLLM รัน **หนึ่ง container ต่อโมเดล** (`wxch-vllm-<ชื่อ>`) โหลดตอนมีคำขอแรก (ใช้เวลาหลายนาที) และถูกปล่อยเมื่อ Pool ต้องการที่ (container ถูกลบ) จำนวน container ที่มีพร้อมกันจำกัดที่ 2 - อิมเมจเริ่มต้น `nvcr.io/nvidia/vllm:26.09-py3` (ของ NVIDIA สำหรับ Spark/GB10; arm64 บีบอัดราว 10.7 GB) ค่าที่ปรับได้ใน `/etc/wxch/node.json`: `vllm_max_len` (32768), `vllm_gpu_util` (0 = คำนวณจากขนาดโมเดล), `vllm_kv_gb` (8), `vllm_extra_args` (เฉพาะรายการที่อนุญาต) - **ความปลอดภัย: agent ไม่ได้สิทธิ์ Docker** เพราะกลุ่ม `docker` เทียบเท่า root โดยไม่ต้องใส่รหัส (ใครเข้าเว็บ terminal/Run script ได้ก็ควบคุมเครื่องได้) แต่สคริปต์ติดตั้ง **`wxch-runner`** ซึ่งเป็น service ของ root ที่ agent เรียกผ่าน unix socket (`/run/wxch/runner.sock`) และยืนยันตัวผู้เรียกจาก uid ของ agent runner รับแค่: ดูสถานะ, ดูรายการ, เริ่ม, หยุด, ดู log ของ container vLLM และ **กำหนดเองทั้งหมด**: อิมเมจ, โฟลเดอร์โมเดล, ช่วงพอร์ต (ไฟล์ `/etc/wxch/runner.json` ของ root) ชื่อโมเดลต้องเป็น `org/name` ที่มีไฟล์อยู่จริงในโฟลเดอร์โมเดล (กัน symlink ออกนอกโฟลเดอร์), พารามิเตอร์ vLLM ต้องอยู่ในรายการอนุญาต (เช่น `--kv-cache-dtype`, `--reasoning-parser`; ไม่อนุญาต `--trust-remote-code`), container ไม่ privileged, `--cap-drop ALL`, เปิดพอร์ตเฉพาะ 127.0.0.1 - ติดตั้ง: `curl -fsSL https://control.wxch.org/setup/40-vllm.sh | sudo sh` (ขั้นดึงอิมเมจใช้เวลานานถ้าเน็ตช้า ผ่านอินเทอร์เน็ตของ PGX ตอนนี้ราว 1-2 ชั่วโมง ถ้าหลุดรันซ้ำได้ จะดึงต่อจาก layer ที่ได้แล้ว) - **ทดสอบบน PGX จริงแล้ว (2026-10-03):** ติดตั้ง runner + อิมเมจ, ดาวน์โหลด `Qwen/Qwen2.5-1.5B-Instruct` (3.1 GB), โหลดผ่าน Gateway ครั้งแรก (~2.5 นาที), ตอบผ่าน API และ `chat.wxch.org`, ปล่อยโมเดลแล้ว container ถูกลบและหน่วยความจำคืน คำสั่ง `docker run` ที่ล็อกสิทธิ์ (`--cap-drop ALL`, `no-new-privileges`, `--shm-size`, พอร์ต 127.0.0.1) ใช้กับ GB10 ได้ - **บั๊กที่เจอตอนทดสอบจริง:** Owner Guard มอง `VLLM::EngineCore` เป็นงาน GPU ของเจ้าของเครื่อง แล้วปล่อยโมเดลที่กำลังโหลดทิ้ง และคำขอที่ถูกยกเลิกไม่ได้รับคำตอบ (ค้าง) แก้แล้ว: ยกเว้นโปรเซสของ runtime ที่เรารันเอง (ชื่อ และ cgroup) และการยกเลิกตอบ 503 เสมอ มีเทสต์ป้องกันซ้ำ - **ผลวัดคร่าวๆ (โมเดลเล็ก 1.5B, ผ่าน Gateway, ไม่ใช่การวัดที่เข้มงวด):** vLLM รัน BF16 (3.1 GB) ได้ ~65 tok/s ต่อคำขอเดียว ส่วน Ollama/LM Studio ใช้ Q4_K_M (~1 GB) ได้ ~185/~167 tok/s เพราะการสร้างทีละคำถูกจำกัดด้วยความเร็วอ่านหน่วยความจำ เทียบกันตรงๆ ไม่ได้ แต่เมื่อมี 4 คำขอพร้อมกัน vLLM ขยายได้ 52 → 219 tok/s (4.2 เท่า) เทียบ Ollama 108 → 172 และ LM Studio 138 → 289 จุดแข็งของ vLLM ควรเห็นชัดกับ NVFP4 และโมเดลใหญ่ ซึ่งยังไม่ได้ทดสอบ ### LM Studio (llmster, ไม่มีหน้าจอ) — `setup/50-lmstudio.sh` - ติดตั้งระดับผู้ใช้ด้วยตัวติดตั้งทางการ (`curl -fsSL https://lmstudio.ai/install.sh | bash`: ตรวจ sha512, รองรับ Linux ARM64, ไม่ต้องใช้ sudo และไม่ต้องใช้ Docker) แล้วตั้ง service `lmstudio.service` ให้เปิดตอนบูต ฟังที่ `127.0.0.1:1234` เก็บโมเดลที่ `/mnt/models/lmstudio` (symlink จาก `~/.lmstudio/models`) - agent สั่งผ่าน REST API ของ LM Studio: ดาวน์โหลด (รับ catalog id, หรือ `org/repo@Q4_K_M` สำหรับ Hugging Face), โหลดด้วย context ที่เรากำหนด (`lmstudio_ctx` 32768), ปล่อย, ลบ (ลบไฟล์โมเดล เพราะ LM Studio ไม่มีคำสั่งลบ; ไม่ลบถ้ากำลังโหลดอยู่) - ชื่อโมเดลในการเรียก API คือ key ของ LM Studio (เช่น `qwen3-0.6b`) ดูได้ที่ `/v1/models` - **ทดสอบบน PGX จริงแล้ว** ด้วยโมเดลเล็ก (Qwen3 0.6B): ดาวน์โหลด → โหลด → ตอบผ่าน Gateway (ปกติ + stream) → ปล่อย → ลบ ### ข้อควรระวัง: งานยาวกับการรีสตาร์ท agent systemd ฆ่า **ทุก process ใน cgroup ของ agent** เมื่อรีสตาร์ท (รวมถึงอัปเดต agent จากหน้าเว็บ) ดังนั้นงานยาวที่เริ่มจาก "Run script"/terminal (เช่นดาวน์โหลดไฟล์ใหญ่) จะตายถ้า agent รีสตาร์ทระหว่างนั้น ถ้าต้องรันงานยาว ให้เริ่มผ่าน `systemd-run --user` และอย่าอัปเดต agent ระหว่างนั้น ส่วนดาวน์โหลดโมเดลจากหน้าเว็บ (agent ทำเอง) ก็หยุดเช่นกัน แต่ vLLM/Hugging Face ดาวน์โหลดต่อได้ (resume) ส่วน LM Studio/Ollama ดาวน์โหลดต่อจากที่ค้างตามความสามารถของมันเอง ## F. สถานะการทดสอบ ทดสอบบน PGX จริง (2026-10-03, DGX Spark, agent 0.2.0, Ollama 0.35.1, ดิสก์ USB-C 931 GB ext4): - ฟอร์แมต + เมาท์ `/mnt/models` + ติดตั้ง Ollama ด้วย `run-all.sh` — ผ่าน (Ollama ฟังที่ `127.0.0.1` เท่านั้น) - RPC ของ agent: `sys.info`, `models.list`, `models.pull` (ดาวน์โหลด `qwen2.5:0.5b` พร้อม progress, ไฟล์อยู่บน USB จริง ไม่มีใน `/usr/share/ollama`), `models.unload`, `models.delete`, `models.import` (นำเข้า GGUF จริง) — ผ่าน - ป้องกัน: ปฏิเสธลบโมเดลที่โหลดอยู่, ปฏิเสธไฟล์นอก `gguf_dir`, ปฏิเสธชื่อโมเดลอันตราย — ผ่าน - ใช้งานโมเดลได้จริง: ครั้งแรก (โหลดเย็นจาก USB) ใช้ ~34 วินาที ครั้งถัดไป ~2.9 วินาที - ชุดทดสอบอัตโนมัติ (Ollama จำลอง) 9 รายการ — ผ่าน Telemetry (agent 0.3.0): agent ส่งค่าทุก 5 วินาที (CPU/RAM/GPU/อุณหภูมิ/โหลด/เวลาเจ้าของว่าง/ดิสก์โมเดล/โมเดลที่โหลด) server เก็บล่าสุด + ประวัติ 30 นาทีในหน่วยความจำ แสดงที่แท็บ "สถานะเครื่อง" — ค่าจริงจาก PGX ผ่าน; การแสดงผลหน้าเว็บทดสอบกับ agent จำลองที่ส่งค่ารูปแบบเดียวกัน ทั้งโหมดมืด/สว่าง ไม่มี error ใน console การอัปเดต agent ด้วยตัวเอง (0.2.0 → 0.3.0) บน PGX จริง — ผ่าน (ไม่ต้องใช้ sudo) GB10: `nvidia-smi` ไม่แสดง GPU memory (N/A) จึงใช้ RAM แบบ unified จาก `/proc/meminfo` แทน **ยังไม่ได้ทดสอบ:** หน้าโมเดลในเบราว์เซอร์จริง (แสดงผล/ปุ่ม), การกดปุ่มอัปเดตในหน้าเว็บ (ทดสอบผ่านช่องทาง admin แล้ว), การล้างเครื่องแล้วทำตามหัวข้อ B ทั้งชุด, การถอด/เสียบ USB ขณะใช้งาน