{ "$schema": "http://json-schema.org/draft-07/schema#", "$id": "embedding.schema.json", "title": "Tibi server config — embedding section (server-level, not project config)", "description": "Der Abschnitt `embedding` aus der Server-config.yml (server.embedding): Provider + Failover-Gruppen + Gold-Datei-Pfad. Quelle der Wahrheit: internal/config/server.go und internal/config/embedding_group.go im tibi-server.", "type": "object", "additionalProperties": false, "properties": { "providers": { "type": "array", "items": { "$ref": "#/definitions/provider" } }, "groups": { "type": "array", "items": { "$ref": "#/definitions/group" } }, "goldenPath": { "type": "string", "description": "Verzeichnis der Gold-Dateien für die Mitglieds-Prüfung (Vorgabe: testdata/embedding-golden relativ zum Arbeitsverzeichnis). Erzeugen mit cmd/embed-probe-golden. Ohne verankerte Gold-Datei prüft die Gruppe nur gegen ihre Referenz." } }, "definitions": { "duration": { "type": "string", "description": "Go-Duration (time.ParseDuration), z. B. 120s, 800ms, 25s, 1m30s, 1.5h", "pattern": "^([0-9]+(\\.[0-9]+)?(ns|us|µs|ms|s|m|h))+$" }, "provider": { "type": "object", "additionalProperties": false, "required": [ "name" ], "properties": { "name": { "type": "string", "description": "Provider-Name; Sammlungen referenzieren ihn (oder eine Gruppe) über vector.provider." }, "type": { "type": "string", "enum": [ "native", "flagembedding" ], "description": "native = ONNX im Prozess (braucht -tags cgo_embedding), flagembedding = externer HTTP-Endpunkt. Ohne Angabe: native." }, "model": { "type": "string" }, "modelPath": { "type": "string", "description": "ONNX-Modellverzeichnis (type: native)." }, "dimensions": { "type": "integer", "minimum": 1 }, "baseURL": { "type": "string", "description": "Embedding-Endpunkt (type: flagembedding)." }, "apiKey": { "type": "string" }, "documentPrefix": { "type": "string" }, "queryPrefix": { "type": "string" }, "timeoutPerAttempt": { "$ref": "#/definitions/duration", "description": "flagembedding: HTTP-Timeout (Vorgabe 120s); native: Schranke je Embed-Aufruf (nur am Aufruf-/Stufen-Eintritt wirksam, ONNX-Runs sind nicht unterbrechbar). Ungültige oder nicht-positive Werte werden ignoriert (Warnung im Log)." }, "slowThreshold": { "$ref": "#/definitions/duration", "description": "Nur gruppenwirksam: langsamere Aufrufe zählen für lowest-latency als langsam." }, "revision": { "type": "string", "description": "Gewichts-/Build-Tag (Datei-Hash, Quantisierung); fließt in die Modell-Identität ein (Gruppen-Prüfung, Query-Cache)." }, "sparse": { "type": "boolean", "description": "false = Endpunkt/Modell liefert keine Sparse-Vektoren: native lädt die Sparse-Session nicht, flagembedding schweigt die einmalige Dense-only-Warnung; in einer Gruppe lehnt die Prüfung abweichende Sparse-Formen ab." } } }, "group": { "type": "object", "additionalProperties": false, "required": [ "name", "members" ], "properties": { "name": { "type": "string", "description": "Gruppenname; darf kein Provider-Name sein und darf nur einmal vorkommen." }, "description": { "type": "string" }, "members": { "type": "array", "minItems": 1, "uniqueItems": true, "items": { "type": "string" }, "description": "Provider-Namen der Gruppe. Alle Mitglieder müssen dieselbe Modell-Identität liefern (Dimensionen, Sparse-Unterstützung, revision)." }, "onSingleQuery": { "type": "object", "additionalProperties": false, "properties": { "policy": { "type": "string", "enum": [ "prefer-in-order", "fastest-wins", "round-robin", "lowest-latency", "weighted" ] }, "preferredOrder": { "description": "Bevorzugte Reihenfolge; als Komma-String oder YAML-Liste. Mitglieder, die fehlen, hängen in Config-Reihenfolge hinten an.", "oneOf": [ { "type": "string" }, { "type": "array", "items": { "type": "string" } } ] }, "timeoutPerAttempt": { "$ref": "#/definitions/duration", "description": "Schranke je Versuch. Der bevorzugte Member läuft genau darin; Ausweich-Member bekommen max(Provider-Timeout, dieser Wert)." }, "timeoutTotal": { "$ref": "#/definitions/duration", "description": "Gesamt-Deadline je Aufruf; muss >= timeoutPerAttempt sein." }, "autoFailback": { "type": "boolean", "description": "true (Vorgabe) = jeder Aufruf beginnt wieder beim bevorzugten Mitglied; false = bleibt beim letzten Gewinner." }, "raceDelay": { "$ref": "#/definitions/duration", "description": "Nur policy fastest-wins: Staffelung zwischen den Teilnehmern." }, "raceMaxFanout": { "type": "integer", "minimum": 0, "description": "Nur policy fastest-wins: maximale parallele Teilnehmer (0 = alle)." }, "weights": { "type": "array", "items": { "type": "integer", "minimum": 0 }, "description": "Nur policy weighted: relative Gewichte je Mitglied, positional zur members-Liste." }, "latencyWindow": { "type": "string", "pattern": "^[0-9]+$", "description": "Fenster für die EWMA-Latenz (lowest-latency) als Ziffern-String (> 0); Go-Feld ist ein String, der per Atoi geprüft wird." }, "retryAttempts": { "type": "integer", "minimum": 0 }, "retryBackoff": { "$ref": "#/definitions/duration" }, "retryBackoffMax": { "$ref": "#/definitions/duration" }, "hedgeAfterSlow": { "$ref": "#/definitions/duration", "description": "prefer-in-order: nach dieser Dauer starten die übrigen Mitglieder parallel (Hedge)." } } }, "onBulkWrite": { "type": "object", "additionalProperties": false, "properties": { "distribution": { "type": "string", "enum": [ "round-robin", "lowest-latency", "weighted" ], "description": "Verteilung der Batch-Ranges über die Mitglieder; ohne Angabe kein Sharding (serieller Schreibpfad). Jeder Range bleibt ganz auf einem Mitglied." }, "maxConcurrentTotal": { "type": "integer", "minimum": 0 }, "maxConcurrentPerEndpoint": { "type": "integer", "minimum": 0, "description": "Pro Mitglied; lokale (native) Mitglieder sind auf 1 begrenzt." }, "timeoutPerAttempt": { "$ref": "#/definitions/duration", "description": "Bulk-Schranke je Versuch; pro Mitglied gilt max(Provider-Timeout, dieser Wert)." }, "timeoutTotal": { "$ref": "#/definitions/duration" } } }, "health": { "type": "object", "additionalProperties": false, "properties": { "checkInterval": { "$ref": "#/definitions/duration", "description": "Abstand der Health-Probes. > 0 aktiviert zusätzlich den Late-Join: quarantänisierte Mitglieder (und offline Gruppen) werden gegen die aktuelle Referenz neu geprüft und kommen zurück, sobald sie passen. 0 = nur Neustart hilft." }, "checkTimeout": { "$ref": "#/definitions/duration", "description": "Schranke je Probe-Embed; die Rundenschranke beim Start skaliert mit der Zahl der Probe-Texte." }, "unhealthyAfterFailures": { "type": "integer", "minimum": 0 }, "healthyAfterSuccesses": { "type": "integer", "minimum": 0 }, "cooldownAfterUnhealthy": { "$ref": "#/definitions/duration", "description": "Pause, bevor ein offenes Mitglied wieder halb geöffnet wird (danach genügt Verkehr, kein Probe-Lauf)." } } } } } } }