如何使用 Gemini 中的函数调用与 API 交互

1. 概览

什么是 Gemini 中的函数调用?

Vertex AI Gemini API 是 Google DeepMind 开发的一系列生成式 AI 模型,专为多模态应用场景而设计。函数调用是 Gemini 模型的一项功能,可让开发者更轻松地从生成模型中获取结构化数据输出。

然后,开发者可以使用这些输出来调用其他 API,并将相关响应数据返回给模型。换句话说,函数调用可帮助您将生成模型连接到外部系统,以便生成的内容包含最新且准确的信息。

函数调用的工作原理

函数使用函数声明进行描述,这有助于生成模型了解函数的用途和形参。将查询中的函数声明传递给生成模型后,模型会根据用户的查询返回一个结构化对象,其中包含相关函数的名称及其参数。请注意,对于函数调用,模型实际上并不会调用函数。相反,您可以使用返回的函数和参数,以您喜欢的任何语言、库或框架调用该函数!

API 接口

构建内容

在此 Codelab 中,您将使用 Vertex AI Gemini API 和 Python 构建生成式 AI 流水线。用户可以使用您的应用询问汇率信息,系统将从外部 API 获取最新数据,并向用户提供解答。

学习内容

  • 如何使用 Python 客户端库与 Gemini 模型交互
  • 如何定义函数声明并将其注册为工具
  • 如何调用 Gemini 并获取函数调用响应
  • 如何将函数响应返回给 Gemini 并响应用户

所需条件

2. 设置和要求

您需要先启用 Vertex AI API 并安装最新版本的 Vertex AI Python 客户端库,然后才能开始在 Gemini 中使用函数调用。

启用 Vertex AI API

如需启用 Vertex AI API,请按以下步骤操作:

  1. 在浏览器中,前往 Vertex AI API 服务详情页面
  2. 点击启用按钮,在您的 Google Cloud 项目中启用 Vertex AI API。

安装适用于 Vertex AI 的 Python 客户端库

如需安装适用于 Vertex AI 的 Python 客户端库,请按以下步骤操作:

  1. 在开发环境中打开一个终端。
  2. 验证您是否拥有有效的 Python 开发环境,并在需要时参阅这些指南
  3. 运行以下命令,安装适用于 Vertex AI 的 Python 客户端库:
    pip install --upgrade google-cloud-aiplatform
    
  4. 如果您在笔记本环境中运行,则可能需要重启运行时/内核才能使用新安装的软件包。

现在,您可以开始使用 Vertex AI API 了!

3. 了解问题

您是否遇到过以下情况:与大语言模型或生成式 AI 模型互动后,您向其询问实时信息或最新信息,但得到的回答却包含过时的信息或不准确的信息?

现在就试试吧!首先,我们将导入相关的 Python 软件包,并初始化 Gemini 模型。您可以在 Python 开发环境(如 ColabColab Enterprise)中运行以下代码,也可以通过安装最新版本的 Python 版 Vertex AI SDK 来运行以下代码:

import vertexai
from vertexai.generative_models import GenerativeModel
model = GenerativeModel("gemini-1.5-pro-001")

现在,我们来问一个有关今天不同货币的汇率的问题:

response = model.generate_content(
    "What's the exchange rate for euros to dollars today?"
)
print(response.text)

模型应该会为您生成有限或过时的回答,类似于以下内容:

As an AI language model, I don't have access to real-time currency exchange
rates. However, as of my last update in September 2021, the approximate exchange
rate between euros (EUR) and US dollars (USD) was:

1 EUR ≈ 1.18 USD

Please note that currency exchange rates constantly fluctuate and can vary
depending on various factors such as economic conditions, supply and demand,
political events, and more. To obtain the most up-to-date and accurate exchange
rate, I recommend using a reliable currency converter or financial website that
provides live rates.

[...]

如果最终用户收到此类响应,他们需要切换上下文,以查询他们感兴趣的货币、获取最新汇率,并自行执行任何转换。

理想情况下,生成模型流水线可以为用户处理部分或全部任务。在下一部分中,您将尝试从生成模型获取结构化响应的一些常见解决方法,以便调用外部系统。

4. 尝试常见的解决方法

在需要来自外部来源的最新信息或数据时使用生成模型时,您可以调用外部 API,然后将结果反馈给生成模型,供其在响应中使用。

在调用外部系统之前,您需要确定要使用的正确函数,从用户中提取相关参数,然后将这些参数放入结构化数据对象中。这通常涉及详尽的提示工程,以强制生成模型输出有效的结构化数据。

我们来回顾一下上一部分提出的问题,并为模型添加一些额外的说明。请尝试向 Gemini 模型发送以下请求:

user_prompt = "What's the exchange rate from euros to US dollars today?"

response = model.generate_content("""
Your task is to extract parameters from the user's input and return it as a
structured JSON payload. The user will ask about the exchange rate and which
currency they are converting from and converting to.

User input: {user_prompt}

Please extract the currencies as parameters and put them in a JSON object.
""".format(user_prompt=user_prompt))
print(response.text)

该结果是以下文本响应,该响应不是有效的 JSON,我们将难以使用:

```json
{
  "currency_from": "euros",
  "currency_to": "US dollars"
}
```

特别要指出的是,文本响应的第一行和最后一行包含用于分隔代码块的反引号,第一行包含语言说明符,而 JSON 对象中的值不是货币交换 API 期望用作输入参数的标准货币缩写(由三个字母组成)。

我们可以尝试使用 Python 将文本后处理为有效的 JSON 和字典,在提示中添加更多指令,提供一个或多个所需输出示例,微调模型,或者再次调用生成模型,要求它清理 JSON。

但有一种更确定的方法!我们来了解一下如何在 Gemini 中使用函数调用来查询外部服务中的信息,并将相关响应返回给最终用户。

5. 函数调用的工作原理

在开始进行参数提取和函数调用之前,我们先了解一下函数调用的步骤以及在运行时使用哪些组件。

Gemini 中的函数调用概览

Gemini API 的用户输入

用户的提示会发送到 Gemini API,在对 Gemini 模型的 API 调用中,开发者在工具中定义一个或多个函数声明,以便 Gemini 模型知道可以调用哪些函数以及如何调用它们。

Gemini API 会返回一个函数调用

根据用户输入的内容和提示,Gemini 将返回包含结构化数据的函数调用响应,结构化数据包括要调用的函数的名称以及要使用的相应参数。

发出 API 请求

然后,您将使用函数名称和参数发出 API 请求,以便从外部系统或 API 检索信息。此 API 请求和响应由开发者在应用代码中实现,不在 Gemini API 和 SDK 的范围发生。例如,您可以使用 Python 中的 requests 库来调用 REST API 并接收 JSON 响应。或者,您也可以使用首选方法和客户端库调用函数。

将 API 响应返回给 Gemini

最后,将 API 响应传递回 Gemini 模型,以便它针对最终用户的初始提示生成响应,或者在 Gemini 模型确定它需要其他信息时调用另一个函数调用响应。

6. 选择您的 API

现在,您已了解函数调用的总体流程和具体步骤,接下来您将构建一个生成式 AI 流水线来获取最新的货币汇率。首先,我们需要选择要用作信息来源的 API。

对于我们的货币兑换应用,我们将使用 REST API (https://www.frankfurter.app/) 来获取有关全球汇率的最新信息。

为了与此 REST API 进行交互,我们可能会在 Python 中使用 requests 进行 REST API 调用,如下所示:

import requests
url = "https://api.frankfurter.app/latest"
response = requests.get(url)
response.text

cURL 请求,例如:

curl https://api.frankfurter.app/latest

返回类似于以下内容的响应:

{
  "amount": 1,
  "base": "EUR",
  "date": "2023-12-20",
  "rates": {
    "AUD": 1.6186, "BGN": 1.9558, "BRL": 5.3287,
    "CAD": 1.4609, "CHF": 0.946, "CNY": 7.8121,
    "CZK": 24.538, "DKK": 7.4565, "GBP": 0.86555,
    "HKD": 8.5439, "HUF": 385.23, "IDR": 16994,
    "ILS": 3.9983, "INR": 91.06, "ISK": 150.3,
    "JPY": 157.12, "KRW": 1425.62, "MXN": 18.6867,
    "MYR": 5.0977, "NOK": 11.2895, "NZD": 1.7421,
    "PHP": 60.991, "PLN": 4.3413, "RON": 4.9699,
    "SEK": 11.129, "SGD": 1.4562, "THB": 38.252,
    "TRY": 31.883, "USD": 1.0944, "ZAR": 20.111
  }
}

由于 Gemini 中的函数调用实际上不会为您进行外部 API 调用,因此在您使用的 API 类型方面不存在此类限制!您可以使用 Cloud Run 服务、Cloud Functions 函数、对 Google Cloud 服务的 API 请求或任何外部 REST API。

7. 定义函数和工具

您已经选择了要使用的 REST API,现在我们可以定义 API 规范并在工具中注册函数。

确保您已安装最新版本的 Python 版 Vertex AI SDK

然后,从 Python SDK 导入必要的模块并初始化 Gemini 模型:

from vertexai.generative_models import (
    Content,
    FunctionDeclaration,
    GenerativeModel,
    Part,
    Tool,
)

model = GenerativeModel("gemini-1.5-pro-001")

再次参考 REST API (https://api.frankfurter.app/),我们可以看到它接受以下输入参数:

参数

类型

说明

from

字符串

换算币种

to

字符串

要换算成的币种

date

字符串

获取汇率的日期

使用这些参数,此 REST API 的部分 OpenAPI 规范(YAML 格式)如下所示:

openapi: 3.0.0
info:
  title: Frankfurter Exchange Rate API
  description: This API provides current and historical exchange rates
  version: 1.0.0
servers:
  - url: https://api.frankfurter.app
paths:
  /{date}:
    get:
      summary: Get the latest currency exchange rates.
      parameters:
        - name: date
          in: path
          description: Get currency rates for a specific date or 'latest' if a date is not specified
          required: true
          schema:
            type: string
        - name: from
          in: query
          description: The currency to convert from.
          required: true
          schema:
            type: string
        - name: to
          in: query
          description: The currency to convert to.
          schema:
            type: string

现在,使用适用于 Gemini 的 Python SDK 将其注册为 FunctionDeclaration

get_exchange_rate_func = FunctionDeclaration(
    name="get_exchange_rate",
    description="Get the exchange rate for currencies between countries",
    parameters={
    "type": "object",
    "properties": {
        "currency_date": {
            "type": "string",
            "description": "A date that must always be in YYYY-MM-DD format or the value 'latest' if a time period is not specified"
        },
        "currency_from": {
            "type": "string",
            "description": "The currency to convert from in ISO 4217 format"
        },
        "currency_to": {
            "type": "string",
            "description": "The currency to convert to in ISO 4217 format"
        }
    },
         "required": [
            "currency_from",
            "currency_date",
      ]
  },
)

务必在函数和参数说明中使用尽可能多的细节,因为生成模型将使用这些信息来确定要选择的函数以及如何在函数调用中填充参数。

最后,您将定义一个包含函数声明的 Tool

exchange_rate_tool = Tool(
    function_declarations=[get_exchange_rate_func],
)

在这里,您在工具中使用了一个函数声明,但请注意,您可以在工具中注册一个或多个函数声明,并且模型将选择在运行时使用的适当函数。请参阅有关 Gemini API 中的函数调用的文档,详细了解 FunctionDeclarationTool 以及 Python 版 Gemini SDK 中的相关类。

您已完成函数和工具定义的配置。在下一部分中,我们将使用此工具调用生成模型,并返回函数调用,用于调用 REST API。

8. 生成函数调用

现在,您可以提示生成模型并添加您定义的 tool

prompt = """What is the exchange rate from Australian dollars to Swedish krona?
How much is 500 Australian dollars worth in Swedish krona?"""

response = model.generate_content(
    prompt,
    tools=[exchange_rate_tool],
)

我们来看一下响应对象:

print(response.candidates[0].content)

role: "model"
parts {
  function_call {
    name: "get_exchange_rate"
    args {
      fields {
        key: "currency_to"
        value {
          string_value: "SEK"
        }
      }
      fields {
        key: "currency_from"
        value {
          string_value: "AUD"
        }
      }
      fields {
        key: "currency_date"
        value {
          string_value: "latest"
        }
      }
    }
  }
}

模型似乎选择了其中一个可用函数,并针对 get_exchange_rate 函数返回了函数调用以及形参。参数格式应符合我们想要的格式。太棒了,您通过生成模型获得了结构化回复!

在下一部分中,您将使用响应中的信息发出 API 请求。

9. 发出 API 请求

回想一下,Gemini 中的函数调用实际上并不会为您进行外部 API 调用。相反,您可以随意使用任何语言、库或框架!

在这里,您将使用 Python 中的 requests 库来调用汇率 REST API。

我们将响应解压缩到 Python 字典中:

params = {}
for key, value in response.candidates[0].content.parts[0].function_call.args.items():
    params[key[9:]] = value
params

现在,我们可以调用 requests 或任何其他方法:

import requests
url = f"https://api.frankfurter.app/{params['date']}"
api_response = requests.get(url, params=params)
api_response.text

返回类似于以下内容的响应:

'{"amount":1.0,"base":"AUD","date":"2024-01-16","rates":{"SEK":6.8682}}'

我们从 REST API 收到了响应,其中包含今天的最新汇率信息。在下一部分中,我们会将这些信息传递回模型,以便模型为用户生成相关的回答。

10. 生成回答

最后,让我们在下一轮对话中将函数响应传回模型,为用户生成响应:

response = model.generate_content(
    [
    Content(role="user", parts=[
        Part.from_text(prompt + """Give your answer in steps with lots of detail
            and context, including the exchange rate and date."""),
    ]),
    Content(role="function", parts=[
        Part.from_dict({
            "function_call": {
                "name": "get_exchange_rate",
            }
        })
    ]),
    Content(role="function", parts=[
        Part.from_function_response(
            name="get_exchange_rate",
            response={
                "content": api_response.text,
            }
        )
    ]),
    ],
    tools=[exchange_rate_tool],
)


response.candidates[0].content.parts[0].text

将函数响应传递回模型后,模型会对用户的提示以及 API 响应中的相关信息做出响应。

The exchange rate from Australian dollars to Swedish krona on January 16, 2024,
is 1 Australian dollar is equal to 6.8663 Swedish krona.

So, 500 Australian dollars would be worth 500 * 6.8663 = 3,433.15 Swedish krona.

11. 查看完整代码示例

此时,您可以使用 Cloud Run 服务、Cloud Functions 函数或其他 Cloud 服务将 Python 代码放入后端 API,并部署使用此后端 API 的前端应用来执行模型查询和 API 调用。

下面是我们最终解决方案的完整代码示例:

import requests
from vertexai.generative_models import (
    Content,
    FunctionDeclaration,
    GenerativeModel,
    Part,
    Tool,
)

model = GenerativeModel("gemini-1.5-pro-001")

get_exchange_rate_func = FunctionDeclaration(
    name="get_exchange_rate",
    description="Get the exchange rate for currencies between countries",
    parameters={
    "type": "object",
    "properties": {
        "currency_date": {
            "type": "string",
            "description": "A date that must always be in YYYY-MM-DD format or the value 'latest' if a time period is not specified"
        },
        "currency_from": {
            "type": "string",
            "description": "The currency to convert from in ISO 4217 format"
        },
        "currency_to": {
            "type": "string",
            "description": "The currency to convert to in ISO 4217 format"
        }
    },
         "required": [
            "currency_from",
            "currency_date",
      ]
  },
)

exchange_rate_tool = Tool(
    function_declarations=[get_exchange_rate_func],
)

prompt = """What is the exchange rate from Australian dollars to Swedish krona?
How much is 500 Australian dollars worth in Swedish krona?"""

response = model.generate_content(
    prompt,
    tools=[exchange_rate_tool],
)

response.candidates[0].content

params = {}
for key, value in response.candidates[0].content.parts[0].function_call.args.items():
    params[key[9:]] = value
params

import requests
url = f"https://api.frankfurter.app/{params['date']}"
api_response = requests.get(url, params=params)
api_response.text

response = model.generate_content(
    [
    Content(role="user", parts=[
        Part.from_text(prompt + """Give your answer in steps with lots of detail
            and context, including the exchange rate and date."""),
    ]),
    Content(role="function", parts=[
        Part.from_dict({
            "function_call": {
                "name": "get_exchange_rate",
            }
        })
    ]),
    Content(role="function", parts=[
        Part.from_function_response(
            name="get_exchange_rate",
            response={
                "content": api_response.text,
            }
        )
    ]),
    ],
    tools=[exchange_rate_tool],
)


response.candidates[0].content.parts[0].text

在此实现中,我们向生成模型使用了两个请求:一个请求用于生成函数调用,另一个请求用于返回函数响应。请注意,这只是使用 Gemini 处理函数调用和函数响应的一种方法。您还可以进行其他函数调用以获取查询的更多信息,或者将函数调用与聊天功能和异步方法结合使用。

如需查看其他代码示例,请参阅 Gemini 中函数调用的示例笔记本

12. 恭喜

通过在 Gemini 中使用函数调用,您已成功构建了与 Vertex AI Gemini API 和 Python 搭配使用的生成式 AI 流水线!用户可以询问汇率信息,系统将从外部 API 获取最新数据并给出回答。

根据最终用户的提示,Gemini 中的函数调用负责选择合适的函数,从提示中提取参数,并返回结构化数据对象供您进行外部 API 调用。

Gemini 中函数调用的设计旨在让你在确定性地提取参数方面做到两全其美,同时将摘要和内容创建工作交由生成模型完成。您可以随意试用流水线中的其他 API 和提示,以及探索与 Vertex AI Gemini API 相关的其他功能。

API 接口

清理

您可以执行以下清理操作,以避免因此 Codelab 中使用的资源向您的 Google Cloud 账号收取费用:

了解详情

通过以下指南和资源,继续了解对话式 AI 和生成式 AI:

许可

此作品已获得 Creative Commons Attribution 2.0 通用许可授权。