leave-copilot
Leave Copilot — 從 MCP 到專屬 Agentic 模型
一套可執行的參考實作:用 MCP 把一組刻意設計得很難的請假/差勤工具標準化,用 Google ADK 打造能操作它們的 Agent,用雙評測量出基座模型的不足,再微調出一個原生擅長操作這組工具的專屬模型。
這是 2026 iThome 鐵人賽 30 天系列的配套程式碼。
為什麼工具是「刻意設計得很難」的
一般設計 API 追求直觀易用,但這個專案需要相反的東西。
驗收的方式是比較微調前後的表現差異 —— 如果工具太直觀,基座模型本來就能正確呼叫,準確率一開始就接近滿分,微調自然展示不出任何提升。那不是因為微調沒效果,而是根本沒有可供改善的空間。
所以選擇標準只有一個:基座模型幾乎必錯,而微調可以教會。
四個刻意植入的難點
# | 難點 | 實作方式 | 模型的典型錯誤 |
① | 跨呼叫依賴 | 編號為不可推測的格式( | 跳過查詢,直接推測 |
② | Elicitation 三態 | 破壞性操作走 | decline 後改用其他工具繞道 |
③ | 狀態機約束 | 狀態只能 | 從 draft 直接跳到 approved |
④ | 參數陷阱 | 時數以小時計(半天 = 4 不是 0.5)、 | 傳 |
這四個難點的共同特徵:它們全部都是 JSON Schema 表達不了的規則。 Schema 管得住 status 必須是四個字串之一,但管不了「這個編號從哪裡來」。
Related MCP server: MCP Leave Management
快速開始
環境
套件 | 版本 | 為什麼 |
|
| 本系列使用 1.x 的 FastMCP,版本範圍不要省略 |
|
| 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會實際連上 Server,逐一觸發四個難點並檢查錯誤訊息與回傳語意:
難點 ① 跨呼叫依賴
✓ 捏造的編號被擋下
✓ 錯誤訊息指出正確取得方式
✓ 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工具集
九個工具,加上一個評測腳本專用的管理端點。
類別 | 工具 |
|
假單 |
| ✅ |
員工 |
| ✅ |
簽核 |
| ✗ |
交接 |
| ✗ |
撤銷 |
| ✗(走 Elicitation) |
管理 |
| ✗ |
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 部署✅ 已完成並實測 ⏳ 建置中
Port 分配
⚠️ FastMCP 與 Google ADK api_server 的預設 port 都是 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,假單狀態也沒變。使用者以為做完了。
這類失敗無法靠 Prompt 消除,因為它源自模型對「安全」的內建傾向。 這正是後續要用微調處理的東西。
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