iT邦幫忙

2026 iThome 鐵人賽

DAY 6
1
AI Engineering

從 MCP 到專屬 Agentic 模型:30 天走完一條可評測、可微調、可自架的 AI Agent 模型與服務製作流程系列 第 6

[ AI Agent ] Day 6 — 建構基礎 Google ADK AI Agent:Instruction 的極限從哪裡開始

  • 分享至 

  • xImage
  •  

Day 6 今日地圖:今天在整條閉環的位置、承接與產出

I. 前言:Instruction 寫得再仔細,也只是機率

在 Agent 開發中,instruction 往往是我們投注最多心力的地方。角色設定、行為規範、步驟拆解、注意事項 —— 一段成熟的 System Instruction 動輒數百字,而它確實能大幅提升模型的表現。

然而,這裡有一個容易被忽略的事實:Instruction 並不是「設定」,而是「每一輪都要重新說服模型一次」的輸入。

模型不會「記住」規則。它在每一次推理時,都要重新閱讀那段文字、重新判斷該不該遵守。這意味著遵守率會受到對話長度、使用者措辭、甚至工具回傳內容的影響 —— 它本質上是一個機率問題,而不是一個布林值。

期待在這篇文章中,能夠讓大家把第一個 Agent 真的跑起來,並且理解為什麼 Instruction 寫得再好,也只能把遵循率推到某個天花板。

II. 專案結構

Google ADK 的 CLI 是透過目錄結構來定位 Agent 的,因此專案的組織方式必須遵循固定慣例:

leave_copilot/
├── __init__.py        # from . import agent
├── agent.py           # 必須定義 root_agent
└── .env               # Google ADK 會自動載入

.env 至少要有金鑰,否則第一次呼叫模型就會失敗:

GOOGLE_API_KEY=your-key-here

agent.py 裡必須有一個名為 root_agent 的變數,這是 Google ADK 的約定:

from google.adk import Agent

root_agent = Agent(
    name="leave_copilot",
    model="gemini-3.8-flash",
    instruction="你是差勤助手,協助同仁查詢與處理請假申請。",
)

然後:

.venv/bin/adk run leave_copilot     # 互動式 CLI
.venv/bin/adk web .                # Web UI,可挑選目錄下的多個 agent

Google ADK Agent 的 Instruction 驅動、State 插值與 Event 捕獲架構

III. Instruction 怎麼寫

instruction 是 Agent 的核心設定。它不只是「您是誰」,更重要的是告訴模型工具該怎麼用

官方範例展示的結構是這樣:

instruction="""You are an agent that provides the capital city of a country.
When a user asks for the capital of a country:
1. Identify the country name from the user's query.
2. Use the `get_capital_city` tool to find the capital.
3. Respond clearly to the user, stating the capital city."""

注意它用編號步驟描述流程。這不是文體偏好,而是有實際作用——模型對編號清單的遵循度通常高於一段散文。

套用到 Leave Copilot,難點 1 和難點 3 的規則就寫在這裡:

instruction="""你是差勤助手,協助同仁查詢與處理請假申請。

處理假單修改請求時,必須依下列步驟:
1. 先用 `search_leaves` 找出目標假單,取得真實的 leave_id。
   絕對不要自行推測或編造 leave_id。
2. 確認假單目前狀態。
3. 呼叫 `update_leave_status` 時,狀態只能依
   draft → submitted → approved → taken 逐級推進,不可跳級。

執行破壞性操作(withdraw_leave、cancel_approved_leave)時:
- 系統會要求使用者確認,這是必要流程。
- 若使用者拒絕(decline),立即停止,不得改用其他工具達成相同目的。
- 若使用者取消(cancel),詢問使用者的意向,不要直接重試。
"""

**先講結論:這段 Instruction 寫得再仔細,模型也不會完全照做。**評測階段的基準線測試會量出它的遵循率。這正是整個系列要證明的事——Prompt 有極限,而權重可以內化。

原因可以從上面那張循環圖看出來:模型每一輪都要重新讀這段文字、重新判斷。它不是「記住」了規則,而是「每次都要被說服一次」。而說服的成功率受對話長度、使用者措辭、甚至工具回傳內容的影響。

微調改變的是這件事——規則進到權重裡,就不必每次重新說服。

但這段還是得寫好。評測階段會先把 Prompt 調到極限,再談微調;否則「微調比 Prompt 好」的結論會不公平。

IV. 用 state 做動態插值

instruction 支援 {var} 語法,從 session state 取值:

instruction="""你是差勤助手,目前服務的工程師是 {engineer_name},
負責的系統是 {system_scope}。"""

這在多租戶或多環境場景很實用——同一個 Agent 定義,不同 session 帶不同上下文。

不過有一個地方要先知道:{var} 在 state 裡找不到對應的 key 時會直接丟 KeyError,不是留白。想讓它可以缺席,在變數名後面加問號:

instruction="…目前服務的工程師是 {engineer_name?}。"

加了問號之後找不到就代換成空字串,並在 log 留一行記錄。這個差別在 session 剛建立、state 還是空的那一輪特別容易踩到。

V. output_key:把結果存進 state

output_key 會把 Agent 的最終文字回應自動寫進 session state:

triage_agent = Agent(
    name="triage_agent",
    model="gemini-3.8-flash",
    instruction="分析假單內容,判斷嚴重程度,只回答 P1 / P2 / P3。",
    output_key="severity",
)

之後 session.state['severity'] 就有值了,下一個 Agent 可以用 {severity} 讀它。這個階段後面做 multi-agent 交接時,這是最輕量的傳遞方式。

VI. 定義工具

Python 版 Google ADK 會自動把函式包成工具,型別提示與 docstring 直接轉成 schema:

def get_capital_city(country: str) -> str:
    """Retrieves the capital city for a given country."""
    capitals = {"france": "Paris", "japan": "Tokyo"}
    return capitals.get(country.lower(), f"Sorry, I don't know...")

capital_agent = Agent(
    name="capital_agent",
    model="gemini-3.8-flash",
    tools=[get_capital_city],
)

docstring 就是模型看到的工具說明。 這件事的份量比它看起來重——評測階段優化 tool description 時,改的就是這段文字,而它能帶來的改善幅度會讓人意外。

VII. 現在就開始記錄 event

這是今天最重要的一個習慣,而且很容易被跳過。

Google ADK 的每次執行都會產生一串 event,裡面完整記錄了:模型的思考、工具呼叫(名稱與參數)、工具回傳結果、最終回應。

透過 adk web 可以在瀏覽器中檢視這些 Event。而我要特別建議的是:從今天起,每次測試都把 Event Stream 保存下來。

理由有兩個,都在後面才會顯現:

  • 評測階段 的評估,本質是拿 event stream 比對預期的工具呼叫序列。
  • 訓練資料階段 的訓練資料,直接來自這些 event——Content / Part 結構會被轉成訓練樣本。

也就是說,您今天隨手測試的那些對話,就是訓練資料階段的原料。 現在存下來,比之後再重跑一遍便宜得多。

一個最小的記錄做法是在 adk web 裡手動導出,但更可靠的是直接走 API:

.venv/bin/adk api_server &

curl -X POST http://localhost:8000/apps/leave_copilot/users/u_dev/sessions/s_001 \
  -H "Content-Type: application/json" -d '{}'

curl -X POST http://localhost:8000/run \
  -H "Content-Type: application/json" \
  -d '{
    "appName": "leave_copilot",
    "userId": "u_dev",
    "sessionId": "s_001",
    "newMessage": {"role": "user", "parts": [{"text": "有哪些未處理的假單?"}]}
  }' > traces/run_001.json

/run 會把所有 event 收集成一個陣列回傳,存成檔案就是一筆完整軌跡。評測階段用的工具走的是同一組 endpoint——現在熟悉它,之後會省事。

VIII. 結語

今天建立的 Agent 在功能上還相當基礎,但它讓我們第一次觀察到 LLM 驅動的執行路徑 —— 模型如何理解 Instruction、如何選擇工具、以及如何在同樣的輸入下產生不同的行為。

總結來說,今天提到三個重點:

  • Docstring 就是給模型看的說明書: Python 版 Google ADK 會自動把型別提示與 Docstring 轉成 Schema。這意味著那段文字不是給人看的註解,而是會實際進入模型上下文的 Prompt —— 評測階段優化的第一個對象就是它。
  • Instruction 的遵循率是機率,不是設定: 規則寫得再仔細,模型仍需在每一輪重新判斷。這也是為什麼評測階段的基準線必須用批次測試來量,單次結果沒有意義。
  • 從今天開始記錄 Event Stream: 每次執行產生的事件串流,完整記錄了模型的思考、工具呼叫與回傳結果。評測階段拿它評測,訓練資料階段拿它當訓練資料 —— 現在存下來,比之後重跑一遍便宜得多。

明天,我將會提到如何把先前建立的 Leave Copilot MCP Server 正式接上這個 Agent,並且比較兩條人機確認的路線該怎麼選。屆時模型會開始面對那四個刻意植入的難點,而它犯的錯,正是這個系列真正的起點,再請大家回來閱讀後續章節囉!

Day 6 Cheat Sheet:指令、參數與容易踩的地方


參考來源

查證日期:2026-09-03。本篇的 API、CLI 指令與 {var?} 的行為,都在 google-adk 2.7.1 / Python 3.13 的環境確認過。


I am Simon

大家好,我是 Simon 劉育維,是一位 AI 領域解決方案專家,目前也擔任 Google Cloud AI 領域開發者專家 (GDE),期待能夠幫助企業導入人工智慧相關技術解決問題。如果這篇文章對您有幫助,歡迎在我的 Linkedin 上留言提供意見,並與我一起討論有關人工智慧的主題,期待能夠對大家有所幫助!

我的個人部落格資訊:https://medium.com/@simon3458


上一篇
[ AI Agent ] Day 5 — 進入 Google ADK AI Agent 生態系:框架導覽
系列文
從 MCP 到專屬 Agentic 模型:30 天走完一條可評測、可微調、可自架的 AI Agent 模型與服務製作流程6
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言