AI Agents — จาก agent loop เดี่ยว ถึงทีม multi-agent
หมวด AI Agents ใหญ่สุดในคลัง (34 ตัว) เพราะมันคือหัวใจของแอป AI ยุคนี้ บทนี้จะไม่ให้คุณจำชื่อทั้ง 34 ตัว แต่จะถอด pattern ร่วม ที่ทุกตัวใช้ — พอเข้าใจ pattern แล้ว เปิดตัวไหนก็อ่านออกทันที และที่สำคัญ: เอาไปเขียนเองบน NestJS/Go ได้ (ควรเรียน HO-0 มาก่อนเพื่อรู้วิธีเดินอ่านโปรเจกต์)
agent ต่างจาก "เรียก LLM ครั้งเดียว" ยังไง
การเรียก LLM ธรรมดา = ส่ง prompt เข้าไป 1 ครั้ง ได้คำตอบ 1 ครั้ง จบ แต่ agent คือการให้ LLM วนคิด-ทำ-ดูผล หลายรอบ โดยมันตัดสินใจเองว่าจะทำอะไรต่อ จนกว่างานจะเสร็จ หัวใจคือ loop ที่เรียกว่า think → act → observe
โปรเจกต์ smolagents_code_agent ในคลังคือตัวอย่างชัดที่สุด — README มันบอกตรง ๆ ว่า
รับโจทย์ภาษาคนแล้ว "reasons through it with a think-act-observe loop" โดยแต่ละรอบมันจะ
เขียนโค้ด Python แล้วรันเอง (มี tool คือ DuckDuckGo ค้นเว็บ + Wikipedia)
และ stream ทุก step ให้ดูสด ๆ นี่คือ agent loop เปลือย ๆ ที่เห็นทุกจังหวะ
กายวิภาคของ agent: 5 ชิ้นส่วน
| ชิ้นส่วน | หน้าที่ | ในโลก NestJS/Go มองเป็น |
|---|---|---|
| LLM (สมอง) | ตัดสินใจว่าจะทำอะไรต่อ | service ที่เรียก API ภายนอก |
| Tools | สิ่งที่ agent เรียกได้ (ค้นเว็บ, query DB, เรียก API) | ชุด method/function ที่ลงทะเบียนไว้ (tool registry) |
| Memory | จำสิ่งที่ทำมาแล้วในรอบก่อน ๆ | state object / เก็บลง Redis-Mongo |
| Loop | วน think-act-observe | while loop ใน service |
| Stopping condition | เงื่อนไขหยุด (จบงาน / ครบจำนวนรอบ) | เงื่อน break — สำคัญมาก กันวนไม่รู้จบ |
แบบที่ 1 · Single-agent + tools (พร้อม MCP)
agent เดี่ยว 1 ตัว แต่มี tool ให้เรียกหลายอย่าง โปรเจกต์
github_intelligence_agent เป็นเคสน่าสนใจ: มันต่อ
MCP (Model Context Protocol)
ของ GitHub เพื่อคุยกับ GitHub API ทั้งหมดผ่านภาษาคน
จุดที่ควรถอดเป็น pattern คือปัญหา "tool เยอะเกินจน context ล้น" —
GitHub MCP มี tool กว่า 40 ตัว ถ้าโหลด schema ทุกตัวเข้า context ตั้งแต่แรกจะเปลืองมหาศาล
README เลยเล่าว่ามันใช้ SearchableToolset ที่ "searches for relevant tools by
keyword and loads only what it needs" — โหลดเฉพาะ tool ที่เกี่ยวกับงานตอนนั้น
pattern พกพา: "อย่ายัด tool ทุกตัวให้ LLM เห็นพร้อมกัน" — ถ้าระบบคุณมี tool เยอะ (เช่น 50 endpoint ใน NestJS) ให้ทำ tool discovery เลือกเฉพาะที่เกี่ยว ก่อนส่งให้ LLM ตัดสินใจ ประหยัด token และแม่นขึ้น — เรื่อง tool schema จะลงลึกใน Lv3 · Tool use
แบบที่ 2 · Multi-agent (ทีมที่แบ่งหน้าที่)
แทนที่จะมี agent เก่งรอบด้าน 1 ตัว ใช้หลาย agent ที่ เชี่ยวชาญคนละอย่าง
ส่งงานต่อกันเป็นทอด ๆ โปรเจกต์ multi_agent_coding_assistant เป็นตัวอย่างที่สะอาดมาก:
4 stage ทำงานเรียงกัน
สิ่งที่หลายคนเข้าใจผิดคือคิดว่า multi-agent ต้องมีเฟรมเวิร์กวิเศษ แต่พอเปิดโค้ดจริง
(agents.py) จะเห็นว่ามันคือ ฟังก์ชันธรรมดา 4 ตัว ที่ต่างกันแค่
"system prompt" (บทบาท) แล้วส่ง output ของตัวก่อนเป็น input ตัวถัดไป:
# agents.py (ย่อจากของจริง) — แต่ละ agent = system prompt + llm.invoke()
def run_planner(llm, task):
messages = [SystemMessage(PLANNER_SYSTEM_PROMPT), HumanMessage(f"Coding task: {task}")]
return llm.invoke(messages).content
# flow ใน app.py: ร้อยต่อกันเป็นทอด ๆ ด้วยโค้ดธรรมดา
plan = run_planner(llm, task)
draft = run_coder(llm, plan)
review = run_reviewer(llm, draft)
final = run_final_coder(llm, plan, draft, review)
pattern พกพา: "multi-agent" ส่วนใหญ่ = บทบาทเฉพาะทาง (system prompt ต่างกัน) + context แยกกัน + ร้อยต่อด้วยโค้ดธรรมดา — ไม่ต้องมีเวทมนตร์ ใน NestJS ก็คือ service หลายตัว (PlannerService, CoderService, ReviewerService) ที่ orchestrator เรียกต่อกัน
แบบที่ 3 · Self-reflection loop (agent ตรวจงานตัวเอง)
ระดับที่ฉลาดขึ้น: agent ที่ เกรดผลงานตัวเองก่อนส่ง ถ้ายังไม่ดีพอก็วนแก้
โปรเจกต์ agentic_rag_system (ใช้ LangGraph)
ทำ RAG ที่ไม่ตอบทันที แต่วน retrieve → grade → (rewrite ถ้าไม่ผ่าน) → generate
MAX_ITERATIONS = 3 กันวนไม่รู้จบ
หัวใจที่ควรจำคือมันคือ state machine ชัด ๆ — โค้ดจริงประกาศ node แล้วต่อ edge โดยมี "เส้นทางแบบมีเงื่อนไข" (conditional edge) และตัวนับรอบกันลูปค้าง:
# rag_graph.py (ย่อจากของจริง) — นิยาม node + edge เหมือนวาด state machine
workflow.add_node("retrieve", retrieve)
workflow.add_node("grade_retrieval", grade_retrieval)
workflow.add_edge("retrieve", "grade_retrieval")
workflow.add_conditional_edges("grade_retrieval", should_continue) # แยกทาง YES/NO
workflow.add_edge("rewrite_query", "retrieve") # วนกลับ
def should_continue(state):
if state["iterations"] >= MAX_ITERATIONS: return "generate" # กันวนไม่จบ
return "generate" if verdict == "YES" else "rewrite"
เฟรมเวิร์ก orchestration — เลือกตัวไหน?
ในคลังคุณจะเจอชื่อพวกนี้เต็มไปหมด จริง ๆ ทุกตัวทำเรื่องเดียวกัน: "ช่วยร้อย agent loop / หลาย agent เข้าด้วยกัน" ต่างกันที่สไตล์ — จำไว้พอให้เลือกถูก ไม่ต้องท่อง:
| เฟรมเวิร์ก | สไตล์ | เหมาะเมื่อ |
|---|---|---|
| LangChain | ต่อ component เป็น chain | flow เส้นตรง เรียบง่าย (เหมือน multi_agent_coding_assistant) |
| LangGraph | state machine (node + edge) | มี loop/เงื่อนไข/ย้อนกลับ (เหมือน agentic RAG) |
| CrewAI / AG2 | "ทีม" ที่มี role คุยกัน | หลาย agent เจรจา/แบ่งงานเอง |
| Agno | agent + tool + memory เบา ๆ | อยาก setup เร็ว น้ำหนักเบา |
| smolagents | code-first (เขียน+รันโค้ดทุก step) | งานที่แก้ด้วยการรันโค้ดได้ |
อย่าเพิ่งรีบหยิบเฟรมเวิร์ก: สำหรับ flow ตรง ๆ 3-4 step (แบบ Planner→Coder→Reviewer) คุณเขียน loop + เรียก LLM เองด้วย SDK ตรง ๆ ก็พอ — เฟรมเวิร์กมีค่าเมื่อ flow ซับซ้อน (loop เยอะ, conditional, หลาย agent คุยกัน)
map ลงงาน NestJS/Go ของคุณ
นี่คือของจริงที่เอาไปใช้ได้: agent loop = service ที่มี while loop + tool registry + state ถ้าคุณเคยเขียน job processor (BullMQ) หรือ state machine (XState) มาก่อน คุณเข้าใจมันอยู่แล้ว
// NestJS — agent loop เปลือย ๆ (pseudo) หน้าตาคุ้นมาก
async runAgent(task: string) {
const state = { task, history: [], iterations: 0 };
while (state.iterations++ < MAX_ITERATIONS) { // stopping condition กันวนไม่จบ
const decision = await this.llm.decide(state); // think
if (decision.done) return decision.answer;
const result = await this.tools.run(decision.tool, decision.args); // act
state.history.push({ decision, result }); // observe → memory
}
}
- Tools = method ใน service ที่คุณลงทะเบียนไว้ (query Mongo, เรียก REST, ส่งอีเมล) พร้อม schema อธิบายให้ LLM รู้ว่าเรียกยังไง
- Multi-agent = orchestrator service เรียก sub-service เฉพาะทางต่อกัน (หรือใช้ queue ส่งงานเป็นทอด)
- Self-reflection = state machine — ถ้าคุ้น XState/BullMQ flow อยู่แล้ว map ตรง ๆ ได้เลย
3 กับดักของ agent ที่ต้องระวังในงานจริง:
(1) วนไม่รู้จบ — ต้องมี MAX_ITERATIONS เสมอ (สังเกตว่า agentic RAG hard-code ไว้ 3);
(2) ค่าใช้จ่ายบาน — ทุกรอบ loop = เรียก LLM = จ่ายเงิน + ช้า ยิ่ง multi-agent ยิ่งคูณ;
(3) tool ทำงานอันตราย — ถ้า tool ลบข้อมูล/จ่ายเงินได้ ต้องมี guard/confirm ก่อนให้ agent เรียกเอง
-
เปิด
sources/Hands-On-AI-Engineering/ai_agents/multi_agent_coding_assistant/agents.pyแล้วหาให้เจอว่ามี agent (system prompt) ทั้งหมดกี่ตัว และแต่ละตัวห้าม/ต้องทำอะไร (ใบ้: มองหาคำว่าSYSTEM_PROMPT) -
เปิด
ai_agents/agentic_rag_system/rag_graph.pyหาMAX_ITERATIONSแล้วอธิบายด้วยคำพูดตัวเองว่า "ถ้าไม่มีบรรทัดนี้จะเกิดอะไรขึ้น" - นึกงานจริงในโปรเจกต์คุณที่เหมาะกับ agent (เช่น "อ่านอีเมลลูกค้า → จัดหมวด → ร่างตอบ") แล้วเขียนว่ามันควรเป็นแบบไหน: single-agent+tools, multi-agent, หรือ self-reflection loop และ tool ที่ต้องมีคืออะไรบ้าง
เมื่อทำเสร็จ พิมพ์ /quiz HO-1 เพื่อทดสอบความเข้าใจ