* feat(docs): mirror every docs/ page in all 65 locales Extends the documentation mirrors from the 22-page core set (#13940) to every Markdown page under docs/: 152 sources x 65 locales = 9,880 mirrors (6,208 new), language bars rewritten for the full locale list, state adopted so the blocking drift gate now covers all 152 pages. run-translation.mjs: an oversized block made only of table rows or list items (PROVIDER_REFERENCE.md 244-row table, FREE_TIERS.md 71-item list) is cut at item boundaries and rejoined without a blank line — the single 16-40 KB request outlived the backend socket for verbose scripts. 48 older mirrors whose tables had lost rows were retranslated with --force. * docs(i18n): refresh mirrors for the sources the base changed since the branch cut Section-level retranslation of the 29 docs (and README.md) whose source or mirrors moved on release/v3.8.51 during the run, then state adoption; the drift gate is green again on the merged tree.
55 KiB
Extending the Compression Pipeline (ไทย)
🌐 Languages: 🇺🇸 English · 🇪🇹 am · 🇸🇦 ar · 🇦🇿 az · 🇧🇬 bg · 🇧🇩 bn · 🇨🇿 cs · 🇩🇰 da · 🇩🇪 de · 🇬🇷 el · 🇪🇸 es · 🇪🇪 et · 🇮🇷 fa · 🇫🇮 fi · 🇫🇷 fr · 🇮🇪 ga · 🇮🇳 gu · 🇳🇬 ha · 🇮🇱 he · 🇮🇳 hi · 🇭🇷 hr · 🇭🇺 hu · 🇦🇲 hy · 🇮🇩 id · 🇳🇬 ig · 🇮🇹 it · 🇯🇵 ja · 🇬🇪 ka · 🇰🇭 km · 🇮🇳 kn · 🇰🇷 ko · 🇱🇹 lt · 🇱🇻 lv · 🇮🇳 ml · 🇮🇳 mr · 🇲🇾 ms · 🇲🇹 mt · 🇲🇲 my · 🇳🇵 ne · 🇳🇱 nl · 🇳🇴 no · 🇮🇳 or · 🇮🇳 pa · 🇵🇭 phi · 🇵🇱 pl · 🇵🇹 pt · 🇧🇷 pt-BR · 🇷🇴 ro · 🇷🇺 ru · 🇱🇰 si · 🇸🇰 sk · 🇸🇮 sl · 🇷🇸 sr · 🇸🇪 sv · 🇰🇪 sw · 🇮🇳 ta · 🇮🇳 te · 🇹🇷 tr · 🇺🇦 uk-UA · 🇵🇰 ur · 🇺🇿 uz · 🇻🇳 vi · 🇳🇬 yo · 🇨🇳 zh-CN · 🇹🇼 zh-TW
สรุปสั้น ๆ: เอนจินการบีบอัดของ OmniRoute สามารถ เสียบต่อได้ — คุณสามารถลงทะเบียนเอนจินแบบกำหนดเอง จัดส่งแพ็กภาษาสำหรับภาษาใหม่ และประกอบไปป์ไลน์แบบซ้อนกันได้ คู่มือนี้จะแสดงวิธีดำเนินการ
คู่มือที่เกี่ยวข้อง:
- COMPRESSION_GUIDE.md — ภาพรวมทั้งหมดของไปป์ไลน์
- COMPRESSION_ENGINES.md — รีจิสทรีเอนจินและเอนจินที่มีมาให้ในตัว
- RTK_COMPRESSION.md — เอนจิน RTK และตัวกรองแบบกำหนดเอง
- COMPRESSION_RULES_FORMAT.md — เอกสารอ้างอิงรูปแบบแพ็กกฎ
ภาพรวม
ระบบการบีบอัดมี จุดขยาย 3 จุด:
| จุดขยาย | กรณีการใช้งาน | ระดับความยาก |
|---|---|---|
| เอนจินแบบกำหนดเอง | เพิ่มอัลกอริทึมการบีบอัดใหม่ทั้งหมด (เช่น ตัวสรุปเฉพาะโดเมน) | ขั้นสูง |
| แพ็กภาษา | เพิ่มการรองรับภาษาธรรมชาติใหม่ (เช่น ภาษาฮินดี ภาษาอาหรับ) | ปานกลาง |
| ไปป์ไลน์แบบซ้อน | ประกอบเอนจินที่มีอยู่ตามลำดับที่กำหนดเอง | เริ่มต้น |
┌─────────────────────────────────────────────────────────────┐
│ กลยุทธ์การบีบอัด │
│ │
│ ข้อความนำเข้า ──▶ getEffectiveMode() ──▶ โหมด │
│ │ │
│ ┌───────────────────────┼──────────┐ │
│ │ │ │ │ │ │
│ ▼ ▼ ▼ ▼ │ │
│ "rtk" "lite" "standard" "stacked" │
│ │ │ │ │ │ │
│ ▼ ▼ ▼ ▼ │ │
│ เอนจิน เอนจิน เอนจิน engines[] │
│ RTK Lite Caveman เชื่อมต่อกัน │
│ │ │ │ │ │ │
│ └─────────┴─────────┴─────────┘ │ │
│ │ │
│ ▼ │
│ เอาต์พุตที่บีบอัดแล้ว │
└─────────────────────────────────────────────────────────────┘
ตัวเลือกกลยุทธ์ทำงานตามโหมด: แต่ละคำขอจะเลือกเพียงหนึ่งโหมด
(rtk / lite / standard / aggressive / ultra / stacked / off)
มีเพียงโหมด "stacked" เท่านั้นที่เชื่อมต่อเอนจินหลายตัวตามลำดับ
โหมดเริ่มต้นที่ทริกเกอร์โดยอัตโนมัติคือ "lite" (ไม่ใช่สายลำดับความสำคัญ 3 ระดับ)
การเขียนเอนจินการบีบอัดแบบกำหนดเอง
อินเทอร์เฟซของเอนจิน (open-sse/services/compression/engines/types.ts) คือสัญญาที่ทุกเอนจินต้องปฏิบัติตาม โดยมีเมธอดที่จำเป็น 5 เมธอด
อินเทอร์เฟซ CompressionEngine
interface CompressionEngine {
id: string; // ID เอนจินที่ไม่ซ้ำกัน
name: string; // ชื่อที่ใช้แสดง
description: string; // คำอธิบายแบบสั้น
icon: string; // ไอคอน (อีโมจิหรือ URL)
targets: CompressionEngineTarget[]; // ["messages", "tool_results", "code_blocks"]
stackable: boolean; // สามารถใช้ในไปป์ไลน์แบบซ้อนได้หรือไม่
stackPriority: number; // ลำดับในไปป์ไลน์แบบซ้อน (ค่าต่ำกว่า = ทำงานก่อน)
metadata: CompressionEngineMetadata;
apply(body, options?): CompressionResult;
compress(body, config?): CompressionResult;
getConfigSchema(): EngineConfigField[];
validateConfig(config): EngineValidationResult;
}
ตัวอย่างขั้นต่ำ: เอนจิน Whitespace
เอนจินที่เรียบง่ายที่สุด — ลบช่องว่างส่วนเกินออกจากข้อความ
import type { CompressionEngine } from "omniroute/compression/engines/types";
import { registerCompressionEngine } from "omniroute/compression/engines/registry";
function preserveCodeBlocks(text: string): string {
// แยกตามเครื่องหมายบล็อกโค้ดและคงช่องว่างภายในบล็อกไว้
const parts = text.split(/(```[\s\S]*?```)/);
return parts
.map((part) => {
if (part.startsWith("```")) {
return part; // อย่าแก้ไขบล็อกโค้ด
}
return part.replace(/\n{3,}/g, "\n\n"); // ใช้กับข้อความร้อยแก้วเท่านั้น
})
.join("");
}
const whitespaceEngine: CompressionEngine = {
id: "whitespace",
name: "ตัวลบช่องว่าง",
description: "ลบช่องว่างและบรรทัดว่างส่วนเกิน",
icon: "📝",
targets: ["messages", "tool_results"],
stackable: true,
stackPriority: 100, // ทำงานหลัง caveman/rtk
metadata: {
id: "whitespace",
name: "ตัวลบช่องว่าง",
description: "ลบช่องว่างและบรรทัดว่างส่วนเกิน",
inputScope: "messages",
targetLatencyMs: 5,
supportsPreview: true,
stable: true,
},
apply(body, options) {
return this.compress(body, options?.config);
},
compress(body, config = {}) {
let originalLength = 0;
let compressedLength = 0;
// วนผ่านอาร์เรย์ข้อความ — รองรับทั้งเนื้อหาแบบสตริงและหลายส่วน
const compressedBody = (body.messages || []).map((msg) => {
if (typeof msg.content === "string") {
originalLength += msg.content.length;
let compressed = msg.content
.replace(/[ \t]+/g, " ")
.replace(/\n{3,}/g, "\n\n")
.replace(/^\s+|\s+$/gm, "");
compressedLength += compressed.length;
return { ...msg, content: compressed };
}
// เนื้อหาแบบหลายส่วน: วนผ่านแต่ละส่วนและบีบอัดเฉพาะส่วนข้อความ
if (Array.isArray(msg.content)) {
const newParts = msg.content.map((part) => {
if (part.type === "text" && typeof part.text === "string") {
originalLength += part.text.length;
let compressed = part.text
.replace(/[ \t]+/g, " ")
.replace(/\n{3,}/g, "\n\n")
.replace(/^\s+|\s+$/gm, "");
compressedLength += compressed.length;
return { ...part, text: compressed };
}
return part; // คง image_url, tool_use และอื่นๆ ไว้
});
return { ...msg, content: newParts };
}
return msg;
});
return {
body: { ...body, messages: compressedBody },
stats: {
originalTokens: Math.ceil(originalLength / 4),
compressedTokens: Math.ceil(compressedLength / 4),
savingsPercent: originalLength > 0 ? 100 * (1 - compressedLength / originalLength) : 0,
techniques: ["whitespace-collapse"],
engineId: "whitespace",
},
};
},
getConfigSchema() {
return [
{
key: "preserveCodeBlocks",
type: "boolean",
label: "คงบล็อกโค้ดไว้",
defaultValue: true,
description: "อย่าแก้ไขช่องว่างภายในบล็อก ```code```",
},
];
},
validateConfig(config) {
if (config.preserveCodeBlocks !== undefined && typeof config.preserveCodeBlocks !== "boolean") {
return { valid: false, errors: ["preserveCodeBlocks ต้องเป็นค่าบูลีน"] };
}
return { valid: true, errors: [] };
},
};
// ลงทะเบียนแบบส่วนกลาง
registerCompressionEngine(whitespaceEngine);
ตำแหน่งสำหรับวางเอนจินแบบกำหนดเอง
~/.omniroute/compression/engines/my-engine.ts # ระดับผู้ใช้
<project>/compression-engines/my-engine.ts # ระดับโปรเจกต์ (โหลดเมื่อเริ่มต้น)
หรือโหลดจากปลั๊กอินผ่านโค้ด:
// ภายในปลั๊กอินของคุณ
import {
registerCompressionEngine,
unregisterCompressionEngine,
} from "@omniroute/open-sse/services/compression/engines/registry";
import { myEngine } from "./engines/my-engine";
export default definePlugin({
name: "my-compression-plugin",
// SDK ของปลั๊กอินเปิดให้ใช้ฮุก onRequest / onResponse / onError ให้ลงทะเบียน
// เอนจินเมื่อโหลดโมดูลปลั๊กอิน (หรือใน onRequest ครั้งแรก) และยกเลิกการลงทะเบียน
// จากขั้นตอนการปิดใช้งานของคุณเอง
onRequest: async (ctx) => {
registerCompressionEngine(myEngine);
},
});
// เมื่อปิดใช้งาน:
// unregisterCompressionEngine("my-engine");
การทดสอบเอนจินของคุณ
ลงทะเบียนเอนจินของคุณในปลั๊กอินหรือฟังก์ชันเริ่มต้น เมื่อลงทะเบียนแล้ว เอนจินจะพร้อมใช้งาน
ในตัวเลือกกลยุทธ์ผ่าน id ของเอนจิน ทดสอบการผสานการทำงานโดยประกอบเอนจินไว้ในไปป์ไลน์แบบซ้อน:
การสร้างชุดภาษา
การบีบอัดแบบ Caveman ใช้ ชุดกฎเฉพาะภาษา เพื่อจัดการคำฟุ่มเฟือย การใช้ถ้อยคำแบบไม่มั่นใจ และรูปแบบการเขียนที่เยิ่นเย้อในภาษาธรรมชาติแต่ละภาษา OmniRoute มาพร้อมกับ ชุดภาษา 6 ชุด ได้แก่ en, es, fr, de, ja, pt-BR
โครงสร้างชุดภาษา
ชุดภาษาคือไดเรกทอรีของ ไฟล์ JSON ภายใต้ open-sse/services/compression/rules/<language>/:
open-sse/services/compression/rules/
├── en/
│ ├── filler.json # คำทักทาย ถ้อยคำแบบไม่มั่นใจ และถ้อยคำสุภาพ
│ ├── context.json # กฎสำหรับลดบริบท
│ ├── dedup.json # กฎการขจัดข้อมูลซ้ำ
│ ├── structural.json # เครื่องหมายวรรคตอนและการจัดรูปแบบ
│ └── ultra.json # กฎการบีบอัดเชิงรุก
├── es/ (โครงสร้างเดียวกัน)
├── fr/ (โครงสร้างเดียวกัน)
├── de/ (โครงสร้างเดียวกัน)
├── ja/ (โครงสร้างเดียวกัน)
└── pt-BR/ (โครงสร้างเดียวกัน)
โครงสร้างของกฎ
แต่ละกฎมีโครงสร้างดังนี้ (จาก open-sse/services/compression/ruleLoader.ts):
interface FileRule {
name: string; // ชื่อที่มนุษย์อ่านเข้าใจได้ (kebab-case)
pattern: string; // รูปแบบนิพจน์ทั่วไปของ JavaScript
replacement?: string; // สิ่งที่จะใช้แทนข้อความที่ตรงกัน
replacementMap?: Record<string, string>; // หรือแมปคีย์→ข้อความแทนที่
flags?: string; // แฟล็กของนิพจน์ทั่วไป (โดยทั่วไปคือ "gi")
context?: "all" | "user" | "system" | "assistant";
category?: "filler" | "context" | "structural" | "dedup" | "terse" | "ultra";
minIntensity?: "lite" | "full" | "ultra"; // ข้ามกฎนี้หากระดับความเข้มต่ำกว่าค่านี้
description?: string; // เอกสารประกอบ
}
ตัวอย่าง: การเพิ่มกฎคำฟุ่มเฟือยสำหรับภาษาฮินดี
{
"language": "hi",
"category": "filler",
"rules": [
{
"name": "polite_opener",
"pattern": "\\b(?:नमस्ते|नमस्कार|आदरणीय)\\b[,!\\s]*",
"replacement": "",
"context": "all",
"category": "filler",
"minIntensity": "lite",
"description": "Strip polite openers like 'नमस्ते'"
},
{
"name": "filler_actually",
"pattern": "\\b(?:असल में|वास्तव में|दरअसल)\\b\\s*",
"replacement": "",
"context": "all",
"category": "filler",
"minIntensity": "lite",
"description": "Strip 'actually' fillers"
},
{
"name": "verbose_plea",
"pattern": "\\b(?:कृपया|कृपया आप|अनुरोध है कि आप)\\b\\s*",
"replacement": "",
"context": "all",
"category": "filler",
"minIntensity": "full",
"description": "Strip 'please' in Hindi"
}
]
}
การตรวจสอบความถูกต้อง
ชุดกฎจะได้รับการตรวจสอบกับ _schema.json เมื่อโหลด ชุดที่มีโครงสร้างไม่ถูกต้องจะโหลดไม่สำเร็จและบันทึกข้อผิดพลาดลงในบันทึก:
RULE_LOADER: pack "hi/filler.json" failed validation:
- rules.0.pattern: Invalid regex
- rules.1.context: must be one of [all, user, system, assistant]
การตรวจสอบความถูกต้องจะทำงานโดยอัตโนมัติเมื่อมีการโหลดชุด (โดยตรวจสอบกับ _schema.json); ชุดที่ไม่ถูกต้องจะถูกปฏิเสธและข้อผิดพลาดข้างต้นจะถูกบันทึก ไม่มีสคริปต์ npm run แยกต่างหากสำหรับตรวจสอบความถูกต้องของชุด — ให้โหลดชุด (เช่น เริ่มเซิร์ฟเวอร์หรือเรียกใช้เส้นทางการบีบอัด) แล้วตรวจดูบันทึก
การโหลดชุดภาษาแบบกำหนดเอง
import { loadRulePack } from "omniroute/compression/ruleLoader";
await loadRulePack("./my-custom-rules/hi/filler.json");
หรือวางไว้ในตำแหน่งที่ระบบรู้จัก:
~/.omniroute/compression/rules/hi/filler.json # ระดับผู้ใช้
<project>/.compression/rules/hi/filler.json # ระดับโปรเจกต์
แนวทางปฏิบัติที่ดีที่สุดสำหรับชุดภาษา
- เริ่มต้นด้วย
filler— กฎเหล่านี้ให้ผลลัพธ์มากที่สุด - ใช้
minIntensityเพื่อควบคุมการใช้กฎเชิงรุก — ช่วยป้องกันการบีบอัดมากเกินไป - รวมกรณีทดสอบไว้ด้วย — เพิ่มอาร์เรย์
tests[]ใน JSON เพื่อตรวจสอบลักษณะการทำงาน - ลำดับมีความสำคัญ — กฎที่อยู่ก่อนจะถูกนำไปใช้ก่อน ให้วางกฎที่ให้ผลกระทบสูงไว้ก่อน
- ใช้
replacementอย่างระมัดระวัง — โดยทั่วไปสตริงว่างคือค่าที่ถูกต้อง และต้องไม่เพิ่มเนื้อหาใหม่
กลยุทธ์การแปล
เมื่อปรับชุดกฎให้รองรับภาษาใหม่:
- แปลชื่อกฎ — ชื่อเหล่านี้จะปรากฏในเอาต์พุตการดีบัก
- ปรับรูปแบบนิพจน์ทั่วไป — การแปลโดยตรงมักใช้ไม่ได้ผล (ขอบเขตคำแตกต่างกัน)
- ทดสอบกับบทสนทนาจริง — ชุดกฎควรปลอดภัยเมื่อนำไปใช้กับอินพุตจริง
- ทำให้สอดคล้องกับธรรมเนียมทางวัฒนธรรม — ตัวอย่างเช่น ชุดภาษาญี่ปุ่นมีคำฟุ่มเฟือยเชิงยกย่องมากกว่าภาษาอังกฤษ
ไปป์ไลน์แบบซ้อน
ไปป์ไลน์แบบซ้อน จะเรียกใช้เอนจินหลายตัวตามลำดับ โดยส่งเอาต์พุตของแต่ละเอนจินไปยังเอนจินถัดไป นี่คือวิธีการทำงานภายในของ mode: stacked
วิธีการทำงานของการซ้อน
อินพุต (10,000 โทเค็น)
│
▼
┌──────────┐
│ เอนจิน │ ลำดับความสำคัญ 10
│ A │ ──▶ เอาต์พุต: 6,000 โทเค็น (-40%)
└────┬─────┘
▼
┌──────────┐
│ เอนจิน │ ลำดับความสำคัญ 50
│ B │ ──▶ เอาต์พุต: 2,400 โทเค็น (-60%)
└────┬─────┘
▼
┌──────────┐
│ เอนจิน │ ลำดับความสำคัญ 100
│ C │ ──▶ เอาต์พุต: 1,200 โทเค็น (-80%)
└────┬─────┘
│
▼
เอาต์พุตสุดท้าย (1,200 โทเค็น, ประหยัดรวม ~88%)
เมื่อเลือก mode: "stacked" เอนจินจะทำงานตามลำดับที่ระบุไว้ในอาร์เรย์ pipeline
เอาต์พุตของเอนจิน N จะกลายเป็นอินพุตของเอนจิน N+1
โหมดการบีบอัด
OmniRoute จะเลือก หนึ่งโหมดต่อคำขอ โดยอิงจากการกำหนดค่า เกณฑ์การทริกเกอร์อัตโนมัติ และการตั้งค่าแทนที่ของคอมโบ
โหมดที่ใช้งานได้กำหนดไว้ใน open-sse/services/compression/types.ts (ชนิด CompressionMode):
| โหมด | เอนจิน | กรณีใช้งาน |
|---|---|---|
off |
ไม่มี | ปิดใช้งานการบีบอัดทั้งหมด |
rtk |
RTK เท่านั้น | เซสชันที่มีเอาต์พุตคำสั่งจำนวนมาก (ประหยัด 80% ขึ้นไป) |
lite |
Lite เท่านั้น | การบีบอัดแบบระมัดระวัง (รวดเร็ว ปลอดภัย) |
standard |
Caveman | การบีบอัดข้อความร้อยแก้วด้วยแพ็กภาษา |
aggressive |
Caveman + Aggressive | การบีบอัดข้อความร้อยแก้วเชิงรุก + การประมวลผลขั้นสุดท้ายเชิงรุก |
ultra |
Ultra | การบีบอัดสูงสุด (มีการสูญเสียข้อมูล ใช้เป็นทางเลือกสุดท้าย) สามารถเลือกกำหนดเส้นทางผ่านเอนจิน SLM LLMLingua-2 ได้เมื่อตั้งค่า ultra.modelPath (หากโมเดลไม่พร้อมใช้งาน ระบบจะเปิดให้ทำงานต่อโดยใช้เส้นทางแบบอิงกฎ) |
stacked |
ไปป์ไลน์แบบกำหนดเอง | ประกอบเอนจินตามลำดับใดก็ได้ (ดูด้านล่าง) |
นอกเหนือจากเอนจินของโหมดข้างต้นแล้ว รีจิสทรียังมาพร้อมกับเอนจินเฉพาะทางที่สามารถนำมาซ้อนกันได้ — CCR, headroom, ionizer และ session-dedup — ซึ่งมีเอกสารอธิบายอยู่ใน COMPRESSION_ENGINES.md
การเลือกโหมดจะกำหนดโดย getEffectiveMode() ใน open-sse/services/compression/strategySelector.ts:
- หากปิดใช้งานการบีบอัด:
"off" - หากมีการตั้งค่าแทนที่ของคอมโบ: ใช้ค่าที่ตั้งไว้แทน
- หากเกินเกณฑ์การทริกเกอร์อัตโนมัติ: ใช้
autoTriggerMode(ค่าเริ่มต้น:"lite") - มิฉะนั้น: ใช้
defaultMode
ไปป์ไลน์แบบซ้อนเริ่มต้น
เมื่อกำหนด mode: "stacked" อย่างชัดเจน ไปป์ไลน์เริ่มต้นจะประกอบด้วย:
- RTK — ตัดสิ่งรบกวนจากเอาต์พุตคำสั่ง (ประหยัด ~80% สำหรับเอาต์พุตเทอร์มินัล)
- Caveman — ลบคำฟุ่มเฟือย ทำให้ข้อความร้อยแก้วกระชับขึ้น (~46% ของข้อความที่เหลือ)
- Lite — ประมวลผลช่องว่างและกำจัดข้อมูลซ้ำเป็นขั้นตอนสุดท้าย
องค์ประกอบนี้ช่วยให้ ประหยัดได้ 78-95% ในเซสชันที่มีการใช้เครื่องมือจำนวนมาก
การกำหนดค่าไปป์ไลน์แบบซ้อน
ในการกำหนดค่าคอมโบ:
{
"compression": {
"mode": "stacked",
"pipeline": [
{ "engine": "rtk", "config": { "intensity": "aggressive" } },
{ "engine": "caveman", "config": { "intensity": "full" } },
{ "engine": "lite", "config": {} }
]
}
}
คุณสามารถละเว้นเอนจิน เพิ่มเอนจินแบบกำหนดเอง หรือจัดลำดับใหม่ได้
การส่งต่อสถานะ
เอนจินสามารถอ่านข้อมูลเมตาจากบริบทของคำขอ (ใน options) ได้:
compress(body, config) {
// อ่านข้อมูลเมตาจากเอนจินก่อนหน้า
const original = options?.compressionComboId; // "my-coding-combo"
// ...
}
ข้อมูลเมตาเป็นแบบ อ่านอย่างเดียว — เอนจินไม่สามารถแก้ไขบริบทของคำขอได้ โดยแก้ไขได้เฉพาะเอาต์พุตเนื้อหาของตนเองเท่านั้น
ข้อควรระวังเกี่ยวกับลำดับการทำงาน
| ลำดับเอนจิน | ผลลัพธ์ |
|---|---|
| RTK → Caveman → Lite | แนะนำ (ตัดสิ่งรบกวนก่อน ตามด้วยภาษา แล้วจึงจัดการช่องว่าง) |
| Lite → RTK → Caveman | ไม่ดี — Lite ตัดช่องว่างออกจากเอาต์พุตดิบ ทำให้การจับคู่รูปแบบของ RTK ล้มเหลว |
| Caveman → RTK | ไม่ดี — Caveman อาจเขียนข้อความใหม่ในลักษณะที่ RTK ไม่รู้จัก |
ลำดับใดก็ได้ที่มี tool_results เป็นอันดับแรก |
ดีกว่า — เอาต์พุตของเครื่องมือเป็นเนื้อหาที่มีสิ่งรบกวนมากที่สุด |
กรณีที่ไม่ควรซ้อน
การซ้อนไม่ได้ดีกว่าเสมอไป:
- ข้อความทั่วไป (ไม่มีเอาต์พุตของเครื่องมือ) — ใช้ Caveman หรือ Lite เพียงตัวเดียวก็เพียงพอ
- ให้ความสำคัญกับต้นทุน — แต่ละเอนจินเพิ่มเวลาแฝง ~5-50ms
- เครื่องมือเฉพาะ — โดยทั่วไป RTK เพียงตัวเดียวก็เพียงพอสำหรับเอาต์พุตของเชลล์
การสร้างไปป์ไลน์แบบกำหนดเอง
ไม่มีรีจิสทรีสำหรับไปป์ไลน์ที่มีชื่อ ไปป์ไลน์แบบซ้อนเป็นเพียง อาร์เรย์ของขั้นตอนแบบอินไลน์
ที่ส่งไปยัง applyStackedCompression() (ส่งออกจาก
@omniroute/open-sse/services/compression/strategySelector):
import { applyStackedCompression } from "@omniroute/open-sse/services/compression/strategySelector";
const result = applyStackedCompression(body, [
{ engine: "rtk", intensity: "aggressive" },
{ engine: "caveman", intensity: "full" },
]);
เมื่อคุณไม่ได้ส่งไปป์ไลน์ ระบบจะใช้ค่าเริ่มต้นเป็น rtk(standard) → caveman(full)
หากต้องการควบคุมผ่านการกำหนดค่า ให้ตั้งค่า mode: "stacked" และระบุอาร์เรย์ของขั้นตอนไว้ภายใต้
stackedPipeline (อ่านจาก config.stackedPipeline):
{
"compression": {
"mode": "stacked",
"stackedPipeline": [
{ "engine": "rtk", "intensity": "aggressive" },
{ "engine": "caveman", "intensity": "full" }
]
}
}
นโยบายการซิงค์กับต้นทาง
เอนจินการบีบอัดของ OmniRoute ให้เครดิตแก่โครงการต้นทางหลายโครงการใน README ("ได้รับแรงบันดาลใจจาก RTK, Caveman, LLMLingua-2, Troglodita") คำถามที่ผู้มีส่วนร่วม มักถามคือ: เมื่อ RTK ต้นทางเพิ่มตัวกรองเครื่องมือใหม่ หรือ Caveman เพิ่มชุดกฎ สิ่งเหล่านั้นจะมาถึง OmniRoute ได้อย่างไร? ส่วนนี้คือคำตอบอย่างเป็นทางการ
สำเนาที่รวมมากับโครงการเทียบกับการนำไปใช้งานแบบอิสระ
| เอนจิน | ความสัมพันธ์กับต้นทาง | ตำแหน่ง |
|---|---|---|
| RTK | การนำไปใช้งานใหม่แบบอิสระ (ได้รับแรงบันดาลใจ ไม่ใช่สำเนา) | open-sse/services/compression/engines/rtk/ |
| Caveman | การนำไปใช้งานใหม่แบบอิสระ (ได้รับแรงบันดาลใจ) | open-sse/services/compression/engines/cavemanAdapter.ts |
| Headroom | ส่วนใหญ่เป็นส่วนภายใน มีเพียงตัวแปลงสัญญาณ gcf/ เท่านั้นที่ รวมมาจากต้นทางอย่างแท้จริง จาก gcf-typescript (MIT, มีเครื่องหมาย SPDX, เฉพาะโปรไฟล์ทั่วไป) |
open-sse/services/compression/engines/headroom/gcf/ |
| LLMLingua-2 / Troglodita | ได้รับแรงบันดาลใจจากต้นทาง (เป็นแนวทางให้กับเอนจิน llmlingua + session-dedup) |
open-sse/services/compression/engines/llmlingua/, session-dedup |
ประเด็นสำคัญ: RTK และ Caveman เป็นการนำ_แนวคิด_ (กฎตัวกรอง ชุดกฎ)
ไปใช้งานด้วย TypeScript แบบคลีนรูม ไม่ใช่ซอร์สทรีที่รวมมาจากต้นทาง ไม่มี
สำเนาต้นทางให้ git pull — ซึ่งเป็นเหตุผลที่ README ใช้คำว่า
"ได้รับแรงบันดาลใจจาก" แทนที่จะเป็น "รวมมาด้วย"
วิธีผสานการปรับปรุงจากต้นทาง
ไม่มีการติดตามรุ่นของต้นทางโดยอัตโนมัติ และไม่มีป้ายกำกับ compression-sync
ซึ่งเป็นการออกแบบโดยตั้งใจ เนื่องจากเอนจินเหล่านี้เป็นการนำไปใช้งานใหม่
ตัวกรองของ RTK หรือชุดกฎของ Caveman จากต้นทางจึงไม่ได้ถูกผสานเข้ามาเป็นโค้ด
แต่จะถูก ถ่ายทอดใหม่เป็นกฎ/ตัวกรองใหม่ในรูปแบบของ OmniRoute เอง (ดู
COMPRESSION_RULES_FORMAT.md) และรวมเข้ามาเป็นครั้งคราว
ผ่าน PR ตามปกติ จุดต่อขยายข้างต้น (เอนจินแบบกำหนดเอง ชุดภาษา ตัวกรอง RTK)
คือวิธีที่ได้รับอนุญาตสำหรับการมีส่วนร่วม
ตัวอย่างล่าสุดของกระบวนการนี้:
- ตัวกรอง RTK สำหรับเอาต์พุตการบิลด์ของ Gradle และ
dotnet(v3.8.42) - ตัวกรอง RTK สำหรับ kubectl / docker-build / composer / gh (#2824)
- ชุดภาษาอินโดนีเซียของ Caveman (#3975) รวมถึงชุดภาษาเยอรมัน / ฝรั่งเศส / ญี่ปุ่น / จีน
Headroom (พร็อกซีบีบอัดอินพุต)
Headroom เป็น ส่วนภายในทั้งหมด — ประกอบด้วยสแนปช็อตตัวแปลงสัญญาณ gcf
ที่รวมมากับโครงการและตรึงเวอร์ชันไว้ พร้อมด้วยเลเยอร์ smartcrusher / toon /
tabular ของ OmniRoute เอง ไม่มีต้นทางที่ใช้งานอยู่ให้ติดตามนอกเหนือจากสำเนา
ที่รวมมากับโครงการ การอัปเดต gcf จะดำเนินการรีเฟรชด้วยตนเองเมื่อตัวแปลงสัญญาณ
เปลี่ยนแปลง และตรวจสอบความถูกต้องอีกครั้งเทียบกับเกตงบประมาณการบีบอัด
(check:compression-budget)
การเสนอการปรับปรุงที่ได้รับแรงบันดาลใจจากต้นทาง
- อย่ารวมโค้ดจากต้นทาง — ให้ถ่ายทอดกฎ/ตัวกรองจากต้นทางใหม่ในรูปแบบของ OmniRoute
- เพิ่มผ่านจุดต่อขยายที่ตรงกันด้านล่าง (ชุดภาษา ตัวกรอง RTK หรือ เอนจินแบบกำหนดเอง)
- อ้างอิงโครงการต้นทางในคำอธิบาย PR (เพื่อให้เครดิต) แทนการ คัดลอกซอร์สที่อยู่ภายใต้สัญญาอนุญาต
- เพิ่มการทดสอบและยืนยันว่าเกต
check:compression-budgetยังคงผ่าน
การเพิ่มรูปแบบเอาต์พุต
รูปแบบเอาต์พุต (ดูตารางแค็ตตาล็อกในคู่มือ)
เป็นส่วนฝั่งการตอบกลับที่ทำงานคู่กับเอนจินอินพุต กล่าวคือ แทนที่จะบีบอัดสิ่งที่คุณ
ส่ง รูปแบบเหล่านี้จะสั่งให้โมเดลสร้างเอาต์พุตที่มีต้นทุนต่ำลง รีจิสทรีคือ
OUTPUT_STYLE_CATALOG ใน open-sse/services/compression/outputStyles/catalog.ts และ
รายการเดียวในแค็ตตาล็อกคือฟีเจอร์ทั้งหมด: ตัวแทรก แผงการตั้งค่าแดชบอร์ด
การจัดเก็บถาวร และเทเลเมทรี ล้วนไล่รายการจากแค็ตตาล็อก — ไม่มีรายการอื่นที่ต้องอัปเดต
- เพิ่มหนึ่งรายการลงใน
OUTPUT_STYLE_CATALOGโดยมีid,label,descriptionและlevelsภาษาอังกฤษทั้งสามระดับ (lite,full,ultra) ทุกระดับต้องลงท้ายด้วย${SHARED_BOUNDARIES}เพื่อให้โค้ด พาธ คำสั่ง ข้อผิดพลาด และ URL คงเดิมทุกประการ ข้อความคำสั่งต้องเป็นแบบ คงที่และกำหนดผลลัพธ์ได้แน่นอน สำหรับแต่ละ(id, level, language)— อนุญาตให้แทรกค่าได้เฉพาะ${SHARED_BOUNDARIES}เท่านั้น - แปลรายการดังกล่าว ต้องมีบล็อก
pt-BRอย่างน้อยภายใต้i18n;ponytailและi-have-adhd(en, pt-BR, es, de, fr, it, ru, zh, ja, id, vi) เป็นโครงสร้างอ้างอิง รูปแบบที่ตั้งใจ ให้รองรับเพียงภาษาเดียวจะกำหนดlocaleแทน (เช่นterse-cjk→zh) และจะ แสดงเป็นตัวเลือกเฉพาะภายใต้โลเคลนั้น - อัปเดตตัวตรวจสอบเมทริกซ์ — เพิ่มภาษาของรูปแบบลงใน
BASELINE_LANGUAGESในtests/unit/compression/output-styles-i18n-matrix.test.tsเกตจะทำให้รูปแบบใหม่ ที่ไม่ได้ถูกจำกัดด้วยโลเคลและไม่มีคำแปลที่กำหนดล้มเหลว เว้นแต่จะมีรายการKNOWN_ENGLISH_ONLYที่ระบุอย่างชัดเจนพร้อมอ้างอิงประเด็นสำหรับติดตาม - เพิ่มการทดสอบเฉพาะรูปแบบ โดยใช้
tests/unit/compression/i-have-adhd-catalog.test.tsเป็นต้นแบบ: ตรวจสอบโครงสร้างแค็ตตาล็อก ข้อกำหนดเรื่องขอบเขตในแต่ละระดับ และจุดยืนยันว่าคำแปลแต่ละรายการเขียนด้วยภาษา ของตนเองแทนที่จะคัดลอกภาษาอังกฤษ - การระบุแหล่งที่มา: หากรูปแบบดัดแปลงมาจากโปรเจกต์ต้นทาง ให้ระบุเครดิตไว้ใน
คอมเมนต์แหล่งที่มาของรายการนั้น (เช่น
i-have-adhd→ ayghri/i-have-adhd, MIT) — ใช้ กฎเดียวกับ "การเสนอการปรับปรุงที่ได้รับแรงบันดาลใจจากต้นทาง" ด้านบน
ไม่จำเป็นต้องเปลี่ยนแปลง UI, สคีมา หรือเทเลเมทรี — ส่วนเหล่านั้นเรนเดอร์จากแค็ตตาล็อก
แนวทางปฏิบัติที่ดีที่สุด
การพัฒนาเอนจิน
- นำ
validateConfigไปใช้เสมอ — เอนจินที่ไม่มีการตรวจสอบความถูกต้องจะทำให้เกิดความล้มเหลวโดยไม่มีการแจ้งเตือน - กำหนด
targetLatencyMsตามความเป็นจริง — ตัวเลือกกลยุทธ์ใช้ค่านี้เพื่อเลือกเอนจิน - ใช้
getConfigSchemaสำหรับแดชบอร์ด — ห้ามซ่อนการกำหนดค่าจากผู้ใช้ - รองรับ
stackable: trueหากเอนจินของคุณไม่มีผลข้างเคียง — เอนจินที่มีผลข้างเคียงไม่ควรซ้อนกัน - เขียนการทดสอบแบบอินไลน์ — เอนจินควรตรวจสอบยืนยันได้ภายใน <1s
การพัฒนาแพ็กภาษา
- เริ่มต้นด้วยระดับความเข้มข้น
lite— กฎของคุณควรปลอดภัยเมื่อใช้การตั้งค่าต่ำสุด - ใช้
contextเพื่อจำกัดขอบเขตกฎ — กฎที่ใช้กับuserเท่านั้นจะไม่ส่งผลต่อพรอมต์ระบบโดยไม่ตั้งใจ - หลีกเลี่ยงการจับคู่คีย์ JSON —
\\bword\\bสามารถจับคู่ภายใน JSON และทำให้ข้อมูลที่มีโครงสร้างเสียหายได้ - ทดสอบด้วยกรณีขอบ — อินพุตว่าง ยูนิโคด ข้อความ RTL และอีโมจิ
- ใช้แพ็กที่มีอยู่เป็นเทมเพลต —
en/filler.jsonเป็นตัวอย่างที่พัฒนาสมบูรณ์ที่สุด
การออกแบบไปป์ไลน์
- ทำโปรไฟล์ก่อนปรับประสิทธิภาพ — วัดผลด้วย
compression_statsก่อน - เลือกใช้การประกอบส่วนแทนการนำไปสร้างใหม่ — ขยายกฎ Caveman ก่อนเขียนเอนจินใหม่
- บันทึกเหตุผลของลำดับไว้ — คอมเมนต์ว่าเหตุใดเอนจิน A จึงอยู่ก่อนเอนจิน B
- ทดสอบที่ระดับความเข้มข้นทั้ง 3 ระดับ —
liteรวดเร็วแต่มีการสูญเสียข้อมูล ส่วนultraช้าแต่แม่นยำ
เอกสารอ้างอิง: เอนจินในตัว
| ID เอนจิน | ซ้อนกันได้ | stackPriority เริ่มต้น | เป้าหมาย |
|---|---|---|---|
lite |
ใช่ | 5 | ข้อความ, ผลลัพธ์ของเครื่องมือ |
rtk |
ใช่ | 10 | ผลลัพธ์ของเครื่องมือ |
standard (caveman) |
ใช่ | 20 | ข้อความ, ผลลัพธ์ของเครื่องมือ, บล็อกโค้ด |
aggressive |
ใช่ | 30 | ข้อความ |
ultra |
ใช่ | 40 | ข้อความ, บล็อกโค้ด |
ดูเพิ่มเติม
- COMPRESSION_GUIDE.md — ภาพรวมของไปป์ไลน์
- COMPRESSION_ENGINES.md — เอกสารอ้างอิงรีจิสทรีของเอนจิน
- COMPRESSION_RULES_FORMAT.md — ข้อกำหนดรูปแบบกฎ
- COMPRESSION_LANGUAGE_PACKS.md — รายละเอียดแพ็กภาษา
- RTK_COMPRESSION.md — เอนจิน RTK และตัวกรองแบบกำหนดเอง
- ซอร์ส:
open-sse/services/compression/(117 ไฟล์, ~250KB)