(with Go as our trusty sidekick)


| ปัญหา | ผลที่ตามมา |
|---|---|
| Toolless | ดึงข้อมูลจาก DB ไม่ได้ ยิง API ไม่ได้ |
| Stateless | คุยจบ ลืมทันที |
| Passive | ไม่ถาม ไม่เคยตอบ ไม่เคยลงมือทำเอง |
Agent = Model + HarnessHarness คือ "สายรัด" หรือโครงที่เราเขียนครอบ LLM เอาไว้ ให้มันมีมือ มีความจำ มีลูป คิด-ทำ-เช็คผล ซ้ำได้เอง
| Concept | LLM | AI Agent |
|---|---|---|
| Role | Oracle (ผู้พยากรณ์) | Worker / Actor |
| State | Stateless | Stateful (มีความจำ) |
| Action | ทายคำตอบ | เรียก Tool จริง |
| Flow | ตอบครั้งเดียวจบ | Loop คิด-ทำ-ทวน |


---> ห้ามทำอะไรเด็ดขาด
- กำหนดตัวตนของ Agent
- ตีกรอบขอบเขตการทำงาน
ชั้นแรกสุดคือการบอกมันว่า "แกเป็นใคร" กับ "แกห้ามทำอะไร"
เป็นเรื่องง่ายที่สุดแต่สำคัญที่สุด เพราะทุกชั้นถัดไปทำงานอยู่ภายใต้กรอบนี้
PO: นี่คือที่ที่เราใส่ business rule ลงไปตรงๆ
QA: เวลาเทสต์ ต้องลองหาทาง "jailbreak" ดูว่ามันหลุดกรอบตรงนี้ไหม
Script พูด:
มาถึงชั้นแรกของการประกอบ Harness — System Instruction หรือ Persona
พูดง่ายๆ คือ ก่อนจะให้ Agent ทำอะไร เราต้องบอกมันก่อนว่า "แกเป็นใคร" กับ "แกห้ามทำอะไรเด็ดขาด"
ดูจาก diagram — เราเริ่มจาก System Prompt แล้วมันจะกำหนดขอบเขตสองด้าน ด้านหนึ่งคือทำอะไรได้บ้าง อีกด้านคือห้ามทำอะไร
ฟังดูเป็นเรื่องง่ายมาก แต่จริงๆ นี่คือชั้นที่สำคัญที่สุด เพราะทุกชั้นที่เราจะประกอบต่อจากนี้ — Tools, State, Callbacks, Workflow — ทำงานอยู่ภายใต้กรอบนี้ทั้งหมด ถ้าชั้นนี้หลวม ชั้นอื่นแน่นแค่ไหนก็ไม่ช่วย
สำหรับ PO ในห้อง — นี่คือจุดที่เราใส่ business rule ลงไปตรงๆ เลย เช่น "ห้ามให้ราคาต่ำกว่าทุน" หรือ "ตอบได้เฉพาะเรื่องสินค้าเรา"
สำหรับ QA — เวลาเทสต์ระบบนี้ สิ่งที่ต้องทำคือลองหาทาง jailbreak ดูว่าถ้าเราพยายามยั่ว มันจะหลุดกรอบที่ตั้งไว้ตรงนี้ไหม
-->
LLM ทำได้แค่ "คิด" แล้วบอกว่าอยากเรียก tool อะไร คนที่ "ลงมือทำจริง" คือโค้ดฝั่งเรา ไม่ใช่ตัว LLM เอง



|
( Tool ทำงานจริง )
|
[ หลังเรียก Tool ] | [ Response ]
- ดักจับ input/output ก่อน-หลัง
- บังคับ policy โดยไม่พึ่งดุลยพินิจของ AI
LLM เชื่อ 100% ไม่ได้ (hallucinate ได้เสมอ) เราเลยต้องมี guardrail ที่เป็นโค้ดล้วนๆ ไม่ใช่ prompt
เราใส่ hook ดักก่อน/หลัง เรียก model หรือ tool ก็ได้
QA/Security: ตรงนี้แหละคือจุดทำ automated security testing — เซ็นเซอร์ PII เช็คสิทธิ์ โดยไม่ต้องหวังพึ่งว่า AI จะ "ทำถูก" เอง
-->



$ claude
> เขียน python script สแกน open port บน localhost
| Claude Code มี... | ...คือชั้นไหนใน Part 3 |
|---|---|
| ตอบเป็นคนไม่ใช่หุ่นยนต์ | System Instruction |
| อ่าน/เขียนไฟล์, รันคำสั่ง | Tools |
| จำบทสนทนา, จำ context โปรเจกต์ | Sessions & State |
| ขอ permission ก่อนทำอะไรเสี่ยง | Callbacks & Safety |
| โหลดความรู้เฉพาะทางตามจังหวะ | Skills |
| แตกงานให้ subagent | Multi-Agent |
ไม่ใช่ "ปลั๊กอิน" ไม่ใช่ "โมเดลใหม่"
Skill = ไฟล์คำสั่ง (instructions) ที่ถูกเขียนแยกไว้เป็นชุดๆ แล้วให้ตัว harness ตัดสินใจว่า "ตอนนี้ควรโหลดชุดไหนเข้ามา"
ทุก skill คือไฟล์ SKILL.md หนึ่งไฟล์
เริ่มด้วย frontmatter สั้นๆ 2 บรรทัด:
name — ชื่อ skilldescription — สรุป 1 บรรทัดว่า "ใช้ตอนไหน"ส่วนเนื้อหาด้านล่าง คือคำสั่งแบบละเอียดยิบ
---
name: brainstorming
description: >
Use before any creative work -
creating features, building
components, designing systems.
---
# Brainstorming Ideas into Designs
... (คำสั่งเต็มยาวๆ ต่อจากนี้) ...
ชั้น 1: name + description <- โหลดเสมอ ทุก skill ทุกครั้ง (เบามาก)
ชั้น 2: เนื้อหาคำสั่งเต็ม <- โหลดเมื่อ "ตรง" กับสิ่งที่กำลังทำ
ชั้น 3: ไฟล์แนบ (scripts, docs) <- โหลดเมื่อ skill นั้นเรียกใช้เอง

Agent = Model + Harness
Model = LLM (ไม่ได้เขียนด้วย Go — เป็น service ที่เราเรียกใช้) Harness = โค้ด Go ทั้งหมดที่ประกอบมาใน Part 3
agent.NewTool(
"run_command",
"Run shell command",
func(ctx context.Context, cmd string) (string, error) {
out, err := exec.Command("sh", "-c", cmd).CombinedOutput()
return string(out), err
},
)
agent.WithBeforeModel(func(ctx context.Context, req *llm.Request) error {
// โหลด skill ตาม trigger (progressive disclosure ชั้น 2)
if isTranslationCommand(req) {
skillData, _ := os.ReadFile("skills/translate.md")
req.System = string(skillData) + "\n" + req.System
}
// กรอง PII ก่อนออกจาก server เสมอ
return redactPII(req)
})

|
+------+------+
| |
[ CHAT ] [ RESEARCH ]
| |
+------+------+
|
[ END ]
- ประกาศ state transition ชัดเจน
- เส้นทางเดินคาดเดาได้ ไม่ freestyle
ตัวอย่างสุดท้ายฝั่ง Go คือ graph workflow — บังคับให้ agent เดินตาม router ก่อนเสมอ
เขียนเป็น node/edge ชัดเจนใน Go เอง ไม่ต้องหวังให้ LLM "จำ" ว่าต้องทำตามลำดับ เพราะโค้ดบังคับไว้แล้ว
-->
func TestAgentWorkflow(t *testing.T) {
mockLLM := mock.NewLLM(
mock.WithToolCall("run_command", `{"cmd":"echo hi"}`),
)
ag := agent.New(mockLLM, tools)
res, _ := ag.Run(ctx, "say hi")
assert.Contains(t, res, "hi")
}
เราไม่ได้เทส AI — เราเทส Harness ของเรา
Minimum bar เมื่อเวลาไม่พอ:
LLM → เจอกำแพง → ใส่ Harness ทีละชั้น → กลายเป็น Agent → ส่อง Claude Code → เจาะ Skill → ใช้ Go ทำ AI Agent ด้วย ADK → Checklist ใช้ AI เขียนโค้ด
(ลองเริ่มสร้าง Agent ตัวแรกของคุณเองได้เลยวันนี้)