29 สิงหาคม 2569 · 22 นาทีในการอ่าน
ทดลองวัดการใช้โทเคนและปรับให้ประหยัดขึ้น
ผมใช้ coding agents ค่อนข้างเยอะในการพัฒนาซอฟต์แวร์ในแต่ละวัน และพอเริ่มรู้สึกถึงข้อจำกัดและลิมิตต่าง ๆ มากขึ้น ผมก็เริ่มสงสัยว่าจริง ๆ แล้วตัวเองใช้โทเคนได้มีประสิทธิภาพแค่ไหน
ยอดใช้งานโดยรวมของผมสูงมาก แต่ตัวเลขรวมอย่างเดียวแทบไม่ได้บอกอะไร ผมอยากรู้
อย่างน้อยก็ในรูปแบบการใช้งานของตัวเอง ว่าโทเคนส่วนใหญ่หายไปกับอะไร กับคำสั่งของผมเอง?
กับ AGENTS.md และคำแนะนำระบบอื่น ๆ? กับเซสชันที่ยาวเกินไป?
หรือกับสิ่งที่ agent ทำหลังจากผมส่งคำขอไปแล้ว?
ตอนนี้มีเครื่องมือสำเร็จรูปสำหรับเรื่องนี้เยอะกว่าเดิมมาก สำหรับ Codex ตัวอย่างหนึ่งคือ ccusage ซึ่งอ่านล็อกเซสชันของ Codex ที่อยู่ในเครื่อง และแสดงการใช้งานแยกตามวัน เดือน และแต่ละเซสชัน รวมถึงโทเคนที่ถูกแคช ได้ ปัจจุบันการรองรับ Codex ยังถูกระบุว่าเป็นเบต้า เพราะรูปแบบล็อกของ Codex CLI ยังมีการเปลี่ยนแปลงอยู่
สำหรับ Claude Code ตัว ccusage
เดียวกันก็อ่านล็อกของ Claude ที่อยู่ในเครื่อง และสร้างรายงานแบบรายวัน รายสัปดาห์
รายเดือน และแยกตามเซสชันได้ ส่วน Claude Code เองก็มีเครื่องมือสำหรับจัดการบริบท
มากขึ้น เช่น /context, การ compact, CLAUDE.md, skills และ subagents
ตอนที่ผมเริ่มเก็บสถิติ ตัวเลือกสำเร็จรูปสำหรับการแยกส่วนแบบละเอียดขนาดนี้ยังมีน้อยกว่า และผมเองก็ไม่ได้ต้องการแค่ยอดใช้งานรวม ผมอยากเข้าใจไม่ใช่แค่ว่าใช้โทเคนไป เท่าไร แต่ใช้ไป กับอะไรภายในเซสชัน
เพราะอย่างนั้นผมจึงทำเครื่องมือตรวจสอบบางส่วนขึ้นมาเอง
ตัวเครื่องมือติดตามที่เขียนเองไม่ใช่ประเด็นหลักของบทความนี้ ถ้าวันนี้ผมต้องการแค่นับการใช้งาน ผมน่าจะเลือกใช้เครื่องมือที่มีอยู่แล้ว สิ่งที่น่าสนใจกว่าคือข้อมูลที่เก็บมาแล้วบอกอะไร
ก่อนเริ่มวัด สิ่งแรกที่ผมสงสัยคือคำสั่งของตัวเอง ผมมักอธิบายงานค่อนข้างละเอียด
นอกจากนั้นยังมี AGENTS.md คำแนะนำระบบที่ถูกโหลดเป็นประจำ และบริบท
ที่เหลือจากขั้นตอนก่อนหน้า มองเผิน ๆ ทั้งหมดนี้ดูเหมือนเป็นส่วนที่น่าจะกินโทเคนมาก
แต่หลังจากคำสั่งแล้ว agent ก็เริ่มรวบรวมบริบทเพิ่มเอง มัน grep โค้ด อ่านไฟล์ หาการใช้งาน (usages) รัน build หรือ tests และรับล็อกกลับมา ก่อนวัดจริง ๆ ผมไม่รู้เลยว่าฝั่งนี้สร้างข้อความเพิ่มขึ้นมามากแค่ไหน
ผมเก็บสถิติอย่างไร
ชุดข้อมูลหลักของผมมาจาก ล็อกเซสชันของ Codex ที่เก็บอยู่ในเครื่อง ผมไม่ได้ต้องการแค่ยอดใช้งานรวม แต่อยากดูแต่ละรอบ แล้วเชื่อมกลับไปได้ว่าตอนนั้นเกิดอะไรขึ้นในเซสชัน
ผมทำ hook เล็ก ๆ ที่ก่อนเริ่มรอบใหม่จะบันทึก snapshot ไว้ในเครื่อง เช่น turn_id
รีโพซิทอรีปัจจุบัน hash ของคำสั่ง ฟิลด์เพิ่มเติมอีกเล็กน้อย และ raw payload
ในกรณีที่ต้องใช้
โฟลว์โดยคร่าว ๆ เป็นแบบนี้:
Codex session
↓
hook
↓
capture metadata
↓
Codex session logs
↓
token_audit.py report
↓
report.json / report.md
ตัว hook ผมตั้งใจทำให้เรียบง่ายที่สุด:
#!/usr/bin/env bash
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
python3 "$SCRIPT_DIR/token_audit.py" capture \
--repo-root "${PWD}" \
--store-raw-payload
ไม่นานผมก็เลิกคิดที่จะคำนวณอะไรซับซ้อนภายใน hook โดยตรง วิธีที่สะดวกกว่าคือบันทึกสถานะ เอาไว้ก่อน แล้วค่อยสร้างรายงานจากข้อมูลที่สะสมไว้ทีหลัง
ตัวอย่าง capture แบบตัดรายละเอียดออกแล้วมีหน้าตาประมาณนี้:
import hashlib
import json
import sys
from datetime import datetime, timezone
from pathlib import Path
raw = sys.stdin.read()
payload = json.loads(raw) if raw.strip() else {}
prompt = payload.get("prompt", "")
repo_root = Path(payload.get("cwd") or ".").resolve()
record = {
"captured_at": datetime.now(timezone.utc).isoformat(),
"turn_id": payload.get("turn_id"),
"repo_root": str(repo_root),
"prompt_preview": prompt[:240],
"prompt_hash": (
hashlib.sha1(prompt.encode("utf-8")).hexdigest()
if prompt else ""
),
}
audit_dir = repo_root / ".token-audit"
audit_dir.mkdir(exist_ok=True)
with (audit_dir / "hook-captures.jsonl").open("a", encoding="utf-8") as handle:
handle.write(json.dumps(record, ensure_ascii=False) + "\n")
ในสคริปต์จริงมีฟิลด์มากกว่านี้เล็กน้อย เช่น branch ขนาดของ repo instructions
handoff files ที่อยู่ใกล้ ๆ และ raw payload แต่หลักการเหมือนเดิม: hook มีหน้าที่บันทึก
สถานะของแต่ละรอบ ส่วนคำสั่ง report อีกตัวค่อยทำงานกับล็อก
ผมรันรายงานแยกต่างหาก:
python3 ./tools/token_audit.py report \
--repo-root "$PWD"
จากนั้นจะได้โครงสร้างประมาณนี้:
.token-audit/
├── hook-captures.jsonl
├── raw-hook-payloads/
└── latest-report/
├── report.json
└── report.md
คำสั่ง report จะไล่อ่านล็อกเซสชัน จับคู่กับ captures แล้วแบ่งข้อมูลใหม่ที่เข้ามา
ออกเป็นหลายหมวด:
- คำสั่งของผู้ใช้ (user prompts);
- คำแนะนำระบบ (developer instructions);
- การโหลด repo ตอนเริ่ม (repo bootstrap);
- อาร์กิวเมนต์ที่ส่งให้ tool (tool call arguments);
- ผลลัพธ์จาก tool (tool outputs);
- loopback จากตัว assistant เอง (assistant loopback).
ส่วนข้อมูลที่ถูกแคช (cached input) ผมนับแยกต่างหาก
นี่ไม่ใช่การสังเกตการณ์ระดับ production และไม่ใช่ระบบเก็บเงิน รูปแบบล็อก อาจเปลี่ยนได้ การจัดหมวดบางส่วนขึ้นอยู่กับ client ที่ใช้ และตัวสคริปต์เองก็ต้องดูแลต่อ สำหรับสิ่งที่ผมต้องการถือว่าเพียงพอ ผมต้องการเห็นโครงสร้างของการใช้งาน และเปรียบเทียบช่วงเวลาต่าง ๆ
สุดท้ายผมเก็บข้อมูลได้ 5,420 รอบจากการใช้งาน 120 วัน
ผลที่ได้
การแยกส่วนที่น่าสนใจที่สุดออกมาแบบนี้:
แหล่งที่มา สัดส่วน
ผลลัพธ์จาก tool 67.4% Loopback จาก assistant 17.9% อาร์กิวเมนต์ที่ส่งให้ tool 8.3% คำสั่งของผู้ใช้ 4.6% คำแนะนำระบบ 1.43% การโหลด repo ตอนเริ่ม 0.34%
ผลออกมาต่างจากที่ผมคาดไว้พอสมควร
คำสั่งที่ผมเขียนเองมีแค่ 4.6% ต่อให้สมมติว่าผมสามารถตัดคำสั่ง ทุกอันให้สั้นลงครึ่งหนึ่งได้ ภาพรวมก็ไม่ได้เปลี่ยนมากนัก
ในทางกลับกัน 67.4% ของข้อมูลใหม่ที่เข้ามามาจากผลลัพธ์ tool
พอเห็นตัวเลขแล้วก็เข้าใจได้ไม่ยาก ในเซสชันปกติ agent รับข้อความกลับมาตลอด เปิดไฟล์ก็ได้ข้อความ ทำ grep ก็ได้ผลลัพธ์ รัน tests ก็ได้ข้อความอีกก้อน บางครั้งสั้น แต่บางครั้งยาวมาก
ก่อนวัด ผมมองสิ่งเหล่านี้เป็นเหมือนงานภายในของ agent มากกว่า ขนาดของคำสั่ง สังเกตง่ายเพราะผมเป็นคนเขียนเอง แต่ผลการค้นหา ที่คืนมาหลายร้อยบรรทัดไม่ได้ให้ความรู้สึกว่าเป็นค่าใช้จ่ายอีกก้อนหนึ่งแบบเดียวกัน
แต่ข้อความเหล่านั้นทั้งหมดก็เข้าไปในบริบท และบางส่วนยังอยู่ต่อไปในรอบถัดไป
แม้แต่ grep ธรรมดาก็มีต้นทุน
เรื่องนี้เห็นชัดเป็นพิเศษตอนทำการรีแฟกเตอร์ขนาดใหญ่และงานแยกโมดูล
ถ้าโครงสร้างคงที่และ agent รู้อยู่แล้วว่าโค้ดที่เกี่ยวข้องอยู่ตรงไหน ทุกอย่างค่อนข้างง่าย แต่ถ้าไฟล์กำลังถูกย้ายระหว่างโมดูล และ dependencies กำลังเปลี่ยน agent ที่เพิ่งเริ่มใหม่ ก็มีเหตุผลที่จะเริ่มประมาณนี้:
rg "Checkout"
ได้ผลลัพธ์มาหลายสิบรายการ แล้วหา protocol ต่อ:
rg "PaymentRouting"
จากนั้นหา implementation หาการใช้งาน (usages) แล้วเปิด router, view model และอาจเปิดโมดูลข้างเคียงเพื่อดูว่าใครเป็นเจ้าของโฟลว์จริง ๆ
ทั้งหมดนี้เป็นการทำงานปกติ ถ้าผมต้องสำรวจส่วนที่ไม่คุ้นเคยในโค้ดเบส ผมก็คงทำคล้าย ๆ กัน ความต่างคือสำหรับ agent ผลลัพธ์จากการค้นหาเหล่านี้กลายเป็นส่วนหนึ่งของบริบทด้วย
ผมจึงลองลดการสำรวจซ้ำ ๆ ด้วยการทำแผนที่สั้น ๆ ของโมดูลสำคัญ ไม่ใช่ เอกสารของทั้งโปรเจกต์ แต่เป็นไฟล์เล็ก ๆ ที่บอกจุดสำคัญของส่วนที่ agent มักเริ่มค้นหาใหม่ตั้งแต่ศูนย์ซ้ำ ๆ
ตัวอย่างเช่น:
## Checkout
Responsibility:
Checkout owns the flow from cart confirmation
to the final order result.
Entry points:
- CheckoutView.swift
- CheckoutViewModel.swift
- CheckoutRouter.swift
Navigation:
- CheckoutRouter.swift
Owns checkout navigation and creates child flows.
State:
- CheckoutViewModel.swift
Handles UI actions and checkout state updates.
Payment:
- RetryPaymentAction.swift
Retry entry point after a failed payment.
- PaymentGatewayClient.swift
Payment API only. Does not own navigation.
Boundaries:
- CheckoutRouter owns navigation.
- Payment module owns payment implementation.
- Cart owns price calculation.
If payment retry is broken:
1. Check RetryPaymentAction.
2. Check state update in CheckoutViewModel.
3. Check routing in CheckoutRouter.
4. Only then search the whole Checkout module.
ชื่อไฟล์ในตัวอย่างนี้เป็นเพียงตัวอย่าง สิ่งสำคัญคือโครงสร้าง
ไฟล์แบบนี้ไม่ควรพยายามอธิบายทุกคลาสให้ agent โค้ดยังต้องถูกอ่านอยู่ดี หน้าที่ของมันคือช่วยตอบคำถามสองสามข้อก่อนเริ่มค้นหาแบบกว้าง ๆ: entry point อยู่ไหน ใครเป็นเจ้าของ navigation, state อยู่ตรงไหน และควรเริ่มดูจากอะไร
สำหรับโมดูลที่ซับซ้อน วิธีนี้มีประโยชน์พอสมควร agent ยังสำรวจโค้ดเหมือนเดิม แต่ไม่ต้องเริ่มทุกครั้งด้วยการค้นหาทั่วทั้งโปรเจกต์
อย่างไรก็ตาม แผนที่แบบนี้ก็ขยายไปเรื่อย ๆ ไม่ได้ ถ้าใส่ทุกอย่างที่เคยมีประโยชน์ลงไป สุดท้ายมันจะกลายเป็นเอกสารภายในอีกชุดที่ต้องอ่าน ต้องดูแล และต้องคอยทำให้ตรงกับโค้ด ผมจึงเก็บเฉพาะจุดอ้างอิงที่ช่วยลดการค้นหาซ้ำจริง ๆ
ส่วน AGENTS.md ให้ผลต่างออกไปเล็กน้อย
ก่อนวัด ผมแทบจะแน่ใจว่า AGENTS.md กินโทเคนในสัดส่วนที่เห็นได้ชัด
เหตุผลง่ายมาก: มันถูกโหลดอยู่เป็นประจำ ดังนั้นเนื้อหาข้างในจึงกลายเป็นส่วนหนึ่งของบริบท ในทุกเซสชัน
Matt Pocock แนะนำไว้ในบทความเกี่ยวกับ
AGENTS.md
ว่าควรมองไฟล์นี้เป็นสรุปสั้นมากกว่าเอกสารเต็ม: เขียนให้สั้นและเป็นข้อกำหนดที่ชัดเจน
ส่วนข้อมูลเฉพาะทางค่อยเปิดให้ agent ใช้เมื่อจำเป็นจริง ๆ
โดยรวมผมเห็นด้วย แต่ในข้อมูลของผม AGENTS.md ไม่ได้เป็นปัญหาหลักเลย:
คำแนะนำระบบ, 1.43%
การโหลด repo ตอนเริ่ม, 0.34%
รวมกันแล้วน้อยกว่า 2% ของข้อมูลใหม่ที่เข้ามา
ไม่ได้แปลว่า AGENTS.md จะยาวเท่าไรก็ได้ สำหรับผม
ผลนี้แค่บอกว่าไม่มีเหตุผลมากนักที่จะเริ่มการปรับปรุงจากตรงนี้ ในขณะที่ผลลัพธ์ tool
อยู่ที่ 67.4%
ภายหลังผมก็ยังกลับไปจัดไฟล์นี้ใหม่อยู่ดี คำแนะนำบางอย่างใช้เฉพาะกับงานบางประเภท เช่น กฎสำหรับการแยกโมดูล หรือโฟลว์เฉพาะ ไม่มีเหตุผลที่จะโหลดทั้งหมดเข้ามาในทุกเซสชัน
ผมจึงย้ายบริบทบางส่วนไปไว้ใน skills
Matt Pocock มีบทความอีกชิ้นชื่อ Writing for Agents และชุด AI Skills for Real Engineers แนวคิดบางส่วนสามารถนำมาใช้ได้ทั้งกับ Claude และ Codex แม้ว่ากลไกจริงของแต่ละตัวจะไม่เหมือนกันทั้งหมด
กฎของผมสำหรับ AGENTS.md จึงกลายเป็นคำถามง่าย ๆ ไม่ใช่ “ยังลบได้อีกสิบบรรทัดไหม?”
แต่เป็น “agent ต้องใช้ข้อมูลนี้ในทุกเซสชันจริงหรือเปล่า?”
บางครั้งคำแนะนำที่ละเอียดขึ้นก็คุ้มกับโทเคนที่เพิ่มขึ้น ถ้าอีกไม่กี่บรรทัดช่วยบอก
ownership ได้ตั้งแต่ต้นและลดการค้นหาทั่วรีโพซิทอรีหลายรอบ การย่อมันเพียงเพื่อทำให้
AGENTS.md สั้นลงก็ไม่ได้มีประโยชน์มากนัก
เรื่องเซสชันยาวคาดเดาได้มากกว่า
เซสชันจะสะสมประวัติไปเรื่อย ๆ
agent ค้นหาบางอย่าง ทดลองสมมติฐาน เจอข้อผิดพลาด ลองอีกวิธี อ่านหลายไฟล์ ทั้งหมดนี้มีประโยชน์ในตอนที่เกิดขึ้น แต่ปัญหาอาจถูกแก้ไปแล้ว ในขณะที่ประวัติยังอยู่
ช่วงการค้นคว้าสร้างบริบทส่วนเกินแบบนี้เยอะมาก เราอาจใช้เวลาตรวจหลายสาเหตุที่เป็นไปได้ แล้วสุดท้ายพบว่าต้นตอจริง ๆ อยู่ที่อีกจุดหนึ่ง สำหรับขั้นตอนถัดไป สิ่งที่สำคัญมักเหลือเพียงผลสุดท้าย: สาเหตุอยู่ตรงนี้ ไฟล์ที่เกี่ยวข้องมีอะไรบ้าง และมีข้อจำกัดอะไรที่ห้ามทำพัง
สมมติฐานเก่าที่ผิดไปแล้วส่วนใหญ่ไม่มีประโยชน์กับเซสชันใหม่
สำหรับงานที่ยาว ผมมี context.md เอาไว้ใช้ต่อระหว่างเซสชัน
ตอนแรกผมทำผิดแบบที่ค่อนข้างเห็นได้ชัด: ผมใช้มันเป็นสมุดบันทึก
## Session 1
Checked payment flow.
Looked at CheckoutViewModel and PaymentService.
First assumption was wrong because...
Build failed with...
## Session 2
Moved implementation.
Found another issue in...
Tried...
พอเวลาผ่านไป ไฟล์เริ่มกลายเป็นบันทึกของงานทั้งหมดที่ผ่านมา ผลคือเซสชันใหม่ได้รับ บริบทเก่าส่วนใหญ่กลับมาอีกครั้ง เพียงแค่เปลี่ยนรูปแบบ
ผมจึงเลิกเติม context.md ต่อไปเรื่อย ๆ แล้วเปลี่ยนเป็นเขียนมันใหม่ให้เหลือเฉพาะสถานะปัจจุบัน
## Current state
Payment retry works, but checkout confirmation
is not refreshed after successful retry.
## Decisions
- Retry logic stays in Checkout.
- Payment module only performs payment operations.
- Navigation stays in CheckoutRouter.
## Important
Refreshing state directly from the view caused
duplicate requests. Do not repeat this approach.
## Relevant files
- CheckoutViewModel.swift
- CheckoutRouter.swift
- RetryPaymentAction.swift
## Next
Trace state update after successful RetryPaymentAction.
โดยปกติข้อมูลประมาณนี้ก็เพียงพอให้เซสชันใหม่ทำงานต่อได้โดยไม่ต้องรับประวัติทั้งหมด
ผมไม่ได้ลบอดีตทุกอย่าง ถ้า agent เคยเดินไปตามทางที่ดูสมเหตุสมผลแต่ผิด และมีโอกาสสูงว่า agent ตัวใหม่จะทำซ้ำ การทิ้งบันทึกสั้น ๆ ไว้ก็มีประโยชน์ เพียงแต่ไม่จำเป็นต้องยกกระบวนการทั้งหมดที่นำไปสู่ข้อสรุปนั้นมาด้วย
ภายหลังผมเจอแนวคิดเกือบเหมือนกันใน /handoff
skill ของ Matt Pocock
Matt Pocock ใช้คำอธิบายที่ผมชอบมาก: portability, not compression เป้าหมายของการส่งต่อ (handoff) ไม่ใช่การสร้างฉบับย่อที่ครบที่สุดของเซสชันก่อนหน้า แต่คือการให้ข้อมูลกับ agent ตัวใหม่มากพอที่จะทำงานต่อได้
สำหรับ Claude สามารถใช้ skill นี้ได้ค่อนข้างตรง ๆ ส่วนใน Codex ผมมี การพัฒนาของตัวเอง แต่หลักคิดเหมือนกัน
เมื่อไรเริ่มเซสชันใหม่ง่ายกว่า
หลังจากนั้นผมเริ่มใช้เซสชันใหม่บ่อยขึ้น
ก่อนหน้านี้ผมไม่อยากเสียบริบทที่สะสมมาแล้ว แต่ในทางปฏิบัติ เมื่อจบขั้นตอนหนึ่งของงาน เรามักต้องใช้เพียงส่วนเล็ก ๆ ของบริบทนั้น
สมมติโฟลว์ของงานเป็นประมาณนี้:
research
→ root cause found
→ implementation
→ validation
ก่อนเริ่ม implementation ผมไม่จำเป็นต้องมีทุกผลลัพธ์จาก rg ทุกไฟล์ที่เคยเปิด หรือทุก
สมมติฐานก่อนหน้า หลายครั้งข้อความประมาณนี้ก็พอ:
Root cause is in RetryPaymentAction.
State must be updated through CheckoutViewModel.
CheckoutRouter owns navigation.
Do not refresh directly from the view:
it causes duplicate requests.
Next: implement state refresh after successful retry.
จากนั้นก็เปิดเธรดใหม่แล้วทำต่อได้
ผมไม่ได้ทำแบบนี้ทุก ๆ ไม่กี่ข้อความ บางครั้งทำต่อในเซสชันเดิมก็ง่ายกว่า แต่ตอนนี้ผมจะไม่เก็บเธรดเก่าไว้เพียงเพราะเสียดายประวัติที่สะสมอยู่ในนั้น
การใช้งานเปลี่ยนไปอย่างไร
ตลอดช่วงที่เก็บข้อมูล ค่าเฉลี่ยข้อมูลใหม่ที่เข้ามาต่อรอบลดลงค่อนข้างชัดเจน
ในช่วงก่อนหน้าช่วงหนึ่งอยู่ที่ประมาณ 54.6K โทเคนต่อรอบ ส่วนช่วงหลังอยู่ที่ประมาณ 29.7K
ต่างกันประมาณ 46%
ข้อมูลที่ถูกแคชเปลี่ยนน้อยกว่ามาก: ประมาณ 652K → 583K ต่อรอบ
แต่ข้อมูลชุดนี้ไม่สามารถแยกได้ว่าการเปลี่ยนแปลงแต่ละอย่างช่วยเท่าไร นี่ไม่ใช่ A/B test งานที่ทำเปลี่ยนไป ความซับซ้อนของเซสชันไม่เท่ากัน และปริมาณการใช้งานในแต่ละช่วงก็แตกต่างกัน
ดังนั้นผมไม่สามารถบอกได้ว่ากี่เปอร์เซ็นต์มาจากแผนที่โมดูล กี่เปอร์เซ็นต์มาจากเซสชันใหม่ และกี่เปอร์เซ็นต์มาจากการส่งต่อที่สั้นลง
ผมมองตัวเลข 46% เป็นแนวโน้มโดยรวม ไม่ใช่หลักฐานว่าเทคนิคใดเทคนิคหนึ่งลดการใช้งาน ได้เท่านั้น
สำหรับผม การแยกส่วนมีประโยชน์มากกว่า เพราะมันบอกว่าควรไปมองปัญหาตรงไหน เมื่อ 67.4% ของข้อมูลใหม่ที่เข้ามามาจากผลลัพธ์ tool การทดลองปรับการค้นหา การอ่านไฟล์ และประวัติเซสชันย่อมสมเหตุสมผลกว่าการพยายามประหยัดอีกไม่กี่โทเคนจากคำสั่ง
แล้ว Claude ล่ะ?
ตัวเลขหลักในบทความนี้มาจากล็อกเซสชันของ Codex ผมตั้งใจแยกเรื่องนี้ให้ชัด เพราะสถิติจาก agent ตัวหนึ่งไม่ควรถูกนำไปใช้กับอีกตัวโดยอัตโนมัติ
แต่แนวคิดทั่วไปนำไปใช้ต่อได้ค่อนข้างดี
Claude Code ตอนนี้มี /context, การ compact, skills และ subagents ตัวอย่างเช่น
subagents ช่วยแยกงานค้นคว้าบางส่วนออกจากเซสชันหลัก
แล้วส่งกลับมาเฉพาะผลลัพธ์ที่จำเป็น
สำหรับการติดตามการใช้งาน สามารถใช้ ccusage ตัวเดียวกันอ่านล็อกของ Claude Code ในเครื่องได้
อีกอย่างที่มีประโยชน์คือ Claude Code status line ของ Matt Pocock ซึ่งแสดงเปอร์เซ็นต์ของ context window ที่ใช้ไปแล้วตรงเทอร์มินัล
status line ไม่ได้ปรับอะไรให้เอง แต่ทำให้เราเห็นสถานะของเซสชัน ตลอดเวลา เช่น:
context: 37%
หรือ:
context: 82%
จึงตัดสินใจได้ง่ายขึ้นว่าจะทำต่อในเซสชันเดิม จะ compact หรือเตรียมส่งต่อ
/handoff ของ Matt Pocock
ช่วยในส่วนการส่งสถานะปัจจุบันให้ agent ใหม่ ส่วนคำแนะนำ
เฉพาะทางสามารถเก็บไว้ใน skills แทนที่จะค่อย
ๆ เปลี่ยน CLAUDE.md หรือ AGENTS.md ให้กลายเป็นเอกสารของทั้งโปรเจกต์
ภายหลังผมนำแนวคิดบางส่วนเหล่านี้กลับมาใช้กับ Codex ด้วย ไม่ได้ย้ายมาแบบหนึ่งต่อหนึ่งในระดับ hooks หรือคำสั่ง แต่ใช้เป็นแนวทางทั่วไปในการจัดบริบท
ถ้าเป็นตอนนี้ ผมจะเขียนตัวติดตามนี้เองอีกไหม?
ถ้าเป้าหมายมีแค่ดูยอดใช้งานรวม ก็คงไม่
สำหรับ Codex และ Claude Code ตอนนี้ ccusage สามารถอ่านข้อมูลในเครื่อง แสดงการใช้งาน และ export JSON เพื่อนำไปวิเคราะห์ต่อได้แล้ว
สคริปต์ของผมมีประโยชน์เพราะผมไม่ได้อยากตอบแค่คำถามว่า:
ผมใช้โทเคนไปเท่าไร?
ผมอยากรู้ว่า:
การใช้งานนี้ประกอบขึ้นมาจากอะไร?
สองคำถามนี้ไม่เหมือนกันเสียทีเดียว
สำหรับคำถามแรก เครื่องมือติดตามการใช้งานที่มีอยู่แล้วก็เพียงพอในตอนนี้ ส่วนคำถามที่สอง การลงไปดูภายในเซสชันยังมีประโยชน์ เพราะเราอาจพบว่าคำสั่งยาว ๆ ที่ดูน่าสงสัยมีสัดส่วนเพียง 4.6% ขณะที่ข้อมูลใหม่ที่เข้ามาส่วนใหญ่จริง ๆ มาจากอีกที่หนึ่ง
สำหรับผม นี่คือผลลัพธ์ที่มีประโยชน์ที่สุดจากการทดลองทั้งหมด
ก่อนวัด ผมแทบจะแน่นอนว่าจะเริ่มจากการย่อคำสั่งและ AGENTS.md
หลังจาก 5,420 รอบ ผลออกมาเป็น:
- คำสั่งของผู้ใช้: 4.6%;
- คำแนะนำระบบ + การโหลด repo ตอนเริ่ม, น้อยกว่า 2%;
- ผลลัพธ์จาก tool: 67.4%.
นี่เป็นตัวเลขจากการใช้งานของผม ไม่ใช่สถิติสากลสำหรับ coding agent ทุกตัว โปรเจกต์อื่นหรือรูปแบบการใช้งานที่ต่างออกไปอาจได้การกระจายที่ต่างกันมาก
แต่หลังจากเห็นข้อมูลนี้ ผมกังวลกับคำสั่งยาว ๆ น้อยลง
ถ้ารายละเอียดเหล่านั้นมีประโยชน์จริง ถ้าอีกสองสามย่อหน้าช่วยบอก agent
ได้ทันทีว่าควรเริ่มจาก CheckoutRouter.swift แทนที่จะค้นหากว้าง ๆ
ไปทั่วทั้งโปรเจกต์ การย่อคำสั่งเพียงเพื่อประหยัดโทเคนก็ไม่ได้มีเหตุผลมากนัก
ตอนนี้สิ่งที่ผมดูมากกว่าคือขนาดของผลการค้นหา การอ่านไฟล์ และผลลัพธ์ tool อื่น ๆ