プログラムの中でLLMに任せられる部分はなるべく丸投げしたい

LLMの力を使ってコーディングの生産性をあげようという動きが活発だが、自分の中には「もはやコードは可能な限り書かない方が善だ」という感覚が生まれつつある。LLMができるタスクをわざわざ人の手を使って再生産したコードで動かすより、LLMに任せられる部分は可能な限りLLMに任せるようにしていきたい。LLMによって高速に書かれたコードであっても、コードとして存在する以上いつかは負債になるからだ。プロンプトももちろん負債にはなりうるが、自分が人間である限りコードよりはプロンプトの方がメンテナンスの難易度は低そうに思える。

まだまだ2025年現在ではLLMにはできないことも多いのでプログラムを自前で書かなければいけない部分もそこそこある。ただ、プログラムの一部分であってもLLMに頼れる部分は頼る、というスタイルは実験的にどんどん取り入れていきたいと思っている。

今回は、「与えられた数字が偶数かどうかを調べて返す」というあえてLLMにやらせなくても良いようなテーマを実際にGeminiを使って関数として実装してみる。

まずはPythonでGeminiを使って数字の2が偶数かどうかをテキストで回答してもらうコードを書く。

from google import genai
api_key = os.environ.get("GOOGLE_API_KEY", "")

client = genai.Client(api_key=api_key)

response = client.models.generate_content(
  model="gemini-2.0-flash",
  contents="数字「2」は偶数ですか?"
)
print(response.text)

下記のようなレスポンスがテキストで返ってくる。

はい、数字の「2」は偶数です。偶数は2で割り切れる整数のことを指します。2は2で割り切れて1になるため、偶数です。

人間が使う分にはテキストで説明される形でも構わないが、プログラムから参照するとなるとJSONなどの形で返ってきて欲しい。

https://ai.google.dev/gemini-api/docs/structured-output?hl=ja&_gl=116ofoby_upMQ.._gaMjAxMzQ1MDIyNy4xNzQ2NTE4MjIx_ga_P1DBVKWT6V*czE3NDY1MTgyMjAkbzEkZzAkdDE3NDY1MTgyMjAkajAkbDAkaDQxNzQ0MDY5NQ..&lang=python

プロンプトでアウトプットにJSONを返すように指定すると、JSONで返してくれるようになる。

response = client.models.generate_content(
  model="gemini-2.0-flash",
  contents='''
  数字「2」は偶数ですか? 結果をJSONで返してください。
  JSONのスキーマは下記のような形でお願いします。
  descriptionは日本語でお願いします。
  Return: {"is_even": bool, "description": str}
  '''
)
print(response.text)

結果は下記のようになる

```json
{
  "is_even": true,
  "description": "数字の2は偶数です。なぜなら、2は2で割り切れるからです。"
}
```

configで response_mime_type を明示的に application/json にすると、余計なmarkdownの装飾がなくなり、JSONで結果が返ってくるようになる。

response = client.models.generate_content(
  model="gemini-2.0-flash",
  contents='''
  数字「2」は偶数ですか? 結果をJSONで返してください。
  JSONのスキーマは下記のような形でお願いします。
  descriptionは日本語でお願いします。
  Return: {"is_even": bool, "description": str}
  ''',
  config={
    'response_mime_type': 'application/json',
  },
)
print(response.text)

結果

{
  "is_even": true,
  "description": "数字の2は偶数です。"
}

configの中でスキーマを指定することもできる。

from pydantic import BaseModel

class EvenCheck(BaseModel):
  is_even: bool
  description: str

response = client.models.generate_content(
  model="gemini-2.0-flash",
  contents='''
  数字「2」は偶数ですか?
  ''',
  config={
    'response_mime_type': 'application/json',
    'response_schema': EvenCheck,
  },
)
print(response.text)

関数としてまとめるとこんな感じになる。

import json
def is_even(a) -> bool:
  # TODO: aが数字じゃなかった場合の対応

  response = client.models.generate_content(
    model="gemini-2.0-flash",
    contents=f'''
    数字「{a}」は偶数ですか?
    ''',
    config={
      'response_mime_type': 'application/json',
      'response_schema': EvenCheck,
    },
  )
  return json.loads(response.text).get("is_even")

is_even(3)

もちろん今回の「偶数かどうか」を調べるだけの処理だったらシンプルに自分でコードを書いた方が早い。そして時々回答がぶれるLLMに比べて確実ではあるし、実行速度も速いはずだ。

ただ、このアプローチの面白いところは「素数かどうかを調べる」「閏年かどうかを調べる」「正しいメールアドレスか調べる」このような内容も全て自然言語で実装できるところである。

LLMの回答は時々間違えるのでその対策が必要だったり、実行速度も普通にコードで実装する場合に比べれば遅くなることの方が多い。なので今時点ではこのアプローチはまだ有効な場面は限られているが、今後の環境の発展の中で有効さが増してくるタイミングはそう遠くないのではないかと思っている。

Pocket

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です