Tối ưu giá trị cho mỗi phiên làm việc với Claude Code
Tóm tắt:
Phần tiêu đề “Tóm tắt:”- Chạy
/cleargiữa các tác vụ không liên quan. Việc này ngăn ngữ cảnh cũ (không liên quan) bị gửi lại cho mô hình (model), giúp giảm số token tiêu tốn. - **Chọn model và effort level trước khi bắt đầu.** Đổi một trong hai thành phần này ở giữa chừng cuộc hội thoại có thể làm hỏng prompt cache, khiến chi phí token tăng lên.
- @-mention file thay vì gõ tên file. File sẽ được đính kèm trực tiếp vào prompt của bạn, giúp tiết kiệm một lệnh gọi Read, hoặc một lượt tìm kiếm nếu Claude phải tự đi tìm file đó.
- Đối với các lệnh cho ra output nhiều, nên dùng các flag/parameter để làm sao ẩn bớt hoặc làm gọn output, hoặc chạy các lệnh này trong subagent. Lý do là các output đều được thêm vào cuộc hội thoại và cứ ở đó trong suốt session, và sẽ nằm trong input gởi cho model trong các bước làm việc tiếp theo.
- Chạy
/contextmột lần trong một phiên mới. Nó cho thấy những gì đang được đưa vào context hiện tại (CLAUDE.md, định nghĩa các MCP tool), để bạn có thể loại bỏ những gì không cần thiết. - Chạy
/compacttrước khi dừng làm việc trong một khoảng thời gian dài. Prompt cache hết hạn sau một giờ, và việc tóm tắt cuộc hội thoại rẻ hơn nhiều khi nó vẫn còn trong cache.
Tối ưu giá trị
Phần tiêu đề “Tối ưu giá trị”Các IDE bạn dùng để viết code thường tính phí cố định (hoặc miễn phí). Cho nên chi phí sử dụng IDE trong một buổi hay một ngày làm việc là không đổi, dù bạn có làm một hay nhiều việc trong buổi làm việc đó thì bạn cũng đều phải trả phí sử dụng IDE như nhau, nghĩa là từng công việc không có chi phí riêng (nếu xét về mặt chi phí sử dụng IDE).
Với các công cụ AI coding agent như Claude Code thì sẽ không giống như vậy. Cùng một tác vụ hoàn thành có thể tốn chi phí khác nhau tuỳ vào cách bạn dùng agent đó như thế nào.
Ví dụ: chúng ta cần kiểm tra và chỉnh sửa một file unit test tương ứng với một file code.
- Một cách tiếp cận là dùng
@ten-fileđể chỉ định chính xác các file này, Claude Code sẽ đọc thẳng các file được chỉ định, thực hiện sửa đổi và hoàn thành công việc sau một vài lượt chạy. - Ở cách tiếp cận khác, do các file không được chỉ định, Claude Code phải chạy lệnh
grepđể quét các file trong dự án nhằm tìm kiếm chính xác file. Cách tiếp cận này khiến Claude Code phải đọc rất nhiều file trước khi tìm được 2 file cần dùng. Nghiêm trọng hơn, các file không liên quan vẫn còn nằm trong phiên làm việc và sẽ được giữ lại, sử dụng làm input (đầu vào) cho các prompt tiếp theo.
Nghĩa là cùng một công việc nhưng với 2 cách tiếp cận khác nhau, sẽ tốn chi phí (token) hoàn toàn khác nhau.

Dùng token hiệu quả không có nghĩa là dùng ít token hơn nói chung. Nó có nghĩa là đảm bảo những token bạn dùng thực sự phục vụ đúng việc bạn yêu cầu.
Vậy hãy cùng xem điều gì quyết định giá của một token, sau đó điều gì quyết định số lượng token một session gửi đi và điều đó có ý nghĩa gì đối với cách bạn vận hành một session.
Điều gì quyết định giá của một token
Phần tiêu đề “Điều gì quyết định giá của một token”Các mô hình LLM tính phí theo token, nhưng thứ bạn thực sự trả tiền là cho việc suy luận (inference): thời gian một GPU (hay TPU, hay bất kỳ phần cứng nào mô hình đang chạy trên đó) chạy mô hình qua các token của bạn.
Ba yếu tố quyết định một token tốn bao nhiêu thời gian:
- Bạn đang chạy mô hình nào?
- Nó là input token hay output token (input có giá khác với output)?
- Nó có được lấy từ cache hay không?
Chúng ta cùng phân tích từng yếu tố.
Mô hình (Model)
Phần tiêu đề “Mô hình (Model)”Một mô hình lớn hơn làm nhiều việc hơn trên cả token đầu vào lẫn đầu ra. Mô hình nào đáng dùng cho loại việc nào là một chủ đề riêng, đã được đề cập trong bài “Chọn model và effort level trong Claude Code”.
Trong bài viết này, bạn chỉ cần hiểu rằng giá/chi phí token đầu vào, token đầu ra và cả các prompt cache đều được tính dựa vào giá của model đang dùng: dùng một mô hình lớn hơn khi vấn đề thực sự khó hoặc mơ hồ, và một mô hình nhỏ hơn khi công việc đơn giản hơn.

Các đường cong chỉ mang tính minh hoạ. Chúng không đại diện cho dữ liệu benchmark thực tế.
Token đầu vào và đầu ra (Input và output tokens)
Phần tiêu đề “Token đầu vào và đầu ra (Input và output tokens)”Một request đi qua GPU theo hai giai đoạn, và chúng tốn chi phí khác nhau.
Đầu tiên, trong giai đoạn prefill, mô hình đọc request và ngữ cảnh (context) của bạn: system prompt, CLAUDE.md, tin nhắn của bạn, và mọi thứ đã được thêm vào cuộc hội thoại trước đó (các file Claude đã đọc và kết quả (output) của các lệnh nó đã chạy). Đó là các token đầu vào (input) của bạn.
Sau đó, trong giai đoạn giải mã (decode), nó viết ra các token đầu ra (output), bao gồm: quá trình suy nghĩ (thinking) của nó, các lệnh gọi tool nó thực hiện, và đoạn text bạn nhìn thấy. Việc này diễn ra từng token một; một đoạn trả lời với 200 token là 200 lượt chạy mô hình nối tiếp nhau. Tính theo từng token, decode đòi hỏi GPU làm việc lâu hơn (so với prefill - input token), đó là lý do output được định giá gấp khoảng 5 lần input.

Phần lớn token đầu ra trong một phiên là token cho việc suy nghĩ (thinking), và mô hình “suy nghĩ” bao nhiêu mỗi lượt là điều mà effort level kiểm soát. Giống như model, effort level mà bạn chọn bằng cách chạy lệnh /effort sẽ được giữ lại làm mặc định cho phiên tiếp theo.
Mẹo: chạy /model và /effort một lần trong một session mới để xem bạn đang thực sự dùng cấu hình nào. Cả hai đều nhớ lựa chọn lần trước của bạn, nên việc này giúp bạn xác nhận lại model và effort phù hợp với độ khó của công việc trong session hiện tại.
Mẹo: nếu bạn đã biết trước một session sẽ chỉ là việc “chân tay” (grunt work), MAX_THINKING_TOKENS=0 claude tắt thinking cho riêng session đó (trừ trên Fable 5), đây là cấu hình làm cho model dùng effort thấp hơn cả khi bạn cấu hình/effort low.
Prompt caching
Phần tiêu đề “Prompt caching”Nếu phần đầu của một request khớp chính xác, từng token một, với phần đầu của một request mà server vừa xử lý trước đó, thì kết quả tính toán (gọi là “state”) mà model tạo ra khi đọc qua đoạn đầu đó chắc chắn sẽ giống hệt nhau ở cả hai lần - vì cùng một input thì model luôn cho ra cùng một kết quả trung gian. Do đó server không cần tính lại đoạn đầu này, mà có thể tái sử dụng ngay kết quả đã lưu từ lần trước, và chỉ cần prefill (tính toán) phần còn lại phía sau - tức là phần mới. Đây gọi là prompt caching.
Đọc từ cache tốn 0.1x (1/10) giá input, vì server chỉ nạp lại trạng thái (state) thay vì tính toán lại. Ghi token vào cache tốn nhiều hơn một chút so với input thông thường, lên đến 2x, vì server còn phải giữ trạng thái đó lại sau này. Nhưng việc ghi chỉ xảy ra một lần cho mỗi token, còn việc đọc với giá 0.1x thì xảy ra ở mỗi lượt sau đó.
Claude Code tự quản lý prompt cache cho mỗi request, bạn không cần kích hoạt cache bằng tay. Tuy nhiên bạn có thể làm hỏng cache, nên việc biết cách bảo vể cache là rất quan trọng để tránh những chi phí không đáng có.
Giả sử bạn gõ “sửa code test đang fail trong utils.test.ts”. Đây là những gì Claude Code gửi đi cho yêu cầu đó:
- Claude Code tạo ra request đầu tiên bằng việc kết hợp system prompt (bao gồm cả định nghĩa tool),
CLAUDE.mdcủa bạn, và tin nhắn của bạn, rồi gửi đi (input token). Do đây là request đầu tiên, chưa có gì trong cache, nên toàn bộ đều được prefill và ghi vào cache. - Model không thể sửa một test nó chưa thấy, nên nó nghĩ một lúc rồi phản hồi bằng một lệnh gọi Read cho
utils.test.ts(output token). Claude Code đọc file, thêm vào cuộc hội thoại, và gửi lại toàn bộ (input token). Lần này mọi thứ từ request 1 được đọc lại từ cache với giá bằng một phần mười (so với giá tính toán nếu không có cache), và chỉ có phần mới (lệnh gọi Read và file đó) là được tính với giá của input thông thường. - Giờ model muốn có file đang được kiểm thử (output). Thêm một lệnh Read, thêm một lần append, và mọi thứ lại được gửi đi: request 1 và 2 từ cache, file thứ hai với giá đầy đủ (input).
- Model phản hồi bằng một lệnh Edit (output). Claude Code áp dụng nó, thêm kết quả vào, và gửi lại toàn bộ. Vẫn tương tự như vậy: lệnh Edit và kết quả của nó là mới, mọi thứ phía trước là đọc từ cache (input).
- Mô hình chạy
npm test(output). Claude Code thêm output của test vào và gửi lại toàn bộ, với output của test là phần mới duy nhất (input). - Test pass, và mô hình phản hồi bằng một bản tóm tắt ngắn (output). Không có lệnh gọi tool nào nghĩa là không có gì để thêm vào và không có request 6, vậy là xong.
Đó là năm request cho một bản sửa lỗi nhỏ, và mỗi request trong số đó chứa toàn bộ cuộc hội thoại tính đến thời điểm đó. Một lượt request điển hình thường có sự chênh lệch như vậy: hàng chục nghìn token đi vào, vài trăm token đi ra. Nhưng chỉ phần mới trong lượt đó mới được tính với giá input thông thường, phần còn lại được tính rẻ hơn nhớ vào cache.
Đó là toàn bộ chi phí cho mỗi lượt: đọc từ cache cho phần lịch sử, giá input đầy đủ cho phần mới, và giá output cho phản hồi.
Cache phải khớp từ đầu request trở đi, và các request luôn được gửi theo cùng một thứ tự: định nghĩa tool, rồi đến system prompt, rồi đến cuộc hội thoại (với CLAUDE.md ở đầu). Nếu bất cứ điều gì trong phần đầu đó thay đổi, mọi thứ phía sau nó sẽ bị prefill lại. Một kết quả tool được thêm vào cuối cuộc hội thoại là trường hợp lý tưởng nhất, vì không có gì phía sau nó. Điều làm hỏng cache là bất cứ thứ gì thay đổi request ở gần phía đầu hơn, hoặc thay đổi thứ mà cache được đánh khoá (key) theo:
**/model**: mỗi model có cache riêng của nó, nên ở lượt tiếp theo toàn bộ cuộc hội thoại sẽ được prefill lại với giá đầy đủ. (Điều này bao gồm cả opusplan, vốn đổi model mỗi lần bạn vào/ra khỏi plan mode.)**/effort**: effort level cũng là một phần của thứ mà cache được đánh khoá theo, nên tương tự vậy. Đó là lý do cả/modelvà/effortđều yêu cầu bạn xác nhận khi đổi giữa chừng cuộc hội thoại.- Fast mode: cũng là một phần của khoá cache, và việc prefill lại diễn ra với giá của fast mode, nên nếu bạn định bật nó, hãy bật ngay từ đầu. (Tắt nó đi thì miễn phí, xét về mặt cache.)
**/compact**: cuộc hội thoại bị thay thế bằng một bản ngắn hơn, nên không có gì trong đó còn khớp nữa (system prompt phía trước nó vẫn còn nguyên). Việc viết bản tóm tắt tự nó rẻ miễn là cuộc hội thoại cũ vẫn còn trong cache, nên nó rẻ hơn nhiều nếu làm trước một kỳ nghỉ dài so với sau đó.- Thời gian: mỗi lượt đều reset lại đồng hồ, nhưng cache hết hạn sau một giờ trên gói subscription hoặc năm phút với API key (
ENABLE_PROMPT_CACHING_1H=1giúp kéo dài thành một giờ). Quay lại sau khoảng thời gian đó, lượt tiếp theo sẽ prefill lại toàn bộ cuộc hội thoại. Việc resume một phiên cũ hầu như luôn gặp tình trạng tương tự: cache thường đã mất vào lúc đó, và system prompt được xây dựng lại ngay khi khởi động.
Không phải điều này có nghĩa là bạn không bao giờ nên đổi model hay effort. Nó có nghĩa là có những thời điểm rẻ để làm việc đó - đầu phiên, hoặc ngay sau một lệnh /clear - và những thời điểm đắt đỏ - giữa một cuộc hội thoại dài.
Mẹo: nếu vài lượt gần nhất đi theo hướng bạn không muốn giữ lại, hãy /rewind về ngay trước chúng thay vì chạy /compact. Rewind chỉ cắt bỏ những lượt đó ở cuối, nên mọi thứ trước đó vẫn còn trong cache và không tốn phí gì. Compact thì viết lại toàn bộ cuộc hội thoại, nên nó luôn tốn phí.
Điều gì quyết định số lượng token một phiên gửi đi
Phần tiêu đề “Điều gì quyết định số lượng token một phiên gửi đi”Điều chính cần biết ở đây là không có gì chỉ được gửi một lần. Mọi thứ kết thúc trong cuộc hội thoại - một file Claude đọc hay output của một lệnh nó chạy - sẽ được gửi lại ở mỗi lượt sau đó, cho đến hết phiên làm việc.
Nó được cache, nên mỗi lần gửi lại đó rẻ, nhưng rẻ không có nghĩa là miễn phí, và nó còn chiếm chỗ trong ngữ cảnh (context) mà mô hình phải “nghĩ” xung quanh ở mỗi lượt.
Đó thực chất là toàn bộ mô hình chi phí của một phiên: có bao nhiêu token kết thúc trong context, chúng ở đó bao nhiêu lượt, và bạn đang chạy bao nhiêu context cùng lúc.
Điều gì kết thúc trong context
Phần tiêu đề “Điều gì kết thúc trong context”Một phần của những gì có trong context đã ở đó trước khi bạn gõ bất cứ điều gì: định nghĩa tool, system prompt, CLAUDE.md, và bất cứ thứ gì khác được nạp lúc khởi động.
Mẹo: chạy /context trong một phiên mới để xem có gì trong đó trước khi bạn gõ gì cả. Giữ CLAUDE.md chỉ chứa những chỉ dẫn cụ thể và chuyển các chỉ dẫn theo từng quy trình (workflow) sang skill, thứ chỉ được nạp khi được dùng đến. Nếu có một MCP server bạn không cần trong phiên này, hãy tắt nó bằng /mcp.
Gần như mọi thứ khác được thêm vào trong phiên đều là kết quả (tool results) của tool: các file Claude đọc, và output của các lệnh nó chạy.
Claude đọc bao nhiêu phần lớn phụ thuộc vào việc nó phải tự tìm ra bao nhiêu. Nếu bạn nói “các bài test đang fail”, trước tiên nó phải tìm ra là bài test nào: một hoặc hai lần grep, vài file được mở ra để xem cái nào liên quan, và tất cả các kết quả đó vẫn nằm trong context rất lâu sau khi chúng không còn hữu ích nữa.
“Sửa bài test đang fail trong utils.test.ts” bỏ qua bước tìm kiếm và chỉ tốn một lệnh gọi Read cho file đó, còn “Sửa bài test đang fail trong @utils.test.ts” thì thậm chí không tốn cả lệnh Read đó.

Mẹo: khi nhắc đến một file, hãy @-mention nó thay vì gõ đường dẫn. Claude Code đính kèm file vào tin nhắn của bạn trước khi bất cứ thứ gì được gửi đi, nên nó nằm ngay trong request đầu tiên và không cần lệnh gọi Read cho nó. Bản thân file vẫn chiếm cùng một lượng chỗ trong context dù theo cách nào, nên bạn chỉ cần nhắc đến nó một lần trong cuộc hội thoại: nó sẽ ở lại đó, và @-mention nó lại ở một lượt sau nhìn chung sẽ đính kèm thêm một bản sao thứ hai.
Điều khác lấp đầy context là output của các lệnh Claude chạy. Mỗi lần nó chạy bài test của bạn, một bản build, hay git log, bất cứ thứ gì được in ra đều được thêm vào cuộc hội thoại giống như một file nó đọc, và ở lại đó trong cùng số lượt.
Những output thực sự lớn thì thực ra lại ổn: sau 30.000 ký tự, Claude Code sẽ ghi output vào một file và chỉ đặt một bản xem trước ngắn cùng đường dẫn vào cuộc hội thoại (BASH_MAX_OUTPUT_LENGTH nếu bạn muốn thay đổi mức này).
Vấn đề là mọi thứ dưới ngưỡng đó. Một test runner in ra 400 bài test pass từng dòng một sẽ nằm dưới giới hạn, và 400 dòng đó giờ là một phần của mọi lượt còn lại. Claude thường sẽ tự xử lý việc này giúp bạn bằng các flag và tail, và nếu bạn không muốn để Claude tự quyết, có một hook nhỏ trong tài liệu giúp viết lại các lệnh gây nhiều output trước khi chúng chạy, để chỉ những dòng quan trọng mới quay trở lại.
Mẹo: đặt hai ba lệnh bạn chạy suốt cả ngày vào CLAUDE.md, kèm theo các flag làm giảm output, theo đúng cách bạn sẽ tự gõ chúng (“chạy một file test đơn lẻ bằng npx vitest run <file> --reporter=dot”). Đây là một bổ sung nhỏ, nhưng nó tiết kiệm một lượt và vài trăm dòng output trong mỗi phiên sau đó.
Nó ở lại đó bao nhiêu lượt
Phần tiêu đề “Nó ở lại đó bao nhiêu lượt”Một phiên dài tốn nhiều hơn cùng một khối lượng công việc trải ra trên vài phiên ngắn, và nhiều hơn bạn tưởng, vì lượt thứ 40 cũng phải đọc lại 39 lượt trước đó. Bạn muốn context trong phiên của mình ngắn gọn và liên quan, nên đừng mang context của tác vụ này sang tác vụ tiếp theo: /clear khi bạn bắt đầu một việc mới, và /compact khi phần đầu của cùng một tác vụ đã xong.

Mẹo: /rename trước khi /clear nếu sau này bạn sẽ muốn quay lại phiên đó. Khi bạn /compact, hãy nói cho nó biết cần giữ lại gì, hoặc đặt một mục “Compact instructions” trong CLAUDE.md nếu đó luôn là cùng một thứ. Và nếu bạn đang dùng model 1M và muốn có lại lưới an toàn auto-compact ở vị trí cũ của nó, /autocompact 200k sẽ đặt nó trở lại (cần Claude Code v2.1.221 trở lên).
Cũng nên để ý đến những lượt xảy ra khi bạn không gõ gì. Một /loop nổ ra như một lượt đầy đủ trong phiên bạn thiết lập nó, mang theo toàn bộ cuộc hội thoại đó mỗi lần, và nếu đã hơn một giờ kể từ lượt cuối, đó còn là một lần trượt cache (cache miss) nữa. Hãy bắt đầu một phiên mới ở một terminal khác và chạy loop từ đó.
Subagent
Phần tiêu đề “Subagent”Cách khác để giữ điều gì đó ngoài context của bạn là để nó xảy ra trong một context khác, và đó chính là mục đích của subagent. Một subagent có context window riêng của nó, với system prompt riêng, các tool, và CLAUDE.md của bạn, nhưng không có cuộc hội thoại của bạn. Nó chạy các lượt của riêng nó, và thứ duy nhất quay trở lại phiên chính là câu trả lời của nó. Mọi thứ khác đều bị vứt bỏ khi nó xong việc.
Nhược điểm của việc không có cuộc hội thoại của bạn là đôi khi subagent phải đọc lại những thứ mà phiên chính đã có sẵn, và nó phải trả tiền cho các lượt của riêng nó trong lúc làm việc đó. Với một việc nhỏ thì đó chỉ là overhead.
Nó đáng giá khi một công việc tạo ra nhiều output mà bạn không cần giữ lại, như việc đọc qua một log. Claude thường sẽ tự chọn dùng subagent cho loại việc đó, và bạn cũng có thể yêu cầu trực tiếp khi nó không tự làm (“đi qua log này trong một subagent”). Chỉ cần nhớ rằng phiên chính chỉ nhận lại những gì subagent chọn để báo cáo.

Mẹo: nếu có một công việc gây nhiều output mà bạn giao đi lặp đi lặp lại, hãy tạo cho nó một định nghĩa subagent riêng với model: haiku (hoặc sonnet). Nếu không nó sẽ chạy trên bất cứ model nào phiên chính của bạn đang dùng.
Nên để ý điều gì trước tiên
Phần tiêu đề “Nên để ý điều gì trước tiên”Trong tất cả những điều nói ở trên, có bốn thứ đáng để ý nhất, xếp theo thứ tự tốn kém giảm dần:
