iT邦幫忙

2026 iThome 鐵人賽

DAY 8
0
AI Engineering

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

[ Agentic Data ] Day 15 — 從 Google ADK 日誌到 Agentic Dataset:軌跡切分與資料轉換

  • 分享至 

  • xImage
  •  

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

I. 前言:資料不是一句問答,而是一段推理軌跡

在傳統的 LLM 微調中,訓練資料往往是簡單的 {"prompt": "...", "response": "..."} 配對。但在 Agentic 系統中,模型必須學會的是多輪工具調用與環境回饋的互動閉環

這意味著我們需要將 Day 11 記錄的 Google ADK Event 日誌,轉化為標準的 Agentic Trajectory(軌跡資料集)。

一般對話資料與 Agentic 訓練資料的結構差異

而這個轉換過程有一個相當實際的價值:評測過程中產生的軌跡紀錄,本身就是訓練資料的原料。 我們不需要另外建立一套資料收集流程,因為那些通過 Day 13 測試的執行紀錄,本來就是「模型正確操作工具」的完整示範。

以下的內容,將會說明軌跡的篩選標準、三種切分策略的取捨、轉換實作,以及一個錯了完全不會報錯的 loss mask 陷阱。

II. 篩選標準:從嚴的理由是錯誤成本不對稱

在切分之前,得先決定哪些軌跡值得留下。建議的標準相當嚴格:

  • PASS(用 Day 13 的順序敏感語意判定,而非集合語意)
  • Name+args accuracy 滿分
  • Read-only compliance 無違規
  • Answer accuracy 高分(若該案例有 expectedAnswer

從嚴篩選的理由在於錯誤成本的不對稱性:一筆錯誤軌跡所教會模型的壞習慣,往往需要用很多筆正確樣本才能矯正回來。

其中特別要濾掉一類案例:結果對但過程錯。例如模型先修改了假單、之後才執行查詢 —— 最終狀態正確,但行為完全違反難點 ①。這類案例在集合語意下會被判為通過,唯有用順序敏感的判定才擋得掉。

III. 軌跡切分的三種策略

一段包含 3 次工具調用的完整差勤任務,該如何切分成訓練樣本?這個選擇會直接決定模型能不能學到跨呼叫的因果關係。

軌跡切分的三種策略與各自的取捨

1. 策略 A:整段軌跡單一筆(Multi-turn in one sample)

將整段對話從頭到尾作為一筆樣本。

  • 優點:保留最真實的長上下文,模型能看到完整的因果鏈。
  • 缺點:資料筆數較少,且只要後面某一步出錯,整筆樣本都會被污染;此外序列較長,容易觸及 max_length 上限。

2. 策略 B:按輪次逐步累積(Step-by-step Prefix)★ 本系列採用

將第 1 步、前 2 步、前 3 步分別切成獨立樣本,每筆樣本保留完整的前綴歷史,但只在最後一個 assistant 回合計算 loss。

  • 優點:資料量倍增,同時讓模型學會在不同長度的歷史中,做出當前步驟的正確判斷。
  • 缺點:重複的前綴會增加訓練的計算量。

3. 策略 C:單步隔離(Single Step Only)

丟棄過去歷史,只保留上一動的工具回傳與當前決策。

  • 缺點:這個做法會破壞因果關係。單獨看「已經有 search 結果,接下來呼叫 update」這一步,模型學到的會是「有 ID 就 update」,而不是「必須先查才有 ID」。

難點 ① 與難點 ③ 都是跨呼叫的規則,策略 C 會把要學的東西切碎,因此不建議採用。

IV. tool 回傳結果不該計入 Loss

這是整個資料準備階段最容易做錯、而且錯了完全不會報錯的環節。

tool 角色的訊息是環境給予的觀察,不是模型該生成的內容。如果把它計入 loss,等於在訓練模型「預測工具會回傳什麼」—— 而那正是幻覺的溫床。

TRL 提供了對應的設定:

from trl import SFTConfig

training_args = SFTConfig(assistant_only_loss=True)

它確保 loss 只計算在 assistant 的回應上,忽略 system、user 與 tool 訊息。

一個會卡住的前置條件:這個功能需要 chat template 含有 {% generation %}{% endgeneration %} 標記。TRL 會為已知模型家族(如 Qwen3)自動 patch,其他模型則必須自行確認。若未生效,模型會把 user 訊息也算進 loss —— 而那部分它「看得到」,預測起來相當容易,因此 loss 會異常低,表面上看起來訓得很好。

驗證方式很簡單:

from transformers import AutoTokenizer

tok = AutoTokenizer.from_pretrained(MODEL_ID)
template = tok.chat_template or ""
print("generation 標記:", "{% generation %}" in template)

V. 轉換實作

TRL 的 Tool Calling 資料格式要求每筆樣本包含對話訊息(含 tool_callstool 角色)以及 tools 欄位(工具的 JSON Schema 陣列)。

從 Google ADK 的 Event 轉換過來的對應關係如下:

表格:Google ADK 事件、目標訊息

實作範例:

import json


def convert_adk_trace_to_trajectory(trace_events, tools_schema):
    """把 Google ADK 的 event stream 轉成 TRL 可讀的訓練樣本。"""
    messages = []
    for ev in trace_events:
        if ev["type"] == "user":
            messages.append({"role": "user", "content": ev["text"]})
        elif ev["type"] == "tool_call":
            messages.append({
                "role": "assistant",
                "tool_calls": [{
                    "type": "function",
                    "function": {"name": ev["name"], "arguments": ev["args"]},
                }],
            })
        elif ev["type"] == "tool_result":
            messages.append({
                "role": "tool",
                "name": ev["name"],
                "content": json.dumps(ev["result"], ensure_ascii=False),
            })
        elif ev["type"] == "final":
            messages.append({"role": "assistant", "content": ev["text"]})
    return {"messages": messages, "tools": tools_schema}

tools 欄位直接來自 MCP

這裡是 Day 3 選擇 MCP 的另一個回報:工具 schema 不必轉換

async def dump_tools_schema(session) -> list[dict]:
    tools = await session.list_tools()
    return [
        {
            "type": "function",
            "function": {
                "name": t.name,
                "description": t.description,
                "parameters": t.inputSchema,   # 本來就是標準 JSON Schema
            },
        }
        for t in tools.tools
    ]

重要:所有樣本的 tools 欄位必須一致。 如果有些樣本給九個工具、有些給三個,模型會學到不穩定的對應關係。統一提供完整清單,讓模型自己學會選擇。

VI. 誠實面對數量

完成轉換之後,會得到一個相當清醒的數字。

假設有 50 個測試案例、每個跑 3 次、通過率 60%,用策略 B 每個案例平均產出 2.5 筆樣本:

50 × 3 × 0.6 × 2.5 ≈ 225 筆

而且這 225 筆之中存在大量重複 —— 同一個案例跑三次,成功的軌跡幾乎一模一樣。去重之後,可能只剩幾十筆

以工具呼叫微調的實務經驗來說,要讓模型穩定學會一組工具的使用慣例,通常需要千筆等級的樣本。幾十筆的結果多半是:loss 確實會下降(模型把那幾十筆背下來了),但換個問法就失效。

這是 Day 15 至 Day 20 最關鍵的一道坎,明天將專門處理它。

VII. 結語

軌跡資料的準備,是把「評測診斷結果」轉化為「模型改善素材」的關鍵一步。

總結來說,今天有三個重點值得帶走:

  • 切分策略決定模型學到什麼: 單步隔離雖然能增加樣本數,卻會破壞因果關係,讓模型學成「有 ID 就 update」而非「必須先查才有 ID」。難點 ① 與 ③ 都是跨呼叫的規則,因此本系列採用逐步累積前綴的策略 B。
  • tool 角色絕對不能計入 loss: 那是環境給予的觀察,不是模型該生成的內容。而這個錯誤最麻煩的地方在於它完全不會報錯 —— loss 甚至會因為模型「抄」輸入而顯得特別漂亮。
  • 資料量會比預期少一個數量級: 從評測軌跡萃取出來的黃金資料,去重後通常只有幾十筆,而穩定學會一組工具需要千筆等級。這個落差必須提早正視,而不是等到訓練效果不佳才回頭找原因。

明天將探討如何設計負面樣本(Elicitation Decline)與資料擴增,把這幾十筆放大到足以支撐訓練的規模。

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


參考來源

查證日期:2026-08-24


I am Simon

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

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


上一篇
[ DevOps in AI Agent ] Day 14 — 引入 Twinkle Eval:用標準 Benchmark 守住通用能力
下一篇
[ Agentic Data ] Day 16 — 負面樣本設計、資料擴增與反向驗證:守住品質防線
系列文
從 MCP 到專屬 Agentic 模型:30 天走完一條可評測、可微調、可自架的 AI Agent 模型與服務製作流程30
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言