jvinhit//lab

Search posts

Type to search across journal entries.

navigate open esc close

Agent Architecture — Bên trong 1 AI agent là gì

Mổ xẻ kiến trúc bên trong 1 AI agent: agent loop, tool use mechanics, 3 tầng memory, planning patterns (ReAct, Plan-and-Execute, Tree of Thoughts), multi-agent system, và 7 cạm bẫy phổ biến.

Bạn dùng Cursor agent, Claude Computer Use, Devin — và cảm giác chúng “thông minh như người”. Nhưng bên trong, agent là 1 hệ thống đơn giản hơn bạn nghĩ: vài component LLM-driven xếp thành loop.

Bài này mổ xẻ kiến trúc đó. Sau khi đọc, bạn không chỉ biết cách dùng agent — mà còn build agent của riêng mình, và biết tại sao agent thỉnh thoảng “ngu” (vì lý do kỹ thuật cụ thể, không phải magic).

Mô hình tư duy: LLM giống một bộ não cực thông minh nhưng bị nhốt trong phòng kín, không tay chân, mất trí nhớ sau mỗi câu. Agent là bộ khung lắp thêm cho bộ não đó: mắt (đọc state), tay (tool), và một cuốn sổ (memory) — rồi cho nó lặp đi lặp lại “nhìn → nghĩ → làm” đến khi xong việc. Toàn bộ “phép màu” của agent chỉ là một vòng lặp quanh lời gọi LLM — phần còn lại là kỹ thuật.


1. Agent là gì — định nghĩa kỹ thuật

Agent là chương trình dùng LLM trong vòng lặp để hoàn thành task qua nhiều bước, có khả năng tương tác với môi trường.

3 yếu tố tách agent khỏi chatbot thường:

ChatbotAgent
Input1 message1 task / goal
Output1 replySequence của action + result
Bước1 lượtN lượt (loop)
ToolKhông / hạn chếRead/write file, terminal, API, web
StateStateless / context-onlyCó memory, planning

Cursor đang gõ code cho bạn = agent. Claude trả lời câu hỏi = chatbot. ChatGPT với “Code Interpreter” = agent (chạy Python trong sandbox).


2. Agent loop — vòng lặp cơ bản

Mọi agent kiến trúc hiện đại đều có chung skeleton:

┌──────────────────────────────────────┐
│  1. OBSERVE — đọc state hiện tại       │
│     (file, terminal output, tool result) │
├──────────────────────────────────────┤
│  2. THINK — LLM reasoning              │
│     (next action là gì? đã xong chưa?)  │
├──────────────────────────────────────┤
│  3. ACT — execute action               │
│     (call tool, edit file, run command) │
├──────────────────────────────────────┤
│  4. CHECK — task done? loop back to 1.  │
└──────────────────────────────────────┘

Pseudo-code:

async function agentLoop(task: string) {
  let history = [{ role: 'user', content: task }];

  while (true) {
    // OBSERVE + THINK: gửi history + tools cho LLM
    const response = await llm.chat({
      messages: history,
      tools: availableTools,
    });

    history.push(response.message);

    // Stop condition
    if (response.finishReason === 'stop') {
      return response.message.content;
    }

    // ACT: thực thi tool calls
    if (response.message.toolCalls) {
      for (const call of response.message.toolCalls) {
        const result = await executeTool(call);
        history.push({
          role: 'tool',
          toolCallId: call.id,
          content: result,
        });
      }
    }
  }
}

15 dòng code. Đây là toàn bộ logic của 1 agent đơn giản. Phần còn lại là tool definition + prompt engineering.


3. Components — 4 phần cấu thành agent

3.1. Brain — LLM

Phần “thinking” của agent. Quyết định:

  • Task này hiểu ra sao
  • Tool nào nên call tiếp theo
  • Khi nào dừng

LLM brain quan trọng nhất. Agent quality phụ thuộc 70% vào model chọn (xem Models Comparison).

3.2. Tools — interface với thế giới

Tool là function model có thể gọi. Định nghĩa qua JSON schema:

{
  "name": "read_file",
  "description": "Read content of a file from the workspace",
  "parameters": {
    "type": "object",
    "properties": {
      "path": {
        "type": "string",
        "description": "Absolute path to file"
      }
    },
    "required": ["path"]
  }
}

LLM nhận schema này như 1 phần của system prompt. Khi cần file content, nó output:

{
  "tool": "read_file",
  "arguments": { "path": "/src/index.ts" }
}

Runtime parse, execute hàm thật, gửi kết quả về làm input cho lượt tiếp theo.

Tool types phổ biến cho coding agent:

  • File: read_file, write_file, delete_file, glob, grep
  • Shell: run_command (sandboxed)
  • Web: fetch_url, web_search
  • Code analysis: read_lints, find_references, goto_definition
  • Sub-agent: delegate_task (xem section 6)

3.3. Memory — bộ nhớ

3 tầng memory:

┌─────────────────────────────────────┐
│  WORKING MEMORY                     │
│  Conversation history hiện tại        │
│  → giới hạn theo context window     │
├─────────────────────────────────────┤
│  EPISODIC MEMORY                    │
│  Tóm tắt task trước, decision đã     │
│  → store ngoài (file, DB), recall   │
├─────────────────────────────────────┤
│  SEMANTIC MEMORY                    │
│  Knowledge về codebase, convention   │
│  → vector DB hoặc preloaded rule     │
└─────────────────────────────────────┘

Cursor:

  • Working = chat hiện tại
  • Episodic = agent-transcripts/ folder
  • Semantic = Rules + Skills + indexed codebase

3.4. Planning module

Đơn giản: LLM brain tự plan inline. Phức tạp: planning module riêng biệt (xem section 5).


4. Tool use — sâu hơn

4.1. Function calling vs free-form

2 cách model “call tool”:

Function calling (modern, structured):

Model output:
{
  "tool_calls": [
    { "name": "read_file", "args": {...} }
  ]
}

API parse JSON tự động. Type-safe, ít hallucinate parameter.

Free-form parsing (legacy):

Model output:
"I'll read the file. <action>read_file('src/index.ts')</action>"

Runtime regex extract. Dễ fail (model output sai format).

Modern API (Anthropic, OpenAI) dùng function calling. Còn dùng free-form chỉ khi model không support (Llama base, model nhỏ).

4.2. Tool result format

Tool result phải đầy đủ + structured:

// ❌ Bad
return 'ok';

// ✅ Good
return JSON.stringify({
  success: true,
  fileContents: '...',
  fileSize: 1234,
  encoding: 'utf8',
});

Model học từ kết quả này. Format consistent → model behavior predictable.

4.3. Tool error handling

Tool fail (file không tồn tại, command exit code khác 0) → trả về error có structure:

{
  "error": true,
  "code": "FILE_NOT_FOUND",
  "message": "File /src/foo.ts does not exist",
  "suggestion": "Use glob_search to find similar files"
}

Model đọc error → quyết định: retry, đổi approach, hỏi user. Không nên throw raw exception → agent loop crash.

4.4. Tool security — sandboxing

Tool có thể làm hại system. Best practice:

  • Filesystem write: giới hạn workspace folder. Block ghi /etc/, ~/.ssh/.
  • Shell exec: timeout, mem limit, no network unless explicit.
  • Network: allowlist domain, không free internet.
  • Approval: tool nguy hiểm (delete, force push) → ask user.

Cursor dùng sandbox với “permission” gradient: read freely, write yêu cầu cẩn thận, network/all yêu cầu user approve.


5. Planning patterns

LLM brain tự plan đơn giản. Nhưng task phức tạp cần pattern formal:

5.1. ReAct (Reasoning + Acting)

Pattern phổ biến nhất. Trong mỗi turn:

Thought: "Tôi cần đọc file X để hiểu structure"
Action: read_file("/src/index.ts")
Observation: <file content>
Thought: "OK, structure đã rõ. Bây giờ cần edit ..."
Action: write_file(...)
...

Mỗi step model explicit reasoning trước action. Dễ debug, dễ audit. Cursor agent dùng pattern này (visible trong “thinking”).

Limitation: reasoning step đốt token. Task dài → cost cao.

5.2. Plan-and-Execute

Tách 2 phase:

  1. Plan: model output 1 plan rõ ràng (5-10 step) cho task.
  2. Execute: agent đi theo plan từng step, không re-plan.
PHASE 1 — Plan:
  1. Read existing implementation
  2. Read test file
  3. Identify gap
  4. Implement fix
  5. Run test
  6. Verify pass

PHASE 2 — Execute step 1, 2, 3, 4, 5, 6.

Ưu: token-efficient, agent không “lạc”. Nhược: rigid, error giữa chừng → cần re-plan.

Solution thực tế: hybrid — execute, nếu phát hiện lệch plan, replan phần còn lại.

5.3. Tree of Thoughts

Cho task có nhiều path khả thi (debug, search). Model:

  1. Generate 3-5 candidate approach.
  2. Evaluate từng approach (LLM judge).
  3. Chọn best, execute.
  4. Nếu fail, revisit branch khác.

Đắt (gấp 3-5x token) nhưng correctness cao hơn cho task khó.

5.4. Reflection

Sau khi finish task:

Thought: "Tôi vừa implement feature. Review:
- Có miss edge case nào không?
- Có vi phạm convention nào?
- Có làm broke test nào không?"

Action: run_test
Action: re-read code

Thought: "Tôi miss case empty array. Fix..."

Self-reflection cải thiện chất lượng output 10-30% trên benchmark. Đổi lại: gấp đôi cost.

5.5. So sánh

PatternCostQualityUse case
ReActTrung bìnhTốtDefault cho mọi task
Plan-and-ExecuteThấpTốtTask structure rõ
Tree of ThoughtsCaoRất tốtDebug, optimization
ReflectionCao (2x)Tốt+Critical task, production

6. Sub-agents — agent gọi agent

Khi 1 agent quá tải (context dài, task heterogeneous), giải pháp là delegate task con cho sub-agent riêng.

PARENT AGENT (project context, user intent)

    ├──► Sub-agent: "Read 50 file & summarize architecture"
    │     → Return: 1 page summary

    ├──► Sub-agent: "Run test suite & report failures"
    │     → Return: list of failing tests

    └──► Sub-agent: "Search docs about X"
          → Return: 3 relevant snippets

Lợi ích

  1. Context isolation: sub-agent đọc 100KB file, parent chỉ thấy 2KB summary. Parent context không bloat.
  2. Specialization: sub-agent có system prompt riêng (vd “you are doc reader, return only quotes”).
  3. Parallel: nhiều sub-agent chạy đồng thời.

Cost

Sub-agent = thêm LLM call. Nếu task không cần isolation, đơn giản hơn là parent tự làm.

Heuristic: dùng sub-agent khi task con sẽ đốt > 5K token, hoặc cần context không liên quan task chính.

Cursor có 5 loại sub-agent built-in: generalPurpose, explore, shell, cursor-guide, best-of-n-runner.

Đọc thêm: Cursor Sub-agents Guide.


7. Multi-agent systems

Khác với “sub-agent” (parent-child, hierarchical), multi-agent là nhiều agent đồng cấp, hợp tác hoặc cạnh tranh.

7.1. Cooperative — chia việc

Pattern: mỗi agent có role, làm phần của mình.

PRODUCT MANAGER agent ──► spec


ARCHITECT agent ──────► design doc


ENGINEER agent ──────► code


QA agent ────────────► test report

Framework support: AutoGen (Microsoft), CrewAI, LangGraph.

Ưu: phân chia rõ, dễ debug. Nhược: rigid, communication overhead, dễ tạo “echo chamber” — các agent confirm nhau sai.

7.2. Adversarial — kiểm tra chéo

PROPOSER agent: "Đây là code"
CRITIC agent: "Có 3 vấn đề: ..."
PROPOSER: "Đã fix: ..."
CRITIC: "OK, no issue."

Pattern này cải thiện quality. Critic agent với system prompt khác proposer (skeptical persona) → catch lỗi proposer miss.

GitHub Copilot Workspace dùng pattern này khi tạo PR — 1 agent code, 1 agent review.

7.3. Khi nào không nên multi-agent

Multi-agent không phải silver bullet. Bạn không cần:

  • Single-step task (“rename variable”)
  • Task đã rõ flow (1 agent đủ)
  • Khi cost / latency là constraint

90% task dùng 1 agent + tools là đủ. Multi-agent thường là over-engineering trừ khi có lý do cụ thể.


8. 7 cạm bẫy phổ biến

8.1. Context bloat

Agent loop dài → history đầy → cost cao + “lost in middle”. Fix:

  • Summarize history định kỳ
  • Drop tool result cũ không relevant
  • Restart loop với tóm tắt khi cần

8.2. Tool hallucination

Model gọi tool không có (“call API X”) hoặc gọi với param sai schema.

Fix:

  • Strict schema validation runtime
  • Tool description rõ ràng
  • Few-shot example trong system prompt

8.3. Infinite loop

Agent repeat 1 action mãi (đặc biệt khi tool fail và model không hiểu tại sao).

Fix:

  • Max steps cap (ví dụ 30 step / task)
  • Detect repeated action → force model thử cách khác
  • Better error message từ tool

8.4. Premature stop

Agent dừng giữa task (“I think I’m done”). Thường do system prompt không rõ “done condition”.

Fix:

  • System prompt explicit: “Stop only when X is verified”
  • Verification step ở cuối (chạy test, check output)

8.5. Tool over-use

Agent call read_file 50 lần khi chỉ cần 5. Token waste.

Fix:

  • Glob/grep trước, sau đó read file targeted
  • Cache tool result trong cùng turn
  • Hint trong system prompt: “Use grep before reading multiple files”

8.6. Off-task drift

Task: fix bug X. Agent end up: refactor function Y, install package Z.

Fix:

  • Constraint cứng trong prompt: “DON’T modify files outside scope”
  • Plan-first pattern (lên plan, user approve, execute strict)

8.7. Catastrophic action

Agent run rm -rf ./ hoặc force push main. Hiếm nhưng đã xảy ra (xem “Replit AI deletes prod database” 2025).

Fix:

  • Sandboxing ở nhiều layer
  • Approval cho destructive action
  • Backup automation
  • Run agent trên branch riêng, không direct main

9. Build agent đơn giản từ scratch

200 dòng TypeScript, 1 agent đầy đủ:

import Anthropic from '@anthropic-ai/sdk';
import { readFileSync, writeFileSync } from 'fs';
import { execSync } from 'child_process';

const client = new Anthropic();

const tools = [
  {
    name: 'read_file',
    description: 'Read file content',
    input_schema: {
      type: 'object',
      properties: { path: { type: 'string' } },
      required: ['path'],
    },
  },
  {
    name: 'write_file',
    description: 'Write content to file',
    input_schema: {
      type: 'object',
      properties: {
        path: { type: 'string' },
        content: { type: 'string' },
      },
      required: ['path', 'content'],
    },
  },
  {
    name: 'run_command',
    description: 'Execute shell command (sandboxed)',
    input_schema: {
      type: 'object',
      properties: { command: { type: 'string' } },
      required: ['command'],
    },
  },
];

function executeTool(name: string, args: any): string {
  if (name === 'read_file') {
    return readFileSync(args.path, 'utf8');
  }
  if (name === 'write_file') {
    writeFileSync(args.path, args.content);
    return `Wrote ${args.content.length} bytes to ${args.path}`;
  }
  if (name === 'run_command') {
    return execSync(args.command, { encoding: 'utf8' });
  }
  throw new Error(`Unknown tool: ${name}`);
}

async function agent(task: string) {
  const messages: any[] = [{ role: 'user', content: task }];

  for (let i = 0; i < 30; i++) {
    const response = await client.messages.create({
      model: 'claude-3-5-sonnet-20241022',
      max_tokens: 4096,
      tools,
      messages,
    });

    messages.push({ role: 'assistant', content: response.content });

    if (response.stop_reason === 'end_turn') {
      console.log('Done');
      return;
    }

    const toolUses = response.content.filter((b) => b.type === 'tool_use');
    const toolResults = toolUses.map((tu: any) => {
      try {
        const result = executeTool(tu.name, tu.input);
        return {
          type: 'tool_result',
          tool_use_id: tu.id,
          content: result,
        };
      } catch (e: any) {
        return {
          type: 'tool_result',
          tool_use_id: tu.id,
          content: `Error: ${e.message}`,
          is_error: true,
        };
      }
    });

    messages.push({ role: 'user', content: toolResults });
  }
}

await agent('Read package.json, count dependencies, write report to deps.md');

Đây là lõi của Cursor (rút gọn). Add: streaming, sandbox, memory, better tool, sub-agent, → bạn có Cursor 0.1.

Hiểu code này = hiểu agent. Phần còn lại là engineering polish.


10. Tổng kết

Agent không phải magic. Nó là:

  1. LLM (brain)
  2. Tools (interface với thế giới)
  3. Loop (observe → think → act)
  4. Memory (working + episodic + semantic)
  5. Planning (ReAct / Plan-Execute / Reflection / etc.)

5 component này, đứa nào yếu → agent yếu phần đó.

Cursor mạnh vì:

  • Brain: Claude 3.5+
  • Tools: 30+ tool integrated với IDE
  • Loop: refined sau hàng triệu request
  • Memory: agent transcripts + Rules + Skills + Codebase index
  • Planning: ReAct + sub-agent + reflection

Bạn build agent của riêng mình → hiểu 5 trục này, optimize từng cái. Đừng “build LangChain wrapper” — hiểu native.


Đọc thêm

Reference