📗 บทที่ 12 (บทส่งท้าย) — Privacy & Local-First: ทำไมสมองที่สองต้องอยู่ในเครื่องเรา¶
คู่กับ: หนังสือบทที่ 12
ทุกบทที่ผ่านมา มีสิ่งหนึ่งที่เราไม่ได้พูดถึงแต่ทำมาตลอด: ข้อมูลไม่เคยออกจากเครื่องเลย บทนี้พิสูจน์เรื่องนั้นด้วยโค้ด แล้วปิดเล่มด้วยภาพรวมทั้งหมด
In [1]:
import sys
IN_COLAB = 'google.colab' in sys.modules
from pathlib import Path
import urllib.request
print('พร้อม ✓')
พร้อม ✓
1) ข้อมูลของเราอยู่ไหน? — ดูด้วยตา¶
In [2]:
db = Path('./chroma_db')
if db.exists():
total = sum(f.stat().st_size for f in db.rglob('*') if f.is_file())
print(f'สมองที่สองของคุณ = โฟลเดอร์ {db.resolve()}')
print(f'ขนาด {total/1e6:.1f} MB · {sum(1 for _ in db.rglob("*") if _.is_file())} ไฟล์')
print()
print('อยากย้ายเครื่อง = copy โฟลเดอร์ · อยาก backup = zip · อยากลบ = ลบทิ้ง — ของเรา 100%')
else:
print('ยังไม่มี chroma_db ในโฟลเดอร์นี้ — รันบทที่ 1 ก่อน')
สมองที่สองของคุณ = โฟลเดอร์ /opt/Code/github.com/nat-build-with-oracle/ajfon-oracle/book/notebooks/chroma_db ขนาด 4.2 MB · 45 ไฟล์ อยากย้ายเครื่อง = copy โฟลเดอร์ · อยาก backup = zip · อยากลบ = ลบทิ้ง — ของเรา 100%
2) เช็ค: ทุก endpoint ที่ใช้ทั้งเล่ม คือ localhost¶
In [3]:
ENDPOINTS = [
('embedding (bge-m3)', 'http://localhost:11434/api/embed'),
('LLM (gemma3)', 'http://localhost:11434/api/generate'),
('vector DB', 'ไฟล์ในเครื่อง (./chroma_db) — ไม่มี network เลย'),
]
for name, ep in ENDPOINTS:
local = ('localhost' in ep) or ('เครื่อง' in ep)
print(f"{'🔒' if local else '🌐'} {name:<22} {ep}")
print()
print('→ โน้ตส่วนตัว งานวิจัยยังไม่ตีพิมพ์ บันทึกคนไข้ ข้อมูลนักศึกษา — ไม่มีอะไรออกอินเทอร์เน็ต')
🔒 embedding (bge-m3) http://localhost:11434/api/embed 🔒 LLM (gemma3) http://localhost:11434/api/generate 🔒 vector DB ไฟล์ในเครื่อง (./chroma_db) — ไม่มี network เลย → โน้ตส่วนตัว งานวิจัยยังไม่ตีพิมพ์ บันทึกคนไข้ ข้อมูลนักศึกษา — ไม่มีอะไรออกอินเทอร์เน็ต
3) เทียบต้นทุน: local vs cloud API (คำนวณเองได้)¶
In [4]:
# สมมติ: vault 10,000 chunk · ค้นวันละ 50 ครั้ง · 1 ปี
chunks, queries_yr = 10_000, 50 * 365
# cloud embedding API (ราคาระดับ ~$0.1 / 1M tokens, chunk ~200 tokens)
embed_cost = chunks * 200 / 1e6 * 0.1
query_cost = queries_yr * 50 / 1e6 * 0.1
print(f'cloud: embed ครั้งแรก ~${embed_cost:.2f} + query 1 ปี ~${query_cost:.2f}')
print(f' + ค่า vector DB cloud รายเดือน + egress + ข้อมูลอยู่บน server คนอื่น')
print()
print(f'local: $0 ทุกรายการ (เครื่องที่มีอยู่แล้ว + Ollama ฟรี) · ข้อมูลอยู่กับเรา')
print()
print('→ เงินไม่ใช่ประเด็นหลักที่ scale นี้ — privacy กับ ownership ต่างหาก')
cloud: embed ครั้งแรก ~$0.20 + query 1 ปี ~$0.09
+ ค่า vector DB cloud รายเดือน + egress + ข้อมูลอยู่บน server คนอื่น
local: $0 ทุกรายการ (เครื่องที่มีอยู่แล้ว + Ollama ฟรี) · ข้อมูลอยู่กับเรา
→ เงินไม่ใช่ประเด็นหลักที่ scale นี้ — privacy กับ ownership ต่างหาก
✅ วัดผลตัวเอง #12 (ข้อสุดท้ายของเล่ม)¶
In [5]:
checks = {
'ข้อมูลเป็นไฟล์ในเครื่อง': db.exists(),
'embed ผ่าน localhost ได้': True,
}
try:
urllib.request.urlopen('http://localhost:11434/api/tags', timeout=2)
except Exception:
checks['embed ผ่าน localhost ได้'] = IN_COLAB # บน Colab ใช้ sentence-transformers ใน VM แทน
for k, v in checks.items():
print(f"{'✅' if v else '❌'} {k}")
assert all(checks.values()), 'local-first ต้องครบ'
print()
print('✅ จบเล่ม! คุณสร้าง second brain ที่ค้นด้วยความหมาย ตอบพร้อมอ้างอิง วัดผลได้ และเป็นของคุณ 100%')
✅ ข้อมูลเป็นไฟล์ในเครื่อง ✅ embed ผ่าน localhost ได้ ✅ จบเล่ม! คุณสร้าง second brain ที่ค้นด้วยความหมาย ตอบพร้อมอ้างอิง วัดผลได้ และเป็นของคุณ 100%
📊 เห็นภาพ — ต้นทุน local vs cloud (1 ปี)¶
In [6]:
# @@VIZ@@
import matplotlib, matplotlib.pyplot as plt
from matplotlib import font_manager as _fm
_av={f.name for f in _fm.fontManager.ttflist}
for _f in ['Thonburi','Loma','Sarabun','Noto Sans Thai','TH Sarabun New']:
if _f in _av: matplotlib.rcParams['font.family']=_f; break
matplotlib.rcParams['axes.unicode_minus']=False
labels=['cloud\n(embed+query/ปี)','local\n(Ollama)']
vals=[embed_cost+query_cost, 0.0]
plt.figure(figsize=(6,3.6)); b=plt.bar(labels,vals,color=['#eda100','#1baf7a'])
plt.bar_label(b,fmt='$%.2f'); plt.ylabel('USD/ปี')
plt.title('บทที่ 12 — เงินใกล้กัน · ประเด็นจริงคือ privacy + ownership'); plt.tight_layout(); plt.show()
🎓 สรุปทั้งเล่ม — สิ่งที่คุณทำได้แล้วจริงๆ¶
| บท | ทักษะที่พิสูจน์แล้ว (ด้วย self-check ✅) |
|---|---|
| 1 | สร้าง second brain 20 บรรทัด (upsert/query) |
| 2 | เลือก embedding model เป็น — bge-m3 แก้ไทย 3/3 |
| 3 | semantic + filter พร้อมกัน (ไม่มี leak) |
| 4 | cosine คำนวณมือ = โค้ด = 1024 มิติ |
| 5 | แผนที่ความหมาย + อ่านคะแนนเป็น (โซนเขียว/เหลือง/แดง) |
| 6 | วัด O(N) จริง · ANN knob · scale-appropriate |
| 7 | สร้าง hybrid เอง (BM25+RRF สูตรเดียวกับ production) |
| 8 | ingest ทั้ง vault แบบ idempotent |
| 9 | RAG ตอบ+cite+รู้จักบอกไม่พบ |
| 10 | ย้าย DB โดยผลไม่เปลี่ยน (ความรู้ติดตัว ไม่ติดเครื่องมือ) |
| 11 | วัดผลเอง: golden set → bge-m3 0.93 vs MiniLM 0.36 |
| 12 | ทั้งหมด local — privacy + ownership 100% |
ไปต่อ¶
- ทฤษฎีลึกทุกหัวข้อ:
deep-technical/(86 บท — จากสมการ attention ถึง CAP theorem) - ระบบ production จริง: ARRA Oracle (
arra-oracle-v3) — ทุก pattern ในเล่มนี้ทำงานจริงในนั้น - Workshop 26 กรกฎาคม 2026 🎓