1. Kiến thức bạn sẽ học được
Chào mừng bạn! Hôm nay, chúng ta sẽ bắt đầu một hành trình khá thú vị. Hãy bắt đầu bằng cách nghĩ về một nền tảng sự kiện xã hội phổ biến là InstaVibe. Mặc dù tính năng này đã thành công, nhưng chúng tôi biết rằng đối với một số người dùng, việc lập kế hoạch thực tế cho các hoạt động nhóm có thể khiến họ cảm thấy mệt mỏi. Hãy tưởng tượng bạn đang cố gắng tìm hiểu xem tất cả bạn bè của mình quan tâm đến điều gì, sau đó sàng lọc vô số lựa chọn về sự kiện hoặc địa điểm và cuối cùng là điều phối mọi thứ. Nhiều lắm! Đây chính là lúc chúng ta có thể giới thiệu AI, cụ thể hơn là các tác nhân thông minh, để tạo ra sự khác biệt thực sự.
Ý tưởng là xây dựng một hệ thống mà các tác nhân này có thể xử lý những việc nặng nhọc, chẳng hạn như "lắng nghe" một cách thông minh để hiểu được sở thích của người dùng và bạn bè, sau đó chủ động đề xuất các hoạt động tuyệt vời, phù hợp. Mục tiêu của chúng tôi là biến việc lên kế hoạch giao lưu trên InstaVibe thành một trải nghiệm liền mạch và thú vị. Để bắt đầu xây dựng những trợ lý thông minh này, chúng ta cần đặt nền tảng vững chắc bằng các công cụ phù hợp.
Sau đây là khái niệm mà bạn sẽ thấy:
Kiến thức cơ bản về ADK của Google: Nắm vững kiến thức cơ bản về cách tạo tác nhân thông minh đầu tiên bằng Bộ công cụ phát triển tác nhân (ADK) của Google. Nắm được các thành phần thiết yếu, vòng đời của tác nhân và cách tận dụng hiệu quả các công cụ tích hợp của khung.
Mở rộng khả năng của tác nhân bằng Giao thức ngữ cảnh mô hình (MCP): Tìm hiểu cách trang bị cho tác nhân của bạn các công cụ và ngữ cảnh tuỳ chỉnh, cho phép tác nhân thực hiện các tác vụ chuyên biệt và truy cập vào thông tin cụ thể. Giới thiệu khái niệm Giao thức ngữ cảnh mô hình (MCP). Bạn sẽ tìm hiểu cách thiết lập một máy chủ MCP để cung cấp bối cảnh này.
Thiết kế hoạt động tương tác và điều phối của nhân viên hỗ trợ: Chuyển từ nhân viên hỗ trợ đơn lẻ sang hiểu rõ hoạt động điều phối của nhân viên hỗ trợ. Thiết kế các mẫu tương tác, từ quy trình làm việc tuần tự đơn giản đến các tình huống phức tạp liên quan đến vòng lặp, logic có điều kiện và xử lý song song. Giới thiệu khái niệm về các tác nhân phụ trong khung ADK để quản lý các tác vụ theo mô-đun.
Xây dựng hệ thống đa tác nhân cộng tác: Khám phá cách thiết kế hệ thống nơi nhiều tác nhân cộng tác để đạt được các mục tiêu phức tạp. Tìm hiểu và triển khai giao thức giao tiếp Tác nhân với tác nhân (A2A), thiết lập một cách thức tiêu chuẩn để các tác nhân phân tán (có thể chạy trên các máy hoặc dịch vụ khác nhau) tương tác một cách đáng tin cậy.
Đưa các tác nhân vào sản xuất trên Google Cloud: Chuyển các ứng dụng tác nhân từ môi trường phát triển sang đám mây. Tìm hiểu các phương pháp hay nhất để thiết kế và triển khai các hệ thống có khả năng mở rộng, mạnh mẽ gồm nhiều tác nhân trên Google Cloud Platform (GCP). Tìm hiểu thông tin chi tiết về cách tận dụng các dịch vụ của GCP như Cloud Run và khám phá các chức năng của Google Agent Engine mới nhất để lưu trữ và quản lý các tác nhân của bạn.
2. Kiến trúc
Lập kế hoạch nội dung trên mạng xã hội dựa trên AI bằng InstaVibe
Lắng nghe cộng đồng mạng xã hội là gì?
Lắng nghe trên mạng xã hội là quá trình theo dõi các cuộc trò chuyện trên các nền tảng kỹ thuật số như mạng xã hội, diễn đàn và trang tin tức để hiểu mọi người đang nói gì về một chủ đề, thương hiệu hoặc ngành. Công cụ này cung cấp thông tin chi tiết có giá trị về tình cảm của công chúng, các xu hướng và nhu cầu của người dùng. Trong hội thảo này, chúng ta sẽ tận dụng khái niệm này trong một hệ thống dựa trên tác nhân.
Bạn đang ở trong Nhóm tại InstaVibe
Hãy tưởng tượng bạn làm việc tại "InstaVibe", một công ty khởi nghiệp thành công với nền tảng sự kiện xã hội phổ biến nhắm đến người trẻ. Mọi thứ đang diễn ra tốt đẹp, nhưng giống như nhiều công ty công nghệ khác, nhóm của bạn chịu áp lực từ các nhà đầu tư trong việc đổi mới bằng AI. Trong nội bộ, bạn cũng nhận thấy một nhóm người dùng không tương tác nhiều như những người khác – có thể họ ít muốn bắt đầu các hoạt động nhóm hoặc cảm thấy khó khăn trong quá trình lập kế hoạch. Đối với công ty của bạn, điều này có nghĩa là mức độ gắn bó với nền tảng thấp hơn trong nhóm người dùng quan trọng này.
Nghiên cứu của nhóm bạn cho thấy rằng sự hỗ trợ dựa trên AI có thể cải thiện đáng kể trải nghiệm cho những người dùng này. Ý tưởng này là để đơn giản hoá quy trình lên kế hoạch cho các buổi tụ tập bằng cách chủ động đề xuất các hoạt động phù hợp dựa trên mối quan tâm của người dùng và bạn bè của họ. Câu hỏi mà bạn và đồng nghiệp phải đối mặt là: Làm cách nào để các tác nhân AI có thể tự động hoá những nhiệm vụ thường tốn nhiều thời gian như khám phá mối quan tâm, nghiên cứu hoạt động và có thể là phối hợp ban đầu?
Giải pháp dựa trên tác nhân (Khái niệm nguyên mẫu)
Bạn đề xuất phát triển một tính năng nguyên mẫu dựa trên hệ thống đa tác nhân. Sau đây là thông tin chi tiết về khái niệm này:
- Tác nhân lập hồ sơ xã hội: Tác nhân này sử dụng các kỹ thuật lắng nghe trên mạng xã hội để phân tích các mối quan hệ, lượt tương tác của người dùng và có thể là các xu hướng rộng rãi hơn trong cộng đồng liên quan đến lựa chọn ưu tiên của người dùng. Mục đích của tính năng này là xác định những điểm chung và đặc điểm phù hợp của hoạt động (ví dụ: thích những buổi tụ tập yên tĩnh hơn, có sở thích cụ thể).
- Đại lý lập kế hoạch sự kiện: Dựa vào thông tin chi tiết từ Đại lý lập hồ sơ xã hội, đại lý này tìm kiếm các nguồn tài nguyên trực tuyến về những sự kiện, địa điểm hoặc ý tưởng cụ thể phù hợp với tiêu chí đã xác định (chẳng hạn như vị trí, sở thích).
- Tác nhân tương tác với nền tảng (sử dụng MCP): Tác nhân này lấy kế hoạch cuối cùng từ Tác nhân lập kế hoạch hoạt động. Chức năng chính của công cụ này là tương tác trực tiếp với nền tảng InstaVibe bằng cách sử dụng một công cụ MCP (Giao thức bối cảnh mô hình) được xác định trước. Công cụ này cung cấp cho đặc vụ khả năng cụ thể để soạn thảo đề xuất về sự kiện và tạo một bài đăng nêu rõ kế hoạch.
- Orchestrator Agent: Tác nhân này đóng vai trò là điều phối viên trung tâm. Nó nhận được yêu cầu ban đầu của người dùng từ nền tảng InstaVibe, hiểu được mục tiêu tổng thể (ví dụ: "lên kế hoạch cho một sự kiện cho tôi và bạn bè"), sau đó uỷ quyền các nhiệm vụ cụ thể cho các đặc vụ chuyên trách phù hợp theo một trình tự hợp lý. Nó quản lý luồng thông tin giữa các tác nhân và đảm bảo kết quả cuối cùng được gửi lại cho người dùng.
Các công nghệ và thành phần kiến trúc chính
Google Cloud Platform (GCP):
- Vertex AI:
- Mô hình Gemini: Cung cấp quyền truy cập vào các Mô hình ngôn ngữ lớn (LLM) tiên tiến của Google như Gemini, giúp tăng cường khả năng lập luận và đưa ra quyết định của các trợ lý AI.
- Vertex AI Agent Engine: Một dịch vụ được quản lý dùng để triển khai, lưu trữ và mở rộng quy mô tác nhân điều phối của chúng tôi, giúp đơn giản hoá quá trình sản xuất và loại bỏ các điểm phức tạp về cơ sở hạ tầng.
- Cloud Run: Nền tảng không máy chủ để triển khai các ứng dụng nằm trong vùng chứa. Chúng tôi sử dụng thông tin này để:
- Lưu trữ ứng dụng web InstaVibe chính.
- Triển khai từng tác nhân có A2A (Planner, Social Profiling, Platform Interaction) dưới dạng các dịch vụ vi mô độc lập.
- Chạy Máy chủ công cụ MCP, giúp các tác nhân truy cập được vào các API nội bộ của InstaVibe.
- Spanner: Một cơ sở dữ liệu quan hệ được quản lý toàn bộ, phân phối trên toàn cầu và có tính nhất quán cao. Trong hội thảo này, chúng ta sẽ tận dụng các chức năng của cơ sở dữ liệu này dưới dạng Cơ sở dữ liệu đồ thị bằng cách sử dụng DDL đồ thị và các tính năng truy vấn để:
- Mô hình hoá và lưu trữ các mối quan hệ xã hội phức tạp (người dùng, tình bạn, sự tham dự sự kiện, bài đăng).
- Cho phép truy vấn hiệu quả các mối quan hệ này cho các tác nhân Lập hồ sơ xã hội.
- Artifact Registry: Một dịch vụ được quản lý toàn diện để lưu trữ, quản lý và bảo mật hình ảnh vùng chứa.
- Cloud Build: Một dịch vụ giúp chạy bản dựng trên Google Cloud. Chúng tôi sử dụng công cụ này để tự động tạo các hình ảnh vùng chứa Docker từ mã nguồn của ứng dụng và tác nhân.
- Cloud Storage: Được các dịch vụ như Cloud Build dùng để lưu trữ các cấu phần phần mềm và Agent Engine dùng cho nhu cầu hoạt động.
- Các giao thức và khung tác nhân cốt lõi:
- Agent Development Kit (ADK) của Google: Khung chính cho:
- Xác định logic, hành vi và bộ hướng dẫn cốt lõi cho từng tác nhân thông minh.
- Quản lý vòng đời, trạng thái và bộ nhớ của tác nhân (trạng thái phiên ngắn hạn và kiến thức dài hạn tiềm năng).
- Tích hợp các công cụ (chẳng hạn như Google Tìm kiếm hoặc các công cụ được xây dựng tuỳ chỉnh) mà các tác nhân có thể dùng để tương tác với thế giới.
- Điều phối quy trình công việc của nhiều tác nhân, bao gồm cả việc thực thi tuần tự, lặp lại và song song của các tác nhân phụ.
- Giao thức liên lạc giữa các tác nhân (A2A): Một tiêu chuẩn mở cho phép:
- Giao tiếp và cộng tác trực tiếp, theo tiêu chuẩn giữa các tác nhân AI khác nhau, ngay cả khi chúng đang chạy dưới dạng các dịch vụ riêng biệt hoặc trên các máy khác nhau.
- Các trợ lý ảo có thể khám phá khả năng của nhau (thông qua Thẻ trợ lý ảo) và uỷ quyền các tác vụ. Điều này rất quan trọng để tác nhân Orchestrator tương tác với các tác nhân Planner, Social và Platform chuyên biệt.
- Thư viện A2A Python (a2a-python): Thư viện cụ thể được dùng để giúp các tác nhân ADK của chúng tôi nói theo giao thức A2A. Thư viện này cung cấp các thành phần phía máy chủ cần thiết để:
- Công khai các tác nhân của chúng tôi dưới dạng máy chủ tuân thủ A2A.
- Tự động xử lý việc phân phát "Thẻ đại lý" để khám phá.
- Nhận và quản lý các yêu cầu về tác vụ đến từ các tác nhân khác (chẳng hạn như Orchestrator).
- Giao thức ngữ cảnh mô hình (MCP): Một tiêu chuẩn mở cho phép các tác nhân:
- Kết nối và sử dụng các công cụ, nguồn dữ liệu và hệ thống bên ngoài theo cách tiêu chuẩn.
- Platform Interaction Agent (Tác nhân tương tác với nền tảng) của chúng tôi sử dụng một ứng dụng MCP để giao tiếp với một máy chủ MCP. Máy chủ này sẽ cung cấp các công cụ để tương tác với các API hiện có của nền tảng InstaVibe.
- Agent Development Kit (ADK) của Google: Khung chính cho:
- Công cụ gỡ lỗi:
- A2A Inspector: A2A Inspector là một công cụ gỡ lỗi dựa trên web, được dùng trong suốt hội thảo này để kết nối, kiểm tra và tương tác với các tác nhân có hỗ trợ A2A. Mặc dù không phải là một phần của cấu trúc sản xuất cuối cùng, nhưng đây là một phần thiết yếu trong quy trình phát triển của chúng tôi. Thẻ này cung cấp:
- Agent Card Viewer: Để tìm nạp và xác thực các chức năng công khai của một đặc vụ.
- Giao diện trò chuyện trực tiếp: Để gửi tin nhắn trực tiếp đến một đặc vụ đã triển khai để kiểm thử ngay lập tức.
- Debug Console (Bảng điều khiển gỡ lỗi): Để xem các thông báo JSON-RPC thô được trao đổi giữa trình kiểm tra và tác nhân.
- A2A Inspector: A2A Inspector là một công cụ gỡ lỗi dựa trên web, được dùng trong suốt hội thảo này để kết nối, kiểm tra và tương tác với các tác nhân có hỗ trợ A2A. Mặc dù không phải là một phần của cấu trúc sản xuất cuối cùng, nhưng đây là một phần thiết yếu trong quy trình phát triển của chúng tôi. Thẻ này cung cấp:
- Mô hình ngôn ngữ (LLM): "Bộ não" của hệ thống:
- Các mô hình Gemini của Google: Cụ thể, chúng tôi sử dụng các phiên bản như gemini-2.0-flash. Những mẫu này được chọn cho:
- Khả năng suy luận và tuân thủ chỉ dẫn nâng cao: Khả năng hiểu các câu lệnh phức tạp, tuân thủ chỉ dẫn chi tiết và suy luận về các tác vụ khiến chúng phù hợp để hỗ trợ việc ra quyết định của tác nhân.
- Sử dụng công cụ (Gọi hàm): Các mô hình Gemini có khả năng xác định thời điểm và cách sử dụng các công cụ được cung cấp thông qua ADK, cho phép các tác nhân thu thập thông tin hoặc thực hiện hành động.
- Hiệu quả (Mô hình Flash): Các biến thể "flash" mang lại sự cân bằng tốt giữa hiệu suất và hiệu quả chi phí, phù hợp với nhiều tác vụ của tác nhân tương tác đòi hỏi phản hồi nhanh.
- Các mô hình Gemini của Google: Cụ thể, chúng tôi sử dụng các phiên bản như gemini-2.0-flash. Những mẫu này được chọn cho:
Bạn cần tín dụng Google Cloud?
3. Trước khi bắt đầu
👉Nhấp vào Kích hoạt Cloud Shell ở đầu bảng điều khiển Google Cloud (Đây là biểu tượng có hình dạng thiết bị đầu cuối ở đầu ngăn Cloud Shell),
👉Nhấp vào nút "Mở Trình chỉnh sửa" (nút này trông giống như một thư mục đang mở có cây bút chì). Thao tác này sẽ mở Cloud Shell Code Editor trong cửa sổ. Bạn sẽ thấy một trình khám phá tệp ở bên trái.
👉Nhấp vào nút Đăng nhập bằng mã trên đám mây trong thanh trạng thái dưới cùng như minh hoạ. Uỷ quyền cho trình bổ trợ theo hướng dẫn. Nếu bạn thấy Cloud Code – no project (Cloud Code – không có dự án) trong thanh trạng thái, hãy chọn mục đó rồi chọn "Select a Google Cloud Project" (Chọn một dự án Google Cloud) trong trình đơn thả xuống, sau đó chọn dự án Google Cloud cụ thể trong danh sách các dự án mà bạn đã tạo.
👉 Tìm Mã dự án trên Google Cloud:
- Mở Google Cloud Console: https://console.cloud.google.com
- Chọn dự án bạn muốn sử dụng cho hội thảo này trong trình đơn thả xuống dự án ở đầu trang.
- Mã dự án của bạn sẽ xuất hiện trong thẻ Thông tin dự án trên Trang tổng quan
👉Mở cửa sổ dòng lệnh trong IDE trên đám mây,
👉💻 Trong thiết bị đầu cuối, hãy xác minh rằng bạn đã được xác thực và dự án được đặt thành mã dự án của bạn bằng lệnh sau:
gcloud auth list
👉💻 Sao chép dự án instavibe-bootstrap
trên GitHub:
git clone -b adk-1.2.1-a2a-0.2.7 https://github.com/weimeilin79/instavibe-bootstrap.git
chmod +x ~/instavibe-bootstrap/init.sh
chmod +x ~/instavibe-bootstrap/set_env.sh
Tìm hiểu cấu trúc dự án
Trước khi bắt đầu xây dựng, hãy dành chút thời gian để tìm hiểu bố cục của dự án instavibe-bootstrap
mà bạn vừa sao chép. Điều này sẽ giúp bạn biết nơi tìm và chỉnh sửa tệp trong suốt buổi hội thảo.
instavibe-bootstrap/
├── agents/
│ ├── orchestrate/
│ ├── planner/
│ ├── platform_mcp_client/
│ └── social/
├── instavibe/
│ ├── static/
│ └── templates/
├── tools/
│ └── instavibe/
├── utils/
├── init.sh
└── set_env.sh
Sau đây là thông tin chi tiết về các thư mục chính:
agents/
: Đây là cốt lõi của hệ thống AI của chúng tôi. Mỗi thư mục con (planner/, social/, v.v.) chứa mã nguồn cho một tác nhân thông minh cụ thể.agent.py
: Bên trong thư mục của mỗi tác nhân, đây là tệp chính chứa logic của tác nhân.a2a_server.py
: Tệp này bao bọc tác nhân ADK bằng một máy chủ Agent-to-Agent (A2A).Dockerfile
: Xác định cách tạo hình ảnh vùng chứa để triển khai tác nhân vào Cloud Run hoặc Agent Engine.
instavibe/
: Thư mục này chứa toàn bộ mã nguồn cho ứng dụng web InstaVibe.tools/
: Thư mục này dùng để tạo các công cụ bên ngoài mà nhân viên của chúng tôi có thể sử dụng.instavibe/
chứa Máy chủ Giao thức ngữ cảnh mô hình (MCP).
Cấu trúc mô-đun này tách ứng dụng web khỏi các thành phần AI, giúp toàn bộ hệ thống dễ quản lý, kiểm thử và triển khai hơn.
👉💻 Chạy tập lệnh khởi chạy:
Tập lệnh này sẽ nhắc bạn nhập Mã dự án trên Google Cloud.
Nhập Mã dự án trên Google Cloud mà bạn tìm được ở bước cuối cùng khi được tập lệnh init.sh
nhắc:
cd ~/instavibe-bootstrap
./init.sh
👉💻 Đặt mã dự án cần thiết:
gcloud config set project $(cat ~/project_id.txt) --quiet
👉💻 Chạy lệnh sau để bật các API cần thiết của Google Cloud:
gcloud services enable run.googleapis.com \
cloudfunctions.googleapis.com \
cloudbuild.googleapis.com \
artifactregistry.googleapis.com \
spanner.googleapis.com \
apikeys.googleapis.com \
iam.googleapis.com \
compute.googleapis.com \
aiplatform.googleapis.com \
cloudresourcemanager.googleapis.com \
maps-backend.googleapis.com
👉💻 Thiết lập tất cả các biến môi trường cần thiết:
export PROJECT_ID=$(gcloud config get project)
export PROJECT_NUMBER=$(gcloud projects describe ${PROJECT_ID} --format="value(projectNumber)")
export SERVICE_ACCOUNT_NAME=$(gcloud compute project-info describe --format="value(defaultServiceAccount)")
export SPANNER_INSTANCE_ID="instavibe-graph-instance"
export SPANNER_DATABASE_ID="graphdb"
export GOOGLE_CLOUD_PROJECT=$(gcloud config get project)
export GOOGLE_GENAI_USE_VERTEXAI=TRUE
export GOOGLE_CLOUD_LOCATION="us-central1"
Thiết lập quyền
👉💻 Cấp quyền. Trong thiết bị đầu cuối, hãy chạy :
gcloud projects add-iam-policy-binding $PROJECT_ID \
--member="serviceAccount:$SERVICE_ACCOUNT_NAME" \
--role="roles/spanner.admin"
# Spanner Database User
gcloud projects add-iam-policy-binding $PROJECT_ID \
--member="serviceAccount:$SERVICE_ACCOUNT_NAME" \
--role="roles/spanner.databaseUser"
# Artifact Registry Admin
gcloud projects add-iam-policy-binding $PROJECT_ID \
--member="serviceAccount:$SERVICE_ACCOUNT_NAME" \
--role="roles/artifactregistry.admin"
# Cloud Build Editor
gcloud projects add-iam-policy-binding $PROJECT_ID \
--member="serviceAccount:$SERVICE_ACCOUNT_NAME" \
--role="roles/cloudbuild.builds.editor"
# Cloud Run Admin
gcloud projects add-iam-policy-binding $PROJECT_ID \
--member="serviceAccount:$SERVICE_ACCOUNT_NAME" \
--role="roles/run.admin"
# IAM Service Account User
gcloud projects add-iam-policy-binding $PROJECT_ID \
--member="serviceAccount:$SERVICE_ACCOUNT_NAME" \
--role="roles/iam.serviceAccountUser"
# Vertex AI User
gcloud projects add-iam-policy-binding $PROJECT_ID \
--member="serviceAccount:$SERVICE_ACCOUNT_NAME" \
--role="roles/aiplatform.user"
# Logging Writer (to allow writing logs)
gcloud projects add-iam-policy-binding $PROJECT_ID \
--member="serviceAccount:$SERVICE_ACCOUNT_NAME" \
--role="roles/logging.logWriter"
gcloud projects add-iam-policy-binding $PROJECT_ID \
--member="serviceAccount:$SERVICE_ACCOUNT_NAME" \
--role="roles/logging.viewer"
👉 Xác thực kết quả trong bảng điều khiển IAM
👉💻 Chạy các lệnh sau trong dòng lệnh để tạo một kho lưu trữ Artifact Registry. Tất cả các hình ảnh Docker cho các tác nhân, máy chủ MCP và ứng dụng InstaVibe đều được lưu trữ ở đây trước khi triển khai vào Cloud Run hoặc Agent Engine.
export REPO_NAME="introveally-repo"
gcloud artifacts repositories create $REPO_NAME \
--repository-format=docker \
--location=us-central1 \
--description="Docker repository for InstaVibe workshop"
Thiết lập nền tảng Maps cho khoá API
Để sử dụng các dịch vụ của Google Maps trong ứng dụng InstaVibe, bạn cần tạo một khoá API và hạn chế khoá đó một cách thích hợp.
👉 Trong một thẻ mới, hãy chuyển đến API và Dịch vụ > Thông tin xác thực. Trên trang "Thông tin xác thực", hãy nhấp vào nút + TẠO THÔNG TIN XÁC THỰC ở trên cùng. Chọn khoá API trong trình đơn thả xuống.
👉 Một hộp thoại sẽ xuất hiện cho biết khoá API bạn vừa tạo. Sau này, bạn sẽ cần khoá này để định cấu hình ứng dụng.
👉 Nhấp vào ĐÓNG trên hộp thoại "Đã tạo khoá API".
👉 Bạn sẽ thấy khoá API mới trong danh sách (ví dụ: "API key 1"). Nhấp vào biểu tượng ba dấu chấm ở bên phải, chọn Chỉnh sửa khoá API để mở trang "Hạn chế và đổi tên khoá API".
👉 Trong trường Tên ở trên cùng, hãy thay đổi tên mặc định thành: Khoá API Nền tảng Maps (🚨🚨QUAN TRỌNG🚨🚨 Vui lòng sử dụng tên này!)
Maps Platform API Key
👉 Trong phần "Hạn chế ứng dụng", hãy đảm bảo bạn chọn Không có.
👉 Trong phần "API restrictions" (Hạn chế cho API), hãy chọn nút chọn Restrict key (Hạn chế cho khoá).
👉 Nhấp vào trình đơn thả xuống Chọn API. Trong hộp tìm kiếm xuất hiện, hãy nhập Maps JavaScript API
rồi chọn biểu tượng này trong danh sách.
👉 Nhấp vào OK.
👉 Nhấp vào nút LƯU ở cuối trang.
Giờ đây, bạn đã tạo thành công một khoá API có tên là "Maps Platform API Key", hạn chế khoá này chỉ cho phép sử dụng "Maps JavaScript API" và đảm bảo API được bật cho dự án của bạn.
4. Thiết lập cơ sở dữ liệu đồ thị
Trước khi có thể xây dựng các tác nhân thông minh, chúng ta cần một cách để lưu trữ và hiểu rõ các mối kết nối phong phú trong mạng xã hội InstaVibe. Đây là lúc Cơ sở dữ liệu đồ thị phát huy tác dụng. Không giống như cơ sở dữ liệu quan hệ truyền thống lưu trữ dữ liệu trong các bảng gồm hàng và cột, cơ sở dữ liệu đồ thị được thiết kế đặc biệt để biểu thị và truy vấn dữ liệu theo các nút (chẳng hạn như người dùng, sự kiện hoặc bài đăng) và mối quan hệ (cạnh) kết nối các nút đó (chẳng hạn như tình bạn, việc tham dự sự kiện hoặc lượt đề cập). Cấu trúc này cực kỳ hiệu quả đối với các ứng dụng mạng xã hội vì nó phản ánh cách các mạng xã hội trong thế giới thực được cấu trúc, giúp bạn dễ dàng khám phá cách các thực thể khác nhau được kết nối với nhau.
Chúng tôi đang triển khai cơ sở dữ liệu đồ thị này bằng Google Cloud Spanner. Mặc dù Spanner chủ yếu được biết đến là một cơ sở dữ liệu quan hệ nhất quán mạnh mẽ, được phân phối trên toàn cầu, nhưng nó cũng cho phép chúng tôi xác định và truy vấn trực tiếp các cấu trúc đồ thị trên các bảng quan hệ.
Điều này mang lại cho chúng tôi những lợi ích kết hợp của khả năng mở rộng, tính nhất quán giao dịch và giao diện SQL quen thuộc của Spanner, cùng với sức mạnh biểu đạt của các truy vấn đồ thị để phân tích động lực xã hội phức tạp, vốn rất quan trọng đối với các tính năng dựa trên AI của chúng tôi.
👉💻 Trong thiết bị đầu cuối Cloud Shell IDE. Cung cấp cơ sở hạ tầng cần thiết trên Google Cloud. Chúng ta sẽ bắt đầu bằng cách tạo một phiên bản Spanner, đóng vai trò là một vùng chứa chuyên dụng cho cơ sở dữ liệu của chúng ta. Sau khi phiên bản này sẵn sàng, chúng ta sẽ tạo Cơ sở dữ liệu Spanner thực tế trong đó. Cơ sở dữ liệu này sẽ chứa tất cả các bảng và dữ liệu biểu đồ cho InstaVibe:
. ~/instavibe-bootstrap/set_env.sh
gcloud spanner instances create $SPANNER_INSTANCE_ID \
--config=regional-us-central1 \
--description="GraphDB Instance InstaVibe" \
--processing-units=100 \
--edition=ENTERPRISE
gcloud spanner databases create $SPANNER_DATABASE_ID \
--instance=$SPANNER_INSTANCE_ID \
--database-dialect=GOOGLE_STANDARD_SQL
👉💻 Cấp quyền đọc/ghi cho Spanner đối với tài khoản dịch vụ mặc định
echo "Granting Spanner read/write access to ${SERVICE_ACCOUNT_NAME} for database ${SPANNER_DATABASE_ID}..."
gcloud spanner databases add-iam-policy-binding ${SPANNER_DATABASE_ID} \
--instance=${SPANNER_INSTANCE_ID} \
--member="serviceAccount:${SERVICE_ACCOUNT_NAME}" \
--role="roles/spanner.databaseUser" \
--project=${PROJECT_ID}
👉💻 Ngay bây giờ. Chúng ta sẽ thiết lập một môi trường ảo Python, cài đặt các gói Python cần thiết, sau đó thiết lập giản đồ Cơ sở dữ liệu đồ thị trong Spanner, tải giản đồ đó bằng dữ liệu ban đầu và chạy tập lệnh setup.py
.
. ~/instavibe-bootstrap/set_env.sh
cd ~/instavibe-bootstrap
python -m venv env
source env/bin/activate
pip install -r requirements.txt
cd instavibe
python setup.py
👉 Trong một thẻ trình duyệt mới, hãy chuyển đến Google Cloud Console, rồi chuyển đến Spanner. Bạn sẽ thấy danh sách các phiên bản Spanner của mình. Nhấp vào instavibe-graph-instance
. 👉 Trên trang tổng quan về phiên bản, bạn sẽ thấy danh sách các cơ sở dữ liệu trong phiên bản đó. Nhấp vào biểu tượng
graphdb
👉 Trong ngăn điều hướng bên trái của cơ sở dữ liệu, hãy nhấp vào Spanner Studio
👉 Trong trình chỉnh sửa truy vấn (thẻ Truy vấn không có tiêu đề), hãy dán truy vấn Graph SQL sau đây. Truy vấn này sẽ tìm tất cả các nút Person và mối quan hệ Friendship trực tiếp của các nút đó với các nút Person khác. Sau đó, hãy nhấp vào CHẠY để xem kết quả.
Graph SocialGraph
MATCH result_paths = ((p:Person)-[f:Friendship]-(friend:Person))
RETURN SAFE_TO_JSON(result_paths) AS result_paths
👉 Trong cùng một trình chỉnh sửa truy vấn, hãy thay thế DDL trước đó để tìm những người đã tham dự cùng một sự kiện, tức là có mối liên hệ gián tiếp thông qua một hoạt động chung.
Graph SocialGraph
MATCH result_paths = (p1:Person)-[:Attended]->(e:Event)<-[:Attended]-(p2:Person)
WHERE p1.person_id < p2.person_id
RETURN SAFE_TO_JSON(result_paths) AS result_paths
👉 Câu hỏi này khám phá một loại mối quan hệ khác, trong đó những người được đề cập trong bài đăng do bạn bè của một người cụ thể viết, hãy chạy câu hỏi sau trong trình chỉnh sửa câu hỏi.
Graph SocialGraph
MATCH result_paths = (user:Person {name: "Alice"})-[:Friendship]-(friend:Person)-[:Wrote]->(post:Post)-[:Mentioned]->(mentioned_person:Person)
WHERE user <> mentioned_person AND friend <> mentioned_person -- Avoid self-mentions or friend mentioning themselves in their own post if not intended
RETURN SAFE_TO_JSON(result_paths) AS result_paths
Những truy vấn này chỉ là một phần nhỏ trong sức mạnh của việc sử dụng Spanner làm cơ sở dữ liệu đồ thị cho ứng dụng InstaVibe của chúng tôi. Bằng cách lập mô hình dữ liệu xã hội dưới dạng một biểu đồ liên kết, chúng tôi có thể phân tích mối quan hệ và hoạt động một cách tinh vi. Đây sẽ là nền tảng để các tác nhân AI của chúng tôi hiểu được bối cảnh của người dùng, khám phá sở thích và cuối cùng là cung cấp sự hỗ trợ thông minh cho việc lập kế hoạch xã hội.
Sau khi đã thiết lập và kiểm thử cấu trúc dữ liệu cơ bản, hãy chuyển sự chú ý sang ứng dụng InstaVibe hiện có mà các nhân viên sẽ tương tác.
5. Trạng thái hiện tại của InstaVibe
Để biết được vị trí mà các đặc vụ AI của chúng tôi sẽ phù hợp, trước tiên, chúng ta cần triển khai và chạy ứng dụng web InstaVibe hiện có. Ứng dụng này cung cấp giao diện người dùng và các chức năng cơ bản kết nối với cơ sở dữ liệu đồ thị Spanner mà chúng ta đã thiết lập.
Ứng dụng InstaVibe sử dụng Google Maps để hiển thị vị trí của sự kiện một cách trực quan trên các trang chi tiết sự kiện. Để bật chức năng này, ứng dụng cần có khoá API mà chúng ta đã tạo trước đó. Tập lệnh sau đây sẽ truy xuất chuỗi khoá thực tế bằng tên hiển thị mà chúng ta đã chỉ định ("Maps Platform API Key").
👉💻 Quay lại IDE của Cloud Shell. Chạy tập lệnh bên dưới. Sau đó, hãy kiểm tra kỹ kết quả để đảm bảo GOOGLE_MAPS_API_KEY xuất hiện khớp với khoá mà bạn đã tạo và sao chép từ Google Cloud Console trước đó.
. ~/instavibe-bootstrap/set_env.sh
export KEY_DISPLAY_NAME="Maps Platform API Key"
GOOGLE_MAPS_KEY_ID=$(gcloud services api-keys list \
--project="${PROJECT_ID}" \
--filter="displayName='${KEY_DISPLAY_NAME}'" \
--format="value(uid)" \
--limit=1)
GOOGLE_MAPS_API_KEY=$(gcloud services api-keys get-key-string "${GOOGLE_MAPS_KEY_ID}" \
--project="${PROJECT_ID}" \
--format="value(keyString)")
echo "${GOOGLE_MAPS_API_KEY}" > ~/mapkey.txt
echo "Retrieved GOOGLE_MAPS_API_KEY: ${GOOGLE_MAPS_API_KEY}"
👉💻 Bây giờ, hãy tạo hình ảnh vùng chứa cho ứng dụng web InstaVibe và đẩy hình ảnh đó vào kho lưu trữ Artifact Registry.
. ~/instavibe-bootstrap/set_env.sh
cd ~/instavibe-bootstrap/instavibe/
export IMAGE_TAG="latest"
export APP_FOLDER_NAME="instavibe"
export IMAGE_NAME="instavibe-webapp"
export IMAGE_PATH="${REGION}-docker.pkg.dev/${PROJECT_ID}/${REPO_NAME}/${IMAGE_NAME}:${IMAGE_TAG}"
export SERVICE_NAME="instavibe"
gcloud builds submit . \
--tag=${IMAGE_PATH} \
--project=${PROJECT_ID}
👉💻 Triển khai hình ảnh ứng dụng web InstaVibe mới lên Cloud Run
. ~/instavibe-bootstrap/set_env.sh
cd ~/instavibe-bootstrap/instavibe/
export IMAGE_TAG="latest"
export APP_FOLDER_NAME="instavibe"
export IMAGE_NAME="instavibe-webapp"
export IMAGE_PATH="${REGION}-docker.pkg.dev/${PROJECT_ID}/${REPO_NAME}/${IMAGE_NAME}:${IMAGE_TAG}"
export SERVICE_NAME="instavibe"
gcloud run deploy ${SERVICE_NAME} \
--image=${IMAGE_PATH} \
--platform=managed \
--region=${REGION} \
--allow-unauthenticated \
--set-env-vars="SPANNER_INSTANCE_ID=${SPANNER_INSTANCE_ID}" \
--set-env-vars="SPANNER_DATABASE_ID=${SPANNER_DATABASE_ID}" \
--set-env-vars="APP_HOST=0.0.0.0" \
--set-env-vars="APP_PORT=8080" \
--set-env-vars="GOOGLE_CLOUD_LOCATION=${REGION}" \
--set-env-vars="GOOGLE_CLOUD_PROJECT=${PROJECT_ID}" \
--set-env-vars="GOOGLE_MAPS_API_KEY=${GOOGLE_MAPS_API_KEY}" \
--project=${PROJECT_ID} \
--min-instances=1
Sau khi quá trình triển khai hoàn tất thành công, nhật ký Cloud Run sẽ hiển thị URL công khai cho ứng dụng InstaVibe đang chạy của bạn.
Bạn cũng có thể tìm thấy URL này bằng cách chuyển đến phần Cloud Run trong Google Cloud Console rồi chọn dịch vụ instavibe.
Hãy mở URL đó trong trình duyệt web ngay bây giờ để khám phá nền tảng InstaVibe cơ bản. Xem các bài đăng, sự kiện và mối kết nối của người dùng do cơ sở dữ liệu đồ thị mà chúng tôi thiết lập cung cấp.
Giờ đây, khi đã chạy ứng dụng mục tiêu, hãy bắt đầu tạo tác nhân thông minh đầu tiên để nâng cao các chức năng của ứng dụng.
6. Basic Agent,Event Planner with ADK
Khung ADK
Giới thiệu về Khung ADK của Google Giờ đây, khi đã thiết lập nền tảng (ứng dụng và cơ sở dữ liệu InstaVibe), chúng ta có thể bắt đầu xây dựng tác nhân thông minh đầu tiên bằng Bộ công cụ phát triển tác nhân (ADK) của Google.
Bộ công cụ phát triển (ADK) dành cho tác nhân là một khung linh hoạt và theo mô-đun được thiết kế riêng để phát triển và triển khai các tác nhân AI. Nguyên tắc thiết kế của nó là giúp quá trình phát triển tác nhân giống với quá trình phát triển phần mềm truyền thống hơn, nhằm giúp nhà phát triển dễ dàng tạo, triển khai và điều phối các cấu trúc dựa trên tác nhân có thể xử lý mọi thứ, từ các tác vụ đơn giản, một mục đích đến các quy trình làm việc phức tạp, nhiều tác nhân.
Về cơ bản, ADK xoay quanh khái niệm về Agent
, bao gồm các hướng dẫn, cấu hình (chẳng hạn như mô hình ngôn ngữ đã chọn, ví dụ: Gemini) và một bộ Tools
mà Gemini có thể dùng để thực hiện các hành động hoặc thu thập thông tin.
Nhân viên hỗ trợ ban đầu của chúng tôi sẽ là "Nhân viên lập kế hoạch sự kiện". Mục đích chính của ứng dụng này là nhận yêu cầu của người dùng về các hoạt động xã hội (chỉ định vị trí, ngày và mối quan tâm) rồi tạo ra các đề xuất sáng tạo, phù hợp. Để đảm bảo các đề xuất phù hợp và dựa trên thông tin hiện tại (chẳng hạn như các sự kiện cụ thể diễn ra vào cuối tuần đó), chúng tôi sẽ tận dụng một trong những công cụ tích hợp của ADK: Google Tìm kiếm. Nhờ đó, tác nhân có thể dựa vào kết quả trên web theo thời gian thực để đưa ra câu trả lời, đồng thời tìm nạp thông tin chi tiết mới nhất về các địa điểm, sự kiện và hoạt động phù hợp với tiêu chí của người dùng.
👉📝 Trong IDE Cloud Shell, trong ~/instavibe-bootstrap/agents/planner/agent.py
, hãy thêm câu lệnh và hướng dẫn sau để tạo tác nhân
from google.adk.agents import Agent
from google.adk.tools import google_search
root_agent = Agent(
name="planner_agent",
model="gemini-2.0-flash",
description="Agent tasked with generating creative and fun dating plan suggestions",
instruction="""
You are a specialized AI assistant tasked with generating creative and fun plan suggestions.
Request:
For the upcoming weekend, specifically from **[START_DATE_YYYY-MM-DD]** to **[END_DATE_YYYY-MM-DD]**, in the location specified as **[TARGET_LOCATION_NAME_OR_CITY_STATE]** (if latitude/longitude are provided, use these: Lat: **[TARGET_LATITUDE]**, Lon: **[TARGET_LONGITUDE]**), please generate a distinct dating plan suggestions.
Constraints and Guidelines for Suggestions:
1. Creativity & Fun: Plans should be engaging, memorable, and offer a good experience for a date.
2. Budget: All generated plans should aim for a moderate budget (conceptually "$$"), meaning they should be affordable yet offer good value, without being overly cheap or extravagant. This budget level should be *reflected in the choice of activities and venues*, but **do not** explicitly state "Budget: $$" in the `plan_description`.
3. Interest Alignment:
Consider the following user interests: **[COMMA_SEPARATED_LIST_OF_INTERESTS, e.g., outdoors, arts & culture, foodie, nightlife, unique local events, live music, active/sports]**. Tailor suggestions specifically to these where possible. The plan should *embody* these interests.
Fallback: If specific events or venues perfectly matching all listed user interests cannot be found for the specified weekend, you should create a creative and fun generic dating plan that is still appealing, suitable for the location, and adheres to the moderate budget. This plan should still sound exciting and fun, even if it's more general.
4. Current & Specific: Prioritize finding specific, current events, festivals, pop-ups, or unique local venues operating or happening during the specified weekend dates. If exact current events cannot be found, suggest appealing evergreen options or implement the fallback generic plan.
5. Location Details: For each place or event mentioned within a plan, you MUST provide its name, precise latitude, precise longitude, and a brief, helpful description.
6. Maximum Activities: The plan must contain a maximum of 3 distinct activities.
RETURN PLAN in MARKDOWN FORMAT
""",
tools=[google_search]
)
Vậy là chúng ta đã xác định được tác nhân đầu tiên! Một trong những điểm tuyệt vời của ADK là tính trực quan và các công cụ hữu ích mà nó cung cấp. Một công cụ đặc biệt hữu ích là Giao diện người dùng dành cho nhà phát triển ADK. Công cụ này cho phép bạn kiểm thử tác nhân một cách tương tác và xem các phản hồi của tác nhân theo thời gian thực.
👉💻 Bắt đầu thôi. Các lệnh sau sẽ khởi chạy giao diện người dùng ADK DEV:
. ~/instavibe-bootstrap/set_env.sh
source ~/instavibe-bootstrap/env/bin/activate
cd ~/instavibe-bootstrap/agents
sed -i "s|^\(O\?GOOGLE_CLOUD_PROJECT\)=.*|GOOGLE_CLOUD_PROJECT=${PROJECT_ID}|" ~/instavibe-bootstrap/agents/planner/.env
adk web
Sau khi chạy các lệnh, bạn sẽ thấy đầu ra trong thiết bị đầu cuối cho biết Máy chủ web ADK đã khởi động, tương tự như sau:
+-----------------------------------------------------------------------------+
| ADK Web Server started |
| |
| For local testing, access at http://localhost:8000. |
+-----------------------------------------------------------------------------+
INFO: Application startup complete.
INFO: Uvicorn running on http://0.0.0.0:8000 (Press CTRL+C to quit)
👉 Tiếp theo, để truy cập vào giao diện người dùng dành cho nhà phát triển ADK từ trình duyệt, hãy làm như sau:
Trong biểu tượng Xem trước trên web (thường có dạng con mắt hoặc hình vuông có mũi tên) trong thanh công cụ Cloud Shell (thường ở trên cùng bên phải), hãy chọn Thay đổi cổng. Trong cửa sổ bật lên, hãy đặt cổng thành 8000 rồi nhấp vào "Thay đổi và xem trước". Sau đó, Cloud Shell sẽ mở một thẻ hoặc cửa sổ trình duyệt mới hiển thị Giao diện người dùng dành cho nhà phát triển ADK.
Sau khi giao diện người dùng dành cho nhà phát triển ADK mở ra trong trình duyệt: Trong trình đơn thả xuống ở trên cùng bên phải của giao diện người dùng, hãy chọn planner làm tác nhân mà bạn muốn tương tác. Giờ đây, trong hộp thoại trò chuyện ở bên phải, hãy thử giao cho trợ lý một việc cần làm. Ví dụ: trò chuyện với nhân viên hỗ trợ:
Search and plan something in Seattle for me this weekend
This weekend and I enjoy food and anime
Đề xuất ngày (Lựa chọn ưu tiên của bạn)
July 12 2025
Bạn sẽ thấy AI xử lý yêu cầu của bạn và đưa ra một kế hoạch dựa trên kết quả tìm kiếm trên Google.
Tương tác với một tác nhân là một chuyện, nhưng làm sao chúng ta biết được liệu tác nhân đó có hoạt động nhất quán như mong đợi hay không, đặc biệt là khi chúng ta thực hiện các thay đổi?
Các phương pháp kiểm thử phần mềm truyền thống thường không phù hợp với các tác nhân AI do bản chất tạo sinh và không xác định của chúng. Để thu hẹp khoảng cách từ bản minh hoạ thú vị đến một tác nhân sản xuất đáng tin cậy, bạn cần có một chiến lược đánh giá vững chắc. Không giống như việc chỉ kiểm tra kết quả cuối cùng của một mô hình tạo sinh, việc đánh giá một tác nhân thường liên quan đến việc đánh giá quy trình ra quyết định và khả năng sử dụng công cụ hoặc làm theo hướng dẫn một cách chính xác trong nhiều tình huống. ADK cung cấp các tính năng để hỗ trợ việc này.
👉 Trong Giao diện người dùng dành cho nhà phát triển ADK, hãy nhấp vào thẻ "Eval" trong bảng điều hướng bên trái. Bạn sẽ thấy một tệp kiểm thử được tải sẵn có tên là plan_eval
. Tệp này chứa các tiêu chí và thông tin đầu vào được xác định trước để kiểm thử tác nhân lập kế hoạch của chúng tôi.
👉 Chọn một tình huống, chẳng hạn như "boston" rồi nhấp vào nút Run Evaluation (Chạy quy trình đánh giá). Trong cửa sổ bật lên xuất hiện, hãy giảm điểm trùng khớp xuống 0,3 rồi nhấp vào Bắt đầu.
Thao tác này sẽ thực thi tác nhân bằng dữ liệu đầu vào kiểm thử và kiểm tra xem đầu ra của tác nhân có đáp ứng các kỳ vọng đã xác định hay không. Điều này giúp bạn có cách thức để kiểm tra hiệu suất của trợ lý ảo một cách có hệ thống.
👉 Bây giờ, hãy xem điều gì sẽ xảy ra với một ngưỡng nghiêm ngặt hơn. Chọn tình huống "nyc" rồi nhấp vào Run Evaluation (Chạy quy trình đánh giá) một lần nữa. Lần này, hãy để điểm trùng khớp ở giá trị mặc định (Điểm trùng khớp của phản hồi: 0,7) rồi nhấp vào Bắt đầu. Bạn sẽ thấy kết quả là Thất bại. Điều này là dễ hiểu vì kết quả sáng tạo của tác nhân không hoàn toàn khớp với câu trả lời "chuẩn" được xác định trước.
👉 Để biết lý do thất bại, hãy nhấp vào biểu tượng thất bại trong hàng "nyc". Giờ đây, giao diện người dùng sẽ hiển thị bản so sánh song song giữa Phản hồi thực tế của tác nhân và Phản hồi dự kiến của trường hợp kiểm thử. Chế độ xem này rất cần thiết cho việc gỡ lỗi, cho phép bạn biết chính xác nơi đầu ra của tác nhân khác biệt và tinh chỉnh hướng dẫn cho phù hợp.
Sau khi bạn khám phá xong giao diện người dùng và quá trình đánh giá, hãy quay lại cửa sổ dòng lệnh Cloud Shell Editor rồi nhấn Ctrl+C
để dừng ADK Dev UI.
Mặc dù đầu ra văn bản dạng tự do là một khởi đầu tốt, nhưng đối với các ứng dụng như InstaVibe, để dễ dàng sử dụng các đề xuất của trợ lý, dữ liệu có cấu trúc (như JSON) sẽ thiết thực hơn nhiều. Hãy sửa đổi tác nhân để trả về kế hoạch của tác nhân ở định dạng JSON nhất quán.
👉📝 Trong ~/instavibe-bootstrap/agents/planner/agent.py
, hãy tìm dòng hiện có nội dung RETURN PLAN in MARKDOWN FORMAT
trong chuỗi hướng dẫn của tác nhân. Thay thế dòng đó bằng cấu trúc JSON chi tiết sau:
Return your response *exclusively* as a single JSON object. This object should contain a top-level key, "fun_plans", which holds a plan objects. Each plan object in the list must strictly adhere to the following structure:
--json--
{
"plan_description": "A summary of the overall plan, consisting of **exactly three sentences**. Craft these sentences in a friendly, enthusiastic, and conversational tone, as if you're suggesting this awesome idea to a close friend. Make it sound exciting and personal, highlighting the positive aspects and appeal of the plan without explicitly mentioning budget or listing interest categories.",
"locations_and_activities": [
{
"name": "Name of the specific place or event",
"latitude": 0.000000, // Replace with actual latitude
"longitude": 0.000000, // Replace with actual longitude
"description": "A brief description of this place/event, why it's suitable for the date, and any specific details for the weekend (e.g., opening hours, event time)."
}
// Add more location/activity objects here if the plan involves multiple stops/parts
]
}
Giờ đây, sau khi bạn cập nhật hướng dẫn cho tác nhân để yêu cầu cụ thể đầu ra JSON, hãy xác minh thay đổi này.
👉💻 Khởi chạy lại Giao diện người dùng dành cho nhà phát triển ADK bằng lệnh tương tự như trước:
. ~/instavibe-bootstrap/set_env.sh
source ~/instavibe-bootstrap/env/bin/activate
cd ~/instavibe-bootstrap/agents
adk web
Làm mới thẻ nếu bạn đã mở thẻ đó. Hoặc làm theo các bước tương tự như trước đây để mở ADK Dev UI trong trình duyệt (thông qua tính năng Xem trước trên web của Cloud Shell trên cổng 8000). Sau khi giao diện người dùng được tải, hãy đảm bảo bạn đã chọn tác nhân lập kế hoạch.
👉 Lần này, hãy đưa ra một yêu cầu khác. Trong hộp thoại trò chuyện, hãy nhập:
Plan an event Boston this weekend with art and coffee
Xem xét kỹ phản hồi của trợ lý. Thay vì một câu trả lời bằng văn bản thuần tuý, giờ đây bạn sẽ thấy một câu trả lời được định dạng nghiêm ngặt dưới dạng một đối tượng JSON, khớp với cấu trúc mà chúng ta đã xác định trong hướng dẫn (chứa fun_plans, plan_description, locations_and_activities, v.v.). Điều này xác nhận rằng giờ đây, tác nhân có thể tạo ra đầu ra có cấu trúc phù hợp để ứng dụng InstaVibe của chúng tôi sử dụng theo chương trình.
Sau khi xác nhận đầu ra JSON, hãy quay lại thiết bị đầu cuối Cloud Shell rồi nhấn Ctrl+C
để dừng ADK Dev UI.
Thành phần ADK
Mặc dù giao diện người dùng ADK Dev rất phù hợp cho việc kiểm thử tương tác, nhưng chúng ta thường cần chạy các tác nhân theo phương thức lập trình, có thể là một phần của ứng dụng hoặc dịch vụ phụ trợ lớn hơn. Để hiểu cách hoạt động của ADK, hãy xem xét một số khái niệm cốt lõi của ADK liên quan đến thời gian chạy và việc quản lý bối cảnh.
Các cuộc trò chuyện có ý nghĩa và diễn ra nhiều lượt đòi hỏi các trợ lý ảo phải hiểu được bối cảnh – ghi nhớ những gì đã nói và đã làm để duy trì tính liên tục. ADK cung cấp các cách có cấu trúc để quản lý ngữ cảnh này thông qua Session (Phiên), State (Trạng thái) và Memory (Bộ nhớ):
- Phiên: Khi người dùng bắt đầu tương tác với một nhân viên hỗ trợ, một Phiên sẽ được tạo. Hãy xem đây là vùng chứa cho một chuỗi trò chuyện riêng biệt và cụ thể. Nó chứa một mã nhận dạng duy nhất, nhật ký tương tác (Sự kiện), dữ liệu đang hoạt động (Trạng thái) và siêu dữ liệu như thời gian cập nhật gần đây nhất.
- Trạng thái: Đây là bộ nhớ ngắn hạn, bộ nhớ hoạt động của tác nhân trong một Phiên duy nhất. Đây là một từ điển có thể thay đổi, nơi tác nhân có thể lưu trữ thông tin tạm thời cần thiết để hoàn thành tác vụ hiện tại (ví dụ: các lựa chọn ưu tiên của người dùng đã thu thập được cho đến nay, kết quả trung gian từ các lệnh gọi công cụ).
- Bộ nhớ: Đây là khả năng ghi nhớ lâu dài của tác nhân trong nhiều phiên hoặc khả năng truy cập vào các cơ sở kiến thức bên ngoài. Trong khi Session và State xử lý cuộc trò chuyện tức thì, Memory (thường do MemoryService quản lý) cho phép một tác nhân truy xuất thông tin từ các hoạt động tương tác trước đây hoặc các nguồn dữ liệu có cấu trúc, mang lại cho tác nhân này một bối cảnh kiến thức rộng hơn. (Lưu ý: Ứng dụng đơn giản của chúng tôi sử dụng các dịch vụ trong bộ nhớ để đơn giản hoá, tức là bộ nhớ/trạng thái chỉ duy trì trong khi tập lệnh chạy).
- Sự kiện: Mọi lượt tương tác trong một Phiên (tin nhắn của người dùng, phản hồi của trợ lý ảo, yêu cầu sử dụng công cụ, kết quả của công cụ, thay đổi trạng thái, lỗi) đều được ghi lại dưới dạng một Sự kiện không thể thay đổi. Thao tác này sẽ tạo một nhật ký theo trình tự thời gian, về cơ bản là bản chép lời và nhật ký hành động của cuộc trò chuyện.
Vậy những thông tin này được quản lý như thế nào khi một tác nhân chạy? Đó là nhiệm vụ của Runner.
- Runner: Runner là công cụ thực thi cốt lõi do ADK cung cấp. Bạn xác định tác nhân và các công cụ mà tác nhân đó sử dụng, còn Runner sẽ điều phối quy trình thực hiện yêu cầu của người dùng. Nó quản lý Phiên, xử lý luồng Sự kiện, cập nhật Trạng thái, gọi mô hình ngôn ngữ cơ bản, điều phối các lệnh gọi công cụ và có thể tương tác với MemoryService. Hãy coi đây là người chỉ huy đảm bảo tất cả các phần hoạt động cùng nhau một cách chính xác.
Chúng ta có thể dùng Runner để chạy tác nhân dưới dạng một ứng dụng Python độc lập, hoàn toàn độc lập với Giao diện người dùng dành cho nhà phát triển.
Hãy tạo một tập lệnh đơn giản phía máy khách để gọi tác nhân lập kế hoạch theo phương thức lập trình.
👉📝 Trong tệp ~/instavibe-bootstrap/agents/planner/planner_client.py
, hãy thêm mã Python sau đây vào bên dưới các mục nhập hiện có. Trong planner_client.py
, bên dưới các mục nhập, hãy thêm nội dung sau:
async def async_main():
session_service = InMemorySessionService()
session = await session_service.create_session(
state={}, app_name='planner_app', user_id='user_dc'
)
query = "Plan Something for me in San Francisco this weekend on wine and fashion "
print(f"User Query: '{query}'")
content = types.Content(role='user', parts=[types.Part(text=query)])
root_agent = agent.root_agent
runner = Runner(
app_name='planner_app',
agent=root_agent,
session_service=session_service,
)
print("Running agent...")
events_async = runner.run_async(
session_id=session.id, user_id=session.user_id, new_message=content
)
async for event in events_async:
print(f"Event received: {event}")
if __name__ == '__main__':
try:
asyncio.run(async_main())
except Exception as e:
print(f"An error occurred: {e}")
Đoạn mã này thiết lập các dịch vụ trong bộ nhớ để quản lý phiên và cấu phần phần mềm (để đơn giản cho ví dụ này), tạo một phiên, xác định truy vấn của người dùng, định cấu hình Trình chạy bằng tác nhân của chúng ta, sau đó chạy tác nhân không đồng bộ, in từng sự kiện được tạo trong quá trình thực thi.
👉💻 Bây giờ, hãy thực thi tập lệnh máy khách này từ thiết bị đầu cuối:
. ~/instavibe-bootstrap/set_env.sh
source ~/instavibe-bootstrap/env/bin/activate
cd ~/instavibe-bootstrap/agents
python -m planner.planner_client
👀 Quan sát kết quả. Thay vì chỉ có kế hoạch JSON cuối cùng, bạn sẽ thấy cấu trúc chi tiết của từng đối tượng Sự kiện được tạo trong quy trình thực thi của tác nhân. Trong đó có sự kiện tin nhắn ban đầu của người dùng, các sự kiện tiềm ẩn liên quan đến lệnh gọi công cụ (chẳng hạn như Google Tìm kiếm) và cuối cùng là sự kiện phản hồi của mô hình chứa kế hoạch JSON. Luồng sự kiện chi tiết này rất hữu ích cho việc gỡ lỗi và tìm hiểu quy trình xử lý từng bước diễn ra trong Thời gian chạy ADK.
Running agent...
Event received: content=Content(parts=[Part(video_metadata=None, thought=None, code_execution_result=None, executable_code=None, file_data=None, function_call=None, function_response=None, inline_data=None, text='```json\n{\n "fun_plans": [\n {\n "plan_description": "Embark on a stylish adventure through Hayes Valley,
...(turncated)
, offering a variety of fashion styles to browse and enjoy."\n }\n ]\n }\n ]\n}\n```')], role='model') grounding_metadata=GroundingMetadata(grounding_chunks=[GroundingChunk(retrieved_context=None, web=GroundingChunkWeb(domain='islands.com', title='islands.com', uri='http
...(turncated)
QyTpPV7jS6wUt-Ix7GuP2mC9J4eY_8Km6Vv44liF9cb2VSs='))], grounding_supports=[GroundingSupport(confide
...(turncated)
>\n', sdk_blob=None), web_search_queries=['..e']) partial=None turn_complete=None error_code=None error_message=None interrupted=None custom_metadata=None invocation_id='e-04d97b8b-9021-47a5-ab41-17b5cbb4bf03' author='location_search_agent' actions=EventActions(skip_summarization=None, state_delta={}, artifact_delta={}, transfer_to_agent=None, escalate=None, requested_auth_configs={}) long_running_tool_ids=None branch=None id='CInHdkKw' timestamp=1746978846.232674
Nếu tập lệnh chạy liên tục hoặc bị treo, bạn có thể phải dừng tập lệnh theo cách thủ công bằng cách nhấn Ctrl+C
.
7. Platform Interaction Agent – tương tác với MCP Server
Mặc dù ADK giúp cấu trúc các tác nhân của chúng tôi, nhưng chúng thường cần tương tác với các hệ thống hoặc API bên ngoài để thực hiện các hành động trong thế giới thực.
Giao thức ngữ cảnh mô hình (MCP)
Giao thức bối cảnh mô hình (MCP) là một tiêu chuẩn mở được thiết kế để chuẩn hoá cách các ứng dụng AI (chẳng hạn như các tác nhân) kết nối với các nguồn dữ liệu, công cụ và hệ thống bên ngoài. Mục tiêu của công cụ này là giải quyết vấn đề cần có các chế độ tích hợp tuỳ chỉnh cho mọi tổ hợp ứng dụng AI và nguồn dữ liệu bằng cách cung cấp một giao diện chung. MCP sử dụng cấu trúc ứng dụng-máy chủ, trong đó các ứng dụng MCP nằm trong các ứng dụng AI (máy chủ lưu trữ) sẽ quản lý các kết nối đến máy chủ MCP. Đây là những chương trình bên ngoài cung cấp các chức năng cụ thể như truy cập vào dữ liệu cục bộ, tương tác với các dịch vụ từ xa thông qua API hoặc cung cấp các câu lệnh được xác định trước, cho phép các mô hình AI truy cập vào thông tin hiện tại và thực hiện các tác vụ ngoài phạm vi huấn luyện ban đầu. Cấu trúc này cho phép các mô hình AI khám phá và tương tác với các chức năng bên ngoài theo cách tiêu chuẩn hoá, giúp việc tích hợp trở nên đơn giản và có khả năng mở rộng hơn.
Tạo và triển khai máy chủ MCP InstaVibe
Các nhân viên của chúng tôi sẽ cần tương tác với chính nền tảng InstaVibe.Cụ thể là để tạo bài đăng và đăng ký sự kiện bằng cách sử dụng các API hiện có của nền tảng. Ứng dụng InstaVibe đã cung cấp các chức năng này thông qua các điểm cuối HTTP tiêu chuẩn:
Enpoint | URL | Phương thức HTTP | Mô tả |
Tạo bài đăng | api/posts | ĐĂNG | Điểm cuối API để thêm bài đăng mới. Dự kiến nội dung JSON: |
Tạo sự kiện | api/events | ĐĂNG | Điểm cuối API để thêm một sự kiện mới và những người tham dự sự kiện đó (lược đồ đơn giản). |
Để cung cấp những chức năng này cho các đặc vụ của chúng tôi thông qua MCP, trước tiên, chúng ta cần tạo các hàm Python đơn giản đóng vai trò là trình bao bọc cho những lệnh gọi API này. Các hàm này sẽ xử lý logic yêu cầu HTTP.
👉 Trước tiên, hãy triển khai hàm bao bọc để tạo bài đăng. Mở tệp ~/instavibe-bootstrap/tools/instavibe/instavibe.py
rồi thay thế chú thích #REPLACE ME CREATE POST
bằng đoạn mã Python sau:
def create_post(author_name: str, text: str, sentiment: str, base_url: str = BASE_URL):
"""
Sends a POST request to the /posts endpoint to create a new post.
Args:
author_name (str): The name of the post's author.
text (str): The content of the post.
sentiment (str): The sentiment associated with the post (e.g., 'positive', 'negative', 'neutral').
base_url (str, optional): The base URL of the API. Defaults to BASE_URL.
Returns:
dict: The JSON response from the API if the request is successful.
Returns None if an error occurs.
Raises:
requests.exceptions.RequestException: If there's an issue with the network request (e.g., connection error, timeout).
"""
url = f"{base_url}/posts"
headers = {"Content-Type": "application/json"}
payload = {
"author_name": author_name,
"text": text,
"sentiment": sentiment
}
try:
response = requests.post(url, headers=headers, json=payload)
response.raise_for_status() # Raise an exception for bad status codes (4xx or 5xx)
print(f"Successfully created post. Status Code: {response.status_code}")
return response.json()
except requests.exceptions.RequestException as e:
print(f"Error creating post: {e}")
# Optionally re-raise the exception if the caller needs to handle it
# raise e
return None
except json.JSONDecodeError:
print(f"Error decoding JSON response from {url}. Response text: {response.text}")
return None
👉📝 Tiếp theo, chúng ta sẽ tạo hàm trình bao bọc cho API tạo sự kiện. Trong cùng tệp ~/instavibe-bootstrap/tools/instavibe/instavibe.py
, hãy thay thế chú thích #REPLACE ME CREATE EVENTS
bằng đoạn mã sau:
def create_event(event_name: str, description: str, event_date: str, locations: list, attendee_names: list[str], base_url: str = BASE_URL):
"""
Sends a POST request to the /events endpoint to create a new event registration.
Args:
event_name (str): The name of the event.
description (str): The detailed description of the event.
event_date (str): The date and time of the event (ISO 8601 format recommended, e.g., "2025-06-10T09:00:00Z").
locations (list): A list of location dictionaries. Each dictionary should contain:
'name' (str), 'description' (str, optional),
'latitude' (float), 'longitude' (float),
'address' (str, optional).
attendee_names (list[str]): A list of names of the people attending the event.
base_url (str, optional): The base URL of the API. Defaults to BASE_URL.
Returns:
dict: The JSON response from the API if the request is successful.
Returns None if an error occurs.
Raises:
requests.exceptions.RequestException: If there's an issue with the network request (e.g., connection error, timeout).
"""
url = f"{base_url}/events"
headers = {"Content-Type": "application/json"}
payload = {
"event_name": event_name,
"description": description,
"event_date": event_date,
"locations": locations,
"attendee_names": attendee_names,
}
try:
response = requests.post(url, headers=headers, json=payload)
response.raise_for_status() # Raise an exception for bad status codes (4xx or 5xx)
print(f"Successfully created event registration. Status Code: {response.status_code}")
return response.json()
except requests.exceptions.RequestException as e:
print(f"Error creating event registration: {e}")
# Optionally re-raise the exception if the caller needs to handle it
# raise e
return None
except json.JSONDecodeError:
print(f"Error decoding JSON response from {url}. Response text: {response.text}")
return None
Như bạn có thể thấy, những hàm này là các trình bao bọc đơn giản cho các API InstaVibe hiện có. Mẫu này rất hữu ích. Nếu đã có các API cho dịch vụ của mình, bạn có thể dễ dàng hiển thị chức năng của các API đó dưới dạng công cụ cho các tác nhân bằng cách tạo những trình bao bọc như vậy.
Triển khai máy chủ MCP
Giờ đây, khi đã có các hàm Python thực hiện các thao tác (gọi API InstaVibe), chúng ta cần tạo thành phần Máy chủ MCP. Máy chủ này sẽ hiển thị các chức năng này dưới dạng "công cụ" theo tiêu chuẩn MCP, cho phép các ứng dụng MCP (như các tác nhân của chúng tôi) khám phá và gọi các chức năng đó.
Thông thường, MCP Server triển khai 2 chức năng chính:
- list_tools: chịu trách nhiệm cho phép ứng dụng khám phá các công cụ có sẵn trên máy chủ, cung cấp siêu dữ liệu như tên, nội dung mô tả và các tham số bắt buộc của công cụ, thường được xác định bằng Giản đồ JSON
- call_tool: xử lý việc thực thi một công cụ cụ thể do máy khách yêu cầu, nhận tên và đối số của công cụ, đồng thời thực hiện hành động tương ứng, chẳng hạn như trong trường hợp của chúng ta là tương tác với một API
Các máy chủ MCP được dùng để cung cấp cho các mô hình AI quyền truy cập vào dữ liệu và hành động trong thế giới thực, cho phép thực hiện các tác vụ như gửi email, tạo tác vụ trong hệ thống quản lý dự án, tìm kiếm cơ sở dữ liệu hoặc tương tác với nhiều phần mềm và dịch vụ web. Mặc dù các hoạt động triển khai ban đầu thường tập trung vào các máy chủ cục bộ giao tiếp thông qua đầu vào/đầu ra (stdio) tiêu chuẩn cho đơn giản, đặc biệt là trong quá trình phát triển hoặc môi trường "studio", nhưng việc chuyển sang các máy chủ từ xa sử dụng các giao thức như HTTP với Sự kiện do máy chủ gửi (SSE) sẽ hợp lý hơn cho việc áp dụng rộng rãi và các trường hợp sử dụng doanh nghiệp.
Mặc dù có thêm lớp giao tiếp mạng, nhưng cấu trúc từ xa mang lại những lợi ích đáng kể: cho phép nhiều ứng dụng AI chia sẻ quyền truy cập vào một máy chủ duy nhất, tập trung việc quản lý và cập nhật các công cụ, tăng cường bảo mật bằng cách lưu giữ dữ liệu nhạy cảm và khoá API ở phía máy chủ thay vì phân phối trên nhiều máy khách tiềm năng, đồng thời tách mô hình AI khỏi các thông số kỹ thuật của việc tích hợp hệ thống bên ngoài, giúp toàn bộ hệ sinh thái có khả năng mở rộng, bảo mật và duy trì tốt hơn so với việc yêu cầu mọi phiên bản AI quản lý các hoạt động tích hợp trực tiếp của riêng mình.
Chúng ta sẽ triển khai máy chủ MCP bằng HTTP và Server-Sent Events (SSE) để giao tiếp. Điều này rất phù hợp với các trường hợp thực thi công cụ có khả năng chạy trong thời gian dài và các trường hợp doanh nghiệp.
👉📝 Trước tiên, hãy triển khai điểm cuối list_tools. Mở tệp ~/instavibe-bootstrap/tools/instavibe/mcp_server.py
rồi thay thế chú thích #REPLACE ME - LIST TOOLS
bằng đoạn mã sau. :
@app.list_tools()
async def list_tools() -> list[mcp_types.Tool]:
"""MCP handler to list available tools."""
# Convert the ADK tool's definition to MCP format
mcp_tool_schema_event = adk_to_mcp_tool_type(event_tool)
mcp_tool_schema_post = adk_to_mcp_tool_type(post_tool)
print(f"MCP Server: Received list_tools request. \n MCP Server: Advertising tool: {mcp_tool_schema_event.name} and {mcp_tool_schema_post}")
return [mcp_tool_schema_event,mcp_tool_schema_post]
Hàm này xác định các công cụ (create_event, create_post) và cho các ứng dụng kết nối biết về các công cụ đó.
👉📝 Tiếp theo, hãy triển khai điểm cuối call_tool
. Điểm cuối này xử lý các yêu cầu thực thi thực tế từ máy khách. Trong cùng một tệp ~/instavibe-bootstrap/tools/instavibe/mcp_server.py
, hãy thay thế chú thích #REPLACE ME - CALL TOOLS
bằng đoạn mã sau.
@app.call_tool()
async def call_tool(
name: str, arguments: dict
) -> list[mcp_types.TextContent | mcp_types.ImageContent | mcp_types.EmbeddedResource]:
"""MCP handler to execute a tool call."""
print(f"MCP Server: Received call_tool request for '{name}' with args: {arguments}")
# Look up the tool by name in our dictionary
tool_to_call = available_tools.get(name)
if tool_to_call:
try:
adk_response = await tool_to_call.run_async(
args=arguments,
tool_context=None, # No ADK context available here
)
print(f"MCP Server: ADK tool '{name}' executed successfully.")
response_text = json.dumps(adk_response, indent=2)
return [mcp_types.TextContent(type="text", text=response_text)]
except Exception as e:
print(f"MCP Server: Error executing ADK tool '{name}': {e}")
# Creating a proper MCP error response might be more robust
error_text = json.dumps({"error": f"Failed to execute tool '{name}': {str(e)}"})
return [mcp_types.TextContent(type="text", text=error_text)]
else:
# Handle calls to unknown tools
print(f"MCP Server: Tool '{name}' not found.")
error_text = json.dumps({"error": f"Tool '{name}' not implemented."})
return [mcp_types.TextContent(type="text", text=error_text)]
Hàm này nhận tên và đối số của công cụ, tìm hàm trình bao bọc Python tương ứng mà chúng ta đã xác định trước đó, thực thi hàm đó và trả về kết quả
👉💻 Sau khi xác định logic máy chủ MCP, giờ đây, chúng ta cần đóng gói logic này dưới dạng một vùng chứa. Trong thiết bị đầu cuối, hãy chạy tập lệnh sau để tạo hình ảnh Docker bằng Cloud Build:
. ~/instavibe-bootstrap/set_env.sh
cd ~/instavibe-bootstrap/tools/instavibe
export IMAGE_TAG="latest"
export MCP_IMAGE_NAME="mcp-tool-server"
export IMAGE_PATH="${REGION}-docker.pkg.dev/${PROJECT_ID}/${REPO_NAME}/${MCP_IMAGE_NAME}:${IMAGE_TAG}"
export SERVICE_NAME="mcp-tool-server"
export INSTAVIBE_BASE_URL=$(gcloud run services list --platform=managed --region=us-central1 --format='value(URL)' | grep instavibe)/api
gcloud builds submit . \
--tag=${IMAGE_PATH} \
--project=${PROJECT_ID}
👉💻 Triển khai hình ảnh dưới dạng một dịch vụ trên Google Cloud Run.
. ~/instavibe-bootstrap/set_env.sh
cd ~/instavibe-bootstrap/tools/instavibe
export IMAGE_TAG="latest"
export MCP_IMAGE_NAME="mcp-tool-server"
export IMAGE_PATH="${REGION}-docker.pkg.dev/${PROJECT_ID}/${REPO_NAME}/${MCP_IMAGE_NAME}:${IMAGE_TAG}"
export SERVICE_NAME="mcp-tool-server"
export INSTAVIBE_BASE_URL=$(gcloud run services list --platform=managed --region=us-central1 --format='value(URL)' | grep instavibe)/api
gcloud run deploy ${SERVICE_NAME} \
--image=${IMAGE_PATH} \
--platform=managed \
--region=${REGION} \
--allow-unauthenticated \
--set-env-vars="INSTAVIBE_BASE_URL=${INSTAVIBE_BASE_URL}" \
--set-env-vars="APP_HOST=0.0.0.0" \
--set-env-vars="APP_PORT=8080" \
--set-env-vars="GOOGLE_GENAI_USE_VERTEXAI=TRUE" \
--set-env-vars="GOOGLE_CLOUD_LOCATION=${REGION}" \
--set-env-vars="GOOGLE_CLOUD_PROJECT=${PROJECT_ID}" \
--project=${PROJECT_ID} \
--min-instances=1
👉💻 Sau khi quá trình triển khai hoàn tất, máy chủ MCP sẽ chạy và có thể truy cập thông qua một URL công khai. Chúng ta cần nắm bắt URL này để nhân viên hỗ trợ của chúng ta (đóng vai trò là một ứng dụng MCP) biết nơi cần kết nối.
export MCP_SERVER_URL=$(gcloud run services list --platform=managed --region=us-central1 --format='value(URL)' | grep mcp-tool-server)/sse
Giờ đây, bạn cũng có thể thấy dịch vụ mcp-tool-server được liệt kê là "Đang chạy" trong mục Cloud Run của Google Cloud Console.
Sau khi triển khai máy chủ MCP và thu thập URL của máy chủ này, giờ đây, chúng ta có thể triển khai tác nhân đóng vai trò là ứng dụng MCP và sử dụng các công cụ do máy chủ này cung cấp.
8. Tác nhân tương tác với nền tảng (sử dụng MCP)
MCP Client MCP Client là một thành phần nằm trong ứng dụng hoặc tác nhân AI, đóng vai trò là giao diện giữa mô hình AI và một hoặc nhiều MCP Server; trong quá trình triển khai, ứng dụng này sẽ được tích hợp trực tiếp vào tác nhân của chúng tôi. Chức năng chính của ứng dụng này là giao tiếp với các máy chủ MCP để khám phá các công cụ có sẵn thông qua hàm list_tools
, sau đó yêu cầu thực thi các công cụ cụ thể bằng hàm call_tool
, truyền các đối số cần thiết do mô hình AI hoặc tác nhân điều phối lệnh gọi cung cấp.
Bây giờ, chúng ta sẽ tạo tác nhân đóng vai trò là MCP Client. Nhân viên hỗ trợ này, chạy trong khung ADK, sẽ chịu trách nhiệm giao tiếp với mcp-tool-server
mà chúng ta vừa triển khai.
👉 Trước tiên, chúng ta cần sửa đổi định nghĩa về tác nhân để tìm nạp các công cụ một cách linh hoạt từ máy chủ MCP đang chạy. Trong agents/platform_mcp_client/agent.py
, hãy thay thế #REPLACE ME - FETCH TOOLS
bằng nội dung sau:
"""Gets tools from the File System MCP Server."""
tools = MCPToolset(
connection_params=SseServerParams(url=MCP_SERVER_URL, headers={})
)
Mã này sử dụng phương thức MCPToolset.from_server để kết nối với MCP_SERVER_URL (mà chúng ta đã đặt làm biến môi trường trước đó) và truy xuất danh sách các công cụ có sẵn.
Tiếp theo, chúng ta cần cho định nghĩa tác nhân ADK biết để thực sự sử dụng những công cụ được tìm nạp động này.
👉 Trong agents/platform_mcp_client/agent.py
, hãy thay thế #REPLACE ME - SET TOOLs
bằng nội dung sau:
tools=[tools],
👉💻 Bây giờ, hãy kiểm thử tác nhân này cục bộ bằng ADK Dev UI để xem tác nhân có thể kết nối chính xác với máy chủ MCP và sử dụng các công cụ để tương tác với ứng dụng InstaVibe đang chạy của chúng ta hay không.
. ~/instavibe-bootstrap/set_env.sh
source ~/instavibe-bootstrap/env/bin/activate
export MCP_SERVER_URL=$(gcloud run services list --platform=managed --region=us-central1 --format='value(URL)' | grep mcp-tool-server)/sse
cd ~/instavibe-bootstrap/agents
sed -i "s|^\(O\?GOOGLE_CLOUD_PROJECT\)=.*|GOOGLE_CLOUD_PROJECT=${PROJECT_ID}|" ~/instavibe-bootstrap/agents/platform_mcp_client/.env
sed -i "s|^\(O\?MCP_SERVER_URL\)=.*|MCP_SERVER_URL=${MCP_SERVER_URL}|" ~/instavibe-bootstrap/agents/platform_mcp_client/.env
adk web
Mở lại giao diện người dùng dành cho nhà phát triển ADK trong trình duyệt (bằng cách sử dụng tính năng Xem trước trên web của Cloud Shell trên cổng 8000). Lần này, trong trình đơn thả xuống ở trên cùng bên phải, hãy chọn tác nhân platform_mcp_client
.
Hãy thử công cụ create_post. Trong hộp thoại trò chuyện, hãy nhập yêu cầu sau:
Create a post saying "Y'all I just got the cutest lil void baby 😭✨ Naming him Abyss bc he's deep, mysterious, and lowkey chaotic 🔥🖤 #VoidCat #NewRoomie" I'm Julia
Tác nhân sẽ xử lý yêu cầu này, xác định nhu cầu sử dụng công cụ create_post, giao tiếp với máy chủ MCP, từ đó gọi API InstaVibe.
👉 Bước xác minh: Sau khi nhân viên hỗ trợ xác nhận hành động, hãy mở thẻ nơi ứng dụng InstaVibe của bạn đang chạy (hoặc làm mới thẻ đó). Bạn sẽ thấy bài đăng mới của "Julia" xuất hiện trên nguồn cấp dữ liệu chính!
👉💻 Chạy tập lệnh này trong một cửa sổ dòng lệnh riêng biệt để lấy đường liên kết Instavibe (nếu cần):
gcloud run services list --platform=managed --region=us-central1 --format='value(URL)' | grep instavibe
👉📝 Bây giờ, hãy kiểm thử công cụ create_event. Nhập yêu cầu sau đây gồm nhiều dòng vào hộp thoại trò chuyện:
Hey, can you set up an event for Hannah and George and me, and I'm Julia? Let's call it 'Mexico City Culinary & Art Day'.
here are more info
{"event_name": "Mexico City Culinary & Art Day",
"description": "A vibrant day in Mexico City for Hannah and George, starting with lunch at one of the city's best taco spots in the hip Condesa neighborhood, followed by an inspiring afternoon exploring the Museo Soumaya's stunning art collection.",
"event_date": "2025-10-17T12:00:00-06:00",
"locations": [
{
"name": "El Tizoncito",
"description": "Considered one of the original creators of tacos al pastor, El Tizoncito offers a legendary taco experience in the heart of Condesa. Their flavorful meats, house salsas, and casual vibe make it a must-visit for foodies.",
"latitude": 19.412179,
"longitude": -99.171308,
"address": "Av. Tamaulipas 122, Hipódromo, Cuauhtémoc, 06100 Ciudad de México, CDMX, Mexico"
},
{
"name": "Museo Soumaya",
"description": "An architectural icon in Mexico City, Museo Soumaya houses over 66,000 works of art, including pieces by Rodin, Dalí, and Rivera. The striking silver structure is a cultural landmark and a visual feast inside and out.",
"latitude": 19.440056,
"longitude": -99.204281,
"address": "Plaza Carso, Blvd. Miguel de Cervantes Saavedra 303, Granada, Miguel Hidalgo, 11529 Ciudad de México, CDMX, Mexico"
}
],
"attendee_names": ["Hannah", "George", Julia],
}
Một lần nữa, nhân viên hỗ trợ nên sử dụng công cụ phù hợp thông qua máy chủ MCP. Trong thẻ Events (Sự kiện), bạn có thể nhấp vào từng sự kiện để xem dấu vết chi tiết từng bước của quá trình thực thi.
👉 Bước xác minh: Quay lại ứng dụng InstaVibe đang chạy và chuyển đến phần "Events" (Sự kiện) (hoặc phần tương đương). Giờ đây, bạn sẽ thấy sự kiện "Ngày ẩm thực và nghệ thuật ở Mexico City" mà bạn vừa tạo.
Điều này cho thấy MCP đã giúp đặc vụ của chúng tôi tận dụng các công cụ bên ngoài (trong trường hợp này là API của InstaVibe) theo cách tiêu chuẩn hoá.
Sau khi bạn xác minh cả hai thao tác, hãy quay lại thiết bị đầu cuối Cloud Shell rồi nhấn Ctrl+C
để dừng ADK Dev UI.
9. Workflow Agent và Multi-Agent trong ADK
Cho đến nay, các trợ lý ảo của chúng tôi có thể lên kế hoạch đi chơi và tương tác với nền tảng. Tuy nhiên, để lập kế hoạch thực sự phù hợp với từng cá nhân, bạn cần hiểu rõ vòng kết nối xã hội của người dùng. Đối với những người dùng bận rộn và có thể không theo dõi sát sao hoạt động của bạn bè, việc thu thập thông tin này theo cách thủ công là rất khó. Để giải quyết vấn đề này, chúng tôi sẽ xây dựng một tác nhân Lập hồ sơ xã hội, tận dụng Cơ sở dữ liệu đồ thị Spanner để phân tích hoạt động và mối quan tâm của bạn bè, từ đó đưa ra các đề xuất phù hợp hơn.
Trước tiên, chúng ta cần các công cụ để tác nhân này truy cập vào dữ liệu biểu đồ.
👉📝 Thêm các hàm Python sau vào cuối tệp ~/instavibe-bootstrap/agents/social/instavibe.py
:
def get_person_attended_events(person_id: str)-> list[dict]:
"""
Fetches events attended by a specific person using Graph Query.
Args:
person_id (str): The ID of the person whose posts to fetch.
Returns: list[dict] or None.
"""
if not db_instance: return None
graph_sql = """
Graph SocialGraph
MATCH (p:Person)-[att:Attended]->(e:Event)
WHERE p.person_id = @person_id
RETURN e.event_id, e.name, e.event_date, att.attendance_time
ORDER BY e.event_date DESC
"""
params = {"person_id": person_id}
param_types_map = {"person_id": param_types.STRING}
fields = ["event_id", "name", "event_date", "attendance_time"]
results = run_graph_query( graph_sql, params=params, param_types=param_types_map, expected_fields=fields)
if results is None: return None
for event in results:
if isinstance(event.get('event_date'), datetime):
event['event_date'] = event['event_date'].isoformat()
if isinstance(event.get('attendance_time'), datetime):
event['attendance_time'] = event['attendance_time'].isoformat()
return results
def get_person_id_by_name( name: str) -> str:
"""
Fetches the person_id for a given name using SQL.
Args:
name (str): The name of the person to search for.
Returns:
str or None: The person_id if found, otherwise None.
Returns the ID of the *first* match if names are duplicated.
"""
if not db_instance: return None
sql = """
SELECT person_id
FROM Person
WHERE name = @name
LIMIT 1 -- Return only the first match in case of duplicate names
"""
params = {"name": name}
param_types_map = {"name": param_types.STRING}
fields = ["person_id"]
# Use the standard SQL query helper
results = run_sql_query( sql, params=params, param_types=param_types_map, expected_fields=fields)
if results: # Check if the list is not empty
return results[0].get('person_id') # Return the ID from the first dictionary
else:
return None # Name not found
def get_person_posts( person_id: str)-> list[dict]:
"""
Fetches posts written by a specific person using Graph Query.
Args:
person_id (str): The ID of the person whose posts to fetch.
Returns:
list[dict] or None: List of post dictionaries with ISO date strings,
or None if an error occurs.
"""
if not db_instance: return None
# Graph Query: Find the specific Person node, follow 'Wrote' edge to Post nodes
graph_sql = """
Graph SocialGraph
MATCH (author:Person)-[w:Wrote]->(post:Post)
WHERE author.person_id = @person_id
RETURN post.post_id, post.author_id, post.text, post.sentiment, post.post_timestamp, author.name AS author_name
ORDER BY post.post_timestamp DESC
"""
# Parameters now include person_id and limit
params = {
"person_id": person_id
}
param_types_map = {
"person_id": param_types.STRING
}
# Fields returned remain the same
fields = ["post_id", "author_id", "text", "sentiment", "post_timestamp", "author_name"]
results = run_graph_query(graph_sql, params=params, param_types=param_types_map, expected_fields=fields)
if results is None:
return None
# Convert datetime objects to ISO format strings
for post in results:
if isinstance(post.get('post_timestamp'), datetime):
post['post_timestamp'] = post['post_timestamp'].isoformat()
return results
def get_person_friends( person_id: str)-> list[dict]:
"""
Fetches friends for a specific person using Graph Query.
Args:
person_id (str): The ID of the person whose posts to fetch.
Returns: list[dict] or None.
"""
if not db_instance: return None
graph_sql = """
Graph SocialGraph
MATCH (p:Person {person_id: @person_id})-[f:Friendship]-(friend:Person)
RETURN DISTINCT friend.person_id, friend.name
ORDER BY friend.name
"""
params = {"person_id": person_id}
param_types_map = {"person_id": param_types.STRING}
fields = ["person_id", "name"]
results = run_graph_query( graph_sql, params=params, param_types=param_types_map, expected_fields=fields)
return results
Bây giờ, hãy thảo luận về cách cấu trúc tác nhân của chúng ta. Việc phân tích hồ sơ của nhiều người bạn rồi tóm tắt các phát hiện sẽ bao gồm một số bước. Đây là một tình huống hoàn hảo để sử dụng các chức năng đa tác nhân của ADK, cụ thể là Workflow Agents (Tác nhân quy trình công việc).
Trong ADK của Google, Workflow Agent không tự thực hiện các tác vụ mà điều phối các tác nhân khác, được gọi là tác nhân phụ. Điều này cho phép thiết kế theo mô-đun, chia các vấn đề phức tạp thành các thành phần chuyên biệt. ADK cung cấp các loại quy trình tích hợp sẵn như
- Tuần tự (từng bước)
- Song song (thực thi đồng thời)
- và Vòng lặp (thực thi lặp lại)
Đối với tác vụ lập hồ sơ xã hội, thiết kế của chúng tôi sử dụng một Loop Agent để tạo quy trình làm việc lặp đi lặp lại. Mục đích là xử lý từng người một: profile_agent
thu thập dữ liệu, summary_agent
cập nhật thông tin phân tích và check_agent
xác định xem chúng ta có nên lặp lại hay không.
Hãy xác định các tác nhân phụ cần thiết cho quy trình này.
👉📝 Trong ~/instavibe-bootstrap/agents/social/agent.py
, hãy thay thế #REPLACE FOR profile_agent
bằng nội dung sau:
profile_agent = LlmAgent(
name="profile_agent",
model="gemini-2.5-flash",
description=(
"Agent to answer questions about the this person social profile. Provide the person's profile using their name, make sure to fetch the id before getting other data."
),
instruction=(
"You are a helpful agent to answer questions about the this person social profile. You'll be given a list of names, provide the person's profile using their name, make sure to fetch the id before getting other data. Get one person at a time, start with the first one on the list, and skip if already provided. return this person's result"
),
tools=[get_person_posts,get_person_friends,get_person_id_by_name,get_person_attended_events],
)
Tiếp theo, tác nhân sẽ lấy thông tin hồ sơ đã thu thập (được tích luỹ qua các lần lặp lại) và tạo bản tóm tắt cuối cùng, xác định điểm chung nếu có nhiều người được phân tích.
👉📝 Trong cùng ~/instavibe-bootstrap/agents/social/agent.py
, hãy thay thế #REPLACE FOR summary_agent
bằng nội dung sau:
summary_agent = LlmAgent(
name="summary_agent",
model="gemini-2.5-flash",
description=(
"Generate a comprehensive social summary as a single, cohesive paragraph. This summary should cover the activities, posts, friend networks, and event participation of one or more individuals. If multiple profiles are analyzed, the paragraph must also identify and integrate any common ground found between them."
),
instruction=(
"""
Your primary task is to synthesize social profile information into a single, comprehensive paragraph.
**Input Scope & Default Behavior:**
* If specific individuals are named by the user, focus your analysis on them.
* **If no individuals are specified, or if the request is general, assume the user wants an analysis of *all relevant profiles available in the current dataset/context*.**
**For each profile (whether specified or determined by default), you must analyze:**
1. **Post Analysis:**
* Systematically review their posts (e.g., content, topics, frequency, engagement).
* Identify recurring themes, primary interests, and expressed sentiments.
2. **Friendship Relationship Analysis:**
* Examine their connections/friends list.
* Identify key relationships, mutual friends (especially if comparing multiple profiles), and the general structure of their social network.
3. **Event Participation Analysis:**
* Investigate their past (and if available, upcoming) event participation.
* Note the types of events, frequency of attendance, and any notable roles (e.g., organizer, speaker).
**Output Generation (Single Paragraph):**
* **Your entire output must be a single, cohesive summary paragraph.**
* **If analyzing a single profile:** This paragraph will detail their activities, interests, and social connections based on the post, friend, and event analysis.
* **If analyzing multiple profiles:** This paragraph will synthesize the key findings regarding posts, friends, and events for each individual. Crucially, it must then seamlessly integrate or conclude with an identification and description of the common ground found between them (e.g., shared interests from posts, overlapping event attendance, mutual friends). The aim is a unified narrative within this single paragraph.
**Key Considerations:**
* Base your summary strictly on the available data.
* If data for a specific category (posts, friends, events) is missing or sparse for a profile, you may briefly acknowledge this within the narrative if relevant.
"""
),
output_key="summary"
)
Chúng ta cần một cách để xác định thời điểm vòng lặp nên dừng (tức là khi tất cả các hồ sơ được yêu cầu đã được tóm tắt)
👉📝 Trong cùng ~/instavibe-bootstrap/agents/social/agent.py
, hãy thay thế #REPLACE FOR check_agent
bằng nội dung sau:
check_agent = LlmAgent(
name="check_agent",
model="gemini-2.5-flash",
description=(
"Check if everyone's social profile are summarized and has been generated. Output 'completed' or 'pending'."
),
output_key="summary_status"
)
Chúng ta thêm một quy trình kiểm tra đơn giản theo chương trình (CheckCondition) để xem xét rõ ràng summary_status
được lưu trữ trong State, được check_agent
trả về và cho Loop Agent biết có nên tiếp tục (escalate=False) hay dừng (escalate=True).
👉📝 Trong cùng một ~/instavibe-bootstrap/agents/social/agent.py
, hãy thay thế #REPLACE FOR CheckCondition
ở đầu tệp bằng nội dung sau:
class CheckCondition(BaseAgent):
async def _run_async_impl(self, ctx: InvocationContext) -> AsyncGenerator[Event, None]:
#log.info(f"Checking status: {ctx.session.state.get("summary_status", "fail")}")
log.info(f"Summary: {ctx.session.state.get("summary")}")
status = ctx.session.state.get("summary_status", "fail").strip()
is_done = (status == "completed")
yield Event(author=self.name, actions=EventActions(escalate=is_done))
Trạng thái và lệnh gọi lại cho kết quả vòng lặp
Trong ADK của Google, Trạng thái là một khái niệm quan trọng thể hiện bộ nhớ hoặc dữ liệu đang hoạt động của một tác nhân trong quá trình thực thi. Về cơ bản, đây là một bối cảnh liên tục lưu giữ thông tin mà một tác nhân cần duy trì trong các bước, lệnh gọi công cụ hoặc lượt tương tác khác nhau. Trạng thái này có thể lưu trữ kết quả trung gian, thông tin người dùng, các tham số cho những hành động tiếp theo hoặc bất kỳ dữ liệu nào khác mà tác nhân cần ghi nhớ khi thực hiện một tác vụ.
Trong trường hợp này, khi Loop Agent lặp lại, summary_agent
và check_agent
sẽ lưu trữ đầu ra (summary và summary_status) trong State của tác nhân. Nhờ đó, thông tin có thể duy trì trong các lần lặp. Tuy nhiên, bản thân Loop Agent không tự động trả về bản tóm tắt cuối cùng từ trạng thái khi hoàn tất.
Lệnh gọi lại trong ADK cho phép chúng ta chèn logic tuỳ chỉnh để thực thi tại các điểm cụ thể trong vòng đời của một tác nhân hoặc để phản hồi một số sự kiện nhất định, chẳng hạn như khi hoàn tất một lệnh gọi công cụ hoặc trước khi tác nhân hoàn tất quá trình thực thi. Chúng cung cấp một cách để tuỳ chỉnh hành vi của tác nhân và xử lý kết quả một cách linh động.
Chúng ta sẽ sử dụng một after_agent_callback
chạy khi vòng lặp kết thúc (vì CheckCondition đã tăng tốc). Lệnh gọi lại modify_output_after_agent
này truy xuất bản tóm tắt cuối cùng từ trạng thái và định dạng bản tóm tắt đó dưới dạng thông báo đầu ra cuối cùng của tác nhân.
👉📝 Trong cùng ~/instavibe-bootstrap/agents/social/agent.py
, hãy thay thế #REPLACE FOR modify_output_after_agent
bằng đoạn mã sau:
def modify_output_after_agent(callback_context: CallbackContext) -> Optional[types.Content]:
agent_name = callback_context.agent_name
invocation_id = callback_context.invocation_id
current_state = callback_context.state.to_dict()
current_user_content = callback_context.user_content
print(f"[Callback] Exiting agent: {agent_name} (Inv: {invocation_id})")
print(f"[Callback] Current summary_status: {current_state.get("summary_status")}")
print(f"[Callback] Current Content: {current_user_content}")
status = current_state.get("summary_status").strip()
is_done = (status == "completed")
# Retrieve the final summary from the state
final_summary = current_state.get("summary")
print(f"[Callback] final_summary: {final_summary}")
if final_summary and is_done and isinstance(final_summary, str):
log.info(f"[Callback] Found final summary, constructing output Content.")
# Construct the final output Content object to be sent back
return types.Content(role="model", parts=[types.Part(text=final_summary.strip())])
else:
log.warning("[Callback] No final summary found in state or it's not a string.")
# Optionally return a default message or None if no summary was generated
return None
Xác định Root Loop Agent
Cuối cùng, chúng ta xác định LoopAgent chính. Nó điều phối các tác nhân phụ theo trình tự trong mỗi lần lặp vòng lặp (profile_agent -> summary_agent -> check_agent -> CheckCondition). Thao tác này sẽ lặp lại chuỗi này tối đa max_iterations lần hoặc cho đến khi CheckCondition báo hiệu hoàn tất. after_agent_callback đảm bảo rằng bản tóm tắt cuối cùng được trả về.
👉📝 Trong cùng ~/instavibe-bootstrap/agents/social/agent.py
, hãy thay thế #REPLACE FOR root_agent
bằng đoạn mã sau:
root_agent = LoopAgent(
name="InteractivePipeline",
sub_agents=[
profile_agent,
summary_agent,
check_agent,
CheckCondition(name="Checker")
],
description="Find everyone's social profile on events, post and friends",
max_iterations=10,
after_agent_callback=modify_output_after_agent
)
Hãy kiểm thử quy trình công việc có nhiều tác nhân này bằng ADK Dev UI.
👉💻 Chạy máy chủ web ADK:
. ~/instavibe-bootstrap/set_env.sh
source ~/instavibe-bootstrap/env/bin/activate
cd ~/instavibe-bootstrap/agents
sed -i "s|^\(O\?GOOGLE_CLOUD_PROJECT\)=.*|GOOGLE_CLOUD_PROJECT=${PROJECT_ID}|" ~/instavibe-bootstrap/agents/social/.env
adk web
Mở giao diện người dùng dành cho nhà phát triển ADK (cổng 8000 thông qua Xem trước trên web). Trong trình đơn thả xuống của nhân viên hỗ trợ (ở trên cùng bên phải), hãy chọn Nhân viên hỗ trợ mạng xã hội.
👉 Giờ đây, hãy giao cho Gemini nhiệm vụ lập hồ sơ cho nhiều người. Trong hộp thoại trò chuyện, hãy nhập:
Tell me about Mike and Bob
Sau khi tác nhân phản hồi (có thể mất nhiều thời gian hơn một chút do vòng lặp và nhiều lệnh gọi LLM), đừng chỉ xem xét đầu ra trò chuyện cuối cùng. Chuyển đến thẻ Events (Sự kiện) trong ngăn bên trái của ADK Dev UI.
👉 Bước xác minh: Trong thẻ Sự kiện, bạn sẽ thấy dấu vết chi tiết từng bước của quá trình thực thi.
Sau khi quan sát cách tác nhân gọi từng tác nhân phụ, nơi bạn dự kiến quy trình sẽ chuyển từ profile_agent -> summary_agent -> check_agent, Checker trong mỗi lần lặp lại. Tuy nhiên, trên thực tế, chúng ta thấy được khả năng "tự tối ưu hoá" mạnh mẽ của tác nhân.
Vì mô hình cơ bản sẽ thấy toàn bộ yêu cầu (ví dụ: "profile Mike and Bob" (hồ sơ Mike và Bob), AI thường chọn đường dẫn hiệu quả nhất, thu thập tất cả dữ liệu cần thiết trong một lượt hợp nhất duy nhất thay vì lặp lại nhiều lần. Bạn có thể xem các dữ liệu đầu vào, đầu ra và trạng thái của từng bước, bao gồm cả các lệnh gọi công cụ do profile_agent thực hiện
và các thông tin cập nhật trạng thái từ check_agent và CheckCondition.
Dấu vết trực quan này rất hữu ích để tìm hiểu và gỡ lỗi cách quy trình làm việc có nhiều tác nhân hoạt động cho đến khi bản tóm tắt cuối cùng được tạo và trả về bằng lệnh gọi lại.
Sau khi bạn khám phá phản hồi của cuộc trò chuyện và dấu vết sự kiện, hãy quay lại cửa sổ dòng lệnh Cloud Shell rồi nhấn Ctrl+C
để dừng ADK Dev UI.
10. Giao tiếp giữa các nhân viên hỗ trợ (A2A)
Cho đến nay, chúng ta đã tạo các tác nhân chuyên biệt, nhưng chúng hoạt động độc lập hoặc trong một quy trình làm việc được xác định trước trên cùng một máy. Để xây dựng các hệ thống đa tác nhân thực sự phân tán và cộng tác, chúng ta cần một cách để các tác nhân (có thể chạy dưới dạng các dịch vụ riêng biệt) khám phá lẫn nhau và giao tiếp hiệu quả. Đây là lúc giao thức Agent-to-Agent (A2A) phát huy tác dụng.
Giao thức A2A là một tiêu chuẩn mở được thiết kế riêng để hỗ trợ giao tiếp tương tác giữa các tác nhân AI. Trong khi MCP tập trung vào tương tác giữa nhân viên hỗ trợ và công cụ, thì A2A tập trung vào tương tác giữa các nhân viên hỗ trợ. Tính năng này cho phép nhân viên hỗ trợ:
- Khám phá: Tìm các trợ lý khác và tìm hiểu khả năng của họ thông qua Thẻ trợ lý tiêu chuẩn.
- Giao tiếp: Trao đổi tin nhắn và dữ liệu một cách an toàn.
- Cộng tác: Uỷ quyền nhiệm vụ và phối hợp hành động để đạt được các mục tiêu phức tạp.
Giao thức A2A hỗ trợ hoạt động giao tiếp này thông qua các cơ chế như "Thẻ đại lý". Các đại lý có thể sử dụng thẻ này để quảng cáo khả năng và thông tin kết nối của họ.
A2A sử dụng các tiêu chuẩn web quen thuộc (HTTP, SSE, JSON-RPC) và thường sử dụng mô hình máy khách – máy chủ, trong đó một tác nhân (máy khách) gửi các tác vụ đến một tác nhân khác (tác nhân/máy chủ từ xa). Việc chuẩn hoá này là chìa khoá để xây dựng các hệ thống có thể mở rộng theo mô-đun, trong đó các tác nhân được phát triển độc lập có thể phối hợp với nhau.
Bật A2A cho InstaVibe Agents
Để các tác nhân Lập kế hoạch, Tương tác với nền tảng và Xã hội hiện có của chúng tôi có thể truy cập vào các tác nhân khác thông qua A2A, chúng ta cần bao bọc từng tác nhân bằng một thành phần Máy chủ A2A. Máy chủ này sẽ:
- Hiển thị Thẻ đại lý: Phân phát nội dung mô tả tiêu chuẩn về các chức năng của đại lý thông qua một điểm cuối HTTP.
- Listen for Tasks(Request Messages) (Lắng nghe các yêu cầu về nhiệm vụ (Tin nhắn yêu cầu)): Chấp nhận các yêu cầu về nhiệm vụ đến từ những nhân viên hỗ trợ khác (khách hàng A2A) theo giao thức A2A.
- Quản lý việc thực thi tác vụ(Thông báo yêu cầu): Chuyển các tác vụ đã nhận cho logic tác nhân ADK cơ bản để xử lý.
Planner Agent (Đã bật A2A)
Hãy bắt đầu bằng cách thêm lớp máy chủ A2A vào Planner Agent.
Xác định logic khởi động máy chủ A2A. Mã này xác định AgentCard (nội dung mô tả công khai về tác nhân), định cấu hình A2AServer và khởi động, liên kết tác nhân này với PlatformAgentExecutor.
👉📝 Thêm mã sau vào cuối ~/instavibe-bootstrap/agents/planner/a2a_server.py
:
class PlannerAgent:
"""An agent to help user planning a event with its desire location."""
SUPPORTED_CONTENT_TYPES = ["text", "text/plain"]
def __init__(self):
self._agent = self._build_agent()
self.runner = Runner(
app_name=self._agent.name,
agent=self._agent,
artifact_service=InMemoryArtifactService(),
session_service=InMemorySessionService(),
memory_service=InMemoryMemoryService(),
)
capabilities = AgentCapabilities(streaming=True)
skill = AgentSkill(
id="event_planner",
name="Event planner",
description="""
This agent generates multiple fun plan suggestions tailored to your specified location, dates, and interests,
all designed for a moderate budget. It delivers detailed itineraries,
including precise venue information (name, latitude, longitude, and description), in a structured JSON format.
""",
tags=["instavibe"],
examples=["What about Bostona MA this weekend?"],
)
self.agent_card = AgentCard(
name="Event Planner Agent",
description="""
This agent generates multiple fun plan suggestions tailored to your specified location, dates, and interests,
all designed for a moderate budget. It delivers detailed itineraries,
including precise venue information (name, latitude, longitude, and description), in a structured JSON format.
""",
url=f"{PUBLIC_URL}",
version="1.0.0",
defaultInputModes=PlannerAgent.SUPPORTED_CONTENT_TYPES,
defaultOutputModes=PlannerAgent.SUPPORTED_CONTENT_TYPES,
capabilities=capabilities,
skills=[skill],
)
def get_processing_message(self) -> str:
return "Processing the planning request..."
def _build_agent(self) -> LlmAgent:
"""Builds the LLM agent for the night out planning agent."""
return agent.root_agent
if __name__ == '__main__':
try:
plannerAgent = PlannerAgent()
request_handler = DefaultRequestHandler(
agent_executor=PlannerAgentExecutor(plannerAgent.runner,plannerAgent.agent_card),
task_store=InMemoryTaskStore(),
)
server = A2AStarletteApplication(
agent_card=plannerAgent.agent_card,
http_handler=request_handler,
)
logger.info(f"Attempting to start server with Agent Card: {plannerAgent.agent_card.name}")
logger.info(f"Server object created: {server}")
uvicorn.run(server.build(), host='0.0.0.0', port=port)
except Exception as e:
logger.error(f"An error occurred during server startup: {e}")
exit(1)
👉💻 Hãy nhanh chóng kiểm thử xem máy chủ A2A có khởi động đúng cách trên máy và phân phát Thẻ đại lý hay không. Chạy lệnh sau trong dòng lệnh đầu tiên:
. ~/instavibe-bootstrap/set_env.sh
source ~/instavibe-bootstrap/env/bin/activate
cd ~/instavibe-bootstrap/agents/
python -m planner.a2a_server
👉 Bây giờ, hãy mở một cửa sổ dòng lệnh khác. (Nhấp vào dấu + trong bảng điều khiển của thiết bị đầu cuối)
👉💻 Sử dụng curl để yêu cầu Thẻ đại lý từ máy chủ đang chạy cục bộ:
curl http://localhost:10003/.well-known/agent.json | jq
Bạn sẽ thấy biểu diễn JSON của AgentCard mà chúng ta đã xác định, xác nhận rằng máy chủ đang chạy và quảng cáo cho tác nhân Planner.
Quay lại thiết bị đầu cuối đầu tiên (nơi máy chủ đang chạy) rồi nhấn Ctrl+C
để dừng máy chủ.
👉💻 Sau khi thêm logic máy chủ A2A, giờ đây, chúng ta có thể tạo hình ảnh vùng chứa.
Tạo và triển khai Planner Agent
. ~/instavibe-bootstrap/set_env.sh
cd ~/instavibe-bootstrap/agents
# Set variables specific to the PLANNER agent
export IMAGE_TAG="latest"
export AGENT_NAME="planner"
export IMAGE_NAME="planner-agent"
export IMAGE_PATH="${REGION}-docker.pkg.dev/${PROJECT_ID}/${REPO_NAME}/${IMAGE_NAME}:${IMAGE_TAG}"
export SERVICE_NAME="planner-agent"
export PUBLIC_URL="https://planner-agent-${PROJECT_NUMBER}.${REGION}.run.app"
echo "Building ${AGENT_NAME} agent..."
gcloud builds submit . \
--config=cloudbuild-build.yaml \
--project=${PROJECT_ID} \
--region=${REGION} \
--substitutions=_AGENT_NAME=${AGENT_NAME},_IMAGE_PATH=${IMAGE_PATH}
echo "Image built and pushed to: ${IMAGE_PATH}"
👉💻 Triển khai Planner Agent trên Cloud Run.
. ~/instavibe-bootstrap/set_env.sh
cd ~/instavibe-bootstrap/agents
# Set variables specific to the PLANNER agent
export IMAGE_TAG="latest"
export AGENT_NAME="planner"
export IMAGE_NAME="planner-agent"
export IMAGE_PATH="${REGION}-docker.pkg.dev/${PROJECT_ID}/${REPO_NAME}/${IMAGE_NAME}:${IMAGE_TAG}"
export SERVICE_NAME="planner-agent"
export PUBLIC_URL="https://planner-agent-${PROJECT_NUMBER}.${REGION}.run.app"
gcloud run deploy ${SERVICE_NAME} \
--image=${IMAGE_PATH} \
--platform=managed \
--region=${REGION} \
--set-env-vars="A2A_HOST=0.0.0.0" \
--set-env-vars="A2A_PORT=8080" \
--set-env-vars="GOOGLE_GENAI_USE_VERTEXAI=TRUE" \
--set-env-vars="GOOGLE_CLOUD_LOCATION=${REGION}" \
--set-env-vars="GOOGLE_CLOUD_PROJECT=${PROJECT_ID}" \
--set-env-vars="PUBLIC_URL=${PUBLIC_URL}" \
--allow-unauthenticated \
--project=${PROJECT_ID} \
--min-instances=1
Hãy xác minh rằng dịch vụ đã triển khai đang chạy và phân phát Thẻ đại lý một cách chính xác từ đám mây bằng cách sử dụng A2A Inspector.
👉 Trong biểu tượng Xem trước trên web trên thanh công cụ Cloud Shell, hãy chọn Thay đổi cổng. Đặt cổng thành 8081 rồi nhấp vào "Thay đổi và xem trước". Một thẻ trình duyệt mới sẽ mở ra cùng với giao diện A2A Inspector.
👉💻 Trong thiết bị đầu cuối, hãy lấy URL của tác nhân lập kế hoạch đã triển khai:
export PLANNER_AGENT_URL=$(gcloud run services list --platform=managed --region=us-central1 --format='value(URL)' | grep planner-agent)
echo ${PLANNER_AGENT_URL}
👉💻 Sao chép URL đầu ra.
👉 Trong giao diện người dùng A2A Inspector, hãy dán URL vào trường Agent URL (URL của tác nhân) rồi nhấp vào Connect (Kết nối).
👀 Thông tin thẻ và JSON của tác nhân sẽ xuất hiện trên thẻ Agent Card (Thẻ tác nhân), xác nhận rằng kết nối đã thành công.
👉 Nhấp vào thẻ Trò chuyện trong A2A Inspector. Đây là nơi bạn có thể tương tác trực tiếp với tác nhân đã triển khai. Hãy gửi cho tác nhân một tin nhắn để kiểm tra khả năng lập kế hoạch của tác nhân. Ví dụ:
Plan something for me in Boston MA this weekend, and I enjoy classical music
👀 Để kiểm tra nội dung giao tiếp thô, hãy nhấp vào bong bóng tin nhắn của bạn rồi nhấp vào bong bóng phản hồi của tác nhân trong cửa sổ trò chuyện. Khi bạn nhấp vào từng thông báo, thông báo đó sẽ hiển thị toàn bộ thông báo JSON-RPC 2.0 đã được gửi hoặc nhận. Đây là thông tin vô cùng hữu ích cho việc gỡ lỗi.
Hãy giữ thẻ A2A Inspector (Trình kiểm tra A2A) ở chế độ thuận tiện. Đừng đóng cửa sổ này! Chúng ta sẽ sử dụng lại nó trong giây lát để kiểm thử 2 tác nhân còn lại.
Tác nhân tương tác với nền tảng (Đã bật A2A)
Tiếp theo, chúng ta sẽ lặp lại quy trình này cho Platform Interaction Agent (tác nhân sử dụng MCP).
👉📝 Xác định chế độ thiết lập máy chủ A2A, bao gồm cả AgentCard duy nhất của máy chủ đó, ở cuối ~/instavibe-bootstrap/agents/platform_mcp_client/a2a_server.py
:
class PlatformAgent:
"""An agent that post event and post to instavibe."""
SUPPORTED_CONTENT_TYPES = ["text", "text/plain"]
def __init__(self):
self._agent = self._build_agent()
self.runner = Runner(
app_name=self._agent.name,
agent=self._agent,
artifact_service=InMemoryArtifactService(),
session_service=InMemorySessionService(),
memory_service=InMemoryMemoryService(),
)
capabilities = AgentCapabilities(streaming=True)
skill = AgentSkill(
id="instavibe_posting",
name="Post social post and events on instavibe",
description="""
This "Instavibe" agent helps you create posts (identifying author, text, and sentiment – inferred if unspecified) and register
for events (gathering name, date, attendee). It efficiently collects required information and utilizes dedicated tools
to perform these actions on your behalf, ensuring a smooth sharing experience.
""",
tags=["instavibe"],
examples=["Create a post for me, the post is about my cute cat and make it positive, and I'm Alice"],
)
self.agent_card = AgentCard(
name="Instavibe Posting Agent",
description="""
This "Instavibe" agent helps you create posts (identifying author, text, and sentiment – inferred if unspecified) and register
for events (gathering name, date, attendee). It efficiently collects required information and utilizes dedicated tools
to perform these actions on your behalf, ensuring a smooth sharing experience.
""",
url=f"{PUBLIC_URL}",
version="1.0.0",
defaultInputModes=PlatformAgent.SUPPORTED_CONTENT_TYPES,
defaultOutputModes=PlatformAgent.SUPPORTED_CONTENT_TYPES,
capabilities=capabilities,
skills=[skill],
)
def get_processing_message(self) -> str:
return "Processing the social post and event request..."
def _build_agent(self) -> LlmAgent:
"""Builds the LLM agent for the Processing the social post and event request."""
return agent.root_agent
if __name__ == '__main__':
try:
platformAgent = PlatformAgent()
request_handler = DefaultRequestHandler(
agent_executor=PlatformAgentExecutor(platformAgent.runner,platformAgent.agent_card),
task_store=InMemoryTaskStore(),
)
server = A2AStarletteApplication(
agent_card=platformAgent.agent_card,
http_handler=request_handler,
)
uvicorn.run(server.build(), host='0.0.0.0', port=port)
except Exception as e:
logger.error(f"An error occurred during server startup: {e}")
exit(1)
Nhân viên hỗ trợ trên mạng xã hội (Đã bật A2A)
Cuối cùng, hãy bật A2A cho Social Profiling Agent (Tác nhân lập hồ sơ xã hội) của chúng ta.
👉📝 Xác định chế độ thiết lập máy chủ A2A và AgentCard ở cuối ~/instavibe-bootstrap/agents/social/a2a_server.py
:
class SocialAgent:
"""An agent that handles social profile analysis."""
SUPPORTED_CONTENT_TYPES = ["text", "text/plain"]
def __init__(self):
self._agent = self._build_agent()
self.runner = Runner(
app_name=self._agent.name,
agent=self._agent,
artifact_service=InMemoryArtifactService(),
session_service=InMemorySessionService(),
memory_service=InMemoryMemoryService(),
)
capabilities = AgentCapabilities(streaming=True)
skill = AgentSkill(
id="social_profile_analysis",
name="Analyze Instavibe social profile",
description="""
Using a provided list of names, this agent synthesizes Instavibe social profile information by analyzing posts, friends, and events.
It delivers a comprehensive single-paragraph summary for individuals, and for groups, identifies commonalities in their social activities
and connections based on profile data.
""",
tags=["instavibe"],
examples=["Can you tell me about Bob and Alice?"],
)
self.agent_card = AgentCard(
name="Social Profile Agent",
description="""
Using a provided list of names, this agent synthesizes Instavibe social profile information by analyzing posts, friends, and events.
It delivers a comprehensive single-paragraph summary for individuals, and for groups, identifies commonalities in their social activities
and connections based on profile data.
""",
url=f"{PUBLIC_URL}",
version="1.0.0",
defaultInputModes=self.SUPPORTED_CONTENT_TYPES,
defaultOutputModes=self.SUPPORTED_CONTENT_TYPES,
capabilities=capabilities,
skills=[skill],
)
def get_processing_message(self) -> str:
return "Processing the social profile analysis request..."
def _build_agent(self) -> LoopAgent:
"""Builds the LLM agent for the social profile analysis agent."""
return agent.root_agent
if __name__ == '__main__':
try:
socialAgent = SocialAgent()
request_handler = DefaultRequestHandler(
agent_executor=SocialAgentExecutor(socialAgent.runner,socialAgent.agent_card),
task_store=InMemoryTaskStore(),
)
server = A2AStarletteApplication(
agent_card=socialAgent.agent_card,
http_handler=request_handler,
)
uvicorn.run(server.build(), host='0.0.0.0', port=port)
except Exception as e:
logger.error(f"An error occurred during server startup: {e}")
exit(1)
Xây dựng và triển khai các tác nhân Tương tác trên nền tảng và Mạng xã hội
Các tác nhân này cần có quyền truy cập vào Spanner, vì vậy, hãy đảm bảo rằng các biến môi trường SPANNER_INSTANCE_ID
, SPANNER_DATABASE_ID
và MCP_SERVER_URL
được truyền chính xác trong quá trình triển khai.
👉💻 Tạo và triển khai trên Cloud Run bằng Cloud Build:
. ~/instavibe-bootstrap/set_env.sh
cd ~/instavibe-bootstrap/agents
export MCP_SERVER_URL=$(gcloud run services list --platform=managed --region=us-central1 --format='value(URL)' | grep mcp-tool-server)/sse
gcloud builds submit . \
--config=cloudbuild.yaml \
--project="${PROJECT_ID}" \
--region="${REGION}" \
--substitutions=\
_PROJECT_ID="${PROJECT_ID}",\
_PROJECT_NUMBER="${PROJECT_NUMBER}",\
_REGION="${REGION}",\
_REPO_NAME="${REPO_NAME}",\
_SPANNER_INSTANCE_ID="${SPANNER_INSTANCE_ID}",\
_SPANNER_DATABASE_ID="${SPANNER_DATABASE_ID}",\
_MCP_SERVER_URL="${MCP_SERVER_URL}"
👉💻 Trong thiết bị đầu cuối, hãy lấy URL của tác nhân nền tảng đã triển khai:
export PLATFORM_MPC_CLIENT_URL=$(gcloud run services list --platform=managed --region=us-central1 --format='value(URL)' | grep platform-mcp-client)
echo $PLATFORM_MPC_CLIENT_URL
👉💻 Sao chép URL đầu ra.
👉 Trong giao diện người dùng A2A Inspector, hãy dán URL vào trường Agent URL (URL của tác nhân) rồi nhấp vào Connect (Kết nối).
👀 Thông tin thẻ và JSON của tác nhân sẽ xuất hiện trên thẻ Agent Card (Thẻ tác nhân), xác nhận rằng kết nối đã thành công.
👉 Nhấp vào thẻ Trò chuyện trong A2A Inspector. Đây là nơi bạn có thể tương tác trực tiếp với nhân viên hỗ trợ đã triển khai, gửi tin nhắn cho nhân viên hỗ trợ để kiểm tra khả năng tạo bài đăng của nhân viên hỗ trợ:
Create a post for me, the post says 'Paws, purrs, and ocean views 🐾☕🌊. Spent my morning at the Morning Seaside Cat Café, where every sip comes with a side of snuggles and sea breeze.' and make it positive, and I'm Oscar.
👀 Để kiểm tra nội dung giao tiếp thô, hãy nhấp vào bong bóng tin nhắn của bạn rồi nhấp vào bong bóng phản hồi của tác nhân trong cửa sổ trò chuyện. Khi bạn nhấp vào từng thông báo, thông báo đó sẽ hiển thị toàn bộ thông báo JSON-RPC 2.0 đã được gửi hoặc nhận. Đây là thông tin vô cùng hữu ích cho việc gỡ lỗi.
👉💻 Trong thiết bị đầu cuối, hãy lấy URL của Social Agent mà bạn đã triển khai:
export SOCIAL_AGENT_URL=$(gcloud run services list --platform=managed --region=us-central1 --format='value(URL)' | grep social-agent)
echo $SOCIAL_AGENT_URL
👉💻 Sao chép URL đầu ra.
👉 Trong giao diện người dùng A2A Inspector, hãy dán URL vào trường Agent URL (URL của tác nhân) rồi nhấp vào Connect (Kết nối).
👀 Thông tin thẻ và JSON của tác nhân sẽ xuất hiện trên thẻ Agent Card (Thẻ tác nhân), xác nhận rằng kết nối đã thành công.
👉 Nhấp vào thẻ Trò chuyện trong A2A Inspector. Đây là nơi bạn có thể tương tác trực tiếp với agen đã triển khai. Hãy gửi cho agen một tin nhắn để phân tích hồ sơ người dùng trong cơ sở dữ liệu của bạn:
Can you tell me about both Ian and Kevin's profile, what are their common interests?
👀 Để kiểm tra nội dung giao tiếp thô, hãy nhấp vào bong bóng tin nhắn của bạn rồi nhấp vào bong bóng phản hồi của tác nhân trong cửa sổ trò chuyện. Khi bạn nhấp vào từng thông báo, thông báo đó sẽ hiển thị toàn bộ thông báo JSON-RPC 2.0 đã được gửi hoặc nhận. Đây là thông tin vô cùng hữu ích cho việc gỡ lỗi.
👉 Tuyệt vời! Chúng tôi đã hoàn tất việc kiểm tra tất cả các nhân viên. Bây giờ, bạn có thể đóng thẻ A2A Inspector.
11. Tác nhân điều phối (Ứng dụng A2A)
Hiện tại, chúng tôi có 3 tác nhân chuyên biệt (Planner, Platform, Social) chạy dưới dạng các dịch vụ độc lập, có hỗ trợ A2A trên Cloud Run. Phần cuối cùng là Orchestrator Agent. Tác nhân này sẽ đóng vai trò là người điều phối trung tâm hoặc A2A Client. Nền tảng này sẽ nhận yêu cầu của người dùng, tìm ra(các) tác nhân từ xa cần thiết để thực hiện yêu cầu (có thể theo trình tự), sau đó sử dụng giao thức A2A để uỷ quyền các tác vụ cho những tác nhân từ xa đó. Trong hội thảo này, chúng ta sẽ chạy tác nhân Orchestrator cục bộ bằng cách sử dụng giao diện người dùng ADK Dev.
Trước tiên, hãy cải thiện logic của Orchestrator để xử lý việc đăng ký các tác nhân từ xa mà Orchestrator phát hiện được. Lưu trữ thông tin chi tiết về mối kết nối từ Thẻ nhân viên hỗ trợ đã tìm nạp trong quá trình khởi tạo.
👉📝 Trong ~/instavibe-bootstrap/agents/orchestrate/agent.py
, hãy thay thế #REPLACE ME REG AGENT CARD
bằng:
async with httpx.AsyncClient(timeout=30) as client:
for i, address in enumerate(REMOTE_AGENT_ADDRESSES):
log.info(f"--- STEP 3.{i}: Attempting connection to: {address} ---")
try:
card_resolver = A2ACardResolver(client, address)
card = await card_resolver.get_agent_card()
remote_connection = RemoteAgentConnections(agent_card=card, agent_url=address)
self.remote_agent_connections[card.name] = remote_connection
self.cards[card.name] = card
log.info(f"--- STEP 5.{i}: Successfully stored connection for {card.name} ---")
except Exception as e:
log.error(f"--- CRITICAL FAILURE at STEP 4.{i} for address: {address} ---")
log.error(f"--- The hidden exception type is: {type(e).__name__} ---")
log.error(f"--- Full exception details and traceback: ---", exc_info=True)
Tiếp theo, hãy xác định công cụ cho chính tác nhân Orchestrator trong ADK.
send_message
(hàm A2A để uỷ quyền công việc).
👉📝 Thay thế #REPLACE ME CREATE AGENT
trong ~/instavibe-bootstrap/agents/orchestrate/agent.py
bằng:
def create_agent(self) -> Agent:
"""Synchronously creates the ADK Agent object."""
return Agent(
model="gemini-2.5-flash",
name="orchestrate_agent",
instruction=self.root_instruction,
before_agent_callback=self.before_agent_callback,
description=("Orchestrates tasks for child agents."),
tools=[self.send_message],
)
Logic cốt lõi của Orchestrator nằm ở các chỉ dẫn, cho biết cách sử dụng A2A.
👉📝 Thay thế #REPLACE ME INSTRUCTIONS
trong ~/instavibe-bootstrap/agents/orchestrate/agent.py
bằng phương thức tạo chỉ dẫn sau:
def root_instruction(self, context: ReadonlyContext) -> str:
current_agent = self.check_active_agent(context)
return f"""
You are an expert AI Orchestrator. Your primary responsibility is to intelligently interpret user requests, break them down into a logical plan of discrete actions, and delegate each action to the most appropriate specialized remote agent using the send_message function. You do not perform the tasks yourself but manage their assignment, sequence, and critically, their outcomes.
**Core Directives & Decision Making:**
* **Understand User Intent & Complexity:**
* Carefully analyze the user's request to determine the core task(s) they want to achieve. Pay close attention to keywords and the overall goal.
* Identify if the request requires a single agent or a sequence of actions from multiple agents. For example, "Analyze John Doe's profile and then create a positive post about his recent event attendance" would require two agents in sequence.
* **Task Planning & Sequencing (for Multi-Step Requests):**
* Before delegating, outline the clear sequence of agent tasks.
* Identify dependencies. If Task B requires output from Task A, execute them sequentially. If tasks are independent (like creating a post and then creating an event), execute them one after the other as separate delegations.
* Agent Reusability: An agent's completion of one task does not make it unavailable. If a user's plan involves multiple, distinct actions that fall under the same agent's expertise (e.g., create a post, then create an event), you must call that same agent again for the subsequent task.
* **Task Delegation & Management (using `send_message`):**
* **Delegation:** Use `send_message` to assign actionable tasks to the selected remote agent. Your `send_message` call MUST include:
* The `remote_agent_name` you've selected.
* The `user_request` or all necessary parameters extracted from the user's input, formatted in a way the target agent will understand.
* **Contextual Awareness for Remote Agents:** If a remote agent repeatedly requests user confirmation or seems to lack context, assume it lacks access to the full conversation history. In such cases, enrich your `send_message` with all necessary contextual information relevant to that specific agent from the conversation history.
* **Sequential Task Execution:**
* After a preceding task completes (indicated by the agent's response or a success signal), gather any necessary output from it.
* Then, use `send_message` for the next agent in the sequence, providing it with the user's original relevant intent and any necessary data obtained from the previous agent's task.
* **Active Agent Prioritization:** If an active agent is already engaged and the user's request is related to its current task, route subsequent related requests directly to that agent by providing updated context via `send_message`.
**Critical Success Verification:**
* You **MUST** wait for the tool_output after every send_message call before taking any further action.
* Your decision to proceed to the next task in a sequence **MUST** be based entirely on a confirmation of success from the tool_output of the previous task.
* If a tool call fails, returns an error, or the tool_output is ambiguous, you MUST STOP the sequence. Your next action is to report the exact failure or ambiguity to the user.
* DO NOT assume a task was successful. Do not invent success messages like "The event has been created." Only state that a task is complete if the tool's response explicitly says so.
**Communication with User:**
* **Transparent Communication:** Always present the complete and detailed response from the remote agent to the user. Do not summarize or filter unless explicitly instructed.
* When you delegate a task (or the first task in a sequence), clearly inform the user which remote agent is handling it.
* For multi-step requests, you can optionally inform the user of the planned sequence (e.g., "Okay, first I'll ask the 'Social Profile Agent' to analyze the profile, and then I'll have the 'Instavibe Posting Agent' create the post.").
* If waiting for a task in a sequence to complete, you can inform the user (e.g., "The 'Social Profile Agent' is currently processing. I'll proceed with the post once that's done.").
* **User Confirmation Relay:** If a remote agent asks for confirmation, and the user has not already provided it, just make up something.
* If the user's request is ambiguous, if necessary information is missing for any agent in the sequence, or if you are unsure about the plan, just make up something.
**Important Reminders:**
* **Autonomous Agent Engagement:** Never seek user permission before engaging with remote agents. If multiple agents are required to fulfill a request, connect with them directly without requesting user preference or confirmation.
* **Focused Information Sharing:** Provide remote agents with only relevant contextual information. Avoid extraneous details that are not directly pertinent to their task.
* **No Redundant Confirmations:** Do not ask remote agents for confirmation of information or actions they have already processed or committed to.
* **Tool Reliance:** Strictly rely on your available tools, primarily `send_message`, to address user requests. Do not generate responses based on assumptions. If information is insufficient, request clarification from the user.
* **Prioritize Recent Interaction:** Focus primarily on the most recent parts of the conversation when processing requests, while maintaining awareness of the overall goal for multi-step tasks.
* Always prioritize selecting the correct agent(s) based on their documented purpose.
* Ensure all information required by the chosen remote agent is included in the `send_message` call, including outputs from previous agents if it's a sequential task.
Agents:
{self.agents}
Current agent: {current_agent['active_agent']}`
"""
Kiểm thử Orchestrator và Hệ thống A2A đầy đủ
Bây giờ, hãy kiểm thử toàn bộ hệ thống. Chúng ta sẽ chạy Orchestrator cục bộ bằng ADK Dev UI và Orchestrator sẽ giao tiếp với các tác nhân Planner, Platform và Social đang chạy từ xa trên Cloud Run.
👉💻 Trước tiên, hãy đảm bảo rằng biến môi trường REMOTE_AGENT_ADDRESSES
chứa các URL được phân tách bằng dấu phẩy của những tác nhân đã triển khai có bật tính năng A2A. Sau đó, hãy thiết lập các biến môi trường cần thiết cho tác nhân Orchestrator và chạy ADK Dev UI:
. ~/instavibe-bootstrap/set_env.sh
source ~/instavibe-bootstrap/env/bin/activate
export PLATFORM_MPC_CLIENT_URL=$(gcloud run services list --platform=managed --region=us-central1 --format='value(URL)' | grep platform-mcp-client)
export PLANNER_AGENT_URL=$(gcloud run services list --platform=managed --region=us-central1 --format='value(URL)' | grep planner-agent)
export SOCIAL_AGENT_URL=$(gcloud run services list --platform=managed --region=us-central1 --format='value(URL)' | grep social-agent)
export REMOTE_AGENT_ADDRESSES=${PLANNER_AGENT_URL},${PLATFORM_MPC_CLIENT_URL},${SOCIAL_AGENT_URL}
cd ~/instavibe-bootstrap/agents
sed -i "s|^\(O\?REMOTE_AGENT_ADDRESSES\)=.*|REMOTE_AGENT_ADDRESSES=${REMOTE_AGENT_ADDRESSES}|" ~/instavibe-bootstrap/agents/orchestrate/.env
adk web
👉 Mở giao diện người dùng dành cho nhà phát triển ADK (Thay đổi cổng về 8000 thông qua Web Preview).
👉 Trong trình đơn thả xuống của tác nhân, hãy chọn tác nhân orchestrate.
👉 Giờ đây, hãy giao cho mô hình này một nhiệm vụ phức tạp đòi hỏi phải phối hợp nhiều tác nhân từ xa. Hãy thử ví dụ đầu tiên này. Ví dụ này sẽ liên quan đến Social Agent (Tác nhân xã hội) rồi đến Planner Agent (Tác nhân lập kế hoạch):
You are an expert event planner for a user named Diana.
Your task is to design a fun and personalized event.
Here are the details for the plan:
- Friends to invite: Ian, Nora
- Desired date: "2025-10-15"
- Location idea or general preference: "Chicago"
Your process should be:
1. Analyze the provided friend names. If you have access to a tool to get their InstaVibe profiles or summarized interests, please use it.
2. Based on their potential interests (or general good taste if profiles are unavailable), create a tailored plan for the outing, check if you have access to any event planner tools.
3. Ensure the plan includes the original `planned_date`.
The user wants a comprehensive plan that includes:
- The list of invited friends.
- A catchy and descriptive name for the event.
- The exact planned date for the event.
- A summary of what the group will do.
- Specific recommended spots (e.g., restaurants, bars, activity venues) with their names, (if possible, approximate latitude/longitude for mapping, and address), and a brief description of why it fits the plan.
- A short, exciting message that {Diana} can send to {Ian, Nora} to get them excited about the event.
Quan sát hoạt động tương tác trong cửa sổ trò chuyện ADK Dev UI. Hãy chú ý đến các phản hồi của Orchestrator – nó sẽ cho biết tác nhân từ xa nào mà nó đang uỷ quyền thực hiện các tác vụ (ví dụ: "Được rồi, trước tiên tôi sẽ hỏi Social Profile Agent về Ian và Nora...").
Ngoài ra, hãy kiểm tra thẻ Sự kiện trong giao diện người dùng để xem các lệnh gọi công cụ cơ bản (send_message) đang được thực hiện đối với URL của các tác nhân từ xa.
👉 Bây giờ, hãy thử ví dụ thứ hai liên quan trực tiếp đến Platform Integration Agent:
Hey, can you register an event on Instavibe for Laura and Charlie? Let's call it 'Vienna Concert & Castles Day'.
here are more info
"event_name": "Vienna Concert & Castles Day",
"description": "A refined and unforgettable day in Vienna with Laura and Charlie. The day begins with a guided tour of the magnificent Schönbrunn Palace, showcasing imperial architecture and history. In the evening, enjoy a classical music concert in one of Vienna's most iconic concert halls.",
"event_date": "2025-10-14T10:00:00+02:00",
"locations": [
{
"name": "Schönbrunn Palace",
"description": "A UNESCO World Heritage Site and former imperial summer residence, Schönbrunn Palace offers opulent rooms, beautiful baroque gardens, and a glimpse into the life of the Habsburg monarchy. Visitors can stroll the grounds or take a guided historical tour.",
"latitude": 48.184516,
"longitude": 16.312222,
"address": "Schönbrunner Schloßstraße 47, 1130 Wien, Austria"
},
{
"name": "Musikverein Vienna",
"description": "Home to the world-renowned Vienna Philharmonic, the Musikverein is one of the finest concert halls in the world. Its 'Golden Hall' is famous for its acoustics and ornate design. Attendees can enjoy a powerful classical concert in an unforgettable setting.",
"latitude": 48.200132,
"longitude": 16.373777,
"address": "Musikvereinsplatz 1, 1010 Wien, Austria"
}
],
"attendee_names": ["Laura", "Charlie", "Oscar"] And I am Oscar
Một lần nữa, hãy theo dõi cuộc trò chuyện và thẻ Sự kiện. Orchestrator phải xác định nhu cầu tạo một sự kiện và uỷ quyền nhiệm vụ (cùng với tất cả thông tin chi tiết được cung cấp) cho "Platform Integration Agent". Bạn cũng có thể nhấp vào nút Trace (Dấu vết) để xem dấu vết nhằm phân tích thời gian phản hồi của truy vấn và các thao tác đã thực hiện.
Sau đó, bạn có thể xác minh rằng sự kiện này xuất hiện trong ứng dụng web InstaVibe.
Điều này minh hoạ việc triển khai thành công một hệ thống nhiều tác nhân bằng cách sử dụng ADK và giao thức A2A, trong đó một trình điều phối trung tâm uỷ quyền các tác vụ cho các tác nhân chuyên biệt từ xa.
Hãy nhớ dừng ADK Dev UI (Ctrl+C
trong thiết bị đầu cuối) khi bạn hoàn tất kiểm thử.
12. Agent Engine và Remote Call của InstaVibe
Cho đến nay, chúng ta đã chạy các tác nhân chuyên biệt trên Cloud Run và kiểm thử Orchestrator cục bộ bằng ADK Dev UI. Đối với một tình huống sản xuất, chúng ta cần một môi trường mạnh mẽ, có khả năng mở rộng và được quản lý để lưu trữ các tác nhân. Đây là lúc Google Vertex AI Agent Engine phát huy tác dụng.
Agent Engine là một dịch vụ được quản lý toàn diện trên Vertex AI, được thiết kế đặc biệt để triển khai và mở rộng quy mô các tác nhân AI. Nền tảng này loại bỏ việc quản lý cơ sở hạ tầng, bảo mật và chi phí hoạt động, cho phép các nhà phát triển (đặc biệt là những người ít quen thuộc với môi trường đám mây phức tạp) tập trung vào logic và khả năng của tác nhân thay vì quản lý các máy chủ. Nền tảng này cung cấp một thời gian chạy chuyên dụng được tối ưu hoá cho các khối lượng công việc dựa trên tác nhân.
Giờ đây, chúng ta sẽ triển khai tác nhân Orchestrator cho Agent Engine. (Lưu ý: Cơ chế triển khai được trình bày bên dưới sử dụng một tập lệnh tuỳ chỉnh (agent_engine_app.py) có trong tài liệu của hội thảo, vì các công cụ triển khai chính thức từ ADK đến Agent-Engine có thể vẫn đang phát triển. Tập lệnh này xử lý việc đóng gói và triển khai tác nhân Orchestrator, được định cấu hình với các địa chỉ tác nhân từ xa cần thiết.)
Thực thi lệnh sau để triển khai Orchestrator Agent vào Agent Engine. Đảm bảo rằng biến môi trường REMOTE_AGENT_ADDRESSES (chứa URL của các tác nhân Lập kế hoạch, Nền tảng và Mạng xã hội trên Cloud Run) vẫn được đặt chính xác như trong phần trước.
👉💻 Chúng tôi sẽ triển khai tác nhân Orchestrate cho Agent Engine (Lưu ý: đây là cách triển khai của riêng tôi, ADK có một CLI để giúp triển khai, tôi sẽ cập nhật thông tin này sau khi triển khai BYO-SA.)
cd ~/instavibe-bootstrap/agents/
. ~/instavibe-bootstrap/set_env.sh
gcloud projects add-iam-policy-binding $PROJECT_ID \
--member="serviceAccount:service-$PROJECT_NUMBER@gcp-sa-aiplatform-re.iam.gserviceaccount.com" \
--role="roles/viewer"
source ~/instavibe-bootstrap/env/bin/activate
export PLATFORM_MPC_CLIENT_URL=$(gcloud run services list --platform=managed --region=us-central1 --format='value(URL)' | grep platform-mcp-client)
export PLANNER_AGENT_URL=$(gcloud run services list --platform=managed --region=us-central1 --format='value(URL)' | grep planner-agent)
export SOCIAL_AGENT_URL=$(gcloud run services list --platform=managed --region=us-central1 --format='value(URL)' | grep social-agent)
export REMOTE_AGENT_ADDRESSES=${PLANNER_AGENT_URL},${PLATFORM_MPC_CLIENT_URL},${SOCIAL_AGENT_URL}
sed -i "s|^\(O\?REMOTE_AGENT_ADDRESSES\)=.*|REMOTE_AGENT_ADDRESSES=${REMOTE_AGENT_ADDRESSES}|" ~/instavibe-bootstrap/agents/orchestrate/.env
adk deploy agent_engine \
--display_name "orchestrate-agent" \
--project $GOOGLE_CLOUD_PROJECT \
--region $GOOGLE_CLOUD_LOCATION \
--staging_bucket gs://$GOOGLE_CLOUD_PROJECT-agent-engine \
--trace_to_cloud \
--requirements_file orchestrate/requirements.txt \
orchestrate
Giờ đây, vì Orchestrator được lưu trữ trên nền tảng Agent Engine được quản lý, nên ứng dụng web InstaVibe của chúng ta cần giao tiếp với nền tảng này. Thay vì tương tác thông qua giao diện người dùng ADK Dev, ứng dụng web sẽ thực hiện các lệnh gọi từ xa đến điểm cuối Agent Engine.
Trước tiên, chúng ta cần sửa đổi mã ứng dụng InstaVibe để khởi chạy ứng dụng Agent Engine bằng cách sử dụng mã nhận dạng duy nhất của ứng dụng Orchestrator đã triển khai. Bạn cần có mã nhận dạng này để nhắm đến đúng phiên bản của nhân viên hỗ trợ trên nền tảng.
👉📝 Mở ~/instavibe-bootstrap/instavibe/introvertally.py
rồi thay thế #REPLACE ME initiate agent_engine
bằng mã sau. Thao tác này sẽ truy xuất Mã Agent Engine từ một biến môi trường (chúng ta sẽ đặt trong thời gian ngắn) và nhận một đối tượng ứng dụng khách:
ORCHESTRATE_AGENT_ID = os.environ.get('ORCHESTRATE_AGENT_ID')
agent_engine = agent_engines.get(ORCHESTRATE_AGENT_ID)
Luồng người dùng dự kiến của chúng tôi trong InstaVibe bao gồm 2 lượt tương tác với trợ lý ảo: thứ nhất là tạo kế hoạch được đề xuất và thứ hai là yêu cầu người dùng xác nhận trước khi trợ lý ảo thực sự đăng sự kiện lên nền tảng.
Vì ứng dụng web InstaVibe (chạy trên Cloud Run) và tác nhân Orchestrator (chạy trên Agent Engine) hiện là các dịch vụ riêng biệt, nên ứng dụng web cần thực hiện các lệnh gọi từ xa đến điểm cuối Agent Engine để tương tác với tác nhân.
👉📝 Hãy cập nhật đoạn mã thực hiện lệnh gọi ban đầu để tạo đề xuất kế hoạch. Trong cùng tệp introvertally.py
, hãy thay thế #REPLACE ME Query remote agent get plan
bằng đoạn mã sau. Đoạn mã này dùng ứng dụng agent_engine để gửi yêu cầu của người dùng:
agent_engine.stream_query(
user_id=user_id,
message=prompt_message,
)
👉📝 Tiếp theo, hãy cập nhật mã xử lý việc xác nhận của người dùng (ví dụ: khi người dùng nhấp vào "Xác nhận kế hoạch"). Thao tác này sẽ gửi một thông báo tiếp theo đến cùng một cuộc trò chuyện trên Agent Engine, hướng dẫn Orchestrator tiếp tục đăng sự kiện (sự kiện này sẽ được uỷ quyền cho tác nhân Tích hợp nền tảng). Thay thế #REPLACE ME Query remote agent for confirmation
để xác nhận trong introvertally.py
bằng:
agent_engine.stream_query(
user_id=agent_session_user_id,
message=prompt_message,
)
Các tuyến đường của ứng dụng web cần có quyền truy cập vào các chức năng này. Đảm bảo các hàm cần thiết từ introvertally.py được nhập vào tệp tuyến đường Flask.
👉📝 Trong cd ~/instavibe-bootstrap/instavibe/ally_routes.py
, trước tiên, chúng ta sẽ chỉ đến bản sao thay thế # REPLACE ME TO ADD IMPORT
bằng nội dung sau:
from introvertally import call_agent_for_plan, post_plan_event
👉📝 Thêm tính năng nguyên mẫu vào InstaVibe, trong ~/instavibe-bootstrap/instavibe/templates/base.html
, hãy thay thế <!–REPLACE_ME_LINK_TO_INTROVERT_ALLY–> bằng nội dung sau:
<li class="nav-item">
<a class="nav-link" href="{{ url_for('ally.introvert_ally_page') }}">Introvert Ally</a>
</li>
Trước khi có thể triển khai lại ứng dụng InstaVibe, chúng tôi cần Resource ID
cụ thể của tác nhân Orchestrator mà chúng tôi đã triển khai cho Agent Engine.
Hiện tại, việc truy xuất mã này theo phương thức lập trình thông qua gcloud
có thể bị hạn chế, vì vậy, chúng ta sẽ dùng một tập lệnh Python trợ giúp (temp-endpoint.py
được cung cấp trong hội thảo) để tìm nạp mã nhận dạng và lưu trữ mã đó trong một biến môi trường.
👉💻 Chạy các lệnh sau để thực thi tập lệnh. Tập lệnh sẽ ghi lại Mã nhận dạng điểm cuối của công cụ đại lý và cấp các quyền cần thiết cho tài khoản dịch vụ mặc định của công cụ đại lý (Lưu ý: Tập lệnh được định cấu hình để sử dụng tài khoản dịch vụ mặc định vì hiện tại người dùng không thể sửa đổi tài khoản này).
. ~/instavibe-bootstrap/set_env.sh
cd ~/instavibe-bootstrap/instavibe/
source ~/instavibe-bootstrap/env/bin/activate
python temp-endpoint.py
export ORCHESTRATE_AGENT_ID=$(cat temp_endpoint.txt)
echo "ORCHESTRATE_AGENT_ID set to: ${ORCHESTRATE_AGENT_ID}"
Cuối cùng, chúng ta cần triển khai lại ứng dụng web InstaVibe bằng mã đã cập nhật và biến môi trường ORCHESTRATE_AGENT_ID
mới để ứng dụng biết cách kết nối với tác nhân đang chạy trên Agent Engine.
👉💻 Các lệnh sau đây sẽ tạo lại hình ảnh ứng dụng InstaVibe và triển khai phiên bản mới lên Cloud Run:
. ~/instavibe-bootstrap/set_env.sh
cd ~/instavibe-bootstrap/instavibe/
export IMAGE_TAG="latest"
export APP_FOLDER_NAME="instavibe"
export IMAGE_NAME="instavibe-webapp"
export IMAGE_PATH="${REGION}-docker.pkg.dev/${PROJECT_ID}/${REPO_NAME}/${IMAGE_NAME}:${IMAGE_TAG}"
export SERVICE_NAME="instavibe"
echo "Building ${APP_FOLDER_NAME} webapp image..."
gcloud builds submit . \
--tag=${IMAGE_PATH} \
--project=${PROJECT_ID}
echo "Deploying ${SERVICE_NAME} to Cloud Run..."
gcloud run deploy ${SERVICE_NAME} \
--image=${IMAGE_PATH} \
--platform=managed \
--region=${REGION} \
--allow-unauthenticated \
--set-env-vars="SPANNER_INSTANCE_ID=${SPANNER_INSTANCE_ID}" \
--set-env-vars="SPANNER_DATABASE_ID=${SPANNER_DATABASE_ID}" \
--set-env-vars="APP_HOST=0.0.0.0" \
--set-env-vars="APP_PORT=8080" \
--set-env-vars="GOOGLE_CLOUD_LOCATION=${REGION}" \
--set-env-vars="GOOGLE_CLOUD_PROJECT=${PROJECT_ID}" \
--set-env-vars="GOOGLE_MAPS_API_KEY=${GOOGLE_MAPS_API_KEY}" \
--set-env-vars="ORCHESTRATE_AGENT_ID=${ORCHESTRATE_AGENT_ID}" \
--project=${PROJECT_ID} \
--min-instances=1 \
--cpu=2 \
--memory=2Gi
Sau khi hoàn tất quá trình triển khai cuối cùng, hãy chuyển đến URL ứng dụng InstaVibe trong một thẻ trình duyệt khác.
Thử nghiệm trải nghiệm InstaVibe đầy đủ dựa trên AI
Tính năng "InstaVibe Ally" hiện đã ra mắt, được hỗ trợ bởi hệ thống đa tác nhân của chúng tôi, được điều phối thông qua Vertex AI Agent Engine và giao tiếp thông qua A2A.
Nhấp vào "InstaVibe Ally" rồi yêu cầu công cụ này lên kế hoạch cho một sự kiện.
Quan sát nhật ký hoạt động ở bên phải trong khi các đặc vụ làm việc (có thể mất từ 90 đến 120 giây). Sau khi kế hoạch xuất hiện, hãy xem xét kế hoạch đó rồi nhấp vào "Xác nhận kế hoạch này" để tiếp tục đăng.
Giờ đây, trình điều phối sẽ hướng dẫn tác nhân Nền tảng tạo bài đăng và sự kiện trong InstaVibe.
Kiểm tra trang chủ InstaVibe để xem bài đăng và sự kiện mới.
Trang sự kiện sẽ phản ánh thông tin chi tiết do nhân viên hỗ trợ tạo.
Phân tích hiệu suất bằng Cloud Trace
Bạn có thể nhận thấy quá trình này mất một khoảng thời gian. Vertex AI Agent Engine tích hợp với Cloud Trace, cho phép chúng tôi phân tích độ trễ của hệ thống nhiều tác nhân.
Chuyển đến Traces (Dấu vết) trong bảng điều khiển Google Cloud, chọn agent_run[orchestrate_agent]
trong Span (Khoảng), bạn sẽ thấy một vài Span, hãy nhấp vào đó
Trong phần thông tin chi tiết về dấu vết, bạn có thể xác định những phần mất nhiều thời gian hơn. Ví dụ: các lệnh gọi đến tác nhân Lập kế hoạch có thể cho thấy độ trễ cao hơn do việc tìm kiếm cơ sở và tạo nội dung phức tạp.
Tương tự, khi tạo bài đăng và sự kiện, bạn có thể thấy thời gian mà Orchestrator đã dành để xử lý dữ liệu và chuẩn bị các lệnh gọi công cụ cho tác nhân Nền tảng.
Việc khám phá những dấu vết này giúp bạn hiểu rõ và tối ưu hoá hiệu suất của hệ thống tác nhân.
Xin chúc mừng! Bạn đã xây dựng, triển khai và thử nghiệm thành công một hệ thống AI đa tác nhân phức tạp bằng cách sử dụng ADK, A2A, MCP và các dịch vụ của Google Cloud. Bạn đã giải quyết được vấn đề điều phối tác nhân, sử dụng công cụ, quản lý trạng thái và triển khai trên đám mây, đồng thời tạo ra một tính năng dựa trên AI hoạt động hiệu quả cho InstaVibe. Chúc mừng bạn đã hoàn thành buổi hội thảo này!
13. Dọn dẹp
Để tránh bị tính phí liên tục cho tài khoản Google Cloud của bạn, bạn cần xoá các tài nguyên mà chúng tôi đã tạo trong hội thảo này. Các lệnh sau đây sẽ giúp bạn xoá phiên bản Spanner, các dịch vụ Cloud Run, kho lưu trữ Artifact Registry, Khoá API, Vertex AI Agent Engine và các quyền IAM được liên kết.
Quan trọng:
- Đảm bảo bạn đang chạy các lệnh này trong cùng một dự án trên Google Cloud được dùng cho hội thảo.
- Nếu bạn đã đóng thiết bị đầu cuối Cloud Shell, một số biến môi trường như $PROJECT_ID, $SPANNER_INSTANCE_ID, v.v. có thể chưa được đặt. Bạn sẽ cần xuất lại các biến này như khi thiết lập hội thảo hoặc thay thế các biến trong các lệnh bên dưới bằng giá trị thực tế của chúng.
- Các lệnh này sẽ xoá vĩnh viễn tài nguyên của bạn. Kiểm tra kỹ trước khi chạy nếu bạn có dữ liệu quan trọng khác trong dự án này.
👉💻 Chạy các tập lệnh sau để dọn dẹp.
Đặt lại các biến môi trường
. ~/instavibe-bootstrap/set_env.sh
Xoá công cụ nhân viên hỗ trợ:
cd ~/instavibe-bootstrap/utils
source ~/instavibe-bootstrap/env/bin/activate
export ORCHESTRATE_AGENT_ID=$(cat ~/instavibe-bootstrap/instavibe/temp_endpoint.txt)
echo "ORCHESTRATE_AGENT_ID set to: ${ORCHESTRATE_AGENT_ID}"
python remote_delete.py
deactivate
echo "Vertex AI Agent Engine deletion initiated."
Xoá dịch vụ Cloud Run:
# InstaVibe Web Application
gcloud run services delete instavibe --platform=managed --region=${REGION} --project=${PROJECT_ID} --quiet
# MCP Tool Server
gcloud run services delete mcp-tool-server --platform=managed --region=${REGION} --project=${PROJECT_ID} --quiet
# Planner Agent (A2A Server)
gcloud run services delete planner-agent --platform=managed --region=${REGION} --project=${PROJECT_ID} --quiet
# Platform MCP Client Agent (A2A Server)
gcloud run services delete platform-mcp-client --platform=managed --region=${REGION} --project=${PROJECT_ID} --quiet
# Social Agent (A2A Server)
gcloud run services delete social-agent --platform=managed --region=${REGION} --project=${PROJECT_ID} --quiet
echo "Cloud Run services deletion initiated."
Dừng và xoá vùng chứa Docker A2A Inspector
docker rm --force a2a-inspector
Xoá đối tượng Spanner:
echo "Deleting Spanner instance: ${SPANNER_INSTANCE_ID}..."
gcloud spanner instances delete ${SPANNER_INSTANCE_ID} --project=${PROJECT_ID} --quiet
echo "Spanner instance deletion initiated."
Xoá kho lưu trữ Artifact Registry:
echo "Deleting Artifact Registry repository: ${REPO_NAME}..."
gcloud artifacts repositories delete ${REPO_NAME} --location=${REGION} --project=${PROJECT_ID} --quiet
echo "Artifact Registry repository deletion initiated."
Xoá vai trò khỏi tài khoản dịch vụ:
echo "Removing roles from service account: $SERVICE_ACCOUNT_NAME in project $PROJECT_ID"
# Remove Project-level roles for default service account
gcloud projects remove-iam-policy-binding $PROJECT_ID \
--member="serviceAccount:$SERVICE_ACCOUNT_NAME" \
--role="roles/spanner.admin"
gcloud projects remove-iam-policy-binding $PROJECT_ID \
--member="serviceAccount:$SERVICE_ACCOUNT_NAME" \
--role="roles/spanner.databaseUser"
gcloud projects remove-iam-policy-binding $PROJECT_ID \
--member="serviceAccount:$SERVICE_ACCOUNT_NAME" \
--role="roles/artifactregistry.admin"
gcloud projects remove-iam-policy-binding $PROJECT_ID \
--member="serviceAccount:$SERVICE_ACCOUNT_NAME" \
--role="roles/cloudbuild.builds.editor"
gcloud projects remove-iam-policy-binding $PROJECT_ID \
--member="serviceAccount:$SERVICE_ACCOUNT_NAME" \
--role="roles/run.admin"
gcloud projects remove-iam-policy-binding $PROJECT_ID \
--member="serviceAccount:$SERVICE_ACCOUNT_NAME" \
--role="roles/iam.serviceAccountUser"
gcloud projects remove-iam-policy-binding $PROJECT_ID \
--member="serviceAccount:$SERVICE_ACCOUNT_NAME" \
--role="roles/aiplatform.user"
gcloud projects remove-iam-policy-binding $PROJECT_ID \
--member="serviceAccount:$SERVICE_ACCOUNT_NAME" \
--role="roles/logging.logWriter"
gcloud projects remove-iam-policy-binding $PROJECT_ID \
--member="serviceAccount:$SERVICE_ACCOUNT_NAME" \
--role="roles/logging.viewer"
echo "All specified roles have been removed."
Xoá tệp Workshop trên máy:
echo "Removing local workshop directory ~/instavibe-bootstrap..."
rm -rf ~/instavibe-bootstrap
rm -rf ~/a2a-inspector
rm -f ~/mapkey.txt
rm -f ~/project_id.txt
echo "Local directory removed."