สร้าง AI Agent ตรวจสุขภาพคลังความรู้ส่วนบุคคล: ค้นหาโน้ตรกร้าง เติม Metadata และจัดหมวดหมู่อัตโนมัติใน Obsidian ด้วย Python + Ollama
เมื่อ Second Brain ขยายตัวจนเกิดโน้ตรกร้างและ Metadata ไม่ครบ มาสร้าง AI Agent ส่วนตัวรันแบบ Local 100% เพื่อสแกน ตรวจสุขภาพ และจัดทำรายงานคลังความรู้ Obsidian Vault พร้อมคำแนะนำการปรับปรุงอย่างอัตโนมัติ
เมื่อระบบ Second Brain หรือคลังความรู้ส่วนตัวในแอปพลิเคชันอย่าง Obsidian ของเราเติบโตขึ้นจากหลักสิบเป็นหลักร้อยหรือหลักพันโน้ต สิ่งที่มักจะเกิดขึ้นตามมาโดยไม่รู้ตัวคือ "ขยะทางปัญญา (Digital Clutter)"
ปัญหาที่พบบ่อยได้แก่: * Orphan Notes (โน้ตรกร้าง): โน้ตที่ไม่มีการสร้างลิงก์เชื่อมโยงเข้า ([[...]]) หรือออกไปหาโน้ตอื่นเลย ทำให้หลุดออกจากเครือข่ายความรู้ * Missing Metadata: โน้ตที่ขาดข้อมูลส่วนหัว (YAML Frontmatter) เช่น วันที่สร้าง, สถานะ (Status), หรือหมวดหมู่ * Untagged Notes: โน้ตที่ไม่ติด แท็ก (Tag) ทำให้ค้นหาและกรองข้อมูลยากในอนาคต
การต้องมานั่งสแกนดูโน้ตทีละไฟล์เพื่อทำความสะอาด vault เป็นงานที่ใช้พลังสมองและเวลาอย่างมหาศาล ในบทความนี้ เราจะมาสร้างระบบ Cognitive Automation ด้วยภาษา Python ร่วมกับ Ollama เพื่อสร้าง Vault Health Check Agent ทำหน้าที่ตรวจสุขภาพคลังความรู้ สกัดข้อบกพร่อง และใช้ Local AI ช่วยวิเคราะห์พร้อมแนะนำการปรับปรุงให้อัตโนมัติแบบ Local 100% ปลอดภัย ไร้กังวลเรื่องข้อมูลส่วนตัวรั่วไหล
ทำไมต้องตรวจสุขภาพ Obsidian Vault แบบ Local 100%?
คลังความรู้ส่วนตัวคือ "สมองส่วนที่สอง" ที่บันทึกทั้งไอเดียธุรกิจ บันทึกส่วนตัว งานวิจัย และแผนการดำเนินชีวิต การวิเคราะห์เนื้อหาใน vault เพื่อจัดหมวดหมู่หรือแนะนำแท็ก จำเป็นต้องให้ AI อ่านเนื้อหาภายในโน้ตเหล่านั้น
หากเราใช้บริการ Cloud AI ทั่วไป ข้อมูลความคิดทั้งหมดจะถูกส่งออกนอกเครื่อง เสี่ยงต่อการนำไปใช้ฝึกโมเดลภายนอก การใช้ Local LLM ผ่าน Ollama ช่วยให้กระบวนการทั้งหมดเกิดขึ้นภายในเครื่องคอมพิวเตอร์ของคุณ 100% ประมวลผลได้เร็ว ไม่เสียค่าบริการรายเดือน และทำงานได้แม้ไม่มีอินเทอร์เน็ต
โครงสร้างการทำงานของ Vault Health Check Agent
สคริปต์ Python ที่เรากำลังจะสร้าง จะทำงาน 4 ขั้นตอนหลัก:
- สแกนไฟล์ (Vault Scanning): อ่านไฟล์
.mdทั้งหมดใน Obsidian Vault เพื่อดึงข้อมูล YAML Frontmatter, แท็ก#tag, และลิงก์ภายใน[[Link]] - วิเคราะห์ความผิดปกติ (Health Audit): ค้นหา Orphan Notes, ไฟล์ที่ไม่มี Metadata, และโน้ตที่สั้นเกินไป
- สังเคราะห์คำแนะนำด้วย Local AI (AI Recommendation): ส่งเนื้อหาของโน้ตที่มีปัญหาให้ Ollama เพื่อช่วยคิด Tag, Category, และแนะนำโน้ตที่ควรลิงก์ถึงกัน
- ออกรายงานสุขภาพ (Health Report Generation): บันทึกรายงานสรุปเป็นไฟล์ Markdown เข้าไปใน Obsidian Vault โดยตรง
สิ่งที่ต้องจัดเตรียมก่อนเริ่มต้น
- Python 3.8+ ติดตั้งในเครื่องเรียบร้อย
- Ollama ติดตั้งและรัน Service เรียบร้อย (ดาวน์โหลดจาก ollama.com)
- ดาวน์โหลดโมเดลภาษาที่เหมาะกับภาษาไทย เช่น gemma2 หรือ llama3.2:
ollama pull gemma2
โค้ด Python: สร้าง Vault Health Check Agent
สร้างไฟล์ vault_health_agent.py แล้ววางโค้ดสคริปต์ที่ออกแบบมาให้อ่านง่าย และใช้ไลบรารีมาตรฐานของ Python โดยไม่ต้องติดตั้งแพ็กเกจเสริม (Zero-dependency):
import os
import re
import json
import urllib.request
from pathlib import Path
# ================= ตั้งค่าระบบ (Configuration) =================
OBSIDIAN_VAULT_PATH = "/home/linn/notes" # ปรับเป็น Path ของ Obsidian Vault ของคุณ
REPORT_OUTPUT_DIR = os.path.join(OBSIDIAN_VAULT_PATH, "Reports")
LLM_MODEL = "gemma2" # โมเดลใน Ollama ที่ต้องการใช้
MAX_NOTES_TO_AI_ANALYZE = 5 # จำกัดจำนวนโน้ตที่มีปัญหาเพื่อส่งให้ AI ช่วยวิเคราะห์ต่อรอบ
# =============================================================
def parse_md_file(file_path):
"""อ่านและสกัดโครงสร้างของไฟล์ Markdown"""
with open(file_path, "r", encoding="utf-8", errors="ignore") as f:
content = f.read()
# สกัด YAML Frontmatter
has_frontmatter = bool(re.match(r'^---\s*\n.*?\n---\s*\n', content, re.DOTALL))
# สกัด WikiLinks [[...]]
links = set(re.findall(r'\[\[([^\]\|]+)(?:\|[^\]]+)?\]\]', content))
# สกัด Tags #tag
tags = set(re.findall(r'(?<!\w)#([a-zA-Z0-9_\-ก-๙]+)', content))
# คำนวณความยาวเนื้อหาแบบหยาบ
clean_text = re.sub(r'^---\s*\n.*?\n---\s*\n', '', content, flags=re.DOTALL).strip()
word_count = len(clean_text.split())
return {
"path": file_path,
"name": Path(file_path).stem,
"has_frontmatter": has_frontmatter,
"links": links,
"tags": tags,
"word_count": word_count,
"content_snippet": clean_text[:400] # สแนปชอตสั้นๆ สำหรับ AI
}
def scan_vault(vault_path):
"""สแกนโน้ตทั้งหมดใน Vault เพื่อหาจุดที่ต้องปรับปรุง"""
all_notes = {}
inbound_links = {}
# เดินสแกนทุกไฟล์ .md
for root, _, files in os.walk(vault_path):
for file in files:
if file.endswith(".md") and not file.startswith("."):
full_path = os.path.join(root, file)
parsed = parse_md_file(full_path)
note_name = parsed["name"]
all_notes[note_name] = parsed
inbound_links.setdefault(note_name, 0)
# นับการลิงก์ข้ามโน้ต (Inbound count)
for note_name, data in all_notes.items():
for target in data["links"]:
clean_target = Path(target).stem
if clean_target in inbound_links:
inbound_links[clean_target] += 1
else:
inbound_links[clean_target] = 1
# แยกประเภทปัญหา
orphans = []
missing_metadata = []
untagged = []
for note_name, data in all_notes.items():
# เป็น Orphan ถ้าไม่มีลิงก์ออก และไม่มีใครลิงก์เข้ามาหา
if len(data["links"]) == 0 and inbound_links.get(note_name, 0) == 0:
orphans.append(data)
if not data["has_frontmatter"]:
missing_metadata.append(data)
if len(data["tags"]) == 0:
untagged.append(data)
return all_notes, orphans, missing_metadata, untagged
def ask_ollama_for_suggestions(note_data):
"""ส่งเนื้อหาโน้ตที่มีปัญหาให้ Ollama ช่วยคิด Tag และ Category"""
prompt = f"""คุณคือผู้เชี่ยวชาญด้านระบบ Second Brain และ PKM (Personal Knowledge Management)
โปรดวิเคราะห์โน้ตด้านล่างนี้ แล้วแนะนำ:
1. หมวดหมู่หลัก (Category) 1 หมวด
2. แท็กที่เหมาะสม 3-5 แท็ก (รูปแบบ #tag)
3. สรุปแนวคิดหลัก 1 ประโยค
ชื่อโน้ต: {note_data['name']}
เนื้อหาบางส่วน:
{note_data['content_snippet']}
ตอบสั้นๆ ชัดเจน ภาษาไทย:"""
payload = {
"model": LLM_MODEL,
"prompt": prompt,
"stream": False
}
try:
req = urllib.request.Request(
"http://localhost:11434/api/generate",
data=json.dumps(payload).encode("utf-8"),
headers={"Content-Type": "application/json"}
)
with urllib.request.urlopen(req, timeout=30) as resp:
res = json.loads(resp.read().decode("utf-8"))
return res.get("response", "").strip()
except Exception as e:
return f"ไม่สามารถเรียก AI ได้: {str(e)}"
def generate_health_report(all_notes, orphans, missing_meta, untagged):
"""สร้างรายงานผลสรุปเป็นไฟล์ Markdown เข้า Obsidian"""
os.makedirs(REPORT_OUTPUT_DIR, exist_ok=True)
report_file = os.path.join(REPORT_OUTPUT_DIR, "Vault-Health-Report.md")
total_count = len(all_notes)
orphan_count = len(orphans)
meta_count = len(missing_meta)
untagged_count = len(untagged)
# คำนวณคะแนนสุขภาพ Vault (คะแนนเต็ม 100)
health_score = max(0, 100 - int((orphan_count * 3 + meta_count * 2 + untagged_count * 1) / (total_count or 1) * 20))
lines = []
lines.append("---")
lines.append("title: 'Vault Health Check Report'")
lines.append("type: 'report'")
lines.append("tags: ['pkm', 'vault-health', 'automation']")
lines.append("---\n")
lines.append("# 🏥 รายงานตรวจสุขภาพคลังความรู้ (Vault Health Report)")
lines.append(f"\n* **จำนวนโน้ตทั้งหมด:** {total_count} ไฟล์")
lines.append(f"* **คะแนนสุขภาพ Vault:** `{health_score}/100`")
lines.append("\n---")
lines.append("### 📊 ภาพรวมข้อบกพร่องที่พบ")
lines.append(f"* 🔗 **Orphan Notes (โน้ตรกร้าง ไร้การเชื่อมโยง):** {orphan_count} ไฟล์")
lines.append(f"* 📋 **Missing Metadata (ขาด Frontmatter):** {meta_count} ไฟล์")
lines.append(f"* 🏷️ **Untagged Notes (ไม่มีแท็ก):** {untagged_count} ไฟล์")
lines.append("\n---\n### 💡 คำแนะนำจาก AI สำหรับโน้ตที่ควรปรับปรุง\n")
# สุ่ม/ดึงโน้ตที่มีปัญหามาให้ AI ช่วยแนะนำ
problematic_notes = (orphans + untagged)[:MAX_NOTES_TO_AI_ANALYZE]
for idx, note in enumerate(problematic_notes, 1):
print(f"กำลังวิเคราะห์ข้อเสนอแนะสำหรับ: {note['name']}...")
ai_suggestion = ask_ollama_for_suggestions(note)
lines.append(f"#### {idx}. [[{note['name']}]]")
lines.append(f"**ปัญหาที่พบ:** {'ไร้ลิงก์เชื่อมโยง ' if note in orphans else ''}{'ไม่มีแท็ก' if note in untagged else ''}")
lines.append(f"**คำแนะนำจาก AI:**\n{ai_suggestion}\n")
lines.append("---\n### 🛠️ Action Items ที่แนะนำให้ทำ")
lines.append("1. เปิดโน้ตในกลุ่ม **Orphan Notes** แล้วเพิ่ม `[[...]]` เชื่อมไปยังโน้ตที่เกี่ยวข้องหรือ MOC")
lines.append("2. เติม YAML Frontmatter ให้กับโน้ตที่ขาดข้อมูลพื้นฐาน")
lines.append("3. ติดแท็กหมวดหมู่หลักเพื่อเพิ่มความสะดวกในการค้นหาผ่าน Dataview")
with open(report_file, "w", encoding="utf-8") as f:
f.write("\n".join(lines))
print(f"\n✅ สร้างรายงานสุขภาพสำเร็จแล้วที่: {report_file}")
if __name__ == "__main__":
print("🔍 กำลังเริ่มสแกน Obsidian Vault...")
all_notes, orphans, missing_meta, untagged = scan_vault(OBSIDIAN_VAULT_PATH)
generate_health_report(all_notes, orphans, missing_meta, untagged)
วิธีการนำไปใช้งาน
- เปิด Terminal แล้วเปลี่ยน Path ในตัวแปร
OBSIDIAN_VAULT_PATHในสคริปต์ให้ตรงกับโฟลเดอร์ Obsidian จริงของคุณ - รันสคริปต์ผ่าน Terminal:
python3 vault_health_agent.py
- เมื่อสคริปต์ทำงานเสร็จ ให้เปิดแอป Obsidian แล้วเข้าไปดูที่โฟลเดอร์
Reports/Vault-Health-Report.mdคุณจะพบกับรายงานสุขภาพที่คำนวณคะแนนและมีคำแนะนำจัดแท็กแบบอัตโนมัติจาก Local AI
ต่องานแบบอัตโนมัติด้วย Cron หรือ Task Scheduler
เพื่อให้คลังความรู้ของคุณได้รับการดูแลอย่างสม่ำเสมอ คุณสามารถตั้งให้สคริปต์นี้ทำงานทุกคืนวันอาทิตย์ผ่าน Cron Job บน Linux/macOS ได้ง่ายๆ:
# เปิดแก้ไข cron
crontab -e
# เพิ่มบรรทัดนี้เพื่อรันทุกวันอาทิตย์ เวลา 22:00 น.
0 22 * * 0 /usr/bin/python3 /path/to/vault_health_agent.py
บทสรุป
การสร้าง Second Brain ไม่ใช่เรื่องของการสะสมปริมาณโน้ตให้ได้มากที่สุด แต่เป็นเรื่องของการรักษาคุณภาพและความเชื่อมโยงของระบบความรู้ การใช้ Cognitive Automation ผ่าน Python และ Ollama ช่วยเปลี่ยนงานดูแลระบบที่น่าเบื่อ ให้กลายเป็นระบบอัตโนมัติที่คอยดูแลสุขภาพสมองส่วนที่สองของคุณอยู่เสมอ โดยที่ข้อมูลความรู้ทั้งหมดยังคงเป็นของคุณ 100% บนเครื่องคอมพิวเตอร์ส่วนตัว