## 課程筆記:第五天 - 從原型到生產 (Prototype to Production)
### 1\. 白皮書總覽:生產的運營手冊
* **核心挑戰**:這最後一哩路通常佔了 80% 的實際工作。
* **人員與流程**:白皮書首先定義了成熟的「代理維運」(Agent Ops) 所需的專業角色,從設計安全護欄的 AI 工程師到管理身份驗證的平台團隊。
* **CI/CD 評估**:
* **核心原則**:**沒有任何代理版本應該在未通過自動化迴歸評估套件(用於證明其品質與安全)之前就上線到生產環境**。
* **安全部署策略**:
* **金絲雀部署 (Canary Deployments)**:從 1% 的用戶開始,逐步放量。
* **藍綠部署 (Blue-Green Deployments)**:允許在出現問題時立即回滾。
* **上線後的循環**:
* 建立一個「**觀察 -\> 行動 -\> 進化**」(Observe -\> Act -\> Evolve) 的持續循環。
* 使用即時監控來觸發立即修復(例如:熔斷器),並將洞察反饋回開發流程中。
* **規模化**:
* 使用 **A2A (Agent-to-Agent)** 協議來建立協作生態系統,讓代理能發現彼此並委派複雜任務。
-----
### 2\. 程式實驗 (Code Lab) 演練
#### 實驗 1:A2A (Agent-to-Agent) 代理間通訊
* **問題**:
1. 單一代理很難處理所有功能。
2. 您可能需要使用由「**其他團隊**」或「**其他組織**」(例如:供應商)建立的代理。
3. 這些代理可能使用**不同的框架、不同的語言,並運行在不同的網路上**。
* **解決方案**:**A2A (Agent-to-Agent)** 協議。這是一個標準,允許跨框架、跨語言、跨組織的代理進行通訊。
* **實驗設定**:
* **您的代理**:`CustomerSupportAgent`(客戶支援代理)。
* **目標**:回答客戶關於產品價格和庫存的問題。
* **問題**:產品資料不在您手上,而是在您的「**供應商**」那裡。
* **供應商的代理**:`ProductCatalogAgent`(產品目錄代理),它在供應商的網路上運行。
* **A2A 如何運作?**
* **Agent Card (代理名片)**:
* 當一個代理符合 A2A 規範時,它會暴露一個稱為「**代理名片**」(Agent Card) 的 JSON 檔案。
* 這張「名片」就像是代理的業務名片,描述了它叫什麼名字、它能做什麼,以及它有哪些工具(例如:`get_product_info`)。
* **部署(第 1 部分:供應商)**:
* 供應商使用 ADK 建立 `ProductCatalogAgent`。
* 供應商**只需一行函式呼叫**,即可將其轉換為 A2A 相容的代理,並指定運行的埠號 (port)。這會自動生成 `agent-card.json`。
* **呼叫(第 2 部分:您)**:
* 在您的 `CustomerSupportAgent` 中,您建立一個「**子代理**」(Sub-agent)。
* 但這個子代理是「**遠端的 A2A 代理**」(Remote A2A Agent)。
* 您需要做的就是在配置中指向供應商的「**代理名片 URL**」(例如:`http://vendor-server:port/.well-known/agent-card.json`)。
* **執行流程**:
1. 客戶向您的 `CustomerSupportAgent` 提問:「iPhone 15 Pro 有貨嗎?」
2. 您的代理看到這個問題,並將其傳遞給設定為子代理的 `RemoteProductCatalogAgent`。
3. 這個遠端代理(實際上是一個代理 proxy)接著呼叫供應商網路上的 A2A 端點。
4. 供應商的 `ProductCatalogAgent` 查詢其內部資料庫,並返回資訊。
5. 資訊傳回給您的 `CustomerSupportAgent`,最後由您的代理回覆客戶。
#### 實驗 2:部署代理到生產環境 (Google Cloud)
* **問題**:您的代理目前只在 Kaggle 筆記本中運行。關閉分頁,代理就消失了。
* **解決方案**:將其部署到 **Vertex AI Agent Engine**。
* **什麼是 Agent Engine?**
* 這是一個專為 AI 代理設計的「**全託管服務**」。
* 它內建了自動擴展 (auto-scaling) 和會話管理 (session management)。
* **部署步驟**:
1. **建立代理**:我們建立一個簡單的 `WeatherAgent`(天氣代理)。
2. **設定**:配置 GCP 專案和區域 (Region)。
3. **部署**:在 ADK 中,部署**只需要一個命令**:`adk deploy agent-engine --agent SampleAgent`。
4. **等待**:部署過程大約需要 3-5 分鐘。
5. **查詢**:部署完成後,您會獲得一個「資源名稱」。您現在可以從任何地方(例如您的筆記本)查詢這個「**遠端代理**」。
* **添加長期記憶**:
* 預設情況下,此代理使用 `InMemorySession`(記憶是短期的)。
* 實驗室展示瞭如何輕鬆地為其配置 **Memory Bank**,使其具備**長期記憶**。
* 這樣,當您結束會話並重新開始時,您可以問:「我上次問的是哪個城市的天氣?」代理將會記得您上次問的是「東京」。
* **最後一步(重要)**:
* **刪除代理**:實驗結束後,請務必**刪除**您部署的 Agent Engine,以避免產生額外費用。
-----
### 3\. 專家 Q\&A 重點
* **Q: 對模型來說,什麼更重要:深度推理能力,還是極致的 token 效率(速度)? (Saurabh)**
* **看情況**。核心推理能力很重要,但如果延遲太高,應用程式在商業上就不可行。
* **趨勢**:隨著模型本身越來越強(內建更多邏輯),代理所需的「外部推理 token」正在**變少**。
* **最佳實踐**:**簡化單一代理的任務**。將複雜任務分解為多個「**子代理**」,而不是建立一個試圖做所有事情的「超級代理」。這對延遲和品質都有好處。
* **Q: 將代理規模化到生產環境,目前業界工具最大的差距是什麼? (Will)**
* **差距**:目前,**人類**是代理的「部署閘門」。
* **未來**:隨著代理數量激增(甚至代理會編寫程式碼來呼叫其他代理),人類評估將無法跟上。
* **解決方案**:我們需要「**AI 評估者**」(AI Evaluators)。
* **分層**:
* 80% 的低風險內部任務,將由「AI 評估者」基於可觀測性(如 Cloud Trace)和模擬數據,進行**自主和持續的評估**並批准部署。
* 20% 的高風險任務(面向客戶、關鍵系統),則**釋放出人類工程師的時間**,讓他們可以專注於深入評估。
* **Q: A2A 協議會成為企業 IT 現代化的標準,還是會增加技術債? (Will, Saurabh)**
* **答案:兩者都是 (Yes and Yes)**。
* **Will**:
* **是標準**:代理工作流正在徹底改變組織。一個衛生系統已經在使用 ADK 代理,為 3 萬名員工提供政策查詢。
* **是技債(但可控)**:它確實會產生新的技債,但諷刺的是,**代理本身**將是償還這些技債的工具(例如:代理執行程式碼審查、修復錯誤)。
* **Saurabh**:
* **AI 民主化**:AI 的承諾是讓「高品質的程式碼」民主化。
* **電腦使用 (Computer Use)**:代理可以為那些介面笨拙的傳統企業系統建立一個易於使用的自然語言介面。
* **Q: 對於跨邊界、不受信任的第三方 A2A 呼叫,推薦的安全模型是什麼? (Socrates, Elias)**
* **Socrates (核心觀點)**:**不要使用「不受信任」的代理**。就像你不會讓陌生人拿你的信用卡一樣。
* **認證**:
* **不推薦**:在代理之間傳遞用戶的 token。
* **不推薦**:每次呼叫新代理都重新認證用戶(體驗糟糕)。
* **未來方向**:一個「**中央代理授權機構**」(像代理警察)。所有代理都與它通信,它會儲存用戶憑證和代理權限,並扮演守門員的角色。
* **Elias**:A2A 協議是建立在現有基礎之上的。你應該使用現有的微服務安全實踐,如 **API 閘道、存取權杖、速率限制**等。
* **Q: 如何限制自主代理的操作範圍,並在出現不良後果時分配責任? (Will, Socrates)**
* **Will (零信任)**:
* **代理身份和註冊表**:這是第一道防線。
* **信任分層**:就像自動駕駛有不同層級 (Level) 一樣,我們需要對代理進行風險分類。
* **安全提升**:為了讓代理能執行任務,組織**被迫**必須將他們那些「隱藏的」或「口頭的」政策**明確地寫成軟體(指令)**,這反而會**提升**整個組織的安全性。
* **Socrates (分而治之)**:
* 將代理群組建成「**小型團隊**」(如經理、審查者、批准者),每個團隊只負責特定任務。
* **人在迴路 (Human-in-the-Loop)** 是**關鍵**的,人類必須為關鍵決策負責。
* **Q: 如何定義代理的「安全降級」策略(例如一個子代理不可用時)? (Elias, Saurabh)**
* **Elias**:
* **控制**:使用一個「**監督者**」(Supervisor) 代理來監控流程,或使用一個獨立的「**評論家**」(Critic) 代理來驗證事實。
* **模型多樣性**:讓「工作者」代理使用 Flash 模型,但讓「監督者」代理使用 Pro 模型,以避免共同的偏見。
* **彈性 (Resilience)**:
* **重試**:實施指數退避 (exponential backoff) 重試機制。
* **重新路由**:如果專家代理失敗,**退回 (fallback)** 到一個通用代理來回答部分問題。
* **透明的 UX**:如果「訂機票」這個關鍵代理失敗了,**不要**退回到通用代理去嘗試訂票。而是要透明地告訴用戶:「訂票服務目前不可用,但這裡有航班資訊和 URL,您可以手動預訂」。
* **Saurabh**:
* **清晰的錯誤訊息**:不要「**靜默失敗**」(silently fail)。如果子代理失敗了,它應該返回清晰的錯誤訊息(例如 503),這樣主代理才能圍繞這個失敗進行調整,並告知用戶。
* **Q: 如何在代理成本不可預測時,保持延遲和成本穩定? (Saurabh, Socrates)**
* **Saurabh**:
1. **提示快取 (Prompt Cache)**:這是最容易被忽視的。當重複的提示(包含工具定義、錯誤訊息等)被發送時,快取可以**大幅降低成本和延遲**。
2. **模型路由 (Model Routing)**:用 Pro 模型做複雜的頂層編排,用 Flash-Lite 模型做「你好」這樣簡單的回應。
3. **約束採樣 (Constraint Sampling)**:如果輸出是在特定範圍內,可以指示模型只從該空間採樣,而不是生成自然語言。
* **Socrates**:
* **安全護欄 (Guardrails)**:在 ADK 的 Callbacks(例如 `before_tool_call`)中設置護欄,一旦發現不相關的內容,**立即停止交互**,避免浪費成本。
-----
### 4\. 隨堂測驗 (Pop Quiz)
* **Q1**: 什麼是「評估閘門部署」(Evaluation-gated deployment)?
* **B**: 一個原則,即**沒有代理版本能在通過自動化評估前接觸到用戶**。
* **Q2**: A2A 和 MCP 協議如何互補?
* **A**: **A2A 用於將複雜任務委派給其他自主代理**;**MCP 用於標準化與特定工具和資源的連接**。
* **Q3**: 哪種安全部署策略涉及運行兩個相同的生產環境,並在它們之間即時切換流量?
* **D**: **藍綠部署 (Blue-Green Deployment)**。
* **Q4**: Google 安全 AI 框架 (Secure AI Framework) 應用於代理的三層防禦是什麼?
* **C**: **策略定義**(系統指令)、**護欄**(過濾)和**人在迴路**(升級)。
* **Q5**: 在「觀察-行動-進化」循環中,「進化」(Evolve) 階段的目的是什麼?
* **B**: 使用來自生產數據的洞察,**更新評估資料集**,並**永久性地改進代理的架構或邏輯**。
---
# Kaggle 實作 - 從提示到行動
本堂課 (Code Lab 5a) 介紹了 **代理間通訊 (Agent2Agent, A2A) 協議**。核心目標是學習如何建立一個多代理系統 (multi-agent system),讓不同的代理(Agent)可以跨網路、跨框架、甚至跨組織地互相溝通與協作。
-----
## 1\. 🤔 為何需要代理間通訊 (A2A)?
隨著 AI 系統變得越來越複雜,單一代理很難處理所有專業領域的任務。我們需要讓專注於不同功能的代理協同工作。
* **單一代理的限制**:一個代理無法同時精通客服、產品查詢、庫存管理和訂單處理。
* **專業分工**:讓不同團隊(甚至外部供應商)建立和維護各自領域的專業代理(例如:產品目錄代理、庫存代理)是更有效率的做法。
* **整合需求**:A2A 協議提供了一個標準化的方式,讓這些位於不同機器、使用不同語言或框架(例如 Python, Java, Node.js)的代理能互相呼叫,就像呼叫一個工具 (Tool) 一樣簡單。
## 2\. 💡 A2A vs. 本地子代理 (Local Sub-Agents)
在 Day 4 中,我們學習了本地代理(在同一個程式碼中)的協作。Day 5 專注於跨網路的 A2A,兩者適用情境不同:
> **本地子代理 (Local Sub-Agents)**
>
> * **情境**:代理都在同一個程式碼庫 (codebase)、由同一個團隊管理、在同一個機器進程中運行。
> * **優點**:效能高、低延遲。
> * **範例**:一個「旅行代理」呼叫同一個程式中的「機票代理」和「飯店代理」。
>
> **A2A 協議 (Agent2Agent Protocol)**
>
> * **情境**:代理位於外部服務器、由不同團隊(如外部供應商)管理、需要跨網路通訊,或使用不同語言撰寫。
> * **優點**:解耦 (Decoupled)、需要正式的 API 合約、跨框架/語言相容。
> * **範例**:您的「客服代理」呼叫外部廠商提供的「產品目錄代理」。
## 3\. 🧪 實驗架構:電子商務系統
本次實驗模擬一個電子商務場景,我們將建立兩個代理:一個內部的「消費者」和一個外部的「供應商」。
```
┌──────────────────────┐ ┌──────────────────────┐
│ Customer Support │ ─A2A──▶ │ Product Catalog │
│ Agent (消費者) │ │ Agent (供應商) │
│ (您的內部系統) │ │ (外部服務) │
└──────────────────────┘ └──────────────────────┘
```
### 代理 1 (供應商): Product Catalog Agent
* **角色**:由外部廠商維護,專門提供產品資訊。
* **工具**:擁有一個 `get_product_info` 工具,用於查詢(模擬的)產品資料庫。
* **任務**:將自己「曝露」(Expose) 到網路上 (例如 `localhost:8001`),等待 A2A 呼叫。
### 代理 2 (消費者): Customer Support Agent
* **角色**:您的內部客服代理,負責回覆客戶問題。
* **工具**:它唯一的工具就是一個能呼叫「供應商代理」的特殊工具。
* **任務**:當被問及產品資訊時,它會透過 A2A 協議呼叫「Product Catalog Agent」來取得資料。
### 互動流程
> 1. 客戶向 **Customer Support Agent** 提問:「你們有賣 Dell XPS 15 嗎?」
> 2. **Customer Support Agent** 意識到它需要產品資訊,決定呼叫它擁有的「A2A 工具」。
> 3. 這個「A2A 工具」向 `localhost:8001` (供應商) 發出網路請求。
> 4. **Product Catalog Agent** 收到請求,執行 `get_product_info` 工具查到 Dell XPS 15 的資訊。
> 5. **Product Catalog Agent** 透過網路將結果(產品資訊字串)回傳。
> 6. **Customer Support Agent** 收到資訊,並將其組織成一句通順的回覆給客戶。
## 4\. 💻 程式碼實作解析
A2A 的實作分為「曝露」(供應商端)和「消費」(消費者端)兩部分。
### 步驟 1: 建立並曝露「供應商代理」 (使用 `to_a2a`)
我們首先定義一個標準的 ADK 代理,並使用 `to_a2a` 將它轉換為一個網路服務。
```python
# (供應商端)
# 1. 像往常一樣,定義一個 Python 工具
def get_product_info(product_name: str) -> str:
# ... (查詢資料庫的邏輯) ...
return "Dell XPS 15, $1,299, In Stock"
# 2. 建立一個標準的 LlmAgent
product_catalog_agent = LlmAgent(
model=Gemini(...),
name="product_catalog_agent",
description="外部廠商的產品目錄代理",
tools=[get_product_info], # 註冊工具
)
# 3. (關鍵) 使用 to_a2a 將代理轉換為網路服務 App
# 我們需要提供一個 Session 服務來管理追蹤 (Tracing)
from google.adk.a2a.utils.agent_to_a2a import to_a2a
from google.adk.sessions import InMemorySessionService
app = to_a2a(
product_catalog_agent,
session_service=InMemorySessionService()
)
# 4. 啟動伺服器 (在 Kaggle 筆記本中,這會在背景運行)
# app.run(port=8001)
```
### 步驟 2: 建立並使用「消費者代理」 (使用 `RemoteA2aAgent`)
在消費者端,我們使用 **`RemoteA2aAgent`** 這個特殊的工具。它會自動處理所有 A2A 網路通訊的細節。
```python
# (消費者端)
from google.adk.agents.remote_a2a_agent import RemoteA2aAgent
# 1. (關鍵) 實例化一個指向「供應商」URL 的遠端代理
remote_product_agent = RemoteA2aAgent(
base_url="http://localhost:8001" # 指向步驟 1 啟動的伺服器
)
# 2. 載入遠端代理的能力 (它會自動抓取供應商的「Agent Card」)
remote_product_agent.load_agent_card()
# 3. 建立我們的「客服代理」
customer_support_agent = LlmAgent(
model=Gemini(...),
name="customer_support_agent",
instruction="你是客服,請使用工具回答產品問題",
# (關鍵) 將遠端代理本身當作一個工具註冊進來
tools=[remote_product_agent],
)
# 4. 執行「客服代理」
from google.adk.runners import Runner
runner = Runner(agent=customer_support_agent)
# 執行後,customer_support_agent 會自動呼叫 remote_product_agent
runner.run("Do you have the Dell XPS 15?")
```
## 5\. 🔑 核心概念總結
* **A2A 協議**:是一種標準,允許代理跨網路、跨框架、跨語言進行通訊。
* **`to_a2a()` (供應商)**:ADK 提供的函式,可快速將一個現有的 `LlmAgent` 曝露為 A2A 網路服務。
* **`RemoteA2aAgent` (消費者)**:ADK 提供的特殊工具,它封裝了 A2A 呼叫的複雜性。您只需將它當作一個普通工具加入到您的代理中,ADK 會自動處理網路請求和回應。
* **解耦 (Decoupling)**:您的「客服代理」完全不需要知道「產品代理」是如何實作的,它只知道如何呼叫這個「工具」即可。