Chapter 15 — Agent Architecture Blueprint: Dynamic Skills vs. Monolithic Prompts
ทำไมต้องชื่อนี้และเรียนไปเพื่ออะไร?
ใน Phase 1 (Day 1–14) เราสร้าง ReAct Agent ที่ใช้งานเครื่องมือ 2–3 ตัว เช่น read_file หรือ run_maven_test โดยยัดคำสั่ง เครื่องมือ และคู่มือทั้งหมดลงใน DEFAULT_SYSTEM_PROMPT ก้อนเดียว (Monolithic Prompt) ซึ่งใช้งานได้ดีในระดับห้องทดลอง
แต่ใน Phase 2 (Enterprise Software Engineering): เมื่อ Agent ต้องรองรับงานจริงนับสิบประเภท เช่น AST Code Skeleton Parsing, Cross-File Call Hierarchy, Git Worktrees Sandboxing, Security Auditing, และ Test Coverage Analysis...
หายนะจะเกิดขึ้นทันทีหากยังใช้ Monolithic Prompt:
1. Prompt Dilution (คำสั่งเจือจาง): การยัดคำสั่ง 40 หน้าลงใน Prompt ทำให้ Attention Span ของ Local LLM ขนาด 7B–14B ถูกกระจายจนจำกฎสำคัญไม่ได้ และเริ่มละเลยเงื่อนไขความปลอดภัย
2. Tool Selection Confusion: เมื่อมี Tools กองรวมกัน 20–30 ชิ้น โมเดลจะเริ่มส่งพารามิเตอร์สับสน หรือเลือกเครื่องมือผิดตัว
3. Context Budget Explosion: กินพื้นที่ Token เริ่มต้นไปแล้วกว่า 6,000–8,000 Tokens ตั้งแต่ยังไม่ได้เริ่มอ่านโค้ดจริง!
Day 15 เราจึงต้องเปลี่ยนผ่านสถาปัตยกรรมสู่ "Dynamic Skills Architecture (Microkernel & Pluggable Skills)":
แยกคู่มือและเครื่องมือเฉพาะทางออกเป็นตลับสกิลอิสระในโฟลเดอร์ skills/ แล้วใช้เทคนิค Two-Stage Progressive Disclosure: เริ่มต้นด้วยสารบัญย่อ (Catalog ~20 tokens/สกิล) และดึงคู่มือตัวเต็มเข้า Working Memory เฉพาะตอนที่ผู้ใช้สั่งงานเรื่องนั้นๆ จริงเท่านั้น!
ใน Day 15 เราจะวางรากฐานโฟลเดอร์ใหม่ skills/ และแยกประเภทไฟล์โครงสร้างของแต่ละ Skill Cartridge เพื่อเตรียมพร้อมสำหรับการสร้าง Registry ใน Day 16:
ทำหน้าที่เป็น Stage 1 Discovery Card บรรจุข้อมูลสั้นกระชับ (~25 Tokens) เช่น ID, ชื่องาน, Triggers และ Description เพื่อให้ ReAct Engine รวบรวมทำสารบัญสั้นๆ (Catalog) ใส่ใน System Prompt โดยไม่ทำให้ Context บวม
ทำหน้าที่เป็น Stage 2 Deep Operational Manual บรรจุกฎเหล็กทางวิศวกรรมเฉพาะทาง (เช่น AAA Pattern, Mocking Strategy, Edge Cases) ซึ่งจะถูกโหลดเข้าสู่ Working Memory เฉพาะตอนที่ Agent ตรวจพบว่าต้องทำงานที่ตรงกับสกิลนั้นเท่านั้น
ปัญหา: โมเดล 7B–14B สับสน เลือกลำดับ Tool ผิด กฎระเบียบเจือจาง และกินแรมตั้งแต่ยังไม่ได้เริ่มอ่านโค้ดงาน
ข้อได้เปรียบ: ประหยัด Token เริ่มต้น 90% โมเดลโฟกัสเฉพาะกฎที่กำลังทำอย่างแม่นยำ และต่อยอดได้ไม่จำกัดจำนวนสกิล
สแกนเจอโฟลเดอร์ใน skills/ ยังไม่กิน RAM
ดึง metadata สั้นๆ ใส่ Catalog ใน System Prompt (~25 tokens)
ตรวจพบเจตนา ดึง instructions.md เข้า Memory ชั่วคราว
งานเสร็จสิ้น ปลดคู่มือออกจาก Memory คืนความสดใหม่ให้ Context
{
"id": "unit_test_synthesizer",
"name": "Enterprise Unit Test Synthesizer",
"description": "สร้าง Unit Test คุณภาพระดับ Enterprise ตามมาตรฐาน AAA Pattern และครอบคลุมทั้ง Happy, Boundary และ Exception Paths",
"triggers": ["test", "unit test", "junit", "pytest", "test case", "mock"],
"version": "1.0.0"
}
# Role: Senior QA Automation & Test Architect
You are operating in specialized 'Unit Test Synthesizer' mode.
## Mandatory Rules:
1. **Strict AAA Structure**: Every test MUST be explicitly divided into:
- `// Arrange`: Setup mocks, inputs, and expected values.
- `// Act`: Execute the single target method under test.
- `// Assert`: Verify return values, exceptions, and verify mock interactions.
2. **Mocking Isolation**: Never call real external databases or network services. Mock all repositories and clients.
3. **Naming Standard**: Test method names must strictly follow `should_[ExpectedBehavior]_When_[StateUnderTest]()`.
4. **Three Critical Paths**: Every tested function must have:
- Happy Path: Valid inputs, expected successful outcome.
- Boundary Path: Empty collections, null checks, edge values (0, MAX_INT).
- Exception Path: Verify expected domain exceptions with `assertThrows`.
{
"id": "git_release_manager",
"name": "Git Release & Changelog Manager",
"description": "วิเคราะห์ Git Commits สร้าง Release Notes ตามมาตรฐาน Keep a Changelog และจัดการ Semantic Versioning",
"triggers": ["git release", "changelog", "release notes", "version bump", "tag"],
"version": "1.0.0"
}
import json
from pathlib import Path
SKILLS_DIR = Path("./skills").resolve()
def estimate_tokens(text: str) -> int:
"""ประมาณการจำนวนโทเค็นอย่างปลอดภัย (Heuristic: ~3.5 ตัวอักษรต่อ 1 token)"""
return int(len(text) / 3.5)
def simulate_monolithic_prompt(skills_root: Path) -> tuple[str, int]:
"""จำลองวิธีแบบเดิม (Monolithic): ยัดทุกคู่มือตัวเต็มของทุกสกิลลง Prompt ก้อนเดียว"""
monolithic_parts = [
"You are an Autonomous Software Engineering Agent.\n",
"--- GENERAL REACT RULES (500 words) ---\n" + ("Rules..." * 50) + "\n"
]
for skill_folder in skills_root.iterdir():
if skill_folder.is_dir() and (skill_folder / "instructions.md").exists():
inst = (skill_folder / "instructions.md").read_text(encoding="utf-8")
monolithic_parts.append(f"\n--- SKILL MANUAL: {skill_folder.name} ---\n{inst}\n")
full_prompt = "".join(monolithic_parts)
return full_prompt, estimate_tokens(full_prompt)
def simulate_two_stage_skills(skills_root: Path, active_skill_id: str) -> tuple[str, str, int]:
"""จำลองวิธีใหม่ (Two-Stage Progressive Disclosure): ส่งสารบัญย่อ + ขยายเฉพาะสกิลที่ Active"""
# Stage 1: สร้าง Catalog สารบัญย่อ
catalog_items = []
active_instructions = ""
for skill_folder in skills_root.iterdir():
if skill_folder.is_dir() and (skill_folder / "metadata.json").exists():
meta = json.loads((skill_folder / "metadata.json").read_text(encoding="utf-8"))
catalog_items.append(f"- [{meta['id']}]: {meta['description']}")
if meta['id'] == active_skill_id and (skill_folder / "instructions.md").exists():
active_instructions = (skill_folder / "instructions.md").read_text(encoding="utf-8")
stage_1_prompt = (
"You are an Autonomous Software Engineering Microkernel Agent.\n\n"
"AVAILABLE SKILLS CATALOG:\n" + "\n".join(catalog_items) + "\n\n"
"When a specialized task arrives, the corresponding manual will be dynamically expanded."
)
total_active_context = stage_1_prompt + "\n\nACTIVE SKILL EXPANSION:\n" + active_instructions
return stage_1_prompt, total_active_context, estimate_tokens(total_active_context)
def main():
print("=" * 70)
print("🚀 Day 15 Lab: Architecture Blueprint — Dynamic Skills vs. Monolithic Prompts")
print("=" * 70)
# 1. ทดสอบจำลอง Monolithic
_, mono_tokens = simulate_monolithic_prompt(SKILLS_DIR)
print(f"\n❌ [Monolithic Architecture] ขนาด Context ตั้งต้น: ~{mono_tokens} Tokens")
print(" 👉 ข้อเสีย: ยัดทุกคู่มือพร้อมกันทั้งหมด ยิ่งเพิ่มสกิล Token ยิ่งระเบิด โมเดลสับสน!")
# 2. ทดสอบจำลอง Two-Stage Progressive Disclosure
stage1_prompt, active_context, dynamic_tokens = simulate_two_stage_skills(SKILLS_DIR, "unit_test_synthesizer")
print(f"\n✅ [Dynamic Skills Architecture] ข้อมูล Stage 1 Catalog:")
print("-" * 50)
print(stage1_prompt)
print("-" * 50)
print(f"🎯 ขนาด Context เมื่อขยายเฉพาะสกิล 'unit_test_synthesizer': ~{dynamic_tokens} Tokens")
saved_percent = ((mono_tokens - dynamic_tokens) / mono_tokens) * 100
print(f"\n📊 ผลลัพธ์: ประหยัดพื้นที่ Token เริ่มต้นได้กว่า {saved_percent:.1f}%!")
print("🏆 พิสูจน์แล้วว่าระบบ Microkernel ช่วยให้ Mac M3 ประมวลผลได้เร็วเฉียบคม ไร้ Prompt Dilution 100%!")
if __name__ == "__main__":
main()
ชำแหละไวยากรณ์สำคัญในสถาปัตยกรรม Dynamic Skills
catalog_items.append(f"- [{meta['id']}]: {meta['description']}")
Stage 1 Low-Footprint Catalog: การส่งเพียง ID และ Description สรุป 1 บรรทัด ช่วยให้ Agent รู้จักทักษะทั้งหมดในระบบ โดยกินพื้นที่เพียง ~20–25 Tokens ต่อสกิลเท่านั้น ทำให้ระบบรองรับการมี 50 สกิลพร้อมกันได้สบายๆ
active_instructions = (skill_folder / "instructions.md").read_text()
Stage 2 On-Demand Expansion: อ่านไฟล์คู่มือตัวเต็มขึ้นมาจากดิสก์เฉพาะเมื่อสกิลนั้นถูกระบุตัวตน (Active) เท่านั้น จึงไม่มีขยะคำสั่งของสกิลอื่นเข้ามาเจือปน Attention
saved_percent = ((mono_tokens - dynamic_tokens) / mono_tokens) * 100
Token Budget Optimization: การประหยัดโทเค็นได้กว่า 80–90% ช่วยปลดล็อกให้โมเดลประมวลผลบน Apple Silicon Unified Memory ได้เร็วขึ้น 3 เท่า และเหลือพื้นที่ Context สำหรับอ่านซอร์สโค้ดจริงได้มากขึ้นมหาศาล
เปิด Terminal บน MacBook M3 แล้วทำตาม 5 ขั้นตอนนี้เพื่อสร้างโครงสร้าง Pluggable Skills และรันสคริปต์ทดสอบสถาปัตยกรรมทันที:
cd ~/se_agent
source .venv/bin/activate
mkdir -p skills/unit_test_synthesizer skills/git_release_manager
touch skills/__init__.py
touch skills/unit_test_synthesizer/metadata.json skills/unit_test_synthesizer/instructions.md
touch skills/git_release_manager/metadata.json
touch test_dynamic_skills_blueprint.py
- นำโค้ดใน ส่วนที่ 4 (ไฟล์ที่ 1) ไปวางใน skills/unit_test_synthesizer/metadata.json
- นำโค้ดใน ส่วนที่ 4 (ไฟล์ที่ 2) ไปวางใน skills/unit_test_synthesizer/instructions.md
- นำโค้ดใน ส่วนที่ 4 (ไฟล์ที่ 3) ไปวางใน skills/git_release_manager/metadata.json
- นำโค้ดใน ส่วนที่ 4 (ไฟล์ที่ 4) ไปวางใน test_dynamic_skills_blueprint.py
python test_dynamic_skills_blueprint.py
🎉 ผลลัพธ์: คุณจะเห็นหน้าจอ Terminal แสดงการเปรียบเทียบชัดเจนว่าวิธีเดิมกิน Token มหาศาล ในขณะที่วิธี Two-Stage Skills ดึงสารบัญ Catalog มาแสดงอย่างสะอาดตา และประหยัดพื้นที่ Token ได้อย่างน่าทึ่ง!
ตอนนี้โฟลเดอร์ skills/ มีโครงสร้างตลับสกิลที่ได้มาตรฐานแล้ว ใน Day 16 เราจะลงมือสร้างคลาส SkillRegistry และ SkillLifecycleManager ใน Python เพื่อสแกนและโหลดสกิลเหล่านี้โดยอัตโนมัติ!
ข้อที่ 1: วัตถุประสงค์หลักของ "Day 15: Agent Architecture Blueprint — Dynamic Skills vs. Monolithic Prompts" คืออะไร?
ข้อที่ 2: ปรากฏการณ์ "Prompt Dilution" (ความเจือจางของคำสั่ง) ส่งผลเสียร้ายแรงอย่างไรต่อ Local LLM ขนาด 7B–14B?
ข้อที่ 3: สถาปัตยกรรม "Microkernel" สำหรับ AI Agent หมายถึงการจัดวางระบบอย่างไร?
ข้อที่ 4: กลยุทธ์ "Two-Stage Progressive Disclosure" ในการบริหารจัดการ Context Window มีขั้นตอนอย่างไร?
ข้อที่ 5: องค์ประกอบมาตรฐานของ 1 Skill Cartridge ในโฟลเดอร์ `skills/` ควรมีไฟล์สำคัญใดบ้าง?
ข้อที่ 6: ข้อมูลในไฟล์ `metadata.json` ประจำแต่ละ Skill มีไว้เพื่อให้ส่วนใดนำไปใช้งาน?
ข้อที่ 7: กฎ "One-Active-Skill Policy" ในการบริหาร Working Memory มีจุดประสงค์เพื่ออะไร?
ข้อที่ 8: แนวคิด "Lazy Loading" ในการจัดการ Skill มีความหมายอย่างไร?
ข้อที่ 9: กระบวนการ "Context Eviction" มีความจำเป็นอย่างไรเมื่อ Agent สลับไปทำงานอื่น?
ข้อที่ 10: "Dedicated Tool Isolation" ช่วยลดปัญหาการเลือก Tool ผิดพลาดได้อย่างไร?
ข้อที่ 11: หากระบบมีสกิลรองรับทั้งหมด 30 สกิล การใช้ Dynamic Two-Stage Skills ประหยัด Token ได้ต่างจาก Monolithic อย่างไร?
ข้อที่ 12: อะไรคือความแตกต่างระหว่าง "Core System Prompt" กับ "Skill Instructions"?
ข้อที่ 13: การแยก Skills เป็นโฟลเดอร์โมดูลอิสระส่งผลดีต่อการขยายระบบ (Extensibility) อย่างไร?
ข้อที่ 14: หลังจากที่เราเข้าใจพิมพ์เขียวสถาปัตยกรรมใน Day 15 แล้ว ใน **Day 16** เราจะลงมือสร้างชิ้นส่วนใดต่อไป?
ข้อที่ 15: ในฐานะสถาปนิกซอฟต์แวร์ (Software Architect) เมื่อคุณเข้าใจสถาปัตยกรรม Dynamic Skills ใน Day 15 คุณรู้สึกอย่างไร?
🏁 สรุปหมุดเชื่อมโยง Day 15 (Chapter Wrap-up)
ใน Day 15 — Agent Architecture Blueprint: Dynamic Skills vs. Monolithic Prompts คุณได้วางรากฐานสถาปัตยกรรม Microkernel และเทคนิค Two-Stage Progressive Disclosure ที่พิสูจน์แล้วว่าช่วยประหยัด Token ได้กว่า 85–90% และปกป้องโมเดลบน MacBook M3 16GB ไม่ให้เกิดอาการ Prompt Dilution ตอนนี้พิมพ์เขียวและโฟลเดอร์ skills/ ของเราพร้อมแล้ว พร้อมก้าวเข้าสู่ Day 16: Building the Dynamic Skill Engine (SkillRegistry & Lifecycle Manager in Python) เพื่อลงมือสร้างเครื่องยนต์สแกนและโหลดสกิลจริงแล้วครับ!