教程:函数调用

函数调用可让您更轻松地从生成模型获取结构化数据输出。然后,您可以使用这些输出来调用其他 API,并将相关响应数据返回给模型。换句话说,函数调用可帮助您将生成模型连接到外部系统,以便生成的内容包含最新、最准确的信息。

您可以向 Gemini 模型提供函数说明。这些函数是采用应用语言编写的函数(也就是说,它们不是 Google Cloud Functions 函数)。模型可能会要求您调用函数并发回结果,以帮助模型处理您的查询。

请参阅函数调用简介了解详情。 您还可以在 Google Colab 中试用此功能,或在 Gemini API 实战宝典代码库中查看示例代码。

照明控制示例 API

假设您有一个带应用编程接口 (API) 的基本照明控制系统,并且您希望允许用户通过简单的文本请求来控制灯。您可以使用函数调用功能解释来自用户的光照更改请求,并将其转换为 API 调用以设置光照值。通过这个假设的照明控制系统,您可以控制光的亮度及其色温,通过两个单独的参数来定义:

参数 类型 必需 说明
brightness number 光级范围为 0 到 100。0 表示关闭,100 表示完整亮度。
colorTemperature string 灯具的色温,可以是 daylightcoolwarm

为简单起见,这个假想的照明系统只有一个灯,因此用户不必指定房间或位置。下面是一个 JSON 请求示例,您可以将其发送到 Light Control API,以使用日光色温将光级更改为 50%:

{
  "brightness": "50",
  "colorTemperature": "daylight"
}

本教程介绍了如何为 Gemini API 设置函数调用,以解释用户的照明请求并将其映射到 API 设置,以控制灯的亮度和色温值。

准备工作:设置您的项目和 API 密钥

在调用 Gemini API 之前,您需要设置项目并配置 API 密钥。

定义 API 函数

创建一个发出 API 请求的函数。此函数应在应用的代码中定义,但可以在应用外部调用服务或 API。Gemini API 不会直接调用此函数,因此您可以通过应用代码控制此函数的执行方式和时间。为便于演示,本教程定义了一个模拟 API 函数,该函数仅返回请求的光照值:

def set_light_values(brightness, color_temp):
    """Set the brightness and color temperature of a room light. (mock API).

    Args:
        brightness: Light level from 0 to 100. Zero is off and 100 is full brightness
        color_temp: Color temperature of the light fixture, which can be `daylight`, `cool` or `warm`.

    Returns:
        A dictionary containing the set brightness and color temperature.
    """
    return {
        "brightness": brightness,
        "colorTemperature": color_temp
    }

创建供模型用于函数调用的函数时,您应该在函数和参数说明中包含尽可能多的详细信息。生成模型使用这些信息来确定要选择哪个函数以及如何为函数调用中的参数提供值。

在模型初始化期间声明函数

如果要对模型使用函数调用,必须在初始化模型对象时声明函数。您可以通过设置模型的 tools 参数来声明函数:

model = genai.GenerativeModel(model_name='gemini-1.5-flash',
                              tools=[set_light_values])

生成函数调用

使用函数声明初始化模型后,您可以使用定义的函数提示模型。您应该通过聊天提示 (sendMessage()) 使用函数调用,因为函数调用通常受益于先前提示和响应的上下文。

chat = model.start_chat()
response = chat.send_message('Dim the lights so the room feels cozy and warm.')
response.text

Python SDK 的 ChatSession 对象可为您处理对话历史记录,从而简化聊天会话的管理。您可以使用 enable_automatic_function_calling 自动让 SDK

# Create a chat session that automatically makes suggested function calls
chat = model.start_chat(enable_automatic_function_calling=True)

并行函数调用

除了上述基本函数调用外,您还可以在一次回合中调用多个函数。本部分举例说明了如何使用并行函数调用。

定义工具。

def power_disco_ball(power: bool) -> bool:
    """Powers the spinning disco ball."""
    print(f"Disco ball is {'spinning!' if power else 'stopped.'}")
    return True


def start_music(energetic: bool, loud: bool, bpm: int) -> str:
    """Play some music matching the specified parameters.

    Args:
      energetic: Whether the music is energetic or not.
      loud: Whether the music is loud or not.
      bpm: The beats per minute of the music.

    Returns: The name of the song being played.
    """
    print(f"Starting music! {energetic=} {loud=}, {bpm=}")
    return "Never gonna give you up."


def dim_lights(brightness: float) -> bool:
    """Dim the lights.

    Args:
      brightness: The brightness of the lights, 0.0 is off, 1.0 is full.
    """
    print(f"Lights are now set to {brightness:.0%}")
    return True

现在,使用一条指令来调用模型,该指令可以使用所有指定工具。

# Set the model up with tools.
house_fns = [power_disco_ball, start_music, dim_lights]

model = genai.GenerativeModel(model_name="gemini-1.5-flash", tools=house_fns)

# Call the API.
chat = model.start_chat()
response = chat.send_message("Turn this place into a party!")

# Print out each of the function calls requested from this single call.
for part in response.parts:
    if fn := part.function_call:
        args = ", ".join(f"{key}={val}" for key, val in fn.args.items())
        print(f"{fn.name}({args})")
power_disco_ball(power=True)
start_music(energetic=True, loud=True, bpm=120.0)
dim_lights(brightness=0.3)

输出的每条结果都反映了模型所请求的单个函数调用。要发回结果,请按请求的顺序包含响应。

# Simulate the responses from the specified tools.
responses = {
    "power_disco_ball": True,
    "start_music": "Never gonna give you up.",
    "dim_lights": True,
}

# Build the response parts.
response_parts = [
    genai.protos.Part(function_response=genai.protos.FunctionResponse(name=fn, response={"result": val}))
    for fn, val in responses.items()
]

response = chat.send_message(response_parts)
print(response.text)
Let's get this party started! I've turned on the disco ball, started playing some upbeat music, and dimmed the lights. 🎶✨  Get ready to dance! 🕺💃

函数调用数据类型映射

从 Python 函数中自动提取架构的功能并非在所有情况下都有效。例如:它不处理您描述嵌套的字典对象字段的情况,但该 API 支持此操作。该 API 能够描述以下任意类型:

AllowedType = (int | float | bool | str | list['AllowedType'] | dict[str, AllowedType])

google.ai.generativelanguage 客户端库提供低级别类型的访问权限,让您可以完全控制。

首先了解一下模型的 _tools 属性,您可以看到它如何描述您将其传递给模型的函数:

def multiply(a:float, b:float):
    """returns a * b."""
    return a*b

model = genai.GenerativeModel(model_name='gemini-1.5-flash',
                             tools=[multiply])

model._tools.to_proto()
[function_declarations {
   name: "multiply"
   description: "returns a * b."
   parameters {
     type_: OBJECT
     properties {
       key: "b"
       value {
         type_: NUMBER
       }
     }
     properties {
       key: "a"
       value {
         type_: NUMBER
       }
     }
     required: "a"
     required: "b"
   }
 }]

这将返回要发送到 API 的 genai.protos.Tool 对象的列表。如果您不熟悉输出的格式,这是因为这些是 Google protobuf 类。每个 genai.protos.Tool(在本例中为 1)都包含一个 genai.protos.FunctionDeclarations 列表,用于描述一个函数及其参数。

以下是使用 genai.protos 类编写的同一个乘法函数的声明。请注意,这些类仅描述 API 的函数,不包含函数的实现。因此,使用此方法不支持自动函数调用,但函数并不总是需要实现。

calculator = genai.protos.Tool(
    function_declarations=[
      genai.protos.FunctionDeclaration(
        name='multiply',
        description="Returns the product of two numbers.",
        parameters=genai.protos.Schema(
            type=genai.protos.Type.OBJECT,
            properties={
                'a':genai.protos.Schema(type=genai.protos.Type.NUMBER),
                'b':genai.protos.Schema(type=genai.protos.Type.NUMBER)
            },
            required=['a','b']
        )
      )
    ])

同样,您也可以将其描述为一个与 JSON 兼容的对象:

calculator = {'function_declarations': [
      {'name': 'multiply',
       'description': 'Returns the product of two numbers.',
       'parameters': {'type_': 'OBJECT',
       'properties': {
         'a': {'type_': 'NUMBER'},
         'b': {'type_': 'NUMBER'} },
       'required': ['a', 'b']} }]}
genai.protos.Tool(calculator)
function_declarations {
  name: "multiply"
  description: "Returns the product of two numbers."
  parameters {
    type_: OBJECT
    properties {
      key: "b"
      value {
        type_: NUMBER
      }
    }
    properties {
      key: "a"
      value {
        type_: NUMBER
      }
    }
    required: "a"
    required: "b"
  }
}

无论采用哪种方式,您都需要将 genai.protos.Tool 的表示形式或工具列表传递给

model = genai.GenerativeModel('gemini-1.5-flash', tools=calculator)
chat = model.start_chat()

response = chat.send_message(
    f"What's 234551 X 325552 ?",
)

与之前一样,该模型会返回调用计算器的 multiply 函数的 genai.protos.FunctionCall

response.candidates
[index: 0
content {
  parts {
    function_call {
      name: "multiply"
      args {
        fields {
          key: "b"
          value {
            number_value: 325552
          }
        }
        fields {
          key: "a"
          value {
            number_value: 234551
          }
        }
      }
    }
  }
  role: "model"
}
finish_reason: STOP
]

自行执行函数:

fc = response.candidates[0].content.parts[0].function_call
assert fc.name == 'multiply'

result = fc.args['a'] * fc.args['b']
result
76358547152.0

将结果发送给模型以继续对话:

response = chat.send_message(
    genai.protos.Content(
    parts=[genai.protos.Part(
        function_response = genai.protos.FunctionResponse(
          name='multiply',
          response={'result': result}))]))