iT邦幫忙

2026 iThome 鐵人賽

DAY 17
0

前幾天不管是 ReAct 還是 Plan-and-Execute,很多事情都是自己管的:

訊息紀錄
工具呼叫
執行迴圈
停止條件
Session 狀態

這樣手刻的好處是每一層都看得懂,但流程開始變多之後,程式也會越來越像一套自己做的 Agent Framework。

所以今天換個方向。

把部分流程交給 Google Agent Development Kit(ADK)。

不過有一件事先講清楚:

使用 Google ADK,不代表一定要使用 Google 的模型。

今天仍然使用前面一路沿用的:

Ollama
+
OllamaClient

只是把它接進 ADK 的模型介面。

這次先不碰 MCP。

先確認:

本機模型
↓
ADK Agent
↓
普通 Python Tool
↓
Session / Event

整條流程能正常跑通。

明天再把 devbench 接回來。

一、先搞清楚 Agent、Runner、Session

ADK 把我們前幾天自己處理的工作拆成幾個角色。

可以先這樣理解:

元件 負責什麼
Agent 定義模型、角色指示與可以使用的 Tools
Runner 驅動一次 Agent 執行流程
Session 保存這段互動需要的狀態與事件

如果對照前面的手刻版本:

以前自己寫
messages
while / for loop
tool dispatch
state

↓

ADK
Agent
Runner
Session

不是突然多了一套新的 Agent 原理。

只是原本自己管理的東西,開始有固定介面可以使用。

今天先做一個非常簡單的 Tool:

def project_info() -> dict:
    """取得目前教學專案的基本資訊。"""

    return {
        "name": "devbench",
        "purpose": "本機開發者工作台",
        "language": "Python",
    }

它不讀私人檔案,也不啟動任何子行程。

今天的目標不是展示 Tool 有多厲害,而是先確認 ADK 這一層真的接通。

如果現在就同時加入:

ADK
MCP
Ollama
Tool Policy

出錯時反而很難知道是哪一層有問題。

二、Google ADK 不一定要接 Gemini

這次比較值得看的地方,是模型怎麼接進 ADK。

我們前面已經有自己的:

OllamaClient

沒必要為了換 Framework,就把整個模型層重寫。

所以新增一個 LocalModel,讓它實作 ADK 提供的 BaseLlm 介面。

概念上是:

ADK LlmRequest
↓
LocalModel
↓
轉成 ChatMessage
↓
OllamaClient.chat()
↓
本機 Ollama

模型回來後再反方向轉換:

Ollama Response
↓
LocalModel
↓
ADK LlmResponse
↓
Runner

最核心的方法是:

async def generate_content_async(...):
    ...

ADK 的 BaseLlm 把模型呼叫抽象成一層介面,所以 Framework 本身不需要知道底下到底是 Gemini、Ollama,還是其他推論服務。

Agent 就可以照常寫:

agent = Agent(
    name="devbench",
    model=LocalModel(),
    instruction=SYSTEM,
    tools=[project_info],
)

這裡我覺得最值得記的反而不是語法,而是這個分層:

Agent Framework
≠
Model Provider

Framework 管流程。

模型供應商負責推論。

兩邊可以分開替換。

三、Adapter 只支援多少,就宣稱多少

雖然 ADK 本身支援的能力很多,但我們今天寫的 LocalModel 並沒有全部實作。

目前只處理:

文字
Tool / Function Calling

沒有實作:

圖片
音訊
Live API
Streaming

所以不能因為 ADK 支援這些能力,就寫成:

我們現在的本機 Agent 已經支援多模態與串流。

Framework 能做什麼,和目前 Adapter 實際做了什麼,是兩回事。

這跟前面 MCP 很像:

Server 提供四個 Tool
≠
Host 一定開放四個 Tool

能力要看實際接起來的那一層。

這次開發環境使用的 ADK 版本以專案裡的:

uv.lock

為準。

如果網路上的範例和本機 API 長得不一樣,第一件事不是一直改 Code,而是先確認:

目前到底裝哪個版本?

Agent Framework 更新速度很快,把不同版本的範例混在一起,通常只會多一堆很難解釋的錯誤。

四、真正跑一次 ADK Agent

今天的 main.py 很短:

import asyncio
import json

from ironman.adk_adapter import run_adk


async def main() -> None:
    result = await run_adk()

    print(
        json.dumps(
            result,
            ensure_ascii=False,
            indent=2,
        )
    )

    assert result["answer"]
    assert "project_info" in result["tool_calls"]


if __name__ == "__main__":
    asyncio.run(main())

這次不只看:

模型最後有沒有回答

還會保存實際執行過的事件,例如:

Tool Call
模型呼叫次數
Session Event
最後答案

原因和前面幾天一樣。

假設模型最後回答:

我查過 devbench 的專案資訊。

不能只因為它說「我查過」就相信。

我們真正要確認的是事件裡有沒有:

project_info

所以測試要求:

"project_info" in result["tool_calls"]

真的成立。

模型自述不是執行紀錄。

https://ithelp.ithome.com.tw/upload/images/20260930/20161224aFuc9itvLV.png隔離環境實測

五、Runner 幫忙跑流程,但限制還是我們決定

前面手刻 Agent 時,我們自己設定:

max_steps
tool_budget

換成 ADK 之後,也不能因為 Framework 已經有執行機制,就完全不管限制。

這次仍然會限制模型最多可以被呼叫幾次。

因為對本機 GPU 來說:

一次 Agent 任務

如果因為錯誤流程變成:

模型
↓
Tool
↓
模型
↓
Tool
↓
模型
↓
Tool
↓
...

GPU 一樣會一直跑。

所以 Framework 可以幫我們管理 Loop。

但:

這個 Loop 最多允許跑多久?

仍然是應用程式自己的決策。

這跟 Day 13 的原則沒有變:

會自己繼續跑的流程,就一定要有上限。

六、Session 不等於 Memory

今天使用的是:

InMemorySessionService

它可以保存目前這段執行需要的 Session 資料與事件。

但關鍵字在:

InMemory

程式一關掉,資料就沒了。

所以今天做到的是:

Session

不是:

長期記憶

更不是:

跨程式重啟恢復
資料庫持久化
跨裝置同步

這幾個概念不要因為都和「記住東西」有關,就混在一起。

目前可以先理解成:

Context
→ 這一輪模型現在看得到什麼

Session
→ 這段互動目前發生過什麼

Memory
→ 跨較長時間保留哪些有用資訊

Persistence
→ 程式重啟後資料還在不在

後面做到 OpenClaw 的 Session、Workspace 和 Memory 時,還會再回來拆這幾個概念。

七、Framework 到底替我們拿走了什麼?

到這裡就可以回頭跟前幾天比較。

原本自己寫 Agent:

建立 messages
↓
呼叫模型
↓
解析 Tool Call
↓
執行 Tool
↓
塞回 Observation
↓
判斷下一輪

今天改成:

建立 Agent
↓
交給 Runner
↓
Runner 管理模型與 Tool 的事件流程
↓
Session 保存狀態

少掉很多流程程式碼。

但有幾件事 ADK 沒有替我們決定:

Tool 到底安不安全
模型可以看到哪些能力
執行上限是多少
哪些資料可以讀
結果到底正不正確

這些問題不會因為換成 Framework 就消失。

Framework 解決的是:

怎麼把 Agent 流程組織得比較一致。

不是:

幫你自動做完所有 Agent 設計。


昨天的 Plan-and-Execute 還是:

我們的程式
↓
自己管理 Planner
↓
自己管理 Executor
↓
自己保存執行狀態

今天開始把部分責任交給 ADK:

ADK Agent
↓
Runner
↓
LocalModel
↓
Ollama

        ↓

Python Tool

而我們原本的 OllamaClient 還在。

代表:

換了 Agent Framework,不代表要把模型與前面的程式全部推倒重來。

今天只是先確認 Framework 與本機模型可以正常合作。

明天再補最後一塊:

ADK
↓
MCP
↓
devbench

看看 Day 10 寫好的 MCP Server,在換成另一套 Agent Framework 之後,是不是還能直接重用。

Day 18:

讓 Google ADK 使用 MCP:把既有工具接進新框架。


參考資料

Google ADK Python - BaseLlm
https://github.com/google/adk-python/blob/main/src/google/adk/models/base_llm.py

Google Agent Development Kit
https://github.com/google/adk-python


上一篇
Day 16:用 Python 實作 Plan-and-Execute:讓 Agent 完成多步任務
下一篇
Day 18:讓 Google ADK 使用 MCP:把既有工具接進新框架
系列文
協定、框架、架構:一條龍搞懂 AI Agent 是怎麼被造出來的 共 18 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言