ประกอบเป็น context layer ตัวเต็ม
เจ็ดบทที่ผ่านมาคุณสร้างเครื่องมือมาทีละชิ้น — retrieval ที่ดึงเฉพาะข้อมูลที่เกี่ยว (บทที่ 2), memory ที่ agent เขียนโน้ตเก็บไว้นอกหน้าต่าง (บทที่ 3), การมองหน้าต่างเป็นงบที่ใช้แล้วหมด (บทที่ 4), compaction ที่สรุปประวัติให้สั้นโดยรักษาสิ่งที่ชี้ขาด (บทที่ 5) และการปั้นผลของ tool ให้เหลือแต่ field ที่ใช้จริง (บทที่ 6) แต่ละชิ้นคุณได้ทดลองแยกกัน บทนี้คือบทที่ทุกชิ้นมาประกอบเป็นระบบเดียว — context layerContext Engineeringตามนิยามของ Anthropic คือ 'ชุดกลยุทธ์ในการคัดสรรและรักษาเซตของ token (ข้อมูล) ที่เหมาะสมที่สุดระหว่างที่ model กำลัง inference' — ไม่ใช่แค่ prompt แต่รวมทุกอย่างที่ model เห็นในแต่ละเทิร์น (system prompt, tools, ผลของ tool, ประวัติบทสนทนา) เป็นวิวัฒนาการต่อยอดจาก Prompt Engineering: prompt เขียนครั้งเดียว แต่ context ต้องคัดสรรใหม่ทุกเทิร์น ดาวเหนือของทั้งศาสตร์คือ 'หาเซต high-signal token ที่เล็กที่สุดที่ยังทำให้ได้ผลลัพธ์ที่ต้องการ'Process ชั้นหนึ่งที่คร่อม agent Order ตัวเดิมจากคอร์สที่ 15 แล้วทำงานร่วมกันในทุกเทิร์น ไม่ใช่ห้าเทคนิคที่ต่างคนต่างอยู่ แต่เป็นสายพานเดียวที่ทุกส่วนเล็งไปที่ดาวเหนือดวงเดียวกัน
บทนี้ประกอบ context layer เต็มตัวคร่อม agent Order จาก repo kaen-food-ordering (กำลังจัดทำ) — retrieval, memory, compaction และ tool ที่ curate มารวมเป็น pipeline เดียวต่อเทิร์น ทุกฝั่ง chat ยังยึด invariant เดิมของ #15 ทั้งหมด และฝั่ง embeddings ยังเป็น provider ที่สอง (จากบทที่ 2) code ในบทนี้เป็นการ ต่อ ชิ้นส่วนที่คุณสร้างในบทก่อนๆ เข้าด้วยกัน ไม่ใช่ของใหม่
ห้าชั้น รวมเป็นสายพานเดียว
หัวข้อที่มีชื่อว่า “ห้าชั้น รวมเป็นสายพานเดียว”ก่อนต่อ code ทวนภาพรวมว่าแต่ละชั้นทำอะไรในหนึ่งเทิร์น และมันเชื่อมกันตรงไหน context layer ไม่ใช่กล่องห้าใบวางเรียงกัน แต่เป็นลำดับขั้นที่ผลของขั้นก่อนป้อนขั้นถัดไป:
- อ่าน memory ที่เกี่ยว (บทที่ 3) — ก่อนเรียก model ดึงโน้ตความจำยาวที่เกี่ยวกับเคสนี้ (
Kind = "memory") มาเสียบเข้า system message - เช็คงบ token (บทที่ 4) — วัด input token ของประวัติปัจจุบัน ถ้าเกินเพดานที่ตั้งไว้ ให้เข้าขั้นถัดไป ถ้ายังไม่เกินก็ข้าม
- compaction (บทที่ 5) — สรุปประวัติที่ยาวให้เหลือ summary ก้อนเดียว รักษา order id + เหตุผลคืนเงิน ทิ้ง blob ที่จัดการไปแล้ว
- เรียก model ด้วย tool ที่ curate + retrieval (บทที่ 2, 6) —
GetResponseAsyncโดยผูก tool ที่คืนผลกระชับ บวกsearchOrderKnowledgeที่ดึงเฉพาะข้อความที่เกี่ยว - เขียน memory ปิดท้าย (บทที่ 3) — หลังเทิร์นจบ ให้ agent
saveMemoryสิ่งที่ต้องรอดข้ามการรีเซ็ตหน้าต่างครั้งหน้า
สังเกตว่าชั้น retrieval (บทที่ 2) กับชั้น memory (บทที่ 3) ใช้โครงสร้างเก็บข้อมูลตัวเดียวกัน — Vector StoreVector Storeที่เก็บ embedding ที่ค้นด้วยความคล้ายเชิงความหมายได้ — เก็บทั้งเวกเตอร์และข้อความต้นทางที่จะป้อนกลับให้ model ในคอร์สใช้ Microsoft.Extensions.VectorData (MEVD): abstraction เป็น GA แล้ว แต่ตัว store จริงยัง prerelease (ใส่ `--prerelease`) model ข้อมูลประกาศด้วย attribute เช่น `[VectorStoreVector(Dimensions: 1536)]` ที่ 'มิติต้องตรงกับ model embedding' เป๊ะ ๆArchitecture ก้อนเดียวที่แยกบทบาทด้วย field Kind ที่ถูก index ไว้ นี่คือกุญแจของการประกอบ: คุณไม่ต้องมีสองระบบ retrieval กับ memory คือ การอ่าน จากคลังเดียวกันด้วยตัวกรองต่างกัน
flowchart TB
U["ข้อความลูกค้า"] --> MEM
MEM["1 · อ่าน long-term memory<br/>Kind = memory"] --> BUD
BUD{"2 · งบ token<br/>เกินเพดาน?"} -->|ใช่| COMP["3 · compaction<br/>สรุปประวัติ"]
BUD -->|ไม่| ASM
COMP --> ASM
ASM["ประกอบ context<br/>retrieval + memory + ประวัติ + tool view"] --> LLM["4 · agent loop จาก #15<br/>claude-opus-4-8"]
LLM --> TOOLS["เรียก tool ที่ curate<br/>searchOrderKnowledge · getOrder · issueRefund"]
TOOLS --> LLM
LLM --> WRITE["5 · saveMemory<br/>สิ่งที่ต้องรอดข้ามเทิร์น"]
WRITE --> ANS["คำตอบถึงลูกค้า"]
VS[("Vector Store ก้อนเดียว<br/>policy · faq · order · memory")]
VS -.-> MEM
VS -.-> TOOLS
WRITE -.-> VS
classDef store fill:#0891b2,stroke:#064e5b,color:#f8fafc;
class VS store;
คำบรรยายภาพ: context layer หนึ่งเทิร์นเดินจากบนลงล่าง — อ่าน memory ที่เกี่ยว เช็คงบ token แล้ว compaction ถ้าเกินเพดาน ประกอบ context ที่คัดแล้วป้อน agent loop เดิมของ #15 ซึ่งเรียก tool ที่ curate ไว้ และปิดท้ายด้วยการเขียน memory สิ่งที่ต้องรอดข้ามเทิร์น ช่องสีฟ้าคือ Vector Store ก้อนเดียวที่ทั้ง retrieval (searchOrderKnowledge) และ memory อ่าน/เขียนร่วมกัน แยกบทบาทด้วย field Kind
คลังเดียว สองบทบาท
หัวข้อที่มีชื่อว่า “คลังเดียว สองบทบาท”จุดเริ่มของการประกอบคือ collection เดียวที่คุณสร้างไว้ในบทที่ 2 เพียงแต่ตอนนี้มันรับ record สองชนิด — เอกสารนโยบาย/FAQ/ออเดอร์สำหรับ retrieval และโน้ตความจำที่ agent เขียนเอง — แยกกันด้วย field Kind ที่ index ไว้ ทั้งสองบทบาทค้นด้วย SearchAsync ตัวเดียวกัน ต่างแค่ตัวกรอง:
// retrieval (บทที่ 2): ค้นเฉพาะนโยบาย/FAQawait foreach (var r in col.SearchAsync(qVector, top: 3, new VectorSearchOptions<OrderDoc> { Filter = d => d.Kind == "policy" || d.Kind == "faq" })) hits.Add(r.Record.Text);
// long-term memory (บทที่ 3): ค้นเฉพาะโน้ตของ agent เองawait foreach (var r in col.SearchAsync(qVector, top: 3, new VectorSearchOptions<OrderDoc> { Filter = d => d.Kind == "memory" })) notes.Add(r.Record.Text);คลังเดียวสองบทบาทนี้คือเหตุผลที่ retrieval กับ memory ไม่ใช่2 project แยกกัน — ทั้งคู่เป็นการอ่าน context ที่เกี่ยวเข้ามาแบบ just-in-time ต่างกันแค่ว่าใครเป็นคน เขียน ของลงคลัง: เอกสารนโยบายคุณเป็นคนใส่ล่วงหน้า ส่วนโน้ต Kind = "memory" คือสิ่งที่ agent เขียนเอง หลังแต่ละเทิร์น
ประกอบชุด tool แล้วเดิน pipeline
หัวข้อที่มีชื่อว่า “ประกอบชุด tool แล้วเดิน pipeline”ชุด tool ของ context layer ต่อยอดจากสามตัวเดิมของ #15 ตรงๆ — เพิ่ม searchOrderKnowledge จากบทที่ 2 และ saveMemory จากบทที่ 3 ส่วน getOrder ใช้ version getOrderView ที่ curate แล้วจากบทที่ 6:
// ชุด tool เต็มของ context layer — สามตัวเดิมของ #15 + retrieval + memoryvar options = new ChatOptions{ Tools = [ searchKnowledge, saveMemory, getOrderView, getDeliveryStatus, issueRefund ]};
// loop เดิมของ #15: x-api-key (ไม่ใช่ Authorization: Bearer), anthropic-version 2023-06-01,// model id เปล่า "claude-opus-4-8" (ตัวอย่าง ณ 2026-07), ไม่ส่ง temperatureIChatClient chat = anthropicChatClient.AsBuilder().UseFunctionInvocation().Build();แล้วห่อหนึ่งเทิร์นด้วย pipeline ห้าขั้นข้างบน — code นี้คือ context layer ทั้งชั้นในรูป method เดียว:
async Task<ChatResponse> RunTurnAsync( List<ChatMessage> history, string userText, IChatClient chat){ // 1. อ่าน memory ที่เกี่ยว (Kind == "memory") เสียบเข้า system message (บทที่ 3) var memoryNotes = await RecallMemoryAsync(userText); history[0] = new(ChatRole.System, baseSystemPrompt + "\n\nโน้ตความจำที่เกี่ยว:\n" + memoryNotes);
// 2. เช็คงบ token ของประวัติ (บทที่ 4) -> 3. compaction ถ้าเกินเพดาน (บทที่ 5) if (await CountInputTokensAsync(history) > CompactionThreshold) history = await CompactAsync(history, chat); // รักษา order id + เหตุผลคืนเงิน ทิ้ง blob ที่จัดการแล้ว
history.Add(new(ChatRole.User, userText));
// 4. เรียก model ด้วย tool ที่ curate + retrieval (บทที่ 2, 6) var reply = await chat.GetResponseAsync(history, options); history.AddMessages(reply);
// 5. ให้ agent เขียน memory สิ่งที่ต้องรอดข้ามเทิร์น (บทที่ 3) // saveMemory เป็น tool ในชุด agent จึงเรียกเองได้ระหว่างเทิร์น // หรือจะ upsert โน้ตปิดท้ายจากฝั่งเราก็ได้ return reply;}ทุกขั้นใน method นี้คือชั้นหนึ่งที่คุณสร้างมาแล้ว — RecallMemoryAsync และ saveMemory คือ memory (บทที่ 3), CountInputTokensAsync คือเครื่องวัดงบ (บทที่ 4), CompactAsync คือ compaction (บทที่ 5), getOrderView ใน options คือ curation (บทที่ 6) และ searchKnowledge คือ retrieval (บทที่ 2) สิ่งที่บทนี้เพิ่มคือ ลำดับ ที่ทำให้ทั้งห้าทำงานประสานกันต่อเทิร์น ไม่ใช่ตัวเทคนิคใหม่
ฝั่ง chat ทั้งหมดในบทนี้ยึดกติกาเดิมของคอร์ส #15 — header x-api-key (ไม่ใช่ Authorization: Bearer), anthropic-version: 2023-06-01, model id เปล่า claude-opus-4-8 (ตัวอย่าง ณ 2026-07 — id เลื่อนไหวตามเวลา), ไม่ส่ง temperature/top_p/top_k และคำตอบ/ผลของ tool อ่านจาก content[] ไม่ใช่ .text ระดับบนสุด ส่วนฝั่ง embeddings ยังเป็น provider ที่สอง (OpenAI text-embedding-3-small, 1536 มิติ) เพราะ Claude ไม่มี endpoint สำหรับ embedding — context layer บังคับให้คุณถือ2 provider เสมอ
เคสทดสอบที่ร้อยทุกชั้นเข้าด้วยกัน
หัวข้อที่มีชื่อว่า “เคสทดสอบที่ร้อยทุกชั้นเข้าด้วยกัน”วิธีพิสูจน์ว่า context layer ทำงานจริง ไม่ใช่แค่ประกอบ code ผ่าน คือเดินเคส support หนึ่งเคสที่ แตะทุกชั้นในเทิร์นเดียวกัน:
- ลูกค้าถามเรื่องคืนเงิน → agent เรียก
searchOrderKnowledgeดึงนโยบายคืนเงินเข้ามา (retrieval) - agent เขียนโน้ตว่าเคสนี้เข้าเงื่อนไขคืนเงิน
saveMemory(memory) - บทสนทนายาวจนงบ token เกินเพดาน →
CompactAsyncสรุปประวัติ (compaction) - หลัง compaction agent ยังปิดเคสได้ถูก — ยืนยัน order id และเหตุผลคืนเงินยังอยู่ครบ ที่จำนวน token ต่ำกว่า agent #15 แบบดิบที่ไม่มี context layer
เกณฑ์ผ่านคือข้อ 4: order id + เหตุผลคืนเงินรอดข้าม compaction และ จำนวน input token รวมต่ำกว่า version ดิบอย่างวัดได้ — นี่คือรูปธรรมของ “minimal performance degradation” ที่บทที่ 5 พูดถึง วัดด้วย field usage ตัวเดียวกับบทที่ 4 อย่าเชื่อ ให้วัด
ดาวเหนือ: หนึ่งประโยคที่ร้อยทั้งแปดบท
หัวข้อที่มีชื่อว่า “ดาวเหนือ: หนึ่งประโยคที่ร้อยทั้งแปดบท”context layer ที่คุณเพิ่งประกอบ ไม่ใช่ห้าเทคนิคที่บังเอิญมาอยู่ด้วยกัน แต่เป็นห้าวิธีเข้าใกล้ ดาวเหนือดวงเดียว ที่บทที่ 1 วางไว้ Anthropic ปิดท้ายด้วยประโยคที่ควรจำขึ้นใจ — “Whether you’re implementing compaction for long-horizon tasks, designing token-efficient tools, or enabling agents to explore their environment just-in-time, the guiding principle remains the same: find the smallest set of high-signal tokens that maximize the likelihood of your desired outcome.”
อ่านประโยคนั้นแล้ว map กลับลงบน pipeline ของคุณ: compaction คือ “long-horizon tasks”, curation คือ “token-efficient tools”, retrieval คือ “explore their environment just-in-time” — ทั้งหมดเล็งไปที่ “the smallest set of high-signal tokens” เดียวกัน นี่คือเหตุผลที่ทั้งคอร์สร้อยเป็นเรื่องเดียว ไม่ใช่รายการเทคนิคแยกส่วน
และปลายทางที่ผู้ใหญ่ที่สุดไม่ใช่ “retrieval อย่างเดียว” หรือ “compaction อย่างเดียว” แต่คือการผสม Anthropic เรียกมันว่า hybrid — “the most effective agents might employ a hybrid strategy, retrieving some data up front for speed, and pursuing further autonomous exploration at its discretion.” context layer ของคุณก็เป็นแบบนั้น: นโยบายที่ใช้บ่อยอาจ pre-stuff ไว้ใน system prompt ส่วนที่เหลือค้นเอาตอน runtime และสำหรับ agent ที่รันยาว ให้จับคู่ memory กับ compaction เข้าด้วยกัน — “For long-running agents, consider using both: compaction keeps the active context small without client-side bookkeeping, and memory preserves the information that must survive summarization.”
Anthropic รายงานว่า memory + context editing ให้ “84% token savings and a 39% performance improvement” บน eval หนึ่งชุด (งานค้นเว็บ 100 เทิร์น, กันยายน 2025) — ใช้เป็น ทิศทาง ว่าการจับคู่สองเทคนิคนี้ช่วยได้จริง ไม่ใช่ตัวเลขที่จะได้เป๊ะกับ workload ของคุณ ตัวเลขทุกตัวในคอร์สนี้เป็น “หลักการที่ลงวันที่” ไม่ใช่กฎตายตัว
ปิดอย่างซื่อสัตย์ แล้วส่งไม้ต่อ
หัวข้อที่มีชื่อว่า “ปิดอย่างซื่อสัตย์ แล้วส่งไม้ต่อ”context layer ทำให้ agent เดิมของ #15 เห็นของที่ถูกต้อง ในทุกเทิร์น — แต่มีคำถามหนึ่งที่บทนี้ตอบเองไม่ได้ และไม่ควรแกล้งตอบ: คุณรู้ได้อย่างไรว่า context layer ช่วยจริง ไม่ใช่แค่รู้สึกว่าช่วย? compaction ที่ “รักษาสิ่งที่ชี้ขาด” อาจทิ้งรายละเอียดที่สำคัญไปเงียบๆ retrieval ที่ recall ต่ำอาจพลาดข้อความที่ตัดสินเคส สิ่งเหล่านี้มองด้วยตาไม่เห็น — ต้อง วัด ด้วยชุดประเมินผลที่ออกแบบมา นั่นคืองานของคอร์สถัดไป ไม่ใช่ข้ออ้างที่บทนี้จะสรุปเอง
context layer พร้อมแล้ว จากนี้ต่อได้สี่ทาง:
- ประเมินว่ามันช่วยจริงไหม → คอร์ส #13 Evals สำหรับ AI agent — คำถามธรรมชาติถัดจากบทนี้: compaction ทิ้งรายละเอียดที่ชี้ขาดไปหรือเปล่า retrieval ดึงของที่เกี่ยวมาครบไหม ตอบได้ด้วย eval เท่านั้น
- ขอบเขตของ agent → คอร์ส #12 Agent ในฐานะ bounded context — context layer อยู่ในขอบเขตของ agent หนึ่งตัว เมื่อไหร่ควรแยกเป็นอีก context
- ห่อ tool เป็น server → คอร์ส #14 ออกแบบ MCP server —
searchOrderKnowledgeกับ tool อื่นๆ แพ็กเป็น server ที่ agent ตัวไหนก็ต่อได้อย่างไร - ทบทวน agent ฐาน → คอร์ส #15 สร้าง AI agent ตัวแรกด้วย C# — LLM + tool + loop ที่ context layer นี้คร่อมอยู่
จบคอร์สนี้ คุณไม่ได้มี agent ที่ฉลาดขึ้นเพราะ model ใหญ่ขึ้น แต่มี agent เดิมที่ เห็นของที่ถูกต้อง ในทุกเทิร์น — นั่นคือทั้งหมดที่ context engineering สัญญาไว้ตั้งแต่บทที่ 1
บทนี้อิงต้นทางที่ลงวันที่กำกับ อ่านต่อได้โดยตรง:
- Anthropic, “Effective context engineering for AI agents” (2025-09-29) — ดาวเหนือที่ร้อยทุกเทคนิค (“smallest set of high-signal tokens…”), hybrid strategy เป็นปลายทางที่ผู้ใหญ่ที่สุด และการมองทุกชั้นเป็นการคัดสรร context ต่อเทิร์น
- Anthropic, “Memory tool” docs (เข้าถึง 2026-07-19) — การจับคู่ memory กับ compaction สำหรับ agent ที่รันยาว
- Anthropic, “Context management” (กันยายน 2025) — ตัวเลข 84% token / 39% performance จาก eval 100 เทิร์น (ลงวันที่ไว้ ไม่ใช่กฎ)
- Microsoft Learn, “Use vector stores in .NET AI apps” (ms.date 2026-02-28) —
SearchAsync,VectorSearchOptions<T>และการกรองด้วย property ที่ index ไว้สำหรับคลังเดียวสองบทบาท - Microsoft Learn, “Microsoft.Extensions.AI libraries” (ms.date 2025-12-10, ปรับ 2026-06-18) —
IChatClient,ChatOptions.Tools,UseFunctionInvocationและChatResponse.Usageสำหรับประกอบ pipeline และวัด token
เช็กความเข้าใจ — บทที่ 8
ข้อ 1 / 3ในการประกอบ context layer ทำไม retrieval (บทที่ 2) กับ long-term memory (บทที่ 3) จึงใช้ Vector Store ก้อนเดียวกันได้?