ข้ามไปยังเนื้อหาหลัก

ความยืดหยุ่นในการแปลเนื้อหา

ไปป์ไลน์การแปลเนื้อหาของ Champollion (เอกสาร Markdown/MDX) ใช้ระบบความยืดหยุ่นหลายชั้นเพื่อรับมือกับความล้มเหลวอย่างมีประสิทธิภาพ ต่างจากการแปลแบบ key-value ที่แต่ละ batch มีขนาดเล็กและการลองใหม่มีต้นทุนต่ำ — การแปลเนื้อหาเกี่ยวข้องกับ prompt ขนาดใหญ่และ output ที่ยาว ซึ่งอาจล้มเหลวด้วยเหตุผลเชิงโครงสร้าง ไม่ใช่แค่ความผิดพลาดชั่วคราว

ปัญหา

การแปลเนื้อหามีรูปแบบความล้มเหลวที่แตกต่างจากการแปลแบบ key-value อย่างมีนัยสำคัญ:

รูปแบบความล้มเหลวKey-Valueเนื้อหา
Rate limit (429)พบบ่อย, ชั่วคราวพบบ่อย, ชั่วคราว
Timeoutพบน้อย (batch เล็ก)พบบ่อย (output ยาว)
Response ว่างเปล่าพบน้อยพบบ่อย (ข้อจำกัด output, ตัวกรอง)
Output ถูกตัดทอนไม่มี (ตรวจสอบด้วย JSON)เกิดขึ้นโดยไม่มีสัญญาณเตือน
ตัวกรองเนื้อหาพบน้อยมากอาจเกิดขึ้น (เอกสาร CLI, เอกสารด้านความปลอดภัย)
ข้อจำกัดของโมเดลลองใหม่แก้ได้ลองใหม่ไม่ช่วย

ข้อสังเกตสำคัญ: การลองซ้ำ request เดิมที่ล้มเหลวไม่ใช่ความซ้ำซ้อนที่มีประโยชน์ แต่คือความดื้อรั้น ระบบความยืดหยุ่นที่ดีต้องระบุ สาเหตุ ของความล้มเหลวและเปลี่ยนแนวทางให้เหมาะสม

ภาพรวมสถาปัตยกรรม

ชั้นที่ 1: การลองใหม่แบบวินิจฉัยก่อน

ก่อนตัดสินใจว่าจะลองใหม่ อย่างไร ระบบจะตรวจสอบ API response เพื่อทำความเข้าใจว่า อะไร ล้มเหลว

การวิเคราะห์ Finish Reason

LLM API ทุกตัวจะส่งคืน finish_reason พร้อมกับข้อความที่สร้างขึ้น Champollion ใช้ข้อมูลนี้เพื่อตัดสินใจลองใหม่อย่างชาญฉลาด:

finish_reasonความหมายการดำเนินการ
stop + มีเนื้อหาโมเดลทำงานเสร็จสมบูรณ์✅ ยอมรับผลลัพธ์
stop + ว่างเปล่าโมเดลไม่สร้าง output⚠️ ลองใหม่ request เดิม (ชั่วคราว)
lengthOutput ถึงขีดจำกัด token🔶 แบ่งเอกสารเป็น chunk อัตโนมัติ
content_filterตัวกรองความปลอดภัยบล็อก output🔴 บันทึกและข้ามไป (ลองใหม่ไม่ช่วย)
null / ไม่มีค่าResponse มีรูปแบบผิดพลาด⚠️ ลองใหม่ request เดิม (ชั่วคราว)

วิธีนี้แทนที่แนวทางเดิมที่ปฏิบัติต่อความล้มเหลวทุกประเภทเหมือนกันด้วยการลองใหม่แบบ backoff

งบประมาณการลองใหม่

งบประมาณการลองใหม่มาตรฐานสำหรับความล้มเหลวชั่วคราว:

รอบจำนวนครั้งTimeoutBackoff
มาตรฐาน4 (0→3)60s1s → 2s → 4s
ยกระดับ4 (0→3)120s1s → 2s → 4s
รวม8~3.5 นาที กรณีเลวร้ายที่สุด

ระหว่างรอบ จะมีช่วงพัก 10 วินาทีเพื่อให้ปัญหาชั่วคราวคลี่คลาย

ชั้นที่ 2: การแบ่งเนื้อหาเป็น Chunk

เมื่อเอกสารมีขนาดเกินเกณฑ์ที่กำหนด — หรือเมื่อชั้นที่ 1 ตรวจพบการตัดทอน output — ระบบจะแบ่งเอกสารออกเป็น chunk ขนาดเหมาะสมสำหรับการแปล

ดู Context Rollover สำหรับการกำหนดค่า chunking โดยละเอียด ประเด็นสำคัญ:

กลยุทธ์การแบ่ง

  1. ขอบเขต Heading## และ ### เป็นขอบเขตหน่วยการแปลที่เป็นธรรมชาติ แต่ละส่วนมีความสมบูรณ์ในตัวเองเพียงพอสำหรับการแปลอิสระ
  2. Fallback ที่ย่อหน้า — หากส่วน heading เดียวมีขนาดเกิน chunk size ให้แบ่งที่บรรทัดว่างสองบรรทัด
  3. การแบ่งแบบ Hard split — ทางเลือกสุดท้ายสำหรับย่อหน้าที่ยาวมาก (เช่น ตาราง) โดยแบ่งที่ขอบเขตประโยค

บริบทระหว่าง Chunk

แต่ละ chunk จะได้รับ 2-3 ย่อหน้าสุดท้ายของการแปล chunk ก่อนหน้า เป็นบริบท เพื่อป้องกัน:

  • การเบี่ยงเบนของคำศัพท์ — โมเดลเห็นว่าตัวเองใช้คำว่า "tableau de bord" ใน chunk ก่อนหน้า
  • การอ้างอิง pronoun — antecedent จากส่วนก่อนหน้าถูกส่งต่อมา
  • ความสม่ำเสมอของ register — โทนที่กำหนดใน chunk 1 คงอยู่ตลอดจนถึง chunk N

ตัวกระตุ้น Auto-Chunking

ตัวกระตุ้นพฤติกรรม
contentChunkSize ตั้งค่าใน configแบ่ง chunk เอกสารที่เกินขนาดนั้นเสมอ
finish_reason: "length" ถูกส่งคืนAuto-chunk เป็น fallback (แม้ไม่มีการตั้งค่า)
Input > ~12KB (ตรวจจับอัตโนมัติ)บันทึกคำแนะนำ แต่ไม่บังคับ

ชั้นที่ 3: ห่วงโซ่ Model Fallback

เมื่อโมเดลที่กำหนดค่าไว้ล้มเหลวอย่างต่อเนื่อง — ไม่ใช่ชั่วคราว แต่เชิงโครงสร้าง — ระบบจะลองใช้โมเดลทางเลือก โมเดลต่างกันมี context window, ขีดจำกัด output, ตัวกรองความปลอดภัย และความสามารถด้านหลายภาษาที่แตกต่างกัน

ห่วงโซ่ Fallback เริ่มต้น

champollion.config.json
{
"contentFallbackChain": [
"google/gemini-2.5-flash",
"anthropic/claude-sonnet-4"
]
}

โมเดลที่กำหนดค่าไว้จะถูกลองก่อนเสมอ โมเดล fallback จะถูกใช้เฉพาะหลังจากรอบการลองใหม่ทั้งหมด (มาตรฐาน + ยกระดับ) หมดแล้ว

เหตุผลที่ต้องใช้หลายสถาปัตยกรรม

สถานการณ์โมเดลหลักล้มเหลวโมเดล Fallback สำเร็จ
เอกสาร CLI ภาษาเวียดนามGemini ส่งคืนค่าว่างClaude จัดการได้ปกติ
เนื้อหาที่ถูกตัวกรองOpenAI บล็อกGemini มีเกณฑ์ตัวกรองต่างกัน
ตารางโครงสร้างยาวโมเดล A ตัดทอนโมเดล B มี output window ใหญ่กว่า

คุณค่าของ fallback คือความหลากหลายทางสถาปัตยกรรม — โมเดลต่างตระกูลมีรูปแบบความล้มเหลวต่างกัน ความล้มเหลวที่เป็นเชิงโครงสร้างสำหรับโมเดลหนึ่งอาจเป็นเรื่องเล็กน้อยสำหรับอีกโมเดลหนึ่ง

ขอบเขต

Model fallback ใช้กับ เนื้อหาเท่านั้น Key-value batch มีขนาดเล็กและแทบไม่เคยล้มเหลวเชิงโครงสร้าง การเพิ่มความซับซ้อนของ fallback ในส่วนนั้นจะเป็นการ over-engineering

ชั้นที่ 4: การบัญชีความล้มเหลว

เมื่อเกิดความล้มเหลว ระบบจะติดตามและรายงานอย่างถูกต้องแทนที่จะดำเนินการต่อโดยเงียบ

ระหว่าง Sync

  • รายการที่ล้มเหลวจะแสดง [FAIL] ใน progress output
  • ความล้มเหลวแต่ละรายการบันทึกสาเหตุเฉพาะ (timeout, response ว่างเปล่า, ตัวกรองเนื้อหา, การตัดทอน)
  • รายการที่เสร็จสมบูรณ์จะถูกบันทึกลง manifest ทันที (incremental persistence)

หลัง Sync

สรุปความล้มเหลวจะแสดงเมื่อสิ้นสุด:

┌─ Content Translation Failures ─────────────────────────────────────┐
│ │
│ 2 of 24 content translations failed: │
│ │
│ ✗ docs/reference/cli.md → vi │
│ Reason: empty response after 8 attempts + 1 fallback model │
│ Models tried: google/gemini-3.1-pro-preview, gemini-2.5-flash │
│ │
│ ✗ docs/guides/troubleshooting.md → ar │
│ Reason: content_filter (no retry — blocked by safety filter) │
│ │
│ Re-run: npx champollion@latest sync │
│ (22 completed translations are cached and won't re-run) │
└─────────────────────────────────────────────────────────────────────┘

Retry Manifest

ไฟล์ที่ล้มเหลวจะถูกเขียนลงใน .champollion-retry.json:

{
"failedAt": "2026-05-27T21:45:00Z",
"files": [
{
"source": "docs/reference/cli.md",
"locale": "vi",
"reason": "empty_response",
"attempts": 8,
"modelsTried": ["google/gemini-3.1-pro-preview", "google/gemini-2.5-flash"]
}
]
}

ในการรัน sync ครั้งถัดไป จะประมวลผลเฉพาะไฟล์เหล่านี้เท่านั้น ไฟล์ที่เสร็จสมบูรณ์แล้วจะถูกเก็บรักษาผ่าน content hash manifest (.champollion-content.lock)

Exit Code

Codeความหมาย
0การแปลทั้งหมดสำเร็จ
1ข้อผิดพลาดในการกำหนดค่า, API key หายไป, ฯลฯ
2ความล้มเหลวบางส่วน — การแปลเนื้อหาบางรายการล้มเหลว

การกำหนดค่า

champollion.config.json
{
"contentChunkSize": 4000,
"contentOverlap": 200,
"contentFallbackChain": [
"google/gemini-2.5-flash",
"anthropic/claude-sonnet-4"
]
}
FieldTypeDefaultคำอธิบาย
contentChunkSizenumber | nullnullจำนวน token สูงสุดต่อ content chunk null = ไม่แบ่ง chunk (auto-chunk เฉพาะเมื่อถูกตัดทอน)
contentOverlapnumber200Token ที่ซ้อนทับกันระหว่าง content chunk เพื่อความต่อเนื่องของบริบท
contentFallbackChainstring[][]โมเดล fallback ที่จะลองเมื่อโมเดลที่กำหนดค่าไว้ล้มเหลวเชิงโครงสร้าง

สถานะการพัฒนา

ฟีเจอร์สถานะ
การลองใหม่แบบวินิจฉัยก่อน (การแยกวิเคราะห์ finish_reason)🔲 วางแผนไว้
การแบ่งเนื้อหาเป็น chunk (แบ่งที่ heading/paragraph)🔲 วางแผนไว้
Context rollover ระหว่าง chunk🔲 วางแผนไว้
ห่วงโซ่ model fallback🔲 วางแผนไว้
รายงานสรุปความล้มเหลว🔲 วางแผนไว้
Retry manifest (.champollion-retry.json)🔲 วางแผนไว้
Exit code 2 สำหรับความล้มเหลวบางส่วน🔲 วางแผนไว้
การลองใหม่แบบยกระดับ (extended timeout)✅ พัฒนาแล้ว (v3.3.3)
ข้อความลองใหม่พร้อมหมายเลขครั้ง✅ พัฒนาแล้ว (v3.3.3)
การแจ้งความล้มเหลวอย่างชัดเจนสำหรับข้อผิดพลาดเนื้อหา✅ พัฒนาแล้ว (v3.3.3)

ดูเพิ่มเติม