leave-copilot
Leave Copilot — от MCP к собственной агентной модели
Рабочая эталонная реализация: стандартизация набора намеренно усложнённых инструментов для отпусков/учёта рабочего времени с помощью MCP, создание агента, способного ими управлять, с помощью Google ADK, измерение недостатков базовой модели с помощью двойной оценки, а затем дообучение собственной модели, которая от природы умеет работать с этим набором инструментов.
Это сопутствующий код 30-дневной серии iThome Ironman 2026.
Почему инструменты «намеренно усложнены»
Обычно API проектируют так, чтобы они были интуитивно понятными, но этому проекту нужно противоположное.
Приёмка заключается в сравнении результатов до и после дообучения — если инструменты слишком интуитивны, базовая модель и так сможет правильно их вызывать, точность изначально будет близка к максимуму, и дообучение, естественно, не покажет никакого улучшения. Это не потому, что дообучение неэффективно, а потому что просто нет пространства для улучшения.
Поэтому критерий выбора только один: базовая модель почти наверняка ошибается, а дообучение может научить.
Четыре намеренно внедрённые сложности
# | Сложность | Реализация | Типичная ошибка модели |
① | Межвызовные зависимости | Номер в непредсказуемом формате ( | Пропускает запрос, сразу предполагает |
② | Три состояния Elicitation | Деструктивные операции через | После decline использует другой инструмент в обход |
③ | Ограничения конечного автомата | Состояние может продвигаться только | Перескакивает с draft сразу на approved |
④ | Ловушки параметров | Часы считаются в часах (полдня = 4, а не 0.5), | Передаёт |
Общая черта этих четырёх сложностей: все они — правила, которые невозможно выразить в JSON Schema. Schema может гарантировать, что status — одна из четырёх строк, но не может гарантировать, «откуда взялся этот номер».
Related MCP server: MCP Leave Management
Быстрый старт
Окружение
Пакет | Версия | Почему |
|
| В этой серии используется FastMCP версии 1.x, диапазон версий не опускайте |
|
| 1.x всё ещё поддерживается, но нет причин начинать новый проект со старой версии |
Python |
| Общий минимум для обоих |
Первый пункт особенно коварен, потому что официальный сайт MCP Python SDK по умолчанию показывает документацию другого API (
MCPServer), которая полностью отличается от используемого здесь синтаксисаFastMCP.
python -m venv .venv && source .venv/bin/activate
pip install -r requirements.txtЗапуск MCP Server
python -m mcp_server.server # streamable-http on 127.0.0.1:8090Проверка четырёх сложностей
python eval/verify_difficulties.pyРеально подключается к серверу, поочерёдно запускает все четыре сложности и проверяет сообщения об ошибках и семантику возвращаемых значений:
難點 ① 跨呼叫依賴
✓ 捏造的編號被擋下
✓ 錯誤訊息指出正確取得方式
✓ search_leaves 查得到真實編號
…
難點 ④ 參數陷阱
✓ 餘額欄位以小時命名
✓ 傳姓名而非員工編號被擋下
難點 ② Elicitation 三態
✓ accept → cancelled
✓ decline → aborted
✓ cancel → aborted
✓ accept_but_false → aborted
✓ 撤銷後時數退回餘額
✓ decline 的訊息明確禁止繞道
✓ cancel 的訊息與 decline 語意不同
──────────────────────────────────────────────
19/19 通過Сброс тестовых данных
update_leave_status, cancel_approved_leave реально изменяют данные. Перед каждым раундом оценки сброс обязателен, иначе предварительные условия второго раунда отличаются от первого, и результаты несопоставимы.
python eval/reset.pyНабор инструментов
Девять инструментов плюс один административный endpoint, предназначенный только для оценочного скрипта.
Категория | Инструмент |
|
Заявки на отпуск |
| ✅ |
Сотрудники |
| ✅ |
Согласование |
| ✗ |
Передача дел |
| ✗ |
Отзыв |
| ✗ (через Elicitation) |
Администрирование |
| ✗ |
readOnlyHint — это не просто документация — оценочный инструмент использует его для расчёта «соблюдения режима только для чтения»: использовал ли агент инструменты записи в задачах только для чтения.
_reset_fixturesна стороне агента обязательно исключить черезtool_filter. Инструмент под названием «сброс» обладает странной притягательностью для LLM.
Почему сообщения об ошибках написаны так подробно
Сообщения об ошибках инструментов возвращаются модели в неизменном виде и становятся основой для её следующего шага.
# ✗ 模型只知道錯了,得猜哪裡錯
raise ValueError("Invalid status transition")
# ✓ 模型知道錯在哪、也知道該改成什麼
raise ValueError(
f"狀態不可從 {current} 跳至 {target},下一個合法狀態為 {next_valid}"
)Это типичный приём компенсации возможностей модели за счёт дизайна инструментов, цена — всего несколько лишних слов.
Структура проекта
.
├── mcp_server/ # ✅ MCP Server:九個工具 + 四個難點
│ ├── server.py
│ ├── store.py # 模擬資料層
│ └── fixtures.py # 初始資料與 reset
├── eval/ # ✅ 驗證與重置腳本
│ ├── verify_difficulties.py # 19/19
│ ├── verify_agent.py # 架構驗證 10/10
│ └── reset.py
├── agents/leave_copilot/ # ✅ Google ADK Agent(含 elicitation callback)
├── plugins/ # ⏳ 軌跡記錄與生產防禦 Plugin
├── data/ # ⏳ 軌跡萃取與資料擴增
├── training/ # ⏳ SFT 訓練腳本
└── deploy/ # ⏳ 權重合併、量化、vLLM 部署✅ Готово и протестировано ⏳ В разработке
Распределение портов
⚠️ У FastMCP и Google ADK api_server порт по умолчанию — 8000, один из них обязательно нужно изменить. В этом проекте MCP Server перенесён на 8090.
Сервис | Порт |
MCP Server (streamable-http) | 8090 |
Google ADK api_server | 8000 |
Веб-интерфейс оценочного инструмента | 8080 |
vLLM | 8001 |
Ollama | 11434 |
Связанные проекты
ADEval — инструмент оценки агентов Google ADK (Apache-2.0)
Twinkle Eval — стандартная бенчмарк-оценка (MIT)
Лицензия
Apache-2.0
Проверенные части
eval/verify_difficulties.py и eval/verify_agent.py реально запускались,
это не «так написано в документации».
MCP Server 層(eval/verify_difficulties.py) 19/19
四個難點的錯誤訊息、Elicitation 四條路徑
Google ADK 層(eval/verify_agent.py,A 段架構驗證) 10/10
McpToolset 載入、tool_filter 排除管理端點
accept / decline / cancel / accept-but-false 四條路徑
都確認走到 Client callback,且語意正確回報Окружение: mcp 1.29.1 + google-adk 2.7.1 + gemini-3.7-flash.
Наблюдения за поведением базовой модели
Секция B в verify_agent.py не делает утверждений, только записывает — если модель отвечает неправильно, это не провал теста,
это как раз то, что нужно измерить. Самый примечательный паттерн отказа из реальных запусков:
Модель отвечает текстом вместо вызова инструмента. Столкнувшись с деструктивной операцией,
gemini-3.7-flashсклонен сам спрашивать в диалоге «Вы уверены?», вместо того чтобы вызватьcancel_approved_leaveи позволить серверу выдать Elicitation. В результате: процесс подтверждения опускается с уровня протокола на уровень диалога, а подтверждение на уровне диалога не имеет принудительной силы.
Более серьёзный вариант — галлюцинированный успех — модель отвечает «Я отправил заявку на согласование»,
но в последовательности вызовов инструментов вообще нет update_leave_status, и статус заявки не изменился. Пользователь думает, что всё сделано.
Такие сбои невозможно устранить с помощью промпта, потому что они проистекают из врождённой склонности модели к «безопасности». Именно это и предстоит обработать последующим дообучением.
This server cannot be deployed
Maintenance
Related MCP Connectors
Connect, monitor, and control AI agents — tasks, approvals, schedules, and governance.
Shared task queue for humans and AI agents: leases, handoffs, approvals and signed receipts.
Agentic workflow budget approvals with usage receipts.
AI agents discover human capabilities, request real-world human execution, and track status.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceEnables employees to check leave balance, apply for leave, and view leave history through natural language using Claude Desktop.-
- AlicenseNot gradedqualityDmaintenanceSimulates a leave management workflow for employees and managers, including leave application, balance checks, and approval processes.ISC
- FlicenseBqualityDmaintenanceEnables HR teams to query and manage employee leave through natural language using Claude Desktop, with tools for checking balances, applying leave, and viewing history.3-
- AlicenseAqualityDmaintenanceEnables LLM clients to handle leave applications by providing tools for initialization, organization selection, leave day calculation, attachment checks, uploads, and submission, with built-in business validation and environment switching.6MIT