Khi bạn dán cả một file log 5,000 dòng vào ChatGPT hoặc Claude và nhận lại câu trả lời hời hợt, chung chung, vấn đề không nằm ở "AI còn ngu". Vấn đề nằm ở cách bạn hiểu — hoặc không hiểu — về cách LLM (large language model) xử lý context. Với QA engineer, đây không phải kiến thức "cho vui" — nó quyết định việc bạn debug được một stack trace 3,000 dòng trong 2 phút, hay ngồi cãi với AI cả buổi vì nó "quên" mất yêu cầu bạn đưa ra ở đầu prompt.
Bài này đi vào nền tảng kỹ thuật: token là gì, context window hoạt động ra sao, AI thực sự nhận được gì khi bạn gửi một prompt, và cách áp dụng tất cả vào công việc phân tích test suite, log, trace ở quy mô thực tế.
Token Là Gì và Vì Sao Nó Quan Trọng Với QA Prompt?
Tokenization Cơ Bản
LLM không đọc chữ như con người. Nó đọc token (đơn vị) — những mảnh nhỏ của văn bản được cắt ra bởi một thuật toán tokenizer (bộ mã hóa từ). Một token có thể là một từ hoàn chỉnh ("test"), một phần của từ ("tion" trong "authentication"), một dấu câu, hoặc một khoảng trắng. Với tiếng Anh, quy tắc ước lượng kinh điển là 1 token ≈ 4 ký tự, hoặc ~0.75 từ/token (tức 100 từ ≈ 133 token).
Với tiếng Việt, tình hình phức tạp hơn nhiều. Vì các tokenizer hiện đại (BPE — Byte Pair Encoding, hoặc các biến thể của nó ở GPT/Claude) được huấn luyện chủ yếu trên dữ liệu tiếng Anh, một từ tiếng Việt có dấu (ví dụ "kiểm thử") thường bị cắt thành 2-4 token thay vì 1, vì mỗi ký tự có dấu (ư, ể, ậ...) chiếm nhiều byte UTF-8 hơn ký tự Latin thường. Kết quả: viết prompt tiếng Việt có thể tốn gấp 1.5-2 lần số token so với cùng nội dung viết bằng tiếng Anh. Đây là lý do nhiều QA lead khuyên viết prompt kỹ thuật bằng tiếng Anh dù team nói tiếng Việt — không phải vì "sang" mà vì tiết kiệm token thật.
Code cũng có đặc thù riêng: dấu ngoặc, dấu chấm phẩy, tên biến dài (getUserAuthenticationTokenFromRequestHeader) đều bị cắt thành nhiều token. Một đoạn code 50 dòng JavaScript thông thường rơi vào khoảng 400-700 token, tùy độ dài tên biến và mức độ nested.
Vì Sao QA Prompt "Ngốn" Token Nhiều
So với dev prompt thuần code, QA prompt có đặc điểm ngốn token hơn hẳn vì phải mang theo nhiều loại context cùng lúc: requirement/user story, code liên quan, test case cũ (để giữ style), log lỗi, stack trace, và đôi khi cả ảnh chụp màn hình (screenshot) được encode thành token hình ảnh riêng.
Ví dụ thực tế: một prompt yêu cầu AI "viết test case cho API thanh toán" mà làm đúng cách sẽ gồm: user story (~150 token), API spec dạng OpenAPI/Swagger snippet (~300-800 token tùy độ chi tiết), 2-3 test case cũ làm mẫu style (~400 token), và bug report liên quan trước đó (~200 token). Tổng đã hơn 1,000-1,500 token chỉ riêng phần input, chưa tính instruction và câu trả lời AI sinh ra. Nhân với việc bạn lặp lại quy trình này cho 20 API endpoint trong một sprint, con số cộng dồn không nhỏ.
Đây cũng là lý do QA prompt dễ "tràn" context window hơn dev prompt thông thường — dev có thể chỉ cần gửi 1 file code, còn QA thường phải gửi nhiều nguồn cùng lúc để AI hiểu đúng bức tranh toàn cảnh.
Token Budget Như Một Thói Quen QA Chuẩn
Coi token như một loại "ngân sách" (budget) bạn phải phân bổ có chủ đích, giống như time-boxing một buổi test session. Một cách phân bổ hợp lý cho prompt phân tích bug:
- 40% cho context (log, code, stack trace)
- 30% cho instruction rõ ràng (yêu cầu, ràng buộc, format output)
- 20% dự phòng cho AI "suy nghĩ" (đặc biệt với model có chain-of-thought — chuỗi suy luận từng bước)
- 10% cho ví dụ mẫu (few-shot example)
Khi bạn thấy mình dồn 90% ngân sách vào context và chỉ còn vài chục token cho instruction, đó là dấu hiệu cần cắt context, không phải viết instruction ngắn hơn.
Ước Lượng Token Thực Tế Không Cần Đếm
Bạn không cần công cụ đếm token chính xác trong lúc làm việc hàng ngày — biết ước lượng nhanh là đủ:
- Text tiếng Anh thường: số từ × 1.3 ≈ số token
- Text tiếng Việt: số từ × 2 đến × 2.5 ≈ số token (do vấn đề dấu đã nói ở trên)
- Code: số dòng × 10-15 ≈ số token (tùy ngôn ngữ, Python thường ít token/dòng hơn Java do cú pháp gọn)
- Log file thô: mỗi dòng log timestamp + message trung bình 15-25 token
Công cụ thực tế nên dùng khi cần chính xác: trang tokenizer công khai của OpenAI (platform.openai.com/tokenizer) cho ước lượng nhanh gần đúng với hầu hết model hiện đại, hoặc dùng lệnh wc -w rồi nhân hệ số ước lượng trên khi cần check nhanh trong terminal.
wc -w server.log | awk '{print $1, "words =~", int($1*1.3), "tokens"}'
Mẹo: Trước khi dán bất cứ thứ gì dài vào AI, chạy wc -l và wc -w trên file đó trước. Nếu số từ vượt quá 3,000-4,000 (~4,000-5,000 token), đừng dán nguyên file — hãy tự hỏi "AI cần đọc toàn bộ hay chỉ cần phần liên quan đến lỗi?" trước khi paste.
Context Window Hoạt Động Ra Sao và Điều Gì Xảy Ra Khi Input Quá Lớn?
Kích Thước Context Window Của Các Model Hiện Nay
Context window là "trí nhớ làm việc" tối đa mà model có thể xử lý trong một lượt — bao gồm cả input bạn gửi VÀ output nó sinh ra. Tính đến 2025-2026, các mốc phổ biến:
- Claude (Anthropic): 200,000 token cho bản tiêu chuẩn, một số cấu hình/gói doanh nghiệp hỗ trợ tới 1 triệu token.
- GPT-4/GPT-5 class (OpenAI): 128,000-400,000 token tùy phiên bản.
- Gemini (Google): 1-2 triệu token ở các bản cao cấp — hiện là nhóm dẫn đầu về kích thước context window thô.
- Model mã nguồn mở (Llama, Qwen, v.v.): dao động 32,000-128,000 token tùy phiên bản.
Nghe thì 200,000 token có vẻ "vô hạn", nhưng quy đổi ra thực tế: 200,000 token ≈ 150,000 từ tiếng Anh ≈ khoảng 500-600 trang sách in, hoặc ước chừng 4,000-6,000 dòng code trung bình. Nghe vẫn nhiều — nhưng một hệ thống microservice có vài chục file, cộng thêm log, cộng thêm lịch sử trò chuyện trong một session agent kéo dài, có thể ăn hết con số này nhanh hơn bạn nghĩ.
Context Window Thực Sự Chứa Gì
Đây là điểm nhiều người hiểu sai: context window KHÔNG chỉ chứa prompt bạn gõ. Nó là tổng của:
1. System prompt — chỉ dẫn nền do platform/tool cấu hình sẵn (bạn thường không thấy, nhưng nó chiếm token)
2. Toàn bộ lịch sử hội thoại trước đó trong session (mọi câu hỏi + câu trả lời cũ)
3. Nội dung bạn dán/upload (code, log, ảnh, file đính kèm)
4. Kết quả gọi tool (nếu bạn dùng agent có thể chạy lệnh, đọc file — output của các lệnh đó cũng ngốn context)
5. Câu trả lời sắp được sinh ra — model phải "để chỗ" cho phần output
Với các coding agent (như Claude Code, Cursor, Windsurf), điểm 4 thường là "kẻ ngốn context giấu mặt" lớn nhất — mỗi lần agent đọc một file, chạy grep, hay xem output test, toàn bộ nội dung đó cộng vào context window dù bạn không chủ động gõ nó.
Điều Gì Xảy Ra Khi Vượt Quá Context Window
Khi tổng token vượt giới hạn cứng, có ba kiểu xử lý tùy hệ thống:
- Lỗi cứng (hard error): API trả lỗi "context length exceeded", request bị từ chối hoàn toàn — thường gặp khi gọi API trực tiếp.
- Tự động cắt (auto-truncation): một số tool/UI tự cắt bớt phần đầu của lịch sử hội thoại để "nhường chỗ" — nguy hiểm vì bạn không luôn biết phần nào bị cắt.
- Tóm tắt ngầm (silent summarization): một số agent framework tự tóm tắt các lượt hội thoại cũ thành bản ngắn hơn khi gần đầy — thông tin chi tiết (số liệu cụ thể, đoạn code chính xác) dễ bị mất trong quá trình này.
Suy Giảm Từ Từ Trước Khi Đụng Giới Hạn Cứng
Đây là điều quan trọng hơn cả giới hạn cứng: chất lượng output suy giảm dần trước khi bạn chạm giới hạn token tối đa. Hiện tượng này gọi là "lost in the middle" (lạc mất ở giữa) — các nghiên cứu về LLM cho thấy model có xu hướng chú ý tốt nhất vào phần đầu và phần cuối của context, còn thông tin nằm ở giữa một context rất dài dễ bị "lướt qua" hoặc trộn lẫn.
Biểu hiện thực tế trong công việc QA: bạn dán một file log 8,000 dòng, yêu cầu AI tìm tất cả lỗi liên quan đến timeout. AI trả lời đúng các lỗi ở đầu và cuối file log, nhưng bỏ sót gần hết lỗi timeout nằm ở khoảng dòng 3,000-5,000 — không phải vì vượt giới hạn token, mà vì hiện tượng suy giảm chú ý (attention decay) khi context quá dài, dù vẫn nằm trong hạn mức cho phép.
Quản Lý Ngân Sách Context Window Trong Session Agent Dài
Khi làm việc với coding agent qua nhiều lượt (ví dụ một session Claude Code kéo dài cả giờ để debug một feature), context window tích lũy dần theo mỗi lượt. Vài nguyên tắc quản lý:
- Chủ động "dọn" context: nếu tool hỗ trợ lệnh reset/clear (như
/cleartrong Claude Code), dùng nó giữa các task không liên quan để tránh mang theo "rác" từ task trước. - Tóm tắt trước khi chuyển task: yêu cầu AI tự tóm tắt trạng thái hiện tại thành vài dòng trước khi bạn chuyển sang vấn đề mới, rồi bắt đầu session mới với bản tóm tắt đó — hiệu quả hơn giữ nguyên toàn bộ lịch sử.
- Theo dõi dấu hiệu cảnh báo: khi AI bắt đầu lặp lại câu trả lời, quên chi tiết bạn vừa nói, hoặc trả lời chậm bất thường (với UI có hiển thị % context đã dùng), đó là lúc nên bắt đầu session mới.
Mẹo: Đừng đợi đến khi AI "quên" mới nhận ra context đã đầy. Với các tool hiển thị % context window đã dùng (Claude Code hiển thị con số này ở status bar), hãy coi mốc 70-80% là "đèn vàng" — chủ động tóm tắt và làm mới session trước khi chạm mốc đó, đừng đợi tới 100%.
AI Thực Sự Thấy Gì So Với Điều Bạn Nghĩ Bạn Đã Gửi?
Pipeline Xử Lý
Từ lúc bạn nhấn Enter đến lúc model sinh câu trả lời, dữ liệu đi qua nhiều lớp biến đổi mà bạn không nhìn thấy trực tiếp:
- Tiền xử lý (preprocessing): input của bạn được ghép với system prompt, lịch sử hội thoại, và metadata (timestamp, user role) thành một chuỗi duy nhất.
- Tokenization: toàn bộ chuỗi đó được cắt thành token theo bộ tokenizer riêng của model.
- Chèn thêm bởi tool/platform: nếu bạn dùng qua một IDE plugin hay agent framework, framework đó thường tự chèn thêm hướng dẫn định dạng, quy tắc an toàn, hoặc kết quả từ các lệnh nó vừa chạy — TẤT CẢ nằm trước hoặc sau nội dung bạn gõ.
- Suy luận (inference): model xử lý toàn bộ chuỗi token đã ghép, không phân biệt "đây là phần tôi gõ" hay "đây là phần hệ thống chèn" — với model, tất cả chỉ là một dòng token liên tục.
- Sinh output: model sinh token kế tiếp lần lượt, dựa trên xác suất, không "đọc lại" toàn bộ input mỗi lần sinh 1 token (dù về mặt cơ chế attention, nó vẫn tham chiếu ngược context — chỉ là không đơn giản như "đọc lại từ đầu" theo nghĩa tuyến tính con người hiểu).
Chèn Ngầm Vào Context
Đây là phần ít người để ý: hầu hết công cụ AI thương mại (ChatGPT, Claude.ai, Copilot, các coding agent) đều chèn thêm nội dung vào context của bạn mà bạn không thấy trực tiếp:
- System prompt ẩn quy định giọng văn, độ dài, các chủ đề cấm.
- Custom instructions bạn từng cấu hình trong settings (nếu có) — được chèn lại vào MỌI request, âm thầm ngốn token.
- Metadata file khi bạn upload file — tên file, loại file, kích thước cũng thành token.
- Với coding agent: system reminders, quy tắc project (như file CLAUDE.md/AGENTS.md), và cấu trúc project được quét tự động — đều được chèn vào context trước khi model thấy câu hỏi thật của bạn.
Hệ quả với QA: nếu bạn dùng một coding agent đã được cấu hình sẵn nhiều custom instruction, ngân sách context "thực dùng được" cho log/code của bạn có thể ít hơn nhiều so với giới hạn model công bố.
Cái Gì Bị Cắt Hoặc Bị Bỏ Qua
Khi context căng, không phải mọi phần đều bị đối xử công bằng. Các phần dễ bị cắt/bỏ qua nhất:
- Phần giữa của tài liệu dài (như đã nói ở "lost in the middle")
- Comment trong code — nhiều tokenizer/model có xu hướng "lướt" comment khi phải tổng hợp thông tin dưới sức ép token, trừ khi bạn yêu cầu rõ ràng phải đọc comment.
- Định dạng phức tạp (bảng markdown lồng nhau, JSON lồng sâu nhiều cấp) — model dễ đọc sai cấu trúc khi độ lồng ghép quá sâu.
- Whitespace và indentation tinh vi — với code Python (nơi indentation mang ý nghĩa cú pháp), model đôi khi "chuẩn hóa" indentation trong đầu và bỏ sót lỗi thụt dòng thực tế trong code gốc.
Kiểm Tra Điều Model Thực Sự Nhận Được
Cách thực tế để kiểm tra:
- Yêu cầu AI lặp lại/tóm tắt phần bạn vừa gửi trước khi nó xử lý tiếp — "Trước khi trả lời, hãy tóm tắt lại 3 điều quan trọng nhất trong đoạn log tôi vừa gửi." Nếu bản tóm tắt sai hoặc thiếu, bạn biết ngay phần nào bị "rớt".
- Dùng API trực tiếp (thay vì UI) khi cần độ chính xác cao — API cho phép bạn kiểm soát chính xác từng phần được gửi, không bị system prompt của UI xen vào.
- Với coding agent có log/trace mode (một số IDE cho xem "raw context" gửi đi), tận dụng để audit định kỳ.
Những Sai Lệch Thường Gặp và Cách Bắt Lỗi
- AI trả lời dựa trên phiên bản code cũ dù bạn đã paste bản mới — do bạn dán code mới vào GIỮA cuộc hội thoại dài, và model vẫn còn "neo" vào bản đầu tiên bạn gửi cách đó nhiều lượt. → Cách bắt: luôn hỏi lại "Bạn đang dựa trên phiên bản code nào tôi gửi — bản lúc đầu hay bản tôi vừa update?"
- AI "bịa" chi tiết không có trong log bạn gửi (hallucination) — thường do log bị cắt và model tự lấp khoảng trống bằng suy đoán hợp lý về mặt ngôn ngữ nhưng sai về sự kiện thực tế. → Cách bắt: yêu cầu AI trích dẫn (quote) chính xác dòng log làm căn cứ cho mỗi kết luận.
- AI bỏ sót yêu cầu ràng buộc bạn đặt ở đầu prompt dài — do "lost in the middle" hoặc do ràng buộc bị chôn dưới quá nhiều context. → Cách bắt: đặt ràng buộc quan trọng nhất ở CUỐI prompt (gần chỗ AI sắp sinh câu trả lời), không chỉ ở đầu.
Mẹo: Khi nghi ngờ AI "quên" hoặc hiểu sai, đừng sửa prompt ngay — hãy hỏi thẳng "Bạn đang dựa vào phần nào trong context tôi gửi để đưa ra kết luận này?" Câu trả lời của AI thường lộ rõ ngay phần context nào đã bị bỏ qua hoặc hiểu sai, giúp bạn sửa đúng chỗ thay vì đoán mò.
Kích Thước Context Window Ảnh Hưởng Thế Nào Đến Việc Phân Tích Test Suite và Log?
Phân Tích Test Suite Ở Quy Mô Lớn
Một test suite thực tế của dự án production trung bình có thể lên tới 500-2,000 test case trải trên hàng chục file. Dán toàn bộ suite vào một prompt là bất khả thi và cũng không cần thiết — không phải vì vượt giới hạn token tuyệt đối (200K token có thể chứa được), mà vì:
1. Chi phí (cost) tăng tuyến tính theo số token — phân tích lại toàn bộ suite mỗi lần hỏi một câu nhỏ là lãng phí.
2. Chất lượng suy giảm do "lost in the middle" khi suite quá lớn.
3. Latency (độ trễ) tăng đáng kể khi input dài.
Chiến lược thực tế: phân tầng theo phạm vi (scope). Khi cần review coverage cho một module, chỉ gửi các test file thuộc module đó (thường 5-15 file, vài trăm đến 1,500 token/file) cộng với danh sách tên các test case ở module khác (chỉ tên, không cần nội dung đầy đủ) để AI biết bối cảnh rộng hơn mà không phải đọc chi tiết.
grep -rEn "^\s*(describe|it|test)\(" src/payment/ --include="*.test.js"
Lệnh trên cho ra một bản "mục lục" test case cực ngắn — dùng làm phần "bối cảnh rộng" trong prompt, giữ cho phần cần đọc chi tiết (module đang review) không bị pha loãng.
Phân Tích Log và Trace Ở Quy Mô Lớn
Log file production hoặc log CI/CD thường dài hàng nghìn đến hàng chục nghìn dòng, trong đó phần liên quan đến lỗi thực tế chỉ chiếm một tỉ lệ nhỏ. Dán nguyên file log là cách chắc chắn kích hoạt "lost in the middle" và lãng phí token cho những dòng INFO/DEBUG vô nghĩa với việc debug.
Chiến lược đúng: trích xuất context xung quanh điểm lỗi, không gửi toàn bộ. Dưới đây là hai ví dụ cụ thể.
Trích các lỗi và context xung quanh từ Jest log:
grep -A 15 "✕\|FAIL" jest-output.log > failures-with-context.txt
awk '/FAIL/{flag=1} /^$/{if(flag)flag=0} flag' jest-output.log > failure-blocks.txt
Trích các dòng xung quanh mỗi ERROR trong server log:
grep -B 5 -A 20 "ERROR" server.log > error-context.txt
grep -B 5 -A 20 "ERROR.*PAYMENT_TIMEOUT" server.log > payment-timeout-context.txt
awk '$0 >= "2026-07-09T14:00:00" && $0 <= "2026-07-09T14:30:00"' server.log | grep -B 5 -A 20 "ERROR"
Với những file log khổng lồ (hàng trăm MB), kết hợp thêm wc -l để biết quy mô trước, và luôn ưu tiên lọc theo khoảng thời gian hoặc mã lỗi cụ thể trước khi đưa vào AI — gửi 200 dòng context đã lọc kỹ luôn hiệu quả hơn gửi 20,000 dòng thô.
Chọn Đúng Kích Thước Context Cho Từng Task
Nguyên tắc chung: kích thước context nên tương ứng với độ đặc thù của câu hỏi, không phải với "cho càng nhiều AI càng thông minh". Vài mốc tham khảo:
| Loại task | Context nên gửi |
|---|---|
| Debug 1 lỗi cụ thể | Chỉ đoạn log/stack trace liên quan (50-300 dòng) + code file liên quan trực tiếp |
| Review coverage 1 module | Test file của module + mục lục test toàn hệ thống |
| Phân tích xu hướng lỗi flaky test theo thời gian | Log đã được tiền xử lý/tổng hợp (aggregate) qua script, không phải log thô |
| Đánh giá tác động thay đổi code (impact analysis) | Diff (patch) cụ thể + test file bị ảnh hưởng, không phải toàn bộ codebase |
Mẹo: Với mọi tác vụ phân tích log/test ở quy mô lớn, luôn viết một bước "tiền xử lý bằng script" (grep/awk/jq) TRƯỚC khi đưa vào AI. Nguyên tắc: script làm việc lọc-thô-thành-tinh, AI làm việc suy luận-trên-dữ-liệu-đã-tinh — đừng bắt AI làm cả hai, vì phần lọc thô chính là nơi ngốn token và gây suy giảm chất lượng nhiều nhất.