۱. مقدمه
نمای کلی
در این آزمایشگاه کد، خواهید دید که چگونه میتوانید با استفاده از یک ویژگی جدید به نام فراخوانی تابع ، به Gemini دسترسی به دادههای بلادرنگ بدهید. برای شبیهسازی دادههای بلادرنگ، یک نقطه پایانی سرویس آب و هوا خواهید ساخت که آب و هوای فعلی را برای ۲ مکان برمیگرداند. سپس یک برنامه چت، با پشتیبانی Gemini، خواهید ساخت که از فراخوانی تابع برای بازیابی آب و هوای فعلی استفاده میکند.
بیایید از یک مثال بصری سریع برای درک فراخوانی تابع استفاده کنیم.
- درخواستهای فوری برای مکانهای آب و هوایی فعلی در یک مکان مشخص
- این اعلان + قرارداد تابع برای getWeather() به Gemini ارسال میشود.
- Gemini درخواست میکند که برنامهی چتبات، دستور "getWeather(Seattle)" را از طرف خودش فراخوانی کند.
- برنامه نتایج را ارسال میکند (دمای ۴۰ درجه فارنهایت و هوای بارانی)
- جمینی نتایج را برای تماسگیرنده ارسال میکند
خلاصه اینکه، Gemini تابع را فراخوانی نمیکند. شما به عنوان توسعهدهنده باید تابع را فراخوانی کرده و نتایج را به Gemini ارسال کنید.

آنچه یاد خواهید گرفت
- نحوه فراخوانی تابع Gemini چگونه است؟
- نحوه استقرار یک برنامه چتبات مبتنی بر Gemini به عنوان یک سرویس Cloud Run
۲. تنظیمات و الزامات
پیشنیازها
- شما وارد کنسول ابری شدهاید.
- شما قبلاً یک تابع نسل دوم را مستقر کردهاید. برای مثال، میتوانید برای شروع ، راهنمای استقرار یک تابع ابری نسل دوم را دنبال کنید.
فعال کردن پوسته ابری
- از کنسول ابری، روی فعال کردن پوسته ابری کلیک کنید
.

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

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

این ماشین مجازی مجهز به تمام ابزارهای توسعه مورد نیاز است. این ماشین یک دایرکتوری خانگی پایدار ۵ گیگابایتی ارائه میدهد و در فضای ابری گوگل اجرا میشود که عملکرد شبکه و احراز هویت را تا حد زیادی افزایش میدهد. بخش عمدهای از کار شما در این آزمایشگاه کد، اگر نگوییم همه، را میتوان با یک مرورگر انجام داد.
پس از اتصال به Cloud Shell، باید ببینید که احراز هویت شدهاید و پروژه روی شناسه پروژه شما تنظیم شده است.
- برای تأیید احراز هویت، دستور زیر را در 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`
- دستور زیر را در Cloud Shell اجرا کنید تا تأیید کنید که دستور gcloud از پروژه شما اطلاع دارد:
gcloud config list project
خروجی دستور
[core] project = <PROJECT_ID>
اگر اینطور نیست، میتوانید با این دستور آن را تنظیم کنید:
gcloud config set project <PROJECT_ID>
خروجی دستور
Updated property [core/project].
۳. متغیرهای محیطی را تنظیم کنید و 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ها
قبل از اینکه بتوانید از این codelab استفاده کنید، باید چندین API را فعال کنید. این codelab به استفاده از APIهای زیر نیاز دارد. میتوانید با اجرای دستور زیر این APIها را فعال کنید:
gcloud services enable run.googleapis.com \
cloudbuild.googleapis.com \
aiplatform.googleapis.com
۴. یک حساب کاربری سرویس برای تماس با Vertex AI ایجاد کنید
این حساب کاربری سرویس توسط Cloud Run برای فراخوانی رابط برنامهنویسی کاربردی Vertex AI Gemini استفاده خواهد شد.
ابتدا، با اجرای این دستور، حساب کاربری سرویس را ایجاد کنید:
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
۵. سرویس Cloud Run بکاند را ایجاد کنید
ابتدا، یک دایرکتوری برای کد منبع ایجاد کنید و با دستور cd به آن دایرکتوری بروید.
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
سیاتل همیشه دمای ۴۰ درجه فارنهایت (۱۲ درجه سانتیگراد) و بارانی و نیواورلئان ۹۹ درجه فارنهایت (حدود ۹۹ درجه سانتیگراد) و رطوبت دارد.
۶. سرویس Frontend را ایجاد کنید
ابتدا، با دستور cd به دایرکتوری 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 را برای بخش کاربری (front end) ایجاد کنید که از 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'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>
۷. سرویس Frontend را به صورت محلی اجرا کنید
ابتدا مطمئن شوید که در دایرکتوری frontend مربوط به codelab خود هستید.
cd .. && pwd
سپس، با اجرای دستور زیر، وابستگیها را نصب کنید:
npm install
استفاده از ADC هنگام اجرای محلی
اگر در Cloud Shell اجرا میکنید، در حال حاضر روی یک ماشین مجازی Google Compute Engine در حال اجرا هستید. اعتبارنامههای شما که با این ماشین مجازی مرتبط هستند (همانطور که با اجرای gcloud auth list نشان داده شده است) به طور خودکار توسط Application Default Credentials استفاده میشوند، بنابراین نیازی به استفاده از دستور gcloud auth application-default login نیست. میتوانید به بخش Run the app locally بروید.
با این حال، اگر برنامه را روی ترمینال محلی خود اجرا میکنید (یعنی در Cloud Shell نیستید)، برای احراز هویت در APIهای گوگل باید از Application Default Credentials استفاده کنید. میتوانید ۱) با استفاده از اعتبارنامههای خود وارد شوید (به شرطی که هر دو نقش Vertex AI User و Datastore User را داشته باشید) یا ۲) میتوانید با جعل هویت حساب کاربری سرویس مورد استفاده در این codelab وارد شوید.
گزینه ۱) استفاده از اعتبارنامههایتان برای ADC
اگر میخواهید از اعتبارنامههای خود استفاده کنید، ابتدا میتوانید gcloud auth list اجرا کنید تا نحوه احراز هویت خود در gcloud را تأیید کنید. در مرحله بعد، ممکن است لازم باشد به هویت خود نقش Vertex AI User را اعطا کنید. اگر هویت شما نقش Owner را دارد، از قبل این نقش کاربری 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
گزینه ۲) جعل هویت یک حساب کاربری سرویس برای ADC
اگر میخواهید از حساب کاربری سرویس ایجاد شده در این codelab استفاده کنید، حساب کاربری شما باید نقش Service Account Token Creator را داشته باشد. میتوانید این نقش را با اجرای دستور زیر به دست آورید:
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
شما میتوانید با باز کردن دکمه پیشنمایش وب و انتخاب پیشنمایش پورت ۸۰۸۰، پیشنمایش وبسایت را مشاهده کنید.

۸. سرویس Frontend را مستقر و آزمایش کنید
ابتدا، این دستور را اجرا کنید تا استقرار شروع شود و حساب سرویس مورد استفاده را مشخص کنید. اگر حساب سرویس مشخص نشده باشد، از حساب سرویس محاسبه پیشفرض استفاده میشود.
gcloud run deploy $FRONTEND \ --service-account $SERVICE_ACCOUNT_ADDRESS \ --source . \ --region $REGION \ --allow-unauthenticated
آدرس اینترنتی سرویس را برای رابط کاربری در مرورگر خود باز کنید. سوالی بپرسید "هوای فعلی سیاتل چگونه است؟" و جمینی باید پاسخ دهد "در حال حاضر 40 درجه و بارانی است." اگر بپرسید "هوای فعلی بوستون چگونه است؟"، جمینی پاسخ خواهد داد "من نمیتوانم این درخواست را انجام دهم. API آب و هوای موجود، دادهای برای بوستون ندارد."
۹. تبریک میگویم!
تبریک میگویم که آزمایشگاه کد را تمام کردید!
توصیه میکنیم مستندات Cloud Run ، Vertex AI Gemini APIs و فراخوانی تابع را بررسی کنید.
آنچه ما پوشش دادهایم
- نحوه فراخوانی تابع Gemini چگونه است؟
- نحوه استقرار یک برنامه چتبات مبتنی بر Gemini به عنوان یک سرویس Cloud Run
۱۰. تمیز کردن
برای جلوگیری از هزینههای ناخواسته، (برای مثال، اگر این سرویس Cloud Run سهواً بیشتر از تخصیص فراخوانی ماهانه Cloud Run شما در سطح رایگان فراخوانی شود)، میتوانید سرویس Cloud Run یا پروژهای را که در مرحله 2 ایجاد کردهاید، حذف کنید.
برای حذف سرویسهای Cloud Run، به کنسول ابری Cloud Run در آدرس https://console.cloud.google.com/functions/ بروید و سرویسهای $WEATHER_SERVICE و $FRONTEND را که در این آزمایشگاه کد ایجاد کردهاید، حذف کنید.
همچنین میتوانید حساب کاربری سرویس vertex-ai-caller را حذف کنید یا نقش Vertex AI User را لغو کنید تا از هرگونه تماس ناخواسته با Gemini جلوگیری شود.
اگر تصمیم به حذف کل پروژه دارید، میتوانید به آدرس https://console.cloud.google.com/cloud-resource-manager بروید، پروژهای را که در مرحله ۲ ایجاد کردهاید انتخاب کنید و گزینه Delete را انتخاب کنید. اگر پروژه را حذف کنید، باید پروژهها را در Cloud SDK خود تغییر دهید. میتوانید با اجرای gcloud projects list لیست تمام پروژههای موجود را مشاهده کنید.