ข้ามไปเนื้อหาหลัก

Category: reference

AI Agents & Agentic Patterns

สถาปัตยกรรมและ patterns สำหรับ AI agents: agentic loop, tool use, multi-step planning, orchestration, parallel agents และการจัดการ context window

· อ่านประมาณ 3 นาที

สารบัญ

Agent คืออะไร

Agent คือ LLM ที่ได้รับ tools และตัดสินใจเองว่าจะใช้ tool อะไร กี่ครั้ง เพื่อให้งานสำเร็จ แทนที่จะตอบครั้งเดียว

[Task] → [LLM] → [Tool call] → [Result] → [LLM] → [Tool call] → ... → [Final Answer]

Agentic Loop พื้นฐาน

async function runAgent(task: string, tools: Tool[]): Promise<string> {
  const messages: Message[] = [{ role: 'user', content: task }];

  while (true) {
    const response = await llm.call({ messages, tools });

    if (response.stop_reason === 'end_turn') {
      return response.text;  // งานเสร็จ
    }

    if (response.stop_reason === 'tool_use') {
      const toolResults = await executeTools(response.tool_calls);
      messages.push(
        { role: 'assistant', content: response.content },
        { role: 'user', content: toolResults },
      );
      // วนซ้ำ
    }

    if (messages.length > MAX_TURNS) throw new Error('Max turns exceeded');
  }
}

Tool Design

// ✓ Tool ที่ดี: action เดียว ผลลัพธ์ชัด
const readFile: Tool = {
  name: 'read_file',
  description: 'อ่านเนื้อหาไฟล์จาก path ที่ระบุ',
  input_schema: {
    type: 'object',
    properties: { path: { type: 'string', description: 'absolute path to file' } },
    required: ['path'],
  },
};

// ❌ Tool ที่ไม่ดี: ทำหลายอย่าง, description ไม่ชัด
const doStuff: Tool = {
  name: 'process_and_save',
  description: 'ทำอะไรบางอย่างกับข้อมูล',  // ❌ ไม่รู้จะใช้เมื่อไหร่
  // ...
};

// ✓ Set of tools ที่ดี: ครอบคลุม แต่ไม่ซ้ำซ้อน
const tools = [
  readFile,
  writeFile,
  listDirectory,
  searchFiles,
  runCommand,
  fetchURL,
];

Agent Patterns

1. ReAct (Reason + Act)

บังคับให้ agent คิดก่อนทำ ลด hallucination และ wrong tool call

const systemPrompt = `
ก่อนทำงานทุกครั้ง ให้คิดออกเสียงใน <thinking> tag ว่า:
- ตอนนี้รู้อะไรบ้าง
- ขาดข้อมูลอะไร
- tool ไหนควรใช้ถัดไป

<thinking>
ผมต้องอ่านไฟล์ config ก่อน เพื่อรู้ว่า database อยู่ที่ไหน
</thinking>
[tool call: readFile]
`;

2. Plan-and-Execute

วางแผนทั้งหมดก่อน แล้วค่อย execute ทีละขั้น

// Phase 1: Planning
const plan = await plannerAgent(task);
// plan = ["อ่านไฟล์ทั้งหมด", "วิเคราะห์ dependencies", "สร้าง summary", ...]

// Phase 2: Execute each step
for (const step of plan.steps) {
  const result = await executorAgent(step, context);
  context.push(result);
}

3. Parallel Agents

แยกงานออกเป็น sub-tasks และรันพร้อมกัน

const results = await Promise.all([
  agent('วิเคราะห์คุณภาพ code', { files: changedFiles }),
  agent('ตรวจ security vulnerabilities', { files: changedFiles }),
  agent('วัด performance impact', { files: changedFiles }),
]);
const combined = synthesizeAgent(results);

4. Orchestrator–Subagent

Agent หลักสั่ง sub-agents ทำงาน แล้วรวมผล

// Orchestrator
const orchestratorPrompt = `
คุณเป็น project manager ควบคุม agents อื่น
เมื่อได้รับงาน ให้แบ่งและมอบหมายให้ sub-agents ที่เหมาะสม:
- frontend_agent: งาน UI/CSS
- content_agent: งานเขียน
- qa_agent: ตรวจคุณภาพ

รายงานกลับเมื่อทุก agent เสร็จหรือติดปัญหา
`;

Context Management

// Context window มีขีดจำกัด — ต้องจัดการ
const MAX_TOKENS = 100_000;  // Claude Sonnet = 200k context

// Strategy 1: Summarize ก่อน overflow
if (estimateTokens(messages) > MAX_TOKENS * 0.8) {
  const summary = await summarizeAgent(messages.slice(0, -5));
  messages = [
    { role: 'user', content: `Summary of previous work:\n${summary}` },
    ...messages.slice(-5),  // เก็บ recent messages
  ];
}

// Strategy 2: Handoff — บันทึก state แล้ว start fresh
const state = await agent.exportState();
// บันทึก state ลง disk หรือ database
// รอบหน้า: load state แล้วใช้ต่อ

Error Recovery

async function robustAgent(task: string): Promise<string> {
  let attempts = 0;
  const errors: string[] = [];

  while (attempts < MAX_RETRIES) {
    try {
      return await runAgent(task);
    } catch (error) {
      errors.push(String(error));
      attempts++;

      // บอก agent เกี่ยวกับ error และให้ลองใหม่
      task = `${task}\n\nPrevious attempt failed: ${error}\nTry a different approach.`;
    }
  }

  throw new Error(`Failed after ${attempts} attempts:\n${errors.join('\n')}`);
}

Human-in-the-Loop

// หยุดรอ human confirm ก่อน action ที่ risky
async function confirmAction(action: string): Promise<boolean> {
  console.log(`\nAgent wants to: ${action}`);
  const answer = await prompt('Approve? (y/n): ');
  return answer.toLowerCase() === 'y';
}

// ใน agentic loop
if (toolCall.name === 'deleteFile' || toolCall.name === 'sendEmail') {
  const approved = await confirmAction(JSON.stringify(toolCall));
  if (!approved) {
    messages.push({ role: 'user', content: 'User rejected this action. Try alternative.' });
    continue;
  }
}

เมื่อไหร่ควรใช้ Agent

สถานการณ์ใช้ Agent?
งานที่ขั้นตอนรู้ล่วงหน้าทั้งหมด❌ ใช้ pipeline แทน
งานที่ต้องตัดสินใจตามข้อมูลที่ได้
งานที่ต้องวนซ้ำหลายรอบ
งาน 1 ขั้นตอนตรงๆ❌ ใช้ single LLM call
งานที่ error cost สูงมาก⚠️ ต้องมี human review