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ế.
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: Skills và Subagents.
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 calls và context 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ạnh | Skill | Subagent |
|---|---|---|
| Bản chất | Instruction / capability | Worker |
| Mục đích | Dạy Claude cách làm | Giao task sang execution riêng |
| Context mặc định | Context hiện tại | Context riêng |
| Tạo agent mới | Không | Có |
| Conversation history | Dùng main history | Non-fork không có full history |
| Tool calls | Trong execution hiện tại | Trong execution của Subagent |
| Tool outputs | Có thể làm tăng main context | Chủ yếu nằm trong Subagent |
| Auto Memory | Memory của agent hiện tại | Có thể có memory riêng |
| Coding conventions | Rất phù hợp | Thường không cần |
| Research nhiều file | Có thể làm | Rất phù hợp |
| Parallel work | Không phải mục đích chính | Phù hợp |
| Context isolation | Không | Có |
| Reusable workflow | Rất tốt | Có thể |
| Specialist role | Không phải mục đích chính | Rấ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: