# OmniRoute Auto-Combo Engine (Ελληνικά) 🌐 **Languages:** 🇺🇸 [English](../../../../routing/AUTO-COMBO.md) · 🇪🇹 [am](../../../am/docs/routing/AUTO-COMBO.md) · 🇸🇦 [ar](../../../ar/docs/routing/AUTO-COMBO.md) · 🇦🇿 [az](../../../az/docs/routing/AUTO-COMBO.md) · 🇧🇬 [bg](../../../bg/docs/routing/AUTO-COMBO.md) · 🇧🇩 [bn](../../../bn/docs/routing/AUTO-COMBO.md) · 🇧🇦 [bs](../../../bs/docs/routing/AUTO-COMBO.md) · 🇨🇿 [cs](../../../cs/docs/routing/AUTO-COMBO.md) · 🇩🇰 [da](../../../da/docs/routing/AUTO-COMBO.md) · 🇩🇪 [de](../../../de/docs/routing/AUTO-COMBO.md) · 🇪🇸 [es](../../../es/docs/routing/AUTO-COMBO.md) · 🇪🇪 [et](../../../et/docs/routing/AUTO-COMBO.md) · 🇮🇷 [fa](../../../fa/docs/routing/AUTO-COMBO.md) · 🇫🇮 [fi](../../../fi/docs/routing/AUTO-COMBO.md) · 🇫🇷 [fr](../../../fr/docs/routing/AUTO-COMBO.md) · 🇮🇪 [ga](../../../ga/docs/routing/AUTO-COMBO.md) · 🇮🇳 [gu](../../../gu/docs/routing/AUTO-COMBO.md) · 🇳🇬 [ha](../../../ha/docs/routing/AUTO-COMBO.md) · 🇮🇱 [he](../../../he/docs/routing/AUTO-COMBO.md) · 🇮🇳 [hi](../../../hi/docs/routing/AUTO-COMBO.md) · 🇭🇷 [hr](../../../hr/docs/routing/AUTO-COMBO.md) · 🇭🇺 [hu](../../../hu/docs/routing/AUTO-COMBO.md) · 🇦🇲 [hy](../../../hy/docs/routing/AUTO-COMBO.md) · 🇮🇩 [id](../../../id/docs/routing/AUTO-COMBO.md) · 🇳🇬 [ig](../../../ig/docs/routing/AUTO-COMBO.md) · 🇮🇹 [it](../../../it/docs/routing/AUTO-COMBO.md) · 🇯🇵 [ja](../../../ja/docs/routing/AUTO-COMBO.md) · 🇬🇪 [ka](../../../ka/docs/routing/AUTO-COMBO.md) · 🇰🇭 [km](../../../km/docs/routing/AUTO-COMBO.md) · 🇮🇳 [kn](../../../kn/docs/routing/AUTO-COMBO.md) · 🇰🇷 [ko](../../../ko/docs/routing/AUTO-COMBO.md) · 🇱🇹 [lt](../../../lt/docs/routing/AUTO-COMBO.md) · 🇱🇻 [lv](../../../lv/docs/routing/AUTO-COMBO.md) · 🇮🇳 [ml](../../../ml/docs/routing/AUTO-COMBO.md) · 🇮🇳 [mr](../../../mr/docs/routing/AUTO-COMBO.md) · 🇲🇾 [ms](../../../ms/docs/routing/AUTO-COMBO.md) · 🇲🇹 [mt](../../../mt/docs/routing/AUTO-COMBO.md) · 🇲🇲 [my](../../../my/docs/routing/AUTO-COMBO.md) · 🇳🇵 [ne](../../../ne/docs/routing/AUTO-COMBO.md) · 🇳🇱 [nl](../../../nl/docs/routing/AUTO-COMBO.md) · 🇳🇴 [no](../../../no/docs/routing/AUTO-COMBO.md) · 🇮🇳 [or](../../../or/docs/routing/AUTO-COMBO.md) · 🇮🇳 [pa](../../../pa/docs/routing/AUTO-COMBO.md) · 🇵🇭 [phi](../../../phi/docs/routing/AUTO-COMBO.md) · 🇵🇱 [pl](../../../pl/docs/routing/AUTO-COMBO.md) · 🇵🇹 [pt](../../../pt/docs/routing/AUTO-COMBO.md) · 🇧🇷 [pt-BR](../../../pt-BR/docs/routing/AUTO-COMBO.md) · 🇷🇴 [ro](../../../ro/docs/routing/AUTO-COMBO.md) · 🇷🇺 [ru](../../../ru/docs/routing/AUTO-COMBO.md) · 🇱🇰 [si](../../../si/docs/routing/AUTO-COMBO.md) · 🇸🇰 [sk](../../../sk/docs/routing/AUTO-COMBO.md) · 🇸🇮 [sl](../../../sl/docs/routing/AUTO-COMBO.md) · 🇷🇸 [sr](../../../sr/docs/routing/AUTO-COMBO.md) · 🇸🇪 [sv](../../../sv/docs/routing/AUTO-COMBO.md) · 🇰🇪 [sw](../../../sw/docs/routing/AUTO-COMBO.md) · 🇮🇳 [ta](../../../ta/docs/routing/AUTO-COMBO.md) · 🇮🇳 [te](../../../te/docs/routing/AUTO-COMBO.md) · 🇹🇭 [th](../../../th/docs/routing/AUTO-COMBO.md) · 🇹🇷 [tr](../../../tr/docs/routing/AUTO-COMBO.md) · 🇺🇦 [uk-UA](../../../uk-UA/docs/routing/AUTO-COMBO.md) · 🇵🇰 [ur](../../../ur/docs/routing/AUTO-COMBO.md) · 🇺🇿 [uz](../../../uz/docs/routing/AUTO-COMBO.md) · 🇻🇳 [vi](../../../vi/docs/routing/AUTO-COMBO.md) · 🇳🇬 [yo](../../../yo/docs/routing/AUTO-COMBO.md) · 🇨🇳 [zh-CN](../../../zh-CN/docs/routing/AUTO-COMBO.md) · 🇹🇼 [zh-TW](../../../zh-TW/docs/routing/AUTO-COMBO.md) --- > **Για χρήστες**: Αναζητάτε έναν γρήγορο τρόπο να ξεκινήσετε; Ανατρέξτε στον [Οδηγό χρήσης του Auto-Combo](../getting-started/AUTO-COMBO-GUIDE.md) για απλές επεξηγήσεις και παραδείγματα. > Αυτοδιαχειριζόμενες αλυσίδες μοντέλων με προσαρμοστική βαθμολόγηση + αυτόματη δρομολόγηση χωρίς ρυθμίσεις ## Αυτόματη Δρομολόγηση Χωρίς Ρύθμιση (πρόθεμα `auto/`) > **ΝΕΟ:** Δεν απαιτείται δημιουργία combo. Χρησιμοποιήστε το πρόθεμα `auto/` απευθείας σε οποιοδήποτε πρόγραμμα-πελάτη. ### Γρήγορα Παραδείγματα | Model ID | Παραλλαγή | Συμπεριφορά | | -------------- | --------- | --------------------------------------------------------------------------------------------- | | `auto` | default | Όλοι οι συνδεδεμένοι πάροχοι, στρατηγική LKGP, ισορροπημένα βάρη | | `auto/coding` | coding | Βάρη με προτεραιότητα ποιότητας, κατάλληλο για δημιουργία κώδικα | | `auto/fast` | fast | Επιλογή με βάρος χαμηλής καθυστέρησης | | `auto/cheap` | cheap | Δρομολόγηση βελτιστοποιημένη ως προς το κόστος (πρώτα το χαμηλότερο κόστος) | | `auto/offline` | offline | Ευνοεί παρόχους με υψηλότερη διαθεσιμότητα ποσόστωσης | | `auto/smart` | smart | Προτεραιότητα ποιότητας + υψηλότερος ρυθμός εξερεύνησης (10%) για καλύτερη ανακάλυψη μοντέλων | | `auto/lkgp` | lkgp | Ρητό LKGP (ίδιο με το προεπιλεγμένο `auto`) | | `auto/chaos` | chaos | Βάρη έγχυσης σφαλμάτων για δοκιμές ανθεκτικότητας (chaos engineering) | ### Σύνθεση Κατηγορίας × Επιπέδου (`auto/:`) Τα επιθήματα τύπου OpenRouter διαχωρίζουν **το είδος της διαδρομής** (κατηγορία) από **τον τρόπο βελτιστοποίησής της** (επίπεδο), ώστε να μπορείτε να τα συνδυάζετε ελεύθερα (#4235 Phase B, `open-sse/services/autoCombo/suffixComposition.ts`): - **Κατηγορίες** (φιλτράρουν το σύνολο υποψηφίων βάσει δυνατότητας): `coding` · `reasoning` · `vision` · `chat` · `multimodal`. Τα `vision`/`multimodal` διατηρούν μοντέλα με δυνατότητα όρασης· το `reasoning` διατηρεί μοντέλα συλλογισμού/σκέψης. - **Επίπεδα** (επιλέγουν βάρη βαθμολόγησης / φίλτρο συνόλου): `fast` (γρήγορη αποστολή) · `cheap` (ψευδώνυμο `floor`, εξοικονόμηση κόστους) · `reliable` (υγεία circuit-breaker + σταθερότητα καθυστέρησης) · `free` / `pro` (φιλτράρουν το σύνολο βάσει επιπέδου μοντέλου μέσω `classifyTier` — δωρεάν επίπεδο έναντι premium). | Παράδειγμα | Επιλύεται σε | | ---------------------- | --------------------------------------------------------------------------------- | | `auto/coding:fast` | σύνολο coding, βάρη χαμηλής καθυστέρησης | | `auto/coding:cheap` | σύνολο coding, βελτιστοποιημένο ως προς το κόστος (ψευδώνυμο `auto/coding:floor`) | | `auto/reasoning:pro` | μόνο μοντέλα συλλογισμού/σκέψης, premium επίπεδο | | `auto/vision` | μοντέλα με δυνατότητα όρασης (χωρίς επίπεδο → ισορροπημένα βάρη) | | `auto/multimodal:free` | μοντέλα με δυνατότητα multimodal, μόνο δωρεάν επίπεδο | Κάθε έγκυρο `auto/[:]` επιλύεται κατ' απαίτηση· ένα επιμελημένο υποσύνολο διαφημίζεται στο `/v1/models` και στον πίνακα ελέγχου (`AUTO_SUFFIX_VARIANTS` στο `open-sse/services/autoCombo/builtinCatalog.ts`). Το φιλτράρισμα είναι **fail-open** — αν κάποιος περιορισμός δεν ταιριάζει με κανένα συνδεδεμένο μοντέλο, χρησιμοποιείται ολόκληρο το σύνολο ώστε η δρομολόγηση να μην διακόπτεται ποτέ. Ο βασικός βαθμολογητής (`combo.ts`) παραμένει αμετάβλητος· το φίλτρο κατηγορίας/επιπέδου εφαρμόζεται στο `buildAutoCandidates`. > **Ζωντανή ευφυΐα μοντέλων:** η καταλληλότητα αυτόματης δρομολόγησης ενημερώνεται από ζωντανές κατατάξεις **Arena ELO** + δεδομένα επιπέδου **models.dev** όταν η σημαία `ARENA_ELO_SYNC_ENABLED` είναι ενεργή (διαφορετικά επιστρέφει στον στατικό χάρτη καταλληλότητας). **Τρόπος χρήσης:** ```bash # Οποιοδήποτε IDE ή εργαλείο CLI που υποστηρίζει μορφή OpenAI Base URL: http://localhost:20128/v1 API Key: # Στον κώδικα/ρύθμισή σας, ορίστε το μοντέλο σε: model: "auto" # ισορροπημένη προεπιλογή model: "auto/coding" # καλύτερο για εργασίες κώδικα model: "auto/fast" # το ταχύτερο διαθέσιμο model: "auto/cheap" # φθηνότερο ανά token ``` **Τι συμβαίνει:** 1. Το OmniRoute εντοπίζει το πρόθεμα `auto/` στο `src/sse/handlers/chat.ts` 2. Ερωτά όλες τις **ενεργές συνδέσεις παρόχων** από τη βάση δεδομένων 3. Φιλτράρει σε αυτές με έγκυρα διαπιστευτήρια (κλειδί API ή διακριτικό OAuth) 4. Καθορίζει το μοντέλο ανά σύνδεση (`connection.defaultModel` ή το πρώτο μοντέλο του παρόχου) 5. Δημιουργεί ένα **εικονικό combo** στη μνήμη (δεν αποθηκεύεται στη ΒΔ) 6. Δρομολογεί χρησιμοποιώντας το προφίλ βάρους της επιλεγμένης παραλλαγής + στρατηγική LKGP **Βασικές ιδιότητες:** - ✅ **Πάντα ενεργό:** Χωρίς εναλλαγή, χωρίς δημιουργία combo, χωρίς καμία ρύθμιση - ✅ **Δυναμικό:** Αντικατοπτρίζει αυτόματα τους τρέχοντες συνδεδεμένους παρόχους - ✅ **Εμμονή συνεδρίας:** Το LKGP διασφαλίζει ότι ο τελευταίος επιτυχής πάροχος έχει προτεραιότητα - ✅ **Πολυλογαριασμός:** Κάθε σύνδεση παρόχου γίνεται ξεχωριστός υποψήφιος - ✅ **Χωρίς εγγραφές ΒΔ:** Το εικονικό combo υπάρχει μόνο για το αίτημα, μηδενικό κόστος παραμονής ### Έλεγχος υποψηφίων ανά κλειδί (#7819, Επίπεδο 1+2) Το `GET /v1/auto-combo/{channel}/candidates` (`{channel}` = το επίθεμα μετά το `auto/`, ή το κυριολεκτικό `auto` για το βασικό κανάλι) είναι ένα **μόνο-ανάγνωσης** τελικό σημείο που καταγράφει το τρέχον σύνολο υποψηφίων ενός καναλιού `auto/*` διακοσμημένο με ζωντανή προσβασιμότητα, επαναχρησιμοποιώντας τις υπάρχουσες αναγνώσεις ανθεκτικότητας (ποτέ ακατέργαστη `state` του circuit breaker): - circuit breaker παρόχου — `getCircuitBreaker(provider).getStatus()` / `.canExecute()` - χρονική αναστολή σύνδεσης — `rateLimitedUntil` / `testStatus` στην επιλυμένη γραμμή `provider_connections` - κλείδωμα μοντέλου — `isModelLocked(provider, connectionId, model)` Κάθε υποψήφιος φέρει επίσης τη σημαία `excluded` αυτού του κλειδιού API. Οι εξαιρέσεις αποθηκεύονται ανά κλειδί API (πίνακας `auto_candidate_overrides`, migration `128`) — το OmniRoute είναι μονό-ενοικιαστής χωρίς πίνακα `users`, οπότε το `apiKeyId` είναι η πλησιέστερη πραγματική ταυτότητα ανά καλούντα — και εφαρμόζονται στο κομβικό σημείο του συνόλου υποψηφίων στο `open-sse/services/autoCombo/virtualFactory.ts` μέσω της καθαρής, ελεγμένης με μοναδικές δοκιμές `filterExcludedCandidates()` (`open-sse/services/autoCombo/candidateOverrides.ts`). Το φίλτρο είναι **fail-open**: ένα μη ορισμένο apiKeyId/κανάλι ή αποτυχία αναζήτησης στη ΒΔ αφήνουν το σύνολο αφιλτράριστο, ώστε ένας χειριστής χωρίς ρυθμισμένες παρακάμψεις να βλέπει δρομολόγηση πανομοιότυπη με πριν από αυτή τη λειτουργία. **Αναβλήθηκε για επόμενο ζήτημα:** βάρη ανά υποψήφιο + ρητή διάταξη (Επίπεδο 3 — τροφοδοτεί τα υπάρχοντα μονοπάτια στρατηγικής βαρύτητας/προτεραιότητας) και καρφίτσωμα συγκεκριμένης στρατηγικής `combo.ts` ανά κανάλι `auto/*` (Επίπεδο 4). Δείτε το σχέδιο #7819 για το ανοικτό ερώτημα σχετικά με το αν οι παρακάμψεις πρέπει να παραμείνουν ανά κλειδί API ή να γίνουν παγκόσμιες δεδομένου του μοντέλου μονό-ενοικιαστή. **Πίσω από τα παρασκήνια:** ```txt Αίτημα: { model: "auto/coding" } ↓ src/sse/handlers/chat.ts εντοπίζει πρόθεμα ↓ createVirtualAutoCombo('coding') → candidatePool από ενεργές συνδέσεις ↓ handleComboChat (ίδια μηχανή με τα αποθηκευμένα combos) ↓ Η αυτόματη βαθμολόγηση επιλέγει τον καλύτερο πάροχο/μοντέλο ανά αίτημα ``` **Αρχεία υλοποίησης:** | Αρχείο | Σκοπός | | --------------------------------------------------------- | ------------------------------------------------- | | `open-sse/services/autoCombo/autoPrefix.ts` | Αναλυτής προθέματος (`parseAutoPrefix`) | | `open-sse/services/autoCombo/virtualFactory.ts` | Δημιουργεί εικονικά αντικείμενα `AutoComboConfig` | | `open-sse/services/autoCombo/providerRegistryAccessor.ts` | Άγκιστρο δοκιμής για προσομοίωση μητρώου παρόχων | | `src/sse/handlers/chat.ts` | Ενσωμάτωση: παράκαμψη προθέματος auto | | `src/shared/constants/providers.ts` | Καταχώρηση συστήματος `SYSTEM_PROVIDERS.auto` | ## Ονόματα Combo που Ταιριάζουν με Πραγματικό Model Id Ένα combo του οποίου το `name` είναι πανομοιότυπο με ένα απλό model id (π.χ. ένα combo με όνομα `gpt-5.5`) είναι ένα **σκόπιμο, υποστηριζόμενο μοτίβο**, όχι σφάλμα: αποτελεί τον μηχανισμό για ανάκαμψη (fallback) παρόχου ανά model id, όπως τεκμηριώνεται στο [#6940](https://github.com/diegosouzapw/OmniRoute/issues/6940). Επειδή η επίλυση combo ελέγχεται πριν από την επίλυση απλού model id (`getComboForModel()` στο `src/sse/services/model.ts`), ένα αίτημα για το απλό id `gpt-5.5` δρομολογείται μέσω των στόχων του combo (π.χ. `acme-responses/gpt-5.5`, `backup-responses/gpt-5.5`) αντί για απευθείας σε έναν μόνο πάροχο — αυτό επαναχρησιμοποιεί την προτεραιότητα combo-πριν-από-επανεγγραφή που δημιουργήθηκε για το [#3227/#3233](https://github.com/diegosouzapw/OmniRoute/issues/3227) και ελέγχεται με παλινδρομικά τεστ από τα `tests/unit/responses-combo-resolution-3227.test.ts` και `tests/unit/combo-name-codex-responses-rewrite.test.ts`. Η δημιουργία ή μετονομασία ενός combo σε όνομα που σκιάζει ένα πραγματικό model id **δεν απορρίπτεται ποτέ** — κάτι τέτοιο θα έσπαγε αυτήν την τεκμηριωμένη ροή εργασίας. Αντ' αυτού (#8530), τα `POST /api/combos` και `PUT /api/combos/[id]` επισυνάπτουν ένα μη αποκλειστικό πεδίο `warning` στην απόκριση όταν το (νέο) όνομα συγκρούεται με ένα πραγματικό model id: ```json { "warning": { "code": "COMBO_NAME_SHADOWS_MODEL", "modelId": "gpt-5.5", "providerId": "openai" } } ``` Κατά την εκκίνηση, η `scanComboModelNameCollisionsAtBoot()` (`src/instrumentation-node.ts`) καταγράφει επίσης μια μονόγραμμη προειδοποίηση `[STARTUP]` που απαριθμεί κάθε υπάρχον combo που σκιάζει ένα model id, ώστε οι διαχειριστές που το συναντούν κατά λάθος (αντί σκόπιμα, σύμφωνα με το #6940) να έχουν ένα σήμα. Το βοηθητικό εργαλείο εντοπισμού βρίσκεται στο `src/lib/combos/modelNameCollision.ts`. ## Κλήση Προσαρμοσμένου Combo από Πελάτη Τα αποθηκευμένα combo (Ρυθμίσεις → Combos) χρησιμοποιούνται μόνο όταν ο πελάτης αποστέλλει το **ακριβές όνομα** του combo στο πεδίο `model` — δεν υπάρχει ασαφής ή μερική αντιστοίχιση του ονόματος combo, ούτε εμπλέκεται πρόθεμα `auto/`. Σειρά επίλυσης (`getComboForModel()` στο `src/sse/services/model.ts`): 1. ακριβής αντιστοίχιση ονόματος combo (`model: "my-combo"`), 2. πρόθεμα `combo/` (`model: "combo/my-combo"`), 3. αντιστοιχίσεις glob model→combo (`/api/model-combo-mappings`). ```bash curl -X POST http://localhost:20128/v1/chat/completions \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{"model":"my-combo","messages":[{"role":"user","content":"Hello"}]}' ``` Δύο συνηθισμένες παγίδες: - **Το `auto` δεν χρησιμοποιεί τα combo σας.** Το `auto`/`auto/*` δημιουργεί τη δική του δεξαμενή υποψηφίων χωρίς ρύθμιση και συμβουλεύεται αποθηκευμένα combo μόνο αν ένα combo έχει κυριολεκτικά το όνομα `auto` (δεν συνιστάται). Για να δρομολογήσετε μέσω ενός combo, αποστείλετε το ακριβές όνομά του — όχι `auto`. - **Το `openrouter/auto` είναι ένα πραγματικό επί πληρωμή προϊόν OpenRouter** («Auto Best Available»), όχι ένα ψευδώνυμο OmniRoute. Αποτελεί την ενιαία στατική καταχώριση μοντέλου του μητρώου OpenRouter (`open-sse/config/providers/registry/openrouter/index.ts`) και χρεώνεται ξεχωριστά. Χρησιμοποιήστε Ρυθμίσεις → Δρομολόγηση → Απόκρυψη επί πληρωμή μοντέλων για να το εξαιρέσετε από τις δεξαμενές `auto`. Δείτε τα [#7992](https://github.com/diegosouzapw/OmniRoute/issues/7992) και [#7111](https://github.com/diegosouzapw/OmniRoute/issues/7111) για την αρχική σύγχυση που τεκμηριώνει αυτό το κείμενο. ## Πώς λειτουργεί (Αποθηκευμένοι Αυτόματοι Συνδυασμοί) Η Μηχανή Αυτόματων Συνδυασμών επιλέγει δυναμικά τον καλύτερο πάροχο/μοντέλο για κάθε αίτημα, χρησιμοποιώντας μια **συνάρτηση βαθμολόγησης 16 παραγόντων** (ορίζεται στο `open-sse/services/autoCombo/scoring.ts` → `DEFAULT_WEIGHTS`). Το άθροισμα των προεπιλεγμένων βαρών είναι `1.0`· τα προσαρμοσμένα βάρη κανονικοποιούνται εκ νέου από τη `normalizeScoringWeights()`. Δύο από τους δεκαέξι — `cacheAffinity` και `resetWindowAffinity` — έχουν προεπιλεγμένο βάρος `0`· το `reliability` έχει `0` στο `DEFAULT_WEIGHTS`, αλλά `0.03` στα γενικά πακέτα και `0.04` στο `reliability-first`, ενώ το `quality` έχει `0.02` στα πακέτα (`0.03` στο `quality-first`): εξακολουθούν να υπολογίζονται για κάθε υποψήφιο και το `cacheAffinity` ελέγχει την αποδιπλοποίηση της προσωρινής μνήμης προτροπών εκτός της βαθμολογίας, επομένως οι παράγοντες με προεπιλεγμένο βάρος μηδέν απλώς δεν συμμετέχουν στη βαθμολόγηση από προεπιλογή, ενώ στα πακέτα συμμετέχουν. ![Βαθμολόγηση 16 παραγόντων Αυτόματων Συνδυασμών](../diagrams/exported/auto-combo-scoring.svg) > Πηγή: [diagrams/auto-combo-scoring.mmd](../diagrams/auto-combo-scoring.mmd) (αναδημιουργήστε μέσω `npm run docs:render-diagrams`). Το όνομα αρχείου διατηρείται για ιστορικούς λόγους· ο πηγαίος κώδικας και το αποδοσμένο διάγραμμα εμφανίζουν και τους 16 παράγοντες που δηλώνονται στο `DEFAULT_WEIGHTS`. | Παράγοντας | Προεπιλεγμένο βάρος | Περιγραφή | | :-------------------- | :------------------ | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `quota` | 0.1429 | Υπολειπόμενο όριο χρήσης / διαθέσιμο περιθώριο ορίου ρυθμού [0..1] | | `health` | 0.1605 | Βαθμολογία εύρυθμης λειτουργίας από τον διακόπτη κυκλώματος (CLOSED=1.0, HALF_OPEN=0.5, OPEN=0.0) | | `costInv` | 0.1429 | Αντίστροφο **μικτό** κόστος (60% τιμή token εισόδου + 40% τιμή token εξόδου, κανονικοποιημένο) — χαμηλότερο κόστος = υψηλότερη βαθμολογία | | `latencyInv` | 0.1143 | Αντίστροφη καθυστέρηση p95, κανονικοποιημένη ως προς το σύνολο — μεγαλύτερη ταχύτητα = υψηλότερη βαθμολογία | | `taskFit` | 0.0762 | Καταλληλότητα για τον τύπο εργασίας (προγραμματισμός, αναθεώρηση, σχεδιασμός, ανάλυση, αποσφαλμάτωση, τεκμηρίωση) | | `stability` | 0.0476 | Σταθερότητα βάσει διακύμανσης από την τυπική απόκλιση της καθυστέρησης — ένας υποψήφιος του οποίου ο χρόνος απόκρισης παρουσιάζει έντονες διακυμάνσεις λαμβάνει χαμηλότερη βαθμολογία | | `tierPriority` | 0.0476 | Προτεραιότητα βαθμίδας λογαριασμού — Ultra=1.0, Pro=0.67, Standard=0.33, Free=0.0 | | `tierAffinity` | 0.0476 | Συνάφεια μεταξύ της βαθμίδας του υποψηφίου και της βαθμίδας που συνιστά το δηλωτικό | | `specificityMatch` | 0.0476 | Αντιστοίχιση μεταξύ της εξειδίκευσης του αιτήματος (υπόδειξη δηλωτικού) και της βαθμίδας του μοντέλου | | `contextAffinity` | 0.0476 | Συνάφεια μεταξύ της ανάγκης του αιτήματος για παράθυρο περιβάλλοντος και του παραθύρου περιβάλλοντος του μοντέλου | | `sessionAvailability` | 0.0476 | Διαθεσιμότητα συνεδρίας OAuth της υποψήφιας σύνδεσης για αυτήν τη συνεδρία (`getOAuthSessionAvailability()`· οι συνδέσεις που δεν χρησιμοποιούν OAuth λαμβάνουν βαθμολογία 1.0) | | `connectionDensity` | 0.0476 | Κατανέμει το φορτίο μεταξύ συνδέσεων του ίδιου παρόχου (αποφυγή συγκέντρωσης) | | `cacheAffinity` | 0.00 | Συνάφεια κατακερματισμού rendezvous προς τη σύνδεση που είναι πιθανότερο να διαθέτει ήδη το πρόθεμα προσωρινής μνήμης προτροπής αυτού του αιτήματος (`open-sse/services/combo/promptCacheAffinity.ts`)· απενεργοποιημένη από προεπιλογή (#8008) | | `resetWindowAffinity` | 0.00 | Προτίμηση προς συνδέσεις των οποίων το παράθυρο επαναφοράς ορίου χρήσης είναι ευνοϊκό (απενεργοποιημένη από προεπιλογή) | | `quality` | 0.03 | Σήμα ποιότητας εξόδου βάσει σχολίων από τον ιχνηλάτη ποιότητας συμβάντων δρομολόγησης· οι υποψήφιοι χωρίς παρατηρήσεις λαμβάνουν ουδέτερη τιμή 0.5 | | `reliability` | 0.00 | Παρατηρούμενο ποσοστό επιτυχίας, `1 - failureRate`, από ιστορικό χρήσης 24 ωρών με ελάχιστο όριο δέκα δειγμάτων (διαφορετικά χρησιμοποιούνται μετρικές πραγματικού χρόνου)· οι υποψήφιοι χωρίς παρατηρήσεις θεωρούνται ότι έχουν τιμή 1.0. Απενεργοποιημένο από προεπιλογή | **Άθροισμα:** `0.1429 + 0.1605 + 0.1429 + 0.1143 + 0.0762 + (7 × 0.0476) + 0.00 + 0.00 + 0.03 + 0.00 = 1.0`, όπως δηλώνεται στο `DEFAULT_WEIGHTS`· τα βάρη που διαμορφώνονται από τον χρήστη κανονικοποιούνται εκ νέου σε μια κατανομή από τη `normalizeScoringWeights()` πριν από τη βαθμολόγηση. ## Πακέτα λειτουργίας 6 προκαθορισμένα προφίλ βαρών στο `open-sse/services/autoCombo/modePacks.ts`. Κάθε πακέτο αντικαθιστά πλήρως τα προεπιλεγμένα βάρη, ώστε να κατευθύνει την επιλογή προς έναν στόχο. Το άθροισμα κάθε πακέτου είναι ήδη `1.0` (`0.9999` όπως εμφανίζεται με τέσσερα δεκαδικά ψηφία), επομένως η `normalizeScoringWeights()` δεν έχει κάτι ουσιαστικό να διορθώσει όταν ένα πακέτο είναι ενεργό — οι παρακάτω τιμές είναι, με την επιφύλαξη της στρογγυλοποίησης, αυτές που εφαρμόζει ο μηχανισμός βαθμολόγησης. | Παράγοντας | ship-fast | cost-saver | quality-first | offline-friendly | reliability-first | chaos-mode | | :-------------------- | :--------- | :--------- | :------------ | :--------------- | :---------------- | :--------- | | `quota` | 0.1133 | 0.1133 | 0.0752 | **0.3324** | 0.1133 | 0.0376 | | `health` | 0.2667 | 0.1810 | 0.1714 | 0.2667 | **0.3524** | **0.4000** | | `costInv` | 0.0276 | **0.3324** | 0.0276 | 0.0752 | 0.0181 | 0.0140 | | `latencyInv` | **0.3048** | 0.0476 | 0.0476 | 0.0476 | 0.0476 | 0.0186 | | `taskFit` | 0.0952 | 0.0952 | **0.3524** | 0.0000 | 0.0952 | 0.1905 | | `stability` | 0.0000 | 0.0476 | 0.1429 | 0.0952 | 0.1905 | 0.1714 | | `tierPriority` | 0.0376 | 0.0376 | 0.0276 | 0.0376 | 0.0276 | 0.0040 | | `tierAffinity` | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | | `specificityMatch` | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | | `contextAffinity` | 0.0095 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0186 | | `sessionAvailability` | 0.0476 | 0.0476 | 0.0476 | 0.0476 | 0.0476 | 0.0476 | | `resetWindowAffinity` | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | 0.0000 | | `connectionDensity` | 0.0476 | 0.0476 | 0.0476 | 0.0476 | 0.0476 | 0.0476 | | `quality` | 0.02 | 0.02 | **0.03** | 0.02 | 0.02 | 0.02 | | `reliability` | 0.03 | 0.03 | 0.03 | 0.03 | **0.04** | 0.03 | Σημειώσεις: - **Τα πακέτα περιλαμβάνουν τα `quality` και `reliability`** (`quality 0.02`, `quality-first 0.03`· `reliability 0.03`, `reliability-first 0.04`) και αντικαθιστούν εξ ολοκλήρου τον χάρτη βαρών (`weights = pack`, όχι συγχώνευση). Το `DEFAULT_WEIGHTS` περιλαμβάνει `quality 0.03 / reliability 0`· η επιλογή `balanced`/`default` διατηρεί αυτές τις προεπιλογές, ενώ η επιλογή ενός πακέτου χρησιμοποιεί τις παραπάνω τιμές του πακέτου. Σε ένα μη προθερμασμένο pool (χωρίς παρατηρήσεις ακόμη, επομένως `quality 0.5` και `reliability 1`), αυτοί οι δύο παράγοντες προσθέτουν `+0.04` με ένα γενικό πακέτο (`0.03 + 0.01`), `+0.045` με το `quality-first` και `+0.05` με το `reliability-first`. - Τα `tierAffinity`, `specificityMatch` και `resetWindowAffinity` είναι ρητά ορισμένα σε `0` σε κάθε πακέτο. - Η έμφαση κάθε πακέτου με μια ματιά: - **ship-fast** → latencyInv 0.3048 + health 0.2667 (συνδέσεις χαμηλού λανθάνοντος χρόνου και καλής κατάστασης) - **cost-saver** → costInv 0.3324 (κερδίζουν τα φθηνότερα token) - **quality-first** → taskFit 0.3524 + stability 0.1429 + quality 0.03, το υψηλότερο από οποιοδήποτε πακέτο (το καλύτερο μοντέλο για την εργασία, με συνέπεια) - **offline-friendly** → quota 0.3324 + health 0.2667 (μέγιστο διαθέσιμο περιθώριο, ανεξάρτητα από την ταχύτητα/το κόστος) - **reliability-first** → health 0.3524 + stability 0.1905 + reliability 0.04, το υψηλότερο από οποιοδήποτε πακέτο (οι λιγότερες εκπλήξεις) - **chaos-mode** → health 0.4000 + taskFit 0.1905 (προφίλ εισαγωγής σφαλμάτων) ### Στοιχεία ελέγχου ανά αίτημα (κεφαλίδες) — #6023 / #6024 / #6025 / #3470 Ένας συνδυασμός `auto` μπορεί να κατευθυνθεί **ανά αίτημα** μέσω τριών κεφαλίδων, χωρίς να τροποποιείται η αποθηκευμένη διαμόρφωση του συνδυασμού. Αυτές εφαρμόζονται μόνο στη στρατηγική `auto` και μόνο για το αίτημα που τις περιλαμβάνει· τα αποθηκευμένα `modePack`/`budgetCap`/`budgetFallback` του συνδυασμού χρησιμοποιούνται όταν απουσιάζει η κεφαλίδα. | Κεφαλίδα | Δέχεται | Επίδραση | | :---------------------------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `X-OmniRoute-Mode` | ένα προκαθορισμένο ψευδώνυμο (`fast`, `balanced`, `quality`, `cheap`, `reliable`, `offline`) ή ένα ακατέργαστο όνομα πακέτου (`ship-fast`, `cost-saver`, `quality-first`, `offline-friendly`, `reliability-first`) | Παρακάμπτει τα βάρη βαθμολόγησης για αυτό το αίτημα. Τα `balanced`/`default` επιβάλλουν τα προεπιλεγμένα βάρη (χωρίς πακέτο). Οι άγνωστες τιμές αγνοούνται (η διαμόρφωση διατηρείται). | | `X-OmniRoute-Budget` | έναν θετικό αριθμό (μέγιστο ποσό USD ανά αίτημα) | Αυστηρό ανώτατο όριο κόστους: οι υποψήφιοι των οποίων το εκτιμώμενο κόστος το υπερβαίνει φιλτράρονται πριν από την επιλογή. Το τι συμβαίνει όταν **κάθε** υποψήφιος το υπερβαίνει ελέγχεται από το `X-OmniRoute-Budget-Fallback` παρακάτω. | | `X-OmniRoute-Budget-Fallback` | `cheapest` (προεπιλογή, ψευδώνυμα: `cheapest-viable`, `soft`) ή `strict` (ψευδώνυμα: `block`, `hard`) | `cheapest`: καταφεύγει στον φθηνότερο υποψήφιο συνολικά, παρόλο που εξακολουθεί να υπερβαίνει το όριο (παλαιότερη συμπεριφορά). `strict`: αρνείται να κάνει επιλογή — το αίτημα αποτυγχάνει άμεσα με `HTTP 402` αντί να υπερβαίνει σιωπηρά τον προϋπολογισμό. Οι άγνωστες τιμές αγνοούνται. | | `X-OmniRoute-Effort` | `auto` (οι υπόλοιπες τιμές είναι δεσμευμένες) | Προσαρμοστικός προϋπολογισμός συλλογισμού: όταν το αίτημα **δεν** περιέχει πεδίο συλλογισμού οποιασδήποτε μορφής (`reasoning_effort`, `reasoning`, `thinking`), η πύλη αντιστοιχίζει το `auto` σε `low`/`medium`/`high` βάσει ντετερμινιστικών ενδείξεων από τη δομή του αιτήματος (μήκος τελευταίου μηνύματος χρήστη, μέγεθος περιεχομένου έως το τελευταίο μήνυμα χρήστη, προηγούμενα αποτελέσματα εργαλείων, βάθος βρόχου εργαλείων). Οι ενδείξεις περιορίζονται στην τρέχουσα αλληλεπίδραση — οτιδήποτε μετά το τελευταίο μήνυμα χρήστη αγνοείται — έτσι ώστε κάθε αίτημα σε έναν βρόχο εργαλείων να αντιστοιχίζεται στο ίδιο επίπεδο (σταθερή αντιστοίχιση ανά αλληλεπίδραση χωρίς κατάσταση, χωρίς κατάσταση συνεδρίας και χωρίς κλιμάκωση στη μέση του βρόχου που θα διέκοπτε τα προθέματα της προσωρινής μνήμης προτροπών του ανάντη συστήματος). Ένα ρητό πεδίο συλλογισμού από τον πελάτη υπερισχύει πάντα. Περιορίζεται σε αιτήματα των οποίων η ανάντη αποστολή αντιστοιχίζεται στη μορφή OpenAI Chat Completions (`targetFormat === FORMATS.OPENAI`) — το `reasoning_effort` είναι πεδίο μορφής OpenAI, επομένως η κεφαλίδα δεν έχει καμία επίδραση σε αίτημα που στοχεύει το Claude ή το Gemini (δείτε `open-sse/handlers/chatCore/adaptiveEffortWiring.ts`). | ```bash # Επιβολή του ταχύτερου προφίλ, περιορισμός αυτού του αιτήματος στα $0.05 και αυστηρός αποκλεισμός αντί υπέρβασης του προϋπολογισμού curl -sS http://localhost:20128/v1/chat/completions \ -H "Content-Type: application/json" \ -H "X-OmniRoute-Mode: fast" \ -H "X-OmniRoute-Budget: 0.05" \ -H "X-OmniRoute-Budget-Fallback: strict" \ -d '{"model":"auto","messages":[{"role":"user","content":"hi"}]}' ``` Η επίλυση είναι μια αμιγής συνάρτηση (`open-sse/services/autoCombo/requestControls.ts`)· οι τιμές που προκύπτουν διοχετεύονται στις υπάρχουσες εισόδους `config.modePack` / `config.budgetCap` / `config.budgetFallback` της μηχανής. Η αποθηκευμένη τιμή `config.budgetFallback` ενός συνδυασμού ("strict" | "cheapest") καθορίζει τη μόνιμη πολιτική· η κεφαλίδα την παρακάμπτει για ένα μόνο αίτημα. ## Όλες οι Στρατηγικές Δρομολόγησης Ο κινητήρας combo του OmniRoute υποστηρίζει **19 στρατηγικές δρομολόγησης** (δηλωμένες στο `src/shared/constants/routingStrategies.ts` → `ROUTING_STRATEGY_VALUES`). Ο ίδιος ο κινητήρας Auto Combo εκτίθεται κάτω από τη στρατηγική `auto`· οι υπόλοιπες είναι διαθέσιμες για αποθηκευμένα combo. | Στρατηγική | Περιγραφή | | :------------------ | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `priority` | Διατεταγμένη λίστα πρώτου στόχου με ρητή προτεραιότητα | | `weighted` | Τυχαία επιλογή με βάρος ανά στόχο | | `round-robin` | Εναλλαγή μεταξύ στόχων με σειρά | | `context-relay` | Μεταφορά πλαισίου μεταξύ στόχων (μεγάλες συνομιλίες) | | `fill-first` | Συμπλήρωση της ποσόστωσης κάθε στόχου πριν μεταβεί στον επόμενο | | `p2c` | Τυχαία εξισορρόπηση φορτίου με τη μέθοδο Power-of-2-choices | | `random` | Ομοιόμορφη τυχαία επιλογή | | `least-used` | Επιλογή του στόχου με το χαμηλότερο τρέχον φορτίο | | `cost-optimized` | Ελαχιστοποίηση κόστους $ ανά αίτημα βάσει τιμοκαταλόγου | | `reset-aware` ⭐ | Ιεράρχηση βάσει χρόνου επαναφοράς ποσόστωσης — τα μικρά παράθυρα επαναφοράς κατατάσσονται υψηλότερα | | `reset-window` | Προτίμηση στόχων των οποίων το παράθυρο ποσόστωσης επαναφέρεται συντομότερα | | `headroom` | Επιλογή του στόχου με το μεγαλύτερο υπολειπόμενο περιθώριο ποσόστωσης | | `strict-random` | Τυχαία επιλογή χωρίς αποκλεισμό επαναλήψεων | | `auto` | Χρήση βαθμολόγησης Auto Combo (16 παράγοντες) — **συνιστάται** | | `lkgp` | Last-Known-Good Path (καρφιτσώνει στον τελευταίο επιτυχή πάροχο, με εναλλακτική επιστροφή στους κανόνες) | | `context-optimized` | Επιλογή του στόχου που ταιριάζει καλύτερα στο τρέχον μέγεθος πλαισίου | | `cache-optimized` | Αναδιάταξη στόχων βάσει συγγένειας με την cache προτροπής — η σύνδεση που είναι πιθανότερο να έχει ήδη αποθηκευμένο το πρόθεμα cache αυτού του αιτήματος δοκιμάζεται πρώτη (`open-sse/services/combo/promptCacheAffinity.ts`, #8008) | | `fusion` 🧬 | Εξάπλωση σε ένα πλαίσιο μοντέλων παράλληλα, με σύνθεση μίας απάντησης μέσω κριτή (βλ. παρακάτω) | | `pipeline` | Εκτέλεση στόχων διαδοχικά, διοχετεύοντας την έξοδο κάθε βήματος ως είσοδο στο επόμενο· επιστρέφεται μόνο η τελική απάντηση (#6396) | ⭐ = Νέο στην έκδοση v3.8.0 · 🧬 = Νέο στην έκδοση v3.8.36 ### Σημασιολογία του `weighted` Το `weighted` είναι μια **αναλογική τυχαία κλήρωση ανά αίτημα** (`open-sse/services/combo/targetSorters.ts` → `selectWeightedTarget`), όχι εξισωτής: - Κάθε αίτημα κληρώνει **ένα** βήμα με πιθανότητα `weight / totalWeight`· τα υπόλοιπα βήματα ταξινομούνται κατά φθίνουσα σειρά βάρους ως εναλλακτική αλυσίδα για αυτό το αίτημα. - Ένα βήμα με βάρος `0` (ή χωρίς βάρος) **δεν κληρώνεται ποτέ** ενώ κάποιο άλλο βήμα έχει βάρος > 0 — μπορεί να εξυπηρετήσει μόνο ως εναλλακτική μετά την αποτυχία του κληρωμένου βήματος. Μόνο όταν **όλα** τα βάρη είναι 0 η επιλογή γίνεται ομοιόμορφη. - Βήματα των οποίων οι στόχοι δεν είναι διαθέσιμοι — circuit breaker παρόχου `OPEN`, cooldown σύνδεσης, αποκλεισμός μοντέλου — αφαιρούνται από την κλήρωση πριν αυτή πραγματοποιηθεί (`open-sse/services/combo/targetResolution.ts`), οπότε ένα μόνο υγιές βήμα μπορεί προσωρινά να κερδίζει κάθε αίτημα. - Το `stickyWeightedLimit` (ρύθμιση combo, προεπιλογή `1` = απενεργοποιημένο) καρφιτσώνει το κληρωμένο βήμα για τόσες συνεχόμενες επιτυχίες πριν γίνει νέα κλήρωση. Για αυστηρή εναλλαγή χρησιμοποιήστε `round-robin`· ίσα βάρη στο `weighted` δίνουν στατιστική — όχι αυστηρή — ισορροπία. ## Στρατηγική Fusion Το `fusion` είναι η μοναδική στρατηγική που **δεν** επιλέγει έναν μόνο στόχο. Διανέμει το prompt σε **κάθε μοντέλο του πάνελ παράλληλα**, και στη συνέχεια ένα ρυθμιζόμενο **μοντέλο-κριτής** συνθέτει μία τελική απάντηση από όλες τις απαντήσεις του πάνελ. Μεταφέρθηκε από το upstream `decolua/9router` (σχεδιασμός Fusion του OpenRouter)· υλοποίηση στο `open-sse/services/fusion.ts`. Πώς λειτουργεί: 0. **Παράκαμψη εργαλείων** — ένα αίτημα που φέρει μη κενό πίνακα `tools` με `tool_choice` που δεν είναι ρητά `"none"` παρακάμπτει εντελώς το πάνελ: δρομολογείται απευθείας σε ένα μοναδικό μοντέλο (το ρυθμισμένο κριτής, ή `panel[0]`) με `tools`/`tool_choice` που περνούν αναλλοίωτα. Τα μέλη του πάνελ δεν έχουν πρόσβαση σε εργαλεία και η οδηγία σύνθεσης του κριτή αποθαρρύνει την εκπομπή κλήσεων εργαλείων, οπότε οι agentic/tool-calling πελάτες λαμβάνουν πραγματική απόφαση κλήσης εργαλείου αντί για συντεθειμένο κείμενο (#6771). 1. **Fan-out** (μόνο για αιτήματα χωρίς εργαλεία) — το prompt αποστέλλεται σε κάθε μοντέλο του πάνελ ταυτόχρονα, αναγκαστικά χωρίς streaming και χωρίς εργαλεία (ο κριτής χρειάζεται πλήρες κείμενο για να συνθέσει). 2. **Συλλογή με χάρη απαρτίας** — μόλις φτάσουν `minPanel` απαντήσεις, ξεκινά ένας σύντομος χρονοδιακόπτης χάριτος για τους αργούς, και στη συνέχεια η fusion προχωρά με όσα έχουν συλλεχθεί. Αυτό περιορίζει την επίπτωση του πιο αργού μοντέλου στον χρόνο τοίχου, με ένα απόλυτο χρονικό όριο ως ανώτατο φράγμα. 3. **Σύνθεση κριτή** — οι απαντήσεις του πάνελ ανωνυμοποιούνται (`Source 1`, `Source 2`, … — ώστε ο κριτής να σταθμίζει το περιεχόμενο, όχι το brand του μοντέλου) και παραδίδονται στον κριτή, ο οποίος αναλύει συναίνεση / αντιφάσεις / μερική κάλυψη / μοναδικές επισημάνσεις / τυφλά σημεία, και στη συνέχεια γράφει **μία** αυθεντική απάντηση. Η κλήση του κριτή διατηρεί το αρχικό `stream` flag του πελάτη + εργαλεία, οπότε το streaming και η χρήση εργαλείων downstream εξακολουθούν να λειτουργούν. 4. **Ομαλή υποβάθμιση** — 0 απαντήσεις πάνελ → `503`· ακριβώς 1 επιζώσα απάντηση → επιστρέφεται απευθείας (τίποτα να συντεθεί)· ένα πάνελ μονού μοντέλου απαντά απευθείας. Ένα μέλος του πάνελ μπορεί επίσης να είναι ένα βήμα `combo-ref` (`{kind: "combo-ref", comboName: "..."}`) που αναφέρεται σε άλλο combo — επιλύεται ως **μία αδιαφανής φωνή πάνελ** (μια πλήρης αναδρομική αποστολή στο αναφερόμενο combo, όχι fan-out των ίδιων στόχων του combo), με την ίδια προστασία βάθους/κύκλου που χρησιμοποιεί κάθε άλλη στρατηγική που καταναλώνει combo-ref (#6764). ### Ρύθμιση παραμέτρων Ρυθμίζεται στο blob `config` του combo (χωρίς μετανάστευση σχήματος — επαναχρησιμοποιεί τον υπάρχοντα πίνακα `combos`): | Πεδίο | Τύπος | Προεπιλογή | Σκοπός | | :--------------------------------------- | :------- | :------------------ | :--------------------------------------------------------------------------------------------------------------- | | `config.judgeModel` | `string` | πρώτο μοντέλο πάνελ | Μοντέλο που συνθέτει την τελική απάντηση | | `config.fusionTuning.minPanel` | `number` | `2` | Επιτυχείς απαντήσεις που απαιτούνται πριν ξεκινήσει ο χρονοδιακόπτης χάριτος (περιορισμένο στο `[2, panelSize]`) | | `config.fusionTuning.stragglerGraceMs` | `number` | `8000` | Πόση ώρα να περιμένει τους αργούς μόλις επιτευχθεί η απαρτία | | `config.fusionTuning.panelHardTimeoutMs` | `number` | `90000` | Απόλυτο ανώτατο όριο ώστε ένα κολλημένο μοντέλο να μην μπλοκάρει το αίτημα | Οι προεπιλογές βρίσκονται στο `FUSION_DEFAULTS` (`open-sse/services/fusion.ts`). ### Παράδειγμα ```bash curl -X POST http://localhost:20128/api/combos \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{ "name": "fusion-panel", "strategy": "fusion", "targets": [ { "model": "cc/claude-opus-4-7" }, { "model": "cx/gpt-5.5" }, { "model": "glm/glm-5.1" } ], "config": { "judgeModel": "cc/claude-opus-4-7", "fusionTuning": { "minPanel": 2, "stragglerGraceMs": 8000, "panelHardTimeoutMs": 90000 } } }' ``` Στη συνέχεια καλέστε το όπως οποιοδήποτε combo: `{"model":"fusion-panel","messages":[...]}`. ## Εικονικό Εργοστάσιο Αυτόματου Συνδυασμού Η μηχανή Auto Combo δεν απαιτεί προκαθορισμένους συνδυασμούς. Αντίθετα, το `open-sse/services/autoCombo/virtualFactory.ts` δημιουργεί υποψήφιους εν κινήσει: 1. Ανακτά `getProviderConnections({ isActive: true })` (όλες οι ενεργοποιημένες συνδέσεις) 2. Φιλτράρει σε αυτές με έγκυρα διαπιστευτήρια (κλειδί API ή μη-ληγμένο OAuth token μέσω `hasUsableOAuthToken()`) 3. Διασταυρώνει με `getProviderRegistry()` για διαθεσιμότητα μοντέλων + τιμολόγηση 4. Για κάθε πλειάδα `(provider, model, connection)`, κατασκευάζει ένα `VirtualAutoComboCandidate` 5. Επιλέγει `connection.defaultModel` (ή το πρώτο μοντέλο του μητρώου) ως στόχο αποστολής 6. Βαθμολογεί κάθε υποψήφιο χρησιμοποιώντας τη 16-παραγοντική `scorePool()` και το πακέτο βαρών της παραλλαγής 7. Επιστρέφει το προκύπτον `AutoComboConfig` στη μνήμη για το `handleComboChat()` — δεν αποθηκεύεται ποτέ στη βάση δεδομένων Αυτό σημαίνει ότι **η προσθήκη νέου παρόχου με ενεργοποιημένο `auto/*` επεκτείνει αυτόματα το σύνολο υποψηφίων** — δεν χρειάζεται χειροκίνητη επεξεργασία συνδυασμών. Ο εικονικός συνδυασμός ανακατασκευάζεται ανά αίτημα, οπότε οι νέες ή πρόσφατα υγιείς συνδέσεις εντοπίζονται αμέσως. ## Αυτο-Επαναφορά - **Προσωρινός αποκλεισμός**: Βαθμολογία < 0.2 → αποκλεισμός για 5 λεπτά (προοδευτική καθυστέρηση, μέγ. 30 λεπτά) - **Αναγνώριση ασφαλιστήρου κυκλώματος**: OPEN → αυτόματος αποκλεισμός· HALF_OPEN → αιτήματα ανίχνευσης - **Λειτουργία συμβάντος**: >50% OPEN → απενεργοποίηση εξερεύνησης, μεγιστοποίηση σταθερότητας - **Ανάκαμψη μετά αποκλεισμό**: Μετά τον αποκλεισμό, το πρώτο αίτημα είναι «ανίχνευση» με μειωμένο χρονικό όριο ## Εξερεύνηση Bandit Το 5% των αιτημάτων (ρυθμιζόμενο) δρομολογείται σε τυχαίους παρόχους για εξερεύνηση. Απενεργοποιείται σε λειτουργία συμβάντος. ## API **Δεν υπάρχει αποκλειστικό endpoint `POST /api/combos/auto`** — το Auto-Combo καταναλώνεται με δύο τρόπους: 1. **Μηδενική διαμόρφωση (προτεινόμενο):** Στείλτε οποιοδήποτε αίτημα ολοκλήρωσης συνομιλίας με `model: "auto"` ή `model: "auto/"`. Το εικονικό εργοστάσιο δημιουργεί τον συνδυασμό ανά αίτημα — χωρίς αποθήκευση, χωρίς κλήσεις API. 2. **Αποθηκευμένος συνδυασμός με `strategy: "auto"`:** Δημιουργήστε έναν κανονικό συνδυασμό μέσω `POST /api/combos` και ορίστε `strategy: "auto"` καθώς και `config.auto.weights` / `config.auto.candidatePool`. Χρησιμοποιείται η ίδια μηχανή βαθμολόγησης· ο συνδυασμός αποθηκεύεται στο `combos` και μπορεί να επαναχρησιμοποιηθεί μέσω ID. Για ανακάλυψη, το `GET /api/combos/auto` καταγράφει κάθε παραλλαγή με το επιλυμένο σύνολο υποψηφίων της, καθώς και `context_length` / `max_output_tokens` — το ΜΕΓΙΣΤΟ στα παράθυρα του συνόλου υποψηφίων. Οι πελάτες (π.χ. το plugin opencode) πρέπει να διαφημίζουν αυτές τις τιμές αντί για `0`: ένα μηδενικό context απενεργοποιεί εντελώς την αυτόματη συμπίεση του opencode, αφήνοντας τις συνεδρίες να μεγαλώνουν μέχρι να καταστρέψει το context η εκκαθάριση ιστορικού της πύλης. Το ΜΕΓΙΣΤΟ είναι ασφαλές να διαφημίζεται επειδή το προ-φίλτρο context του auto-combo δρομολογεί υπερμεγέθη αιτήματα σε υποψηφίους με μεγάλο παράθυρο. ```bash # Χρήση μηδενικής διαμόρφωσης (χωρίς δημιουργία συνδυασμού) curl -X POST http://localhost:20128/v1/chat/completions \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -d '{"model":"auto/coding","messages":[{"role":"user","content":"Hello"}]}' # Αποθηκευμένος αυτόματος συνδυασμός μέσω του κανονικού endpoint συνδυασμών curl -X POST http://localhost:20128/api/combos \ -H "Content-Type: application/json" \ -d '{"id":"my-auto","name":"Auto Coder","strategy":"auto","config":{"auto":{"candidatePool":["anthropic","google","openai"],"weights":{"quota":0.15,"health":0.3,"costInv":0.05,"latencyInv":0.35,"taskFit":0.1,"stability":0,"tierPriority":0.05}}}}' ``` ### Στρατηγικές αυτόματου δρομολογητή Οι αποθηκευμένοι συνδυασμοί `strategy: "auto"` μπορούν να ορίσουν `config.routerStrategy` (ή το παλαιό `config.auto.routerStrategy`) σε μία από τις παρακάτω: - `rules` — προεπιλεγμένη σταθμισμένη βαθμολόγηση - `score` — επιλέγει την υψηλότερη ρυθμισμένη σταθμισμένη βαθμολογία. Ακριβείς ισοπαλίες διατηρούν τη ρυθμισμένη σειρά υποψηφίων· το υπάρχον `explorationRate` δειγματοληπτεί από το πλήρες κατατεταγμένο σύνολο. - `cost` / `eco` — φθηνότερος υγιής πάροχος - `latency` / `fast` — χαμηλότερη καθυστέρηση p95 με ποινή αξιοπιστίας - `sla-aware` / `sla` — προτίμηση υποψηφίων που ικανοποιούν SLO καθυστέρησης p95, ποσοστού σφαλμάτων και προαιρετικού κόστους - `lkgp` — τελευταίος γνωστός καλός πάροχος πρώτα ### Λεπτομέρειες στρατηγικών δρομολογητή Η μηχανή auto-combo παρέχει 6 αντικαταστάσιμες υλοποιήσεις **RouterStrategy** τις οποίες μπορείτε να αλλάξετε μέσω `config.routerStrategy` (ή του παλαιού `config.auto.routerStrategy`). Κάθε στρατηγική επιλέγει έναν πάροχο από το σύνολο υποψηφίων, δεδομένου ενός `RoutingContext` (τύπος εργασίας, υποδείξεις εργαλείων/όρασης, εκτίμηση tokens, προαιρετική πολιτική SLA, προαιρετικός τελευταίος γνωστός καλός πάροχος). #### 1. `rules` (προεπιλογή) — 16-παραγοντική σταθμισμένη βαθμολόγηση Τυλίγει την υπάρχουσα μηχανή βαθμολόγησης. Φιλτράρει υποψηφίους με `OPEN` ασφαλιστήριο κυκλώματος, έπειτα εκτελεί `scorePool()` με τον τρέχοντα τύπο εργασίας και `getTaskFitness()`, επιλέγοντας τον πάροχο με την υψηλότερη βαθμολογία. ```ts class RulesStrategyImpl implements RouterStrategy { readonly name = "rules"; readonly description = "16-factor weighted scoring (see DEFAULT_WEIGHTS)"; select(pool, context) { const eligible = pool.filter((c) => c.circuitBreakerState !== "OPEN"); const ranked = scorePool( eligible.length > 0 ? eligible : pool, context.taskType, undefined, getTaskFitness ); return { provider: ranked[0].provider /* ... */ }; } } ``` **Πότε να χρησιμοποιήσετε**: Προεπιλογή. Χρησιμοποιήστε όταν θέλετε ισορροπημένο συμβιβασμό σε όλα τα σήματα. **Ψευδώνυμο**: `rules` (χωρίς ψευδώνυμο) --- #### 2. `cost` / `eco` — φθηνότερος υγιής πάροχος Ταξινομεί το σύνολο υποψηφίων κατά `costPer1MTokens` (αύξουσα) και επιλέγει τον φθηνότερο. Φιλτράρει πρώτα τους υποψηφίους με `OPEN`. ```ts class CostStrategyImpl implements RouterStrategy { readonly name = "cost"; readonly description = "Always selects cheapest available provider"; select(pool, context) { const healthy = pool.filter((c) => c.circuitBreakerState !== "OPEN"); const sorted = [...healthy].sort((a, b) => a.costPer1MTokens - b.costPer1MTokens); return { provider: sorted[0].provider /* ... */ }; } } ``` **Πότε να χρησιμοποιήσετε**: Φόρτοι εργασίας ευαίσθητοι στο κόστος, ομαδική επεξεργασία ή εργασίες παρασκηνίου. **Ψευδώνυμα**: `cost`, `eco` --- #### 3. `latency` / `fast` — χαμηλότερη καθυστέρηση p95 με ποινή αξιοπιστίας Ταξινομεί κατά `p95LatencyMs + (errorRate * 1000)`. Η ποινή ποσοστού σφαλμάτων διασφαλίζει ότι οι αναξιόπιστοι πάροχοι κατατάσσονται χαμηλότερα ακόμα και αν η ονομαστική τους καθυστέρηση είναι χαμηλή. ```ts class LatencyStrategyImpl implements RouterStrategy { readonly name = "latency"; readonly description = "Prioritizes lowest p95 latency with reliability weighting"; select(pool, context) { const healthy = pool.filter((c) => c.circuitBreakerState !== "OPEN"); const sorted = [...healthy].sort( (a, b) => a.p95LatencyMs + a.errorRate * 1000 - (b.p95LatencyMs + b.errorRate * 1000) ); return { provider: sorted[0].provider /* ... */ }; } } ``` **Πότε να χρησιμοποιήσετε**: Φόρτοι εργασίας ευαίσθητοι στην καθυστέρηση, όπως πραγματικής ώρας συνομιλία, αυτόματη συμπλήρωση ή διαδραστικοί βοηθοί κωδικοποίησης. **Ψευδώνυμα**: `latency`, `fast` --- #### 4. `sla-aware` / `sla` — συμμόρφωση SLO καθυστέρησης/σφαλμάτων/κόστους Βαθμολογεί κάθε υποψήφιο ανάλογα με το πόσο καλά ικανοποιεί τη ρυθμισμένη πολιτική SLO: | Παράγοντας | Βάρος | Τύπος | | ----------------------- | ----- | --------------------------------------------------------- | | Βαθμολογία καθυστέρησης | 35% | `threshold / max(value, ε)` | | Βαθμολογία σφαλμάτων | 35% | `threshold / max(value, ε)` | | Βαθμολογία υγείας | 15% | `1.0` (CLOSED) / `0.5` (HALF_OPEN) / `0.0` (OPEN) | | Βαθμολογία κόστους | 10% | `threshold / max(value, ε)` ή αντίστροφα κανονικοποιημένο | | Βαθμολογία σταθερότητας | 5% | αντίστροφα κανονικοποιημένη τυπική απόκλιση καθυστέρησης | Όταν `hardConstraints: true`, οι υποψήφιοι ταξινομούνται πρωτίστως κατά **βαθμολογία παραβίασης** (πόσο υπερβαίνουν οποιοδήποτε SLO), έπειτα κατά σύνθετη βαθμολογία. Διαφορετικά είναι απλώς η σύνθετη βαθμολογία. ```ts class SLAStrategyImpl implements RouterStrategy { readonly name = "sla-aware"; readonly description = "Selects the provider most likely to satisfy latency, error-rate, and cost SLOs"; select(pool, context) { // ... βαθμολογεί κάθε υποψήφιο έναντι πολιτικής: { targetP95Ms, maxErrorRate, maxCostPer1MTokens, hardConstraints } } } ``` **Πεδία SLA** (ορίζονται στη διαμόρφωση του συνδυασμού): ```json { "strategy": "auto", "config": { "routerStrategy": "sla-aware", "slaTargetP95Ms": 1500, "slaMaxErrorRate": 0.05, "slaMaxCostPer1MTokens": 5, "slaHardConstraints": true } } ``` **Πότε να χρησιμοποιήσετε**: Φόρτοι εργασίας παραγωγής με αυστηρούς προϋπολογισμούς καθυστέρησης, ποσοστού σφαλμάτων ή κόστους. **Ψευδώνυμα**: `sla-aware`, `sla` --- #### 5. `lkgp` — τελευταίος γνωστός καλός πάροχος πρώτα Δοκιμάζει πρώτα τον **τελευταίο γνωστό καλό πάροχο** (εφόσον έχει οριστεί), έπειτα ανατρέχει στη στρατηγική `rules`. Χρήσιμο για συνεκτικότητα συνεδρίας — ο ίδιος πάροχος χειρίζεται τα αιτήματα συνέχισης σε μια συνομιλία. ```ts class LKGPStrategyImpl implements RouterStrategy { readonly name = "lkgp"; readonly description = "Tries last known good provider first, then falls back to rules"; select(pool, context) { if (context.lkgpEnabled === false) { return getStrategy("rules").select(pool, context); } if (context.lastKnownGoodProvider) { const candidates = pool.filter( (c) => c.provider === context.lastKnownGoodProvider && c.circuitBreakerState !== "OPEN" ); if (candidates.length > 0) { return { provider: candidates[0].provider /* ... */ }; } } // Ανάδρομη χρήση στρατηγικής rules return getStrategy("rules").select(pool, context); } } ``` **Πότε να χρησιμοποιήσετε**: Πολύ-στροφές συνομιλίες όπου θέλετε ο ίδιος πάροχος να χειρίζεται τα αιτήματα συνέχισης (π.χ. για caching, συνέχεια context ή συνέπεια τιμολόγησης). **Ψευδώνυμο**: `lkgp` (χωρίς ψευδώνυμο) --- ### Προσαρμοσμένες στρατηγικές δρομολογητή Μπορείτε να καταχωρίσετε τη δική σας υλοποίηση `RouterStrategy` μέσω του δημόσιου API: ```ts import { registerStrategy, type RouterStrategy, } from "@omniroute/open-sse/services/autoCombo/routerStrategy"; class MyCustomStrategy implements RouterStrategy { readonly name = "my-custom"; readonly description = "My custom routing strategy"; select(pool, context) { // Η λογική δρομολόγησής σας εδώ return { provider: pool[0].provider, model: pool[0].model, strategy: this.name, reason: "MyCustomStrategy: ...", candidatesConsidered: pool.length, finalScore: 1.0, }; } } registerStrategy("my-custom", new MyCustomStrategy()); ``` Έπειτα χρησιμοποιήστε το: ```json { "strategy": "auto", "config": { "routerStrategy": "my-custom" } } ``` --- ### Οδηγός επιλογής στρατηγικής δρομολογητή | Περίπτωση χρήσης | Στρατηγική | Αιτιολογία | | ----------------------------- | ----------- | ------------------------------------------------- | | Ισορροπημένος φόρτος εργασίας | `rules` | Προεπιλογή — λαμβάνει υπόψη όλους τους παράγοντες | | Ελαχιστοποίηση κόστους | `cost` | Επιλέγει πάντα τον φθηνότερο | | Ελαχιστοποίηση καθυστέρησης | `latency` | Επιλέγει τον γρηγορότερο αξιόπιστο πάροχο | | Αυστηρά SLO | `sla-aware` | Φιλτράρει κατά κατώφλια p95/σφαλμάτων/κόστους | | Πολύ-στροφής συνομιλία | `lkgp` | Συνεκτικότητα συνεδρίας | Πεδία SLA-aware: ```json { "strategy": "auto", "config": { "routerStrategy": "sla-aware", "slaTargetP95Ms": 1500, "slaMaxErrorRate": 0.05, "slaMaxCostPer1MTokens": 5, "slaHardConstraints": true } } ``` ## Καταλληλότητα Εργασιών 30+ μοντέλα βαθμολογήθηκαν σε 6 τύπους εργασιών (`coding`, `review`, `planning`, `analysis`, `debugging`, `documentation`). Υποστηρίζει μοτίβα μπαλαντέρ (π.χ., `*-coder` → υψηλή βαθμολογία coding). ## Ανακεφαλαίωση Αυτόματων Παραλλαγών Συμπεριλαμβανομένου του απλού `auto` (προεπιλογή) και των 6 τιμών `AutoVariant` που δηλώνονται στο `autoPrefix.ts`, υπάρχουν **7 επικαλέσιμα αναγνωριστικά μοντέλων**: `auto`, `auto/coding`, `auto/fast`, `auto/cheap`, `auto/offline`, `auto/smart`, `auto/lkgp` (Το `AutoVariant` απαριθμεί 6 τιμές· η 7η επιλογή είναι «χωρίς παραλλαγή» — απλό `auto` — που χειρίζεται από το `parseAutoPrefix()` ως `variant: undefined`.) ## Πώς εντάσσονται τα επίπεδα στο Auto-Combo Η συνάρτηση βαθμολόγησης 16 παραγόντων (`open-sse/services/autoCombo/scoring.ts`) αντιμετωπίζει την ένταξη σε επίπεδο ως δύο σήματα: `tierPriority` (0.0476) και `tierAffinity` (0.0476). Δείτε τον κανονικό [πίνακα παραγόντων βαθμολόγησης](#how-it-works-persisted-auto-combos) παραπάνω για το πλήρες σύνολο `DEFAULT_WEIGHTS` — οι ανά-πακέτο παρακάμψεις (ship-fast/cost-saver/quality-first/ offline-friendly) αναφέρονται στον πίνακα «Προφίλ βαρών ανά πακέτο». Το επίπεδο από μόνο του **δεν** επιβάλλει το Επίπεδο 1 πρώτα — αν η καθυστέρηση του Επιπέδου 1 είναι κακή ή η σχέση κόστους-ποιότητας δεν είναι βέλτιστη, κερδίζει το Επίπεδο 2. Για να επιβάλετε σειρά επιπέδων, χρησιμοποιήστε τη στρατηγική combo `priority` και τακτοποιήστε τους παρόχους ανά επίπεδο. Για να ευνοήσετε σε μεγάλο βαθμό το Επίπεδο 1 (συνδρομή), αυξήστε το βάρος `tierPriority`: ```json { "strategy": "auto", "config": { "auto": { "weights": { "tierPriority": 0.3, "costInv": 0.05 } } } } ``` Δείτε το `docs/marketing/TIERS.md` για ορισμούς επιπέδων και κατάταξη παρόχων. ## Δοκιμές & Κάλυψη ### Ντετερμινιστικός πίνακας αποφάσεων δρομολόγησης (`npm run test:combo:matrix`) Το `tests/integration/combo-matrix/*.test.ts` αποδεικνύει την **απόφαση** δρομολόγησης όλων των 19 δημόσιων στρατηγικών από άκρο σε άκρο μέσω του πραγματικού αγωγού combo με εικονικό upstream. Η κάλυψη περιλαμβάνει: - Όλες τις 19 στρατηγικές `ROUTING_STRATEGY_VALUES` (ordered, weighted, cost, context, fusion, …). - `quota-share` (εσωτερικό) από άκρο σε άκρο: δικαιοσύνη DRR + αποπροτεραιοποίηση κορεσμού μέσω του πραγματικού σημείου σύνδεσης `selectQuotaShareTarget` (`registerQuotaFetcher` / `setLKGP` / `__setHeadroomSaturationFetcherForTests`). - Κάλυψη καθολικής μεταβίβασης `context-relay` σε κάθε πλήθος στόχων. Αυτή η σουίτα εκτελείται στο CI (εργασία `test:integration`) με `--test-concurrency=1` και `--test-force-exit` ώστε να είναι ντετερμινιστική και να μην απαιτεί ζωντανά διαπιστευτήρια. ### Δοκιμές καπνού με πραγματική σύνδεση (ΔΕΝ συμπεριλαμβάνονται στο CI — πραγματικοί πάροχοι) | Εντολή | Τι κάνει | | :------------------------------------- | :----------------------------------------------------------------------------------------------------------- | | `npm run test:combo:live` | Ενδο-διεργασιακή πραγματική δρομολόγηση με `RUN_COMBO_LIVE=1`· λαμβάνει στιγμιότυπο ζωντανής βάσης OmniRoute | | `npm run test:combo:live:vps` | HTTP κλήσεις σε ζωντανό διακομιστή OmniRoute (ορίστε `COMBO_LIVE_BASE_URL`) | | `npm run test:combo:live:vps:failover` | Το ίδιο, με σκόπιμα σενάρια αποτυχίας και ανάκαμψης | Αυτές οι δοκιμές καπνού ασκούν την πραγματική διαδρομή επικοινωνίας (combo → πάροχος → ολοκλήρωση). Αποκλείονται σκόπιμα από το CI επειδή απαιτούν ζωντανά διαπιστευτήρια και πρόσβαση σε VPS. --- ## Αρχεία | Αρχείο | Σκοπός | | :-------------------------------------------------------- | :----------------------------------------------------------------------------------------------------- | | `open-sse/services/autoCombo/scoring.ts` | Συνάρτηση βαθμολόγησης 16 παραγόντων, `DEFAULT_WEIGHTS`, κανονικοποίηση δεξαμενής | | `open-sse/services/autoCombo/taskFitness.ts` | Αναζήτηση καταλληλότητας μοντέλου × εργασίας | | `open-sse/services/autoCombo/engine.ts` | Λογική επιλογής, bandit, όριο προϋπολογισμού | | `open-sse/services/autoCombo/selfHealing.ts` | Αποκλεισμός, διερευνητικές αιτήσεις, κατάσταση συμβάντος | | `open-sse/services/autoCombo/modePacks.ts` | 6 προφίλ βαρών (ship-fast, cost-saver, quality-first, offline-friendly, reliability-first, chaos-mode) | | `open-sse/services/autoCombo/autoPrefix.ts` | Αναλυτής προθέματος `auto/` + 6 παραλλαγές | | `open-sse/services/autoCombo/virtualFactory.ts` | Δημιουργεί `AutoComboConfig` στη μνήμη από ενεργές συνδέσεις | | `open-sse/services/autoCombo/providerRegistryAccessor.ts` | Αγκίστρι δοκιμών για προσομοίωση μητρώου παρόχων | | `src/shared/constants/routingStrategies.ts` | `ROUTING_STRATEGY_VALUES` (19 στρατηγικές) | | `src/sse/handlers/chat.ts` | Ενσωμάτωση: βραχυκύκλωμα αυτόματου προθέματος |