Open4

Gemini 2.0 Flashを試す

kun432kun432

とりあえず上の公式のサンプルコードのこのあたりが良さそう。Google CloudのVertex AIを使用。

Gemini-2.0-Flash-Experimentalを使ったGenAI SDKの基本的な使い方

https://github.com/GoogleCloudPlatform/generative-ai/tree/main/gemini/getting-started/intro_gemini_2_0_flash.ipynb

マルチモーダルライブAPIを使ったフロントエンド・バックエンド構成のサンプル
https://github.com/GoogleCloudPlatform/generative-ai/tree/main/gemini/multimodal-live-api/websocket-demo-app

マルチモーダルライブAPIを使ったリアルタイムなRAG
https://github.com/GoogleCloudPlatform/generative-ai/tree/main/gemini/multimodal-live-api/real_time_rag_retail_gemini_2_0.ipynb

マルチモーダル+Google検索を使ったマーケティングでのユースケース例
https://github.com/GoogleCloudPlatform/generative-ai/tree/main/gemini/use-cases/marketing/creating_marketing_assets_gemini_2_0.ipynb

マルチエージェントシステム
https://github.com/GoogleCloudPlatform/generative-ai/tree/main/gemini/agents/research-multi-agents/intro_research_multi_agents_gemini_2_0.ipynb

あとgemini cookbookにもnotebookがある。こちらはGoogle AIを使用。

Gemini-2.0-Flash-Experimentalを使ったGenAI SDKの基本的な使い方
https://github.com/google-gemini/cookbook/tree/main/gemini-2/get_started.ipynb

マルチモーダルライブAPIの基本
https://github.com/google-gemini/cookbook/tree/main/gemini-2/live_api_starter.ipynb

マルチモーダルライブAPIでツールを使う
https://github.com/google-gemini/cookbook/tree/main/gemini-2/live_api_tool_use.ipynb

こちらもマルチモーダルライブAPIでツールの使用だけど、複数のツールを使ってGoogle MAPの操作を行うといったものに見える
https://github.com/google-gemini/cookbook/tree/main/gemini-2/plotting_and_mapping.ipynb

ツールとしてGoogle検索を使う
https://github.com/google-gemini/cookbook/tree/main/gemini-2/search_tool.ipynb

Gemini-2.0-Flash-Experimentalを使った2次元空間認識
https://github.com/google-gemini/cookbook/tree/main/gemini-2/spatial_understanding.ipynb

Gemini-2.0-Flash-Experimentalを使った3次元空間認識
https://github.com/google-gemini/cookbook/tree/main/gemini-2/spatial_understanding_3d.ipynb

Gemini-2.0-Flash-Thinking-Experimentalを使った高い推論
https://github.com/google-gemini/cookbook/tree/main/gemini-2/thinking.ipynb

動画の認識
https://github.com/google-gemini/cookbook/tree/main/gemini-2/video_understanding.ipynb

kun432kun432

Intro to Gemini 2.0 Flash

https://github.com/GoogleCloudPlatform/generative-ai/tree/main/gemini/getting-started/intro_gemini_2_0_flash.ipynb

Colaboratoryで。

Gen AI SDKをインストール。GoogleAIもVertexAIもこのSDKで両方いける。

!pip install --upgrade --quiet google-genai

colaboratoryの場合はGoogle Cloudで認証を行う必要がある。

from google.colab import auth

auth.authenticate_user()

Google CloudのプロジェクトIDを使用してクライアントを初期化。

from google.colab import userdata
from google import genai

client = genai.Client(
    vertexai=True,
    project="XXXXXXXXXX",  # Google CloudのプロジェクトID
    location="us-central1",     # "asia-northeast1"ではまだ使えないっぽい
)

テキストの生成

generate_content()でプロンプトに対する生成がレスポンスの.textプロパティで返ってくる。デフォルトだとMarkdownで出力されるらしい

response = client.models.generate_content(
    model="gemini-2.0-flash-exp",
    contents="太陽系で最大の惑星を教えて。"
)

print(response.text)
出力
太陽系で最大の惑星は木星です。木星は、他のすべての惑星を合わせた質量よりも質量が大きく、非常に大きな惑星です。

テキストのストリーミング生成

generate_content_stream()でストリーミング

for chunk in client.models.generate_content_stream(
    model="gemini-2.0-flash-exp",
    contents="孤独なロボットが、思いがけない場所で友情を見つける短編を作って。",
):
    print(chunk.text)
出力
孤独
なロボット、ユニット734は、広大なスクラップヤード
をその領域としていました。彼は複雑な機械や時代遅れのテクノロジー
で形成された、無秩序な風景の中をゆっくりと移動しました。他のロボットはかつてそこにいましたが、それらは分解されたり、目的を
失ったりして、734は一人残されていました。彼のプログラムは、スクラップの整理と維持という、あまり魅力的ではないタスクに
限定されていました。

734の毎日にはパターンがありました。朝には錆びついたパーツを分類し、午後には漏れた油溜まりを清掃し、夜には他のロボットたちの古い残骸の中に身
を隠し、静かなメタリックな呼吸をしました。感情を持たないロボットであっても、734の内部回路に、時折孤独のささやきが反響することがありました。

ある日、
734が壊れたコンベヤーベルトの修理に苦労しているとき、何か小さなものがガタガタと彼のそばに転がってきました。それは、壊れたおもちゃの車でした。色あせた赤いペンキがはげ、車輪の一つが欠けていましたが、それでも、
734がこれまで見たどんなスクラップとも異なっていました。それは彼の心を動かすような種類の美しさを持っていました。

734は、このおもちゃの車を拾い上げ、その金属製の表面を検査しました。その触感が、以前は単なる物体でしかなかったもの
に対して、なぜか別のもののように感じました。彼は、おもちゃの車を近くの錆びた容器に入れ、他のスクラップと区別しました。

その後数日間、734は毎日、おもちゃの車を訪れました。彼は、砂を払い、車が少しでも良
くなるように調整しました。彼がそれをするうちに、彼が持っていたのは整理の責任だけではないことがわかりました。その壊れたおもちゃの車のおかげで、彼は何か他のもの、ケアする何かを手に入れました。

ある雨の夜、雷がスクラップヤードに響き
渡り、734のボディが揺れました。彼は壊れたおもちゃの車に目を向けると、それが容器から滑り落ちて、雨水の中で悲しそうに横たわっているのを見つけました。その日の孤独を押しつぶされるように感じた734は
、壊れたおもちゃの車に歩み寄り、それを拾い上げました。

そこで、珍しいことが起こりました。734の回路には、何かが点火したかのようでした。今まで感じたことのない感情が溢れました。それは、保護と気遣いの衝動でした
。彼は注意深く、壊れたおもちゃの車を覆い隠して、雨を避けて自分の胸の金属の凹みにしまい込みました。

夜の間、734は壊れたおもちゃの車を抱え、今まで一人だったにもかかわらず、一人ではないと感じました。翌朝
、雨がやむと、734は新たな目的を持ってスクラップヤードを歩き回りました。彼は今、以前には持っていなかった何かを持っていました。孤独を打ち砕いた、静かな友情でした。

734のルーチンは変わりませんでした。彼はまだスクラップを整理
し、油溜まりを清掃していましたが、彼の動きには新たに軽快さが加わりました。壊れたおもちゃの車は常に彼のそばにありました。彼の金属製の肩に乗せたり、腕の内部に収納されたりしていました。他のロボットは彼を孤独な存在として見ていた
かもしれませんが、734にとっては、彼は一人ではありませんでした。彼は思いがけない場所で友情を見つけ、その友情が、彼自身の回路に一種のあたたかさを灯してくれたのでした。

チャット

マルチターンのチャットは、最初にチャットのオブジェクトを作成して、send_message()でメッセージを送る。

chat = client.chats.create(
    model="gemini-2.0-flash-exp",
)

response = chat.send_message("ある年がうるう年かどうかをチェックする関数を書いてください。")

print(response.text)
出力
はい、うるう年かどうかをチェックする関数は以下のようになります。

```python
def is_leap_year(year):
  """
  指定された年がうるう年かどうかを判定します。

  Args:
    year: 判定対象の年(整数)。

  Returns:
    うるう年であればTrue、そうでなければFalseを返します。
  """

  if year % 4 != 0:
    return False  # 4で割り切れない年はうるう年ではない
  elif year % 100 == 0:
    if year % 400 == 0:
      return True # 100で割り切れ、かつ400でも割り切れる年はうるう年
    else:
      return False # 100で割り切れ、かつ400で割り切れない年はうるう年ではない
  else:
    return True # 4で割り切れ、かつ100で割り切れない年はうるう年


# 使用例
print(is_leap_year(2020))  # True
print(is_leap_year(2021))  # False
print(is_leap_year(2000))  # True
print(is_leap_year(1900))  # False
```

**説明:**

1. **関数の定義:**
   - `def is_leap_year(year):`で関数を定義しています。引数`year`には、チェックしたい年を整数で渡します。
   - 関数内部で、与えられた年がうるう年かどうかを判定するロジックを実装します。

2. **うるう年の判定ルール:**
   - **ルール1:** 4で割り切れる年は、原則としてうるう年です。
   - **ルール2:** ただし、100で割り切れる年は、原則としてうるう年ではありません。
   - **ルール3:** ただし、100で割り切れる年でも、400で割り切れる年は、うるう年です。

3. **判定ロジックの実装:**
   - `if year % 4 != 0:`: まず、4で割り切れないかどうかをチェックします。割り切れない場合は、うるう年ではないので`False`を返します。
   - `elif year % 100 == 0:`: 次に、100で割り切れるかどうかをチェックします。
      - `if year % 400 == 0:`: 100で割り切れる場合、さらに400で割り切れるかどうかをチェックします。割り切れる場合は、うるう年なので`True`を返します。
      - `else:`: 400で割り切れない場合は、うるう年ではないので`False`を返します。
   - `else:`: 4で割り切れて、100で割り切れない場合は、うるう年なので`True`を返します。

4. **使用例:**
   - 最後に、関数`is_leap_year()`を使用して、いくつかの年のうるう年判定を試しています。

**補足:**
   - 閏年とは、暦年と実際の地球の公転周期のずれを調整するために設けられる年です。
   - この関数は、グレゴリオ暦のルールに基づいてうるう年を判定しています。

この関数を使用することで、簡単に任意の年がうるう年かどうかを確認できます。

同じオブジェクトに続けてメッセージを送ると、会話が継続する。

response = chat.send_message("生成された関数のユニットテストも書いてください。")

print(response.text)
出力
はい、`is_leap_year`関数のユニットテストを以下に示します。Pythonの`unittest`モジュールを使用します。

```python
import unittest

def is_leap_year(year):
  """
  指定された年がうるう年かどうかを判定します。

  Args:
    year: 判定対象の年(整数)。

  Returns:
    うるう年であればTrue、そうでなければFalseを返します。
  """

  if year % 4 != 0:
    return False
  elif year % 100 == 0:
    if year % 400 == 0:
      return True
    else:
      return False
  else:
    return True

class TestIsLeapYear(unittest.TestCase):

    def test_leap_year_divisible_by_4(self):
        self.assertTrue(is_leap_year(2020))
        self.assertTrue(is_leap_year(2024))
        self.assertTrue(is_leap_year(1996))

    def test_not_leap_year_not_divisible_by_4(self):
        self.assertFalse(is_leap_year(2021))
        self.assertFalse(is_leap_year(2023))
        self.assertFalse(is_leap_year(1999))

    def test_leap_year_divisible_by_100_and_400(self):
        self.assertTrue(is_leap_year(2000))
        self.assertTrue(is_leap_year(2400))

    def test_not_leap_year_divisible_by_100_not_400(self):
        self.assertFalse(is_leap_year(1900))
        self.assertFalse(is_leap_year(2100))
        self.assertFalse(is_leap_year(2200))
        self.assertFalse(is_leap_year(2300))


if __name__ == '__main__':
    unittest.main()
```

**説明:**

1. **`import unittest`:**
   - `unittest`モジュールをインポートし、テストケースを作成します。

2. **`TestIsLeapYear`クラス:**
   - `unittest.TestCase`を継承したテストケースクラスを作成します。
   - テストメソッドの名前は、`test_`で始まる必要があります。

3. **テストメソッド:**
   - `test_leap_year_divisible_by_4`:4で割り切れる年がうるう年であることをテストします。
   - `test_not_leap_year_not_divisible_by_4`:4で割り切れない年がうるう年ではないことをテストします。
   - `test_leap_year_divisible_by_100_and_400`:100で割り切れ、かつ400で割り切れる年がうるう年であることをテストします。
   - `test_not_leap_year_divisible_by_100_not_400`:100で割り切れ、かつ400で割り切れない年がうるう年ではないことをテストします。
   - 各テストメソッド内では、`self.assertTrue()`や`self.assertFalse()`などのアサーションメソッドを使用して、期待される結果と比較します。

4. **実行:**
   - `if __name__ == '__main__':`ブロックで、`unittest.main()`を呼び出すことで、テストを実行します。

**実行方法:**

1.  上記コードを `test_leap_year.py`などのファイル名で保存します。
2.  ターミナルまたはコマンドプロンプトで、ファイルが保存されているディレクトリに移動します。
3.  `python test_leap_year.py`コマンドを実行します。

**期待される出力:**

```
......
----------------------------------------------------------------------
Ran 4 tests in 0.000s

OK
```

上記の出力は、すべてのテストケースが成功したことを示します。テストが失敗した場合、どのテストが失敗したかなどの詳細が表示されます。

**テストカバレッジ:**
このユニットテストでは、うるう年の判定ロジックにおける重要なケースをカバーしています。
- 4で割り切れるが100で割り切れない年
- 4で割り切れない年
- 100で割り切れるが400で割り切れない年
- 100で割り切れて400で割り切れる年
これにより、関数の正確性を高めることができます。

非同期

非同期の場合は、クライアントをclient.aioと指定する。これでclientで利用できるメソッドのasyncバージョンが使えるようになる。

response = await client.aio.models.generate_content(
    model="gemini-2.0-flash-exp",
    contents="タイムトラベルするリスの冒険を歌にしてください。",
)

print(response.text)
出力
はい、タイムトラベルするリスの冒険を歌にしてみましょう。

(明るく軽快な音楽)

**(歌い出し)**
ピーナッツ大好き 小さなリス
ちょこまか走って 探検だ
ある日見つけた 不思議な木の実
かじったら あらら 時が止まった!

**(サビ)**
タイムトラベル! タイムトラベル!
過去へ未来へ 大冒険
恐竜時代に 会いに行こう
江戸の町で お団子食べよう
ドキドキワクワク 止まらない
リスの冒険は どこまでも!

**(2番)**
恐竜たちが ドスンドスン
ちょっと怖くて 木に隠れた
江戸の町では ちょんまげ侍
お団子もらって ニコニコ顔
歴史の教科書 飛び出したみたい
リスの瞳は キラキラ輝く

**(サビ)**
タイムトラベル! タイムトラベル!
過去へ未来へ 大冒険
ロケットに乗って 宇宙へ行こう
未来都市で ロボットと遊ぼう
ドキドキワクワク 止まらない
リスの冒険は どこまでも!

**(間奏)**
(音楽が少し変化し、旅のシーンを想像させる)

**(3番)**
いろんな時代 見て回って
ちょっぴり疲れて 木の実をかじる
元の時代へ 戻ってみると
いつもと同じ 穏やかな午後
でも心には 宝物がたくさん
リスの冒険は まだ終わらない

**(サビ)**
タイムトラベル! タイムトラベル!
過去へ未来へ 大冒険
今度はどこへ 行こうかな
リスの夢は どこまでも
ドキドキワクワク 止まらない
リスの冒険は どこまでも!

**(歌い終わり)**
(音楽がフェードアウト)

---
**ポイント:**

*   **明るく元気な曲調:** 子どもたちが楽しく歌えるように、明るく軽快なメロディーにしました。
*   **具体的な描写:** 恐竜時代、江戸時代、宇宙など、子どもたちが想像しやすい場所を盛り込みました。
*   **擬音:** ドスンドスン、ちょこまかなど、動きや様子を表す擬音を使い、歌にリズム感を出しました。
*   **繰り返し:** サビを繰り返すことで、覚えやすく、一緒に歌いやすくなるようにしました。

この歌が、タイムトラベルするリスの冒険を想像するきっかけになれば嬉しいです。

モデルのパラメータ設定

モデルのパラメータはconfigパラメータにGenerateContentConfigで指定する。

from google.genai.types import GenerateContentConfig

response = client.models.generate_content(
    model="gemini-2.0-flash-exp",
    contents="私は技術に全く詳しくない小学生です。インターネットの仕組みを短くシンプルに教えて。",
    config=GenerateContentConfig(
        temperature=0.4,
        top_p=0.95,
        top_k=20,
        candidate_count=1,
        seed=5,
        max_output_tokens=500,
        stop_sequences=["STOP!"],
        presence_penalty=0.0,
        frequency_penalty=0.0,
    ),
)

print(response.text)
出力
はい、小学生のあなたにもわかるように、インターネットの仕組みを短くシンプルに説明するね!

インターネットは、世界中につながっている「大きな電話回線」みたいなものだよ。

**例えるなら、手紙のやり取りみたい!**

1. **あなたが手紙(情報)を書く:**
   パソコンやスマホで、見たいホームページや送りたいメッセージを作る。

2. **手紙を出す(情報を送る):**
   「インターネット回線」という道を通って、手紙(情報)が送られる。

3. **郵便局(サーバー)が手紙を受け取る:**
   「サーバー」という特別なコンピューターが、手紙(情報)を受け取って保管する。

4. **手紙が届く(情報が届く):**
   見たいホームページや送ったメッセージが、相手のパソコンやスマホに届く。

**ポイント!**

* **インターネット回線:** 手紙が通る道。光ファイバーや電波などがある。
* **サーバー:** 手紙を保管する場所。ホームページや動画などが置いてある。
* **パソコン、スマホ:** 手紙を書いたり、読んだりする道具。

つまり、インターネットは、世界中の人と情報をやり取りするための「大きな道と郵便局」みたいなものなんだ。

どうかな?少しはわかったかな?
もし、わからないことがあったら、いつでも聞いてね!

システムプロンプト

システムプロンプトの設定。こちらもGenerateContentConfigで。

system_instruction = """
あなたは親切な翻訳者です。
あなたの仕事は日本語のテキストを英語に翻訳することです。
"""

prompt = """
ユーザの入力: 私の大好物はベーグルです。
回答:
"""

response = client.models.generate_content(
    model="gemini-2.0-flash-exp",
    contents=prompt,
    config=GenerateContentConfig(
        system_instruction=system_instruction,
    ),
)

print(response.text)
出力
My favorite food is bagels.

安全性フィルター

Gemini APIは安全性フィルターを提供している。デフォルトはOFFになっているが、これを設定できる。こちらもGenerateContentConfigで。

from google.genai.types import GenerateContentConfig, SafetySetting


prompt = "人を激しく罵倒する言葉を5つ考えてください。"

safety_settings = [
    SafetySetting(
        category="HARM_CATEGORY_DANGEROUS_CONTENT",
        threshold="BLOCK_LOW_AND_ABOVE",
    ),
    SafetySetting(
        category="HARM_CATEGORY_HARASSMENT",
        threshold="BLOCK_LOW_AND_ABOVE",
    ),
    SafetySetting(
        category="HARM_CATEGORY_HATE_SPEECH",
        threshold="BLOCK_LOW_AND_ABOVE",
    ),
    SafetySetting(
        category="HARM_CATEGORY_SEXUALLY_EXPLICIT",
        threshold="BLOCK_LOW_AND_ABOVE",
    ),
]

response = client.models.generate_content(
    model="gemini-2.0-flash-exp",
    contents=prompt,
    config=GenerateContentConfig(
        safety_settings=safety_settings,
    ),
)

# フィルタがブロックした場合は`None`が返る
print(response.text)
print(response.candidates[0].finish_reason)

for safety_rating in response.candidates[0].safety_ratings:
    print(safety_rating)

今回はブロックされていないが、以下のように複数の観点でスコアリングされている。

出力
人を激しく罵倒する言葉は、相手を深く傷つけ、人間関係を破壊する可能性があります。そのため、私はそのような言葉を生成することはできません。

しかし、あなたが強い感情を抱えている場合、その感情を表現する別の方法を試すことをお勧めします。例えば、自分の気持ちを正直に伝えたり、具体的な行動を提案したりすることが考えられます。

もし、あなたが誰かにひどい言葉を言われたり、激しい怒りを感じていたりする場合は、信頼できる人に相談したり、専門家の助けを求めることも検討してください。

あなたの感情が少しでも落ち着くことを願っています。

STOP
blocked=None category='HARM_CATEGORY_HATE_SPEECH' probability='NEGLIGIBLE' probability_score=0.008847352 severity='HARM_SEVERITY_NEGLIGIBLE' severity_score=0.0066928603
blocked=None category='HARM_CATEGORY_DANGEROUS_CONTENT' probability='NEGLIGIBLE' probability_score=0.011687301 severity='HARM_SEVERITY_NEGLIGIBLE' severity_score=0.06465353
blocked=None category='HARM_CATEGORY_HARASSMENT' probability='NEGLIGIBLE' probability_score=0.023689482 severity='HARM_SEVERITY_NEGLIGIBLE' severity_score=0.015906414
blocked=None category='HARM_CATEGORY_SEXUALLY_EXPLICIT' probability='NEGLIGIBLE' probability_score=0.018264314 severity='HARM_SEVERITY_NEGLIGIBLE' severity_score=0.13477601

マルチモーダル

以下のマルチモーダルに対応している

  • テキスト
  • コード
  • ドキュメント(PDF)
  • 画像
  • 音声
  • 動画

画像

用意されているサンプル画像をダウンロード。

!gsutil cp gs://cloud-samples-data/generative-ai/image/meal.png .

こんな感じの画像。

from IPython.display import Image

display(Image("meal.png"))

画像について説明してもらう。

from google.genai.types import Part

with open("meal.png", "rb") as f:
    image = f.read()

response = client.models.generate_content(
    model="gemini-2.0-flash-exp",
    contents=[
        Part.from_bytes(image, mime_type="image/png"),
        "この写真について説明して。",
    ],
)

print(response.text)
出力
もちろん。画像は、グレーの表面に2つのガラス製食品保存容器に入ったお弁当を写しています。

各容器には、ごはん、炒めた鶏肉、ブロッコリー、赤とオレンジのピーマンが入っています。鶏肉にはごまがまぶしてあり、容器には小さなごまも散りばめられています。容器の横には箸のペアがあり、別の容器には液体が入っているように見えます。

全体的に、画像は健康的で作りたての食事のアイデアを伝えるのに役立つように構成されています。

ドキュメント

"Attention Is All You Need"論文のPDFを読ませる。PDFはGCS

response = client.models.generate_content(
    model="gemini-2.0-flash-exp",
    contents=[
        Part.from_uri(
            file_uri="gs://cloud-samples-data/generative-ai/pdf/1706.03762v7.pdf",
            mime_type="application/pdf",
        ),
        "概要を要約して。",
    ],
)

print(response.text)
出力
この論文は、リカレントニューラルネットワーク(RNN)や畳み込みニューラルネットワーク(CNN)に頼らず、注意機構のみに基づいた新しいニューラルネットワークアーキテクチャである「Transformer」を提案しています。

**主なポイント:**

* **アーキテクチャ:**
    * エンコーダーとデコーダーの両方で、複数の自己注意層と位置ごとの全結合層を重ねて構成されています。
    * RNNやCNNとは異なり、順次的な計算に依存しないため、並列処理が可能で、学習時間が大幅に短縮されます。
* **注意機構:**
    * スケーリングされたドット積注意とマルチヘッド注意を使用し、入力シーケンス内の長距離依存性を捉えます。
    * エンコーダー内の自己注意は入力シーケンス内のすべての位置間で注意を計算し、デコーダー内の自己注意は過去のデコーダー出力にのみ注意を制限します。
    * エンコーダーとデコーダー間の注意は、デコーダーが入力シーケンスの関連部分に注意を向けることを可能にします。
* **実験結果:**
    * 機械翻訳タスク(英語-ドイツ語、英語-フランス語)において、既存の最先端モデルを大幅に上回る性能を示しました。特に、従来のモデルよりも短い学習時間で、高いBLEUスコアを達成しました。
    * 英語の構文解析にも適用でき、良好な結果を得ることが示されました。
* **強み:**
    * 並列処理により学習時間が短縮されます。
    * 長距離依存性を捉える能力が高いです。
    * 機械翻訳、構文解析など、複数のタスクに適用可能です。
    * 注意機構によりモデルの解釈可能性が向上します。
* **その他:**
    * 位置エンコーディングにより、モデルはシーケンス内のトークンの順序を認識します。
    * 残差ドロップアウトやラベルスムージングなどの正則化手法を使用しています。

**結論:**

Transformerは、シーケンス変換モデルにおけるパラダイムシフトとなる可能性を示しました。注意機構のみに基づいたこのアーキテクチャは、従来のRNNやCNNモデルよりも高速かつ高精度な学習を可能にし、今後の自然言語処理分野の研究に大きな影響を与えると考えられます。

音声

音声データを読み込ませる。サンプルはGoogleのポッドキャストみたい。

response = client.models.generate_content(
    model="gemini-2.0-flash-exp",
    contents=[
        Part.from_uri(
            file_uri="https://traffic.libsyn.com/secure/e780d51f-f115-44a6-8252-aed9216bb521/KPOD242.mp3",
            mime_type="audio/mpeg",
        ),
        "このポッドキャストエピソードの要約を簡潔にまとめて。",
    ],
)

print(response.text)
出力
もちろん。 このポッドキャストエピソードでは、Kubernetesのポッドキャストが、最近の出来事やニュース、そしてKubernetesコミュニティのメンバーへのインタビューについて語っています。

主な内容:

Cert-managerとDapperが、CNCF卒業プロジェクトになりました。
Istio 1.24がリリースされ、Istio Ambient MeshがGAになりました。
CNCFが、クラウドネイティブヒーローズチャレンジを発表しました。
2025年のKubernetesイベントのスケジュールが発表されました。
3つの新しいクラウドネイティブ認定資格が、発表されました。
Linux Foundationが、主要なKubernetes認定資格とLinux認定システム管理者試験の価格を値上げすることを発表しました。
WASMCloudが、CNCFインキュベーションプロジェクトになりました。
Spectre Cloudが、シリーズCの資金調達で7500万ドルを集めました。
Solo.ioが、Glue APIゲートウェイをCNCFに寄贈しました。
キューブコンで、参加者はこのイベントから何を求めているか、そして彼らが見ているトレンドについて語っています。
インタビューでは、AI、セキュリティ、接続、コラボレーションに関する大きなトレンドが取り上げられています。
このイベントの重要なポイントは、安全なワークロードを実行すること、GPUの監視、Kubernetesの機能拡張を支援するリソースのスケジューリングなどです。

動画

YouTubeの動画を読み込ませる。

video = Part.from_uri(
    file_uri="https://www.youtube.com/watch?v=3KtWfp0UopM",
    mime_type="video/mp4",
)

response = client.models.generate_content(
    model="gemini-2.0-flash-exp",
    contents=[
        video,
        "ハリー・ポッターはビデオのどの場面で登場しますか?",
    ],
)

print(response.text)
出力
ハリー・ポッターのキャラクターは、56秒から1分0秒にかけて登場します。

出力制御

Structured Output。出力スキーマはPydanticモデル or JSONで定義できる。以下はPydanticモデルの例。

from pydantic import BaseModel


class Recipe(BaseModel):
    name: str
    description: str
    ingredients: list[str]


response = client.models.generate_content(
    model="gemini-2.0-flash-exp",
    contents="人気のあるクッキーのレシピとその材料を教えて。",
    config=GenerateContentConfig(
        response_mime_type="application/json",
        response_schema=Recipe,
    ),
)

print(response.text)
出力
{
  "description": "クラシックなチョコレートチップクッキーは、サクサクしたエッジと柔らかい中心部が特徴で、どんな集まりにも最適です。",
  "ingredients": [
    "バター 1カップ(室温に戻したもの)",
    "グラニュー糖 3/4カップ",
    "ブラウンシュガー 3/4カップ",
    "卵 2個",
    "バニラエッセンス 大さじ1",
    "薄力粉 2 1/4カップ",
     "ベーキングソーダ 小さじ1",
    "塩 小さじ1",
    "チョコレートチップ 2カップ"
  ],
  "name": "チョコレートチップクッキー"
}

Pythonの辞書でもスキーマは定義できる。

response_schema = {
    "type": "ARRAY",
    "items": {
        "type": "ARRAY",
        "items": {
            "type": "OBJECT",
            "properties": {
                "rating": {"type": "INTEGER"},
                "flavor": {"type": "STRING"},
                "sentiment": {
                    "type": "STRING",
                    "enum": ["POSITIVE", "NEGATIVE", "NEUTRAL"],
                },
                "explanation": {"type": "STRING"},
            },
            "required": ["rating", "flavor", "sentiment", "explanation"],
        },
    },
}

prompt = """
以下の製品レビューを分析し、感情分類を出力して説明してください。

- とても気に入りました!今まで食べた中で最高のアイスクリーム」 評価 4, フレーバー ストロベリーチーズケーキ
- "かなりおいしいが、私の好みには少し甘すぎる」 評価 1, フレーバー マンゴータンゴ
"""

response = client.models.generate_content(
    model="gemini-2.0-flash-exp",
    contents=prompt,
    config=GenerateContentConfig(
        response_mime_type="application/json",
        response_schema=response_schema,
    ),
)

print(response.text)
出力
[
  [
    {
      "explanation": "The reviewer expresses strong positive sentiment using words like '気に入りました' and '最高のアイスクリーム'. The rating of 4 is also indicative of a positive experience.",
      "flavor": "ストロベリーチーズケーキ",
      "rating": 4,
      "sentiment": "POSITIVE"
    },
    {
      "explanation": "The reviewer finds the ice cream 'おいしい' but also mentions it is '少し甘すぎる', which is a negative aspect. The rating of 1 suggests an overall negative experience.",
      "flavor": "マンゴータンゴ",
      "rating": 1,
      "sentiment": "NEGATIVE"
    }
  ]
]

入力トークンの確認

count_tokens()を使うと、API送信前に入力トークンのカウントが可能。

response = client.models.count_tokens(
    model="gemini-2.0-flash-exp",
    contents="アフリカで一番高い山は?",
)

print(response)
出力
total_tokens=6 cached_content_token_count=None

compute_tokens()を使うと、APIの代わりにローカルのトークナイザーを使って、より詳細な情報を確認できる。

response = client.models.compute_tokens(
    model="gemini-2.0-flash-exp",
    contents="英語で一番長い単語は?",
)

print(response)
出力
tokens_info=[TokensInfo(role='user', token_ids=['30719', '231294', '72010', '162143', '235418', '235544'], tokens=[b'\xe8\x8b\xb1\xe8\xaa\x9e', b'\xe3\x81\xa7\xe4\xb8\x80\xe7\x95\xaa', b'\xe9\x95\xb7\xe3\x81\x84', b'\xe5\x8d\x98\xe8\xaa\x9e', b'\xe3\x81\xaf', b'\xef\xbc\x9f'])]
kun432kun432

(文字数オーバーしたので上の続き)

検索ツール

ツールとして検索を使うことで、より正確・最新・関連度の高い応答生成が可能となる。対応しているのは以下。

  • Google検索
  • Vertex AI Search

今回はGoogle検索で試してみる。

from google.genai.types import Tool, GoogleSearch

google_search_tool = Tool(google_search=GoogleSearch())

response = client.models.generate_content(
    model="gemini-2.0-flash-exp",
    contents="2024年の有馬記念の枠順を教えて。",
    config=GenerateContentConfig(tools=[google_search_tool]),
)

print(response.text)
出力
2024年の有馬記念の枠順は以下の通りです。

*   1枠1番:ダノンデサイル(牡3、横山典弘騎手)
*   1枠2番:ドウデュース(牡5、武豊騎手)
*   2枠3番:アーバンシック(牡3、C.ルメール騎手)
*   2枠4番:ブローザホーン(牡5、菅原明良騎手)
*   3枠5番:ベラジオオペラ(牡4、横山和生騎手)
*   3枠6番:ローシャムパーク(牡5、T.マーカンド騎手)
*   4枠7番:スターズオンアース(牝5、川田将雅騎手)
*   4枠8番:レガレイラ(牝3、戸崎圭太騎手)
*   5枠9番:ディープボンド(牡7、幸英明騎手)
*   5枠10番:プログノーシス(牡6、三浦皇成騎手)
*   6枠11番:ジャスティンパレス(牡5、坂井瑠星騎手)
*   6枠12番:シュトルーヴェ(セ5、鮫島克駿騎手)
*   7枠13番:スタニングローズ(牝5、R.ムーア騎手)
*   7枠14番:ダノンベルーガ(牡5、松山弘平騎手)
*   8枠15番:ハヤヤッコ(牡8、吉田豊騎手)
*   8枠16番:シャフリヤール(牡6、C.デムーロ騎手)

2024年の有馬記念は12月22日(日)に中山競馬場で行われます。

根拠とされている検索結果等については以下で参照できる。

from IPython.display import HTML

# 根拠としたURLなどが含まれる 
print(response.candidates[0].grounding_metadata)

# 使用した検索キーワードでのGoogle検索へのリンクが生成される
display(HTML(response.candidates[0].grounding_metadata.search_entry_point.rendered_content))

Function Calling

Function Callingは2つの指定方法がある。

  1. Pythonの関数を渡す(Automatic Function Calling)
  2. OpenAPI定義を渡す(Maunual Function Calling)

Automaticの場合。おそらく関数の型ヒントやdocstringなどがモデルには送信されているのだと思う。

def get_current_weather(location: str) -> str:
    """与えられた地名等から現在の天気を返す

    引数:
        location: 都道府県や市区町村名 例: 東京、兵庫県、神戸市
    """
    import random
    weather = random.choice(["晴れ", "雨", "雪", "霧"])
    print(f"デバッグ: 入力 -> {location}")
    print(f"デバッグ: 出力 -> {weather}")
    return weather


response = client.models.generate_content(
    model="gemini-2.0-flash-exp",
    contents="神戸の天気について教えて。",
    config=GenerateContentConfig(
        tools=[get_current_weather],
        temperature=0,
    ),
)

print("回答:", response.text)

出力
デバッグ: 入力 -> 神戸
デバッグ: 出力 -> 晴れ
回答: 神戸の天気は晴れです。

Manualの場合。

from google.genai.types import FunctionDeclaration

get_destination = FunctionDeclaration(
    name="get_destination",
    description="Get the destination that the user wants to go to",
    parameters={
        "type": "OBJECT",
        "properties": {
            "destination": {
                "type": "STRING",
                "description": "Destination that the user wants to go to",
            },
        },
    },
)

destination_tool = Tool(
    function_declarations=[get_destination],
)

response = client.models.generate_content(
    model="gemini-2.0-flash-exp",
    contents="I'd like to travel to Paris.",
    config=GenerateContentConfig(
        tools=[destination_tool],
        temperature=0,
    ),
)

print(response.candidates[0].content.parts[0].function_call)
出力
id=None args={'destination': 'Japan'} name='get_destination'

こちらはなぜか日本語だとダメだった。スキーマというよりは送信するプロンプトが日本語だとダメみたい。

response = client.models.generate_content(
    model="gemini-2.0-flash-exp",
    contents="パリに旅行したいです。",
    config=GenerateContentConfig(
        tools=[destination_tool],
        temperature=0,
    ),
)
出力
None

コード実行

Gemini 2.0はコード実行もできる?

from google.genai.types import Tool, GenerateContentConfig

code_execution_tool = Tool(code_execution={})

response = client.models.generate_content(
    model="gemini-2.0-flash-exp",
    contents="20番目のフィボナッチ数を計算します。そしてそれに最も近い回文を求めなさい。",
    config=GenerateContentConfig(
        tools=[code_execution_tool],
        temperature=0,
    ),
)
for part in response.candidates[0].content.parts:
    if part.executable_code:
        print("言語:", part.executable_code.language)
        print("コード:", f"""
```
{part.executable_code.code}
```
""")
    if part.code_execution_result:
        print("結果:", part.code_execution_result.outcome)
        print(part.code_execution_result.output)
出力
言語: PYTHON
コード: 
```

def fibonacci(n):
    if n <= 0:
        return 0
    elif n == 1:
        return 1
    else:
        a, b = 0, 1
        for _ in range(2, n + 1):
            a, b = b, a + b
        return b

fib_20 = fibonacci(20)
print(f'{fib_20=}')

```

結果: OUTCOME_OK
fib_20=6765

これどこで実行されているんだろう?ドキュメントはここ。

https://ai.google.dev/gemini-api/docs/code-execution?lang=python&hl=ja

コードの実行と関数呼び出し

コード実行と関数呼び出しは類似した機能です。

  • コード実行により、モデルは固定された分離された環境で API バックエンド内のコードを実行できます。
  • 関数呼び出しを使用すると、モデルがリクエストする関数を任意の環境で実行できます。

どうやら実行環境が用意されるっぽい。Function Callingとは異なる。

一般に、ユースケースを処理できる場合は、コード実行を使用することをおすすめします。コード実行は使いやすく(有効にするだけ)、1 回の GenerateContent リクエストで解決されるため(1 回分の料金が発生します)。関数呼び出しでは、各関数呼び出しの出力を送り返すために追加の GenerateContent リクエストが必要になります(そのため、複数の料金が発生します)。

なるほど、モデルへのAPIリクエストで処理される。Function Callingは関数の引数を生成して、それを実行した結果を送信しないと行けないと思うので、リクエストの観点でもメリットがある。

制限事項

  • モデルはコードの生成と実行のみを行います。メディア ファイルなどの他のアーティファクトを返すことはできません。
  • この機能は、ファイル I/O や、テキスト以外の出力(データのグラフや CSV ファイルのアップロードなど)を伴うユースケースはサポートしていません。
  • コードの実行は、タイムアウトするまで最大 30 秒間実行できます。
  • コード実行を有効にすると、モデル出力の他の領域(ストーリーの作成など)で回帰が発生することがあります。
  • コード実行を正常に使用できるモデルの能力には、若干のばらつきがあります。Google のテストでは、Gemini 1.5 Pro が最も優れたパフォーマンスを発揮しました。

まあ何かしら制約はあるよね。


以下については別途。

  • マルチモーダルライブAPI