- OpenAI-compatible gateway with intelligent routing via cortiq-router (allaigate) - Embedded build-free admin SPA at /admin: 7 languages (en/ru/de/fr/es/zh/tr), light/dark themes, hot config reload (no restart) - Admin API, per-request statistics + Prometheus /metrics, secret store, playground - English documentation (primary) with Russian translations (*.ru.md)
11 KiB
Read this in English.
Протоколы Cortiq Gateway
Контракты входящих протоколов и кросс-стандартных механизмов. Каждый протокол
включается флагом в [protocols]. Внутри всё приводится к канонической модели
(см. ARCHITECTURE.md).
Общее правило маршрутизации во всех протоколах:
model = "cortiq-auto"→ включить интеллектуальный роутинг через cortiq-router.model = "cortiq-auto:quality-first"→ роутинг с указанным policy-профилем (cost-saver|balanced|quality-first).model = "<реальный id из конфига>"→ passthrough к этой модели без роутинга.
Оглавление
- OpenAI Chat Completions
- OpenAI Completions (legacy)
- OpenAI Embeddings
- OpenAI Models
- Anthropic Messages
- MCP (Model Context Protocol)
- Native passthrough
- Кросс-стандарты
1. OpenAI Chat Completions
POST /v1/chat/completions — основной endpoint, де-факто стандарт для агентов.
Запрос
{
"model": "cortiq-auto", // роутинг; или реальный id для passthrough
"messages": [
{ "role": "system", "content": "You are a helpful assistant." },
{ "role": "user", "content": "Solve x^2 - 5x + 6 = 0" }
],
"temperature": 0.7,
"max_tokens": 1024,
"stream": false,
"tools": [ /* function-calling, проксируется к провайдеру как есть */ ],
"tool_choice": "auto",
"stop": ["\n\n"],
"top_p": 1.0,
"response_format": { "type": "json_object" }
}
Поддерживаются стандартные поля OpenAI; неизвестные поля проксируются к провайдеру без изменений (forward-compatible).
Ответ (без стриминга)
{
"id": "chatcmpl-9f...",
"object": "chat.completion",
"created": 1718800000,
"model": "local-qwen", // РЕАЛЬНО выбранная модель
"choices": [
{
"index": 0,
"message": { "role": "assistant", "content": "x = 2 или x = 3" },
"finish_reason": "stop"
}
],
"usage": {
"prompt_tokens": 24,
"completion_tokens": 11,
"total_tokens": 35
},
"cortiq": { // расширение (включается cortiq.echo=true)
"task_label": "math",
"complexity": { "score": 0.22, "tier": "low" },
"selected_model": "local-qwen",
"route_source": "router", // router | cache | fallback | pinned
"router_request_id": "req_...",
"cost_usd": 0.0
}
}
Поле
cortiq— необязательное расширение. OpenAI-SDK его игнорируют. Если клиент не хочет «лишних» полей — выключитеcortiq.echo, метаданные останутся в заголовках.
Метаданные в заголовках (всегда)
X-Cortiq-Request-Id: req_...
X-Cortiq-Task-Label: math
X-Cortiq-Complexity-Score: 0.22
X-Cortiq-Complexity-Tier: low
X-Cortiq-Selected-Model: local-qwen
X-Cortiq-Route-Source: router
X-Cortiq-Cost-Usd: 0.000000
Ответ (стриминг, stream: true)
SSE, формат OpenAI: серия чанков chat.completion.chunk, завершается data: [DONE].
Шлюз проксирует чанки провайдера один-в-один (без буферизации), добавив метаданные
роутинга в HTTP-заголовки до начала потока.
data: {"id":"chatcmpl-9f","object":"chat.completion.chunk","choices":[{"delta":{"role":"assistant"},"index":0}]}
data: {"id":"chatcmpl-9f","object":"chat.completion.chunk","choices":[{"delta":{"content":"x = 2"},"index":0}]}
data: {"id":"chatcmpl-9f","object":"chat.completion.chunk","choices":[{"delta":{},"finish_reason":"stop","index":0}]}
data: [DONE]
2. OpenAI Completions (legacy)
POST /v1/completions — для старых интеграций. Внутри prompt оборачивается в
одно user-сообщение и идёт по тому же пути. Ответ — object: "text_completion".
// запрос
{ "model": "cortiq-auto", "prompt": "Translate to French: hello", "max_tokens": 64 }
// ответ
{ "object": "text_completion", "model": "local-qwen",
"choices": [ { "text": "bonjour", "index": 0, "finish_reason": "stop" } ],
"usage": { "prompt_tokens": 6, "completion_tokens": 2, "total_tokens": 8 } }
3. OpenAI Embeddings
POST /v1/embeddings. Два режима (настраивается):
provider— проксировать к embedding-модели из пула;router— вернуть эмбеддинг энкодером cortiq-router (тот же вектор, что роутер использует для классификации — удобно для согласованного RAG).
// запрос
{ "model": "cortiq-embed", "input": ["first text", "second text"] }
// ответ
{
"object": "list",
"data": [
{ "object": "embedding", "index": 0, "embedding": [0.01, -0.02, /* ... */] },
{ "object": "embedding", "index": 1, "embedding": [0.03, 0.00, /* ... */] }
],
"model": "cortiq-embed",
"usage": { "prompt_tokens": 4, "total_tokens": 4 }
}
4. OpenAI Models
GET /v1/models — автодискавери для клиентов. Возвращает виртуальные модели шлюза
(cortiq-auto, cortiq-embed) и все реальные модели пула.
{
"object": "list",
"data": [
{ "id": "cortiq-auto", "object": "model", "owned_by": "cortiq-gateway" },
{ "id": "local-qwen", "object": "model", "owned_by": "cortiq-gateway" },
{ "id": "gpt-4o-mini", "object": "model", "owned_by": "cortiq-gateway" },
{ "id": "claude-opus", "object": "model", "owned_by": "cortiq-gateway" }
]
}
5. Anthropic Messages
POST /v1/messages — для Claude-нативных агентов и Anthropic SDK.
// запрос
{
"model": "cortiq-auto",
"max_tokens": 1024,
"system": "You are a helpful assistant.",
"messages": [ { "role": "user", "content": "Solve x^2 - 5x + 6 = 0" } ],
"stream": false
}
// ответ
{
"id": "msg_...",
"type": "message",
"role": "assistant",
"model": "local-qwen",
"content": [ { "type": "text", "text": "x = 2 или x = 3" } ],
"stop_reason": "end_turn",
"usage": { "input_tokens": 24, "output_tokens": 11 }
}
Стриминг — нативные Anthropic-события (message_start, content_block_delta,
message_delta, message_stop). Если выбранная модель — не-Anthropic-провайдер,
шлюз транслирует через каноническую модель в обе стороны.
6. MCP (Model Context Protocol)
Шлюз поднимает MCP-сервер (JSON-RPC 2.0 поверх HTTP+SSE или stdio) и публикует маршрутизацию как инструменты для MCP-нативных оркестраторов.
Публикуемые инструменты:
| Инструмент | Назначение |
|---|---|
route_and_complete |
классифицировать + выполнить на выбранной модели, вернуть ответ |
classify_task |
только классификация (тип задачи + сложность), без выполнения |
tools/list отдаёт JSON-схемы. Пример вызова tools/call:
// запрос (JSON-RPC)
{
"jsonrpc": "2.0", "id": 1, "method": "tools/call",
"params": {
"name": "route_and_complete",
"arguments": { "prompt": "Solve x^2 - 5x + 6 = 0", "profile": "balanced" }
}
}
// ответ
{
"jsonrpc": "2.0", "id": 1,
"result": {
"content": [ { "type": "text", "text": "x = 2 или x = 3" } ],
"isError": false,
"_meta": { "task_label": "math", "tier": "low", "selected_model": "local-qwen" }
}
}
7. Native passthrough
POST /route — тонкая обёртка над cortiq-router /v1/route для клиентов, которым
нужно только решение (без выполнения). Тело и ответ совпадают с контрактом роутера
(см. cortiq-router/docs/ФОРМАТ_ЗАПРОСА_И_ОТВЕТА.md). Полезно для отладки и для тех,
кто хочет сам управлять вызовом LLM.
8. Кросс-стандарты
Едины для всех HTTP-протоколов.
8.1 Аутентификация
Authorization: Bearer sk-gw-...
Виртуальный ключ шлюза. Маппится на аккаунт ([[api_keys]]). Если ключи не настроены —
открытый режим (для локальной разработки). Ключи провайдеров наружу не отдаются.
8.2 Идемпотентность
Idempotency-Key: <уникальный-id-операции>
Повтор с тем же ключом в окне idempotency.ttl отдаёт сохранённый ответ
(безопасные ретраи агентов, без двойного вызова LLM и двойного биллинга).
8.3 Rate-limit
На 429 возвращаются:
Retry-After: 2
X-RateLimit-Limit: 600
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1718800060
8.4 Трассировка
Приём и проброс W3C traceparent; OpenTelemetry-спаны inbound→route→provider.
В ответе — X-Request-Id. Это позволяет сшить сквозной трейс агент → шлюз → провайдер.
8.5 Формат ошибки (OpenAI-совместимый)
{
"error": {
"message": "no healthy model available for tier 'high'",
"type": "upstream_unavailable", // invalid_request_error | authentication_error | rate_limit_error | upstream_unavailable | internal_error
"code": "no_healthy_model",
"param": null
}
}
OpenAI/Anthropic SDK парсят такой конверт нативно. Сопоставление статусов:
| Тип | HTTP | retriable |
|---|---|---|
invalid_request_error |
400 | нет |
authentication_error |
401 | нет |
rate_limit_error |
429 | да |
upstream_unavailable |
502/503 | да |
internal_error |
500 | да |
8.6 Учёт стоимости
usage отдаётся в формате протокола (OpenAI/Anthropic). Дополнительно — стоимость
в заголовке X-Cortiq-Cost-Usd и в cortiq.cost_usd (если включено cortiq.echo).
Цена считается из price_in/price_out модели в конфиге × токены.