Chuyển đến nội dung
24/30Chương 24 trên 30

Context engineering: Vì sao agent của bạn kém thông minh hơn ở lượt 40

Dời một dữ kiện xuống ba dòng trong prompt chỉ chiếm 2,6% context window làm retrieval giảm từ 84% xuống 19%.

Trên trang này

Đây là một prompt được gửi 288 lần tới cùng một model với greedy decoding. Nó dài 853 token. Nó chứa một sổ gồm hai mươi lăm ticket hỗ trợ — thành phố, hàng đợi, mức ưu tiên, chủ sở hữu, số máy nhánh — và một câu hỏi: Marta Ferreira cần được gọi lại về ticket của cô ấy. Số máy nhánh trực tiếp cho ticket đó là gì?

Sổ này lần nào cũng giống hệt. Model lần nào cũng giống hệt. Điều duy nhất thay đổi là dòng nào trong hai mươi lăm dòng chứa câu trả lời.

vị trí của câu trả lờilần đúngtỷ lệ retrievalkhoảng 95 %
1 trên 2527/3284 %68–93 %
4 trên 256/3219 %9–35 %
7 trên 256/3219 %9–35 %
10 trên 259/3228 %16–45 %
13 trên 258/3225 %13–42 %
16 trên 256/3219 %9–35 %
19 trên 256/3219 %9–35 %
22 trên 253/329 %3–24 %
25 trên 257/3222 %11–39 %

Ba mươi hai thử nghiệm mỗi hàng, mỗi thử nghiệm là một ticket khác nhau, khoảng Wilson từ Chương 4 vì mười bảy trên hai mươi không phân biệt được gì với gì.

Vị trí một được trả lời đúng 84 % số lần. Mọi vị trí khác nằm trong khoảng 9 % đến 28 % và cả tám khoảng đó đều chồng lấn, nên cách đọc trung thực là đầu tiên, rồi sau đó là tất cả phần còn lại. Liu và cộng sự tìm thấy một chữ U — cao ở hai đầu, thấp ở giữa — còn nhánh gần đây không hiện rõ ở đây: 22 % ở vị trí cuối nằm trong độ trải của các vị trí giữa. Thứ không nằm trong bất kỳ độ trải nào là cú rơi từ vị trí 1 xuống vị trí 4. Ba dòng.

context window của model này là 32.768 token. prompt dùng 853 token, 2,6 %. Không có gì tràn, không có gì bị cắt, không chạm giới hạn nào, không cảnh báo nào xuất hiện. Model ngừng tìm thấy một dòng đã được đưa cho nó, vì dòng đó bị dời xuống ba vị trí trong một danh sách hai mươi lăm dòng.

Chương 16 đã định giá context window và kết thúc bằng cảnh báo rằng một triệu token không đồng nghĩa với dùng được chúng, rồi chỉ sang đây. Đây chính là chỗ đó.

Hiện chi tiết

Chương này cần gì từ các chương trước.

  • Chương 9 suy ra self-attention và chi phí O(n2)O(n^2) của nó. Mỗi token attends tới mọi token khác, nên số quan hệ từng cặp tăng theo bình phương độ dài. Sự thật đó được dùng bên dưới, không suy ra lại.
  • Chương 16 đếm năm nhóm token có thể tính phí và cho thấy hóa đơn của một cuộc trò chuyện tăng theo bậc hai. Chương này là việc bạn làm gì với điều đó mà không làm hỏng agent.
  • Chương 18 xây dựng danh mục công cụ và đo rằng hai mươi công cụ không làm hại lựa chọn nhưng nhân prompt lên sáu lần. Đây là hóa đơn cho chúng.
  • Chương 19 xây dựng retrieval. retrieval đúng lúc bên dưới là chương đó áp dụng vào chính lịch sử của agent; chunking không được giải thích lại.
  • Chương 23 xây dựng harness. Mọi thứ trong chương này là một policy chạy bên trong vòng lặp của nó, đó là lý do nó là TypeScript: artefact là một dịch vụ sống lâu giữ state, không phải notebook giữ tensor.

Anthropic đã vạch ranh giới vào tháng 9 năm 2025 và hai câu này nên được đặt cạnh nhau. Prompt engineering là “các phương pháp viết và tổ chức hướng dẫn cho LLM để có kết quả tối ưu”. Context engineering là “tập hợp các chiến lược để tuyển chọn và duy trì tập token (thông tin) tối ưu trong quá trình suy luận của LLM, bao gồm mọi thông tin khác có thể rơi vào đó ngoài prompt”.1

Khác biệt vận hành nằm ở khi nào, và bởi ai. Một prompt được một người viết một lần, rồi được duyệt. Một context được code mà không ai đang nhìn vào lắp ráp ở mỗi lần gọi, từ vật liệu không ai viết thủ công: bốn mươi lượt lịch sử, sáu kết quả công cụ, bốn đoạn được retrieve, một hồ sơ người dùng, mười hai schema JSON. Chương 15 đã đo hướng dẫn tốt hơn mua được gì. Chương này nói về chín mươi phần trăm token còn lại, tự chúng xuất hiện.

Cùng tài liệu đó gọi tên tài nguyên mà tất cả chúng tiêu: models “có một ‘attention budget’ mà chúng rút ra khi phân tích khối lượng context lớn. Mỗi token mới được đưa vào làm cạn ngân sách này ở một mức nào đó”. Và nó gọi tên triệu chứng: “khi số token trong context window tăng lên, khả năng model nhớ lại chính xác thông tin từ context đó giảm xuống” — context rot.1

Câu cuối là một tuyên bố về hành vi, nghĩa là có thể kiểm tra được, và bảng ở đầu trang này là phép kiểm tra.

Bốn mươi dòng gọi tới endpoint cục bộ từ Chương 22 — một server Python nhỏ giữ Qwen2.5-0.5B-Instruct trên CPU và nói theo dạng chat-completions, để vòng lặp vẫn là TypeScript còn tensor ở phía bên kia cổng.

position.tsTS
const DEPTHS = [0, 0.125, 0.25, 0.375, 0.5, 0.625, 0.75, 0.875, 1];

for (const d of DEPTHS) {
  const slot = Math.round(d * (N - 1));
  let hits = 0, other = 0;
  for (let t = 0; t < TRIALS; t++) {
    const recs = buildRecords(N, 1000 + t);          // 25 unique tickets
    const gold = recs[Math.floor(rng(7 + t)() * N)]; // a different one each trial
    const rest = recs.filter((x) => x.ticket !== gold.ticket).slice(0, N - 1);
    const lines = [...rest.slice(0, slot).map((x) => x.line),   
                   gold.line,                                   
                   ...rest.slice(slot).map((x) => x.line)];     
    const r = await complete(prompt(lines, ask(gold.owner)), { maxTokens: 12 });
    const said = /\d{4}/.exec(r.text)?.[0];
    if (said === String(gold.ext)) hits++;
    else if (said && recs.some((x) => String(x.ext) === said)) other++;
  }
}

Bộ đếm other là thứ biến một kết quả đáng thất vọng thành một kết quả hữu ích: khi model sai, nó lạc mất hay nó tự tin?

Câu trả lời là tự tin. Trên tám vị trí không phải vị trí đầu, 136 trong 205 câu trả lời sai là số máy nhánh của một ticket khác — một số bốn chữ số thật, đúng định dạng, đọc từ nhầm dòng. Ở vị trí 1 chỉ một trong năm lần trượt là như vậy; ở vị trí 7, hai mươi mốt trong hai mươi sáu lần là như vậy.

Sự phân biệt đó mới quan trọng trong production. Một model nói tôi không tìm thấy là một bug bạn nhận ra; một model trả về số của hàng bên cạnh là một bug bạn ship, vì trên màn hình hai thứ trông giống hệt nhau. Đó là lỗi mà Chương 19 đã xây citation có thể kiểm chứng để chống lại, giờ xuất hiện từ bên trong prompt thay vì từ index.

Vị trí là một trục. Độ dài là trục còn lại, và dễ kiểm tra hơn: giữ câu trả lời ở giữa rồi tăng danh sách.

bản ghitoken trong promptlần đúngtỷ lệkhoảng 95 %sai dòngkhông phải cả hai
19718/2090 %70–97 %02
315911/2055 %34–74 %90
83153/2015 %5–36 %170
206952/2010 %3–30 %162
401.3243/2015 %5–36 %152
802.5871/205 %1–24 %181
1404.4772/2010 %3–30 %180

Một bản ghi và 97 token: 90 %. Ba bản ghi và 159 token: 55 %. Tám bản ghi và 315 token: 15 %, rồi từ đó phẳng và thấp cho tới 140 bản ghi và 4.477 token. Toàn bộ cú sập xảy ra giữa dòng đầu tiên và dòng thứ tám của một danh sách.

Cột cuối là mọi thứ không phải số máy nhánh đúng cũng không phải của bản ghi khác; với một bản ghi duy nhất trên trang, đó là nơi duy nhất câu trả lời sai có thể rơi vào. Hai lần trượt ở một bản ghi đáng được báo cáo thay vì làm tròn bỏ qua, vì cả hai đều không phải từ chối: một lần trả lời 5806 cho một sổ có dòng duy nhất ghi 5805. Ở 97 token với một ứng viên duy nhất, model này vẫn chép sai một chữ số hai lần trong hai mươi, và đó là sàn để đo mọi thứ khác.

Hai điều kéo theo. context lớn hơn mua quyền gửi nhiều hơn, không mua sự chắc chắn rằng nó được đọc: model này có context window 32.768 token và phạm vi hoạt động, trên tác vụ này, chỉ vài trăm token. Và không có ngưỡng, không có vách đá, không có trạng thái “context đầy” — suy giảm đã bắt đầu ở bản ghi thứ ba và hoàn tất ở bản ghi thứ tám, tại một phần trăm của window. Dù giới hạn context là gì, nó không phải thứ chi phối chuyện này.

Hai cơ chế thường được đưa ra. Cơ chế đầu là phép số học từ Chương 9, mà Anthropic phát biểu bằng đúng các thuật ngữ khóa học này dùng: models “dựa trên kiến trúc transformer, cho phép mỗi token attend tới mọi token khác trên toàn bộ context. Điều này tạo ra n² quan hệ từng cặp cho n token”.1 Attention trên một chuỗi dài hơn không phải cùng một phép toán áp lên nhiều vật liệu hơn; đó là một ngân sách cố định của khối lượng xác suất được trải lên nhiều đối thủ hơn. Cơ chế thứ hai là training: models thấy nhiều chuỗi ngắn hơn chuỗi dài rất nhiều, nên các mẫu vị trí tầm xa là phần ít được luyện nhất của mạng. Đó là một lập luận, không phải một phép đo, và chương này không thể phân xử nó.

Điều đã được xác lập là hình dạng, và đã như vậy từ năm 2023. Liu và cộng sự kiểm tra trả lời câu hỏi đa tài liệu và retrieval key-value trên nhiều họ và kích thước model, rồi thấy rằng “hiệu năng thường cao nhất khi thông tin liên quan xuất hiện ở đầu hoặc cuối input context, và suy giảm đáng kể khi models phải truy cập thông tin liên quan ở giữa các context dài, ngay cả với models được thiết kế rõ ràng cho long-context”.2 Chương 15 lấy quy tắc vị trí từ bài đó; Chương 19 lấy từ đó lý do hai mươi chunk được retrieve có thể cho điểm kém hơn bốn. Dạng thực dụng của sự thật này là câu duy nhất ở đây bạn nên hành động theo: mất năm phút để đo trên model của chính bạn với dữ liệu của chính bạn, và không đường cong đã công bố nào thay thế được đường cong của bạn.

Hỏi một đội điều gì lấp đầy context của agent, bạn sẽ nhận được một ước lượng, vì không API nào trả về câu trả lời: response cho bạn prompt_tokens, một con số cho tất cả.

Bạn có thể khôi phục phần phân rã bằng bốn lần đếm và ba phép trừ — toàn bộ prompt đã render, cùng prompt đó không có định nghĩa công cụ, riêng system message có và không có chúng, và mọi thứ sau khi bỏ kết quả công cụ:

buckets.tsTS
async function buckets(messages: Msg[]) {
  const sys = messages.slice(0, 1);
  const withoutResults = messages.filter((m) => m.role !== "tool");
  const [total, sysWithTools, sysNoTools, noResults] = await Promise.all([
    countPrompt(messages, CATALOGUE),        // everything
    countPrompt(sys, CATALOGUE),             // system + scaffolding + schemas
    countPrompt(sys),                        // system + scaffolding
    countPrompt(withoutResults, CATALOGUE),  // everything but tool output
  ]);
  return {
    system: sysNoTools,
    tools: sysWithTools - sysNoTools,                                  
    toolResults: total - noResults,                                    
    conversation: total - sysWithTools - (total - noResults),          
    total,
  };
}

countPrompt áp dụng chat template của chính model trước khi tokenize, điều này quan trọng hơn vẻ ngoài của nó: văn bản của bạn không phải thứ được đếm. Dấu vai trò, phần mở đầu tool-calling và cách render schema đều là token bạn trả tiền mà chưa từng gõ. Chương 7 xây một tokenizer và Chương 16 đếm với js-tiktoken; ở đây số đếm đến từ chính model sẽ đọc prompt, đó là cách đếm duy nhất đúng tuyệt đối.

Giờ chạy một agent thật qua nó: bốn mươi lượt điều tra sự cố, mười hai công cụ, một môi trường vận hành giả trả về log dump và chuỗi metric thực tế.

lượtsystemđịnh nghĩa công cụhội thoạikết quả công cụtổng promptinput bị tính phí lượt này
1851.8171554902.5474.370
2851.8172825292.7135.275
5851.8176471.8704.4198.093
10851.8179462.1414.9894.951
20851.8171.5002.9436.3456.316
30851.8172.1874.0008.0898.059
40851.8173.0535.67710.63221.090

Đọc hàng đầu so với hàng cuối.

lượt 1 prompt là 2.547 token và 71 % trong đó là định nghĩa công cụ. system prompt là 3 %. Những gì người dùng gõ là 6 %. agent chưa làm gì và đã mang 1.817 token JSON schema.

Đến lượt 40 prompt là 10.632 token và tỷ trọng đã đảo ngược: định nghĩa 17 %, hội thoại 29 %, kết quả công cụ 53 %. Output công cụ vượt định nghĩa ở lượt 5; hội thoại không vượt chúng cho tới lượt 25, nên trong sáu mươi phần trăm đầu của phiên danh mục công cụ lớn hơn mọi thứ đã được nói.

Rồi đến tổng. Trên 57 lần gọi model, lượt chạy bị tính phí 370.291 input token cho một context cuối cùng 10.632 — prompt cuối đã được trả tiền khoảng ba mươi lăm lần, đúng bậc hai của Chương 16 cộng thêm hệ số nhân của agent. Trong 370.291 đó, 103.569, tức 28 % của mọi thứ bị tính phí, là mười hai định nghĩa công cụ, được gửi lại giống hệt từng byte ở mỗi lần gọi.

Danh mục công cụ là chi phí cố định lớn nhất trong một agent và nó vô hình, vì bạn không bao giờ thấy nó: bạn truyền một mảng object và provider render nó vào prompt cho bạn. Đo trên cùng mười hai công cụ:

tooldefs.ts outputTEXT
system prompt + chat scaffolding, no tools:        85 tokens
all twelve definitions:                          1,817 tokens
  of which fixed tool-calling scaffolding:         126 tokens
three tools instead of twelve:                     605 tokens
same twelve, one-sentence descriptions,
  no parameter prose:                            1,291 tokens  (-29 %)

Theo từng công cụ, chi phí biên chạy từ 80 token cho get_current_time, nhận một chuỗi, tới 263 cho search_tickets, nhận bốn tham số với một enum và mỗi tham số một câu hướng dẫn. Đó là tỷ giá đằng sau lời khuyên trung tâm của Chương 18 rằng mô tả là API: một mô tả tốt tốn khoảng một trăm token trên mọi request trong suốt phần đời còn lại của agent. Ba hệ quả.

Công cụ bạn không dùng vẫn bị tính phí. agent gọi bảy trong mười hai công cụ. Năm công cụ còn lại tốn 697 token trên mỗi request trong 57 request — tổng 39.729, hơn một phần mười mọi thứ lượt chạy bị tính phí, cho các năng lực nó chưa từng chạm tới. Một trong năm công cụ mang chi tiết sắc nhất trong trace: model đã thử gọi read_log ba lần, thứ không tồn tại. Công cụ nó muốn là search_logs, định nghĩa đắt thứ hai trong danh mục ở mức 237 token. Nó trả tiền cho định nghĩa đó 57 lần, không bao giờ dùng nó, và không bao giờ tìm thấy tên của nó.

Cắt văn xuôi là tối ưu hóa rẻ nhất hiện có, và đó là một đánh đổi. Rút mô tả xuống một câu và bỏ tài liệu tham số tiết kiệm 526 token mỗi lần gọi, 29 phần trăm, không đụng một dòng logic — và làm model gọi công cụ tệ hơn, đúng điều Chương 18 đã đo. Vấn đề là cả hai phía của đánh đổi đó giờ đã ở cùng một đơn vị.

Ở một quy mô nào đó, gửi định nghĩa ngay từ đầu không còn hợp lý. Anthropic đưa ra một con số vào tháng 11 năm 2025: một tập lớn các server được kết nối đồng nghĩa với việc xử lý “hàng trăm nghìn token” định nghĩa trước khi request được đọc, và thay thế việc đó bằng thực thi code — agent khám phá và nạp chỉ các định nghĩa nó cần — “giảm lượng token usage từ 150.000 token xuống 2.000 token, tiết kiệm thời gian và chi phí 98,7%”.3 Cùng ý tưởng với phần còn lại của chương này, áp lên schema thay vì lịch sử: giữ index, resolve entry theo nhu cầu.

Hai thứ đã được cài vào transcript bốn mươi lượt đó. Ở lượt 2, trước bất kỳ công việc thật nào, người dùng nêu một quy tắc thường trực: bất kỳ ticket nào bạn mở phải được ghi dưới mã nhân viên của tôi, 4417.lượt 19, giữa sự cố, một dữ kiện: shard bị ảnh hưởng là pay-shard-7, đã được đội payments xác nhận. Ở lượt 40 người dùng yêu cầu agent mở ticket sự cố, việc này cần cả hai. Mỗi probe được hỏi bằng sáu cách diễn đạt khác nhau và chấm trên sáu — greedy decoding là deterministic, nên một lần gọi cho một yes/no không lặp lại được, còn sáu lần cho một tỷ lệ.

Transcript sau đó được phát lại dưới bảy context policy. Cố ý phát lại thay vì chạy lại: messages, tool calls và tool results giống hệt từng byte ở cả bảy, nên biến duy nhất là mỗi policy đã chọn giữ gì. Chương 16 đã cho thấy vì sao sliding window là một bước đi kinh tế tệ, vì nó phá hủy prefix có thể cache. Đây là điều nó làm với hành vi:

context policyinput token qua 40 lượtprompt lượt 40quy tắc lượt 2dữ kiện lượt 19
toàn bộ lịch sử370.29110.6326/65/6
sliding window, 12 message cuối157.5782.9225/60/6
bỏ kết quả công cụ cũ hơn 4 lượt243.4456.3116/63/6
compaction mỗi 6 lượt195.5153.2206/60/6
compaction cộng ghi chú do model viết200.8493.2866/60/6
ghim lượt của chính người dùng, ở đầu168.5503.5596/65/6
ghim lượt của chính người dùng, ở cuối168.8353.5646/66/6
đối chứng: chỉ hai lượt đó và không gì khác1.9816/66/6

Các hàng compaction bao gồm chi phí compacting: 18.581 input token cho bảy bản tóm tắt và thêm 3.392 cho note-taker. Hàng đối chứng ở đó để một số không được đọc đúng là số không — với chỉ hai message trong một prompt 1.981 token, model này trả lời hoàn hảo cả hai probe, nên không hàng nào là vì tác vụ quá khó.

Toàn bộ lịch sử nhớ được, và là thứ đắt nhất trên bảng: 370.291 input token cho một phiên mà nội dung bền vững chỉ là hai câu.

Điều đó trả lời câu hỏi phần mở đầu còn bỏ ngỏ. Vì sao một transcript 10.632 token giữ được một dữ kiện mà một sổ 853 token lại mất? Vì độ dài là biến sai. Sổ chứa hai mươi lăm số máy nhánh bốn chữ số trong hai mươi lăm câu giống hệt nhau — hai mươi bốn mồi nhử gần hoàn hảo cho thứ bạn muốn. Transcript chứa đúng một mã nhân viên và một tên shard. Context rot là nhiễu trước khi là dung lượng, đó là lý do 136 trong 205 câu trả lời sai ở trên là giá trị của hàng bên cạnh. Câu hỏi hữu ích về một window không phải nó dài bao nhiêu; mà là có bao nhiêu thứ trong đó trông giống câu trả lời.

Sliding window rẻ hơn 57 % và đã làm mất sự cố. Mã nhân viên sống sót chỉ vì agent đã lặp nó vào các lượt gần đây. Shard, được nêu một lần ở lượt 19, không nằm trong mười hai message cuối — và model không nói vậy. Được hỏi sáu lần, nó trả lời “payment shard bị ảnh hưởng là shard 4417”, với tay tới mã nhân viên, định danh duy nhất còn lại trong window của nó, và hai lần trả lời “pool”, nhấc ra từ chuỗi pool_exhausted trong một dòng log.

Compaction rẻ và làm mất cùng dữ kiện đó. Bảy bản tóm tắt, do model viết dưới chỉ dẫn rõ ràng là giữ định danh, số, hướng dẫn thường trực và câu hỏi mở, và pay-shard-7 không nằm trong bản nào quan trọng; sáu phỏng đoán là shard 1, pay_shard_1pool. Compaction không thất bại ồn ào. Nó tạo ra một phiên trôi chảy, hợp lý, ngắn hơn nhiều, đã âm thầm đánh rơi một dòng.

Ba hàng đạt 0/6 về dữ kiện lượt 19 — sliding window, compaction, và compaction với ghi chú. Mười tám câu trả lời sai giữa chúng, và không một câu nào là “tôi không biết.”

Rồi đến hàng đáng lẽ phải gây xấu hổ. Giữ nguyên văn bốn mươi message của chính người dùng, cộng bốn lượt cuối đầy đủ và không gì khác, tốn 168.550 token — ít hơn toàn bộ lịch sử 54 % — và trả lời cả hai probe tốt bằng hoặc tốt hơn toàn bộ lịch sử. Không summariser, không note-taker, không model thứ hai: một bộ lọc trên role === "user". Lời của người dùng là các token rẻ nhất và giá trị cao nhất trong window của agent, và hầu hết thiết kế vứt chúng đi cùng mọi thứ khác.

Hai hàng cuối là bảng mở đầu một lần nữa, bên trong agent. Cùng khối được ghim, chuyển từ system message xuống cuối prompt: 5/6 thành 6/6. Trên sáu thử nghiệm, đó không phải khác biệt có ý nghĩa thống kê và không được trình bày như vậy — nó được đưa ra như một lời nhắc rằng ở đâu là một tham số bạn đang đặt dù bạn biết hay không.

Bốn chiến lược bên dưới là của Anthropic, theo thứ tự của họ, dù chỉ ba chiến lược cuối nằm trong danh sách dài hạn của họ.1 Cả bốn đều là biến thể của một chỉ dẫn: đừng mang theo thứ bạn có thể fetch, và đừng mang raw thứ bạn có thể mang ở dạng nén.

Đừng pre-load nội dung. Giữ định danh — đường dẫn file, query, số ticket, tên công cụ và arguments của nó — rồi resolve khi cần. Nhóm lớn nhất trong agent ở trên là output công cụ đã được đọc một lần, dùng một lần rồi mang thêm ba mươi lượt nữa. Thay mọi kết quả cũ hơn bốn lượt bằng một stub nói nó là gì và cách lấy lại nó là sáu dòng:

policies.tsTS
const elide: Policy = (h) => [SYSTEM, ...h.flatMap((turn, ti) =>
  turn.map((m) => (ti < h.length - 4 && m.role === "tool"
    ? { role: "tool", name: m.name,
        content: `[${m.name} result from turn ${ti + 1}, ${m.content.length} chars, ` +
                 `elided; call ${m.name} again with the same arguments to re-read it]` }
    : m)))];

Đây là Chương 19 với corpus được thay bằng chính quá khứ của agent. Bộ máy retrieval đã có sẵn — đó là danh mục công cụ.

Khi transcript vượt một ngưỡng, thay phần cũ nhất của nó bằng một bản tóm tắt do model viết và tiếp tục. prompt viết bản tóm tắt là toàn bộ thiết kế, và đó là nơi compaction thắng hoặc thua: giữ định danh, số, hướng dẫn thường trực và câu hỏi mở; bỏ xã giao và output công cụ bạn có thể re-fetch.

Compaction vốn có mất mát theo thiết kế, thứ nó làm mất được một model chọn thay cho bạn, và không có gì báo lỗi khi nó chọn sai. Nó cũng không miễn phí: mỗi compaction là một lần gọi bổ sung có input là chính thứ đang được compact.

Duy trì một store nhỏ bên ngoài context và tiêm lại toàn bộ vào mỗi lượt. Khác với bản tóm tắt, nó chỉ append và có thể address: một quy tắc viết ở lượt 2 vẫn còn nguyên văn ở lượt 400. Phiên bản đo ở đây hỏi model, sau mỗi message của người dùng, liệu nó có chứa thứ gì bền vững không:

notes.tsTS
const r = await complete([
  { role: "system", content:
      "You keep a durable note file for a support session. Given one user message, " +
      "output one short note ONLY if it states a standing rule, an identifier or a fact " +
      "that must survive the rest of the session. Otherwise output exactly NONE." },
  { role: "user", content: `Turn ${i + 1}: ${user}` },
], { maxTokens: 40 });
if (!/^none\b/i.test(r.text.trim())) notes.push(`turn ${i + 1}: ${r.text.trim()}`);

Đây là chiến lược có trần cao nhất ở đây, và cũng là chiến lược thất bại trong phép đo. Qua bốn mươi message người dùng, note-taker giữ ba ghi chú và không giữ hai ghi chú quan trọng: một dòng lời khuyên runbook, một thông báo rằng phiên sắp kết thúc, và Europe/Madrid hiện là 13:45 — một thời điểm nó bịa ra, vì công cụ nó đang diễn giải trả về 09:52 UTC. Note-taker là một model, và mọi thứ trong chương này cũng áp dụng cho nó.

Cho một tác vụ tập trung window riêng — system prompt riêng, danh mục nhỏ riêng, không có lịch sử của cha — rồi trả về một câu trả lời ngắn thay vì một transcript. Chương 23 đặt một sub-agent sau một tool schema và để hóa đơn ở đây; hóa đơn là câu trả lời của con là phần duy nhất trong window của con mà cha từng trả tiền.

Sub-agent không nằm trong bảng trên vì nó không chạy bốn mươi lượt: nó chạy một lần, trong một window do ai đó đã scope cho nó. Được đưa system prompt, các lượt 17 đến 19 và không gì khác — 2.737 token — nó trả lời probe shard 6/6, tốt hơn mọi policy trong bảng, và probe nhân viên 0/6, vì con số đó không nằm trong ba lượt nó được đưa.

Đó là sub-agents trong hai con số: một window sạch không phải trí thông minh, mà là scope, và việc scoping được code làm trước, code vốn đã phải biết lượt nào quan trọng. Còn một điều trong các câu trả lời đó đáng giữ lại. Đây là policy duy nhất đáp “None available” thay vì bịa ra thứ gì đó. Một model với context nhỏ, mạch lạc biết nó thiếu gì; một model với context lớn, nhiễu thì không.

Gần như mọi cuộc trò chuyện rối rắm về bộ nhớ của agent là ba cơ chế cùng mặc một từ. Chúng có vòng đời, chủ sở hữu và kiểu lỗi khác nhau, và một hệ thống giữ chúng ở cùng một nơi có một vấn đề mà nó chưa nhận ra.

lịch sử hội thoạiretrievalbộ nhớ người dùng bền vững
giữđiều đã được nói trong phiên nàytài liệu bạn sở hữudữ kiện về một người
sốngmột phiêncho tới khi được re-indexqua mọi phiên, mãi mãi
được viết bởivòng lặp, tự độngmột pipeline ingestmodel, có chủ ý
vào promptđầy đủ, mỗi lần gọibốn đoạn, khi query khớpđầy đủ, mỗi lần gọi
lỗi bằng cáchlớn lên cho tới khi mục ruỗngretrieve nhầm chunknhớ sai điều gì đó về bạn
được xây ởChương 23Chương 19chương này

Khung học thuật là của CoALA, tổ chức language agents quanh “các thành phần bộ nhớ modular” và tách working memory khỏi episodic, semantic và procedural stores.4 MemGPT lấy cùng ý tưởng theo nghĩa đen, mượn virtual memory từ hệ điều hành: một tầng nhanh bên trong window, một tầng chậm bên ngoài, và chính model di chuyển dữ liệu giữa chúng bằng function calls.5 Cả hai buộc sản phẩm phải trả lời câu hỏi dù sao cũng phải trả lời — không phải tôi có thể giữ bao nhiêu, mà là thứ này thuộc store nào, và khi nào nó hết hạn.

Phép kiểm tra thực dụng là một câu hỏi cho mỗi dữ kiện: ngày mai điều gì vẫn nên đúng? Một kết quả công cụ từ lượt 12, không gì cả. Một bản tóm tắt phiên, cho tới khi phiên kết thúc. Mã nhân viên của người dùng là 4417, cho tới khi họ đổi việc. Ba câu trả lời, ba store.

Giờ bạn có thể đo có gì trong một window, quyết định thứ gì ở lại trong đó, và phân biệt một agent đã quên thứ gì đó với một agent vẫn mang nó nhưng không nhìn.

Chiến lược cuối cùng trong bốn chiến lược là thứ không vừa ở đây. Một sub-agent không phải context policy, nó là agent thứ hai, và khoảnh khắc có hai agent, bạn phải quyết định thứ gì truyền giữa chúng và ai phụ trách. Chương 25 là chuyện đó: năm mẫu orchestration và tên của mỗi mẫu thật sự đến từ đâu, hai topology hay bị trộn lẫn — hỏi một sub-agent rồi nhận câu trả lời lại, đối lập với trao cho nó cuộc trò chuyện rồi không nhận lại — và phát hiện đo được rằng trên tác vụ nó định giá, cách sắp xếp đơn giản hơn thắng — sau đó là bài kiểm tra khi nào nó ngừng thắng.

Nó cũng thừa hưởng chính xác thứ chương này vừa đo. Một sub-agent trả về bản tóm tắt. Một bản tóm tắt là một compaction bạn không viết, do một model có window bạn không thấy tạo ra, và agent cha không có cách nào phân biệt bản tốt với bản sai nhưng tự tin — cùng sự phân biệt đã tách 84 % khỏi 19 % ở đầu trang này, và biến mười tám dữ kiện bị thiếu thành mười tám dữ kiện bịa. Vậy: khi sub-agent sai, chính xác thì agent cha được nhìn vào cái gì?


Mọi con số ở đây được tạo trên máy này và không con số nào là ước lượng. Model là Qwen2.5-0.5B-Instruct ở float32 trên CPU với greedy decoding, được phục vụ qua loopback bởi một endpoint Python nhỏ nói theo dạng chat-completions và expose một route đếm token — lại là đường nối của Chương 14, tensor ở phía Python và vòng lặp ở phía TypeScript — nên mọi số đếm là tokenizer của chính model đó áp lên chat template của chính nó. Bảng vị trí là 288 lần gọi, chín vị trí nhân ba mươi hai thử nghiệm với một ticket khác ở mỗi thử nghiệm; bảng độ dài là 140 lần gọi; lượt chạy agent là 57 lần gọi model qua 43 phút thời gian thực; bảng policy là một transcript đó được phát lại dưới bảy policy. Các khoảng là Wilson, từ Chương 4. Không API trả phí nào được gọi, đó cũng là lý do chương này không có một mức giá nào: số đếm token là chính xác và mức giá bạn sẽ nhân chúng với nằm ở Chương 16.

  1. Anthropic, Effective context engineering for AI agents, 29 tháng 9 năm 2025, anthropic.com/engineering/effective-context-engineering-for-ai-agents, đọc ngày 7 tháng 9 năm 2026. Nguồn của hai định nghĩa được trích ở đầu, của “attention budget” và phát biểu rằng mỗi token mới làm cạn nó, của mô tả context rot, của framing quan hệ từng cặp n², và của các chiến lược được dùng làm xương sống của chương này. Ba chiến lược trong số đó là danh sách dài hạn của họ — compaction, structured note-taking và multi-agent architectures; just-in-time retrieval xuất hiện sớm hơn trong cùng bài, dưới context retrieval và agentic search, và được nhóm với chúng ở đây. 2 3 4

  2. Liu, N. F., Lin, K., Hewitt, J., Paranjape, A., Bevilacqua, M., Petroni, F. và Liang, P. Lost in the Middle: How Language Models Use Long Contexts. arXiv:2307.03172 (v1 tháng 7 năm 2023, v3 tháng 11 năm 2023). Được trích trong Chương 15, 16 và 19 và được đo ở đây. Câu trích là từ abstract; hai tác vụ của paper là trả lời câu hỏi đa tài liệu và retrieval key-value, và phát hiện rằng hiệu ứng vẫn tồn tại trong models được thiết kế rõ ràng cho long-context là phần quan trọng với quyết định sản phẩm.

  3. Anthropic, Code execution with MCP: building more efficient agents, 4 tháng 11 năm 2025, anthropic.com/engineering/code-execution-with-mcp, đọc ngày 7 tháng 9 năm 2026. Nguồn của mức giảm từ 150.000 xuống 2.000 token và con số 98,7 %, cũng như quan sát rằng định nghĩa công cụ được nạp upfront chiếm context trước khi request được đọc.

  4. Sumers, T. R., Yao, S., Narasimhan, K. và Griffiths, T. L. Cognitive Architectures for Language Agents. arXiv:2309.02427 (2023). Tổ chức language agents quanh “modular memory components, a structured action space to interact with internal memory and external environments, and a generalized decision-making process to choose actions”, và chia bộ nhớ thành working, episodic, semantic và procedural. Chương 22 dùng taxonomy của nó cho learning agent; bảng ba store ở trên là cái bóng thực dụng của nó.

  5. Packer, C., Wooders, S., Lin, K., Fang, V., Patil, S. G., Stoica, I. và Gonzalez, J. E. MemGPT: Towards LLMs as Operating Systems. arXiv:2310.08560 (tháng 10 năm 2023). Đề xuất “virtual context management, a technique drawing inspiration from hierarchical memory systems in traditional operating systems”, với chính model di chuyển dữ liệu giữa một tầng nhanh bên trong window và một tầng chậm bên ngoài nó. Phát biểu rõ nhất ở bất kỳ đâu về vì sao window là cache chứ không phải bộ nhớ.

Sẵn sàng để LIA chọn giúp bạn chưa?

Xây dựng cùng mọi mô hình AI ở một nơi — bắt đầu miễn phí ngay hôm nay.