نحوه استفاده از Cloud Run با فراخوانی عملکرد Gemini

1. مقدمه

نمای کلی

در این لبه کد، خواهید دید که چگونه می توانید با استفاده از یک ویژگی جدید به نام Function Calling به Gemini دسترسی به داده های بلادرنگ بدهید. برای شبیه‌سازی داده‌های زمان واقعی، یک نقطه پایانی سرویس آب‌وهوا ایجاد می‌کنید که آب و هوای فعلی را برای ۲ مکان برمی‌گرداند. سپس یک برنامه چت ایجاد می‌کنید که توسط Gemini پشتیبانی می‌شود، که از فراخوانی عملکرد برای بازیابی آب و هوای فعلی استفاده می‌کند.

بیایید از یک تصویر سریع برای درک فراخوانی تابع استفاده کنیم.

  • درخواست های سریع برای مکان های آب و هوای فعلی در یک مکان مشخص
  • این دستور + قرارداد تابع ()getWeather به Gemini ارسال می شود
  • Gemini از برنامه ربات چت درخواست می کند که از طرف خود "getWeather(Seattle)" را صدا کند.
  • برنامه نتایج را ارسال می کند (40 درجه فارنهایت و بارانی)
  • جمینی نتایج را برای تماس گیرنده برمی گرداند

به طور خلاصه، Gemini تابع را صدا نمی کند. شما به‌عنوان توسعه‌دهنده باید تابع را فراخوانی کرده و نتایج را به Gemini ارسال کنید.

نمودار جریان فراخوانی تابع

چیزی که یاد خواهید گرفت

  • فراخوانی تابع Gemini چگونه کار می کند
  • نحوه استقرار یک برنامه چت بات مجهز به Gemini به عنوان یک سرویس Cloud Run

2. راه اندازی و الزامات

پیش نیازها

  • شما به کنسول Cloud وارد شده اید.
  • شما قبلاً یک تابع نسل دوم را مستقر کرده اید. برای مثال، می‌توانید برای شروع، استقرار یک راه‌اندازی سریع نسل دوم Cloud Function را دنبال کنید.

Cloud Shell را فعال کنید

  1. از Cloud Console، روی Activate Cloud Shell کلیک کنید d1264ca30785e435.png .

cb81e7c8e34bc8d.png

اگر این اولین باری است که Cloud Shell را راه اندازی می کنید، با یک صفحه میانی روبرو می شوید که آن را توصیف می کند. اگر با یک صفحه میانی مواجه شدید، روی Continue کلیک کنید.

d95252b003979716.png

تهیه و اتصال به Cloud Shell فقط باید چند لحظه طول بکشد.

7833d5e1c5d18f54.png

این ماشین مجازی با تمام ابزارهای توسعه مورد نیاز بارگذاری شده است. این یک فهرست اصلی 5 گیگابایتی دائمی ارائه می‌کند و در Google Cloud اجرا می‌شود، که عملکرد و احراز هویت شبکه را بسیار افزایش می‌دهد. بسیاری از کارهای شما، اگر نه همه، در این کد لبه با مرورگر قابل انجام است.

پس از اتصال به Cloud Shell، باید ببینید که احراز هویت شده اید و پروژه به ID پروژه شما تنظیم شده است.

  1. برای تایید احراز هویت، دستور زیر را در Cloud Shell اجرا کنید:
gcloud auth list

خروجی فرمان

 Credentialed Accounts
ACTIVE  ACCOUNT
*       <my_account>@<my_domain.com>

To set the active account, run:
    $ gcloud config set account `ACCOUNT`
  1. دستور زیر را در Cloud Shell اجرا کنید تا تأیید کنید که دستور gcloud از پروژه شما اطلاع دارد:
gcloud config list project

خروجی فرمان

[core]
project = <PROJECT_ID>

اگر اینطور نیست، می توانید آن را با این دستور تنظیم کنید:

gcloud config set project <PROJECT_ID>

خروجی فرمان

Updated property [core/project].

3. متغیرهای محیط را راه اندازی کنید و API ها را فعال کنید

تنظیم متغیرهای محیطی

می توانید متغیرهای محیطی را تنظیم کنید که در سراسر این کد لبه مورد استفاده قرار می گیرند.

PROJECT_ID=<YOUR_PROJECT_ID>
REGION=<YOUR_REGION, e.g. us-central1>
WEATHER_SERVICE=weatherservice
FRONTEND=frontend
SERVICE_ACCOUNT="vertex-ai-caller"
SERVICE_ACCOUNT_ADDRESS=$SERVICE_ACCOUNT@$PROJECT_ID.iam.gserviceaccount.com

API ها را فعال کنید

قبل از اینکه بتوانید از این کد لبه استفاده کنید، چندین API وجود دارد که باید آنها را فعال کنید. این آزمایشگاه کد نیاز به استفاده از API های زیر دارد. با اجرای دستور زیر می توانید آن API ها را فعال کنید:

gcloud services enable run.googleapis.com \
    cloudbuild.googleapis.com \
    aiplatform.googleapis.com

4. یک حساب کاربری برای تماس با Vertex AI ایجاد کنید

این حساب سرویس توسط Cloud Run برای فراخوانی Vertex AI Gemini API استفاده خواهد شد.

ابتدا با اجرای این دستور اکانت سرویس ایجاد کنید:

gcloud iam service-accounts create $SERVICE_ACCOUNT \
  --display-name="Cloud Run to access Vertex AI APIs"

دوم، نقش Vertex AI User را به حساب سرویس اختصاص دهید.

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

5. سرویس Cloud Run را ایجاد کنید

ابتدا یک دایرکتوری برای کد منبع و سی دی در آن دایرکتوری ایجاد کنید.

mkdir -p gemini-function-calling/weatherservice gemini-function-calling/frontend && cd gemini-function-calling/weatherservice

سپس یک فایل package.json با محتوای زیر ایجاد کنید:

{
    "name": "weatherservice",
    "version": "1.0.0",
    "description": "",
    "main": "app.js",
    "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1"
    },
    "keywords": [],
    "author": "",
    "license": "ISC",
    "dependencies": {
        "express": "^4.18.3"
    }
}

سپس یک فایل منبع app.js با محتوای زیر ایجاد کنید. این فایل حاوی نقطه ورود سرویس و حاوی منطق اصلی برنامه است.

const express = require("express");
const app = express();

app.get("/getweather", (req, res) => {
    const location = req.query.location;
    let temp, conditions;

    if (location == "New Orleans") {
        temp = 99;
        conditions = "hot and humid";
    } else if (location == "Seattle") {
        temp = 40;
        conditions = "rainy and overcast";
    } else {
        res.status(400).send("there is no data for the requested location");
    }

    res.json({
        weather: temp,
        location: location,
        conditions: conditions
    });
});

const port = parseInt(process.env.PORT) || 8080;
app.listen(port, () => {
    console.log(`weather service: listening on port ${port}`);
});

app.get("/", (req, res) => {
    res.send("welcome to hard-coded weather!");
});

سرویس آب و هوا را مستقر کنید

می توانید از این دستور برای استقرار سرویس آب و هوا استفاده کنید.

gcloud run deploy $WEATHER_SERVICE \
  --source . \
  --region $REGION \
  --allow-unauthenticated

سرویس هواشناسی را تست کنید

می‌توانید آب و هوای ۲ مکان را با استفاده از curl تأیید کنید:

WEATHER_SERVICE_URL=$(gcloud run services describe $WEATHER_SERVICE \
              --platform managed \
              --region=$REGION \
              --format='value(status.url)')

curl $WEATHER_SERVICE_URL/getweather?location=Seattle

curl $WEATHER_SERVICE_URL/getweather?location\=New%20Orleans

سیاتل 40 درجه فارنهایت و بارانی و نیواورلئان 99 درجه فارنهایت و همیشه مرطوب است.

6. سرویس Frontend را ایجاد کنید

ابتدا سی دی را وارد فهرست فرانت اند کنید.

cd gemini-function-calling/frontend

سپس یک فایل package.json با محتوای زیر ایجاد کنید:

{
  "name": "demo1",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "start": "node app.js",
    "nodemon": "nodemon app.js",
    "cssdev": "npx tailwindcss -i ./input.css -o ./public/output.css --watch",
    "tailwind": "npx tailwindcss -i ./input.css -o ./public/output.css",
    "dev": "npm run tailwind && npm run nodemon"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "dependencies": {
    "@google-cloud/vertexai": "^0.4.0",
    "axios": "^1.6.7",
    "express": "^4.18.2",
    "express-ws": "^5.0.2",
    "htmx.org": "^1.9.10"
  },
  "devDependencies": {
    "nodemon": "^3.1.0",
    "tailwindcss": "^3.4.1"
  }
}

سپس یک فایل منبع app.js با محتوای زیر ایجاد کنید. این فایل حاوی نقطه ورود سرویس و حاوی منطق اصلی برنامه است.

const express = require("express");
const app = express();
app.use(express.urlencoded({ extended: true }));
app.use(express.json());
const path = require("path");

const fs = require("fs");
const util = require("util");
const { spinnerSvg } = require("./spinnerSvg.js");

const expressWs = require("express-ws")(app);

app.use(express.static("public"));

const {
    VertexAI,
    FunctionDeclarationSchemaType
} = require("@google-cloud/vertexai");

// get project and location from metadata service
const metadataService = require("./metadataService.js");

// instance of Gemini model
let generativeModel;

// 1: define the function
const functionDeclarations = [
    {
        function_declarations: [
            {
                name: "getweather",
                description: "get weather for a given location",
                parameters: {
                    type: FunctionDeclarationSchemaType.OBJECT,
                    properties: {
                        location: {
                            type: FunctionDeclarationSchemaType.STRING
                        },
                        degrees: {
                            type: FunctionDeclarationSchemaType.NUMBER,
                            "description":
                                "current temperature in fahrenheit"
                        },
                        conditions: {
                            type: FunctionDeclarationSchemaType.STRING,
                            "description":
                                "how the weather feels subjectively"
                        }
                    },
                    required: ["location"]
                }
            }
        ]
    }
];

// on instance startup
const port = parseInt(process.env.PORT) || 8080;
app.listen(port, async () => {
    console.log(`demo1: listening on port ${port}`);

    const project = await metadataService.getProjectId();
    const location = await metadataService.getRegion();

    // Vertex client library instance
    const vertex_ai = new VertexAI({
        project: project,
        location: location
    });

    // Instantiate models
    generativeModel = vertex_ai.getGenerativeModel({
        model: "gemini-1.0-pro-001"
    });
});

const axios = require("axios");
const baseUrl = "https://weatherservice-k6msmyp47q-uc.a.run.app";

app.ws("/sendMessage", async function (ws, req) {

    // this chat history will be pinned to the current 
    // Cloud Run instance. Consider using Firestore &
    // Firebase anonymous auth instead.

    // start ephemeral chat session with Gemini
    const chatWithModel = generativeModel.startChat({
        tools: functionDeclarations
    });

    ws.on("message", async function (message) {
        let questionToAsk = JSON.parse(message).message;
        console.log("WebSocket message: " + questionToAsk);

        ws.send(`<div hx-swap-oob="beforeend:#toupdate"><div
                        id="questionToAsk"
                        class="text-black m-2 text-right border p-2 rounded-lg ml-24">
                        ${questionToAsk}
                    </div></div>`);

        // to simulate a natural pause in conversation
        await sleep(500);

        // get timestamp for div to replace
        const now = "fromGemini" + Date.now();

        ws.send(`<div hx-swap-oob="beforeend:#toupdate"><div
                        id=${now}
                        class=" text-blue-400 m-2 text-left border p-2 rounded-lg mr-24">
                        ${spinnerSvg}
                    </div></div>`);

        const results = await chatWithModel.sendMessage(questionToAsk);

        // Function calling demo
        let response1 = await results.response;
        let data = response1.candidates[0].content.parts[0];

        let methodToCall = data.functionCall;
        if (methodToCall === undefined) {
            console.log("Gemini says: ", data.text);
            ws.send(`<div
                        id=${now}
                        hx-swap-oob="true"
                        hx-swap="outerHTML"
                        class="text-blue-400 m-2 text-left border p-2 rounded-lg mr-24">
                        ${data.text}
                    </div>`);

            // bail out - Gemini doesn't want to return a function
            return;
        }

        // otherwise Gemini wants to call a function
        console.log(
            "Gemini wants to call: " +
                methodToCall.name +
                " with args: " +
                util.inspect(methodToCall.args, {
                    showHidden: false,
                    depth: null,
                    colors: true
                })
        );

        // make the external call
        let jsonReturned;
        try {
            const responseFunctionCalling = await axios.get(
                baseUrl + "/" + methodToCall.name,

                {
                    params: {
                        location: methodToCall.args.location
                    }
                }
            );
            jsonReturned = responseFunctionCalling.data;
        } catch (ex) {
            // in case an invalid location was provided
            jsonReturned = ex.response.data;
        }

        console.log("jsonReturned: ", jsonReturned);

        // tell the model what function we just called
        const functionResponseParts = [
            {
                functionResponse: {
                    name: methodToCall.name,
                    response: {
                        name: methodToCall.name,
                        content: { jsonReturned }
                    }
                }
            }
        ];

        // // Send a follow up message with a FunctionResponse
        const result2 = await chatWithModel.sendMessage(
            functionResponseParts
        );

        // This should include a text response from the model using the response content
        // provided above
        const response2 = await result2.response;
        let answer = response2.candidates[0].content.parts[0].text;
        console.log("answer: ", answer);

        ws.send(`<div
                        id=${now}
                        hx-swap-oob="true"
                        hx-swap="outerHTML"
                        class="text-blue-400 m-2 text-left border p-2 rounded-lg mr-24">
                        ${answer}
                    </div>`);
    });

    ws.on("close", () => {
        console.log("WebSocket was closed");
    });
});

function sleep(ms) {
    return new Promise((resolve) => {
        setTimeout(resolve, ms);
    });
}

یک فایل input.css برای tailwindCSS ایجاد کنید.

@tailwind base;
@tailwind components;
@tailwind utilities;

فایل tailwind.config.js را برای tailwindCSS ایجاد کنید.

/** @type {import('tailwindcss').Config} */
module.exports = {
    content: ["./**/*.{html,js}"],
    theme: {
        extend: {}
    },
    plugins: []
};

فایل metadataService.js را برای دریافت شناسه پروژه و منطقه برای سرویس Cloud Run ایجاد کنید. این مقادیر برای نمونه‌سازی نمونه‌ای از کتابخانه‌های کلاینت Vertex AI استفاده خواهند شد.

const your_project_id = "YOUR_PROJECT_ID";
const your_region = "YOUR_REGION";

const axios = require("axios");

module.exports = {
    getProjectId: async () => {
        let project = "";
        try {
            // Fetch the token to make a GCF to GCF call
            const response = await axios.get(
                "http://metadata.google.internal/computeMetadata/v1/project/project-id",
                {
                    headers: {
                        "Metadata-Flavor": "Google"
                    }
                }
            );

            if (response.data == "") {
                // running locally on Cloud Shell
                project = your_project_id;
            } else {
                // use project id from metadata service
                project = response.data;
            }
        } catch (ex) {
            // running locally on local terminal
            project = your_project_id;
        }

        return project;
    },

    getRegion: async () => {
        let region = "";
        try {
            // Fetch the token to make a GCF to GCF call
            const response = await axios.get(
                "http://metadata.google.internal/computeMetadata/v1/instance/region",
                {
                    headers: {
                        "Metadata-Flavor": "Google"
                    }
                }
            );

            if (response.data == "") {
                // running locally on Cloud Shell
                region = your_region;
            } else {
                // use region from metadata service
                let regionFull = response.data;
                const index = regionFull.lastIndexOf("/");
                region = regionFull.substring(index + 1);
            }
        } catch (ex) {
            // running locally on local terminal
            region = your_region;
        }
        return region;
    }
};

یک فایل به نام spinnerSvg.js ایجاد کنید

module.exports.spinnerSvg = `<svg class="animate-spin -ml-1 mr-3 h-5 w-5 text-blue-500"
                    xmlns="http://www.w3.org/2000/svg"
                    fill="none"
                    viewBox="0 0 24 24"
                >
                    <circle
                        class="opacity-25"
                        cx="12"
                        cy="12"
                        r="10"
                        stroke="currentColor"
                        stroke-width="4"
                    ></circle>
                    <path
                        class="opacity-75"
                        fill="currentColor"
                        d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
                    ></path></svg>`;

یک فهرست public جدید ایجاد کنید.

mkdir public
cd public

اکنون فایل index.html برای قسمت جلویی ایجاد کنید که از htmx استفاده می کند.

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta
            name="viewport"
            content="width=device-width, initial-scale=1.0"
        />
        <script
            src="https://unpkg.com/htmx.org@1.9.10"
            integrity="sha384-D1Kt99CQMDuVetoL1lrYwg5t+9QdHe7NLX/SoJYkXDFfX37iInKRy5xLSi8nO7UC"
            crossorigin="anonymous"
        ></script>

        <link href="./output.css" rel="stylesheet" />
        <script src="https://unpkg.com/htmx.org/dist/ext/ws.js"></script>

        <title>Demo 2</title>
    </head>
    <body>
        <div id="herewego" text-center>
            <!-- <div id="replaceme2" hx-swap-oob="true">Hello world</div> -->
            <div
                class="container mx-auto mt-8 text-center max-w-screen-lg"
            >
                <div
                    class="overflow-y-scroll bg-white p-2 border h-[500px] space-y-4 rounded-lg m-auto"
                >
                    <div id="toupdate"></div>
                </div>
                <form
                    hx-trigger="submit, keyup[keyCode==13] from:body"
                    hx-ext="ws"
                    ws-connect="/sendMessage"
                    ws-send=""
                    hx-on="htmx:wsAfterSend: document.getElementById('message').value = ''"
                >
                    <div class="mb-6 mt-6 flex gap-4">
                        <textarea
                            rows="2"
                            type="text"
                            id="message"
                            name="message"
                            class="block grow rounded-lg border p-6 resize-none"
                            required
                        >
What&apos;s is the current weather in Seattle?</textarea
                        >
                        <button
                            type="submit"
                            class="bg-blue-500 text-white px-4 py-2 rounded-lg text-center text-sm font-medium"
                        >
                            Send
                        </button>
                    </div>
                </form>
            </div>
        </div>
    </body>
</html>

7. سرویس Frontend را به صورت محلی اجرا کنید

ابتدا مطمئن شوید که در frontend پوشه کد لبه خود هستید.

cd .. && pwd

سپس با اجرای دستور زیر، وابستگی ها را نصب کنید:

npm install

استفاده از ADC هنگام اجرای محلی

اگر در Cloud Shell در حال اجرا هستید، در حال حاضر روی یک ماشین مجازی موتور محاسباتی گوگل کار می کنید. اعتبارنامه شما مرتبط با این ماشین مجازی (همانطور که با اجرای gcloud auth list نشان داده شده است) به طور خودکار توسط Application Default Credentials استفاده می شود، بنابراین لازم نیست از دستور gcloud auth application-default login استفاده کنید. می توانید به بخش اجرای برنامه به صورت محلی پرش کنید

با این حال، اگر در ترمینال محلی خود در حال اجرا هستید (یعنی نه در Cloud Shell)، باید از اعتبارنامه پیش فرض برنامه برای احراز هویت در API های Google استفاده کنید. شما می توانید 1) با استفاده از اطلاعات کاربری خود وارد شوید (به شرطی که هر دو نقش کاربر Vertex AI و کاربر Datastore را داشته باشید) یا 2) می توانید با جعل هویت حساب سرویس مورد استفاده در این Codelab وارد سیستم شوید.

گزینه 1) استفاده از اعتبارنامه خود برای ADC

اگر می‌خواهید از اعتبارنامه‌های خود استفاده کنید، می‌توانید ابتدا gcloud auth list را اجرا کنید تا نحوه احراز هویت خود را در gcloud تأیید کنید. در مرحله بعد، ممکن است لازم باشد به هویت خود نقش Vertex AI User را بدهید. اگر هویت شما دارای نقش مالک است، از قبل این نقش کاربری Vertex AI را دارید. اگر نه، می‌توانید این دستور را اجرا کنید تا به هویت خود، نقش کاربر Vertex AI و نقش کاربر Datastore را اعطا کنید.

USER=<YOUR_PRINCIPAL_EMAIL>

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

gcloud projects add-iam-policy-binding $PROJECT_ID \
  --member user:$USER \
  --role=roles/datastore.user

سپس دستور زیر را اجرا کنید

gcloud auth application-default login

گزینه 2) جعل هویت یک حساب سرویس برای ADC

اگر می‌خواهید از حساب سرویس ایجاد شده در این کد لبه استفاده کنید، حساب کاربری شما باید نقش ایجاد کننده رمز حساب سرویس را داشته باشد. با اجرای دستور زیر می توانید این نقش را بدست آورید:

gcloud projects add-iam-policy-binding $PROJECT_ID \
  --member user:$USER \
  --role=roles/iam.serviceAccountTokenCreator

در مرحله بعد، دستور زیر را برای استفاده از ADC با حساب سرویس اجرا می کنید

gcloud auth application-default login --impersonate-service-account=$SERVICE_ACCOUNT_ADDRESS

برنامه را به صورت محلی اجرا کنید

در نهایت، می توانید برنامه را با اجرای اسکریپت زیر راه اندازی کنید. این اسکریپت توسعه دهنده همچنین فایل output.css را از tailwindCSS تولید می کند.

npm run dev

با باز کردن دکمه Web Preview و انتخاب Preview Port 8080 می توانید پیش نمایش وب سایت را مشاهده کنید

پیش نمایش وب - پیش نمایش دکمه پورت 8080

8. سرویس Frontend را مستقر و آزمایش کنید

ابتدا این دستور را اجرا کنید تا استقرار شروع شود و حساب سرویس مورد استفاده را مشخص کنید. اگر یک حساب سرویس مشخص نشده باشد، از حساب پیش فرض سرویس محاسباتی استفاده می شود.

gcloud run deploy $FRONTEND \
  --service-account $SERVICE_ACCOUNT_ADDRESS \
  --source . \
  --region $REGION \
  --allow-unauthenticated

URL سرویس را برای قسمت جلویی در مرورگر خود باز کنید. یک سوال بپرسید "آب و هوای فعلی سیاتل چگونه است؟" و جوزا باید پاسخ دهد "در حال حاضر 40 درجه و باران است." اگر بپرسید "آب و هوای فعلی بوستون چگونه است؟"، Gemini با "من نمی توانم این درخواست را انجام دهم. API آب و هوای موجود داده ای برای بوستون ندارد" پاسخ می دهد.

9. تبریک می گویم!

برای تکمیل کد لبه تبریک می گویم!

توصیه می‌کنیم اسناد Cloud Run ، Vertex AI Gemini APIها و فراخوانی تابع را مرور کنید.

آنچه را پوشش داده ایم

  • فراخوانی تابع Gemini چگونه کار می کند
  • نحوه استقرار یک برنامه چت بات مجهز به Gemini به عنوان یک سرویس Cloud Run

10. پاکسازی کنید

برای جلوگیری از هزینه‌های غیرعمدی، (به عنوان مثال، اگر این سرویس Cloud Run سهواً بیشتر از تخصیص فراخوانی ماهانه Cloud Run در ردیف رایگان فراخوانی شود)، می‌توانید سرویس Cloud Run را حذف کنید یا پروژه‌ای را که در مرحله 2 ایجاد کرده‌اید حذف کنید.

برای حذف سرویس‌های Cloud Run، به کنسول Cloud Run Cloud در https://console.cloud.google.com/functions/ بروید و سرویس‌های $WEATHER_SERVICE و $FRONTEND را که در این آزمایشگاه ایجاد کرده‌اید حذف کنید.

همچنین ممکن است بخواهید حساب سرویس vertex-ai-caller حذف کنید یا نقش Vertex AI User را لغو کنید تا از تماس‌های غیرعمدی با Gemini جلوگیری کنید.

اگر تصمیم به حذف کل پروژه دارید، می‌توانید به https://console.cloud.google.com/cloud-resource-manager بروید، پروژه‌ای را که در مرحله ۲ ایجاد کرده‌اید انتخاب کنید و حذف را انتخاب کنید. اگر پروژه را حذف کنید، باید پروژه ها را در Cloud SDK خود تغییر دهید. با اجرای gcloud projects list می توانید لیست تمام پروژه های موجود را مشاهده کنید.