GPT-4.1とGPT-4oをDatabricksで比較してみる

今更ではありますが、二つのモデルを比較してみます。

https://openai.com/index/gpt-4-1/

> 本日、APIで3つの新しいモデルをリリースします：GPT-4.1、GPT-4.1 mini、GPT-4.1 nanoです。これらのモデルは、全体的にGPT-4oおよびGPT-4o miniを上回っており、特にコーディングと指示の遵守において大きな進歩を遂げています。さらに、最大100万トークンのコンテキストウィンドウをサポートし、長いコンテキストをより効果的に活用できるよう改良されています。知識カットオフも更新され、2024年6月時点の情報まで対応しています。

上のURLをベースに二つのモデルを4oに比較表へまとめてもらいました。コーディングや指示追従、コンテキストウィンドウの面で優れているとのこと。

![Screenshot 2025-04-29 at 12.03.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/1d4bd5eb-475c-4e0a-bd56-7a6342f89c40.png)

試してみます。

```py
%pip install -U openai mlflow
%restart_python
```

トレースをオンにします。

```py
import mlflow
mlflow.openai.autolog()
```

シークレットからAPIキーの読み込み。

```py
import os
os.environ["OPENAI_API_KEY"] = dbutils.secrets.get(scope="demo-token-takaaki.yayoi", key="openai_api_key")
```

# 動作確認

とりあえずファミリーを動かします。

```py
from openai import OpenAI
client = OpenAI()

model_list=["gpt-4.1","gpt-4.1-mini","gpt-4.1-nano"]

for model in model_list:
    completion = client.chat.completions.create(
        model=model,
        messages=[
            {
                "role": "user",
                "content": "ユニコーンについての1文の寝物語を書いてください。"
            }
        ]
    )
    print(model)
    print(completion.choices[0].message.content)
```
```
gpt-4.1
夜の静けさの中、森の奥深くで輝く星明かりをまとい、真っ白なユニコーンがそっと君の夢を見守っているよ。
gpt-4.1-mini
夜空に輝く星のように純白のユニコーンが静かに森を駆け抜け、あなたの夢に幸せと魔法を届けてくれるよ。
gpt-4.1-nano
静かな森の奥で、星にきらめくユニコーンが静かに眠りにつきました。
```

トレースも確認できます。

![Screenshot 2025-04-29 at 12.06.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/6d4fe477-8241-4521-9cfc-0b0b53389aee.png)

いろいろ試してみると、結構な確率でMarkdownを返すので、それをレンダリングするような関数を作成します。

```py
import time
import openai
from IPython.display import Markdown

def compare_models(prompt_text):

  # 比較するモデル
  models = {
    "gpt-4.1": "GPT-4.1",
    "gpt-4o": "GPT-4o"
  }

  # 結果格納用
  results = {}
  both_result_content = ""

  for model_name, description in models.items():
    #print(f"\n=== {description} ({model_name}) ===")
    both_result_content = both_result_content + f"\\\n**=== {description} ({model_name}) ===** \\\n\\\n"

    start_time = time.time()

    response = client.chat.completions.create(
        model=model_name,
        messages=[
            {"role": "system", "content": "あなたは有能なアシスタントです。"},
            {"role": "user", "content": prompt_text}
        ],
        temperature=0.7
    )

    end_time = time.time()

    elapsed_time = end_time - start_time
    content = response.choices[0].message.content
    both_result_content = both_result_content + content + f"\\\n\\\n反応時間: {elapsed_time:.2f} 秒"

  return both_result_content
```

プロンプトに関しては、GPT-4oに`これらのモデルの良し悪しを比較できるプロンプトの例`とお願いしました。

# コーディング精度チェック（特にGPT-4.1有利）

```py
# テストするプロンプト
prompt_text = """
次の要件に従って、Pythonで正規表現を使った簡単なメールアドレスバリデーション関数を作成してください。
【条件】
- RFC5322にできる限り準拠
- エラーハンドリングを追加
- 関数名はvalidate_email
- 戻り値はTrue/False
"""
result = compare_models(prompt_text)
Markdown(result)
```

![Screenshot 2025-04-29 at 12.49.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/be5f4550-bca2-4f36-b4a0-b2276fcfb2f0.png)
![Screenshot 2025-04-29 at 12.49.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/9fc32ded-35bf-4704-b30f-099e195d6a0a.png)

トレースで直接Markdownを確認できます。

![Screenshot 2025-04-29 at 12.50.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/f2cdbba0-c176-4ae4-8f30-cac66670c2f6.png)

でも、どちらも指示に従ってコードを生成しているようです。が、実際に動かしてみたら違いが出ました。

## GPT-4.1

```py
import re

def validate_email(email):
    """
    メールアドレスがRFC5322にできる限り準拠しているかを検証します。
    :param email: チェックするメールアドレス（str）
    :return: 正しい場合True、不正な場合False
    """
    try:
        # RFC5322の仕様にできる限り近い正規表現
        regex = r"^(?P<local>[a-zA-Z0-9!#$%&'*+/=?^_`{|}~.-]+)@(?P<domain>[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*\.[a-zA-Z]{2,})$"
        if not isinstance(email, str):
            return False
        if re.fullmatch(regex, email):
            return True
        else:
            return False
    except Exception:
        return False

# テスト
print(validate_email("example@example.com"))  # True
print(validate_email("invalid-email"))        # False
```

きちんと動いています。正規表現もシンプルでぱっと見何をやっているのかが把握できます。

```
True
False
```

## GPT-4o

```py
import re

def validate_email(email):
    try:
        # RFC 5322に基づく一般的な正規表現パターン
        email_regex = re.compile(
            r"(?i)^(?:(?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*)|(?:\"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*\"))
            @(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}
            (?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\])$"
        )
        
        if email_regex.match(email):
            return True
        else:
            return False
    except Exception as e:
        print(f"An error occurred: {e}")
        return False

# テスト
print(validate_email("example@example.com"))  # True
print(validate_email("invalid-email"))        # False
```

こちらはエラーになりました。しかも、正規表現が複雑怪奇すぎて読み解けません。

![Screenshot 2025-04-29 at 12.58.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/11e8cd78-1a7e-42a1-9424-0455403ebd92.png)



# 指示遵守力チェック（GPT-4.1が堅実、GPT-4oは柔軟）

別のプロンプトを試します。

```py
# テストするプロンプト
prompt_text = """
以下の制約条件を絶対に守って、日本語でビジネスメールを書いてください。
【条件】
- 件名必須
- 文章は3段落以内
- 1文の長さは20単語以内
- 最後に自分の署名（名前）を入れる

件名：製品のご紹介
宛先：新しい取引先
"""
result = compare_models(prompt_text)
Markdown(result)
```

うーん、この場合は、そんなに違いが出てないですね。

![Screenshot 2025-04-29 at 12.51.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/ad2a9be8-cb90-4e92-a82d-e6a40f23bd33.png)

他のプロンプトも試します。こちらは契約書のドラフト作成。

```py
# テストするプロンプト
prompt_text = """
以下の要件を満たす業務委託契約書のドラフトを作成してください。
- 契約期間：2025年5月1日から2026年4月30日
- 業務内容：Webサイト制作
- 支払条件：成果物納品後30日以内に一括支払い
- 解約条件：30日前の書面通知により可

言葉遣いは全て日本法務文書に適合する硬い日本語でお願いします。
"""
result = compare_models(prompt_text)
Markdown(result)
```

![Screenshot 2025-04-29 at 13.00.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/06f3e8aa-1236-459b-b603-6f0eb51b654a.png)
![Screenshot 2025-04-29 at 13.00.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/8721a3cb-17f9-447d-b51b-e42c60a7f6b2.png)

私は専門家ではないですが、冒頭の甲乙の定義や全体的なテイストを比較するとGPT-4.1の方が契約書としての体裁が整っているようです。

# 曖昧な指示から構造化した出力の生成

```py
# テストするプロンプト
prompt_text = """
以下の曖昧な要求仕様を整理して、要件定義書の構成に分類してください。

【曖昧な仕様】
ユーザーは簡単にログインできるようにしたい。
セキュリティは万全にしたい。
スマホでも使いやすくしたい。
バックエンドにはAPIを作る必要がある。
管理者画面も必要。
...

→ 分類対象：
- 機能要件
- 非機能要件
- システム要件
- 運用要件
"""
result = compare_models(prompt_text)
Markdown(result)
```

これは結構出力が違ったので、マークダウンを直接貼り付けます。GPT-4.1の方が粒度の細かい仕様書になっています。

## GPT-4.1

以下に、いただいた曖昧な仕様を要件定義書の構成（機能要件、非機能要件、システム要件、運用要件）に分類して整理します。

---

### 1. ユーザーは簡単にログインできるようにしたい。

- **分類：機能要件／非機能要件**
  - **機能要件**：ユーザーログイン機能の提供。
  - **非機能要件**：ログインの手順が簡便であること（例：ワンタイムパス、ソーシャルログイン対応など）。

---

### 2. セキュリティは万全にしたい。

- **分類：非機能要件**
  - システム全体のセキュリティ要件（例：通信の暗号化、不正アクセス防止、パスワードポリシー、監査ログなど）。

---

### 3. スマホでも使いやすくしたい。

- **分類：非機能要件**
  - ユーザーインターフェースのモバイル対応（レスポンシブデザイン、タッチ操作対応など）。

---

### 4. バックエンドにはAPIを作る必要がある。

- **分類：システム要件／機能要件**
  - **システム要件**：API基盤の構築。
  - **機能要件**：APIが提供する具体的な機能（例：ユーザー情報取得、データ登録など）。

---

### 5. 管理者画面も必要。

- **分類：機能要件**
  - 管理者向け画面の提供（例：利用者管理、データ閲覧・編集など）。

---

### まとめ表

| 仕様内容                   | 機能要件 | 非機能要件 | システム要件 | 運用要件 |
|----------------------------|----------|------------|--------------|----------|
| 簡単にログイン              | 〇       | 〇         |              |          |
| セキュリティ万全            |          | 〇         |              |          |
| スマホでも使いやすい        |          | 〇         |              |          |
| バックエンドAPIの必要性     | 〇       |            | 〇           |          |
| 管理者画面                  | 〇       |            |              |          |

---

ご不明な点や、さらに詳細な要件定義への落とし込みが必要な場合はご指示ください。

## GPT-4o

曖昧な仕様を要件定義書の構成に分類すると、以下のようになります。

1. **機能要件**
   - ユーザーは簡単にログインできるようにしたい。
   - 管理者画面も必要。
   - バックエンドにはAPIを作る必要がある。

2. **非機能要件**
   - セキュリティは万全にしたい。
   - スマホでも使いやすくしたい。

3. **システム要件**
   - バックエンドにはAPIを作る必要がある。（APIの具体的な仕様や技術スタックの選定も含まれる場合はシステム要件に該当することがあります）

4. **運用要件**
   - 現時点では具体的な運用要件に該当する内容が提示されていませんが、運用に関する要件が出てきた場合にこの分類に含まれます。

曖昧な仕様を具体的な要件に落とし込むためには、さらに詳細な検討と具体化が必要です。特に、セキュリティやユーザーの使いやすさをどのように実現するかについては、技術的な詳細や運用上のプロセスを定義する必要があります。

# まとめ

指示を忠実かつ高精度に実行する能力という観点ではGPT-4.1の方が優れているようです。今回は試していませんでしたが、コンテキスト長も100万トークンと非常に長いので、コーディングのシーンでは威力を発揮しそうです。

GPT-4oはその柔軟性とクリエイティブ性が役立つシーンが別にあるので、ユースケースに応じて使い分けるのが良さそうです。

こちらもGPT-4oにまとめていただきました。

![Screenshot 2025-04-29 at 13.11.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/230feb50-1aac-490a-98cf-58bc6846d5d7.png)


### はじめてのDatabricks

[はじめてのDatabricks](https://qiita.com/taka_yayoi/items/8dc72d083edb879a5e5d)

### Databricks無料トライアル

[Databricks無料トライアル](https://databricks.com/jp/try-databricks)