Gemini API: Python으로 함수 호출

ai.google.dev에서 보기 Google Colab에서 실행 GitHub에서 소스 보기

Gemini 모델에 함수 설명을 제공할 수 있습니다. 모델이 쿼리를 처리할 수 있도록 함수를 호출하고 결과를 돌려보내도록 요청할 수 있습니다.

설정

Python SDK 설치

Gemini API용 Python SDK는 google-generativeai 패키지에 포함되어 있습니다. pip를 사용하여 종속 항목을 설치합니다.

pip install -U -q google-generativeai

패키지 가져오기

필요한 패키지를 가져옵니다.

import pathlib
import textwrap
import time

import google.generativeai as genai


from IPython import display
from IPython.display import Markdown

def to_markdown(text):
  text = text.replace('•', '  *')
  return Markdown(textwrap.indent(text, '> ', predicate=lambda _: True))

API 키 설정

Gemini API를 사용하려면 먼저 API 키를 가져와야 합니다. 아직 키가 없으면 Google AI Studio에서 클릭 한 번으로 키를 만듭니다.

API 키 가져오기

Colab에서 왼쪽 패널의 'boot' 아래에 있는 보안 비밀 관리자에 키를 추가합니다. 이름을 API_KEY로 지정합니다.

API 키가 있으면 SDK에 전달합니다. 여기에는 두 가지 방법이 있습니다.

  • GOOGLE_API_KEY 환경 변수에 키를 배치합니다 (SDK가 자동으로 거기에서 가져옴).
  • genai.configure(api_key=...)에 키 전달
try:
    # Used to securely store your API key
    from google.colab import userdata

    # Or use `os.getenv('API_KEY')` to fetch an environment variable.
    GOOGLE_API_KEY=userdata.get('GOOGLE_API_KEY')
except ImportError:
    import os
    GOOGLE_API_KEY = os.environ['GOOGLE_API_KEY']

genai.configure(api_key=GOOGLE_API_KEY)

함수 기본사항

genai.GenerativeModel를 만들 때 함수 목록을 tools 인수에 전달할 수 있습니다.

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

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

model
genai.GenerativeModel(
    model_name='models/gemini-1.0-pro',
    generation_config={},
    safety_settings={},
    tools=<google.generativeai.types.content_types.FunctionLibrary object at 0x10e73fe90>,
)

권장되는 함수 호출 사용 방법은 채팅 인터페이스를 사용하는 것입니다. 주된 이유는 FunctionCalls가 채팅의 멀티턴 구조에 잘 맞기 때문입니다.

chat = model.start_chat(enable_automatic_function_calling=True)

자동 함수 호출이 사용 설정되면 모델에서 요청하는 경우 chat.send_message가 함수를 자동으로 호출합니다.

정답이 포함된 텍스트 응답을 단순히 반환하는 것 같습니다.

response = chat.send_message('I have 57 cats, each owns 44 mittens, how many mittens is that in total?')
response.text
'The total number of mittens is 2508.'
57*44
2508

ChatSession.history에서 이벤트의 순서를 확인할 수 있습니다.

  1. 질문을 보냈습니다.
  2. 모델이 glm.FunctionCall로 응답했습니다.
  3. genai.ChatSession가 함수를 로컬에서 실행하고 모델을 다시 glm.FunctionResponse로 전송했습니다.
  4. 모델이 답변에 함수 출력을 사용했습니다.
for content in chat.history:
    part = content.parts[0]
    print(content.role, "->", type(part).to_dict(part))
    print('-'*80)
user -> {'text': 'I have 57 cats, each owns 44 mittens, how many mittens is that in total?'}
--------------------------------------------------------------------------------
model -> {'function_call': {'name': 'multiply', 'args': {'a': 57.0, 'b': 44.0} } }
--------------------------------------------------------------------------------
user -> {'function_response': {'name': 'multiply', 'response': {'result': 2508.0} } }
--------------------------------------------------------------------------------
model -> {'text': 'The total number of mittens is 2508.'}
--------------------------------------------------------------------------------

일반적으로 상태 다이어그램은 다음과 같습니다.

모델은 항상 텍스트 또는 FunctionCall로 응답할 수 있습니다. 모델이 FunctionCall을 전송하면 사용자는 FunctionResponse로 응답해야 합니다.

모델은 텍스트 응답을 반환하기 전에 여러 함수 호출로 응답할 수 있으며 함수 호출은 텍스트 응답 앞에 옵니다.

이 모든 작업은 자동으로 처리되지만 더 세부적으로 관리할 수 있는 방법은 다음과 같습니다.

  • 기본 enable_automatic_function_calling=False를 그대로 두고 glm.FunctionCall 응답을 직접 처리합니다.
  • 또는 채팅 기록도 관리해야 하는 GenerativeModel.generate_content를 사용합니다.

[선택사항] 낮은 수준의 액세스

모든 경우에 Python 함수에서 스키마 자동 추출이 작동하지는 않습니다. 예를 들어 중첩된 사전 객체의 필드를 설명하는 사례는 처리하지 않지만 API는 이를 지원합니다. API는 다음 유형을 설명할 수 있습니다.

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

google.ai.generativelanguage 클라이언트 라이브러리는 하위 수준 유형에 대한 액세스를 제공하여 완전한 제어 기능을 제공합니다.

import google.ai.generativelanguage as glm

먼저 모델의 _tools 속성을 살펴보면 모델에 전달한 함수를 어떻게 설명하는지 확인할 수 있습니다.

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

model = genai.GenerativeModel(model_name='gemini-1.0-pro',
                             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로 전송될 glm.Tool 객체 목록이 반환됩니다. 출력된 형식이 익숙하지 않은 경우 Google protobuf 클래스이기 때문입니다. 각 glm.Tool (여기서는 1)에는 함수와 인수를 설명하는 glm.FunctionDeclarations 목록이 포함됩니다.

다음은 glm 클래스를 사용하여 작성된 동일한 곱셈 함수에 관한 선언입니다.

이러한 클래스는 API의 함수를 설명할 뿐이며 함수의 구현을 포함하지 않습니다. 따라서 자동 함수 호출에서는 이를 사용할 수 없지만 함수에 항상 구현이 필요하지는 않습니다.

calculator = glm.Tool(
    function_declarations=[
      glm.FunctionDeclaration(
        name='multiply',
        description="Returns the product of two numbers.",
        parameters=glm.Schema(
            type=glm.Type.OBJECT,
            properties={
                'a':glm.Schema(type=glm.Type.NUMBER),
                'b':glm.Schema(type=glm.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']} }]}
glm.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"
  }
}

어느 쪽이든 glm.Tool 표현 또는 도구 목록을

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

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

모델이 계산기의 multiply 함수를 호출하는 glm.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(
    glm.Content(
    parts=[glm.Part(
        function_response = glm.FunctionResponse(
          name='multiply',
          response={'result': result}))]))

요약

SDK에서 기본 함수 호출이 지원됩니다. 자연스러운 양방향 구조 때문에 채팅 모드를 사용하면 더 쉽게 관리할 수 있습니다. 텍스트 응답을 생성할 수 있도록 실제로 함수를 호출하고 결과를 모델로 다시 전송하는 일을 담당합니다.