Cowork Bench
EN: Cowork Bench is a multi-tool agent benchmark: 496 end-to-end tasks that mirror real office workflows — pull data from a mock database, build Excel/Word/PPTX artifacts, schedule calendar events, send emails — executed through MCP (Model Context Protocol) servers (~120 tools visible per task). Evaluation is fully deterministic (programmatic checks + SQL side-effect verification, no LLM-as-judge) and runs entirely locally: one Docker Compose, a seeded PostgreSQL, zero external API calls at eval time. All task statements and system prompts are in Russian (identifiers stay Latin for exact matching), with Russia-specific domains (railways, MosBirzha, 1C HR, e-commerce). Requirements: Docker + bash; see the Quick Start below (in Russian). Built on top of Toolathlon (Apache 2.0).
— мультитул-бенчмарк для LLM-агентов: задачи реальных рабочих процессов, локальная PostgreSQL, без внешних API на этапе прогона.
Обучать и оценивать LLM-агентов на реальном использовании инструментов сложно: существующие датасеты либо узки по покрытию инструментов, либо малы по масштабу, либо зависят от живых внешних API, которые меняются со временем. Cowork Bench — большой самодостаточный набор задач с богатой мок-базой, который целиком работает локально: на этапе оценки не требуется ни одного внешнего вызова. Все задания и системные промпты — на русском языке; идентификаторы (имена файлов, листов, колонок, email, тикеры, статус-слаги) сохранены на латинице для детерминированной проверки.
Каждая задача просит агента выполнить сквозную цель — например, вытащить данные из мок-базы, собрать Excel-отчёт, поставить событие в календарь и отправить письмо — пользуясь фиксированным набором MCP-серверов (Model Context Protocol) как инструментами.
Каждая задача полностью автоматизирована: preprocess/main.py готовит исходное состояние воркспейса, агент исполняет задачу доступными инструментами, а evaluation/main.py сверяет результат с эталоном (groundtruth_workspace/). Ни ручной разметки, ни живых внешних сервисов.
Бенчмарк нагружает способности, важные на практике: многошаговое планирование по разнородным инструментам, чтение и запись структурированных форматов, синхронизацию данных между системами и доведение длинных задач до конца под фиксированным бюджетом шагов.
Раннер
В репозитории два раннера:
- CAMEL (
main.py) — дефолт: единый проход агент+оценка, минимальная обвязка. - Strands (
main_strands.py) — phase-aware раннер с изоляцией эталона (агент не видитgroundtruth_workspace/иevaluation/), устойчивым стримингом и ретраями; именно им получены solo-результаты из таблицы ниже. Включение:AGENT_ENTRY=main_strands.py,AGENT_PHASE_AWARE=1+ переменныеLLM_*— см.docs/STRANDS.md.
Дефолтный раннер — CAMEL-агент (main.py). Завершение задачи определяется по тому, что модель закончила ход (перестала вызывать инструменты) — служебный инструмент claim_done не требуется: статус SUCCESS ставится, когда агент завершил ход без новых tool-call'ов (см. utils/roles/task_agent.py). Оценка делается эвалуатором задачи по сайд-эффектам, а не по факту вызова сигнального тула.
Модель и провайдер для CAMEL-раннера задаются (в порядке приоритета):
- переменными окружения
MODEL_NAMEиMODEL_PROVIDER(их читаетmain.py); - аргументами
--model_name/--provider; - файлом
scripts/eval_config.json(fallback).
Ключ и эндпоинт берутся из MODEL_API_KEY / MODEL_API_URL. Допустимые значения MODEL_PROVIDER: openai, anthropic, gemini, deepseek, aihubmix, openai_compatible.
Quick Start
Требуется только Docker и bash. Всё остальное (Python, MCP-серверы, миграции) — внутри контейнеров.
cp .env.example .env # вписать MODEL_* (см. ниже)
docker build -t cowork-pack:latest . # собрать образ (один раз, ~10–15 мин)
./cowork_bench up # поднять Postgres (cowork_pg) + сеть cowork_net
./cowork_bench test-db # smoke миграций db/* на свежем PG
./cowork_bench run <task-name> # один прогон одной задачи (агент + оценка)
./cowork_bench stability <task> 5 # 5 прогонов подряд, сводка PASS/FAIL
./cowork_bench bench 3 # параллельный прогон всех задач (concurrency=3)
./cowork_bench tasks [pattern] # список задач (опционально по подстроке)
./cowork_bench stop # аварийная зачистка контейнеров + lock
./cowork_bench help # полный список команд
./cowork_bench up запускает docker compose up -d (Postgres cowork_pg, сеть cowork_net и опциональный dev-shell-контейнер cowork). Для одиночного прогона задачи (run) достаточно, чтобы cowork_pg был healthy, а сеть cowork_net существовала — scripts/run_containerized.sh сам поднимает эфемерные контейнеры агента под каждую задачу. cowork_bench source-ит .env и по умолчанию использует CAMEL-раннер (AGENT_FRAMEWORK=camel, IMAGE=cowork-pack:latest); любой дефолт переопределяется через .env/env. Грабли окружения — в docs/ENVIRONMENT_QUIRKS.md.
Минимальный .env для CAMEL-раннера
MODEL_PROVIDER=openai_compatible # openai | anthropic | gemini | deepseek | aihubmix | openai_compatible
MODEL_NAME=your-model-name
MODEL_API_KEY=sk-REPLACE_ME
MODEL_API_URL=https://your-llm-endpoint/v1 # нужен для openai_compatible / aihubmix
Оценка результата
С дефолтным CAMEL-раннером оценка выполняется автоматически в том же прогоне: main.py после завершения агента сам вызывает эвалуатор и пишет вердикт в eval_res.json. Отдельную команду запускать не нужно.
Отдельный standalone-грейдер scripts/run_eval.py (и отдельный eval-контейнер в run_containerized.sh) задействуется только для phase-aware раннеров с изоляцией эталона (см. «Подключение своего раннера»).
Где смотреть результат
dumps/<task>/<timestamp>/.../SingleUserTurn-<task>/
├── traj_log.json # config + status прогона
├── traj.json # полная траектория (messages + tool_calls)
├── eval_res.json # {"pass": true|false, "details": "..."}
└── workspace/ # файлы, которые сделал агент
Агрегат параллельного прогона — benchmark_logs/fully_parallel_<timestamp>/summary.csv.
Подключение своего раннера
scripts/run_containerized.sh выбирает entrypoint агента так:
AGENT_ENTRY=<path>— явный путь к вашему скрипту-раннеру (высший приоритет);- иначе
AGENT_FRAMEWORK=strands→main_strands.py; - иначе дефолт →
main.py(CAMEL).
Контракт движка:
- принимает
--task_dir <task>и--max_steps <N>; - пишет
traj_log.jsonи каталогworkspace/под/workspace/dumps— оттуда их находит грейдерscripts/run_eval.py.
Изоляция эталона (опционально). Чтобы агент гарантированно не видел groundtruth_workspace/ и evaluation/, прогон разбивается на две фазы (агент в санитизированном контейнере → оценка отдельно). Это включается, если раннер — main_strands.py, либо если выставлено AGENT_PHASE_AWARE=1; тогда агент должен поддерживать флаг --phase agent. Без этого выполняется единый проход (агент + оценка вместе, полный mount, без изоляции).
# свой раннер с изоляцией эталона
AGENT_ENTRY=my_runner.py AGENT_PHASE_AWARE=1 \
bash scripts/run_containerized.sh <task-name> 100
Код раннера и грейдера запекается в образ (Dockerfile: COPY . .), поэтому собранный из этого репозитория образ работает без host-mount'ов. Для быстрой итерации над кодом раннера — DEV_MOUNTS=1 (оверлей host-кода).
Архитектура: MCP-серверы
configs/mcp_servers/*.yaml регистрирует MCP-сервер, local_servers/<name>/ содержит его код. Бэкенд для «SQL-подобных» MCP — общий PostgreSQL cowork_pg, схема per-MCP (например canvas, moex, wc, hr1c_data).
Данные грузятся детерминированно: db/init.sql.gz — полный дамп (все схемы, включая русские данные rzd, teamly, moex, hr1c, gform, релейблинг canvas, wc), автоматически применяется docker-entrypoint'ом Postgres при первом старте.
Добавить новый домен → форкнуть MCP в local_servers/, написать post-init миграцию db/zzz_<name>_after_init.sql (префикс zzz_ гарантирует загрузку после init.sql.gz — entrypoint сортирует файлы по алфавиту), зарегистрировать её в docker-compose.yml (volume в /docker-entrypoint-initdb.d/) и сервер в configs/mcp_servers/<name>.yaml. Готовый рецепт — docs/RUSSIFICATION.md.
Структура задачи
Все задачи лежат в tasks/finalpool/. Каждая директория задачи имеет единый layout:
<task-name>/
├── task_config.json # какие MCP-серверы и локальные тулы доступны агенту
├── docs/
│ ├── task.md # описание задачи (показывается агенту)
│ └── agent_system_prompt.md
├── evaluation/main.py # автоматический эвалуатор
├── preprocess/main.py # подготовка состояния БД (запускается перед задачей)
├── initial_workspace/ # входные файлы в воркспейсе агента
└── groundtruth_workspace/ # эталонные выходы для проверки
Описания задач (task.md) написаны без брендовых имён инструментов — сервисы вроде базы знаний, общего календаря или LMS описаны обобщённо. Это та же конвенция обфускации, что и в исходном проекте Toolathlon: она мешает агенту срезать углы по узнаванию ключевых слов и заставляет рассуждать о реальном использовании инструментов.
Мок-база
Подключение: БД cowork_gym на контейнере cowork_pg (внутри сети — cowork_pg:5432, с хоста — localhost:15433; пользователь eigent, пароль camel).
Все данные отдаёт локальный PostgreSQL, инициализируемый из сжатого дампа (db/init.sql.gz) плюс post-init миграции. Внешних вызовов в рантайме нет — окружение полностью контролируемо, без лимитов API, смены схем или дрейфа данных.
Данные выведены или симулированы по реальным источникам: Kaggle OULAD (Open University Learning Analytics) для LMS, Kaggle HR Analytics для корпоративного HR, биржевые ряды для финансов, комбинация Kaggle Amazon и DummyJSON для e-commerce, плюс русские форки (РЖД, база знаний, формы).
Богатые данными схемы
| Домен | Описание | Схема |
|---|---|---|
| canvas | LMS — курсы, пользователи, записи, задания, сдачи, тесты, рубрики, объявления (русифицированные имена/реалии) | canvas |
| moex | Биржа — котировки, финансовая отчётность, новости, опционы, держатели | moex |
| woocommerce/insales | E-commerce — товары, заказы, клиенты, купоны, отзывы | wc |
| rzd | Ж/д — станции, поезда, маршруты, места | rzd |
| teamly | База знаний (российский аналог Confluence) | teamly |
| forms | Опросы/формы на PG-бэкенде | gform |
| hr1c | Корпоративный HR | hr1c_data |
| youtube | Видеоплатформа — каналы, плейлисты, видео, транскрипты | youtube |
Результаты
Прогоны июнь–июль 2026, все 496 задач, метрика pass@1. Метод solo — single-thread прогоны Strands-раннером (concurrency 1): чистый pass@1 при нуле инфра-столлов. Метод parallel — более ранние многопоточные прогоны с поправкой ex-stall (см. сноски).
| Модель | Окно | PASS@1 | Метод |
|---|---|---|---|
| MiniMax-M3 (428B-A23B, FP8) | 400k | 323 / 496 — 65.1% | parallel |
| Qwen 3.5 397B-A17B (BF16, MoE) | 262k | 312 / 496 — 62.9% | solo |
| Qwen 3.6 27B (Dense, FP8) | 262k | 309 / 496 — 62.3% | solo |
| Qwen 3.6 35B-A3B (FP8, MoE) | 262k | 300 / 496 — 60.5% | solo |
| Qwen 3.5 122B-A10B (MoE) | 262k | 265 / 496 — 53.4% | parallel |
| Gemma 4 31B (Dense, FP8) † | 262k | 243 / 496 — 49.0% | solo |
| GigaCode Agentic v1.6 * (80B-A3B, FP8) | 262k | 120 / 421 — 28.5% | parallel, ex-stall |
| GigaChat-3.5 (432B-A28B) *** | 130k | 119 / 496 — 24.0% | solo |
| GigaChat-3-Max ** (90B Dense, FP8) | 130k | 41 / 375 — 10.9% | parallel, ex-stall |
| GigaChat-3-Pro *** | 130k | 24 / 496 — 4.8% | solo |
* GigaCode Agentic v1.6 — исключены инфра-фейлы: 75 stream-stall. Метрика 28.5% = 120/421 дошедших до эвала (сырой pass@1 = 120/496 = 24.2%).
** GigaChat-3-Max — исключены инфра-фейлы: 59 stream-stall + 22 × HTTP 500 + 32 task_timeout. Метрика 10.9% = 41/375 дошедших до эвала (сырой pass@1 = 41/496 = 8.3%).
*** GigaChat-3.5 / 3-Pro — прогнаны через legacy
functions-API с транслирующим прокси (1 инструмент за ход — структурный гандикап); реальное окно ~130k. 3-Pro — без reasoning.† Gemma 4 31B — self-hosted FP8 (
RedHatAI/gemma-4-31B-it-FP8-dynamic), vLLM 0.24, idle 600с. Чистый single-shot solo-прогон, 0 инфра-столлов. Прежние 51.8% были best-of-many на BF16 (аккумуляция лучших раундов из-за столлов gemma4-парсера); заменены честным одиночным прогоном.
Бенч даёт большой разброс по силе моделей (65% → 5%); внутри семейства Qwen влияют и размерность, и поколение: 3.6-модели 27B/35B держат уровень флагмана 3.5-397B (60–63%), тогда как 3.5-122B — 53.4%.
Что отличает Cowork Bench
- Масштаб и разнообразие. Сотни задач по десяткам MCP-серверов и нескольким доменам данных; задачи требуют настоящей кросс-системной координации, а не одиночных lookup'ов.
- Полностью локально и воспроизводимо. Всё окружение поднимается из одного Docker Compose. Ключи к внешним сервисам на этапе оценки не нужны. Дамп PostgreSQL версионируется и детерминирован — результаты воспроизводимы между машинами и во времени.
- Реалистичная сложность. Задачи списаны с реальных рабочих процессов: HR-аналитика в Excel, сверка сдач LMS с дедлайнами в календаре, генерация презентаций из собранных данных и подобные многошаговые цели. Большинству задач нужно 4–7 инструментов.
Acknowledgements
Cowork Bench построен на инфраструктуре и исходных пайплайнах данных проекта:
Toolathlon: Benchmarking LLM Agents on Real-World Tool-Use Tasks HKUST-NLP — https://github.com/hkust-nlp/Toolathlon
Дизайн схемы мок-базы, интерфейсы MCP-серверов и фреймворк оценки происходят из проекта Toolathlon (Apache License 2.0, см. LICENSE). Cowork Bench локализует пул задач на русский язык, заменяет ряд внешних сервисов на российские форки и расширяет набор данных.
Каталог local_servers/ содержит vendored-форки сторонних open-source MCP-серверов (filesystem, excel, word, powerpoint, playwright, fetch и др.) — авторство и лицензии указаны в их собственных манифестах внутри соответствующих подкаталогов.
No comments yet
Be the first to share your take.