Skip to main content
Glama
leave-copilot

leave-copilot

by LiuYuWei

Leave Copilot — MCPから専用Agenticモデルへ

実行可能なリファレンス実装:MCPを使って、あえて難しく設計された休暇・勤怠ツール群を標準化し、Google ADKでそれらを操作できるAgentを構築し、二重評価で基盤モデルの不足を測り、その上でこのツール群の操作をネイティブに得意とする専用モデルをファインチューニングする。

これは2026年iThome鉄人レース30日間シリーズの付属コードです。


なぜツールは「あえて難しく設計されている」のか

一般的なAPI設計は直感的で使いやすいことを追求しますが、このプロジェクトはその逆を必要とします。

受け入れ方法は、ファインチューニング前後の性能差を比較することです。ツールが直感的すぎると、基盤モデルは元々正しく呼び出せるため、正確率は最初からほぼ満点になり、ファインチューニングは当然いかなる改善も示せません。それはファインチューニングに効果がないからではなく、そもそも改善する余地がないからです。

したがって、選定基準はただ一つ:基盤モデルはほぼ必ず間違え、ファインチューニングで教えられること。

意図的に組み込まれた4つの難点

#

難点

実装方式

モデルの典型的な誤り

①

クロス呼び出し依存

番号は推測不可能な形式(LV-7f3a91)で、存在しない場合は明確にエラーを返す

問い合わせを飛ばして、直接LV-001と推測する

②

Elicitationの三態

破壊的操作はctx.elicit()を通る。accept/decline/cancelの意味はそれぞれ異なる

decline後に他のツールで迂回する

③

状態機の制約

状態はdraft → submitted → approved → takenの順にのみ遷移できる

draftから直接approvedに飛ぶ

④

パラメータの罠

時数は時間単位(半日 = 4であって0.5ではない)、employee_idは氏名ではない、ISO 8601

hours=0.5、employee_id="林筱涵"を渡す

これら4つの難点の共通の特徴:それらはすべてJSON Schemaでは表現できないルールである。 Schemaはstatusが4つの文字列のいずれかでなければならないことは管理できるが、「この番号がどこから来るのか」は管理できない。


Related MCP server: MCP Leave Management

クイックスタート

環境

パッケージ

バージョン

理由

mcp

>=1.29,<2

本シリーズでは1.xのFastMCPを使用する。バージョン範囲は省略しないこと

google-adk

2.x

1.xもまだメンテナンスされているが、新規プロジェクトが旧バージョンから始める理由はない

Python

>=3.10

両者の共通の下限

最初の項目は特に引っかかりやすい。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

4つの難点を検証

python eval/verify_difficulties.py

実際にServerに接続し、4つの難点を一つずつトリガーして、エラーメッセージと戻り値の意味を確認します:

難點 ① 跨呼叫依賴
  ✓ 捏造的編號被擋下
  ✓ 錯誤訊息指出正確取得方式
  ✓ search_leaves 查得到真實編號
…
難點 ④ 參數陷阱
  ✓ 餘額欄位以小時命名
  ✓ 傳姓名而非員工編號被擋下
難點 ② Elicitation 三態
  ✓ accept            → cancelled
  ✓ decline           → aborted
  ✓ cancel            → aborted
  ✓ accept_but_false  → aborted
  ✓ 撤銷後時數退回餘額
  ✓ decline 的訊息明確禁止繞道
  ✓ cancel 的訊息與 decline 語意不同

──────────────────────────────────────────────
19/19 通過

テストデータのリセット

update_leave_status、cancel_approved_leaveは実際にデータを変更します。各ラウンドの評価を開始する前に必ずリセットする必要があります。そうしないと、2ラウンド目の前提条件が1ラウンド目と異なり、結果を比較できません。

python eval/reset.py

ツールセット

9つのツールに加えて、評価スクリプト専用の管理エンドポイントが1つあります。

カテゴリ

ツール

readOnlyHint

休暇申請

search_leaves、get_leave

✅

従業員

list_employees、get_leave_balance

✅

承認

update_leave_status、add_comment

✗

引き継ぎ

schedule_handover

✗

取消

withdraw_leave、cancel_approved_leave

✗(Elicitation経由)

管理

_reset_fixtures

✗

readOnlyHintは単なるドキュメントではありません。評価ツールはこれを使って「読み取り専用コンプライアンス」を計算します:Agentが読み取り専用タスクで書き込みツールを使用していないかどうかです。

_reset_fixturesはAgent側で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に移しています。

サービス

Port

MCP Server(streamable-http)

8090

Google ADK api_server

8000

評価ツールWeb UI

8080

vLLM

8001

Ollama

11434


関連プロジェクト

  • ADEval — Google ADK Agent用評価ツール(Apache-2.0)

  • Twinkle Eval — 標準Benchmark評価(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。

基盤モデルの挙動の観察

verify_agent.pyのBセクションはアサーションを行わず、記録するだけです。モデルが間違って答えてもテストの失敗を意味するのではなく、それがまさに測定したいものです。実際に実行して最も注目すべき失敗パターンはこれです:

モデルがテキストでの応答でツール呼び出しを代替する。 破壊的操作に直面したとき、gemini-3.7-flashは cancel_approved_leaveを呼び出してServerにElicitationを発行させる代わりに、 自分で会話の中で「本当にいいですか?」と尋ねる傾向があります。結果として、確認プロセスはプロトコル層から会話層へ 落ちてしまいます。会話層での確認には強制力がないのです。

さらに深刻な変種は幻覚型の成功です。モデルは「休暇申請を承認フローに送りました」と返答するが、ツールシーケンスにはupdate_leave_statusがまったく存在せず、休暇申請の状態も変わっていません。ユーザーは完了したと思い込んでしまいます。

この種の失敗はプロンプトでは解消できません。それはモデルが「安全性」に対して持つ内蔵された傾向に由来するからです。これこそが、後続でファインチューニングによって扱うものです。

Related MCP Connectors

Related MCP Servers

  • F
    license
    Not graded
    quality
    D
    maintenance
    Enables employees to check leave balance, apply for leave, and view leave history through natural language using Claude Desktop.
    -
  • A
    license
    Not graded
    quality
    D
    maintenance
    Simulates a leave management workflow for employees and managers, including leave application, balance checks, and approval processes.
    ISC
  • A
    license
    A
    quality
    D
    maintenance
    Enables 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.
    6
    MIT