ลองทำ Privacy Filter ให้ AI ด้วยเครื่องเก่าที่บ้าน
ผมใช้ AI ในชีวิตประจำวันมากขึ้นเรื่อยๆ ทั้ง Claude ทั้ง Gemini ช่วยเขียนโค้ด คิดงาน แก้ปัญหา
แต่มีบางวันที่อยากถามเรื่องที่อ่อนไหวหน่อย เช่น ให้ดูฟอร์มที่มีเลข SSN (เลขประกันสังคมของสหรัฐฯ) ให้ดีบัก config ที่มี password
ให้ช่วยอ่าน email ที่มีข้อมูลสำคัญ หรือให้ตรวจสอบเรื่องบัญชีธนาคาร
“แล้วผมก็หยุดคิดว่า ข้อมูลพวกนี้ถูกส่งขึ้น server ของบริษัทอื่นทั้งหมดนะ”
จริงๆ ก็เชื่อใจ Google กับ Anthropic อยู่แล้วนะ ฮ่าๆ แต่ก็แอบไม่สบายใจ
เลยคิดว่าลองทำ project สนุกๆ ดูดีกว่า
จุดเริ่มต้น: อยากรันทุกอย่างในเครื่องตัวเอง
แผนแรกคือรัน AI ทั้งหมดใน local (ในเครื่องตัวเอง ไม่ผ่านอินเทอร์เน็ต) ไม่ต้องส่งข้อมูลออกเลย ตอนนั้น Gemma 4 เพิ่งออก
ก็ลองเลย ใช้ผ่าน Open WebUI (หน้าเว็บสำหรับคุยกับ AI ที่รันในเครื่อง) ด้วย
เริ่มจาก e4b ก่อน เพราะน่าจะเป็น model ที่เล็กที่สุดที่เข้าใจ image ได้ด้วย
แต่ผลคือ… ช้ามากครับ โมเดลมันใหญ่เกิน VRAM (หน่วยความจำของ GPU) 4GB ของผม เลย spill ลง CPU
(เมื่อ VRAM ไม่พอ โมเดลจะดึง RAM ปกติมาใช้แทน ซึ่งช้ากว่ากันมาก)
response ทีนึงนาน 38 วินาที ใช้ผ่าน Open WebUI ยิ่งช้าลงอีก
เครื่องผม: คอมเก่าที่บ้าน ใส่ GPU (ชิปประมวลผลกราฟิก) NVIDIA GTX 1050 Ti VRAM แค่ 4GB รัน Ubuntu Server เปิดตลอด 24 ชั่วโมง
ทางเลือกอื่นที่คิดถึง:
| ตัวเลือก | ปัญหา |
|---|---|
| รันทุกอย่าง local | ต้องการ VRAM เยอะ โมเดลดีๆ ต้องการ 16GB+ |
| ใช้ cloud AI ตรงๆ | ข้อมูลส่วนตัวออกจากเครื่องไปอยู่บน server ของบริษัทอื่นทั้งดุ้น |
| เช่า cloud GPU server (เช่าเครื่องพลังสูงออนไลน์) | $150-300/เดือน แถมข้อมูลก็ยังออกนอกบ้านอยู่ดี |
ไอเดีย: Screen ก่อนส่ง
คิดขึ้นมาเองว่า ถ้าลบข้อมูลส่วนตัวออกก่อนที่มันจะออกจากบ้าน cloud AI ก็จะเห็นแค่ข้อความสะอาดๆ
เอาไอเดียนี้ไปคุยกับ Claude ดูว่าเป็นไปได้ไหม แล้วไปค้นดูว่ามีคนทำแบบนี้กันบ้างไหม ปรากฎว่ามี concept นี้อยู่จริงๆ
เลยลองทำดู
แผนคือสร้าง proxy server (ตัวกลางที่รับส่งข้อมูลแทนเรา) ที่นั่งอยู่กลางระหว่างเราและ cloud AI:
รันบนเครื่องเก่าที่บ้าน
- ตรวจสอบ API key (รหัสสำหรับพิสูจน์ตัวตนว่าใครเป็นคนส่งข้อมูล)
- สแกนข้อความด้วย AI ในเครื่อง
- แทนที่ PII ด้วย
[SSN][PASSWORD] - ส่งข้อความสะอาดไป cloud
- ส่งคำตอบกลับมา
จุดสำคัญ: cloud model ไม่เคยเห็นข้อมูลจริงๆ มันเห็นแค่ [SSN], [CREDIT_CARD], [PASSWORD] แทน
เลือก Local Model สำหรับ Screen
ทดสอบกับ Claude ว่าโมเดลไหนน่าจะ fit กับเครื่องที่มี ดูหลายตัว สุดท้ายได้ผลนี้:
ลองไปหลายตัวเรียงกัน:
| โมเดล | ขนาด | ผล |
|---|---|---|
| Gemma 4 27B | ~16GB | ใช้ไม่ได้เลย VRAM ไม่พอ |
| Gemma 4 e4b | 9.6GB | Spill ลง CPU ช้ามาก ~38 วินาที/ตอบ |
| Gemma 4 e2b | 7.2GB | เร็วขึ้นหน่อย แต่ยังช้า และไม่รองรับ image |
| qwen2.5vl:3b | 3.2GB | เร็ว แต่ benchmark (ผลทดสอบความแม่นยำ) PII screening ไม่ดีเท่า |
| phi4-mini | 2.5GB | เร็ว แต่ benchmark PII screening ไม่ดีเท่า |
| gemma3:4b | 3.3GB | Fit VRAM พอดี เร็ว รองรับ image ✓ |
ที่เลือก gemma3:4b ไม่ใช่แค่เพราะขนาดหรือความเร็ว โมเดลนี้รองรับ image ด้วย
ซึ่ง e2b ทำไม่ได้ เผื่อในอนาคตถ้าส่ง screenshot ไปให้ AI
โมเดลนี้จะสแกน sensitive data ในภาพได้ก่อนส่งออก
บทเรียน: โมเดลเล็กที่ fit ใน VRAM เร็วกว่าโมเดลใหญ่ที่ spill ลง CPU มากกว่า 10 เท่า
สิ่งที่ Proxy ตรวจจับ
ใช้วิธี hybrid คือผสม regex (การค้นหาข้อความด้วย pattern เช่น “ตัวเลข 9 หลักที่มีขีด”) กับ LLM (โมเดล AI ที่เข้าใจความหมายของภาษา) เข้าด้วยกัน แทนที่จะใช้อย่างใดอย่างหนึ่ง
Regex (เร็ว แม่นยำ 100% สำหรับ format คงที่)
- SSN:
XXX-XX-XXXX,XXX XX XXXX,ssn#XXXXXXXXX→[SSN] - บัตรเครดิต 16 หลัก (Visa, MC, Discover) →
[CREDIT_CARD] - บัตรเครดิต 15 หลัก (Amex) →
[CREDIT_CARD] - Routing number (รหัสธนาคาร) / Account number (หมายเลขบัญชี) →
[ROUTING],[ACCOUNT]
LLM — gemma3:4b (เฉพาะสิ่งที่ไม่มี format คงที่)
- Password และ passphrase →
[PASSWORD] - รันเฉพาะเมื่อเจอคีย์เวิร์ด “password”, “passwd”, “secret”, “pin” เท่านั้น
- ข้อความทั่วไปที่ไม่มีคีย์เวิร์ดพวกนี้ ข้าม LLM ไปเลย เร็วขึ้นมาก
ทำไมถึงต้อง Hybrid?
เวอร์ชันแรกผมใช้ gemma3:4b สแกนทุกอย่าง ปัญหาที่เจอ:
- โมเดลแทนที่คำว่า “ssn” แทนที่จะแทนที่ตัวเลข
482-91-7823 - ผลลัพธ์ไม่สม่ำเสมอ ขึ้นอยู่กับว่าเขียนประโยคยังไง
SSN มี format ตายตัว regex จัดการได้ดีกว่า เร็วกว่า แม่นกว่า
แต่ password ไม่มี format ตายตัว LLM เข้าใจ context ได้ดีกว่า
Caching: แก้ปัญหาที่ไม่ได้คาดไว้
พอใช้กับ Open WebUI ก็เจอปัญหาที่ไม่ได้คาดไว้ UI นี้ส่ง conversation history (ประวัติการสนทนาทั้งหมดตั้งแต่ต้น) ทุกครั้งที่ส่งข้อความใหม่
คุยไป 10 รอบ รอบที่ 10 proxy ต้องสแกน 10 ข้อความ ทั้งที่ 9 ข้อความแรกสแกนไปแล้ว ช้าโดยไม่จำเป็น
วิธีแก้คือ cache (เก็บผลที่คำนวณไว้แล้วไว้ใช้ซ้ำ) ด้วย SHA-256 hash (รหัสเฉพาะที่สร้างจากเนื้อหาข้อความ ถ้าข้อความเหมือนกันทุกตัวอักษร hash จะเหมือนกันเป๊ะ) ถ้าเจอข้อความที่เคยสแกนแล้ว คืนผลทันทีโดยไม่ต้องถาม AI อีกรอบ
_cache: dict[str, str] = {}
def _hash(value: str) -> str:
return hashlib.sha256(value.encode()).hexdigest()
async def screen_text(text: str) -> str:
key = _hash(text)
if key in _cache:
return _cache[key] # ไม่ต้องถาม LLM
# ... เรียก gemma3:4b ...
_cache[key] = result
return resultAPI Design: Compatible กับ OpenAI
Proxy ทำงานในรูปแบบเดียวกับ OpenAI API (มาตรฐานการเชื่อมต่อที่แอปและ UI ส่วนใหญ่รองรับ) เลย ไม่ต้องแก้โค้ด client แค่เปลี่ยน URL
POST http://YOUR_SERVER_IP:8000/v1/chat/completions
Authorization: Bearer <your-key>
{
"model": "screened/groq/llama-3.3-70b-versatile",
"messages": [{"role": "user", "content": "my ssn is 482-91-7823"}]
}Convention ของชื่อ model:
groq/llama-3.3-70b-versatile→ ส่งตรงไป Groq ไม่สแกนscreened/groq/llama-3.3-70b-versatile→ สแกนก่อน แล้วส่ง Groqscreened/gemini-2.0-flash→ สแกนก่อน แล้วส่ง Gemini
ทุก response มี metadata บอกว่าผ่าน screening หรือเปล่า:
"x_pii_proxy": {
"screened": true,
"screen_time_s": 1.23,
"screener_model": "gemma3:4b"
}ผลการทดสอบ
| Input | Output | ผล |
|---|---|---|
my ssn is 482-91-7823 | my ssn is [SSN] | ✓ |
social security 482 91 7823 | social security [SSN] | ✓ |
ssn#482917823 | ssn#[SSN] | ✓ |
my visa is 4111 1111 1111 1111 | my visa is [CREDIT_CARD] | ✓ |
my password is Hunter2@secure | my password is [PASSWORD] | ✓ |
passwd: abc123 | passwd: [PASSWORD] | ✓ |
order #482917823 please ship | ไม่เปลี่ยน | ✓ ไม่ false positive (ไม่แทนที่ผิดพลาด) |
I scored 4111 points | ไม่เปลี่ยน | ✓ ไม่ false positive |
what is an SSN? | ไม่เปลี่ยน | ✓ ถามเฉยๆ ไม่มีเลข |
ค่าใช้จ่าย
| รายการ | ค่าใช้จ่าย |
|---|---|
| คอมเก่าที่บ้าน + GTX 1050 Ti | มีอยู่แล้ว |
| Groq free tier (แพ็กเกจฟรี 14,400 req/วัน) | $0 |
| Gemini free tier (แพ็กเกจฟรี 1,500 req/วัน) | $0 |
| ค่าไฟ | ~$5-10/เดือน |
| รวม | ~$5-10/เดือน |
เทียบกับเช่า cloud GPU server: $150-300/เดือน
สิ่งที่ได้เรียนรู้
- Hybrid regex+LLM ดีกว่า LLM อย่างเดียว ใช้ regex สำหรับ format คงที่ ใช้ LLM เฉพาะส่วนที่ต้องเข้าใจ context
- VRAM คือข้อจำกัดจริงๆ โมเดลที่ fit ใน VRAM เร็วกว่าที่ spill ลง CPU มากกว่า 10 เท่า
- OpenAI-compatible API ตัดสินใจถูก client ทุกตัว ทุก UI ใช้ได้เลยโดยไม่ต้องแก้โค้ด
- Cache conversation history จำเป็นมาก สำหรับ chat UI ที่ส่ง history ทั้งหมดทุกครั้ง
- Free tier ของ cloud พอสำหรับใช้ส่วนตัว Groq 14,400 req/วันเกินพอแล้ว
สรุป
โปรเจกต์นี้ทำสนุกๆ มากกว่าจะเป็น production-ready solution จริงๆ
และถ้าพูดตรงๆ ผมก็เชื่อใจ Anthropic กับ Google อยู่แล้วในระดับนึงนะ ฮ่าๆ
แต่ก็ได้เรียนรู้อะไรเยอะจากการทำ
ถ้าอยากใช้จริงจัง วิธีที่ดีที่สุดน่าจะเป็น build เครื่องมาสำหรับรัน local model โดยตรงเลย
แต่ถ้ายังไม่อยากลงทุน มีเครื่องเก่าอยู่บ้าน GPU ไม่แรงมากก็ลองทำ proxy แบบนี้ได้เลย
ต้นทุนแทบไม่มี แต่ได้เรียนรู้เยอะ
Tech stack สรุป: FastAPI + Ollama (gemma3:4b) + Groq/Gemini free tier + Open WebUI + systemd
Leave a Reply