生成式模型可有效解決許多類型的問題。但這類方法受到下列限制的限制:
- 這些模型會在訓練後凍結,導致知識過時。
- 但無法查詢或修改外部資料。
函式呼叫可協助您克服部分限制。函式呼叫有時也稱為「工具使用」,因為這項功能可讓模型使用 API 和函式等外部工具,產生最終回應。
您可以在 Google Cloud 說明文件中進一步瞭解函式呼叫,包括函式呼叫的用途實用清單。
所有 Gemini 型號 (Gemini 1.0 型號除外) 都支援函式呼叫模式。
本指南說明如何實作函式呼叫設定,類似於本頁下一節所述的範例。大致來說,以下是設定應用程式中函式呼叫的步驟:
編寫函式,為模型提供產生最終回應所需的資訊 (例如,函式可以呼叫外部 API)。
建立函式宣告,說明函式及其參數。
在模型初始化期間提供函式宣告,讓模型知道如何在必要時使用函式。
設定應用程式,讓模型可傳送必要資訊,以便應用程式呼叫函式。
將函式的回應傳回模型,以便模型產生最終回應。
函式呼叫範例總覽
向模型傳送要求時,您也可以為模型提供一組「工具」(例如函式),讓模型用於產生最終回應。為了使用這些函式並進行呼叫 (稱為「函式呼叫」),模型和應用程式需要彼此來回傳遞資訊,因此建議您透過多回合即時通訊介面使用函式呼叫功能。
假設您有一個應用程式,使用者可以輸入類似以下的提示:What was the weather in Boston on October 17, 2024?
。
Gemini 模型可能不知道這項天氣資訊,但假設您知道有可提供這項資訊的外部天氣服務 API。您可以使用函式呼叫,為 Gemini 模型提供該 API 和天氣資訊的路徑。
首先,您要在應用程式中編寫函式 fetchWeather
,與這個假設的外部 API 互動,該 API 具有以下輸入和輸出:
參數 | 類型 | 必要 | 說明 |
---|---|---|---|
輸入 | |||
location |
物件 | 是 | 要取得天氣資訊的城市名稱和州名。 僅支援美國境內的城市。必須一律為 city 和 state 的巢狀物件。 |
date |
字串 | 是 | 擷取天氣資料的日期 (必須一律採用 YYYY-MM-DD 格式)。 |
輸出 | |||
temperature |
整數 | 是 | 溫度 (華氏) |
chancePrecipitation |
字串 | 是 | 降雨/降雪機率 (以百分比表示) |
cloudConditions |
字串 | 是 | Cloud 條件 (clear 、partlyCloudy 、mostlyCloudy 、cloudy 其中之一)
|
初始化模型時,您會告知模型這個 fetchWeather
函式存在,以及如何在必要時使用該函式處理傳入的要求。這稱為「函式宣告」。模型不會直接呼叫函式。相反地,當模型處理傳入的要求時,會決定 fetchWeather
函式是否可協助回應要求。如果模型判斷函式確實有用,就會產生結構化資料,協助應用程式呼叫函式。
再次查看收到的要求:What was the weather in Boston on October 17, 2024?
。模型很可能會判斷 fetchWeather
函式可協助產生回覆。模型會查看 fetchWeather
需要哪些輸入參數,然後為函式產生大致如下所示的結構化輸入資料:
{
functionName: fetchWeather,
location: {
city: Boston,
state: Massachusetts // the model can infer the state from the prompt
},
date: 2024-10-17
}
模型會將這項結構化輸入資料傳遞至您的應用程式,以便應用程式呼叫 fetchWeather
函式。當應用程式從 API 接收天氣狀況時,就會將資訊傳遞給模型。這項天氣資訊可讓模型完成最終處理作業,並針對 What was the weather in Boston on October 17, 2024?
的初始要求產生回應
模型可能會提供最終的自然語言回應,例如:
On October 17, 2024, in Boston, it was 38 degrees Fahrenheit with partly cloudy skies.
實作函式呼叫
事前準備
如果您尚未完成,請參閱入門指南,瞭解如何設定 Firebase 專案、將應用程式連結至 Firebase、新增 SDK、初始化 Vertex AI 服務,以及建立 GenerativeModel
例項。
本指南的其餘步驟會說明如何實作函式呼叫設定,類似於「函式呼叫範例簡介」(請參閱本頁頂端部分) 所述的工作流程。
您可以在本頁稍後的部分查看此函式呼叫範例的完整程式碼範例。
步驟 1:編寫函式
假設您有一個應用程式,使用者可以輸入類似以下的提示:What was the weather in Boston on October 17, 2024?
。Gemini 模型可能不知道這項天氣資訊,但假設您知道有可提供這項資訊的外部天氣服務 API。本指南的範例會依賴這個假設的外部 API。
在應用程式中編寫函式,讓函式與假設的外部 API 互動,並為模型提供產生最終要求所需的資訊。在這個天氣範例中,會是 fetchWeather
函式呼叫這個假設的外部 API。
Swift
// This function calls a hypothetical external API that returns
// a collection of weather information for a given location on a given date.
func fetchWeather(city: String, state: String, date: String) -> JSONObject {
// TODO(developer): Write a standard function that would call an external weather API.
// For demo purposes, this hypothetical response is hardcoded here in the expected format.
return [
"temperature": .number(38),
"chancePrecipitation": .string("56%"),
"cloudConditions": .string("partlyCloudy"),
]
}
Kotlin
// This function calls a hypothetical external API that returns
// a collection of weather information for a given location on a given date.
// `location` is an object of the form { city: string, state: string }
data class Location(val city: String, val state: String)
suspend fun fetchWeather(location: Location, date: String): JsonObject {
// TODO(developer): Write a standard function that would call to an external weather API.
// For demo purposes, this hypothetical response is hardcoded here in the expected format.
return JsonObject(mapOf(
"temperature" to JsonPrimitive(38),
"chancePrecipitation" to JsonPrimitive("56%"),
"cloudConditions" to JsonPrimitive("partlyCloudy")
))
}
Java
// This function calls a hypothetical external API that returns
// a collection of weather information for a given location on a given date.
// `location` is an object of the form { city: string, state: string }
public JsonObject fetchWeather(Location location, String date) {
// TODO(developer): Write a standard function that would call to an external weather API.
// For demo purposes, this hypothetical response is hardcoded here in the expected format.
return new JsonObject(Map.of(
"temperature", JsonPrimitive(38),
"chancePrecipitation", JsonPrimitive("56%"),
"cloudConditions", JsonPrimitive("partlyCloudy")));
}
Web
// This function calls a hypothetical external API that returns
// a collection of weather information for a given location on a given date.
// `location` is an object of the form { city: string, state: string }
async function fetchWeather({ location, date }) {
// TODO(developer): Write a standard function that would call to an external weather API.
// For demo purposes, this hypothetical response is hardcoded here in the expected format.
return {
temperature: 38,
chancePrecipitation: "56%",
cloudConditions: "partlyCloudy",
};
}
Dart
// This function calls a hypothetical external API that returns
// a collection of weather information for a given location on a given date.
// `location` is an object of the form { city: string, state: string }
Future<Map<String, Object?>> fetchWeather(
Location location, String date
) async {
// TODO(developer): Write a standard function that would call to an external weather API.
// For demo purposes, this hypothetical response is hardcoded here in the expected format.
final apiResponse = {
'temperature': 38,
'chancePrecipitation': '56%',
'cloudConditions': 'partlyCloudy',
};
return apiResponse;
}
步驟 2:建立函式宣告
建立稍後會提供給模型的函式宣告 (本指南的下一個步驟)。
在宣告中,請盡可能在函式及其參數的說明中加入詳細資料。
模型會使用函式宣告中的資訊,判斷要選取哪個函式,以及如何為實際函式呼叫提供參數值。請參閱本頁後續的其他行為和選項,瞭解模型如何在函式之間做出選擇,以及如何控管這項選擇。
請注意下列提供的結構定義事項:
您必須以與 OpenAPI 結構定義相容的結構定義格式提供函式宣告。Vertex AI 僅提供部分 OpenAPI 結構定義支援。
支援的屬性如下:
type
、nullable
、required
、format
、description
、properties
、items
、enum
。系統不支援下列屬性:
default
、optional
、maximum
、oneOf
。
根據預設,對於 Vertex AI in Firebase SDK,除非您在
optionalProperties
陣列中將所有欄位指定為選用欄位,否則系統會將所有欄位視為必要欄位。對於這些選填欄位,模型可以填入欄位或略過欄位。請注意,這與 Gemini API in Vertex AI 的預設行為相反。
如要瞭解函式宣告的最佳做法,包括名稱和說明的提示,請參閱 Google Cloud 說明文件中的「最佳做法」。
以下說明如何編寫函式宣告:
Swift
let fetchWeatherTool = FunctionDeclaration(
name: "fetchWeather",
description: "Get the weather conditions for a specific city on a specific date.",
parameters: [
"location": .object(
properties: [
"city": .string(description: "The city of the location."),
"state": .string(description: "The US state of the location."),
],
description: """
The name of the city and its state for which to get the weather. Only cities in the
USA are supported.
"""
),
"date": .string(
description: """
The date for which to get the weather. Date must be in the format: YYYY-MM-DD.
"""
),
]
)
Kotlin
val fetchWeatherTool = FunctionDeclaration(
"fetchWeather",
"Get the weather conditions for a specific city on a specific date.",
mapOf(
"location" to Schema.obj(
mapOf(
"city" to Schema.string("The city of the location."),
"state" to Schema.string("The US state of the location."),
),
description = "The name of the city and its state for which " +
"to get the weather. Only cities in the " +
"USA are supported."
),
"date" to Schema.string("The date for which to get the weather." +
" Date must be in the format: YYYY-MM-DD."
),
),
)
Java
FunctionDeclaration fetchWeatherTool = new FunctionDeclaration(
"fetchWeather",
"Get the weather conditions for a specific city on a specific date.",
Map.of("location",
Schema.obj(Map.of(
"city", Schema.str("The city of the location."),
"state", Schema.str("The US state of the location."))),
"date",
Schema.str("The date for which to get the weather. " +
"Date must be in the format: YYYY-MM-DD.")),
Collections.emptyList());
Web
const fetchWeatherTool = {
functionDeclarations: [
{
name: "fetchWeather",
description:
"Get the weather conditions for a specific city on a specific date",
parameters: Schema.object({
properties: {
location: Schema.object({
description:
"The name of the city and its state for which to get " +
"the weather. Only cities in the USA are supported.",
properties: {
city: Schema.string(
description: "The city of the location."
),
state: Schema.string(
description: "The US state of the location."
),
},
}),
date: Schema.string({
description:
"The date for which to get the weather. Date must be in the" +
" format: YYYY-MM-DD.",
}),
},
}),
},
],
};
Dart
final fetchWeatherTool = FunctionDeclaration(
'fetchWeather',
'Get the weather conditions for a specific city on a specific date.',
parameters: {
'location': Schema.object(
description:
'The name of the city and its state for which to get'
'the weather. Only cities in the USA are supported.',
properties: {
'city': Schema.string(
description: 'The city of the location.'
),
'state': Schema.string(
description: 'The US state of the location.'
),
},
),
'date': Schema.string(
description:
'The date for which to get the weather. Date must be in the format: YYYY-MM-DD.'
),
},
);
步驟 3:在模型初始化期間提供函式宣告
您最多可在要求中提供 128 個函式宣告。請參閱本頁稍後的其他行為和選項,瞭解模型如何在函式之間進行選擇,以及如何控制該選擇 (使用 toolConfig
設定函式呼叫模式)。
Swift
import FirebaseVertexAI
// Initialize the Vertex AI service and the generative model.
let model = VertexAI.vertexAI().generativeModel(
modelName: "gemini-2.0-flash",
// Provide the function declaration to the model.
tools: [.functionDeclarations([fetchWeatherTool])]
)
Kotlin
// Initialize the Vertex AI service and the generative model
val model = Firebase.vertexAI.generativeModel(
modelName = "gemini-2.0-flash",
// Provide the function declaration to the model.
tools = listOf(Tool.functionDeclarations(listOf(fetchWeatherTool)))
)
Java
// Initialize the Vertex AI service and the generative model
// Use a model that supports function calling, like a Gemini 1.5 model
GenerativeModelFutures model = GenerativeModelFutures.from(
FirebaseVertexAI.getInstance()
.generativeModel("gemini-1.5-flash",
null,
null,
// Provide the function declaration to the model.
List.of(Tool.functionDeclarations(List.of(fetchWeatherTool)))));
Web
import { initializeApp } from "firebase/app";
import { getVertexAI, getGenerativeModel } from "firebase/vertexai";
// TODO(developer) Replace the following with your app's Firebase configuration
// See: https://firebase.google.com/docs/web/learn-more#config-object
const firebaseConfig = {
// ...
};
// Initialize FirebaseApp
const firebaseApp = initializeApp(firebaseConfig);
// Initialize the Vertex AI service
const vertexAI = getVertexAI(firebaseApp);
// Initialize the generative model
const model = getGenerativeModel(vertexAI, {
model: "gemini-2.0-flash",
// Provide the function declaration to the model.
tools: fetchWeatherTool
});
Dart
import 'package:firebase_vertexai/firebase_vertexai.dart';
import 'package:firebase_core/firebase_core.dart';
await Firebase.initializeApp();
// Initialize the Vertex AI service and the generative model.
_functionCallModel = FirebaseVertexAI.instance.generativeModel(
model: 'gemini-2.0-flash',
// Provide the function declaration to the model.
tools: [
Tool.functionDeclarations([fetchWeatherTool]),
],
);
步驟 4:呼叫函式以叫用外部 API
如果模型判斷 fetchWeather
函式確實可協助產生最終回應,則應用程式需要使用模型提供的結構化輸入資料,實際呼叫該函式。
由於資訊需要在模型和應用程式之間來回傳遞,因此建議您透過多輪對話介面使用函式呼叫。
以下程式碼片段說明如何告知應用程式模型想要使用 fetchWeather
函式。這也表示模型已為函式呼叫 (及其基礎外部 API) 提供必要的輸入參數值。
在這個例子中,傳入的要求包含提示 What was the weather in Boston on October 17, 2024?
。根據這個提示,模型推斷出 fetchWeather
函式所需的輸入參數 (即 city
、state
和 date
)。
Swift
let chat = model.startChat()
let prompt = "What was the weather in Boston on October 17, 2024?"
// Send the user's question (the prompt) to the model using multi-turn chat.
let response = try await chat.sendMessage(prompt)
var functionResponses = [FunctionResponsePart]()
// When the model responds with one or more function calls, invoke the function(s).
for functionCall in response.functionCalls {
if functionCall.name == "fetchWeather" {
// TODO(developer): Handle invalid arguments.
guard case let .object(location) = functionCall.args["location"] else { fatalError() }
guard case let .string(city) = location["city"] else { fatalError() }
guard case let .string(state) = location["state"] else { fatalError() }
guard case let .string(date) = functionCall.args["date"] else { fatalError() }
functionResponses.append(FunctionResponsePart(
name: functionCall.name,
// Forward the structured input data prepared by the model
// to the hypothetical external API.
response: fetchWeather(city: city, state: state, date: date)
))
}
// TODO(developer): Handle other potential function calls, if any.
}
Kotlin
val prompt = "What was the weather in Boston on October 17, 2024?"
val chat = model.startChat()
// Send the user's question (the prompt) to the model using multi-turn chat.
val result = chat.sendMessage(prompt)
val functionCalls = result.functionCalls
// When the model responds with one or more function calls, invoke the function(s).
val fetchWeatherCall = functionCalls.find { it.name == "fetchWeather" }
// Forward the structured input data prepared by the model
// to the hypothetical external API.
val functionResponse = fetchWeatherCall?.let {
// Alternatively, if your `Location` class is marked as @Serializable, you can use
// val location = Json.decodeFromJsonElement<Location>(it.args["location"]!!)
val location = Location(
it.args["location"]!!.jsonObject["city"]!!.jsonPrimitive.content,
it.args["location"]!!.jsonObject["state"]!!.jsonPrimitive.content
)
val date = it.args["date"]!!.jsonPrimitive.content
fetchWeather(location, date)
}
Java
String prompt = "What was the weather in Boston on October 17, 2024?";
ChatFutures chatFutures = model.startChat();
// Send the user's question (the prompt) to the model using multi-turn chat.
ListenableFuture<GenerateContentResponse> response =
chatFutures.sendMessage(new Content("user", List.of(new TextPart(prompt))));
ListenableFuture<JsonObject> handleFunctionCallFuture = Futures.transform(response, result -> {
for (FunctionCallPart functionCall : result.getFunctionCalls()) {
if (functionCall.getName().equals("fetchWeather")) {
Map<String, JsonElement> args = functionCall.getArgs();
JsonObject locationJsonObject =
JsonElementKt.getJsonObject(args.get("location"));
String city =
JsonElementKt.getContentOrNull(
JsonElementKt.getJsonPrimitive(
locationJsonObject.get("city")));
String state =
JsonElementKt.getContentOrNull(
JsonElementKt.getJsonPrimitive(
locationJsonObject.get("state")));
Location location = new Location(city, state);
String date = JsonElementKt.getContentOrNull(
JsonElementKt.getJsonPrimitive(
args.get("date")));
return fetchWeather(location, date);
}
}
return null;
}, Executors.newSingleThreadExecutor());
Web
const chat = model.startChat();
const prompt = "What was the weather in Boston on October 17, 2024?";
// Send the user's question (the prompt) to the model using multi-turn chat.
let result = await chat.sendMessage(prompt);
const functionCalls = result.response.functionCalls();
let functionCall;
let functionResult;
// When the model responds with one or more function calls, invoke the function(s).
if (functionCalls.length > 0) {
for (const call of functionCalls) {
if (call.name === "fetchWeather") {
// Forward the structured input data prepared by the model
// to the hypothetical external API.
functionResult = await fetchWeather(call.args);
functionCall = call;
}
}
}
Dart
final chat = _functionCallModel.startChat();
const prompt = 'What was the weather in Boston on October 17, 2024?';
// Send the user's question (the prompt) to the model using multi-turn chat.
var response = await chat.sendMessage(Content.text(prompt));
final functionCalls = response.functionCalls.toList();
// When the model responds with one or more function calls, invoke the function(s).
if (functionCalls.isNotEmpty) {
final functionCall = functionCalls.first;
if (functionCall.name == 'fetchWeather') {
// Forward the structured input data prepared by the model
// to the hypothetical external API.
Map<String, dynamic> location =
functionCall.args['location']! as Map<String, dynamic>;
var date = functionCall.args['date']! as String;
var city = location['city']! as String;
var state = location['state']! as String;
final functionResult = await fetchWeather(Location(city, state), date);
...
} else {
throw UnimplementedError(
'Function not declared to the model: ${functionCall.name}',
);
}
步驟 5:將函式輸出內容提供給模型,以產生最終回覆
fetchWeather
函式傳回天氣資訊後,應用程式需要將資訊傳回模型。
接著,模型會執行最終處理作業,並產生最終的自然語言回應,例如:On October 17, 2024 in Boston, it was 38 degrees Fahrenheit with partly cloudy skies.
Swift
// Send the response(s) from the function back to the model
// so that the model can use it to generate its final response.
let finalResponse = try await chat.sendMessage(
[ModelContent(role: "function", parts: functionResponses)]
)
// Log the text response.
print(finalResponse.text ?? "No text in response.")
Kotlin
// Send the response(s) from the function back to the model
// so that the model can use it to generate its final response.
val finalResponse = chat.sendMessage(content("function") {
part(FunctionResponsePart("fetchWeather", functionResponse!!))
})
// Log the text response.
println(finalResponse.text ?: "No text in response")
Java
ListenableFuture<GenerateContentResponse> modelResponseFuture = Futures.transformAsync(
handleFunctionCallFuture,
// Send the response(s) from the function back to the model
// so that the model can use it to generate its final response.
functionCallResult -> chatFutures.sendMessage(new Content("function",
List.of(new FunctionResponsePart(
"fetchWeather", functionCallResult)))),
Executors.newSingleThreadExecutor());
Futures.addCallback(modelResponseFuture, new FutureCallback<GenerateContentResponse>() {
@Override
public void onSuccess(GenerateContentResponse result) {
if (result.getText() != null) {
// Log the text response.
System.out.println(result.getText());
}
}
@Override
public void onFailure(Throwable t) {
// handle error
}
}, Executors.newSingleThreadExecutor());
Web
// Send the response from the function back to the model
// so that the model can use it to generate its final response.
result = await chat.sendMessage([
{
functionResponse: {
name: functionCall.name, // "fetchWeather"
response: functionResult,
},
},
]);
console.log(result.response.text());
Dart
// Send the response from the function back to the model
// so that the model can use it to generate its final response.
response = await chat
.sendMessage(Content.functionResponse(functionCall.name, functionResult));
其他行為和選項
以下是您需要在程式碼中納入的函式呼叫其他行為,以及可控制的選項。
模型可能會要求再次呼叫函式或其他函式。
如果單一函式呼叫的回應不足以讓模型產生最終回應,模型可能會要求額外的函式呼叫,或要求呼叫完全不同的函式。後者只有在您在函式宣告清單中為模型提供多個函式時才會發生。
您的應用程式必須支援模型可能要求的額外函式呼叫。
模型可能會要求同時呼叫多個函式。
您可以在函式宣告清單中為模型提供最多 128 個函式。因此,模型可能會判斷需要多個函式才能產生最終回覆。並可能決定同時呼叫其中部分函式,這稱為平行函式呼叫。
您的應用程式必須能夠因應模型可能同時要求執行多個函式,並且需要將函式提供的所有回應傳回模型。
您可以控制模型是否可以要求呼叫函式,以及呼叫函式的做法。
您可以設定一些限制,規範模型應如何使用提供的函式宣告,以及是否應使用這些宣告。這稱為設定函式呼叫模式。例如:
您可以強制模型一律使用函式呼叫,而非允許模型選擇立即的自然語言回應和函式呼叫。這稱為強制函式呼叫。
如果您提供多個函式宣告,可以限制模型只使用提供的函式子集。
您可以透過新增工具設定 (toolConfig
) 以及提示和函式宣告,實作這些限制 (或模式)。在工具設定中,您可以指定下列任一模式。最實用的模式是 ANY
。
眾數 | 說明 |
---|---|
AUTO |
預設模型行為。模型會決定是否使用函式呼叫或自然語言回覆。 |
ANY |
模型必須使用函式呼叫 (「強制函式呼叫」)。如要將模型限制為部分函式,請在 allowedFunctionNames 中指定允許的函式名稱。 |
NONE |
模型不得使用函式呼叫。這項行為等同於模型要求,但沒有任何相關的函式宣告。 |
其他功能
試用其他功能
瞭解如何控管內容產生作業
- 瞭解提示設計,包括最佳做法、策略和提示範例。
- 設定模型參數,例如溫度參數和輸出符記數量上限 (適用於 Gemini),或顯示比例和人物生成 (適用於 Imagen)。
- 使用安全性設定,調整可能會收到有害回應的機率。
進一步瞭解支援的型號
瞭解可用於各種用途的模型,以及相關配額和價格。針對使用 Vertex AI in Firebase 的體驗提供意見回饋