Cách kiểm thử cục bộ một tác nhân ADK ghi vào Google Trang tính trước khi triển khai lên Cloud Run

1. Giới thiệu

Tổng quan

Trong bài đăng này, bạn sẽ tạo một tác nhân Gemini bằng Bộ công cụ phát triển tác nhân (ADK) của Google và FastAPI. Trước khi triển khai, bạn sẽ định cấu hình Thông tin xác thực mặc định của ứng dụng (ADC) để kiểm thử cục bộ bằng cùng một tài khoản dịch vụ làm danh tính dịch vụ Cloud Run.

Để giao tiếp với Google Trang tính, ứng dụng của bạn cần có Mã truy cập OAuth với phạm vi thích hợp để truy cập vào bảng tính. Bạn sẽ tìm hiểu cách lấy mã truy cập này khi chạy cục bộ và trên Cloud Run bằng ADC:

  • Cục bộ: ADC tìm thông tin đăng nhập do lệnh gcloud auth application-default tạo. Bạn có thể tìm thêm thông tin tại đây
  • Trên Cloud Run: ADC sử dụng Máy chủ siêu dữ liệu để lấy thông tin đăng nhập. Bạn có thể tìm thêm thông tin tại đây.

Lưu ý về thuật ngữ:

Bạn có thể quen thuộc hơn với các thuật ngữ "giả định danh tính" hoặc "giả định cùng các quyền". Trong Google Cloud, việc mạo danh một tài khoản dịch vụ cho phép một thực thể đã xác thực truy cập vào mọi thứ mà tài khoản dịch vụ có thể truy cập. Chỉ những thực thể đã xác thực có các quyền thích hợp mới có thể mạo danh tài khoản dịch vụ. Bạn có thể đọc thêm tại đây https://docs.cloud.google.com/iam/docs/service-account-overview#impersonation

Kiến thức bạn sẽ học được

  • Cách định cấu hình Thông tin xác thực mặc định của ứng dụng (ADC) cho môi trường cục bộ
  • Cách tạo một tác nhân ADK có thể đọc và ghi vào một Trang tính của Google
  • Cách triển khai tác nhân lên Cloud Run

2. Thiết lập và yêu cầu

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

  • Bạn đã đăng nhập vào Cloud Console.
  • Bạn đã triển khai một dịch vụ Cloud Run trước đó. Ví dụ: bạn có thể làm theo hướng dẫn triển khai dịch vụ Cloud Run để bắt đầu.

Đặt các biến môi trường

Bạn có thể đặt các biến môi trường sẽ được sử dụng trong suốt lớp học lập trình này.

Bạn có thể tìm thấy Mã trang tính trong URL của Trang tính của Google khi sao chép đường liên kết Chia sẻ, ví dụ: https://docs.google.com/spreadsheets/d/YOUR_SPREADSHEET_ID/edit?usp=sharing

PROJECT_ID=<YOUR-PROJECT-ID>
REGION=<YOUR_REGION>
SPREADSHEET_ID=<YOUR_SPREADSHEET_ID>
SA_NAME=sheet-agent-sa
SERVICE_ACCOUNT_EMAIL=$SA_NAME@$PROJECT_ID.iam.gserviceaccount.com

Bật các API bắt buộc của Google Cloud

gcloud services enable \
  sheets.googleapis.com \
  aiplatform.googleapis.com \
  artifactregistry.googleapis.com \
  cloudbuild.googleapis.com \
  run.googleapis.com \
  logging.googleapis.com \
  --project=$PROJECT_ID

Tạo tài khoản dịch vụ

Trước tiên, hãy tạo Tài khoản dịch vụ bằng lệnh sau.

gcloud iam service-accounts create $SA_NAME \
    --description="Service account for spreadsheet agent codelab" \
    --display-name="Spreadsheet Agent Service Account" \
    --project=$PROJECT_ID

Tiếp theo, hãy cấp vai trò Người dùng Vertex AI cho Tài khoản dịch vụ (cần thiết cho các mô hình Gemini trên Vertex AI)

gcloud projects add-iam-policy-binding $PROJECT_ID \
    --member="serviceAccount:$SERVICE_ACCOUNT_EMAIL" \
    --role="roles/aiplatform.user"

Cấp cho danh tính gcloud của bạn quyền mạo danh Tài khoản dịch vụ (cần thiết cho quá trình phát triển cục bộ). Bạn có thể xem danh tính gcloud bằng cách chạy gcloud auth list

USER_EMAIL=$(gcloud config get-value account)

gcloud iam service-accounts add-iam-policy-binding $SERVICE_ACCOUNT_EMAIL \
    --member="user:$USER_EMAIL" \
    --role="roles/iam.serviceAccountTokenCreator" \
    --project=$PROJECT_ID
  1. Mở Trang tính của Google trong trình duyệt.
  2. Nhấp vào nút Chia sẻ.
  3. Dán email Tài khoản dịch vụ $SERVICE_ACCOUNT_EMAIL và cấp cho tài khoản này quyền Chỉnh sửa.

3. Tạo ứng dụng

Trước tiên, hãy tạo một thư mục cho mã nguồn và chuyển sang thư mục đó.

mkdir local-adk-sheets-codelab && cd $_

Sau đó, hãy tạo một tệp main.py có nội dung sau:

import os
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from google.auth import default
from googleapiclient.discovery import build
from google.adk.agents.llm_agent import Agent
from google.adk.runners import InMemoryRunner

# 1. Environment and Global Google Sheets Client Setup (ADC)
SPREADSHEET_ID = os.environ.get("SPREADSHEET_ID")
if not SPREADSHEET_ID:
    raise ValueError("SPREADSHEET_ID environment variable is missing. Please set it before running.")

credentials, _ = default(scopes=['https://www.googleapis.com/auth/spreadsheets'])
sheets_api = build('sheets', 'v4', credentials=credentials).spreadsheets()

# 2. Tools
def read_spreadsheet(range_name: str) -> dict:
    """Reads values from the Google Spreadsheet for a given range.
   
    Args:
        range_name: The A1 notation or R1C1 notation of the range to retrieve, e.g., 'Sheet1!A1:D10'.
    """
    return sheets_api.values().get(spreadsheetId=SPREADSHEET_ID, range=range_name).execute()

def update_spreadsheet(range_name: str, values: list[list[str]]) -> dict:
    """Updates the Google Spreadsheet range with the specified grid of values.
   
    Args:
        range_name: The A1 notation or R1C1 notation of the range to update, e.g., 'Sheet1!C2'.
        values: A list of lists of strings representing the grid of values to write.
    """
    return sheets_api.values().update(
        spreadsheetId=SPREADSHEET_ID,
        range=range_name,
        valueInputOption="USER_ENTERED",
        body={"values": values}
    ).execute()

# 3. Agent Definition
MODEL_NAME = os.environ.get("GEMINI_MODEL", "gemini-3.1-flash-lite")
root_agent = Agent(
    name="spreadsheet_agent",
    model=MODEL_NAME,
    instruction="""You are a helpful spreadsheet assistant.
    You can read and write to the user's Google Spreadsheet using the tools provided.
    Always use the appropriate tools when the user asks you to read or update a spreadsheet.
    When updating a range, make sure the values parameter is a list of lists (e.g. [[value]]).
    Be concise and helpful in your responses.""",
    description="An agent that can read and write to a specific Google Spreadsheet.",
    tools=[read_spreadsheet, update_spreadsheet]
)

# 4. FastAPI Application Setup
app = FastAPI()

class ChatRequest(BaseModel):
    prompt: str

@app.post("/chat")
async def chat_endpoint(request: ChatRequest):
    try:
        async with InMemoryRunner(app_name="sheets_agent_app", agent=root_agent) as runner:
            events = await runner.run_debug(request.prompt, quiet=True)
           
            # Extract the final response text
            texts = [
                "".join(p.text for p in e.content.parts if p.text)
                for e in reversed(events) if e.content and e.content.parts
            ]
            return {"response": next((t for t in texts if t), "No response from agent.")}
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

Tiếp theo, hãy tạo một tệp requirements.txt có nội dung sau:

fastapi>=0.100.0
uvicorn>=0.22.0
google-adk>=1.27.1
google-auth
google-api-python-client

4. Kiểm thử dịch vụ cục bộ

gcloud auth application-default login --impersonate-service-account=$SERVICE_ACCOUNT_EMAIL
GOOGLE_GENAI_USE_VERTEXAI=1 GOOGLE_CLOUD_PROJECT=$PROJECT_ID SPREADSHEET_ID=$SPREADSHEET_ID uvicorn main:app --host 0.0.0.0 --port 8080

Bây giờ, hãy kiểm thử tác nhân của bạn từ một thiết bị đầu cuối khác:

curl -X POST http://localhost:8080/chat \
    -H "Content-Type: application/json" \
    -d '{"prompt": "Update spreadsheet '$SPREADSHEET_ID' at range Sheet1!A1 with the value hello world"}'

Máy chủ sẽ phản hồi: {"response":"The spreadsheet at Sheet1!A1 has been updated with the value \"hello world\"."}

5. Triển khai lên Cloud Run

Bây giờ bạn đã biết tài khoản dịch vụ của mình có các quyền thích hợp để truy cập vào bảng tính, bạn sẽ triển khai lên Cloud Run bằng tài khoản dịch vụ làm danh tính dịch vụ.

gcloud run deploy local-adk-sheets-codelab \
    --source . \
    --region=$REGION \
    --set-env-vars GOOGLE_GENAI_USE_VERTEXAI=1,GOOGLE_CLOUD_PROJECT=$PROJECT_ID,GOOGLE_CLOUD_LOCATION=global,SPREADSHEET_ID=$SPREADSHEET_ID \
    --service-account $SERVICE_ACCOUNT_EMAIL \
    --no-allow-unauthenticated \
    --project=$PROJECT_ID

Khi quá trình triển khai hoàn tất, hãy gửi lời nhắc đến dịch vụ Cloud Run.

# Retrieve the Service URL
SERVICE_URL=$(gcloud run services describe local-adk-sheets-codelab --region $REGION --format 'value(status.url)')
curl -X POST $SERVICE_URL/chat \
    -H "Authorization: bearer $(gcloud auth print-identity-token)" \
    -H "Content-Type: application/json" \
    -d '{"prompt": "Update spreadsheet '$SPREADSHEET_ID' at range Sheet1!A1 with the value hello world"}'

Bạn sẽ nhận được phản hồi {"response":"OK. I've updated cell A1 in Sheet1 with \"hello world\"."}

Bây giờ hãy mở Trang tính của Google. Bạn sẽ thấy giá trị "hello world" trong ô đầu tiên.

6. Xin chúc mừng!

Chúc mừng bạn đã hoàn thành lớp học lập trình này!

Tiếp theo là gì?

Bạn nên khám phá tài liệu sau để mở rộng khả năng của tác nhân:

Nội dung chúng ta đã đề cập

  • Cách định cấu hình Thông tin xác thực mặc định của ứng dụng (ADC) cho môi trường cục bộ
  • Cách tạo một tác nhân ADK có thể đọc và ghi vào một Trang tính của Google
  • Cách triển khai tác nhân lên Cloud Run

7. Dọn dẹp

Để tránh bị tính phí ngoài ý muốn (ví dụ: nếu hàm Cloud Run này vô tình được gọi nhiều lần hơn hạn mức gọi Cloud Run hằng tháng của bạn trong gói miễn phí), bạn có thể xoá dịch vụ Cloud Run hoặc xoá dự án.

Để xoá một dịch vụ Cloud Run, hãy chuyển đến Cloud Run trong Cloud Console tại https://console.cloud.google.com/run/ rồi xoá dịch vụ local-adk-sheets-codelab mà bạn đã tạo trong lớp học lập trình này.

Nếu chọn xoá toàn bộ dự án, bạn có thể chuyển đến https://console.cloud.google.com/cloud-resource-manager, chọn dự án bạn đã tạo ở Bước 2 rồi chọn Xoá. Nếu bạn xoá dự án, bạn cần thay đổi dự án trong Cloud SDK. Bạn có thể xem danh sách tất cả các dự án hiện có bằng cách chạy gcloud projects list.