zalo-icon
facebook-icon
phone-icon
TechData.AI Logo
XÂY DỰNG HỆ THỐNG ĐA TÁC NHÂN CHO NỘI DUNG CHUYÊN GIA VỚI GOOGLE ADK, MCP VÀ CLOUD RUN – PHẦN 1

Xây dựng hệ thống đa tác nhân cho nội dung chuyên gia với Google ADK, MCP và Cloud Run - Phần 1

Shir Meir Lador

Trưởng phòng AI, Product DevRel

Sứ mệnh của đội ngũ chúng tôi là đẩy nhanh hành trình của nhà phát triển, từ việc viết mã đến vận hành các khối lượng công việc AI an toàn trên Google Cloud. Để giúp các nhà phát triển thành công, chúng tôi tập trung vào việc xác định những câu hỏi cấp bách nhất của họ và xây dựng các bản demo cung cấp giải pháp trực quan, dễ triển khai.

Gần đây, tôi đã vô cùng hào hứng khi máy chủ Developer Knowledge MCP mới ra mắt. Điều này đã truyền cảm hứng cho tôi xây dựng Dev Signal—một hệ thống đa tác nhân được thiết kế với Bộ công cụ phát triển tác nhân Google (ADK)—để xác định các câu hỏi kỹ thuật từ Reddit, nghiên cứu chúng bằng tài liệu chính thức, và soạn thảo các bài blog kỹ thuật chi tiết. Dev Signal cũng cung cấp các hình ảnh tùy chỉnh bằng Nano Banana Pro. Tôi thậm chí còn tích hợp một lớp bộ nhớ dài hạn để tác nhân có thể ghi nhớ các sở thích và phong cách viết blog cụ thể của tôi.

Bằng cách kết nối trợ lý lập trình của mình, Gemini CLI, với máy chủ kiến thức nhà phát triển MCP, tôi đã xây dựng và triển khai toàn bộ hệ thống này lên Google Cloud Run chỉ trong hai ngày.

Cho dù bạn muốn học cách kiến trúc một hệ thống đa tác nhân phức tạp với bộ nhớ dài hạn, tận dụng các máy chủ MCP cục bộ và từ xa để chuẩn hóa công cụ, hay viết các script Terraform chi tiết để triển khai Cloud Run an toàn, tôi sẽ hướng dẫn bạn cách thực hiện!

Nếu bạn muốn tìm hiểu sâu hơn về mã nguồn và khám phá theo tốc độ của riêng mình, bạn có thể sao chép kho lưu trữ tại đây.

Hình ảnh minh họa hệ thống đa tác nhân Dev Signal
Ảnh bìa video: Tổng quan về hệ thống đa tác nhân Dev Signal

Bạn sẽ học được gì

Trong loạt bài blog bốn phần này, tôi sẽ dẫn dắt bạn qua từng bước của quá trình tôi biến dự án này thành hiện thực. Mỗi bài đăng blog sẽ ghi lại hành trình xây dựng và triển khai Dev Signal:

  • Phần 1: Công cụ xây dựng khả năng tác nhân – Bạn sẽ bắt đầu bằng cách thiết lập môi trường dự án và trang bị cho tác nhân của mình các công cụ sử dụng Giao thức Ngữ cảnh Mô hình (MCP). Bạn sẽ học cách kết nối với Reddit để khám phá xu hướng, tài liệu Google Cloud để xác thực thông tin kỹ thuật, và một công cụ Nano Banana Pro tùy chỉnh để tạo ảnh.
  • Phần 2: Kiến trúc đa tác nhân với bộ nhớ dài hạn – Bạn sẽ xây dựng "bộ não" của hệ thống bằng cách triển khai một bộ điều phối gốc và một nhóm các tác nhân chuyên biệt. Bạn cũng sẽ tích hợp ngân hàng bộ nhớ Vertex AI, cho phép tác nhân học hỏi và duy trì các tùy chọn của bạn qua các phiên làm việc.
  • Phần 3: Thử nghiệm tác nhân cục bộ – Trước khi chuyển lên đám mây, bạn sẽ đồng bộ hóa các thành phần của tác nhân và xác minh hiệu suất của nó trên máy trạm của mình. Bạn sẽ sử dụng một trình chạy thử nghiệm chuyên dụng để mô phỏng toàn bộ vòng đời của việc khám phá, nghiên cứu và tạo nội dung đa phương tiện, với trọng tâm đặc biệt là xác thực tính bền vững của bộ nhớ dài hạn bằng cách kết nối tác nhân cục bộ của bạn trực tiếp với ngân hàng bộ nhớ Vertex AI trên đám mây.
  • Phần 4: Triển khai lên Cloud Run và con đường tới sản xuất – Cuối cùng, bạn sẽ triển khai dịch vụ của mình trên Google Cloud Run bằng Terraform để có cơ sở hạ tầng tái tạo. Bạn cũng sẽ thảo luận về các bước tiếp theo cần thiết cho một hệ thống sản xuất an toàn, chất lượng cao.

Bắt đầu với Dev Signal

Dev Signal là một tác nhân giám sát thông minh được thiết kế để lọc nhiễu và tạo ra giá trị. Dev Signal hoạt động theo các cách sau:

  1. Khám phá: Tìm kiếm trên Reddit các câu hỏi kỹ thuật có tương tác cao.
  2. Xác thực: Nghiên cứu câu trả lời bằng tài liệu chính thức của Google Cloud để đảm bảo độ chính xác.
  3. Sáng tạo: Soạn thảo các bài đăng blog kỹ thuật chuyên nghiệp dựa trên những phát hiện của nó.
  4. Tạo nội dung đa phương tiện: Tạo tiêu đề đồ họa thông tin tùy chỉnh cho các bài đăng đó.
  5. Bộ nhớ dài hạn: Sử dụng ngân hàng bộ nhớ Vertex AI để ghi nhớ phản hồi của bạn qua các phiên làm việc khác nhau.

Điều kiện tiên quyết

Trước khi bắt đầu, hãy xác minh rằng các công cụ sau đã được cài đặt:

  • Python 3.12+
  • uv (trình quản lý gói Python):
    curl -LsSf https://astral.sh/uv/install.sh | sh
  • Google Cloud SDK (CLI `gcloud`) đã được cài đặt và xác thực.
  • Terraform (dành cho cơ sở hạ tầng dưới dạng mã).
  • Node.js & npm (bắt buộc cho công cụ Reddit MCP).

Bạn cũng sẽ cần:

  • Một Dự án Google Cloud đã bật tính năng thanh toán.
  • Các API đã được bật: Vertex AI, Cloud Run, Secret Manager, Artifact Registry.
  • Thông tin xác thực API Reddit (Client ID, Secret) – Bạn có thể lấy từ Cổng thông tin nhà phát triển Reddit.
  • Khóa API kiến thức nhà phát triển (để tìm kiếm tài liệu Google Cloud) – Hướng dẫn lấy khóa có tại đây.

Thiết lập dự án

Hệ thống Dev Signal được xây dựng bằng cách chạy Gói khởi động tác nhân trước, tuân theo quy trình làm việc kiến trúc tự động được mô tả trong tập Agent Factory của Remigiusz Samborski và Vlad Kolesnikov. Nền tảng này cung cấp cấu trúc thư mục mô-đun của dự án, được sử dụng để phân tách các mối quan tâm giữa Logic tác nhân, Mã máy chủ, Tiện ích và Công cụ.

Gói khởi động là một điểm xuất phát mạnh mẽ vì nó tự động tạo ra cơ sở hạ tầng chuyên nghiệp, các quy trình CI/CD và công cụ quan sát trong vài giây. Điều này cho phép bạn tập trung hoàn toàn vào trí thông minh độc đáo của tác nhân, đồng thời đảm bảo nền tảng bên dưới vẫn an toàn và có thể mở rộng. Bằng cách xây dựng dựa trên mã nền tảng được tạo này với sự hỗ trợ AI từ Gemini CLI và Antigravity, quá trình phát triển được tăng tốc đáng kể.

Kiến trúc cấp cao của gói khởi động tác nhân:

Sơ đồ kiến trúc cấp cao của gói khởi động tác nhân

1. Khởi tạo dự án

Tạo một thư mục mới cho dự án của bạn và khởi tạo nó. Chúng tôi sẽ sử dụng `uv`, một trình quản lý gói Python cực kỳ nhanh.

uv init dev-signal

2. Cấu trúc thư mục

Dự án của chúng ta sẽ tuân theo cấu trúc này. Chúng ta sẽ điền các tệp này từng bước một.

dev-signal/
├── dev_signal_agent/
│   ├── __init__.py
│   ├── agent.py           # Logic & điều phối tác nhân
│   ├── fast_api_app.py    # Máy chủ ứng dụng & kết nối bộ nhớ
│   ├── app_utils/         # Cấu hình môi trường
│   │   └── env.py
│   └── tools/             # Khả năng bên ngoài
│       ├── __init__.py
│       ├── mcp_config.py  # Cấu hình công cụ (Reddit, Docs)
│       └── nano_banana_mcp/# Công cụ tạo ảnh cục bộ tùy chỉnh
│           ├── __init__.py
│           ├── main.py
│           ├── nano_banana_pro.py
│           ├── media_models.py
│           ├── storage_utils.py
│           └── requirements.txt
├── deployment/
│   └── terraform/         # Cơ sở hạ tầng dưới dạng mã
├── .env                   # Bí mật cục bộ (khóa API)
├── Makefile               # Phím tắt để xây dựng/triển khai
├── Dockerfile             # Định nghĩa container
└── pyproject.toml         # Các phụ thuộc

3. Định nghĩa các phụ thuộc

Cập nhật tệp `pyproject.toml` của bạn với các phụ thuộc cần thiết. Chúng tôi sử dụng `google-adk` cho framework tác nhân và `google-genai` cho tương tác mô hình.

[project]
name = "dev-signal"
version = "0.1.0"
description = "A multi-agent system for monitoring and content creation."
readme = "README.md"
requires-python = ">=3.12, <3>=0.1.0",
     "google-genai>=1.0.0",
     "mcp>=1.0.0",
     "python-dotenv>=1.0.0",
     "fastapi>=0.110.0",
     "uvicorn>=0.29.0",
     "google-cloud-logging>=3.0.0",
     "google-cloud-aiplatform>=1.38.0",
     "fastmcp>=2.13.0",
     "google-cloud-storage>=3.6.0",
     "google-auth>=2.0.0",
     "google-cloud-secret-manager>=2.26.0",
]

Chạy `uv sync` để cài đặt tất cả. Tạo một thư mục mới cho mã tác nhân.

mkdir dev_signal_agent
cd dev_signal_agent

Xây dựng khả năng tác nhân: công cụ MCP

Tác nhân của chúng ta cần tương tác với thế giới bên ngoài. Chúng tôi sử dụng Giao thức Ngữ cảnh Mô hình (MCP) để chuẩn hóa điều này. MCP là một tiêu chuẩn phổ quát để kết nối các tác nhân AI với dữ liệu và công cụ bên ngoài. Thay vì viết các trình bao bọc API tùy chỉnh, chúng tôi sử dụng các máy chủ MCP tiêu chuẩn. Điều này cho phép chúng tôi kết nối với các API (Reddit), Cơ sở kiến thức (Google Cloud Docs), và thậm chí cả các script cục bộ (Tạo ảnh bằng Nano Banana Pro) thông qua một giao diện chung. Tạo một thư mục mới cho các công cụ tác nhân.

mkdir tools
cd tools

Cấu hình công cụ

Chúng ta sẽ định nghĩa bộ công cụ của mình trong `dev_signal_agent/tools/mcp_config.py`.

Tệp này định nghĩa các tham số kết nối cho ba công cụ chính của chúng ta.

  • Reddit: Kết nối thông qua một tiến trình con stdio cục bộ.
  • Kiến thức Nhà phát triển: Kết nối thông qua một điểm cuối HTTP từ xa.
  • Nano Banana: Kết nối thông qua một tiến trình con stdio cục bộ (script Python tùy chỉnh của chúng ta).

Tìm kiếm Reddit (Công cụ khám phá)

Máy chủ Reddit MCP đóng vai trò là cầu nối với API Reddit, cho phép tác nhân của bạn khám phá các bài đăng thịnh hành và phân tích mức độ tương tác mà không cần phải viết các trình bao bọc API phức tạp. Để đảm bảo tính di động, mã sử dụng chiến lược "tìm hoặc lấy": nó kiểm tra xem có cài đặt cục bộ hay không, và nếu không có, sẽ tự động sử dụng `npx` để tải xuống và chạy máy chủ theo yêu cầu.

Thay vì kết nối mạng, tác nhân khởi chạy máy chủ dưới dạng một tiến trình con cục bộ và giao tiếp qua luồng nhập và xuất chuẩn (stdio). Trong Google ADK, lớp `McpToolset` hoạt động như một trình bao bọc phổ quát chuẩn hóa các kết nối này, cho phép tác nhân của bạn tương tác với nhiều công cụ khác nhau, từ tài nguyên cộng đồng đến các script tùy chỉnh như trình tạo ảnh Nano Banana, sử dụng một giao diện chung. Bằng cách truyền thông tin xác thực API một cách an toàn thông qua các biến môi trường, hệ thống đảm bảo các mô-đun "plug-and-play" này hoạt động như một cầu nối liền mạch giữa AI và các nền tảng bên ngoài.

Dán mã này vào `dev_signal_agent/tools/mcp_config.py`:

import os
import shutil
from mcp import StdioServerParameters
from google.adk.tools import McpToolset
from google.adk.tools.mcp_tool import StreamableHTTPConnectionParams, StdioConnectionParams

def get_reddit_mcp_toolset(client_id: str = "", client_secret: str = "", user_agent: str = ""):
    """
    Kết nối tới máy chủ Reddit MCP.
    Máy chủ này chạy dưới dạng tiến trình con cục bộ (stdio) và proxy các yêu cầu tới API Reddit.
    """
    # Kiểm tra xem 'reddit-mcp' đã được cài đặt toàn cầu chưa, nếu không thì dùng npx để chạy
    cmd = "reddit-mcp" if shutil.which("reddit-mcp") else "npx"
    args = [] if shutil.which("reddit-mcp") else ["-y", "--quiet", "reddit-mcp"]
    
    # Tiêm bí mật vào môi trường của riêng tiến trình con
    env = {
        **os.environ, 
        "DOTENV_CONFIG_SILENT": "true", 
        "LANG": "en_US.UTF-8"
    }

    if client_id: env["REDDIT_CLIENT_ID"] = client_id
    if client_secret: env["REDDIT_CLIENT_SECRET"] = client_secret
    if user_agent: env["REDDIT_USER_AGENT"] = user_agent

    return McpToolset(
        connection_params=StdioConnectionParams(
            server_params=StdioServerParameters(
                command=cmd, 
                args=args, 
                env=env # Truyền bí mật đã tiêm trực tiếp tới tiến trình con
            ),
            timeout=120.0
        )
    )

Tài liệu Google Cloud (Công cụ kiến thức)

Máy chủ Developer Knowledge MCP cung cấp nền tảng vững chắc cho tác nhân của bạn bằng cách cho phép nó tìm kiếm toàn bộ kho tài liệu chính thức của Google Cloud. Không giống như máy chủ Reddit cục bộ, đây là một dịch vụ được quản lý bởi Google và được truy cập dưới dạng một điểm cuối từ xa qua internet. Nó cung cấp các công cụ chuyên biệt như `google_developer_documentation_search` cho các truy vấn ngữ nghĩa và `google_developer_documentation_fetch` để truy xuất toàn bộ nội dung markdown, đảm bảo rằng mọi tuyên bố kỹ thuật mà tác nhân đưa ra đều được hỗ trợ bởi các dữ kiện chính xác, cập nhật.

Lưu ý: Bạn cũng có thể kết nối các công cụ trợ lý lập trình của mình như Gemini CLI hoặc Antigravity với máy chủ kiến thức nhà phát triển MCP để trang bị cho chúng tài liệu Google Cloud hữu ích, cập nhật. Tôi đã sử dụng nó khi viết bài blog này!

Để kết nối, tác nhân sử dụng lớp `McpToolset` với `StreamableHTTPConnectionParams`, trỏ đến một URL web thay vì khởi chạy một tiến trình cục bộ. Nó xác thực an toàn bằng cách sử dụng `DK_API_KEY` (khóa API của bạn) được truyền trong tiêu đề yêu cầu, cho phép tác nhân thực hiện "quét nghiên cứu toàn diện" trên các tài liệu chính thức, ý kiến cộng đồng và ngữ cảnh web rộng hơn thông qua một giao diện chuẩn hóa duy nhất.

Dán mã này vào `dev_signal_agent/tools/mcp_config.py`:

def get_dk_mcp_toolset(api_key: str = ""):
    """
    Kết nối tới Kiến thức Nhà phát triển (Google Cloud Docs).
    Đây là máy chủ MCP từ xa được truy cập qua HTTP.
    """
    headers = {}
    if api_key:
        headers["X-Goog-Api-Key"] = api_key
    else:
        # Dự phòng về os.environ để kiểm thử cục bộ nếu không được truyền qua API
        headers["X-Goog-Api-Key"] = os.getenv("DK_API_KEY", "")

    return McpToolset(
        connection_params=StreamableHTTPConnectionParams(
            url="https://developerknowledge.googleapis.com/mcp",
            headers=headers
        )
    )

Trình tạo ảnh (Nano Banana MCP)

Mặc dù chúng ta đã sử dụng các máy chủ MCP bên ngoài cho Reddit và tài liệu, chúng ta cũng có thể xây dựng máy chủ MCP tùy chỉnh của riêng mình để gói logic Python cụ thể. Trong trường hợp này, chúng tôi đang tạo một công cụ tạo ảnh được cung cấp bởi Gemini 3 Pro Image (còn gọi là Nano Banana Pro). Điều này chứng minh rằng bất kỳ hàm Python nào cũng có thể được chuẩn hóa thành một công cụ mà bất kỳ tác nhân nào cũng có thể hiểu được.

Cách tạo ảnh hoạt động:

  • FastMCP: Chúng tôi sử dụng thư viện `fastmcp` để đơn giản hóa đáng kể việc tạo máy chủ, cho phép chúng tôi đăng ký các hàm Python làm công cụ chỉ với vài dòng mã.
  • Tích hợp Gemini: Máy chủ sử dụng Google GenAI SDK để gọi mô hình `gemini-3-pro-image-preview`, chuyển đổi các gợi ý mô tả của tác nhân thành dữ liệu ảnh thô.
  • Tải lên & Lưu trữ trên GCS: Vì giao diện tác nhân thường yêu cầu URL để hiển thị ảnh, máy chủ tự động tải các byte đã tạo lên Google Cloud Storage (GCS) và trả về một liên kết công khai.

Để kết nối công cụ cục bộ này, chúng tôi sử dụng `StdioConnectionParams` vì máy chủ chạy dưới dạng một tiến trình con cục bộ giao tiếp qua luồng nhập và xuất chuẩn. Phương thức truyền tải này khớp trực tiếp với cấu hình `transport="stdio"` mà chúng ta sẽ định nghĩa trong điểm vào máy chủ của mình, đảm bảo kết nối liền mạch cho các script cục bộ tùy chỉnh của bạn.

Mã sau đây định nghĩa kết nối MCP trong `dev_signal_agent/tools/mcp_config.py`. Chúng tôi sử dụng `uv run` để đảm bảo máy chủ khởi động trong một môi trường cách ly với tất cả các phụ thuộc được cài đặt chính xác.

Dán mã này vào `dev_signal_agent/tools/mcp_config.py`:

def get_nano_banana_mcp_toolset():
    """
    Kết nối tới trình tạo ảnh 'Nano Banana' cục bộ của chúng ta.
    Điều này minh họa cách gói một script Python cục bộ làm công cụ MCP.
    """
    path = os.path.join("dev_signal_agent", "tools", "nano_banana_mcp", "main.py")
    bucket = os.getenv("AI_ASSETS_BUCKET")     
    return McpToolset(
        connection_params=StdioConnectionParams(
            server_params=StdioServerParameters(
                command="uv", 
                args=["run", path], 
                env={**os.environ, "AI_ASSETS_BUCKET": bucket}
            ),
            timeout=600.0 # Tạo ảnh có thể mất thời gian
        )
    )

Triển khai logic máy chủ Nano Banana Pro

Bây giờ, chúng ta sẽ triển khai logic thực tế cho máy chủ này. Việc triển khai này dựa trên mã demo Agent Factory của Remigiusz Samborski. Mặc dù mã gốc của Remi cung cấp hướng dẫn triển khai máy chủ MCP lên Cloud Run, chúng ta sẽ chạy nó ở đây dưới dạng một tiến trình con cục bộ để phát triển và thử nghiệm nhanh hơn.

Để bắt đầu, hãy tạo thư mục cho máy chủ mới của chúng ta:

mkdir -p dev_signal_agent/tools/nano_banana_mcp
cd dev_signal_agent/tools/nano_banana_mcp

Điểm vào máy chủ (`main.py`)

Tệp này đóng vai trò là "bộ não" khởi tạo và khởi động máy chủ MCP.

  • Khởi tạo FastMCP: Chúng tôi sử dụng thư viện `FastMCP` để tạo một máy chủ có tên "MediaGenerators" và đăng ký hàm `generate_image` của chúng tôi làm công cụ.
  • Ghi nhật ký an toàn: Hàm `_initialize_console_logging` rất quan trọng. Nó buộc tất cả nhật ký phải chuyển đến `sys.stderr`. Điều này là do giao thức "stdio" của MCP sử dụng `sys.stdout` để giao tiếp giữa tác nhân và công cụ; các nhật ký tiêu chuẩn gửi đến `stdout` sẽ làm hỏng giao thức đó.
  • Thực thi: Dòng `mcp.run(transport="stdio")` khởi động máy chủ dưới dạng một tiến trình con cục bộ, cho phép nó lắng nghe các yêu cầu từ tác nhân của bạn qua đầu vào chuẩn.

Dán mã này vào `dev_signal_agent/tools/nano_banana_mcp/main.py`

import logging
import os
import sys
from fastmcp import FastMCP
from dotenv import load_dotenv
from nano_banana_pro import generate_image

def _initialize_console_logging(min_level: int = logging.INFO):
    # Đảm bảo nhật ký đi tới STDERR để chúng không làm hỏng giao thức stdio của MCP
    handler = logging.StreamHandler(sys.stderr)
    logging.basicConfig(level=min_level, handlers=[handler], force=True)

tools = [generate_image]
mcp = FastMCP(name="MediaGenerators", tools=tools)

if __name__ == "__main__":
    load_dotenv()
    _initialize_console_logging()
    mcp.run(transport="stdio")

Logic tạo sinh (`nano_banana_pro.py`)

Đây là nơi quá trình tạo ảnh thực tế diễn ra bằng Gemini.

  • GenAI Client: Chúng tôi khởi tạo `genai.Client()` để tương tác với các mô hình tạo sinh của Google.
  • Chọn mô hình: Nó nhắm mục tiêu cụ thể đến mô hình `gemini-3-pro-image-preview`. Chúng tôi đặt `response_modalities` thành "IMAGE" để cho mô hình biết chúng tôi muốn hình ảnh, không chỉ văn bản.
  • Tính mạnh mẽ: Mã bao gồm một vòng lặp `MAX_RETRIES` (đặt là 5) để xử lý mọi lỗi tạo sinh tạm thời, đảm bảo tác nhân có nhiều lần thử để lấy một hình ảnh hợp lệ.
  • Xử lý byte: Khi mô hình tạo ra hình ảnh, nó sẽ ở dạng dữ liệu nội tuyến thô. Chúng tôi trích xuất các byte này và gọi hàm trợ giúp để chuyển chúng lên đám mây.
  • Chuyển đổi URI: Cuối cùng, nó thay thế đường dẫn nội bộ `gs://` bằng một URL `https://` có thể truy cập bằng trình duyệt để người dùng có thể thực sự xem hình ảnh.

Dán mã này vào `dev_signal_agent/tools/nano_banana_mcp/nano_banana_pro.py`

import logging
from typing import Literal, Optional
from google import genai
from google.genai import types
from media_models import MediaAsset
from storage_utils import upload_data_to_gcs

AUTHORIZED_URI = "https://storage.mtls.cloud.google.com/"
MAX_RETRIES = 5

async def generate_image(
    prompt: str,
    aspect_ratio: Literal["16:9", "9:16"] = "16:9",
) -> MediaAsset:
    """Tạo một hình ảnh bằng mô hình Gemini 3 Image."""
    genai_client = genai.Client()
    content = types.Content(parts=[types.Part.from_text(text=prompt)], role="user")
    
    logging.info(f"Đang bắt đầu tạo ảnh cho lời nhắc: {prompt[:50]}...")
    asset = MediaAsset(uri="")
    
    for _ in range(MAX_RETRIES):
        response = genai_client.models.generate_content(
            model="gemini-3-pro-image-preview",
            contents=[content],
            config=types.GenerateContentConfig(
                response_modalities=["IMAGE"],
                image_config=types.ImageConfig(aspect_ratio=aspect_ratio)
            )
        )
        if response and response.parts:
            for part in response.parts:
                if part.inline_data and part.inline_data.data:
                    # Tải lên các byte thô lên GCS
                    gcs_uri = await upload_data_to_gcs(
                        "mcp-tools",
                        part.inline_data.data,
                        part.inline_data.mime_type
                    )
                    asset = MediaAsset(uri=gcs_uri)
                    break
        if asset.uri: break

    if not asset.uri:
        asset.error = "Không có hình ảnh nào được tạo."
    else:
        # Chuyển đổi URI gs:// thành URL truy cập được bằng HTTP nếu cần
        asset.uri = asset.uri.replace('gs://', AUTHORIZED_URI)
        logging.info(f"URL hình ảnh: {asset.uri}")
        
    return asset

Trợ giúp tải lên GCS (`storage_utils.py`)

Vì các tác nhân cần một liên kết web để hiển thị hình ảnh, tiện ích này xử lý việc lưu trữ trên Google Cloud Storage (GCS).

  • Chọn bucket động: Nó tìm kiếm tên bucket trong các biến môi trường của bạn, ưu tiên `AI_ASSETS_BUCKET` trước `LOGS_BUCKET_NAME` để đảm bảo luôn có nơi để lưu dữ liệu.
  • Tên tệp duy nhất: Chúng tôi sử dụng hàm băm MD5 của dữ liệu hình ảnh thô để tạo một tên tệp duy nhất. Điều này ngăn chặn xung đột tên tệp và là một cách đơn giản để tránh tải lên các hình ảnh trùng lặp.
  • Tải lên đám mây: Phương thức `blob.upload_from_string` đẩy các byte hình ảnh thô trực tiếp vào bucket GCS của bạn.

Dán mã này vào `dev_signal_agent/tools/nano_banana_mcp/storage_utils.py`

import hashlib
import mimetypes
import os
from google.cloud.storage import Client, Blob
from dotenv import load_dotenv

load_dotenv()
storage_client = Client()
ai_bucket_name = os.environ.get("AI_ASSETS_BUCKET") or os.environ.get("LOGS_BUCKET_NAME")
ai_bucket = storage_client.bucket(ai_bucket_name)

async def upload_data_to_gcs(agent_id: str, data: bytes, mime_type: str) -> str:
    file_name = hashlib.md5(data).hexdigest()
    ext = mimetypes.guess_extension(mime_type) or ""
    blob_name = f"assets/{agent_id}/{file_name}{ext}"
    blob = Blob(bucket=ai_bucket, name=blob_name)
    blob.upload_from_string(data, content_type=mime_type, client=storage_client)
    return f"gs://{ai_bucket_name}/{blob_name}"

Mô hình dữ liệu (`media_models.py`)

Tệp này đảm bảo rằng dữ liệu của chúng ta tuân theo một cấu trúc nghiêm ngặt (Schema).

  • Đầu ra có cấu trúc: Bằng cách sử dụng `BaseModel` của Pydantic, chúng tôi đảm bảo rằng công cụ luôn trả về một đối tượng JSON nhất quán chứa một `uri` (liên kết) và một thông báo lỗi tùy chọn. Điều này giúp tác nhân AI dễ dàng hiểu và xử lý kết quả của công cụ hơn rất nhiều.

Dán mã này vào `dev_signal_agent/tools/nano_banana_mcp/media_models.py`

from typing import Optional
from pydantic import BaseModel

class MediaAsset(BaseModel):
    uri: str
    error: Optional[str] = None

Các phụ thuộc của công cụ (`requirements.txt`)

Mặc dù chúng ta sử dụng `uv` để chạy mã của mình, một tệp `requirements.txt` vẫn rất cần thiết vì nó định nghĩa các phụ thuộc cụ thể mà `uv` cần cài đặt để máy chủ Nano Banana hoạt động. Điều này cung cấp "nguyên liệu" cần thiết để thiết lập môi trường biệt lập trước khi máy chủ khởi động.

Tệp này liệt kê ba thư viện cốt lõi cần thiết cho công cụ này:

  • google-cloud-storage: Được sử dụng để lưu trữ các hình ảnh được tạo trên đám mây.
  • google-genai: Cung cấp logic cho việc tạo ảnh Gemini 3 Pro.
  • fastmcp: Framework biến script Python của chúng ta thành một công cụ MCP tiêu chuẩn hóa.

Dán mã này vào `dev_signal_agent/tools/nano_banana_mcp/requirements.txt`

google-cloud-storage==3.6.*
google-genai==1.52.*
fastmcp==2.13.*

Tóm tắt

Trong phần đầu tiên của loạt bài này, chúng ta đã tập trung vào việc thiết lập các khả năng cốt lõi của tác nhân bằng cách chuẩn hóa các tích hợp bên ngoài của nó thông qua Giao thức Ngữ cảnh Mô hình (MCP). Chúng ta đã khởi tạo dự án bằng `uv` để quản lý phụ thuộc tốc độ cao và cấu hình thành công ba bộ công cụ quan trọng: Reddit để khám phá xu hướng, Google Cloud Docs để xác thực thông tin kỹ thuật, và một máy chủ MCP "Nano Banana" tùy chỉnh để tạo ảnh đa phương tiện. Bằng cách tận dụng `McpToolset` của Google ADK, chúng ta đã trừu tượng hóa logic API phức tạp thành các mô-đun đơn giản, cắm-và-chạy, đảm bảo rằng các công cụ của chúng ta chia sẻ một giao diện chung, tách rời tích hợp khỏi trí thông minh.

Để tìm hiểu sâu hơn về nền tảng kỹ thuật của chúng ta, bạn có thể khám phá máy chủ Developer Knowledge MCP để tìm hiểu thêm về việc xác thực kiến thức hoặc truy cập kho lưu trữ GitHub của Google ADK để khám phá các khả năng cốt lõi của framework.

Với bộ công cụ của chúng ta đã được cấu hình đầy đủ và sẵn sàng hoạt động, giờ đây chúng ta có thể chuyển sang Phần 2, nơi chúng ta sẽ xây dựng kiến trúc đa tác nhân và tích hợp ngân hàng bộ nhớ Vertex AI để điều phối các khả năng này. Nếu bạn muốn đi trước, bạn có thể khám phá toàn bộ mã nguồn cho toàn bộ loạt bài trong kho lưu trữ GitHub của chúng ta.

Xin gửi lời cảm ơn đặc biệt đến Remigiusz Samborski vì những đánh giá và phản hồi hữu ích về bài viết này. Để có thêm nội dung như thế này, hãy theo dõi tôi trên Linkedin và X.

MagicFlow | TechData.AI

Scroll to Top