Проблема
Когда ИИ-помощник работает с 1С, часть задач удобно отдавать узким исполнителям. Один пишет запрос и доводит его до зелёного на базе, другой читает модуль и ищет ошибки. У каждого своё задание (промпт), свой набор инструментов и своя модель: на массовые задачи дорогая модель не нужна, а с персональными данными наружу ходить нельзя вовсе.
Без общей службы это превращается в россыпь скриптов:
- у каждого поставщика свой способ вызова:
claude -pсо своими ключами командной строки, HTTP-запросы к DeepSeek, отдельный сервер локальной модели; - при прямом HTTP-вызове модели цикл «модель просит инструмент → инструмент отвечает → модель продолжает» приходится писать самому, и для каждого скрипта заново подключать поиск по коду и проверку запроса;
- агент думает минутами, а MCP-клиент ждёт ответ инструмента ограниченное время — первые версии оркестратора упирались в 60-секундный таймаут;
- нет общей истории: сколько стоил вызов, сколько ходов сделал агент и что ему вернул инструмент на пятом ходу — не узнать.
Решение
Агенты лежат в каталоге, служба отдаёт их клиенту как MCP-инструменты:
agents/
query-builder/
config.toml # модель, инструменты, лимиты
prompt.md # шаблон задания, поля входа подставляются как {{ поле }}
bsl-reviewer/
config.toml
prompt.md
Клиент видит 21 инструмент, главные — invoke_agent (вызвать и дождаться) и agent_run (запустить в фоне). Новая папка или правка задания подхватываются примерно через 500 мс — без сборки и без перезапуска службы.
Минимальный агент — agents/summarizer/config.toml:
name = "summarizer"
description = "Краткое изложение текста в JSON."
version = "0.1.0"
kind = "prompt-template" # prompt-template | agent-loop | orchestrator
[model]
provider = "deepseek" # секция [providers.direct.<имя>], "claude-cli", "codex-cli" или "mock"
name = "deepseek-flash"
[response]
format = "json"
[input]
required = ["text"]
optional = ["max_points"]
И prompt.md к нему:
Изложи текст кратко. Верни JSON: {"points": ["...", "..."]}.
Пунктов не больше {{ max_points | default(value=5) }}.
Текст:
{{ text }}
Вид агента задаёт поле kind: prompt-template — один запрос без инструментов, agent-loop — цикл с инструментами, orchestrator — агент, который сам вызывает других агентов через ту же службу.
Модель — строка в конфиге
| Поставщик | Как подключается | Особенности |
|---|---|---|
| DeepSeek и любой OpenAI-совместимый API | секция [providers.direct.<имя>] |
сюда же — локальная модель на своём сервере |
| Anthropic Messages | та же секция с api = "anthropic" |
MCP-инструменты, кэш системного задания |
| Claude Code | claude -p процессом |
работа по подписке, вход через /login |
| Codex CLI | codex процессом |
вход через codex login |
Перевести агента на другую модель — поменять две строки в [model]. Прогнать всю платформу на одной модели для сравнения — force_provider и force_model в главном конфиге. Цены задаются на каждую модель отдельно, стоимость вызова пишется в историю.
Инструменты агенту — из любых MCP-серверов
Агент вида agent-loop получает инструменты других MCP-серверов — и тех, что работают по HTTP, и тех, что запускаются процессом. Пример — агент, который пишет запрос и проверяет его на базе:
kind = "agent-loop"
[execution]
max_turns = 20
allowed_tools = [
"mcp__1c__validate_query",
"mcp__1c__execute_query",
"mcp__1c__get_metadata_structure",
]
mcp_config = '''{"mcpServers":{"1c":{"type":"http","url":"${ONEC_MCP_URL}"}}}'''
Цикл «модель просит инструмент → служба вызывает → результат возвращается модели» служба ведёт сама. Поэтому инструменты работают не только у Claude Code, но и у DeepSeek, и у локальной модели. Для 1С это значит: агент на дешёвой модели ищет по выгрузке конфигурации, сверяет код с API платформы и проверяет текст запроса на базе — теми же MCP-серверами, что подключены к основному помощнику.
allowed_tools сужает набор: каждый лишний инструмент — ещё один канал, по которому данные уходят модели. Адреса и ключи — через ${ИМЯ} или ${ИМЯ:-значение} из окружения или файла .env: в конфиге агента секретов нет.
Вызов не держит чат
agent_run с именем агента сразу возвращает call_id и путь файла-итога, работа идёт в фоне службы. Проверка по call_id отвечает мгновенно: running с числом секунд от старта, done с результатом или error.
Итог дополнительно пишется файлом <runs_dir>/<call_id>-<агент>.json через временный файл и переименование — файл появляется целиком, его достаточно дождаться средствами клиента. Передумали — agent_cancel: вызов закрывается ошибкой, файл-итог дописывается, ждущий не зависает.
Всё записано
Каждый вызов — строка в agent_calls: агент, поставщик, модель, входящие и исходящие токены, чтение из кэша, стоимость, длительность, статус, родительский вызов. Для прямых поставщиков (DeepSeek, локальные модели) каждый ход цикла пишется отдельно в agent_turns — что модель получила, что ответила, что вернул инструмент.
SELECT id, agent_name, provider, cost_usd, latency_ms
FROM agent_calls ORDER BY id DESC LIMIT 20;
Журнал ходов окупился на первой же серьёзной отладке. Модель при генерации модуля несколько раз подряд возвращала одну и ту же синтаксическую ошибку, и это выглядело как предел её возможностей. Разбор ходов показал другое: номер строки в подсказке считался по всему модулю, хотя проверялась одна процедура, а в тело процедуры попадало вступление из ответа модели. Чинить пришлось обратную связь, а не модель.
Журнал самой службы ведётся отдельно, в своём файле SQLite, и хранится 30 дней — он пишется и тогда, когда основная база недоступна.
Эксплуатация
- Хранилище. По умолчанию встроенный SQLite: внешняя база не нужна, файл и схема создаются при первом запуске. PostgreSQL — по адресу в переменной
AGENTS_MCP_TASK_STORE_DSN. - Перечитка без перезапуска. Главный конфиг перечитывается при сохранении файла или инструментом
config_reload; что всё-таки требует перезапуска, служба перечисляет в ответе. - Остановка без обрыва.
prepare_shutdownзакрывает приём новых вызовов и перечисляет идущие; останавливать службу можно, когда ответ сменится наready. - Связь с клиентом. Streamable HTTP без состояния сессии — после перезапуска службы клиент не получает «404 Session not found». Для клиентов без HTTP —
--transport stdio. - Платформы. Windows и Linux (glibc 2.30 и новее), корректная остановка по Ctrl+C и SIGTERM, один экземпляр на каталог журналов. Готовые архивы — около 7 МБ.
Цифры за три месяца
Журнал вызовов моей установки за 19.06–14.09.2026:
| Поставщик | Вызовов | Модели |
|---|---|---|
| Claude Code по подписке | 6 294 | Opus — 4 932, Sonnet — 1 312, Haiku — 48 |
| DeepSeek по API | 1 947 | deepseek-v4-flash — 1 769, deepseek-v4-pro — 104, deepseek-flash — 74 |
| Своя видеокарта (RTX 3090) | 1 940 | gemma-4-31B — 1 424, Qwen3.8-27B — 427, ещё девять моделей — 89 |
| Прочие (Codex, OpenRouter и др.) | 170 |
Итого 10 351 вызов и 78 разных агентов, включая временные проверочные. Успешно завершились 96,2 % вызовов, ошибкой — 3,8 %. Десять агентов за это время сменили поставщика — строкой в конфиге, без правки кода.
По назначению вызовы распределились так:
- 5 020 — агенты, которые пишут и правят навыки по стенограммам рабочих сессий;
- 3 063 — выделение фактов из стенограмм сессий и карточек знаний;
- 1 843 — конвейер генерации внешних обработок 1С, почти целиком на локальной модели;
- 425 — остальное: исполнитель кода по плану, составитель запросов, проверочные агенты.
Пример: план — Opus, код — DeepSeek, приёмка — Opus
Так сейчас пишется код в моих проектах:
- План пишет Claude Opus в Claude Code: какие файлы трогать, что в них поменять, чем проверить.
- Код пишет агент на DeepSeek Flash (
reasoning_effort = "high", до 100 ходов, потолок 40 минут). Он работает прямо в каталоге проекта: читает и правит файлы инструментамиfs_*службы, ищет по коду через MCP-индекс. Оболочки у него нет — ни сборки, ни тестов. - Приёмка снова за Opus: сборка, тесты, проверка на работающем сервисе и чтение
git diff, а не только отчёта исполнителя.
Claude Code запускает исполнителя через agent_run, получает call_id и путь файла-итога и ждёт появления файла фоновой задачей — беседа в это время свободна. Исполнитель возвращает JSON: status (done, partial или failed), files_written, summary, blockers.
Первые три дня такой работы, 11–13.09.2026:
| Показатель | Значение |
|---|---|
| Вызовов исполнителя | 53 |
| Прервано | 3: один — перезапуском службы, два отменены вручную |
| Длительность задания | медиана 2,7 мин, максимум 12,6 мин |
| Ходов на задание | медиана 22, максимум 78 |
| Входящих токенов, прочитанных из кэша | 96,8 % |
Последняя строка и делает схему дешёвой. Агентный цикл на каждом ходу заново отправляет модели всю историю, почти вся она попадает в кэш, а чтение из кэша у DeepSeek Flash стоит $0,006 за миллион токенов против $0,3 за обычный вход. Фактический счёт DeepSeek за вечер с семью заданиями — $0,16: 133 запроса, 7,49 млн токенов, 93,5 % из кэша.
Что нашла приёмка на тех семи заданиях: код аккуратный и в стиле проекта, дефектов три. Один — ошибка самого исполнителя: не тот элемент на веб-странице для поиска. Два — следствие неполного плана: в нём не были описаны особенности окружения, а именно ограничение библиотеки управления браузером на вызовы из разных потоков и порядок появления элементов на странице. Отсюда правило: чем точнее план и чем подробнее в нём окружение, тем меньше правок на приёмке. И отчёт status: done значит «файлы записаны», а не «работает» — поэтому приёмка не пропускается.
Один из прерванных вызовов оборвался посреди работы, когда службу перезапустили под новую сборку, — задание пришлось прогонять заново. Вечером того же дня в службе появился prepare_shutdown.
Конфиденциальность
Запуск агента отправляет поставщику модели текст задания, системное задание агента, прочитанные файлы и ответы всех выданных агенту MCP-инструментов — выборки из базы, куски кода, пути. Изоляции по умолчанию нет, поставщик хранит полученное по своим правилам.
В README расписан безопасный режим:
- копия репозитория через
git worktree— в неё не попадают.envи другие файлы вне git; - отдельный индекс кода по этой копии, чтобы модель не увидела список остальных проектов машины;
- копия базы и учётная запись только на чтение;
- узкий
allowed_toolsи[fs].allowed_roots, ограниченный каталогом копии; - отдельный ключ поставщика со своей квотой.
Первые два шага делает образец scripts/clean_copy.py. Для данных, которые нельзя отдавать наружу совсем, остаётся локальная модель на своей видеокарте.
Ограничения
- Агентов в репозитории нет — только движок. Задания под свои задачи пишутся самостоятельно, формат описан в README.
- Интерфейса нет: управление — MCP-инструментами, история — SQL-запросами к базе.
- Стоимость вызовов через Claude Code считается по тарифу API, а оплата идёт подпиской — это ориентир, а не счёт.
- Codex CLI из секции
[execution]применяет толькоextra_args, остальные поля служба пропускает с предупреждением. - У поставщиков с
api = "anthropic"нет живой записи потока и вытеснения старой истории из окна контекста. - Схему PostgreSQL служба не создаёт — миграции из
migrations_pg/применяются вручную.
Установка
Готовые архивы — в выпуске на GitHub: agents-mcp-windows-x64.zip и agents-mcp-linux-x64.tar.gz, внутри бинарник, README и образец конфига. Сборка из исходников:
git clone https://github.com/Regsorm/agents-mcp
cd agents-mcp
cargo build --release
Запуск:
agents-mcp.exe --config C:\agents-mcp\configs\agents-mcp.toml
Служба слушает http://127.0.0.1:8025/mcp. Подключение в .mcp.json клиента:
"agents": {
"type": "http",
"url": "http://127.0.0.1:8025/mcp"
}
Ключ DeepSeek — в переменной окружения, имя которой указано в api_key_env поставщика. Claude Code и Codex CLI ключа не требуют, они авторизуются своим входом.
Исходники: https://github.com/Regsorm/agents-mcp (MIT).
Вступайте в нашу телеграмм-группу Инфостарт