Post

Claude Code: Hiểu đúng Skills và Subagents

Tìm hiểu cách Skills và Subagents hoạt động trong Claude Code, cách chúng tác động đến context, memory, tool calls và khi nào nên sử dụng từng cơ chế.

Claude Code: Hiểu đúng Skills và Subagents

Khi bắt đầu dùng Claude Code cho các project lớn, chúng ta thường gặp hai khái niệm khá dễ nhầm với nhau: SkillsSubagents.

Cả hai đều giúp Claude làm việc tốt hơn, nhưng bản chất của chúng hoàn toàn khác nhau.

Nếu chỉ cần nhớ một ý xuyên suốt bài viết thì có thể dùng mental model sau:

1
2
3
4
5
6
7
Skill
= bổ sung "cách làm / kiến thức / workflow"
  cho agent đang làm việc

Subagent
= giao một task cho một worker
  chạy trong context riêng

Hay nhìn dưới góc độ lập trình:

1
2
Skill    ≈ import instruction module
Subagent ≈ spawn worker/process

Điểm khác biệt cốt lõi là:

1
2
3
4
5
Skill
→ context augmentation

Subagent
→ context isolation

Trong bài này, chúng ta sẽ đi sâu hơn một chút vào cách hai cơ chế này thực sự hoạt động trong Claude Code, đặc biệt là cách chúng liên quan tới conversation context, memory, tool callscontext engineering.


Skills

Skill thực chất là gì?

Một Skill trong Claude Code là một tập hướng dẫn có thể tái sử dụng, thường được định nghĩa bằng một file SKILL.md.

Ví dụ:

1
2
3
4
.claude/
└── skills/
    └── api-conventions/
        └── SKILL.md

Nội dung có thể như sau:

1
2
3
4
5
6
7
8
9
10
11
---
name: api-conventions
description: Các convention khi implement API trong project
---

Khi implement API:

- validate input
- sử dụng error response thống nhất
- không truy cập database trực tiếp từ controller
- thêm integration test cho endpoint mới

Skill phù hợp với những thứ chúng ta thường phải lặp lại cho Claude:

  • coding convention;
  • architecture guideline;
  • checklist;
  • quy trình deploy;
  • cách viết test;
  • domain knowledge;
  • workflow nhiều bước.

Thay vì copy đi copy lại cùng một prompt vào conversation, chúng ta đóng gói nó thành Skill.

Có thể hiểu đơn giản:

1
2
Skill
= reusable prompt + supporting resources

Skill được load vào context như thế nào?

Một điểm quan trọng là Claude Code không đưa toàn bộ nội dung của tất cả SKILL.md vào context ngay từ đầu.

Với Skill mặc định, Claude biết các Skill đang khả dụng thông qua metadata, đặc biệt là phần description.

Ví dụ Claude có thể biết rằng:

1
2
3
4
5
6
7
8
9
10
Available skills:

api-conventions
→ Quy tắc implement API trong project

frontend-patterns
→ Convention khi viết React

deploy
→ Workflow deploy application

Nhưng full nội dung của api-conventions/SKILL.md chưa nhất thiết nằm trong context.

Khi Claude thấy Skill phù hợp với task hiện tại, hoặc khi chúng ta gọi trực tiếp:

1
/api-conventions

thì nội dung đã render của SKILL.md mới được đưa vào conversation.

Giả sử chúng ta đã nói chuyện với Claude một lúc:

1
2
3
4
5
6
7
8
9
System / CLAUDE.md

User 1
Assistant 1

User 2
Assistant 2

User 3

User 3, Claude nhận ra cần dùng api-conventions.

Mental model có thể hình dung như sau:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
System / CLAUDE.md

User 1
Assistant 1

User 2
Assistant 2

User 3

[Skill: api-conventions]
<nội dung SKILL.md>

Assistant 3

Skill không tạo một Claude mới, cũng không tạo một context window mới.

Nó bổ sung instruction vào conversation hiện tại của agent đang làm việc.

Vì vậy, ở mức conceptual:

1
2
3
Skill
≈ inject thêm instruction
  vào context hiện tại

Với reference content thông thường, Skill chạy inline để Claude có thể sử dụng nó cùng với conversation context hiện tại.

Skill có còn tồn tại ở những câu hỏi sau không?

Có.

Đây là một điểm rất đáng chú ý khi thiết kế Skill.

Giả sử:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Turn 1
User: ...

Turn 2
User: Implement API này
→ Claude load api-conventions

Turn 3
User: ...

Turn 4
User: ...

Turn 5
User: Implement thêm endpoint mới

Ở Turn 5, nội dung Skill đã load ở Turn 2 vẫn có thể nằm trong conversation context:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Turn 1
...

Turn 2
[Skill: api-conventions]
Assistant...

Turn 3
...

Turn 4
...

Turn 5
User: Implement thêm endpoint...

Claude Code không cần đọc lại file SKILL.md ở mỗi turn.

Theo lifecycle hiện tại của Skills, khi một Skill được invoke, rendered content của nó đi vào conversation như một message và tiếp tục tồn tại trong session.

Điều này có nghĩa là:

1
2
3
4
5
6
7
8
9
10
11
Turn 2
→ load Skill A

Turn 3
→ instruction của Skill A vẫn có thể ảnh hưởng

Turn 4
→ vẫn còn

Turn 5
→ có thể tiếp tục reuse

Nếu Claude invoke lại Skill nhưng rendered content giống hệt bản đã có trong context, Claude Code không cần append thêm nguyên một bản SKILL.md.

Nếu rendered content thay đổi, ví dụ do arguments hoặc dynamic context thay đổi, nội dung mới có thể được append lại.

Ví dụ Skill:

1
2
3
Analyze module:

$ARGUMENTS

Lần đầu:

1
/analyze auth

render thành:

1
2
3
Analyze module:

auth

Lần sau:

1
/analyze payment

render thành:

1
2
3
Analyze module:

payment

Hai rendered prompt khác nhau, nên invocation sau mang thêm thông tin mới vào context.

Skill và compaction

Conversation không thể dài vô hạn.

Khi context đủ lớn, Claude Code có thể compact conversation, tức summarize phần history cũ để giải phóng token.

Ví dụ:

1
2
3
4
5
Turn 1
Turn 2 → Skill A
Turn 3
...
Turn 100

sau compaction có thể trở thành:

1
2
3
4
5
Conversation summary

[Skill A]

newer messages...

Claude Code có cơ chế mang các Skill đã invoke qua quá trình compaction trong một token budget nhất định.

Do đó không nên hiểu rằng:

1
2
Skill load một lần
→ tồn tại tuyệt đối mãi mãi

Mental model phù hợp hơn là:

1
2
3
Skill đã được invoke
→ tiếp tục tồn tại trong session/context
→ nhưng vẫn chịu giới hạn context và compaction

Đây cũng là lý do SKILL.md nên đủ súc tích. Một Skill dài hàng nghìn token, sau khi được load, sẽ trở thành một phần chi phí context trong các turn sau.

Skill có phải Memory không?

Không.

Các khái niệm sau cần được tách riêng:

1
2
3
4
CLAUDE.md
Skill
Auto Memory
Conversation History

Chúng đều có thể cung cấp thông tin cho Claude, nhưng lifecycle và mục đích khác nhau.

Có thể hình dung main context như:

1
2
3
4
5
6
7
8
9
10
┌──────────────────────────────┐
│ Main Agent Context           │
│                              │
│ System instructions          │
│ CLAUDE.md                    │
│ Main auto memory             │
│ Conversation history         │
│ Loaded Skills                │
│ Tool calls / tool results    │
└──────────────────────────────┘

CLAUDE.md phù hợp với những thông tin nền mà Claude gần như luôn cần biết về project.

Skill phù hợp với knowledge hoặc workflow chỉ cần load khi có task liên quan.

Auto Memory là cơ chế để Claude lưu lại một số kiến thức qua nhiều conversation.

Do đó:

1
2
3
4
5
6
7
8
CLAUDE.md
= baseline project instructions

Skill
= reusable instructions được load khi cần

Auto Memory
= persistent knowledge giữa các conversation

Subagents

Nếu Skill chủ yếu là thêm knowledge vào một agent đang có, thì Subagent giải quyết một bài toán khác: delegation và context isolation.

Subagent thực chất là gì?

Giả sử main Claude đang implement một feature và cần nghiên cứu authentication architecture của cả project.

Thay vì main agent tự đọc hàng chục file, nó có thể giao task đó cho một Subagent:

1
2
3
4
5
6
Main Agent
    │
    │ "Hãy phân tích authentication architecture"
    │
    ▼
Subagent

Một non-fork Subagent thông thường bắt đầu với một fresh, isolated context window.

Nó không mặc định nhìn thấy toàn bộ conversation history của main agent, các Skill main đã invoke, hay toàn bộ file main agent đã đọc trước đó.

Main Claude sẽ tạo một delegation message mô tả task cho Subagent.

Mental model:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
┌───────────────────────────┐
│ Main Agent                │
│                           │
│ conversation              │
│ main memory               │
│ loaded skills             │
└─────────────┬─────────────┘
              │
              │ delegation task
              ▼
┌───────────────────────────┐
│ Subagent                  │
│                           │
│ own context               │
│ own system prompt         │
│ task prompt               │
│ own tools                 │
│ own tool calls            │
│ own tool outputs          │
│ own transcript            │
│ own memory (optional)     │
└─────────────┬─────────────┘
              │
              │ result / summary
              ▼
┌───────────────────────────┐
│ Main Agent                │
│                           │
│ receives final result     │
└───────────────────────────┘

Tool calls của Subagent có làm đầy main context không?

Đây là một trong những giá trị lớn nhất của Subagents.

Giả sử để nghiên cứu một module, Subagent phải thực hiện:

1
2
3
Grep x 30
Read x 50
Bash x 20

Nếu main agent tự làm tất cả, main conversation có thể phải chứa một lượng lớn intermediate output:

1
2
3
4
5
6
7
8
Main context

██████████████████████████
grep outputs
file contents
command outputs
temporary observations
██████████████████████████

Nếu giao cho Subagent:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Subagent context

██████████████████████████
30 grep
50 file reads
20 commands
analysis
██████████████████████████

             ↓

Main receives

██████
summary
██████

Tool calls, results và transcript của Subagent được quản lý riêng. Khi Subagent hoàn thành, main agent chủ yếu nhận report/result của nó.

Ví dụ:

1
2
3
4
5
6
Authentication architecture:

1. JWT được tạo tại auth/service.ts.
2. Middleware validate token tại middleware/auth.ts.
3. Refresh token được lưu trong Redis.
4. Có một vấn đề authorization tại ...

Main context không cần chứa toàn bộ 50 file mà Subagent đã đọc để đi đến kết luận đó.

Do đó, Subagent rất hữu ích không chỉ vì chúng ta có thêm một “AI worker”, mà còn vì chúng giúp bảo vệ context của main agent khỏi intermediate noise.

Subagent và Memory

Auto Memory của main conversation không tự động được đưa sang non-fork Subagent.

Nếu muốn một custom Subagent có persistent memory riêng, Claude Code hỗ trợ cấu hình memory.

Ví dụ:

1
2
3
4
5
6
7
8
---
name: code-reviewer
description: Review code và tìm các vấn đề lặp lại
memory: project
---

Review code dựa trên convention của project.
Lưu lại các pattern và recurring issue quan trọng vào memory.

Có thể hình dung:

1
2
3
4
5
6
7
8
9
10
Main Agent
└── Main Auto Memory


Code Reviewer
└── Code Reviewer Memory


Database Agent
└── Database Agent Memory

Các memory này không nên được coi là cùng một vùng nhớ.

Một nuance quan trọng là CLAUDE.md khác Auto Memory.

Custom non-fork Subagent thông thường vẫn có thể nhận hierarchy CLAUDE.md của project, trong khi main Auto Memory không được load sang nó. Một số built-in agent như Explore và Plan có hành vi riêng và bỏ qua CLAUDE.md.

Vì vậy không nên gộp:

1
CLAUDE.md

và:

1
Auto Memory

thành cùng một khái niệm.

Forked Subagent

Không phải Subagent nào cũng bắt đầu từ fresh context.

Claude Code còn có khái niệm fork.

Forked Subagent inherit conversation của main agent tại thời điểm được tạo:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Main context
██████████████████
conversation
skills
tool history
current state
██████████████████
        │
        │ fork
        ▼
Forked Subagent
██████████████████
same starting context
██████████████████

Sau khi fork, execution tiếp tục tách riêng.

Tool calls mới của fork vẫn nằm ngoài main conversation và khi hoàn thành, kết quả được trả về main.

Do đó:

1
2
3
4
5
6
7
Non-fork Subagent
→ fresh context
→ input isolation tốt

Forked Subagent
→ inherit full current context
→ tiện khi task phụ cần rất nhiều background

Fork phù hợp khi chúng ta muốn giao một side task nhưng việc mô tả lại toàn bộ background cho một fresh Subagent quá tốn kém.


Skills và Subagents khác nhau như thế nào?

Bảng sau tóm tắt mental model quan trọng nhất:

Khía cạnhSkillSubagent
Bản chấtInstruction / capabilityWorker
Mục đíchDạy Claude cách làmGiao task sang execution riêng
Context mặc địnhContext hiện tạiContext riêng
Tạo agent mớiKhông
Conversation historyDùng main historyNon-fork không có full history
Tool callsTrong execution hiện tạiTrong execution của Subagent
Tool outputsCó thể làm tăng main contextChủ yếu nằm trong Subagent
Auto MemoryMemory của agent hiện tạiCó thể có memory riêng
Coding conventionsRất phù hợpThường không cần
Research nhiều fileCó thể làmRất phù hợp
Parallel workKhông phải mục đích chínhPhù hợp
Context isolationKhông
Reusable workflowRất tốtCó thể
Specialist roleKhông phải mục đích chínhRất phù hợp

Một cách nhớ ngắn hơn:

1
2
3
4
5
Skill
= HOW

Subagent
= WHO + WHERE

Skill mô tả:

1
HOW should this work be done?

Subagent quyết định:

1
2
WHO should do this work,
and in which execution context?

Kết hợp Skills và Subagents

Skills và Subagents không phải hai cơ chế cạnh tranh nhau.

Ngược lại, chúng bổ sung cho nhau rất tốt.

Preload Skills vào Subagent

Ví dụ chúng ta có một backend developer agent:

1
2
3
4
5
6
7
8
9
---
name: api-developer
description: Implement backend API
skills:
  - api-conventions
  - error-handling-patterns
---

Implement API endpoints theo convention của team.

Khi Subagent khởi động, full content của các Skill được khai báo trong skills có thể được inject vào context của Subagent ngay từ đầu.

Mental model:

1
2
3
4
5
Backend Subagent
        │
        ├── api-conventions
        ├── error-handling-patterns
        └── testing-guidelines

Điều này giúp tách hai concern:

1
2
3
4
5
Subagent
= specialist / worker

Skill
= knowledge / procedure

Thay vì duplicate cùng một bộ API convention vào nhiều agent:

1
2
3
backend-agent prompt
review-agent prompt
migration-agent prompt

chúng ta có thể tạo một Skill chung:

1
api-conventions

và reuse:

1
2
3
4
5
                 api-conventions
                 /      |      \
                /       |       \
               ▼        ▼        ▼
        backend-agent reviewer migration-agent

Chạy Skill trong Subagent

Chiều ngược lại cũng được hỗ trợ.

Một Skill có thể khai báo:

1
context: fork

Ví dụ:

1
2
3
4
5
6
7
8
9
10
11
12
13
---
name: deep-research
description: Research một phần codebase
context: fork
agent: Explore
---

Research $ARGUMENTS:

1. Tìm các file liên quan.
2. Đọc implementation.
3. Phân tích dependency.
4. Trả về summary kèm file reference.

Khi đó Skill không chạy inline trong main context nữa.

Flow sẽ gần giống:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/deep-research authentication
            │
            ▼
        SKILL.md
            │
            ▼
    isolated subagent context
            │
            ▼
     search / read / analyze
            │
            ▼
         summary
            │
            ▼
       Main Agent

Điều này cho thấy ranh giới giữa Skill và Subagent không hoàn toàn cứng.

Skill vẫn mô tả workflow, nhưng workflow đó có thể được thực thi trong một execution context riêng.


Khi nào nên dùng cái nào?

Rule thực tế mình thấy dễ nhớ nhất là đặt câu hỏi theo ý định.

Nếu chúng ta nghĩ:

1
2
"Tôi muốn Claude hiện tại
biết thêm cách làm việc này."

hãy nghĩ tới Skill.

Ví dụ:

1
2
3
4
5
6
7
API conventions
React conventions
testing standards
deployment workflow
git workflow
security checklist
architecture guidelines

Nếu chúng ta nghĩ:

1
2
"Tôi muốn giao task này cho một worker riêng,
không muốn quá trình exploration làm đầy main context."

hãy nghĩ tới Subagent.

Ví dụ:

1
2
3
4
5
6
7
research codebase
search nhiều file
security review
dependency investigation
log analysis
test analysis
parallel implementation

Nếu chúng ta nghĩ:

1
2
"Tôi muốn một specialist riêng,
nhưng specialist phải tuân theo convention của team."

thì thường câu trả lời là:

1
Subagent + Skills

Ví dụ một project lớn có thể tổ chức như sau:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
                       CLAUDE.md
                           │
                           ▼
                      Main Agent
                           │
          ┌────────────────┼────────────────┐
          │                │                │
          ▼                ▼                ▼
   Backend Agent     Frontend Agent    Reviewer Agent
          │                │                │
          ▼                ▼                ▼
        Skills            Skills           Skills

   API conventions    React patterns   Review rules
   DB patterns        UI standards     Security rules
   Testing            Testing          Architecture

Có thể mở rộng mental model này thêm một chút:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
CLAUDE.md
→ baseline project instructions

Skills
→ reusable knowledge / workflow

Subagents
→ isolated workers

MCP
→ external tools / integrations

Hooks
→ lifecycle automation

Context Engineering: lý do Subagent đặc biệt hữu ích

Khi làm việc với coding agent, một vấn đề rất dễ gặp là context pollution.

Main Claude càng làm nhiều exploration:

1
2
3
4
5
6
7
Read
Grep
Bash
logs
test outputs
temporary hypothesis
failed approaches

thì càng nhiều token trong context được sử dụng cho thông tin trung gian.

Trong khi mục tiêu cuối cùng có thể chỉ cần vài kết luận:

1
2
3
4
- auth flow nằm ở đâu;
- bug nằm ở file nào;
- dependency nào đang gây lỗi;
- approach nào nên implement.

Subagents cho phép biến:

1
large exploration context

thành:

1
small useful report

trước khi thông tin quay trở lại main agent.

Có thể xem đây như một dạng “context compression by delegation”:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Main Agent
    │
    │ task
    ▼
Subagent
    │
    ├─ 50 file reads
    ├─ 30 greps
    ├─ 20 commands
    ├─ failed hypotheses
    └─ detailed analysis
    │
    ▼
compact result
    │
    ▼
Main Agent

Đây là một lý do rất thực tế để sử dụng Subagents ngay cả khi một main agent về lý thuyết vẫn có khả năng tự làm toàn bộ task.


Kết luận

Nếu chỉ cần nhớ ba dòng sau:

1
2
3
4
5
6
7
8
CLAUDE.md
= Claude luôn nên biết gì về project

Skill
= Claude cần biết thêm CÁCH LÀM gì khi cần

Subagent
= Claude nên GIAO VIỆC gì sang context khác

thì chúng ta đã có mental model khá tốt để tổ chức Claude Code.

Điểm cốt lõi nhất:

1
2
3
4
5
6
7
Skill
→ thêm instruction / capability
  vào agent hiện tại

Subagent
→ tạo execution boundary
  và context riêng cho một task

Skills giúp tăng capability.

Subagents giúp chia execution và quản lý context.

Trong project nhỏ, CLAUDE.md kết hợp với một vài Skills thường đã đủ.

Khi codebase lớn hơn, các task cần đọc nhiều file, chạy nhiều tool hoặc có thể thực hiện song song, Subagents bắt đầu mang lại giá trị rõ rệt.

Và khi một Subagent cần tuân theo convention hoặc domain knowledge của team, thay vì copy những instruction đó vào prompt của từng agent, hãy đóng gói chúng thành Skills rồi reuse.


Bạn có thể tìm hiểu chi tiết hơn tại:

This post is licensed under CC BY 4.0 by the author.