จัดระเบียบผลของ tool
ตั้งแต่บทที่ 2 คุณคิดเรื่อง context ในฐานะสิ่งที่คุณ เลือกใส่ เข้าไป — retrieval ดึงข้อมูลเข้ามา memory เขียนโน้ตกลับมา compaction สรุปประวัติให้สั้นลง แต่มีแหล่ง context อีกก้อนหนึ่งที่มักถูกมองข้าม เพราะมันไม่ได้มาจากมือคุณโดยตรง — มันคือ สิ่งที่ tool ของคุณ คืนกลับมา ในคอร์สที่ 15 getOrder คืน record ออเดอร์ทั้งก้อนเข้า loop ทุก field ในก้อนนั้น — line item ที่อยู่จัดส่ง payment token field audit — เดินทางเข้า context window เท่ากันหมด ไม่ว่า agent จะได้ใช้มันจริงหรือไม่ บทนี้ปรับสายตาอีกองศา: ผลลัพธ์ของ tool คือ context ที่คุณออกแบบได้ และการปั้นมันให้เหลือแต่ของที่จำเป็นคือหนึ่งในการใช้จ่ายงบที่คุ้มที่สุด
บทนี้ปั้น getOrder ตัวเดิมของ agent Order จาก repo kaen-food-ordering (กำลังจัดทำ) ให้คืนเฉพาะ field ที่ support agent ใช้เหตุผลได้จริง แล้ววัดผลต่างของ token ด้วย field usage เทคนิคนี้ต่อยอดจากการเคลียร์ผลของ tool ที่เกริ่นไว้ในบทที่ 5 และใช้เครื่องวัด token ตัวเดียวกับบทที่ 4
ผลของ tool คือ context ที่คุณออกแบบ
หัวข้อที่มีชื่อว่า “ผลของ tool คือ context ที่คุณออกแบบ”เวลาเราพูดถึง “การจัดระเบียบ context” ภาพในหัวมักเป็นการคัด prompt หรือคัดประวัติบทสนทนา แต่ในระบบที่วนเป็น loop ปริมาณ context ก้อนใหญ่ที่สุดที่พอกขึ้นต่อเนื่อง กลับเป็น ผลของ tool — และตรงนั้นแหละที่วิศวกรมักปล่อยตามยถากรรม เพราะโดย default เราเขียน tool ให้ return object ที่มีอยู่ในมือ ซึ่งบ่อยครั้งคือ aggregate ทั้งก้อนจาก repository
การจัดระเบียบผลของ toolTool-result Curationการออกแบบสิ่งที่ tool 'คืนกลับ' ให้เป็น output สัญญาณสูง แทนการทุ่ม JSON ดิบทั้งก้อน — เช่นเปลี่ยน `getOrder` ให้คืน view ที่มีแค่ 3–5 field ที่ agent ใช้เหตุผลจริง (id, status, ลูกค้า, ยอด) payload ที่ tool คืนคือ context ที่เรากำลัง engineer อยู่ ยิ่ง object เล็ก token ยิ่งน้อย โดย agent ยังแก้เคสได้ครบProcess คือการออกแบบ สิ่งที่ tool คืนกลับมา อย่างจงใจ ให้ agent เห็นเฉพาะ field ที่มันต้องใช้เหตุผลจริง ไม่ใช่ทั้ง JSON ก้อน — มองอีกมุมคือ payload ที่ tool คืน ก็คือ context ที่คุณกำลัง engineer ไม่ต่างจาก system prompt หรือผลของ retrieval มันเดินทางเข้า context window ผ่าน block tool_result ใน content[] (แบบเดียวกับที่คุณเห็นในคอร์ส #15) ทุก byte ที่คุณ return เกินความจำเป็น คือ token ที่ไปกิน งบ tokenToken Budgetการมอง context window เป็นงบ token ที่ใช้แล้วหมดและต้องจัดลำดับความสำคัญว่าจะใส่อะไร — เพดานหน้าต่างสูงสุดคือ 'เพดาน ไม่ใช่เป้า' วัดการใช้จริงจาก field `usage` ของ agent (#15) เทิร์นต่อเทิร์นแล้วตัด token สัญญาณต่ำ (เช่น blob JSON ดิบเก่า ๆ) ทิ้งก่อนProcess ของทุกเทิร์นที่เหลือ เพราะผลก้อนนั้นค้างอยู่ในประวัติและถูกส่งกลับเข้า model ซ้ำทุกรอบจนกว่าจะถูกเคลียร์
นี่คือเหตุผลที่ Anthropic จัดให้ tool เป็นคันโยกด้านประสิทธิภาพโดยตรง — “tools promote efficiency, both by returning information that is token efficient and by encouraging efficient agent behaviors.” สังเกตว่าประโยคนี้พูดถึงสองด้าน: คืนผลที่ประหยัด token และ ชักนำให้ agent ทำงานอย่างประหยัด ทั้งคู่ขึ้นกับสิ่งที่ tool คืนกลับมา
ทำไมการคืน aggregate ทั้งก้อนถึงแพง
หัวข้อที่มีชื่อว่า “ทำไมการคืน aggregate ทั้งก้อนถึงแพง”ลองดู getOrder version ที่คุณน่าจะเขียนแบบตรงไปตรงมาที่สุดก่อน:
// ❌ version ดิบ — คืน Order aggregate ทั้งก้อนเข้า contextAITool getOrder = AIFunctionFactory.Create( (string orderId) => repo.Find(orderId), // Order ทั้งก้อน: line items, ที่อยู่จัดส่ง, // payment token, field audit, timestamp ภายใน ฯลฯ name: "getOrder", description: "Look up a food-delivery order.");version นี้ทำงานถูกต้อง — agent ได้ข้อมูลครบ แต่มันคืน ทุกอย่าง ที่ aggregate มี ทั้งที่ support agent ที่กำลังตัดสินใจเรื่องคืนเงินแทบไม่ต้องดู payment token หรือ field audit เลย ทุก field ส่วนเกินนี้:
- กินงบ token ทันที — ก้อน JSON ยิ่งใหญ่ =
tool_resultยิ่งยาว และมันค้างในประวัติ ถูกส่งซ้ำทุกเทิร์นถัดไป งบที่ควรเหลือไว้ให้ผล retrieval หรือประวัติที่สำคัญกว่า ถูก field ที่ไม่ได้ใช้แย่งไป - เจือจางสัญญาณ — ดาวเหนือของทั้งคอร์ส (จากบทที่ 1) คือ “finding the smallest possible set of high-signal tokens that maximize the likelihood of some desired outcome” field ที่ agent ไม่ได้ใช้ไม่ใช่แค่ “เปล่าประโยชน์” แต่มันเป็น noise ที่ model ต้องแบ่งความสนใจไปแยกทิ้ง
- เพิ่มพื้นที่ให้พลาด — payment token หรือข้อมูลส่วนบุคคลที่ไม่จำเป็นต่อการตัดสินใจ ไม่ควรเดินทางเข้า context ตั้งแต่แรกอยู่แล้ว
Anthropic วางกติกาของ tool ที่ดีไว้ชัด — “tools should be self-contained, robust to error, and extremely clear with respect to their intended use.” tool ที่คืน aggregate ทั้งก้อนละเมิดข้อ “clear with respect to their intended use” เพราะมันไม่ได้สื่อว่า agent ควร สนใจ field ไหน มันโยนทุกอย่างให้แล้วปล่อยให้ model เดาเอง
Anthropic ไม่ได้ มีประโยคตรงๆ ว่า tool ควร “คืนผลที่ high-signal” คำว่า “high-signal” เป็นของ ดาวเหนือ ที่พูดถึง token โดยรวม ("smallest possible set of high-signal tokens…") ไม่ใช่กติกาเฉพาะของ tool ดังนั้นหลัก “คืนเฉพาะ field ที่ใช้จริง ไม่ใช่ JSON ทั้งก้อน” คือการ ประยุกต์ แนวทาง token-efficiency ของ Anthropic ลงกับผลของ tool ไม่ใช่การยกประโยคที่มีอยู่แล้วมาอ้าง
ปั้นให้เหลือ view ที่ support agent ใช้จริง
หัวข้อที่มีชื่อว่า “ปั้นให้เหลือ view ที่ support agent ใช้จริง”วิธีแก้ตรงไปตรงมา: อย่าคืน aggregate คืน view ที่มีเฉพาะ field ที่ support agent ใช้เหตุผล — order id, สถานะ, ชื่อลูกค้า, ยอดรวม และเวลาที่สั่ง เท่านั้น ประกาศเป็น record เล็กๆ ตัวหนึ่ง แล้วให้ tool คืนมันแทน:
// ✅ curated — คืนเฉพาะ field ที่ support agent ใช้ตัดสินใจ// OrderStatus คือ enum 7 ค่าจาก domain ฟู้ดเดลิเวอรี (เช่น Placed, Delivered, Cancelled…)record OrderView( string OrderId, OrderStatus Status, string CustomerName, decimal Total, DateTimeOffset PlacedAt);
AITool getOrderView = AIFunctionFactory.Create( (string orderId) => repo.Find(orderId) is { } o ? new OrderView(o.Id, o.Status, o.CustomerName, o.Total, o.PlacedAt) : null, name: "getOrder", description: "Look up a food-delivery order. Returns id, status, customer, total, placed-at only.");จุดที่ต้องสังเกต:
nameยังเป็น"getOrder"เหมือนเดิม — จากมุมของ agent สัญญายังหน้าตาเดิม เปลี่ยนแค่ รูปร่างของผลที่คืน ให้กระชับลง ไม่ต้องแตะ prompt หรือ loopdescriptionบอกชัดว่าคืนอะไรบ้าง — “Returns id, status, customer, total, placed-at only” ทำให้ tool “clear with respect to its intended use” ตามกติกาข้างบน model รู้ล่วงหน้าว่าจะได้ field ไหน- object ที่
AIFunctionFactory.Createคืน ถูก serialize เป็น blocktool_resultในcontent[](invariant เดิมจาก #15 — คำตอบและผลของ tool อยู่ในcontent[]ไม่มี.textระดับบนสุด) object เล็กลง =tool_resultสั้นลง = token น้อยลงตรงๆ - ฝั่ง chat ทุกอย่างเหมือน #15 ทั้งหมด — header
x-api-key(ไม่ใช่Authorization: Bearer),anthropic-version: 2023-06-01, model id เปล่าclaude-opus-4-8(ตัวอย่าง ณ 2026-07), และ ไม่ส่งtemperatureการจัดระเบียบผลของ tool เป็นเรื่องของ payload ที่คืน ไม่แตะการตั้งค่า request เลย
flowchart TB
subgraph RAW["❌ version ดิบ — คืน Order ทั้งก้อน"]
R1["getOrder"] --> R2["JSON ก้อนใหญ่<br/>line items · ที่อยู่ · payment token · audit"]
R2 --> RW["context window<br/>เปลือง token กับ field ที่ไม่ได้ใช้"]
end
subgraph CUR["✅ curated — คืนเฉพาะ 5 field"]
C1["getOrder"] --> C2["OrderView<br/>id · สถานะ · ลูกค้า · ยอด · เวลาสั่ง"]
C2 --> CW["context window<br/>token สัญญาณสูง เหลือที่ว่าง"]
end
classDef bloat fill:#b91c1c,stroke:#7f1d1d,color:#f8fafc;
classDef lean fill:#0891b2,stroke:#064e5b,color:#f8fafc;
class RW bloat;
class CW lean;
คำบรรยายภาพ: บน — getOrder version ดิบคืน JSON ก้อนใหญ่ทั้ง line item ที่อยู่ payment token และ field audit เข้า context window ทุก field กินงบเท่ากันไม่ว่าจะได้ใช้จริงหรือไม่ ล่าง — version curated คืนแค่ OrderView 5 field ที่ support agent ใช้ตัดสินใจ ผลของ tool สั้นลง เหลืองบไว้ให้ context ที่สำคัญกว่า tool ตัวเดิม สัญญาเดิม — เปลี่ยนแค่รูปร่างของสิ่งที่คืนกลับมา
วัดผลต่าง ไม่ใช่เดา
หัวข้อที่มีชื่อว่า “วัดผลต่าง ไม่ใช่เดา”หัวใจของวินัยทั้งคอร์สคือ วัด ไม่ใช่เชื่อ ใช้เครื่องวัด token ตัวเดียวกับบทที่ 4 — field usage — เดินทราน script เดิม 5 เทิร์น สองรอบ เปลี่ยนแค่ว่าผูก getOrder version ดิบหรือ version getOrderView:
// เทิร์นเดียวกัน เปลี่ยนแค่ tool ที่ผูก แล้วอ่าน usagevar options = new ChatOptions { Tools = [getOrderView, getDeliveryStatus, issueRefund] };var reply = await chat.GetResponseAsync(history, options);
// input token ที่ model เห็นในเทิร์นนี้ (จากบทที่ 4)Console.WriteLine($"input tokens: {reply.Usage?.InputTokenCount}");รันเทียบ2 version แล้วคุณจะเห็นสองอย่างพร้อมกัน: (1) จำนวน input token ของ version curated ต่ำกว่าอย่างเห็นได้ และช่องว่างยิ่งถ่างเมื่อประวัติสะสมผลของ tool มากขึ้น เพราะก้อนที่เล็กกว่าถูกส่งซ้ำทุกเทิร์น (2) agent ยัง ปิดเคสได้เหมือนเดิม — ยืนยันสถานะออเดอร์และตัดสินใจคืนเงินได้ครบ เพราะ field ที่มันใช้จริงยังอยู่ นี่คือรูปธรรมของ “ผลลัพธ์เท่าเดิมที่ token น้อยลง” ที่ดาวเหนือเล็งไว้
reply.Usage เป็น UsageDetails และ field อย่าง InputTokenCount จะมีค่าก็ต่อเมื่อ connector ฝั่ง Anthropic เติมค่าให้ (ข้อควรระวังเดียวกับที่กำกับไว้ในบทที่ 4) ถ้าได้ null ให้ถอยไปนับด้วย POST /v1/messages/count_tokens หรือ field usage จาก Messages API ดิบตรงๆ อย่าเดา token ของ Claude ด้วย tiktoken เพราะคนละ tokenizer นับต่ำกว่าจริงราว 15–20%
จับคู่กับการเคลียร์ผลของ tool
หัวข้อที่มีชื่อว่า “จับคู่กับการเคลียร์ผลของ tool”การจัดระเบียบตอนที่ tool คืนผล เป็นด่านแรก แต่ยังมีด่านที่สอง: เมื่อผลก้อนนั้นทำหน้าที่เสร็จแล้ว มันก็ไม่จำเป็นต้องค้างในประวัติอีก ถ้า agent ดึงออเดอร์มาดู ตัดสินใจคืนเงิน และออกคำสั่งคืนเงินไปแล้ว ผลของ getOrder เทิร์นก่อนหน้าก็หมดหน้าที่ — เคลียร์มันออกจากประวัติได้เลย นี่คือ “รูปแบบที่เบาและปลอดภัยที่สุดของ compaction” ที่บทที่ 5 พูดถึง สองเทคนิคนี้เสริมกัน: curation ทำให้แต่ละผลของ tool เล็กตั้งแต่ต้น ส่วนการเคลียร์ทำให้ผลที่ หมดอายุ หลุดออกจากงบ
ดูรายละเอียดการเคลียร์ผลของ tool และ compaction ที่ บทที่ 5 — Compaction สู้ context rot — curation กับการเคลียร์ในบทนั้น คือสองด้านของการดูแลผลของ tool ให้เบาตลอด lifecycle
แล้ว tool ชุด 3 ตัวของเราล่ะ
หัวข้อที่มีชื่อว่า “แล้ว tool ชุด 3 ตัวของเราล่ะ”ระวังอย่าตีความบทนี้ว่า “tool ยิ่งน้อยยิ่งดี” หรือ “ต้องยุบ tool ให้เหลือตัวเดียว” ประเด็นคือ รูปร่างของผลที่คืน ไม่ใช่จำนวน tool ในทางกลับกัน anti-pattern ที่ Anthropic เตือนคือ tool ที่ เยอะและซ้ำซ้อน ต่างหาก — “One of the most common failure modes we see is bloated tool sets that cover too much functionality or lead to ambiguous decision points about which tool to use.”
ชุด getOrder / getDeliveryStatus / issueRefund จากคอร์ส #15 เป็นตัวอย่าง ที่ดี ของข้อนี้อยู่แล้ว — แต่ละตัวมีหน้าที่เดียวชัดเจน ไม่ทับซ้อนกัน model ไม่ต้องลังเลว่าจะเรียกตัวไหน สิ่งที่บทนี้เพิ่มเข้าไปไม่ใช่การลดจำนวน tool แต่คือการทำให้ ผลที่แต่ละตัวคืน ประหยัด token ขึ้น — ชุดที่กระชับดีอยู่แล้ว บวกกับผลที่กระชับขึ้น คือทั้งสองด้านของประโยค “return token efficient + encourage efficient behavior” ที่เปิดบทนี้
บทนี้อิงต้นทางที่ลงวันที่กำกับ อ่านต่อได้โดยตรง:
- Anthropic, “Effective context engineering for AI agents” (2025-09-29) — tool ในฐานะคันโยกด้านประสิทธิภาพ (คืนผลที่ประหยัด token และชักนำพฤติกรรมที่ประหยัด), กติกาของ tool ที่ดี (self-contained, robust to error, ชัดเจนต่อการใช้งาน), anti-pattern ของ bloated tool sets และดาวเหนือ “smallest set of high-signal tokens”
- Microsoft Learn, “Microsoft.Extensions.AI libraries” (ms.date 2025-12-10, ปรับ 2026-06-18) —
AIFunctionFactory.Create,AITool,ChatOptions.ToolsและChatResponse.Usage/UsageDetailsสำหรับวัด token
เช็กความเข้าใจ — บทที่ 6
ข้อ 1 / 3การจัดระเบียบผลของ tool (tool-result curation) หมายถึงอะไร?