Skip to main content
Glama
leave-copilot

leave-copilot

by LiuYuWei

Leave Copilot — MCP에서 전용 Agentic 모델까지

실행 가능한 참조 구현: MCP로 의도적으로 어렵게 설계된 휴가/근태 도구를 표준화하고, Google ADK로 이를 조작할 수 있는 Agent를 만들고, 이중 평가로 기반 모델의 부족함을 측정한 뒤, 이 도구들을 원래 잘 다루는 전용 모델을 미세 조정합니다.

이것은 2026 iThome 철인전 30일 시리즈의 부속 코드입니다.


도구가 '의도적으로 어렵게 설계된' 이유

일반적으로 API 설계는 직관적이고 사용하기 쉽게 하는 것을 추구하지만, 이 프로젝트는 그 반대가 필요합니다.

검수 방식은 미세 조정 전후의 성능 차이를 비교하는 것입니다. 도구가 너무 직관적이면 기반 모델이 원래 올바르게 호출할 수 있어 정확도가 처음부터 만점에 가깝고, 미세 조정은 자연히 어떤 개선도 보여주지 못합니다. 미세 조정이 효과가 없어서가 아니라, 개선할 여지가 아예 없기 때문입니다.

따라서 선택 기준은 단 하나입니다: 기반 모델이 거의 반드시 틀리고, 미세 조정으로 가르칠 수 있는 것.

의도적으로 심은 네 가지 난점

#

난점

구현 방식

모델의 전형적인 오류

①

호출 간 의존성

번호를 추측 불가능한 형식(LV-7f3a91)으로 하고, 없으면 명시적으로 오류 보고

조회를 건너뛰고 LV-001로 추측

②

Elicitation 삼태

파괴적 작업은 ctx.elicit()를 거치며, accept/decline/cancel 의미가 각각 다름

decline 후 다른 도구로 우회

③

상태 머신 제약

상태는 draft → submitted → approved → taken 단계로만 진행

draft에서 approved로 직접 점프

④

매개변수 함정

시간은 시간(hour) 단위(반나절 = 4, 0.5 아님), employee_id는 이름이 아님, ISO 8601

hours=0.5, employee_id="林筱涵" 전달

이 네 가지 난점의 공통 특징: 모두 JSON Schema로 표현할 수 없는 규칙입니다. Schema는 status가 네 문자열 중 하나여야 한다는 것은 관리할 수 있지만, '이 번호가 어디서 왔는지'는 관리할 수 없습니다.


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

네 가지 난점 검증

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

도구 모음

아홉 개의 도구와 평가 스크립트 전용 관리 엔드포인트 하나가 있습니다.

카테고리

도구

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 部署

✅ 완료 및 실측됨 ⏳ 구축 중


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

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