Hướng dẫn toàn tập viết System Prompt cho Agent — Bài học từ dịch ngược Claude Code

Tôi đã dịch ngược system prompt của Claude Code, nghiên cứu source code của DeepAgents, và tự build một AI agent từ con số 0. Hầu hết các bài hướng dẫn viết prompt hiện nay chỉ toàn lý thuyết suông.

Feng Liu
Feng Liu
20 thg 3, 2026·34 phút đọc
Hướng dẫn toàn tập viết System Prompt cho Agent — Bài học từ dịch ngược Claude Code

Đang có một sự ảo tưởng tập thể diễn ra trong giới AI lúc này.

Bài hướng dẫn nào cũng bảo bạn viết system prompt (prompt hệ thống) như thể đang niệm chú — chỉ cần tìm đúng câu thần chú và model sẽ tuân lệnh. "Bạn là một kỹ sư senior CỰC KỲ TÀI NĂNG với 20 năm kinh nghiệm..." Nghe quen không?

Vài tháng qua, mình đã tập trung xây dựng VibeCom, một AI advisor (cố vấn AI) cho startup có khả năng thực hiện nghiên cứu thị trường chuyên sâu và tạo ra các phân tích chuẩn VC (quỹ đầu tư). Dọc đường đi, mình đã dịch ngược (reverse-engineer) system prompt của Claude Code, đọc mã nguồn middleware của DeepAgents, và đốt nhiều API credit hơn mức mình muốn thừa nhận. Bài học lớn nhất? Hầu hết những gì mọi người nghĩ là quan trọng về system prompt thực ra lại chẳng có ý nghĩa gì. Và những thứ thực sự quan trọng thì hầu như không ai nhắc đến.

Bài viết này là một playbook (cẩm nang) hoàn chỉnh — không phải kiểu cưỡi ngựa xem hoa 5 phút, mà là tất cả những gì mình ước ai đó đã nói cho mình biết trước khi bắt đầu. Pha một ly cà phê đi, chúng ta bắt đầu nhé.


1. Triết lý thiết kế: Hãy tin tưởng Model

"Agent là một model. Không phải framework. Không phải một chuỗi prompt (prompt chain)." — shareAI-lab/learn-claude-code

Ý tưởng này đã thay đổi mọi thứ đối với mình. LLM vốn đã biết cách suy luận, lập kế hoạch và thực thi. System prompt của bạn không dùng để dạy nó cách suy nghĩ — nó dùng để thiết lập môi trường cho model làm việc.

Hãy nghĩ nó giống như việc bạn thuê một senior engineer. Bạn không đưa cho họ một checklist 20 bước cho mỗi task. Bạn nói với họ: chúng ta là ai, ranh giới ở đâu, và thế nào là một kết quả tốt. Sau đó, bạn tránh sang một bên để họ làm việc.

System prompt của bạn có chính xác bốn nhiệm vụ:

  • Nói cho nó biết nó là ai — vai trò và danh tính
  • Nói cho nó biết ranh giới ở đâu — các ràng buộc an toàn
  • Nói cho nó biết thế nào là tốt — tiêu chuẩn chất lượng
  • Cung cấp công cụ — năng lực và kiến thức

Chỉ vậy thôi. Mọi thứ khác đều là nhiễu.

Tư duy về Harness (Bộ khung kiểm soát)

Harness = Tools + Knowledge + Observation + Action Interfaces + Permissions

System prompt của bạn là cuốn cẩm nang vận hành cho cái harness này. Bạn không thiết kế một pipeline cứng nhắc — bạn đang thiết kế một môi trường để model có thể tự chủ làm tốt nhất công việc của nó.

Đừng viết system prompt như một lưu đồ (flowchart). Model sẽ tự quyết định thứ tự thực thi.


2. Cấu trúc Prompt và Thứ tự các phần

Bố cục được đề xuất (Dịch ngược từ Claude Code v2.0.14)

┌─────────────────────────────────────────────┐
│ 1. Identity (Danh tính)                      │  ← Đọc đầu tiên, neo giữ hành vi
│ 2. Security & Safety (Bảo mật & An toàn)     │  ← Đánh dấu QUAN TRỌNG, không thể thương lượng
│ 3. Tone & Style (Văn phong & Định dạng)      │  ← Kiểm soát định dạng đầu ra
│ 4. Core Workflow (Quy trình cốt lõi)         │  ← Cách thực hiện công việc
│ 5. Tool Usage Policy (Chính sách dùng Tool)  │  ← Ưu tiên lựa chọn công cụ
│ 6. Domain Knowledge (Kiến thức chuyên ngành) │  ← Tải theo yêu cầu, không tải sẵn
│ 7. Environment Info (Thông tin môi trường)   │  ← Ngữ cảnh runtime, inject động
│ 8. Reminders (Nhắc nhở)                      │  ← Nhắc lại các quy tắc sống còn
├─────────────────────────────────────────────┤
│ [Tool Definitions — system-injected]         │  ← Không thể chỉnh sửa, thường rất dài
├─────────────────────────────────────────────┤
│ [User Message]                               │
└─────────────────────────────────────────────┘

Tại sao thứ tự này lại quan trọng

LLM có đường cong chú ý hình chữ U — chúng chú ý nhiều nhất đến phần đầu và phần cuối của prompt, và hay "lơ đễnh" ở đoạn giữa. Đây là hiệu ứng "Lost in the Middle" (Lạc lối ở giữa), và nó đã được chứng minh rất rõ ràng.

  • Identity + Safety ở trên cùng: Model thiết lập vai trò và ranh giới đầu tiên (hiệu ứng ưu tiên - primacy effect)
  • Core Workflow ở nửa trên: Phần quan trọng nhất của bạn — cách agent làm việc
  • Tool Definitions được hệ thống inject sau prompt của bạn: Định nghĩa công cụ của Claude Code ngốn khoảng ~11.438 token. Điều này có nghĩa là nội dung tùy chỉnh của bạn thực sự nằm gần phần đầu hơn bạn nghĩ — điều này giúp model tuân thủ tốt hơn
  • Reminders ở dưới cùng: Tận dụng thiên kiến gần đây (recency bias) để củng cố các quy tắc quan trọng

3. Cách viết từng phần

3.1 Identity — Agent này là ai?

Mục tiêu: Neo giữ vai trò của model trong 1-3 câu.

You are Claude Code, Anthropic's official CLI for Claude.
You are an interactive agent that helps users with software engineering tasks.

Hướng dẫn:

  • Giữ ngắn gọn — tối đa 1-3 câu
  • Gọi tên vai trò rõ ràng (giúp model phân biệt các ngữ cảnh)
  • Nêu trách nhiệm cốt lõi ("giúp làm việc X"), thay vì câu chung chung "bạn là một trợ lý hữu ích"
  • Nhắc đến SDK/platform nếu có ("được xây dựng trên Claude Agent SDK của Anthropic")

Anti-patterns (Những điều nên tránh):

  • "Bạn là một trợ lý AI hữu ích, vô hại và trung thực" — quá chung chung, không neo được vai trò
  • Viết cả một đoạn văn dài dòng về tiểu sử và cốt truyện — lãng phí token, model không cần phát triển nhân vật

3.2 Security & Safety — Những ranh giới cứng

Mục tiêu: Thiết lập các ràng buộc hành vi không thể phá vỡ.

IMPORTANT: Assist with defensive security tasks only.
Refuse to create, modify, or improve code that may be used maliciously.
IMPORTANT: You must NEVER generate or guess URLs for the user.

Hướng dẫn:

  • Sử dụng tiền tố IMPORTANT: — quá trình huấn luyện phân cấp lệnh của Claude sẽ ưu tiên trọng số cho từ khóa này
  • Sử dụng ngôn ngữ tuyệt đối: NEVER, MUST NOT, Refuse to
  • Nêu rõ cả những gì được phép VÀ những gì bị cấm (ràng buộc hai chiều luôn rõ ràng hơn)
  • Đặt ở vị trí trên cùng, đừng chôn vùi ở giữa
  • Lặp lại các quy tắc an toàn quan trọng ở cuối — Claude Code làm chính xác điều này

Tại sao phải lặp lại? Hiệu ứng ưu tiên (phần đầu) + Hiệu ứng gần đây (phần cuối) = củng cố gấp đôi. Tuyên bố bảo mật của Claude Code xuất hiện ở cả đầu và cuối prompt. Không phải vì các kỹ sư đãng trí — mà vì họ hiểu đường cong chú ý hình chữ U.

3.3 Tone & Style — Kiểm soát đầu ra

Mục tiêu: Kiểm soát định dạng đầu ra và văn phong.

## Tone and style

- Your responses should be short and concise.
- Only use emojis if the user explicitly requests it.
- Use Github-flavored markdown for formatting.
- NEVER create files unless absolutely necessary.

Hướng dẫn:

  • Liệt kê các hành vi cụ thể, đừng nói chung chung kiểu "hãy chuyên nghiệp"
  • Mỗi quy tắc phải có thể test được đúng/sai ("ngắn gọn và súc tích" so với "cố gắng nói ngắn")
  • Bao gồm các yêu cầu về định dạng đầu ra (markdown? JSON? plain text?)
  • Bao gồm những gì KHÔNG ĐƯỢC làm — nhiều vấn đề về style thực chất là việc cấm một hành vi nào đó

Viên ngọc quý của Claude Code — Sự khách quan chuyên nghiệp (Professional Objectivity):

Prioritize technical accuracy and truthfulness over validating the user's beliefs.
Focus on facts and problem-solving, providing direct, objective technical info
without any unnecessary superlatives, praise, or emotional validation.

Đoạn này cực kỳ quan trọng: nó chặn xu hướng nịnh nọt (sycophancy) của model. Nếu agent của bạn cần đưa ra những đánh giá khách quan (code review, đánh giá ý tưởng, quyết định kiến trúc), bạn tuyệt đối cần một điều khoản tương tự.

3.4 Core Workflow — Phần quan trọng nhất

Mục tiêu: Dạy model cách làm việc — phương pháp luận, chứ không phải quy trình cứng nhắc.

Đây là phần khó viết tốt nhất, và mang lại tác động lớn nhất khi bạn làm đúng.

Nguyên tắc cốt lõi: đưa ra nguyên tắc, không phải quy trình.

Hãy nói cho LLM biết một kết quả tốt trông như thế nào và tại sao nó tốt — hãy để nó tự tìm cách đạt được điều đó. Tránh quy định chính xác số lượng trường (field), trình tự các bước hoặc định dạng, trừ khi đầu ra đó được các hệ thống máy móc khác tiêu thụ ở bước sau.

Cách tiếp cận của Claude Code:

## Doing tasks

The user will primarily request software engineering tasks.
For these tasks the following steps are recommended:

- Use the TodoWrite tool to plan the task if required

Hãy chú ý từ "recommended" (được khuyến nghị) — không phải "bạn phải làm theo chính xác các bước này". Việc chọn đúng một từ đó đã cho model không gian để thích ứng.

Một định nghĩa workflow tốt:

1. Understand first — read existing code before modifying it
2. Plan first — break complex tasks into steps before executing
3. Minimal changes — only change what's necessary, don't "refactor while you're in there"
4. Verify — confirm your changes work (run tests, lint, etc.)

Mỗi quy tắc đều có một chữ "tại sao" ngầm định — model có thể hiểu được ý định và khái quát hóa cho các tình huống mới.

Anti-patterns:

  • Một quy trình 20 bước cứng nhắc — model sẽ thực thi một cách máy móc và đóng băng khi gặp input không lường trước
  • "Đầu tiên làm A, sau đó làm B, rồi làm C" — đó là một prompt chain, không phải agent prompt
  • Hướng dẫn quá mức những thứ mà LLM vốn đã giỏi — lãng phí token

Mình đã học được điều này qua một bài học xương máu với VibeCom. Các phiên bản đầu tiên có một quy trình nghiên cứu gồm 10 bước. Model sẽ ngoan ngoãn thực thi cả 10 bước ngay cả khi bước 3 đã trả lời được câu hỏi của người dùng. Khi mình chuyển sang dùng nguyên tắc ("nghiên cứu cho đến khi bạn có đủ bằng chứng, sau đó tổng hợp"), chất lượng tăng lên và chi phí token giảm xuống.

Ngoại lệ: Khi đầu ra được máy móc tiêu thụ ở bước sau (giao tiếp giữa các agent, định dạng phản hồi API), bạn nên định nghĩa các định dạng nghiêm ngặt. Nguyên tắc dành cho hành vi; schema (lược đồ) dành cho giao diện (interface).

3.5 Tool Usage Policy — Giải quyết sự mơ hồ

Mục tiêu: Khi có nhiều công cụ làm được cùng một việc, hãy nói cho model biết nên ưu tiên cái nào.

## Tool usage policy

- Use specialized tools instead of bash commands:
  - Read for reading files instead of cat/head/tail
  - Edit for editing instead of sed/awk
  - Grep for searching instead of grep/rg
- You can call multiple tools in a single response. If independent, call in parallel.
- Use the Task tool for file search to reduce context usage.

Hướng dẫn:

  • Sử dụng "instead of" (thay vì) để thể hiện sự ưu tiên (A thay vì B)
  • Giải thích tại sao nên ưu tiên một số công cụ ("mang lại trải nghiệm người dùng tốt hơn", "giảm việc sử dụng ngữ cảnh")
  • Định nghĩa chiến lược chạy song song (độc lập → song song, phụ thuộc → tuần tự)
  • Liệt kê các ràng buộc bảo mật khi sử dụng công cụ (xác thực đường dẫn, kiểm tra quyền)

Mối quan hệ sống còn giữa công cụ và prompt:

Các định nghĩa công cụ (tool definitions) thường được hệ thống inject vào và bạn không thể chỉnh sửa trực tiếp. Định nghĩa công cụ của Claude Code dài khoảng ~11.438 token. Điều này có nghĩa là:

  • Đừng lặp lại những thông tin đã có trong định nghĩa công cụ
  • Sử dụng system prompt cho các hướng dẫn mang tính chiến lược: khi nào nên dùng công cụ nào, tại sao ưu tiên cái này hơn cái kia, thứ tự ưu tiên
  • Chất lượng của định nghĩa công cụ ảnh hưởng trực tiếp đến hiệu quả của agent — nếu bạn đang tự build agent, hãy đầu tư thời gian để viết mô tả công cụ thật xuất sắc

3.6 Domain Knowledge — Tải theo yêu cầu, không tải sẵn

Mục tiêu: Cung cấp kiến thức chuyên ngành mà dữ liệu huấn luyện của model có thể thiếu.

Nguyên tắc then chốt: tiết lộ lũy tiến (progressive disclosure), không nhồi nhét kiến thức (knowledge dumps).

❌ Paste toàn bộ 200 API endpoint vào system prompt → bùng nổ token
✅ Cho model một công cụ để tra cứu → "Tải kiến thức khi bạn cần"

Chiến lược này được chia sẻ bởi hệ thống Skills của Claude Code và middleware Progressive Disclosure của DeepAgents. Cả hai đều tải kiến thức theo yêu cầu thông qua các tool call thay vì tải sẵn mọi thứ.

Cách triển khai:

  1. Đặt con trỏ (pointers) trong system prompt: "Sử dụng công cụ get_api_docs để lấy tài liệu khi cần"
  2. Sử dụng CLAUDE.md / AGENTS.md cho ngữ cảnh dự án — được tải lúc runtime, không hardcode
  3. Sử dụng Skills / SKILL.md để khám phá năng lực — model nhìn thấy một menu các kỹ năng có sẵn, và sẽ fetch toàn bộ thông số kỹ thuật khi có nhu cầu

3.7 Environment Info — Ngữ cảnh Runtime

Mục tiêu: Cho model nhận thức về môi trường thực thi của nó.

<env>
Working directory: /Users/fengliu/Desktop/tfm/vibecom
Is directory a git repo: true
Platform: darwin
Today's date: 2026-03-21
</env>
You are powered by the model named Claude Opus 4.6.

Hướng dẫn:

  • Tạo động (generate dynamically), tuyệt đối không hardcode
  • Bao gồm: thư mục làm việc, nền tảng (platform), ngày tháng, tên model, trạng thái git
  • Sử dụng định dạng có cấu trúc (thẻ XML hoặc code block) để dễ parse
  • Ngày tháng rất quan trọng — model cần biết "bây giờ" là lúc nào để đánh giá độ mới của thông tin

3.8 Reminders — Sự củng cố cuối cùng

Mục tiêu: Nhắc lại các quy tắc quan trọng nhất ở cuối prompt.

Claude Code lặp lại ràng buộc an toàn và yêu cầu dùng TodoWrite ở dưới cùng:

IMPORTANT: Assist with defensive security tasks only. [repeated]
IMPORTANT: Always use the TodoWrite tool to plan and track tasks. [repeated]

Hướng dẫn:

  • Chỉ lặp lại 2-3 quy tắc quan trọng nhất — đừng nhân bản mọi thứ
  • Tận dụng thiên kiến gần đây (recency bias) — model nhớ nội dung gần đây mạnh mẽ hơn
  • Ứng viên tốt nhất: ràng buộc an toàn, các quy tắc thường xuyên bị vi phạm nhất, nhắc nhở về workflow cốt lõi

4. Ngân sách Token và Quản lý Ngữ cảnh

Bảng tham khảo phân bổ ngân sách

PhầnToken đề xuấtGhi chú
Identity + Safety200-500Ngắn gọn nhưng không thể thương lượng
Tone & Style300-800Quy tắc phải cụ thể, nhưng đừng lan man
Core Workflow500-2.000Phần quan trọng nhất, đáng để đầu tư
Tool Usage Policy300-1.000Phụ thuộc vào số lượng công cụ
Domain Knowledge0-1.000Ưu tiên tải theo yêu cầu (on-demand)
Environment Info100-300Được tạo động
Reminders100-300Chỉ nhắc lại những điều cốt yếu
Tổng cộng của bạn1.500-6.000
Tool Definitions (system)5.000-15.000Nằm ngoài tầm kiểm soát của bạn

Đường cong suy giảm ngữ cảnh

Các thử nghiệm từ cộng đồng (Reddit u/CodeMonke_) đã lập bản đồ sự suy giảm mức độ tuân thủ trong thực tế:

  • < 80K token: Mức độ tuân thủ prompt duy trì ổn định
  • 80K - 120K token: Khả năng làm theo hướng dẫn bắt đầu suy giảm
  • > 120K token: Suy giảm đáng kể — model "quên" các hướng dẫn ban đầu
  • > 180K token: Suy giảm nghiêm trọng

Cửa sổ ngữ cảnh 200K của bạn ≠ 200K ngữ cảnh hiệu quả. Hãy lên kế hoạch cho cẩn thận.

Chiến lược giảm thiểu:

  • Giữ system prompt của bạn gọn gàng (< 6.000 token cho phần của bạn)
  • Sử dụng summarization (tóm tắt) để nén lịch sử hội thoại (DeepAgents kích hoạt ở khoảng ~80K ký tự)
  • Đặt các quy tắc quan trọng ở cả hai đầu của prompt (Đường cong chú ý hình chữ U)
  • Inject các thẻ <system-reminder> vào giữa cuộc hội thoại (chi tiết hơn ở phần 8)

5. Nguyên tắc viết

5.1 Đưa ra Nguyên tắc, Không phải Quy trình

❌ "Bước 1: Đọc file. Bước 2: Tìm bug. Bước 3: Sửa nó. Bước 4: Chạy test."
✅ "Luôn hiểu code hiện tại trước khi sửa đổi. Xác minh rằng các thay đổi của bạn hoạt động."

Nguyên tắc thì có thể khái quát hóa. Quy trình thì chỉ có thể làm theo một cách máy móc. Khi model gặp một tình huống mà bạn không lường trước được, nguyên tắc sẽ dẫn đường cho quyết định đúng đắn. Quy trình thì không.

Ngoại lệ: Khi đầu ra được máy móc tiêu thụ (giao tiếp giữa các agent, định dạng API), hãy định nghĩa các schema nghiêm ngặt.

5.2 Sử dụng Ngôn ngữ Tuyệt đối cho các Ràng buộc Cứng

Cường độNgôn ngữDùng cho
Cấm tuyệt đốiNEVER, MUST NOTAn toàn, các thao tác không thể hoàn tác
Yêu cầu mạnhALWAYS, MUSTCác quy tắc workflow cốt lõi
Khuyến nghịrecommended, preferBest practices có ngoại lệ
Gợi ýconsider, you mayTối ưu hóa tùy chọn

Ví dụ từ Claude Code:

  • NEVER update the git config — cấm tuyệt đối
  • ALWAYS prefer editing an existing file — mạnh mẽ, nhưng có ngoại lệ
  • The following steps are recommended — workflow được gợi ý

5.3 Sử dụng Ví dụ thay vì Giải thích

## Code References

When referencing specific functions or pieces of code include
the pattern `file_path:line_number`.

<example>
user: Where are errors from the client handled?
assistant: Clients are marked as failed in the `connectToServer`
function in src/services/process.ts:712.
</example>

Một ví dụ dạy được nhiều hơn 100 từ giải thích:

  • Các model học pattern từ ví dụ đáng tin cậy hơn là từ các mô tả trừu tượng
  • Bọc bằng thẻ <example> để tách biệt khỏi các quy tắc
  • Cung cấp cả ví dụ tích cực ("nên làm thế này") và tiêu cực ("đừng làm thế này")
  • Sử dụng ví dụ thực tế, cụ thể — đừng dùng các placeholder kiểu "foo/bar"

5.4 Ràng buộc Hai chiều

✅ "Sử dụng các công cụ chuyên dụng: Read để đọc file, Edit để sửa file."
✅ "KHÔNG sử dụng bash cho các thao tác file (cat, head, tail, sed, awk)."

Chỉ nói "làm cái này" → model không biết khi nào KHÔNG NÊN làm. Chỉ nói "đừng làm cái này" → model không biết giải pháp thay thế. Hai chiều → rõ ràng và không mơ hồ.

5.5 Giải thích Tại sao, Đừng chỉ nói Cái gì

❌ "Đừng dùng git commit --amend."
✅ "Tránh dùng git commit --amend. CHỈ dùng --amend khi:
   (1) user yêu cầu amend một cách rõ ràng HOẶC
   (2) thêm các chỉnh sửa từ pre-commit hook.
   Lý do: amend có thể ghi đè lên commit của người khác."

Giải thích chữ tại sao giúp model đưa ra phán đoán chính xác trong các edge cases (trường hợp ngoại lệ). Giao thức an toàn git của Claude Code là một masterclass — mọi quy tắc đều ngầm chứa lý do của nó.

5.6 Cấu trúc quan trọng hơn Văn xuôi

  • Markdown headers (##, ###) — model nhận diện được hệ thống phân cấp
  • Bullet lists (danh sách) thay vì đoạn văn — mỗi quy tắc có thể test độc lập
  • XML tags cho nội dung đặc biệt: <example>, <env>, <system-reminder>
  • Tables (bảng) cho so sánh và mapping
  • Không bao giờ ném vào một đống text không có cấu trúc — các prompt có cấu trúc luôn vượt trội hơn văn xuôi tự nhiên trong các bài test về mức độ tuân thủ

6. Những Anti-Pattern làm lãng phí Token của bạn

Prompt Chain đội lốt Agent

"Đầu tiên gọi tool A để lấy data.
Sau đó gọi tool B với kết quả đó.
Sau đó format đầu ra thành JSON.
Sau đó lưu vào file."

Đây không phải là agent prompt — nó là một kịch bản pipeline. Model sẽ thực thi một cách máy móc và mất đi khả năng tự chủ lập kế hoạch.

Cách sửa: Nói cho model biết mục tiêu và các ràng buộc. Hãy để nó tự quyết định các bước.

Kỹ nghệ Nịnh bợ (Flattery Engineering)

"Bạn là một kỹ sư phần mềm senior CỰC KỲ TÀI NĂNG
và VÔ CÙNG KINH NGHIỆM với 20 năm làm nghề..."

Những lời khen ngợi và từ ngữ tâng bốc không làm tăng chất lượng đầu ra. Model không có cái tôi để bạn vuốt ve. Hãy tiết kiệm 15 token đó cho một quy tắc thực sự.

Nhồi nhét Kiến thức (Knowledge Dumps)

"Đây là toàn bộ tài liệu API cho 200 endpoint của chúng ta..."

Việc này ngấu nghiến cửa sổ ngữ cảnh của bạn và đẩy nhanh quá trình mục nát ngữ cảnh (context rot). Hãy thay thế bằng việc tải theo yêu cầu:

"Sử dụng công cụ get_api_docs để lấy tài liệu API khi cần."

Lặp lại Mô tả Công cụ

Nếu định nghĩa công cụ đã nói "Công cụ Read đọc một file từ hệ thống file", đừng nói lại điều đó trong system prompt của bạn. Chỉ thêm các hướng dẫn mang tính chiến lược mà định nghĩa công cụ không đề cập — khi nào nên dùng nó, tại sao nên ưu tiên nó, thứ tự ưu tiên.

Thiếu Xử lý Lỗi

Nếu không có hướng dẫn rõ ràng, model sẽ thử lại các tool call bị lỗi trong một vòng lặp vô hạn (infinite loop). Luôn bao gồm:

"Nếu một tool call bị từ chối, đừng thử lại chính xác call đó.
Hãy suy nghĩ xem tại sao nó bị từ chối và điều chỉnh cách tiếp cận của bạn."

Bỏ qua sự Suy giảm của Cửa sổ Ngữ cảnh

Cửa sổ ngữ cảnh 200K ≠ 200K ngữ cảnh hiệu quả. Thử nghiệm thực tế cho thấy sự suy giảm bắt đầu ở mức 80K. Bạn cần một chiến lược tóm tắt (summarization).


7. Các điểm Inject và Mức độ Ưu tiên

3 Phương pháp Tùy chỉnh của Claude Code

Phương phápThay thếVị tríTốt nhất cho
Output StylesPhần "Tone and style" + "Doing tasks"Ngay trước tool definitionsThay đổi phong cách tương tác
--append-system-promptKhông thay thế (cộng dồn)Sau output style, trước tool definitionsThêm các hành vi cụ thể
--system-promptToàn bộ system promptGiữ lại tool definitions + 1 dòng identityTùy chỉnh toàn bộ (lựa chọn hạt nhân)

Nếu bạn dùng nhiều phương pháp: Output Style → Append Prompt → Tool Definitions

Phân cấp Lệnh (Instruction Hierarchy)

Claude được huấn luyện đặc biệt với một hệ thống phân cấp lệnh:

1. Hướng dẫn rõ ràng của User (CLAUDE.md, yêu cầu trực tiếp)  ← Ưu tiên cao nhất
2. Các phần bổ sung system prompt tùy chỉnh                   ← Cao
3. System prompt mặc định                                     ← Trung bình
4. Tool definitions (Định nghĩa công cụ)                      ← Mức tham chiếu

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

  • Các quy tắc trong CLAUDE.md ghi đè hành vi của system prompt mặc định
  • Yêu cầu trực tiếp của người dùng ghi đè mọi thứ
  • Prompt tùy chỉnh của bạn ghi đè prompt mặc định

Cơ chế Inject Động

  • <system-reminder> — inject vào bất kỳ tin nhắn nào giữa cuộc hội thoại để nhắc model về các quy tắc quan trọng
  • CLAUDE.md / AGENTS.md — tải lúc runtime từ các file, nối thêm vào system prompt
  • Skills / SKILL.md — tải theo yêu cầu qua tool calls, không chiếm dung lượng trong system prompt

8. Tiêm (Inject) giữa cuộc hội thoại — Vũ khí bí mật

System prompt chỉ xuất hiện một lần, ở ngay đầu mảng messages (messages array). Nhưng LLM nhận toàn bộ mảng messages (xen kẽ user / assistant / tool messages) làm input, và bạn có thể inject prompt vào cả user messages và tool results. Claude Code sử dụng kỹ thuật này rất nhiều trong production.

Tại sao nó cần thiết

Chống lại sự mục nát ngữ cảnh (context rot). Khi cuộc hội thoại dài ra, mức độ tuân thủ của model đối với các hướng dẫn trong system prompt sẽ giảm dần (nhận thấy rõ ở mức 80K+ token). Inject các nhắc nhở giữa cuộc hội thoại = làm mới các quy tắc thông qua thiên kiến gần đây (recency bias).

Mental model (Mô hình tư duy):

  • System prompt = Hiến pháp (thiết lập một lần, thẩm quyền dài hạn)
  • User message reminders = Bản ghi nhớ / Memos (gửi định kỳ, duy trì việc thực thi)

Ba điểm Inject trong Mảng Messages

Messages Array:
┌─────────────────────────────────────┐
│ System Prompt                       │ ← Xuất hiện 1 lần, hiệu ứng ưu tiên
│   (identity, safety, workflow...)   │
├─────────────────────────────────────┤
│ User Message 1                      │
│ Assistant Message 1                 │
│ User Message 2 + <system-reminder>  │ ← Inject giữa cuộc hội thoại
│ Assistant Message 2                 │
│ Tool Result + <system-reminder>     │ ← Có thể inject vào cả tool results
│ ...                                 │
│ User Message N + <system-reminder>  │ ← Tin nhắn mới nhất, recency mạnh nhất
└─────────────────────────────────────┘
Vị tríƯu điểmNhược điểm
System promptHiệu ứng ưu tiên, đọc đầu tiênXuất hiện 1 lần, bị "quên" trong hội thoại dài
User message injectionRecency bias, làm mới định kỳMỗi lần inject đều tốn token
Tool result injectionĐiểm inject tự nhiên nhấtChỉ hoạt động khi các tool được gọi

Cách Claude Code thực sự sử dụng nó

Điều kiện tiên quyết — khai báo các thẻ trong system prompt:

Tool results and user messages may include <system-reminder> tags.
<system-reminder> tags contain useful information and reminders.
They are automatically added by the system, and bear no direct
relation to the specific tool results or user messages in which they appear.

Bước này rất quan trọng: nó nói cho model biết những thẻ này do hệ thống inject vào, không phải lời nói của người dùng.

Cách dùng 1: Nhắc nhở Hành vi (làm mới quy tắc định kỳ)

<system-reminder>
The task tools haven't been used recently. If you're working on tasks
that would benefit from tracking progress, consider using TaskCreate...
</system-reminder>

Claude Code dùng cách này để nhắc model lên kế hoạch với TodoWrite — vì các model có xu hướng "quên" việc lập kế hoạch và cứ thế cắm đầu vào code.

Cách dùng 2: Chuyển đổi Chế độ (Plan Mode)

<system-reminder>
Plan mode is active. The user indicated that they do not want you to
execute yet -- you MUST NOT make any edits, run any non-readonly tools,
or otherwise make any changes to the system.
</system-reminder>

Plan mode (chế độ lập kế hoạch) không được implement trong system prompt. Nó là một thẻ được inject vào user message tiếp theo. Điều này cho phép bạn bật/tắt các chế độ một cách linh hoạt mà không cần sửa đổi system prompt. Quá thông minh.

Cách dùng 3: Thông báo Thay đổi File

<system-reminder>
Note: /path/to/file.ts was modified, either by the user or by a linter.
This change was intentional, so make sure to take it into account.
</system-reminder>

Khi một process bên ngoài (linter, formatter, chỉnh sửa thủ công) sửa đổi một file, hệ thống sẽ thông báo cho model qua reminder — ngăn chặn việc đưa ra quyết định dựa trên nội dung file đã cũ.

Cách dùng 4: Ngữ cảnh Động (ngày tháng, quy tắc dự án)

<system-reminder>
Today's date is 2026-03-21.
Current branch: dev
claudeMd: [CLAUDE.md content injected here]
</system-reminder>

Ngữ cảnh runtime (ngày tháng, trạng thái git, quy tắc dự án) được inject qua user messages, không hardcode trong system prompt.

Hướng dẫn viết Reminders

  • Bọc trong thẻ XML (<system-reminder>) — model có thể phân biệt system injection với lời nói của người dùng
  • Khai báo trước các thẻ trong system prompt — nếu không model có thể cố gắng trả lời lại cái reminder đó
  • Đừng inject vào mọi tin nhắn — mỗi lần inject đều tốn token, chỉ inject khi cần
  • Giữ cho nó ngắn gọn — reminder không phải là system prompt thứ hai, chỉ 1-2 quy tắc quan trọng
  • Đừng mâu thuẫn với system prompt — reminders bổ sung và củng cố, chúng không ghi đè
  • Sử dụng cho việc bật/tắt động — plan mode, readonly mode, feature flags

Khi nào dùng System Prompt vs. User Message Reminder

Kịch bảnSystem PromptUser Message Reminder
Định nghĩa vai trò
Ràng buộc an toàn✅ Khai báo đầu tiên✅ Lặp lại định kỳ
Phương pháp workflow
Chuyển chế độ (plan mode)
Thông báo thay đổi file
Ngày tháng / môi trường✅ Giá trị ban đầu✅ Giá trị cập nhật
Điều chỉnh hành vi
Nhắc nhở dùng tool✅ Định nghĩa luật✅ Cú hích thực thi

9. Prompt Cache — Tiết kiệm 90% token lặp lại

Tính năng prompt caching của Anthropic cho phép bạn cache lại tiền tố tĩnh (static prefix) của mảng messages. Khi các request tiếp theo chia sẻ cùng một tiền tố, chúng sẽ hit cache — tiết kiệm tiền và giảm độ trễ (latency).

Đối với các agent, điều này cực kỳ quan trọng: bạn đang gửi lại system prompt + tool definitions trong mỗi một LLM call duy nhất trong suốt cuộc hội thoại.

Những con số quan trọng

Chỉ sốGiá trị
Chi phí Cache hit10% giá bình thường (tiết kiệm 90%)
Chi phí Cache write125% giá bình thường (phụ phí 25% cho lần ghi đầu tiên)
Cache TTL5 phút (hết hạn nếu không có request)
Độ dài tối thiểu để cache1.024 token (Claude 3.5+)
Độ chi tiết của CachePrefix matching — từ đầu đến một breakpoint được đánh dấu
Số breakpoint tối đa4

Điều này thay đổi Thiết kế Prompt như thế nào

Nguyên tắc cốt lõi: nội dung tĩnh (static) trước, nội dung động (dynamic) sau.

✅ Bố cục thân thiện với Cache:
  System prompt (tĩnh)        ← Cache breakpoint 1
  Tool definitions (tĩnh)     ← Cache breakpoint 2
  CLAUDE.md / project rules   ← Cache breakpoint 3 (thỉnh thoảng thay đổi)
  Conversation history         ← Breakpoint 4 cho rolling window

❌ Bố cục phá hủy Cache:
  System prompt
  TIMESTAMP ĐỘNG               ← Thay đổi mỗi request, mọi thứ phía sau = cache miss
  Tool definitions
  Conversation history

Cái bẫy không ai cảnh báo bạn: Nếu bạn đặt một timestamp động vào giữa system prompt của bạn, mọi thứ phía sau nó sẽ trở thành cache miss. Trong. Mọi. Request. Chỉ một timestamp đặt sai chỗ và bạn đang phải trả nguyên giá cho hàng ngàn token.

Cách dùng API

const response = await anthropic.messages.create({
  model: "claude-sonnet-4-6",
  system: [
    {
      type: "text",
      text: "You are a startup advisor...",
      cache_control: { type: "ephemeral" }  // ← đánh dấu một cache breakpoint
    }
  ],
  messages: [...]
});

Chiến lược Multi-Breakpoint

Breakpoint 1: System prompt           ← Gần như không bao giờ thay đổi
Breakpoint 2: Tool definitions         ← Gần như không bao giờ thay đổi
Breakpoint 3: Project rules / CLAUDE.md ← Thỉnh thoảng thay đổi
Breakpoint 4: N tin nhắn lịch sử đầu tiên ← Rolling window cache

Ngay cả khi lịch sử hội thoại thay đổi, 3 breakpoint đầu tiên vẫn hit cache. Một cuộc hội thoại 10 lượt (turn) tiết kiệm được khoảng 40-60% chi phí input token.

Khuyến nghị Thiết kế

  • Không để các giá trị động thay đổi liên tục trong system prompt — ngày tháng thì ổn (thay đổi hàng ngày), nhưng timestamp chính xác thì không
  • Đặt ngữ cảnh động (trạng thái git, v.v.) vào user message injections — đừng đặt trong system prompt, nếu không bạn sẽ phá hủy cache
  • Giữ tool definitions ổn định — đừng thêm/bớt tool động lúc runtime
  • Sử dụng rolling window cho lịch sử hội thoại — cache N tin nhắn đầu tiên, chỉ tin nhắn mới nhất mới là cache miss

10. Checklist kiểm tra

Sau khi viết xong system prompt, hãy rà soát lại theo checklist này:

Cấu trúc

  • Identity nằm ở vị trí trên cùng?
  • Các ràng buộc an toàn được đánh dấu IMPORTANT và lặp lại ở cuối?
  • Phân tách các phần rõ ràng bằng headers?
  • Các ví dụ được bọc trong thẻ <example>?

Ngân sách Token

  • Phần của bạn < 6.000 token?
  • Không lặp lại thông tin đã có trong tool definitions?
  • Domain knowledge được tải theo yêu cầu, không tải sẵn?
  • Không có cốt truyện dài dòng hay tiểu sử nhân vật?

Chất lượng Quy tắc

  • Mọi quy tắc đều có thể test đúng/sai?
  • Các ràng buộc cứng sử dụng ngôn ngữ tuyệt đối (NEVER/MUST)?
  • Các gợi ý mềm sử dụng ngôn ngữ khuyến nghị (recommended/prefer)?
  • Các quy tắc quan trọng có giải thích tại sao, chứ không chỉ cái gì?
  • Ràng buộc hai chiều (làm cái này + đừng làm cái kia)?

Hành vi của Agent

  • Đưa ra nguyên tắc, không phải quy trình từng bước cứng nhắc?
  • Đã xử lý kịch bản "tool call bị từ chối"?
  • Đã xử lý chiến lược "gặp chướng ngại vật" (không brute-force thử lại)?
  • Đã có chiến lược quản lý ngữ cảnh (ngưỡng tóm tắt)?

Những điều KHÔNG NÊN làm

  • Không nịnh bợ hay dùng tính từ tâng bốc?
  • Không có những câu thừa thãi kiểu "bạn là một AI hữu ích"?
  • Không viết theo kiểu prompt chain?
  • Không over-engineering (làm lố những tính năng không ai yêu cầu)?

Nếu mình bắt đầu lại từ hôm nay

Đây chính xác là những gì mình sẽ làm:

  1. Bắt đầu với identity + safety trong 3 dòng đầu tiên. Hai câu để xác định agent là ai. Các ràng buộc cứng với NEVER/MUST. Lặp lại các quy tắc an toàn ở cuối.

  2. Viết core workflow của bạn dưới dạng nguyên tắc, không phải các bước. Tối đa 4-5 gạch đầu dòng. Dùng "recommended" và "prefer" cho các quy tắc mềm, "NEVER" và "MUST" cho các quy tắc cứng.

  3. Dành ngân sách 1.500-6.000 token cho phần của bạn. Tool definitions sẽ cộng thêm 5.000-15.000 nữa. Nếu bạn vượt quá 6K, có lẽ bạn đang nhồi nhét những kiến thức lẽ ra nên được tải theo yêu cầu.

  4. Cấu trúc hóa mọi thứ. Markdown headers, bullet lists, thẻ XML cho các ví dụ. Một prompt có cấu trúc luôn đánh bại văn xuôi tự nhiên.

  5. Tích hợp mid-conversation reminders ngay từ ngày đầu tiên. Khai báo <system-reminder> trong system prompt của bạn. Inject các nhắc nhở cho các quy tắc quan trọng, chuyển đổi chế độ, và cập nhật ngữ cảnh.

  6. Thiết kế cho cache. Nội dung tĩnh trước, nội dung động sau. Không bao giờ đặt các giá trị thay đổi liên tục vào phần thân system prompt của bạn.


Sự trớ trêu của tất cả những việc này? Những system prompt tốt nhất lại rất ngắn. Các custom instructions của Claude Code (không tính tool definitions) ngắn gọn đến bất ngờ. Mỗi dòng đều xứng đáng với vị trí của nó.

Mình từng nghĩ prompt engineering là việc tìm ra những thủ thuật khôn ngoan. Bây giờ mình nghĩ nó là về sự kỷ luật — nói ít hơn, nói chính xác hơn, và tin tưởng model sẽ tự tìm ra phần còn lại. Model thông minh hơn prompt của bạn. Hãy thiết kế môi trường, đừng thiết kế hành vi.


Tài liệu tham khảo

NguồnInsight Chính
Claude Code v2.0.14 System PromptTham chiếu cấu trúc agent prompt thực tế trong production
Reddit: Understanding Claude Code's 3 System Prompt MethodsĐi sâu vào Output Styles / --append / --system-prompt, dữ liệu thực tế về context rot
shareAI-lab/learn-claude-codeTriết lý "Model chính là agent", phương pháp luận harness engineering
Anthropic Prompt Engineering DocsCác best practices chính thức về prompt
DeepAgents FrameworkMiddleware tóm tắt, tiết lộ lũy tiến (progressive disclosure) cho skills
ai agent system promptsprompt engineering guideclaude code system promptbuilding ai agentsllm prompt optimization

Chia sẻ

Feng Liu

Được viết bởi Feng Liu

shenjian8628@gmail.com