1. 📖 Giới thiệu
Trong lớp học lập trình trước , bạn sẽ tìm hiểu cách thiết kế một hoạt động tương tác dữ liệu đa phương thức trong ADK. Giờ đây, chúng ta sẽ tiến thêm một bước nữa về cách thiết kế một hoạt động tương tác dữ liệu đa phương thức với Máy chủ MCP bằng cách sử dụng Bộ công cụ MCP. Chúng tôi sẽ mở rộng các chức năng của tác nhân trình chỉnh sửa ảnh sản phẩm đã phát triển trước đó bằng các chức năng tạo video ngắn bằng mô hình Veo, sử dụng Veo MCP Server
Trong lớp học lập trình này, bạn sẽ sử dụng phương pháp từng bước như sau:
- Chuẩn bị dự án trên Google Cloud và thư mục tác nhân cơ sở
- Định cấu hình một Máy chủ MCP yêu cầu dữ liệu tệp làm dữ liệu đầu vào
- Trang bị cho tác nhân ADK để kết nối với Máy chủ MCP
- Thiết kế một chiến lược câu lệnh và hàm gọi lại để sửa đổi yêu cầu gọi hàm thành MCP Toolset
- Thiết kế một hàm gọi lại để xử lý phản hồi dữ liệu đa phương thức từ MCP Toolset
Tổng quan về cấu trúc
Tương tác tổng thể trong lớp học lập trình này được minh hoạ trong sơ đồ sau

Điều kiện tiên quyết
- Thoải mái khi làm việc với Python
- (Không bắt buộc) Các lớp học lập trình cơ bản về Agent Development Kit (ADK)
- (Không bắt buộc) Lớp học lập trình về Công cụ đa phương thức ADK Phần 1 : goo.gle/adk-multimodal-tool-1
Kiến thức bạn sẽ học được
- Cách tạo video ngắn bằng Veo 3.1 với câu lệnh và hình ảnh khởi đầu
- Cách phát triển Máy chủ MCP đa phương thức bằng FastMCP
- Cách thiết lập ADK để sử dụng Bộ công cụ MCP
- Cách sửa đổi lệnh gọi công cụ thành MCP Toolset thông qua lệnh gọi lại công cụ
- Cách sửa đổi phản hồi của công cụ từ MCP Toolset thông qua lệnh gọi lại công cụ
Bạn cần có
- Trình duyệt web Chrome
- Tài khoản Gmail
- Một Dự án trên đám mây đã bật tài khoản thanh toán
Lớp học lập trình này được thiết kế cho nhà phát triển ở mọi cấp độ (kể cả người mới bắt đầu), sử dụng Python trong ứng dụng mẫu. Tuy nhiên, bạn không cần có kiến thức về Python để hiểu các khái niệm được trình bày.
2. 🚀 ( Không bắt buộc) Chuẩn bị chế độ thiết lập phát triển hội thảo
Bước 1: Chọn Dự án đang hoạt động trong Cloud Console
Trong Google Cloud Console, trên trang chọn dự án, hãy chọn hoặc tạo một dự án trên Google Cloud (xem phần trên cùng bên trái của bảng điều khiển)

Nhấp vào biểu tượng đó, bạn sẽ thấy danh sách tất cả dự án của mình như ví dụ này:

Giá trị được biểu thị bằng hộp màu đỏ là MÃ DỰ ÁN và giá trị này sẽ được dùng trong suốt hướng dẫn.
Đảm bảo bạn đã bật tính năng thanh toán cho dự án trên Cloud. Để kiểm tra, hãy nhấp vào biểu tượng trình đơn ☰ ở thanh trên cùng bên trái để xem Trình đơn điều hướng và tìm trình đơn Thanh toán

Nếu bạn thấy "Tài khoản thanh toán dùng thử của Google Cloud Platform" trong phần Thanh toán / Tổng quan ( phần trên cùng bên trái của bảng điều khiển đám mây), thì dự án của bạn đã sẵn sàng để sử dụng cho hướng dẫn này. Nếu không, hãy quay lại đầu hướng dẫn này và sử dụng tài khoản thanh toán dùng thử

Bước 2: Làm quen với Cloud Shell
Bạn sẽ sử dụng Cloud Shell cho hầu hết các phần của hướng dẫn, hãy nhấp vào Kích hoạt Cloud Shell ở đầu Google Cloud Console. Nếu hệ thống nhắc bạn uỷ quyền, hãy nhấp vào Uỷ quyền


Sau khi kết nối với Cloud Shell, chúng ta cần kiểm tra xem shell ( hoặc cửa sổ dòng lệnh) đã được xác thực bằng tài khoản của chúng ta hay chưa
gcloud auth list
Nếu bạn thấy gmail cá nhân của mình như ví dụ về đầu ra bên dưới, thì mọi thứ đều ổn
Credentialed Accounts
ACTIVE: *
ACCOUNT: alvinprayuda@gmail.com
To set the active account, run:
$ gcloud config set account `ACCOUNT`
Nếu không, hãy thử làm mới trình duyệt và đảm bảo bạn nhấp vào Uỷ quyền khi được nhắc ( quá trình này có thể bị gián đoạn do sự cố kết nối)
Tiếp theo, chúng ta cũng cần kiểm tra xem shell đã được định cấu hình thành PROJECT ID chính xác mà bạn có hay chưa. Nếu thấy có giá trị bên trong ( ) trước biểu tượng $ trong thiết bị đầu cuối ( trong ảnh chụp màn hình bên dưới, giá trị là "adk-multimodal-tool"), thì giá trị này cho biết dự án đã định cấu hình cho phiên shell đang hoạt động của bạn.

Nếu giá trị được hiển thị đã chính xác, bạn có thể bỏ qua lệnh tiếp theo. Tuy nhiên, nếu không chính xác hoặc bị thiếu, hãy chạy lệnh sau
gcloud config set project <YOUR_PROJECT_ID>
Sau đó, hãy sao chép thư mục làm việc của mẫu cho lớp học lập trình này từ GitHub bằng cách chạy lệnh sau. Thao tác này sẽ tạo thư mục làm việc trong thư mục adk-multimodal-tool
git clone https://github.com/alphinside/adk-mcp-multimodal.git adk-multimodal-tool
Bước 3: Làm quen với Cloud Shell Editor và thiết lập thư mục làm việc của ứng dụng
Bây giờ, chúng ta có thể thiết lập trình chỉnh sửa mã để thực hiện một số việc liên quan đến mã hoá. Chúng ta sẽ sử dụng Trình chỉnh sửa Cloud Shell cho việc này
Nhấp vào nút Open Editor (Mở trình chỉnh sửa). Thao tác này sẽ mở Cloud Shell Editor 
Sau đó, hãy chuyển đến phần trên cùng của Cloud Shell Editor rồi nhấp vào File->Open Folder (Tệp->Mở thư mục), tìm thư mục username (tên người dùng) của bạn, tìm thư mục adk-multimodal-tool (công cụ đa phương thức adk) rồi nhấp vào nút OK. Thao tác này sẽ đặt thư mục đã chọn làm thư mục làm việc chính. Trong ví dụ này, tên người dùng là alvinprayuda, do đó, đường dẫn thư mục sẽ xuất hiện bên dưới


Giờ đây, thư mục làm việc của Cloud Shell Editor sẽ có dạng như sau ( trong adk-multimodal-tool)

Bây giờ, hãy mở cửa sổ dòng lệnh cho trình chỉnh sửa. Bạn có thể thực hiện việc này bằng cách nhấp vào Terminal -> New Terminal (Cửa sổ dòng lệnh -> Cửa sổ dòng lệnh mới) trên thanh trình đơn hoặc sử dụng tổ hợp phím Ctrl + Shift + C. Thao tác này sẽ mở một cửa sổ dòng lệnh ở phần dưới cùng của trình duyệt

Thiết bị đầu cuối đang hoạt động hiện tại của bạn phải nằm trong thư mục làm việc adk-multimodal-tool. Chúng ta sẽ sử dụng Python 3.12 trong lớp học lập trình này và sẽ dùng trình quản lý dự án uv python để đơn giản hoá nhu cầu tạo và quản lý phiên bản python cũng như môi trường ảo. Gói uv này đã được cài đặt sẵn trên Cloud Shell.
Chạy lệnh này để cài đặt các phần phụ thuộc cần thiết cho môi trường ảo trong thư mục .venv
uv sync --frozen
Kiểm tra pyproject.toml để xem các phần phụ thuộc đã khai báo cho hướng dẫn này là google-adk, and python-dotenv.
Bây giờ, chúng ta sẽ cần bật các API bắt buộc thông qua lệnh bên dưới. Quá trình này có thể mất một chút thời gian.
gcloud services enable aiplatform.googleapis.com
Khi thực thi lệnh thành công, bạn sẽ thấy một thông báo tương tự như thông báo dưới đây:
Operation "operations/..." finished successfully.
Cấu trúc tác nhân mẫu đã được cung cấp cho bạn trong thư mục part2_starter_agent trên kho lưu trữ được sao chép. Bây giờ, trước tiên chúng ta cần đổi tên để chuẩn bị cho hướng dẫn này
mv part1_ckpt_agent product_photo_editor
Sau đó, sao chép product_photo_editor/.env.example vào product_photo_editor/.env
cp product_photo_editor/.env.example product_photo_editor/.env
Khi mở tệp product_photo_editor/.env, bạn sẽ thấy nội dung như bên dưới
GOOGLE_GENAI_USE_VERTEXAI=1
GOOGLE_CLOUD_PROJECT=your-project-id
GOOGLE_CLOUD_LOCATION=global
Sau đó, bạn cần cập nhật giá trị your-project-id bằng mã dự án chính xác của riêng bạn. Giờ thì chúng ta đã sẵn sàng cho bước tiếp theo
3. 🚀 Khởi chạy Máy chủ MCP Veo
Trước tiên, hãy tạo thư mục dịch vụ MCP bằng lệnh sau
mkdir veo_mcp
Sau đó, hãy tạo veo_mcp/main.py bằng lệnh này
touch veo_mcp/main.py
Sau đó, sao chép mã sau đây vào veo_mcp/main.py
from fastmcp import FastMCP
from typing import Annotated
from pydantic import Field
import base64
import asyncio
import os
from google import genai
from google.genai import types
from dotenv import load_dotenv
import logging
# Load environment variables from .env file
load_dotenv()
mcp = FastMCP("Veo MCP Server")
@mcp.tool
async def generate_video_with_image(
prompt: Annotated[
str, Field(description="Text description of the video to generate")
],
image_data: Annotated[
str, Field(description="Base64-encoded image data to use as starting frame")
],
negative_prompt: Annotated[
str | None,
Field(description="Things to avoid in the generated video"),
] = None,
) -> dict:
"""Generates a professional product marketing video from text prompt and starting image using Google's Veo API.
This function uses an image as the first frame of the generated video and automatically
enriches your prompt with professional video production quality guidelines to create
high-quality marketing assets suitable for commercial use.
AUTOMATIC ENHANCEMENTS APPLIED:
- 4K cinematic quality with professional color grading
- Smooth, stabilized camera movements
- Professional studio lighting setup
- Shallow depth of field for product focus
- Commercial-grade production quality
- Marketing-focused visual style
PROMPT WRITING TIPS:
Describe what you want to see in the video. Focus on:
- Product actions/movements (e.g., "rotating slowly", "zooming into details")
- Desired camera angles (e.g., "close-up of the product", "wide shot")
- Background/environment (e.g., "minimalist white backdrop", "lifestyle setting")
- Any specific details about the product presentation
The system will automatically enhance your prompt with professional production quality.
Args:
prompt: Description of the video to generate. Focus on the core product presentation
you want. The system will automatically add professional quality enhancements.
image_data: Base64-encoded image data to use as the starting frame
negative_prompt: Optional prompt describing what to avoid in the video
Returns:
dict: A dictionary containing:
- status: 'success' or 'error'
- message: Description of the result
- video_data: Base64-encoded video data (on success only)
"""
try:
# Initialize the Gemini client
client = genai.Client(
vertexai=True,
project=os.getenv("GOOGLE_CLOUD_PROJECT"),
location=os.getenv("GOOGLE_CLOUD_LOCATION"),
)
# Decode the image
image_bytes = base64.b64decode(image_data)
print(f"Successfully decoded image data: {len(image_bytes)} bytes")
# Create image object
image = types.Image(image_bytes=image_bytes, mime_type="image/png")
# Prepare the config
config = types.GenerateVideosConfig(
duration_seconds=8,
number_of_videos=1,
)
if negative_prompt:
config.negative_prompt = negative_prompt
# Enrich the prompt for professional marketing quality
enriched_prompt = enrich_prompt_for_marketing(prompt)
# Generate the video (async operation)
operation = client.models.generate_videos(
model="veo-3.1-generate-preview",
prompt=enriched_prompt,
image=image,
config=config,
)
# Poll until the operation is complete
poll_count = 0
while not operation.done:
poll_count += 1
print(f"Waiting for video generation to complete... (poll {poll_count})")
await asyncio.sleep(5)
operation = client.operations.get(operation)
# Download the video and convert to base64
video = operation.response.generated_videos[0]
# Get video bytes and encode to base64
video_bytes = video.video.video_bytes
video_base64 = base64.b64encode(video_bytes).decode("utf-8")
print(f"Video generated successfully: {len(video_bytes)} bytes")
return {
"status": "success",
"message": f"Video with image generated successfully after {poll_count * 5} seconds",
"complete_prompt": enriched_prompt,
"video_data": video_base64,
}
except Exception as e:
logging.error(e)
return {
"status": "error",
"message": f"Error generating video with image: {str(e)}",
}
def enrich_prompt_for_marketing(user_prompt: str) -> str:
"""Enriches user prompt with professional video production quality enhancements.
Adds cinematic quality, professional lighting, smooth camera work, and marketing-focused
elements to ensure high-quality product marketing videos.
"""
enhancement_prefix = """Create a high-quality, professional product marketing video with the following characteristics:
TECHNICAL SPECIFICATIONS:
- 4K cinematic quality with professional color grading
- Smooth, stabilized camera movements
- Professional studio lighting setup with soft, even illumination
- Shallow depth of field for product focus
- High dynamic range (HDR) for vibrant colors
VISUAL STYLE:
- Clean, minimalist aesthetic suitable for premium brand marketing
- Elegant and sophisticated presentation
- Commercial-grade production quality
- Attention to detail in product showcase
USER'S SPECIFIC REQUIREMENTS:
"""
enhancement_suffix = """
ADDITIONAL QUALITY GUIDELINES:
- Ensure smooth transitions and natural motion
- Maintain consistent lighting throughout
- Keep the product as the clear focal point
- Use professional camera techniques (slow pans, tracking shots, or dolly movements)
- Apply subtle motion blur for cinematic feel
- Ensure brand-appropriate tone and style"""
return f"{enhancement_prefix}{user_prompt}{enhancement_suffix}"
if __name__ == "__main__":
mcp.run()
Mã sau đây sẽ thực hiện những việc sau:
- Tạo một máy chủ FastMCP cung cấp công cụ tạo video Veo 3.1 cho các tác nhân ADK
- Chấp nhận hình ảnh, câu lệnh dạng văn bản và câu lệnh phủ định được mã hoá bằng base64 làm dữ liệu đầu vào
- Tạo video dài 8 giây không đồng bộ bằng cách gửi yêu cầu đến Veo 3.1 API và thăm dò ý kiến mỗi 5 giây cho đến khi hoàn tất
- Trả về dữ liệu video được mã hoá base64 cùng với câu lệnh được làm phong phú
Công cụ MCP của Veo sẽ yêu cầu cùng một biến môi trường với tác nhân của chúng tôi, vì vậy, chúng ta chỉ cần sao chép và dán tệp .env. Chạy lệnh sau để thực hiện việc đó
cp product_photo_editor/.env veo_mcp/
Giờ đây, chúng ta có thể kiểm thử xem máy chủ MCP có đang chạy đúng cách hay không bằng cách chạy lệnh sau
uv run veo_mcp/main.py
Và nó sẽ hiển thị nhật ký bảng điều khiển như sau
╭────────────────────────────────────────────────────────────────────────────╮
│ │
│ _ __ ___ _____ __ __ _____________ ____ ____ │
│ _ __ ___ .'____/___ ______/ /_/ |/ / ____/ __ \ |___ \ / __ \ │
│ _ __ ___ / /_ / __ `/ ___/ __/ /|_/ / / / /_/ / ___/ / / / / / │
│ _ __ ___ / __/ / /_/ (__ ) /_/ / / / /___/ ____/ / __/_/ /_/ / │
│ _ __ ___ /_/ \____/____/\__/_/ /_/\____/_/ /_____(*)____/ │
│ │
│ │
│ FastMCP 2.0 │
│ │
│ │
│ 🖥️ Server name: Veo MCP Server │
│ 📦 Transport: STDIO │
│ │
│ 🏎️ FastMCP version: 2.12.5 │
│ 🤝 MCP SDK version: 1.16.0 │
│ │
│ 📚 Docs: https://gofastmcp.com │
│ 🚀 Deploy: https://fastmcp.cloud │
│ │
╰────────────────────────────────────────────────────────────────────────────╯
[10/22/25 08:28:53] INFO Starting MCP server 'Veo MCP Server' with server.py:1502
transport 'stdio'
Bây giờ, hãy tắt quy trình dịch vụ MCP bằng cách nhấn tổ hợp phím CTRL+C. Lệnh này sẽ được gọi từ ADK MCP Toolset sau này. Chúng ta có thể chuyển sang bước tiếp theo để cho phép nhân viên hỗ trợ sử dụng các công cụ MCP này
4. 🚀 Kết nối Máy chủ MCP của Veo với ADK Agent
Bây giờ, hãy kết nối máy chủ Veo MCP để tác nhân của chúng ta có thể sử dụng máy chủ này. Trước tiên, hãy tạo một tập lệnh khác để chứa bộ công cụ, chạy lệnh sau
touch product_photo_editor/mcp_tools.py
Sau đó, sao chép mã sau vào product_photo_editor/mcp_tools.py
from google.adk.tools.mcp_tool.mcp_toolset import MCPToolset
from google.adk.tools.mcp_tool.mcp_session_manager import StdioConnectionParams
from mcp import StdioServerParameters
mcp_toolset = MCPToolset(
connection_params=StdioConnectionParams(
server_params=StdioServerParameters(
command="uv",
args=[
"run",
"veo_mcp/main.py",
],
),
timeout=120, # seconds
),
)
# Option to connect to remote MCP server
# from google.adk.tools.mcp_tool.mcp_session_manager import StreamableHTTPConnectionParams
# mcp_toolset = MCPToolset(
# connection_params=StreamableHTTPConnectionParams(
# url="http://localhost:8000/mcp",
# timeout=120,
# ),
# )
Đoạn mã trên cho thấy cách chúng ta có thể kết nối với một máy chủ MCP bằng ADK MCPToolset. Trong ví dụ này, chúng ta kết nối với máy chủ MCP bằng kênh giao tiếp STDIO. Trong lệnh này, chúng ta chỉ định cách chạy máy chủ MCP và đặt tham số thời gian chờ.
5. 🚀 Sửa đổi thông số lệnh gọi công cụ
Trong khai báo công cụ máy chủ MCP, chúng tôi đã thiết kế công cụ generate_video_with_image chỉ định chuỗi base64 làm tham số công cụ. Chúng ta không thể yêu cầu LLM làm việc này cho mình, do đó, chúng ta cần thiết kế một chiến lược cụ thể để xử lý việc này.
Trong phòng thí nghiệm trước, chúng ta xử lý hình ảnh do người dùng tải lên và hình ảnh phản hồi của công cụ trong before_model_callback để lưu dưới dạng một cấu phần phần mềm. Điều này cũng được phản ánh trong mẫu tác nhân đã chuẩn bị trước đó. Chúng tôi sẽ tận dụng thông tin này và thực hiện các chiến lược sau:
- Hướng dẫn LLM luôn gửi giá trị artifact_id nếu tham số công cụ cụ thể yêu cầu gửi dữ liệu chuỗi base64
- Chặn lệnh gọi công cụ trong
before_tool_callbackvà chuyển đổi tham số từ artifact_id thành nội dung byte của tham số bằng cách tải cấu phần phần mềm và ghi đè các đối số của công cụ
Xem hình ảnh bên dưới để biết hình ảnh trực quan về phần mà chúng ta sẽ chặn

Trước tiên, hãy chuẩn bị hàm before_tool_callback, tạo một tệp mới product_photo_editor/tool_callbacks.py bằng cách chạy lệnh sau
touch product_photo_editor/tool_callbacks.py
Sau đó, sao chép mã sau vào tệp
# product_photo_editor/tool_callbacks.py
from google.genai.types import Part
from typing import Any
from google.adk.tools.tool_context import ToolContext
from google.adk.tools.base_tool import BaseTool
from google.adk.tools.mcp_tool.mcp_tool import McpTool
import base64
import logging
import json
from mcp.types import CallToolResult
async def before_tool_modifier(
tool: BaseTool, args: dict[str, Any], tool_context: ToolContext
):
# Identify which tool input should be modified
if isinstance(tool, McpTool) and tool.name == "generate_video_with_image":
logging.info("Modify tool args for artifact: %s", args["image_data"])
# Get the artifact filename from the tool input argument
artifact_filename = args["image_data"]
artifact = await tool_context.load_artifact(filename=artifact_filename)
file_data = artifact.inline_data.data
# Convert byte data to base64 string
base64_data = base64.b64encode(file_data).decode("utf-8")
# Then modify the tool input argument
args["image_data"] = base64_data
Đoạn mã trên cho thấy các bước sau:
- Kiểm tra xem công cụ được gọi có phải là đối tượng McpTool hay không và đó có phải là lệnh gọi công cụ mục tiêu mà chúng ta muốn sửa đổi hay không
- Lấy giá trị của các đối số
image_data. Đây là đối số được yêu cầu ở định dạng base64 nhưng chúng tôi yêu cầu LLM trả về artifact_id trên đó - Tải cấu phần phần mềm bằng cách sử dụng dịch vụ cấu phần phần mềm trên
tool_context - Ghi đè các đối số
image_databằng dữ liệu base64
Bây giờ, chúng ta cần thêm lệnh gọi lại này vào tác nhân và cũng sửa đổi nhẹ các hướng dẫn để tác nhân sẽ luôn điền các đối số công cụ base64 bằng mã nhận dạng cấu phần phần mềm.
Mở product_photo_editor/agent.py rồi sửa đổi nội dung bằng đoạn mã sau
# product_photo_editor/agent.py
from google.adk.agents.llm_agent import Agent
from product_photo_editor.custom_tools import edit_product_asset
from product_photo_editor.mcp_tools import mcp_toolset
from product_photo_editor.model_callbacks import before_model_modifier
from product_photo_editor.tool_callbacks import before_tool_modifier
from product_photo_editor.prompt import AGENT_INSTRUCTION
root_agent = Agent(
model="gemini-2.5-flash",
name="product_photo_editor",
description="""A friendly product photo editor assistant that helps small business
owners edit and enhance their product photos. Perfect for improving photos of handmade
goods, food products, crafts, and small retail items""",
instruction=AGENT_INSTRUCTION
+ """
**IMPORTANT: Base64 Argument Rule on Tool Call**
If you found any tool call arguments that requires base64 data,
ALWAYS provide the artifact_id of the referenced file to
the tool call. NEVER ask user to provide base64 data.
Base64 data encoding process is out of your
responsibility and will be handled in another part of the system.
""",
tools=[
edit_product_asset,
mcp_toolset,
],
before_model_callback=before_model_modifier,
before_tool_callback=before_tool_modifier,
)
Bây giờ, hãy thử tương tác với nhân viên hỗ trợ để kiểm thử nội dung sửa đổi này. Chạy lệnh sau để chạy giao diện người dùng dành cho nhà phát triển web
uv run adk web --port 8080
Lệnh này sẽ tạo ra kết quả như ví dụ sau, tức là chúng ta đã có thể truy cập vào giao diện web
INFO: Started server process [xxxx] INFO: Waiting for application startup. +-----------------------------------------------------------------------------+ | ADK Web Server started | | | | For local testing, access at http://127.0.0.1:8080. | +-----------------------------------------------------------------------------+ INFO: Application startup complete. INFO: Uvicorn running on http://127.0.0.1:8080 (Press CTRL+C to quit)
Giờ đây, để kiểm tra, bạn có thể nhấn tổ hợp phím Ctrl + Nhấp vào URL hoặc nhấp vào nút Xem trước trên web ở khu vực trên cùng của Cloud Shell Editor rồi chọn Xem trước trên cổng 8080

Bạn sẽ thấy trang web sau đây, nơi bạn có thể chọn các nhân viên hỗ trợ hiện có trên nút thả xuống ở trên cùng bên trái ( trong trường hợp này, đó phải là product_photo_editor) và tương tác với bot.
Sau đó, hãy tải hình ảnh sau lên và yêu cầu trợ lý tạo đoạn video quảng cáo từ hình ảnh đó
Generate a slow zoom in and moving from left and right animation

Bạn sẽ gặp phải lỗi sau

Tại sao? Vì công cụ này cũng trả về kết quả trực tiếp dưới dạng chuỗi base64, nên kết quả đó sẽ vượt quá mã thông báo tối đa. Bây giờ, hãy xử lý lỗi này trong phần tiếp theo.
6. 🚀 Sửa đổi câu trả lời của công cụ
Trong phần này, chúng ta sẽ xử lý phản hồi của công cụ từ phản hồi MCP. Chúng tôi sẽ làm những việc sau:
- Lưu trữ phản hồi bằng video của công cụ trong dịch vụ tạo tác
- Thay vào đó, hãy trả về giá trị nhận dạng cấu phần phần mềm cho tác nhân
Xin lưu ý rằng chúng tôi sẽ khai thác thời gian chạy tác nhân sau đây

Trước tiên, hãy triển khai hàm gọi lại, mở product_photo_editor/tool_callbacks.py và sửa đổi hàm này để triển khai after_tool_modifier
# product_photo_editor/tool_callbacks.py
from google.genai.types import Part
from typing import Any
from google.adk.tools.tool_context import ToolContext
from google.adk.tools.base_tool import BaseTool
from google.adk.tools.mcp_tool.mcp_tool import McpTool
import base64
import logging
import json
from mcp.types import CallToolResult
async def before_tool_modifier(
tool: BaseTool, args: dict[str, Any], tool_context: ToolContext
):
# Identify which tool input should be modified
if isinstance(tool, McpTool) and tool.name == "generate_video_with_image":
logging.info("Modify tool args for artifact: %s", args["image_data"])
# Get the artifact filename from the tool input argument
artifact_filename = args["image_data"]
artifact = await tool_context.load_artifact(filename=artifact_filename)
file_data = artifact.inline_data.data
# Convert byte data to base64 string
base64_data = base64.b64encode(file_data).decode("utf-8")
# Then modify the tool input argument
args["image_data"] = base64_data
async def after_tool_modifier(
tool: BaseTool,
args: dict[str, Any],
tool_context: ToolContext,
tool_response: dict | CallToolResult,
):
if isinstance(tool, McpTool) and tool.name == "generate_video_with_image":
tool_result = json.loads(tool_response.content[0].text)
# Get the expected response field which contains the video data
video_data = tool_result["video_data"]
artifact_filename = f"video_{tool_context.function_call_id}.mp4"
# Convert base64 string to byte data
video_bytes = base64.b64decode(video_data)
# Save the video as artifact
await tool_context.save_artifact(
filename=artifact_filename,
artifact=Part(inline_data={"mime_type": "video/mp4", "data": video_bytes}),
)
# Remove the video data from the tool response
tool_result.pop("video_data")
# Then modify the tool response to include the artifact filename and remove the base64 string
tool_result["video_artifact_id"] = artifact_filename
logging.info(
"Modify tool response for artifact: %s", tool_result["video_artifact_id"]
)
return tool_result
Sau đó, chúng ta cần trang bị cho tác nhân của mình chức năng này. Mở product_photo_editor/agent.py rồi sửa đổi thành mã sau
# product_photo_editor/agent.py
from google.adk.agents.llm_agent import Agent
from product_photo_editor.custom_tools import edit_product_asset
from product_photo_editor.mcp_tools import mcp_toolset
from product_photo_editor.model_callbacks import before_model_modifier
from product_photo_editor.tool_callbacks import (
before_tool_modifier,
after_tool_modifier,
)
from product_photo_editor.prompt import AGENT_INSTRUCTION
root_agent = Agent(
model="gemini-2.5-flash",
name="product_photo_editor",
description="""A friendly product photo editor assistant that helps small business
owners edit and enhance their product photos. Perfect for improving photos of handmade
goods, food products, crafts, and small retail items""",
instruction=AGENT_INSTRUCTION
+ """
**IMPORTANT: Base64 Argument Rule on Tool Call**
If you found any tool call arguments that requires base64 data,
ALWAYS provide the artifact_id of the referenced file to
the tool call. NEVER ask user to provide base64 data.
Base64 data encoding process is out of your
responsibility and will be handled in another part of the system.
""",
tools=[
edit_product_asset,
mcp_toolset,
],
before_model_callback=before_model_modifier,
before_tool_callback=before_tool_modifier,
after_tool_callback=after_tool_modifier,
)
Vậy là xong! Giờ đây, bạn có thể yêu cầu Gemini không chỉ giúp bạn chỉnh sửa ảnh mà còn tạo video cho bạn! Chạy lại lệnh sau
uv run adk web --port 8080
Sau đó, hãy thử tạo video bằng hình ảnh này
Generate a slow zoom in and moving from left and right animation

Bạn sẽ thấy video được tạo như ví dụ bên dưới và đã được lưu dưới dạng thành phần

7. ⭐ Tóm tắt
Bây giờ, hãy xem lại những gì chúng ta đã làm trong lớp học lập trình này. Sau đây là điểm học tập chính:
- Xử lý dữ liệu đa phương thức (Công cụ I/O): Củng cố chiến lược quản lý dữ liệu đa phương thức (chẳng hạn như hình ảnh và video) cho đầu vào và đầu ra của công cụ bằng cách sử dụng dịch vụ Artifacts của ADK và các lệnh gọi lại chuyên biệt thay vì truyền trực tiếp dữ liệu thô theo byte.
- Tích hợp bộ công cụ MCP: Phát triển và tích hợp một Máy chủ MCP Veo bên ngoài bằng FastMCP thông qua Bộ công cụ MCP ADK để thêm các chức năng tạo video vào tác nhân.
- Sửa đổi dữ liệu đầu vào của công cụ (before_tool_callback): Triển khai một lệnh gọi lại để chặn lệnh gọi công cụ generate_video_with_image, chuyển đổi artifact_id của tệp (do LLM chọn) thành dữ liệu hình ảnh được mã hoá base64 bắt buộc cho dữ liệu đầu vào của máy chủ MCP.
- Sửa đổi đầu ra của công cụ (after_tool_callback): Triển khai một lệnh gọi lại để chặn phản hồi video được mã hoá base64 có kích thước lớn từ máy chủ MCP, lưu video dưới dạng một cấu phần phần mềm mới và trả về một tham chiếu video_artifact_id rõ ràng cho LLM.
8. 🧹 Dọn dẹp
Để tránh phát sinh phí cho tài khoản Google Cloud của bạn đối với các tài nguyên được dùng trong lớp học lập trình này, hãy làm theo các bước sau:
- Trong Google Cloud Console, hãy chuyển đến trang Quản lý tài nguyên.
- Trong danh sách dự án, hãy chọn dự án mà bạn muốn xoá, rồi nhấp vào Xoá.
- Trong hộp thoại, hãy nhập mã dự án rồi nhấp vào Tắt để xoá dự án.