Agent รันมาหกนาทีแล้ว สปินเนอร์ยังหมุนอยู่ พอผมสั่งหยุดมัน /info สรุปบิลไว้ที่ $4.18 และ /report นับการเรียกใช้เครื่องมือได้แปดสิบเก้าครั้ง กับงานที่ผมประเมินไว้ว่าแค่สามครั้งกับไม่กี่เซนต์ มันอ่านไฟล์เดิมไปสิบเอ็ดรอบ มัน grep หาสัญลักษณ์ตัวหนึ่ง ได้ผลลัพธ์ว่าง เรียบเรียง grep ใหม่ ได้ผลลัพธ์ว่างอีก แล้วก็ทำแบบนี้ไปเรื่อย ๆ — อย่างสุภาพ อย่างมั่นใจ อย่างแพง — เพราะไม่มีอะไรในลูปบอกให้มันหยุด

ส่วนที่แย่ที่สุดไม่ใช่สี่ดอลลาร์ แต่คือผมไม่รู้เลยว่า ทำไม จนกว่าจะลงไปหา Agent ไม่โยน stack trace ออกมาเวลามันออกนอกลู่ มันไม่แครช มันแค่เงียบ ๆ ทำสิ่งที่ผิด รายงานว่าสำเร็จ แล้วยื่นบิลให้คุณ จากภายนอก รันที่ยอดเยี่ยมกับรันที่หายนะหน้าตาเหมือนกันเป๊ะ: ข้อความไหลผ่าน เครื่องมือทำงาน คำตอบสุดท้ายหนึ่งคำตอบ

โพสต์นี้คือเครื่องมือวัดที่ผมหวังว่าได้ต่อไว้ก่อนรันนั้น ไม่ใช่หลังจากนั้น ทั้งหมดนี้มาพร้อม Octomind รันไทม์ agent ภาษา Rust แบบโอเพนซอร์สของเรา และส่วนสุดท้ายเพิ่ม OctoHub ไว้ด้านหน้า เพื่อจับสิ่งเดียวที่ตัว agent เองแสดงให้ดูไม่ได้: ไบต์ดิบที่ส่งถึงโมเดลจริง ๆ


ทำไม Agent ถึงล้มเหลวอย่างเงียบ ๆ

ซอฟต์แวร์แบบดั้งเดิมล้มเหลวเสียงดัง null deref, 500, assertion ที่พัง — ความล้มเหลวมีรูปร่าง มีตำแหน่ง มีหมายเลขบรรทัด ความล้มเหลวของ agent ไม่มีสิ่งเหล่านั้นเลย เพราะในมุมมองของรันไทม์ ไม่มีอะไรล้มเหลว ทุกการเรียก API คืน 200 ทุกเครื่องมือออกด้วยโค้ด 0 โมเดลผลิตข้อความที่ถูกไวยากรณ์และดูสมเหตุสมผลในทุกขั้น พฤติกรรม โดยรวม ผิด แต่ไม่มีปฏิบัติการเดี่ยว ๆ ตัวไหนผิดเลย

ในทางปฏิบัติ ความล้มเหลวรวมกลุ่มเป็นสี่รูปแบบ และแต่ละแบบมองไม่เห็นพอดีในจังหวะที่คุณอยากจะจับมันได้:

  • ผิดเครื่องมือ แต่มั่นใจถูก โมเดลคว้า grep ทั้งที่ควรอ่านไฟล์ หรือยิงไปที่ shell ทั่วไปทั้งที่มีเครื่องมือเฉพาะวางอยู่ตรงนั้น มันไม่ลังเลเลย — การเลือกเครื่องมือผิดจากภายนอกหน้าตาเหมือนการเลือกถูกเป๊ะ (เราเขียนบทความเต็ม ๆ เรื่องการลดพื้นที่เครื่องมือเพื่อสู้กับเรื่องนี้: MCP ที่ปรับแต่งเองควรอยู่ในรีโปของคุณ)
  • การตัดทอนคอนเท็กซ์ บทสนทนาโตเกินหน้าต่าง การบีบอัดทำงาน และข้อเท็จจริงที่ agent ต้องใช้ก็ถูกย่อจนหายไป ตอนนี้มันให้เหตุผลจากความจำที่สูญเสียข้อมูล และคุณก็มองไม่เห็นรอยต่อ
  • ลูปที่ควบคุมไม่อยู่ ผลลัพธ์ว่าง → เรียบเรียงใหม่ → ผลลัพธ์ว่าง → เรียบเรียงใหม่ แต่ละเทิร์นดูสมเหตุสมผลเดี่ยว ๆ ตัวแพตเทิร์นเองคือบั๊ก และคุณสังเกตได้แค่จากจำนวนการเรียกเครื่องมือ
  • โทเคนระเบิด เครื่องมือตัวหนึ่งเทไฟล์ขนาด 200KB ลงคอนเท็กซ์ หรืออาร์กิวเมนต์ของการเรียกเครื่องมือตัวหนึ่งบวมขึ้น และตอนนี้ทุกเทิร์นถัดไปก็ส่งทั้งหมดนั้นซ้ำ ต้นทุนกลายเป็นซูเปอร์ลิเนียร์ และอาการเดียวคือใบแจ้งหนี้

คุณดีบักสิ่งที่มองไม่เห็นไม่ได้ ดังนั้นงานแรกคือทำให้รันสังเกตได้ — ทั้งหลังเกิดเหตุและระหว่างทาง


ระดับ 0: /info — เงินหายไปไหน

คำถามที่ตอบได้เร็วที่สุดคือ "เซสชันนี้ใช้เงินจริง ๆ เท่าไร และในรูปแบบไหน" ภายในเซสชันแบบโต้ตอบใด ๆ /info:

╭ /info
│ session  my-feature-x
│ model       openrouter:anthropic/claude-sonnet-5
│ tokens      214,883 total
│ breakdown   18,402 in · 9,114 out · 184,201 cache rd · 2,890 cache wr · 276 reasoning
│ cost        $4.18661
│ throughput  41.3 tok/s
╰ /info  my-feature-x

ทุกฟิลด์ที่นี่คือการวินิจฉัย ตัวที่แกะเคสลูปควบคุมไม่อยู่ของผมออกคือแถว breakdown 184,201 cache rd เทียบกับ 18,402 in หมายความว่าคอนเท็กซ์เดิมถูกอ่านซ้ำเกือบทุกเทิร์น — ลายเซ็นของลูปที่เอาแต่ต่อท้ายโดยไม่เคยจบ ส่วนจำนวนการเรียกใช้เครื่องมือที่ยืนยันเรื่องนี้อยู่ลึกลงไปอีกระดับ ใน /report

/info ยังแจกแจงค่าใช้จ่ายนอกเหนือจากลูปหลักด้วย — โทเคนและต้นทุนของโมเดลบีบอัดเอง การวางมาร์กเกอร์แคชพร้อมยอดอ่าน/เขียน ซับเอเจนต์ใด ๆ และ supervisor ต่างมีเซกชันของตัวเอง — ดังนั้นเมื่อบิลสูง คุณจะเห็นว่าบทสนทนาหลักหรือกระบวนการเบื้องหลังเป็นตัวกิน

ถ้าเซสชันเคยบีบอัดแม้แต่ครั้งเดียว /info จะแสดงบล็อก compression: บีบอัดไปกี่ครั้ง ลบข้อความไปเท่าไร ประหยัดโทเคนไปเท่าไร อัตราส่วนเฉลี่ย นั่นคือสัญญาณเตือนล่วงหน้าเรื่องการตัดทอน ถ้าคุณเห็นการบีบอัดระดับโปรเจกต์สามครั้งในเซสชันสั้น ๆ แสดงว่า agent ลืมอะไรไปแล้ว และควรรู้ก่อนจะไว้ใจข้อสรุปของมัน


ระดับ 1: /report — ต้นทุนต่อคำขอ ไม่ใช่ต่อเซสชัน

/info คือยอดรวมของเซสชัน /report คือใบเสร็จแยกรายการ — หนึ่งแถวต่อหนึ่งคำขอของผู้ใช้ สร้างใหม่จากบันทึกเซสชัน:

╭ /report
│ #   request                          cost      tools  task     ai       proc
│ ──  ───────────────────────────────  ────────  ─────  ───────  ───────  ───────
│  1  add a health-check endpoint      $0.04120      3   18s      12s      1s
│  2  wire it into the router          $0.02980      2   11s      9s       1s
│  3  why is the test flaky            $3.98120     84   5m 31s   3m 40s   20s
│ ──  ───────────────────────────────  ────────  ─────  ───────  ───────  ───────
│  Σ  3 request(s)                     $4.05220     89   6m 00s   4m 01s   22s
╰ /report  3 request(s) · $4.05220

นั่นไง คำขอที่ 3 — "why is the test flaky" — คือบิลทั้งหมด การเรียกเครื่องมือแปดสิบสี่ครั้งสำหรับคำถามเดียว คำขอที่ประพฤติดีสองอันขนาบหายนะหนึ่งอันไว้ และถ้าไม่มีการแยกต่อคำขอ ทั้งสามก็เบลอรวมเป็นยอดเซสชันเดียวกัน /report คือวิธีที่คุณหาว่า พรอมต์ไหน ที่ส่ง agent ออกนอกราง ซึ่งเป็นคำถามที่คุณต้องตอบจริง ๆ ก่อนจะแก้อะไรได้

คอลัมน์แยกเวลา task (ทั้งคำขอ ตั้งแต่ต้นจนจบ) ออกจากเวลา ai (เฉพาะการเรียกโมเดล) เมื่อ task เกิน ai ไปมาก แสดงว่าเครื่องมือของคุณช้า เมื่อทั้งสองวิ่งไล่กัน แสดงว่าโมเดลกำลังวิ่งไปกลับเยอะ — ลายเซ็นลูปอีกครั้ง


ระดับ 2: /context — อ่านว่าจริง ๆ แล้ว agent กำลังคิดเรื่องอะไร

ต้นทุนและตัวนับบอกคุณว่า มี บางอย่างผิด การจะเห็นว่า อะไร คุณต้องอ่านข้อความ /context ดัมป์บทสนทนาสด ๆ เป็น JSON ที่มีโครงสร้าง พร้อมตัวกรอง:

/context              # ทั้งหมด
/context large        # เฉพาะข้อความเกิน 1000 ตัวอักษร — หาตัวกินคอนเท็กซ์
/context tool         # เฉพาะผลลัพธ์เครื่องมือ — ดูว่า agent ได้อะไรกลับมาจริง ๆ
/context assistant    # เฉพาะเทิร์นของโมเดลเอง

/context large คือตัวที่ผมคว้าเมื่อโทเคนระเบิด มันดึงข้อความที่ทำให้หน้าต่างบวมขึ้นมาให้เห็นเป๊ะ ๆ — มักเป็นผลลัพธ์เครื่องมือตัวหนึ่งที่คืนไฟล์ยักษ์หรือ JSON blob ก้อนใหญ่ — และตอนนี้คุณรู้แล้วว่าต้องสอนเครื่องมือตัวไหนให้แบ่งหน้าหรือตัดทอน ในหายนะ flaky-test ของผม /context tool แสดงผลลัพธ์ grep แปดสิบกว่าอันที่ว่างเปล่าทั้งหมด โมเดลไม่เคยปรับกลยุทธ์เลยเพราะไม่มีอะไรบอกมันว่ากลยุทธ์ไม่ได้ผล การอ่านผลลัพธ์เครื่องมือทำให้ลูปชัดเจนในราวสิบห้าวินาที


ระดับ 3: บันทึกเซสชัน — บันทึกครบถ้วนที่เล่นซ้ำได้

ทุกอย่างข้างบนอ่านจากสิ่งประดิษฐ์ชิ้นเดียว: ไฟล์เซสชัน Octomind เขียนทุกเซสชันลงที่

~/.local/share/octomind/sessions/<name>.jsonl.zst

มันคือ JSONL ที่บีบอัดด้วย zstd — หนึ่งอ็อบเจกต์ JSON ต่อบรรทัด บรรทัดส่วนใหญ่คือข้อความบทสนทนาดิบ (role: user|assistant|tool|system) แทรกอยู่ระหว่างนั้นคือมาร์กเกอร์ที่มีไทป์ ซึ่งรันไทม์ต้องใช้สร้างสถานะใหม่ตอน resume:

มาร์กเกอร์ บันทึกอะไร
STATS ยอดรวมที่กำลังวิ่ง — ต้นทุน เวลา API เวลาเครื่องมือ — ณ จุดนั้น
COMPRESSION_POINT มีการบีบอัด: ชนิด ข้อความที่ลบ โทเคนที่ประหยัด
RESTORATION_POINT เช็กพอยต์ /done — ข้อความก่อนหน้ายุบเมื่อโหลดใหม่
KNOWLEDGE_ENTRY ข้อเท็จจริงที่สกัดระหว่างบีบอัด ฉีดกลับเข้าไปตอน resume
COMMAND คำสั่งรันไทม์ (/model, /role, /effort…) เล่นซ้ำตอน resume
PLAN_SNAPSHOT / SCHEDULE_SNAPSHOT แผน / ตารางเวลาที่กำลังใช้งาน เพื่อให้รอดจากการรีสตาร์ท

ไฟล์นี้คือความจริงพื้นฐาน /report ถูกสร้างจากการคลายบีบอัดไฟล์นี้แล้วเดินผ่านรายการ STATS และ USER/COMMAND เพื่อแบ่งต้นทุนระหว่างคำขอตามตัวอักษรเลย คุณทำแบบเดียวกันเองได้:

zstd -dc ~/.local/share/octomind/sessions/my-feature-x.jsonl.zst \
  | jq -r 'select(.role == "tool") | "\(.content | length)\t\(.name)"' \
  | sort -n | tail

one-liner นั้นจัดอันดับผลลัพธ์เครื่องมือตามขนาดตรงจากบันทึก — ตัวกินโทเคนของคุณ โดยไม่ต้องเปิดเซสชันด้วยซ้ำ เพราะบันทึกเป็น JSONL แบบ append-only มันจึงเป็นสิ่งประดิษฐ์สำหรับเล่นซ้ำที่สมบูรณ์แบบด้วย: resume เซสชันเดิมเป๊ะ ๆ ด้วย octomind run --resume my-feature-x หรือหยิบอันล่าสุดของไดเรกทอรีปัจจุบันด้วย --resume-recent แล้วรันไทม์จะสร้างสถานะใหม่จากบรรทัดเหล่านี้เอง


ระดับ 4: RUST_LOG — เมื่อต้องมองเข้าไปในรันไทม์

บันทึกเซสชันแสดงว่า บทสนทนาคืออะไร เมื่อคุณต้องเห็นว่า รันไทม์ทำอะไร — ทำไมเซิร์ฟเวอร์ MCP ไม่โหลด ทำไมเครื่องมือถูกข้าม โพรไวเดอร์คืนอะไรมาจริง ๆ — ให้เปิด trace Octomind สร้างบน crate tracing หลังตัวแปรสภาพแวดล้อมมาตรฐาน RUST_LOG ในโหมด CLI จงใจ ไม่มี subscriber ของ trace จนกว่าคุณจะขอ — ผู้ใช้ได้เอาต์พุตสีสะอาด ไม่ใช่สายดับเพลิง ตั้ง RUST_LOG แล้วสายดับเพลิงก็เปิด:

# ทุกอย่างที่ระดับ debug
RUST_LOG=debug octomind run

# จำกัดให้แค่โมดูลเดียว — มีประโยชน์กว่ามากในทางปฏิบัติ
RUST_LOG=octomind::mcp=debug octomind run

# หลายขอบเขต ระดับผสม
RUST_LOG=octomind::session=debug,octomind::mcp=trace octomind run

ขอบเขตมีความหมาย RUST_LOG=debug ในเซสชันที่วุ่นวายอ่านไม่รู้เรื่อง ส่วน RUST_LOG=octomind::mcp=debug เมื่อเครื่องมือไม่โผล่จะบอกคุณเป๊ะ ๆ ว่าผู้สมัครตัวไหนถูกรับหรือปฏิเสธและเพราะอะไร นี่คือระดับที่ "agent มองไม่เห็นเครื่องมือของผม" เลิกเป็นปริศนา

ในโหมดเอาต์พุตมีโครงสร้าง — ACP และ WebSocket — stdout และ stderr ถูกสงวนไว้สำหรับโปรโตคอล ดังนั้น trace จึงไปลงไฟล์แทน:

~/.local/share/octomind/logs/acp-debug.log        ← trace ของ ACP
~/.local/share/octomind/logs/acp-errors.jsonl     ← ข้อผิดพลาด ACP แบบมีโครงสร้าง
~/.local/share/octomind/logs/websocket-debug.log  ← trace ของ WebSocket

ถ้าคุณรัน Octomind หลังเอดิเตอร์ผ่าน ACP แล้วมีบางอย่างผิด หลักฐานก็อยู่ในไฟล์เหล่านั้น


ระดับ 5: --format jsonl — ส่งรันเข้าทูลของคุณเอง

ทุกอย่างที่ผ่านมาเป็นของมนุษย์ที่อ่านเทอร์มินัล พอคุณเอา agent ใส่ CI หรือไปป์ไลน์ คุณต้องการรันเป็นสตรีมของอีเวนต์มีโครงสร้างที่คุณ assert ได้ octomind run --format jsonl ปล่อยอ็อบเจกต์ JSON หนึ่งตัวต่อบรรทัด — สตรีมอีเวนต์ภายในตัวเดียวกับที่เซิร์ฟเวอร์ WebSocket ใช้ — แท็กด้วย type:

echo "audit the auth module" | octomind run developer:general --format jsonl

แต่ละบรรทัดเป็นอีเวนต์แยกกัน ตัวแปรที่คุณจะสนใจ:

type บรรจุอะไร
assistant ชิ้นข้อความตอบของโมเดล
thinking เนื้อหาการให้เหตุผล แยกจากคำตอบ
tool_use tool, tool_id, server, params — agent กำลังจะลงมือ
tool_result tool, content, success — สิ่งที่กลับมา
cost session_tokens, session_cost, input_tokens, output_tokens, cache_read_tokens, cache_write_tokens, reasoning_tokens
error ข้อความความล้มเหลว
injected เทิร์นที่ไม่ใช่ผู้ใช้ — ตัวจับเวลาตามกำหนด, agent เบื้องหลัง, skill — พร้อม source_kind
skill skill ถูกเปิดใช้ ใช้งาน หรือลืม

ตอนนี้โหมดความล้มเหลวกลายเป็น assertion นับอีเวนต์ tool_use แล้วทำให้ build พังถ้าคำขอเดียวเกินเกณฑ์ — นั่นคือสายสะดุดกันลูปควบคุมไม่อยู่ของคุณ เฝ้าดู session_cost ในอีเวนต์ cost แล้วแจ้งเตือนเมื่อเกินงบ กรอง tool_result หา success: false agent ที่เคยล้มเหลวเงียบ ๆ ตอนนี้ล้มเหลวในแบบที่ jq จับได้:

echo "run the migration check" \
  | octomind run --format jsonl \
  | jq -c 'select(.type == "tool_use") | .tool' \
  | sort | uniq -c | sort -rn

นั่นพิมพ์ฮิสโทแกรมการเรียกเครื่องมือของทั้งรัน ถ้า shell อยู่บนสุดด้วยจำนวน 60 คุณก็เจอลูปก่อนที่มันจะเจอกระเป๋าเงินของคุณ — และมันเป็น one-liner ในสเต็ป CI ไม่ใช่คนนั่งจ้องสปินเนอร์


ระดับ 6: OctoHub — จับทุกคำขอ upstream

มีสิ่งหนึ่งที่อะไรข้างบนทั้งหมดแสดงให้ดูไม่ได้ เพราะมันเกิดใต้ตัว agent: ไบต์ที่แน่นอน ที่ Octomind ส่งให้โพรไวเดอร์และไบต์ที่แน่นอนที่กลับมา มุมมองของ agent คือข้อความของมันเอง มันแสดงคำขอระดับสายไฟไม่ได้ — โมเดลที่ resolve แล้ว เพย์โหลดที่ serialize เต็ม ๆ การตอบดิบของโพรไวเดอร์ เวลาแฝงจริง เมื่อคุณสงสัยว่าปัญหาอยู่ที่ชั้นแปล (system prompt ที่ไม่ใช่อย่างที่คุณคิด, สคีมาเครื่องมือที่โพรไวเดอร์ทำพัง, โมเดลที่ไม่ใช่ตัวที่คุณตั้งค่า) คุณต้องเห็นสายไฟ

OctoHub คือพร็อกซี LLM ของเรา และการบันทึกคำขอ/การตอบแบบครบถ้วนคือเหตุผลที่มันมีอยู่ ชี้ Octomind มาที่มันแทนโพรไวเดอร์ แล้วทุก completion จะลงในฐานข้อมูลพร้อมอินพุต เอาต์พุต และเมตริกแนบมา รันมัน:

./octohub   # ฟังที่ 127.0.0.1:8080 โดยปริยาย

มันพูดทั้ง POST /v1/completions (รูปแบบดั้งเดิมของมัน) และ POST /v1/chat/completions (OpenAI คลาสสิก เสียบใช้แทนได้กับไคลเอนต์ที่เข้ากันได้กับ OpenAI ตัวใดก็ตาม) และทั้งคู่กระทบเอนจินเดียวกันและเขียนลงตาราง completions เดียวกันด้วยรหัสเรกคอร์ด id เดียวกัน หลังรัน ดึงเรกคอร์ดดิบกลับมาด้วย admin API:

curl "http://127.0.0.1:8080/v1/admin/completions?limit=50" \
  -H "Authorization: Bearer <master-key>"

แต่ละเรกคอร์ดบรรจุภาพครบที่ agent ให้ไม่ได้:

{
  "id": "cmpl_<uuid>",
  "session_id": "<uuid>",
  "input_model": "my-model",
  "resolved_model": "gpt-5.5",
  "provider": "openai",
  "usage": {
    "input_tokens": 10,
    "output_tokens": 5,
    "total_tokens": 15,
    "cost": 0.0001,
    "request_time_ms": 320
  },
  "input": [...],
  "output": [...],
  "created_at": 1700000000
}

input_model เทียบกับ resolved_model เพียงอย่างเดียวก็จับบั๊กทั้งกลุ่ม "ทำไมมันทำตัวต่างไป" ได้ — คุณขอโมเดลหนึ่ง แต่ alias resolve ไปเป็นอีกตัว อาเรย์ input และ output คือเพย์โหลดตามตัวอักษร ดังนั้นสคีมาเครื่องมือที่โพรไวเดอร์สำลักก็อยู่ตรงนั้นให้อ่านได้ request_time_ms คือเวลาแฝงจริงของโพรไวเดอร์ แยกจากอะไรก็ตามที่ Octomind เพิ่มเข้าไป และ GET /v1/admin/usage รวมทั้งหมดตามคีย์ API และช่วงเวลา ซึ่งคือวิธีที่คุณก้าวจาก "agent แพง" ไปสู่ "คีย์นี้ โมเดลนี้ ชั่วโมงนี้" โดยไม่ต้องเดา (ถ้าคุณรัน agent กับหลายโพรไวเดอร์พร้อมกัน พร็อกซีก็เป็นที่ที่ทำให้เรื่องนี้สมเหตุสมผลด้วย — ดู agent เดียวข้ามหลายโมเดล)

พร็อกซีเปลี่ยนขอบเขตของโมเดลจากขอบทึบ ๆ ให้กลายเป็นพื้นผิวที่บันทึกและสืบค้นได้ ที่จัดเก็บโดยปริยายคือ SQLite — db_url = "sqlite://octohub.db" หรือตั้ง OCTOHUB_DB_URL — จึงไม่มีโครงสร้างพื้นฐานที่ต้องตั้งก่อนคุณจะเริ่มอ่านคำขอ


เมื่อ agent ทำ X ให้ดู Y

จุดประสงค์ทั้งหมดคือเปลี่ยน "agent ทำอะไรงง ๆ" ให้เป็นการค้นหาที่รู้จัก นี่คือตารางที่ติดอยู่เหนือโต๊ะของผม:

อาการ ดูที่แรก กำลังหาอะไร
ต้นทุนเซสชันโผล่มาจากไหนไม่รู้ /info cache rdin ในแถว breakdown
พรอมต์เดียวกินงบหมด /report แถวเดียวที่แบกบิล
หน้าต่างคอนเท็กซ์เต็ม / โมเดล "ลืม" บล็อก compression ของ /info แล้ว /context large จำนวนการบีบอัด และข้อความที่ใหญ่เกิน
ลูป / การเรียกเครื่องมือซ้ำ คอลัมน์ tools ของ /report หรือ jsonl + uniq -c เครื่องมือเดิม อาร์กิวเมนต์เดิม ไม่คืบหน้า
เครื่องมือไม่พร้อมใช้สำหรับ agent RUST_LOG=octomind::mcp=debug ทำไมผู้สมัครถูกข้าม
ผลลัพธ์เครื่องมือดูผิด /context tool ไบต์จริงที่โมเดลได้รับ
ทำตัวเหมือนโมเดลอื่น OctoHub GET /v1/admin/completions input_model เทียบ resolved_model
โพรไวเดอร์ error หรือเวลาแฝงแปลก input/output ของเรกคอร์ด OctoHub, request_time_ms เพย์โหลดดิบและเวลาจริง
ต้องการสายสะดุดใน CI --format jsonl นับ tool_use เฝ้า cost จับ error
เล่นซ้ำรันเดิมเป๊ะ octomind run --resume <name> เล่นซ้ำจาก <name>.jsonl.zst

การวินิจฉัยในสองนาที

นี่คือสิ่งที่หายนะ flaky-test จะเป็นไป ถ้าต่อทั้งหมดนี้ไว้ตั้งแต่ต้น แทนปริศนาหกนาทีที่มันเป็นจริง ๆ

สปินเนอร์รันนาน /report — คำขอที่ 3 คือ $3.98 และเรียกเครื่องมือ 84 ครั้ง อีกสองอันปกติ งั้นก็พรอมต์นั้นแหละ /context tool — ผลลัพธ์ grep ว่างแปดสิบอัน โมเดลไม่เคยเปลี่ยนกลยุทธ์ นั่นไงลูป และนั่นไงเหตุผล เวลารวมจนถึงสาเหตุราก: ราวเก้าสิบวินาที ไม่ต้องเสียสี่ดอลลาร์ เพราะในไปป์ไลน์จริง ฮิสโทแกรมการเรียกเครื่องมือจาก jsonl คงสะดุดเกณฑ์และฆ่ารันตั้งแต่การเรียกเครื่องมือครั้งที่ยี่สิบ

ไม่มีอะไรในนี้แปลกใหม่ มันคือสัญชาตญาณเดียวกับการ logging, metrics และ tracing ในระบบใด ๆ ที่คุณจะเอาขึ้นโปรดักชัน — นำมาใช้กับระบบที่ความล้มเหลวเงียบโดยธรรมชาติ agent จะไม่บอกคุณว่ามันหลงทาง แต่รันสังเกตได้ครบถ้วนถ้าคุณถามมันให้ถูกวิธี: /info สำหรับรูปร่าง /report สำหรับตัวการ /context สำหรับการให้เหตุผล บันทึกเซสชันสำหรับบันทึก RUST_LOG สำหรับรันไทม์ --format jsonl สำหรับเครื่องจักร และ OctoHub สำหรับสายไฟ

ต่อมันไว้ก่อนรันที่แพง ไม่ใช่หลังจากนั้น

— Don


Octomind และ OctoHub เป็นโอเพนซอร์สภายใต้ Apache-2.0 ถ้าพื้นผิวดีบักที่คุณต้องการยังขาดอยู่ ก็ เปิด issue — การมองเห็นภายในในโพสต์นี้มีอยู่ส่วนใหญ่เพราะ agent ของเราเองทำเราประหลาดใจไม่หยุด