· ai-tools / llm / context-engineering
Context engineering năm 2026 — sáu pattern thực sự hiệu quả
Context engineering quyết định model nhìn thấy gì khi inference. Sáu pattern kèm code: ordering, caching, compaction, sub-agent isolation, và nhiều hơn nữa.
Bởi Ethan
2.844 từ · 15 phút đọc
Context engineering quan trọng hơn prompt engineering. Những từ bạn chọn có ảnh hưởng, nhưng thứ model được tiếp cận — và theo thứ tự nào — mới là yếu tố quyết định liệu nó có hoàn thành được task hay không. Sáu pattern dưới đây bao phủ phần lớn failure mode trong hệ thống LLM production: context rot, position effects, chi phí token dư thừa, overflow trong hội thoại dài, bộ nhớ orchestrator không giới hạn, và retrieval kém hiệu quả lúc khởi tạo. Bài viết này trình bày cả sáu pattern với code thực tế.
Bài viết này dành cho ai
Các developer đang xây dựng hoặc vận hành hệ thống dựa trên LLM và đang đụng trần về chất lượng hoặc chi phí. Nếu bạn còn đang thử nghiệm với chat prompt cơ bản, phần nền tảng sẽ hữu ích. Nếu bạn đang chạy agent trong production, bỏ qua thẳng đến phần pattern.
Context engineering thực sự là gì
Andrej Karpathy định nghĩa nó vào tháng 6 năm 2025: “the delicate art and science of filling the context window with just the right information for the next step.” CEO Shopify Tobi Lutke đưa ra phiên bản dành cho người thực hành: “the art of providing all the context for the task to be plausibly solvable by the LLM.”
Anthropic chính thức hóa thuật ngữ này trong một bài đăng engineering tháng 9 năm 2025: “the set of strategies for curating and maintaining the optimal set of tokens (information) during LLM inference.”
Sự phân biệt với prompt engineering là quan trọng. Prompt engineering là về cách bạn diễn đạt một request. Context engineering là về thông tin nào model được tiếp cận khi xử lý request đó — các tài liệu, lịch sử hội thoại, tools, facts đã truy xuất, ghi chú của agent. Diễn đạt hoàn hảo trên một context sai sẽ không cứu được bạn.
Context rot: tại sao nhiều không phải là tốt hơn
Cơ chế attention tính toán mọi token với mọi token khác. Khi độ dài context tăng, tín hiệu hữu ích bị loãng dần. Anthropic gọi sự suy giảm chất lượng này là “context rot.”
Nền tảng thực nghiệm đến từ Liu et al. (2023, “Lost in the Middle: How Language Models Use Long Contexts”). Khi kiểm tra multi-document QA và key-value retrieval trên các model có context window 4K–32K token, họ phát hiện ra đường cong hiệu suất hình chữ U: recall cao nhất khi thông tin liên quan xuất hiện ở đầu hoặc cuối context window, và giảm đáng kể ở phần giữa. Các model thực sự đọc qua tất cả tài liệu — chúng chỉ chú ý ít hơn đến phần ở giữa.
Tài liệu Claude context của Anthropic nêu rõ mục tiêu: “the smallest possible set of high-signal tokens.” Thêm context để bù đắp cho retrieval yếu hoặc thiếu summarization chỉ làm vấn đề trở nên tệ hơn.
Các model long-context hiện đại (Claude Opus 4.8 và Fable 5 hỗ trợ đến 1M token) không loại bỏ context rot; chúng chỉ nâng ngưỡng để context rot bắt đầu xảy ra muộn hơn. Kỷ luật quản lý những gì đưa vào context vẫn không thể bỏ qua.
Nguyên tắc vị trí: đặt query ở cuối
Kiểm tra nội bộ của Anthropic cho thấy đặt query sau các tài liệu dài cải thiện chất lượng phản hồi lên đến 30% trong các task multi-document. Đường cong attention hình chữ U giải thích tại sao: thông tin ở đầu và cuối được chú ý nhiều nhất. Nếu instruction của bạn ở trên cùng và tài liệu 50 trang theo sau, query ở vị trí được chú ý nhiều nhưng tài liệu thì không. Hãy đảo ngược lại.
import anthropic
client = anthropic.Anthropic()
# Tài liệu ở trên, query ở dưới cùng
response = client.messages.create(
model="claude-sonnet-4-6",
max_tokens=1024,
messages=[
{
"role": "user",
"content": """<documents>
<document index="1">
<document_content>
[Your 50-page reference document here]
</document_content>
</document>
<document index="2">
<document_content>
[Second reference document here]
</document_content>
</document>
</documents>
Based on the documents above, which sections describe the liability conditions?""",
}
],
)
print(response.content[0].text)
Các XML tag (<documents>, <document index="n">, <document_content>) phân tách các loại nội dung để model không xử lý đoạn text truy xuất như là một phần của instruction. Query đặt sau cùng, sau tất cả tài liệu.
Điều này đảo ngược thói quen thông thường là viết instruction trước rồi mới đến context. Cả hai đầu vào đều nằm trong context window — sự khác biệt chỉ là về vị trí.
Prompt caching: biến context thành đòn bẩy chi phí
Context lặp đi lặp lại — một system prompt lớn, một tài liệu tham khảo, một bộ few-shot example — tốn chi phí như nhau mỗi request trừ khi bạn cache lại. Với cache_control, Anthropic API lưu trữ biểu diễn tensor key-value của một prefix. Cache read tốn 0.10× giá input token thông thường; cache write tốn 1.25×. Với các workload có static prefix vượt vài nghìn token và bạn thực hiện nhiều lần gọi mỗi session, caching nhanh chóng có lợi.
import anthropic
client = anthropic.Anthropic()
LARGE_SYSTEM_PROMPT = """You are an expert analyzing legal contracts.
[... your 20,000-token reference document here ...]
"""
# Request đầu tiên — ghi cache (trả 1.25× cơ bản cho token được cache)
response1 = client.messages.create(
model="claude-sonnet-4-6",
max_tokens=1024,
system=[
{"type": "text", "text": "You are a contract analyst."},
{
"type": "text",
"text": LARGE_SYSTEM_PROMPT,
"cache_control": {"type": "ephemeral"}, # cache breakpoint
},
],
messages=[{"role": "user", "content": "Summarize the termination clauses."}],
)
print("Cache write tokens:", response1.usage.cache_creation_input_tokens)
print("Cache read tokens:", response1.usage.cache_read_input_tokens) # 0 ở lần gọi đầu
# Request tiếp theo (trong vòng 5 phút) — đọc cache (trả 0.10× cơ bản)
response2 = client.messages.create(
model="claude-sonnet-4-6",
max_tokens=1024,
system=[
{"type": "text", "text": "You are a contract analyst."},
{
"type": "text",
"text": LARGE_SYSTEM_PROMPT, # phải khớp byte-cho-byte
"cache_control": {"type": "ephemeral"},
},
],
messages=[{"role": "user", "content": "List the indemnification provisions."}],
)
print("Cache read tokens:", response2.usage.cache_read_input_tokens) # > 0 khi cache hit
Điều gì phá vỡ caching: bất kỳ thay đổi byte nào trong prefix — timestamp nhúng trong system prompt, per-request user ID đặt trước breakpoint, một khoảng trắng thừa thay đổi theo lần gọi. Kiểm tra kỹ code xây dựng prompt của bạn trước khi giả định prefix đã ổn định. Các request đầu tiên đồng thời đều miss cache; hãy khởi động bằng một lần gọi tuần tự trước khi mở rộng quy mô.
TTL mặc định là 5 phút; TTL 1 giờ có sẵn với giá 2× giá input cơ bản. TTL 5 phút mặc định được reset mỗi lần cache hit, nên các session đang hoạt động giữ cache warm mà không tốn thêm chi phí.
Để so sánh chi tiết hơn về caching giữa Anthropic, OpenAI, và Gemini, xem prompt caching năm 2026.
Sáu pattern để quản lý context
1. Compaction
Khi số lượng token trong một session tiến gần đến giới hạn của model, hãy tóm tắt lịch sử và khởi tạo lại với bản tóm tắt đó làm context mới. Model mất khả năng nhớ từng chữ nhưng vẫn giữ được sự liên tục về ngữ nghĩa.
import anthropic
client = anthropic.Anthropic()
def summarize_conversation(messages: list[dict]) -> str:
summary_prompt = f"""Summarize the following conversation, preserving all decisions,
findings, and open questions. Be precise — this summary becomes the only record.
{messages}"""
response = client.messages.create(
model="claude-sonnet-4-6",
max_tokens=2048,
messages=[{"role": "user", "content": summary_prompt}],
)
return response.content[0].text
def manage_context(messages: list[dict], token_threshold: int = 80000) -> list[dict]:
# Ước tính thô: 1 token ≈ 4 ký tự
approx_tokens = sum(len(str(m)) // 4 for m in messages)
if approx_tokens > token_threshold:
summary = summarize_conversation(messages[:-4]) # giữ lại 2 lượt cuối nguyên vẹn
return [
{"role": "user", "content": f"[Previous conversation summary]\n{summary}"},
{"role": "assistant", "content": "Understood. Continuing from where we left off."},
] + messages[-4:]
return messages
# Dùng trong vòng lặp multi-turn
conversation = []
while True:
user_input = input("You: ")
if user_input.lower() == "quit":
break
conversation.append({"role": "user", "content": user_input})
conversation = manage_context(conversation)
response = client.messages.create(
model="claude-sonnet-4-6",
max_tokens=1024,
messages=conversation,
)
assistant_msg = response.content[0].text
conversation.append({"role": "assistant", "content": assistant_msg})
print(f"Assistant: {assistant_msg}")
Điểm yếu: Summarization làm mất thông tin. Nếu hội thoại chứa một con số cụ thể, một câu trích dẫn, hoặc một quyết định sẽ quan trọng ở bước sau, bản tóm tắt có thể bỏ qua. Hoặc giữ lại các lượt gần đây nguyên vẹn (như ví dụ đã làm với messages[-4:]), hoặc viết các bản tóm tắt có cấu trúc tường minh bảo toàn các quyết định và câu hỏi còn mở.
2. Bộ nhớ ngoài có cấu trúc
Với các task kéo dài qua nhiều lần reset context — dự án nhiều ngày, agent chạy liên tục — hãy dùng một file như bộ nhớ bền vững. Ghi phát hiện vào đó, khởi tạo lại context từ file, và tiếp tục.
Pattern mà chính agent framework của Anthropic sử dụng: một file NOTES.md mà agent đọc lúc bắt đầu mỗi context window và cập nhật lúc kết thúc. Khi reset, context mới bắt đầu từ NOTES.md thay vì từ trống.
Format quan trọng. Một file đầy văn xuôi rất khó để truy vấn. Một file với các entry có ngày tháng và phân loại (## Decision: 2026-06-10: chọn Postgres thay vì SQLite vì...) cho phép bạn hoặc model tìm lại quyết định trước đó mà không cần đọc toàn bộ file.
3. Sub-agent isolation
Context của orchestrator là tài nguyên đắt giá nhất trong hệ thống multi-agent. Mỗi lần gọi sub-agent trả về một dump 10,000 token đều cộng vào tổng mà orchestrator phải mang theo. Sub-agent isolation kiểm soát chi phí đó: sub-agent nhận một context mới và hẹp; nó trả về một bản tóm tắt ngắn gọn; orchestrator chỉ thêm bản tóm tắt đó.
import anthropic
client = anthropic.Anthropic()
def run_sub_agent(task: str, context: str) -> str:
"""Sub-agent có context riêng. Trả về bản tóm tắt ngắn gọn."""
response = client.messages.create(
model="claude-sonnet-4-6",
max_tokens=512,
system="You are a research assistant. Return a concise summary of your findings — 200 words max.",
messages=[
{
"role": "user",
"content": f"Task: {task}\n\nAvailable context:\n{context}",
}
],
)
return response.content[0].text
# Orchestrator duy trì context gọn nhẹ
orchestrator_context = []
# Ủy thác nghiên cứu; sub-agent nhận context cụ thể, không phải toàn bộ lịch sử hội thoại
research_summary = run_sub_agent(
task="Find all references to rate-limiting in the provided API spec",
context="[Paste the relevant API spec section here — not the full conversation history]",
)
# Orchestrator chỉ thêm bản tóm tắt 200 từ
orchestrator_context.append({
"role": "user",
"content": f"Research findings on rate-limiting:\n{research_summary}",
})
# Tiếp tục công việc orchestrator với context chỉ tăng thêm ~200 token, không phải ~10,000
response = client.messages.create(
model="claude-sonnet-4-6",
max_tokens=1024,
system="You are an API integration architect.",
messages=orchestrator_context + [
{"role": "user", "content": "Based on the findings, what retry strategy should we implement?"}
],
)
print(response.content[0].text)
Điểm yếu: Bản tóm tắt của sub-agent mất chi tiết. Nếu sau này orchestrator cần các rate-limit header nguyên văn hoặc mã lỗi chính xác, bản tóm tắt 200 từ sẽ không có chúng. Quyết định trước những gì orchestrator sẽ cần và yêu cầu tường minh trong task của sub-agent.
Để xem cách triển khai đầy đủ bằng TypeScript với tools và memory, xem cách build AI agent bằng TypeScript — tools, memory, MCP.
4. Just-in-time retrieval
Tải một manual 500 trang vào context ngay từ đầu mỗi hội thoại tốn token dù hội thoại có cần đến nó hay không. JIT retrieval tải thông tin qua tools vào đúng lúc nó trở nên cần thiết.
Kinh nghiệm chung: đưa cho model một tool tìm kiếm (get_manual_section(query: str)) thay vì toàn bộ manual. Với hầu hết câu hỏi, model gọi tool một lần và truy xuất phần liên quan. Toàn bộ tài liệu không bao giờ vào context. Với các hệ thống dựa trên RAG, đây là cơ chế hoạt động; kỷ luật context engineering nằm ở chỗ quyết định cái gì cần pre-load so với cái gì cần truy xuất theo yêu cầu.
Khi nào nên pre-load: thông tin model gần như chắc chắn sẽ cần (cấu hình, user profile, task hiện tại). Khi nào nên truy xuất theo yêu cầu: tài liệu tham khảo, documentation, hồ sơ lịch sử.
5. Sliding window
Với các hội thoại streaming khi tính gần đây quan trọng hơn lịch sử, giữ lại k cặp message cuối trong context và bỏ phần còn lại.
Pattern này tương đương ConversationBufferWindowMemory từ LangChain 0.0.x (đã deprecated trong v0.3) và tương đương với việc duy trì một messages deque có giới hạn trong code của bạn. Đánh đổi: model mất nhận thức về các quyết định trước cửa sổ. Dùng compaction (pattern 1) nếu bạn cần liên tục ngữ nghĩa; dùng sliding window nếu bạn cần tính gần đây và có thể chấp nhận việc quên những gì đã qua.
6. Summarization middleware
Thay vì compaction khi overflow, chạy một background summarizer ở một ngưỡng token có thể cấu hình — SummarizationMiddleware của LangChain nhận tham số trigger={"tokens": N}; khi hội thoại vượt quá ngưỡng đó, middleware tự động tóm tắt các message cũ hơn (có thể cấu hình qua keep={"messages": N} để giữ bao nhiêu lượt gần đây nguyên vẹn). Middleware xử lý việc thay thế mà không cần bạn can thiệp vào vòng lặp hội thoại.
Lợi thế so với compaction thủ công: ngưỡng đã tính đến model (nó biết khi nào cần kích hoạt, không phải bạn), và bản tóm tắt được thêm vào như một system note thay vì được chèn vào như một fake user message. Bất lợi: bạn mất quyền kiểm soát những gì bản tóm tắt giữ lại.
RAG chỉ là một cơ chế, không phải toàn bộ bộ môn
Retrieval-augmented generation (RAG) là kỹ thuật để điền vào context lúc runtime — lấy các tài liệu liên quan từ một vector store và đưa vào prompt. Đây là cách triển khai tốt của JIT retrieval (pattern 4 ở trên), nhưng nó chỉ xử lý một chiều của context engineering.
Context engineering còn bao gồm: thiết kế system prompt, cắt gọn tool output, tỉa hội thoại, chuyển state trong multi-agent, chiến lược caching, và thứ tự context. Một RAG pipeline nhét 20 chunk không liên quan vào giữa context window đang vi phạm ba pattern trên cùng một lúc.
Sự nhầm lẫn này phổ biến vì RAG là nơi hầu hết team chạm trần context đầu tiên. Trần đó là vấn đề context engineering; RAG là một trong nhiều giải pháp.
Những gì cần theo dõi trong production
Các metric về cache và context cho biết các pattern này có đang hoạt động hay không:
- Cache hit rate:
usage.cache_read_input_tokens / (usage.cache_read_input_tokens + usage.cache_creation_input_tokens)mỗi request. Dưới 60% với các prompt bạn kỳ vọng ổn định nghĩa là có gì đó đang phá vỡ cache key. - Context utilization: số token context bạn thực sự gửi đi so với giới hạn của model. Tỷ lệ cao không phải vấn đề trừ khi chất lượng đang suy giảm; đó là tín hiệu để xem xét compaction.
- Vị trí ở giữa context: nếu hệ thống retrieval của bạn đang đặt chunk liên quan nhất ở vị trí 50 trong tổng số 100, nó đang ở vùng được chú ý ít nhất. Sắp xếp các chunk đã truy xuất với chunk liên quan nhất ở đầu hoặc cuối.
Các công cụ observability như LangSmith hiển thị các metric này theo session mà không cần instrumentation thủ công. Để phân bổ chi phí theo các pattern context, xem chi phí thực của việc vận hành AI agent team năm 2026. Để tối ưu chi phí ở tầng chọn model, xem LLM cost routing: khi nào Haiku hiệu quả hơn Opus.
Kết luận
Context engineering là kỹ thuật phân biệt các LLM prototype đang chạy với các hệ thống production thực sự đáng tin cậy. Sáu pattern này không phải các tính năng độc lập để thêm từng cái một — chúng kết hợp với nhau. Một production agent thường cần sub-agent isolation (3) để giữ orchestrator gọn nhẹ, JIT retrieval (4) để tránh pre-load mọi thứ, compaction (1) cho các session dài, và caching để kiểm soát chi phí. Nguyên tắc vị trí và XML structuring là cải tiến ít tốn công có thể áp dụng ngay cho các prompt hiện có.
Tài liệu Anthropic API trình bày giới hạn context window hiện tại, cú pháp cache_control, và các benchmark MRCR/GraphWalks mà Anthropic dùng nội bộ để đo lường chất lượng long-context recall.
Nguồn tham khảo
- Karpathy về context engineering: x.com/karpathy/status/1937902205765607626
- Simon Willison về nguồn gốc thuật ngữ: simonwillison.net/2025/Jun/27/context-engineering/
- Bài đăng engineering của Anthropic: anthropic.com/engineering/effective-context-engineering-for-ai-agents
- Tài liệu context windows của Anthropic: docs.anthropic.com/en/docs/build-with-claude/context-windows
- Tài liệu prompt caching của Anthropic: docs.anthropic.com/en/docs/build-with-claude/prompt-caching
- Hướng dẫn prompting của Anthropic: docs.anthropic.com/en/docs/build-with-claude/prompt-engineering/claude-4-best-practices
- Liu et al. (2023): semanticscholar.org/paper/Lost-in-the-Middle
- Tài liệu context engineering của LangChain: docs.langchain.com/oss/python/langchain/context-engineering
- Khảo sát về context engineering (arXiv 2025): arxiv.org/pdf/2507.13334