AI-компоненты — кодинг, транскрибация, голос и семантический поиск
Mockarty поставляет четыре опциональных self-hosted компонента, которые включают AI-возможности. Каждый работает рядом с admin-узлом. Аккаунт Mockarty Cloud не нужен; для полностью air-gapped установки зеркалируйте образы и модели компонентов, а coding runner направьте на endpoint модели внутри того же окружения.
| Компонент | Бинарь | Что включает |
|---|---|---|
| Автономная разработка | mockarty-coder-runner |
Изолированная реализация и проверка кода для автономных миссий |
| Распознавание речи | mockarty-whisper-runner |
Расшифровки голосовых сообщений и записей встреч в Обсуждениях, плюс AI-протокол встречи |
| Синтез речи | mockarty-tts-runner |
Серверное действие Озвучить — общий голосовой ответ, публикуемый в тред для всех |
| Семантический поиск | mockarty-rag-runner |
Поиск по смыслу, «найти похожие» для тест-кейсов и wiki-страниц, векторные возможности Базы знаний |
Распознавание речи, голос и семантические функции мягко деградируют при отсутствии своего компонента. Автономные миссии остаются видимыми и без подключённой мощности кодеров, чтобы оператор видел причину и мог подключить раннер, а не потерял миссию.
Как компоненты подключаются
Каждый компонент аутентифицируется на admin-узле API-токеном (создайте в UI: Настройки → API-токены, или попросите администратора) и представляется при старте. Две переменные окружения обязательны всегда:
MOCKARTY_URL=http://your-mockarty:5770 # базовый URL admin-узла
MOCKARTY_API_TOKEN=<api-token>
Привязка к пространству имён. По умолчанию компонент с администраторским токеном обслуживает всю инсталляцию (общий пул). Задайте RUNNER_NAMESPACE=<name>, чтобы выделить его одному пространству имён — полезно, когда трафик одной команды не должен конкурировать с другими. Токен, привязанный к пространству имён, автоматически ограничивает компонент этим пространством имён.
Компоненты шлют heartbeat каждые 30 секунд и снимаются с учёта при штатной остановке — списки компонентов у админа всегда отражают реальность.
Как задание попадает в компонент
По умолчанию компонент сам запрашивает работу у админ-узла: держит длинный запрос открытым и берёт задание, как только оно появляется. Входящий доступ по сети не нужен — поэтому так работает и за NAT, и в CI, и на ноутбуке.
Если админ-узел может достучаться до компонента по сети, дополнительно можно разрешить передавать задание напрямую — тогда исчезает пауза между «задание создано» и «компонент его увидел». Оба способа работают одновременно: сначала пробуется прямая передача, а всё, что доставить не удалось (компонент уже занят или недоступен), просто остаётся в очереди и забирается обычным образом. Ничего не теряется, а выключить это можно в любой момент — достаточно убрать переменные.
Чтобы включить, дайте компоненту порт для приёма, адрес, по которому его видно, и общий секрет, который знает и админ-узел:
| Переменная | Где | Значение |
|---|---|---|
RUNNER_PUSH_ADDR |
компонент | Порт для приёма заданий, например :8790. Пусто = только запрашивать самому (по умолчанию) |
RUNNER_ADVERTISE_HOST |
компонент | Хост, по которому админ-узел достучится до компонента, например tts-1. Пусто = компонент не предлагает прямую передачу |
RUNNER_PUSH_SECRET |
компонент | Общий секрет. Если не задан — берётся MOCKARTY_A2A_SECRET, так что на весь пул хватает одного значения |
RUNNER_STATE_DIR |
компонент | Каталог durable-журнала принятых заданий. При прямой передаче смонтируйте его на постоянное хранилище |
RUNNER_STATE_ID |
компонент | Стабильный идентификатор этого журнала при замене процесса или pod. Он должен соответствовать ровно одному опубликованному push endpoint |
MOCKARTY_A2A_SECRET |
админ-узел | Тот же секрет. Не задан — админ-узел никогда не передаёт задания напрямую |
На этом же порту компонент отвечает на GET /healthz — удобно как liveness-проба в Kubernetes. Больше заданий одновременно, чем указано в RUNNER_CONCURRENCY, компонент не примет: лишние передачи он отклонит, и эти задания подождут в очереди.
Прежде чем подтвердить приём напрямую переданного задания распознавания или
синтеза, компонент записывает его идентификатор в RUNNER_STATE_DIR. Храните
этот каталог на постоянном томе: после перезапуска процесса компонент узнает то
же задание и не выполнит платную работу дважды. При первом запуске создаётся
пустой журнал. Если журнал повреждён или недоступен для записи, push-приём
закрывается безопасно и не принимает работу без durable-доказательства, поэтому
том с состоянием нужно сохранять при заменах. Pull-режиму журнал не нужен.
Задайте RUNNER_STATE_ID стабильным значением, которое сохраняется при замене
pod. Один опубликованный push-адрес должен вести ровно к одному журналу runner;
нельзя ставить несколько push-реплик за балансируемым адресом. Helm chart
требует replicaCount: 1, пока включён этот push-канал.
Раннер автономной разработки
mockarty-coder-runner выполняет этапы кодинга в автономных миссиях. Для on-prem обычно используется pull-режим: раннер сам делает исходящие запросы к admin-узлу, объявляет только выбранные для этого процесса движок и sandbox, берёт работу только при наличии мощности и перед снятием с регистрации доставляет durable-результат. Push-режим подходит инсталляциям, где admin-узел может обращаться к раннеру.
Настройка доверия
Admin-узел подписывает короткоживущие аттестации задач, а раннер проверяет их парным публичным ключом. Обе привязки должны совпадать точно:
- задайте на admin-узле
MOCKARTY_CODER_ADMIN_URLсо стабильным публичным базовым URL; - запускайте каждый раннер с тем же URL в
--admin-urlи стабильным--runner-id; - храните seed/private key подписи admin-узла в Kubernetes Secret или другом хранилище секретов под именем
MOCKARTY_CODER_ATTEST_KEY; - собирайте образ раннера только с парным публичным ключом:
--build-arg CODER_ATTEST_PUBLIC_KEY_B64=<base64-ed25519-public-key>.
Никогда не помещайте seed/private key подписи в образ раннера, build argument или окружение раннера. Source-only сборка без встроенного публичного ключа закрывается с ошибкой. MOCKARTY_CODER_ALLOW_DEV_OPEN=1 открывает её только для изолированного локального запуска разработчика и никогда не должна использоваться в общем или production-окружении.
Без ключа боевой узел ничего не подписывает. При ENV=production и незаданном MOCKARTY_CODER_ATTEST_KEY маршруты кодера отвечают, но регистрация раннера и его heartbeat получают отказ с указанием переменной, которую надо задать. Так сделано намеренно: ключ, сгенерированный на лету, меняется при каждом перезапуске — подписи, выданные до него, перестают проверяться после, а раннер, собранный с закреплённым публичным ключом, не примет их вообще. Установке, которая кодер не запускает, ключ не нужен и ничего не меняется. На машине разработчика (ENV не задан или отличается от production) временный ключ создаётся, чтобы с флотом можно было работать локально.
Для Helm оставьте URL admin-узла в values, а seed подписи подключите из Secret:
admin:
env:
MOCKARTY_CODER_ADMIN_URL: "https://mockarty.company.example"
extraEnvFrom:
- secretRef:
name: mockarty-coder-attestation # ключ: MOCKARTY_CODER_ATTEST_KEY
Запуск в pull-режиме
Создайте API-токен, привязанный к пространству имён, в Настройки → API-токены, выберите отдельный транспортный секрет раннера и запустите образ:
docker run --rm \
-v mockarty-coder-state:/home/coder/.mockarty-coder \
-e MOCKARTY_CODER_TOKEN=<namespace-api-token> \
-e MOCKARTY_CODER_SECRET=<runner-transport-secret> \
-e DEEPSEEK_API_KEY=<model-key> \
ghcr.io/your-org/mockarty-coder-runner:version \
--pull --admin-url https://mockarty.company.example \
--namespace my-team --runner-id coder-01 \
--engine opencode --sandbox local
Сохраняйте том рабочего каталога между рестартами: в нём находятся ожидающие доставки результатов и ограниченный набор квитанций exact-replay, а не только временные checkout. Для недоверенных задач используйте --sandbox docker, если на хосте раннера доступен Docker. Раннер объявляет только выбранные sandbox и движок, поэтому admin не выдаёт ему работу для возможностей, которых у процесса нет. --max-concurrent ограничен CPU-бюджетом процесса.
Для Docker-изоляции также нужны заранее загруженный образ движка в --image и доступ к выделенному или rootless Docker daemon. Образ раннера содержит Docker CLI, но не daemon. Подключите socket daemon внутрь контейнера раннера (обычно в /var/run/docker.sock) и добавьте GID группы socket через Docker-флаг --group-add; если CLI или daemon недоступен, раннер завершится до регистрации. Socket хостового Docker даёт широкие права на этот хост, поэтому не делите обычный production-daemon с недоверенными автономными задачами. Любой, кто управляет этим daemon, может просматривать окружение рабочего контейнера; считайте daemon и его операторов частью доверенной границы секретов. Используйте выделенный хост раннера или rootless daemon и отдельно ограничьте его сеть. Пример выше с --sandbox local намеренно работает без изоляции и подходит только для изолированного dev-раннера.
Если coder-задача объявляет оригинальные файлы, раннер получает их до запуска
движка. Задайте точный HTTPS POST endpoint в
MOCKARTY_CODER_MATERIAL_BROKER_URL, а его Bearer service credential передайте
через MOCKARTY_CODER_MATERIAL_BROKER_TOKEN. Задача не может использовать эти
значения как credential модели, репозитория или рабочего файла. Раннер проверяет
размер, SHA-256 digest, MIME-тип и тело каждого ответа, атомарно размещает полный
набор в .mockarty-materials/ и не передаёт движку или отчёту одноразовые
handle. Брокер обязан привязать выдачу к task, поколению lease, логической
попытке, design digest и plan digest из запроса.
Запуск в push-режиме
Push-режим подходит установкам, где админ-узел достаёт до раннера напрямую: админ отдаёт задание сразу, как оно встало в очередь, а не ждёт очередного опроса.
Раннер при этом всё равно регистрируется у админа, поэтому ему нужен тот же токен пространства имён, что и pull-раннеру, плюс адрес, который админ будет набирать:
docker run --rm -p 7480:7480 \
-v mockarty-coder-state:/home/coder/.mockarty-coder \
-e MOCKARTY_CODER_TOKEN=<токен-API-пространства-имён> \
-e MOCKARTY_CODER_SECRET=<транспортный-секрет-раннера> \
-e DEEPSEEK_API_KEY=<ключ-модели> \
ghcr.io/your-org/mockarty-coder-runner:version \
--listen 0.0.0.0:7480 --callback-url http://coder-01.internal:7480 \
--admin-url https://mockarty.company.example \
--namespace my-team --runner-id coder-01 \
--engine opencode --sandbox local
--callback-url — это адрес, который наберёт админ. Если в --listen уже назван конкретный хост, адрес выводится сам; у привязки ко всем интерфейсам (0.0.0.0:7480) набираемой формы нет, поэтому раннер откажется стартовать без явного значения, вместо того чтобы объявить адрес, до которого не дозвониться.
Исходящие запросы админ подписывает учётными данными, которые сам выдаёт этому раннеру при регистрации; раннер перенимает их автоматически, и на каждой перерегистрации они меняются. Настраивать ничего не нужно.
Задание, от которого раннер отказался — он занят, либо запрос до него не дошёл, — сразу возвращается в очередь, поэтому раннер, который вдобавок опрашивает админ, заберёт его сам. Отчёты уезжают тем же долговечным путём, что и в pull-режиме, а SIGTERM по-прежнему сливает принятую работу и снимает раннера с учёта.
Доступ к репозиториям
Задача может указать credential репозитория через repo.tokenEnv, но никогда не переносит само значение токена. Раннер принимает имя переменной только тогда, когда MOCKARTY_CODER_REPO_TOKEN_BINDINGS привязывает к ней точный HTTPS origin репозитория:
MOCKARTY_CODER_REPO_TOKEN_BINDINGS="git.company.example=GITLAB_TOKEN,github.com=GH_TOKEN"
Формат: host=ENV[,host=ENV]. Для стандартного HTTPS-порта 443 указывается только хост. Для нестандартного порта укажите host:port=ENV, например git.company.example:8443=GITLAB_TOKEN. Сопоставление точное, URL репозитория обязан использовать HTTPS, а одну переменную нельзя перепривязать к другому origin. Внутренние credentials раннера — MOCKARTY_CODER_TOKEN, MOCKARTY_CODER_SECRET, ключ подписи аттестаций и Mockarty MCP key — никогда не разрешены как credentials репозитория.
Токен передаётся Git через приватный короткоживущий askpass-helper. Он не попадает в аргументы процесса и не сохраняется в .git/config.
Health и остановка
Push-режим предоставляет GET /healthz для liveness и GET /readyz для готовности принимать работу. Readiness выключается сразу с началом drain, а liveness остаётся доступной до завершения текущей работы. Квитанции завершённых задач атомарно записываются в рабочий каталог. Если та же попытка очереди физически доставлена повторно после потерянного ответа или рестарта процесса, раннер отправляет сохранённый результат, а не повторяет оплачиваемую задачу; явный новый retry остаётся новым выполнением, даже если текст задания не изменился. Результат, сохранённый непосредственно перед сбоем, доставляется до приёма новой работы после рестарта, а push-режим продолжает повторять durable-доставку без требования ещё одного рестарта. Pull-режим также перестаёт брать задания при неопределённости heartbeat/lease или доставки durable-результата. Бюджет остановки учитывает самый длинный timeout уже принятой задачи и время доставки результата; раннер не сообщает о штатном снятии с регистрации, пока оплаченная работа не согласована.
Распознавание речи (транскрибация)
Когда живой компонент транскрибации есть, в Обсуждениях появляются:
- автоматические текстовые расшифровки под голосовыми сообщениями,
- расшифровки и AI-протокол (решения, вопросы, поручения) для записей встреч.
Аудио ходит только между компонентом и admin-узлом.
Длинные записи (встречи) расшифровываются по сегментам: текст задачи
расшифровки растёт по мере распознавания каждого сегмента — не нужно ждать
конца всего файла, чтобы прочитать первые минуты. Готовая расшифровка, как и
прежде, публикуется один раз и целиком под записью.
Запуск через Docker Compose
Готовый compose-файл входит в поставку (deploy/compose/docker-compose.whisper-runner.yml). В образ уже запечена небольшая многоязычная модель, поэтому минимальный запуск — две переменные:
MOCKARTY_URL=http://admin:5770 MOCKARTY_API_TOKEN=<token> \
docker compose -f docker-compose.whisper-runner.yml up -d
Выделить пул одному пространству имён и отмасштабировать:
MOCKARTY_URL=... MOCKARTY_API_TOKEN=... RUNNER_NAMESPACE=my-team \
docker compose -f docker-compose.whisper-runner.yml up -d --scale whisper-runner=2
Другая модель распознавания без пересборки образа — смонтируйте каталог с GGML-моделью:
WHISPER_MODEL_DIR=/srv/models WHISPER_MODEL_FILE=ggml-large-v3-turbo-q5_0.bin \
MOCKARTY_URL=... MOCKARTY_API_TOKEN=... \
docker compose -f docker-compose.whisper-runner.yml up -d
Запуск в Kubernetes (Helm)
Компонент входит в Helm-чарт Mockarty — включите его в values:
whisperRunner:
enabled: true
namespace: "sandbox" # обслуживаемое пространство имён
apiToken: "" # инлайн для dev; в проде — existingSecret
existingSecret: "" # Secret с API_TOKEN
Запуск бинаря напрямую
Компонент оборачивает локальный процесс whisper-server (проект whisper.cpp) — установите его и укажите GGML-модель:
| Переменная | Обязательна | Значение |
|---|---|---|
MOCKARTY_URL |
да | Базовый URL admin-узла |
MOCKARTY_API_TOKEN |
да | API-токен |
WHISPER_MODEL_PATH |
да | Путь к файлу GGML-модели |
WHISPER_SERVER_BIN |
нет | Путь к whisper-server (по умолчанию ищется в PATH) |
WHISPER_LANGUAGES |
нет | Языки для анонса (по умолчанию auto) |
RUNNER_NAME |
нет | Отображаемое имя (по умолчанию whisper-<hostname>) |
RUNNER_NAMESPACE |
нет | Обслуживать только это пространство имён (пусто = общий пул) |
RUNNER_CONCURRENCY |
нет | Параллельные задания (по умолчанию 1) |
WHISPER_TRIM_SILENCE |
нет | 1 = предварительно срезать тишину через ffmpeg |
RUNNER_PUSH_ADDR |
нет | Принимать задания, переданные напрямую (см. Как задание попадает в компонент) |
RUNNER_ADVERTISE_HOST |
нет | Хост, по которому админ-узел достучится до компонента |
RUNNER_PUSH_SECRET |
нет | Общий секрет для прямой передачи (по умолчанию — MOCKARTY_A2A_SECRET) |
MOCKARTY_URL=http://localhost:5770 MOCKARTY_API_TOKEN=<token> \
WHISPER_MODEL_PATH=/models/ggml-small-q5_1.bin \
./mockarty-whisper-runner
Для эфемерного CI-сценария флаг --once обрабатывает одно задание и завершает процесс.
Альтернатива: внешний API транскрибации
Если у вас уже есть сервис распознавания речи с OpenAI-совместимым аудио-эндпоинтом, компонент можно не ставить — укажите его admin-узлу:
MOCKARTY_TRANSCRIBE_URL=https://stt.internal/v1/audio/transcriptions
MOCKARTY_TRANSCRIBE_KEY=<key> # опционально
MOCKARTY_TRANSCRIBE_MODEL=whisper-1 # опционально
Если настроено и то и другое, приоритет у живых компонентов; внешний API обслуживает пространства имён, которые не покрыты компонентами.
Синтез речи (серверное «Озвучить»)
Текстовые сообщения в Обсуждениях всегда можно озвучить в браузере (каждый слышит локально). С установленным компонентом синтеза действие Озвучить дополнительно умеет создавать общий голосовой ответ — аудиосообщение публикуется в тред, и его может прослушать любой участник.
Запуск в Docker Compose
Готовый compose-файл поставляется с дистрибутивом (deploy/compose/docker-compose.tts-runner.yml). В образ запечён русский голос по умолчанию, поэтому минимальный запуск — две переменные:
MOCKARTY_URL=http://admin:5770 MOCKARTY_API_TOKEN=<токен> \
docker compose -f docker-compose.tts-runner.yml up -d
Выделить пул одному пространству имён и масштабировать его:
MOCKARTY_URL=... MOCKARTY_API_TOKEN=... RUNNER_NAMESPACE=my-team \
docker compose -f docker-compose.tts-runner.yml up -d --scale tts-runner=2
Использовать другой голос без пересборки образа — примонтируйте каталог с голосовой моделью Piper (.onnx + её .onnx.json):
PIPER_VOICE_DIR=/srv/voices PIPER_VOICE_FILE=en_US-lessac-medium.onnx \
MOCKARTY_URL=... MOCKARTY_API_TOKEN=... \
docker compose -f docker-compose.tts-runner.yml up -d
Запуск в Kubernetes (Helm)
Helm-чарт Mockarty включает компонент — активируйте его в values:
ttsRunner:
enabled: true
namespace: "sandbox" # обслуживаемое пространство имён
apiToken: "" # inline для dev; в production — existingSecret
existingSecret: "" # Secret с ключом API_TOKEN
Запуск бинаря напрямую
Компонент оборачивает синтезатор Piper — установите piper и скачайте голосовую модель (.onnx):
| Переменная | Обязательна | Значение |
|---|---|---|
MOCKARTY_URL |
да | Базовый URL admin-узла |
MOCKARTY_API_TOKEN |
да | API-токен |
PIPER_MODEL |
да | Путь к голосовой модели Piper (.onnx) |
PIPER_BIN |
нет | Путь к piper (по умолчанию ищется в PATH) |
PIPER_VOICE_NAME |
нет | Имя голоса для анонса (по умолчанию — имя файла модели) |
RUNNER_NAME |
нет | Отображаемое имя (по умолчанию tts-<hostname>) |
RUNNER_NAMESPACE |
нет | Обслуживать только это пространство имён (пусто = общий пул) |
RUNNER_CONCURRENCY |
нет | Параллельные задания (по умолчанию 1) |
RUNNER_PUSH_ADDR |
нет | Принимать задания, переданные напрямую (см. Как задание попадает в компонент) |
RUNNER_ADVERTISE_HOST |
нет | Хост, по которому админ-узел достучится до компонента |
RUNNER_PUSH_SECRET |
нет | Общий секрет для прямой передачи (по умолчанию — MOCKARTY_A2A_SECRET) |
MOCKARTY_URL=http://localhost:5770 MOCKARTY_API_TOKEN=<token> \
PIPER_MODEL=/models/ru_RU-irina-medium.onnx \
./mockarty-tts-runner
Флаг --once поддерживается для эфемерного CI-запуска. Без этого компонента вариант общего голосового ответа недоступен; локальная озвучка в браузере продолжает работать.
Настройки голосовых задач пространства
Пространство может задать два условия для автоматической голосовой работы — голосовых заметок, уходящих в расшифровку, и ответов, уходящих в озвучку, — в Настройки → AI и встречи:
- Язык голосовых задач — язык по умолчанию (BCP-47, например
ru-RU), который проставляется на автоматически поставляемые задачи. Язык, явно указанный в самом запросе, всегда сильнее. - Селектор голосовых раннеров — пары
key=valueчерез запятую: метки, которые раннер обязан объявлять (например,region=eu,gpu=true). Пусто — задачу обслуживает любой подходящий раннер.
Обе настройки — это ограничение на то, куда уходит работа: очередь пропускает раннер, не подходящий под селектор (или под объявленный язык), и оставляет задачу тому, кто подходит. Если живого подходящего раннера нет вообще, задача остаётся в очереди с видимой причиной — её не заберёт чужой раннер и она не зависнет молча; добавьте раннер с подходящими метками, и очередь подхватит его.
Те же настройки доступны через API (GET/PUT /api/v1/namespaces/{namespace}/ai-settings, поля voiceLanguage и voiceRunnerSelector) и агентам — через MCP-инструменты namespace_voice_settings_get / namespace_voice_settings_update.
Семантический поиск
С зарегистрированным семантическим компонентом Mockarty добавляет к обычному поиску возможности «по смыслу»:
- семантический поиск по сущностям продукта (кейсы, wiki-страницы, моки…),
- «найти похожие» — обнаружение почти-дубликатов тест-кейсов, связанных wiki-страниц,
- векторные возможности Базы знаний.
Векторы хранятся в собственной базе Mockarty — компонент является stateless-вычислителем. Его остановка или масштабирование ничего не теряет.
В отличие от двух компонентов выше, admin-узел сам вызывает этот компонент, поэтому он должен быть доступен с admin-узла по анонсируемому URL:
| Переменная | Обязательна | Значение |
|---|---|---|
MOCKARTY_URL |
да | Базовый URL admin-узла |
MOCKARTY_API_TOKEN |
да | API-токен |
ADVERTISE_URL |
да | URL, по которому admin обращается к компоненту |
EMBED_MODEL_PATH |
да | Путь к GGUF-модели эмбеддингов |
EMBED_SECRET |
да для сетевых адресов | Bearer-секрет, который обязан предъявлять admin. Его можно не задавать только при явном loopback-IP в LISTEN_ADDR |
LISTEN_ADDR |
нет | Адрес прослушивания (по умолчанию :8090) |
RUNNER_NAME |
нет | Отображаемое имя (по умолчанию rag-<hostname>) |
RUNNER_NAMESPACE |
нет | Обслуживать только это пространство имён (пусто = общий пул) |
LLAMA_ARG_THREADS |
нет | Число рабочих потоков llama.cpp (по умолчанию определяется CPU-бюджет контейнера) |
LLAMA_ARG_CTX_SIZE |
нет | Размер контекста (по умолчанию 2048) |
LLAMA_ARG_BATCH |
нет | Размер физического batch; не меньше размера контекста (по умолчанию 2048) |
LLAMA_ARG_UBATCH |
нет | Размер micro-batch; не больше физического batch (по умолчанию 2048) |
LLAMA_ARG_N_PARALLEL |
нет | Число параллельных слотов эмбеддингов (по умолчанию минимум из 2 и настроенного бюджета рабочих потоков) |
Компонент оборачивает локальный llama-server (проект llama.cpp) в режиме эмбеддингов. GET /healthz служит liveness-пробой. GET /readyz сообщает о готовности только после загрузки модели и регистрации компонента на admin-узле. Запрос эмбеддингов выполняется через POST /v1/embeddings с JSON и настроенным Bearer-секретом. Запросы больше 8 МиБ отклоняются; когда все настроенные слоты заняты, компонент отвечает 429 с Retry-After, чтобы вызывающая сторона повторила запрос без перегрузки модели.
Запуск через Docker Compose
MOCKARTY_URL=http://admin:5770 MOCKARTY_API_TOKEN=<token> \
ADVERTISE_URL=http://rag-runner:8090 EMBED_SECRET=<random-secret> \
docker compose -f docker-compose.rag-runner.yml up -d
Задайте в RAG_RUNNER_IMAGE образ из вашего зеркала registry. Если Compose должен собрать его локально, укажите RAG_MODEL_SHA256 с проверенным SHA-256 файла из RAG_MODEL_URL: при отсутствии или несовпадении checksum сборка останавливается. Задавайте RAG_MODEL_MODE=NONE только когда собственная модель монтируется при запуске: укажите её каталог на хосте в EMBED_MODEL_DIR, а EMBED_MODEL_PATH направьте на /ext-models/<file>.
Запуск в Kubernetes (Helm)
ragRunner:
enabled: true
namespace: "" # пусто = общий пул; задайте namespace для выделенного compute
embedSecret: "" # bearer-секрет, который admin предъявляет при вызовах
apiToken: "" # инлайн для dev; в проде — existingSecret
existingSecret: "" # Secret с API_TOKEN + EMBED_SECRET
Чарт автоматически подставляет ADVERTISE_URL на внутрикластерный сервис.
Альтернатива: внешний API эмбеддингов
Подойдёт любой OpenAI/Ollama/TEI-совместимый сервер эмбеддингов — укажите его admin-узлу вместо запуска компонента:
MOCKARTY_EMBED_URL=https://embeddings.internal/v1/embeddings
MOCKARTY_EMBED_KEY=<key> # опционально
MOCKARTY_EMBED_MODEL=<model-name> # опционально
Без компонента и без MOCKARTY_EMBED_URL семантические функции скрыты, обычный поиск по ключевым словам продолжает работать.
Мониторинг
Зарегистрированные компоненты видны через API:
curl -H "Authorization: Bearer <token>" http://localhost:5770/api/v1/transcribe/runners
curl -H "Authorization: Bearer <token>" http://localhost:5770/api/v1/transcribe/jobs
curl -H "Authorization: Bearer <token>" http://localhost:5770/api/v1/tts/runners
curl -H "Authorization: Bearer <token>" http://localhost:5770/api/v1/semantic/endpoints
curl -H "Authorization: Bearer <token>" http://localhost:5770/api/v1/semantic/status
Каждая запись содержит имя компонента, модель, пространство имён, последний heartbeat и счётчики заданий — компонент, переставший слать heartbeat, автоматически выпадает из диспетчеризации.
Если после перезапуска администра запись речевого раннера исчезла, раннер
зарегистрируется снова при следующем heartbeat. Временная ошибка сети или
сервера не создаёт вторую регистрацию; после восстановления администра
проверьте список раннеров.
Задания, ждущие ответа компонента
Если Mockarty отправил задание компоненту, а ответ не пришёл — оборвалось
соединение, вышло время, компонент умер на полуслове, — задание удерживается,
а не повторяется. Компонент мог уже начать работу, а распознавание и синтез
стоят настоящих денег: отдать то же задание второму компоненту значит заплатить
дважды.
Удержанные задания видны отдельным списком. Для просмотра требуется право чтения
целевого пространства имён; пространство вне области доступа вызывающего скрывается:
curl -H "Authorization: Bearer <token>" http://localhost:5770/api/v1/transcribe/jobs/fenced
curl -H "Authorization: Bearer <token>" http://localhost:5770/api/v1/tts/jobs/fenced
В каждой записи указан компонент, за которым задание удерживается, и сколько оно
ждёт. Само оно не сдвинется — проверьте компонент и зафиксируйте ответ. Для
сверки требуется право записи в целевое пространство имён; viewer и auditor не
могут закрывать оплачиваемую работу.
curl -X POST -H "Authorization: Bearer <token>" -H "Content-Type: application/json" \
-d '{"runnerId":"<id компонента>","outcome":"not_started"}' \
http://localhost:5770/api/v1/transcribe/jobs/<id задания>/reconcile-delivery
not_started— компонент не начинал. Задание возвращается в очередь другому
компоненту, а неудавшаяся доставка не списывается с его попыток.started— начал. Задание закрывается и не повторяется.
Агент делает то же самое через media_delivery_queue и
media_delivery_reconcile. Оба фиксируют установленный вами факт и ни один из
них не проверяет компонент за вас.
CLI и все поддерживаемые SDK предоставляют те же две операции:
mockarty-cli media-delivery queue --engine transcribe
mockarty-cli media-delivery reconcile <id-задания> --engine transcribe \
--runner-id <id-компонента> --outcome not_started
page, err := client.MediaDelivery().ListFenced(ctx, "transcribe")
err = client.MediaDelivery().Reconcile(ctx, "transcribe", jobID, runnerID, "not_started")
page = client.media_delivery.list_fenced("transcribe")
client.media_delivery.reconcile("transcribe", job_id, runner_id, "not_started")
Map<String, Object> page = client.mediaDelivery().listFenced("transcribe");
client.mediaDelivery().reconcile("transcribe", jobId, runnerId, "not_started");
См. также
- Обсуждения — голосовые сообщения, встречи, расшифровки
- База знаний (RAG) — что питает семантический поиск
- ИИ-функции — AI-ассистент и агент
- Установка и развёртывание — развёртывание самой платформы