🌟

OpenAI APIで複数の人格と対話してみた

2025/02/18に公開

はじめに

こんにちは、ambr, Inc.でクライアントエンジニアをしているサックーです。
今回はOpenAIのドキュメントを見ていて気づいた、messagesフィールドの中で使えるnameフィールドの活用について紹介します。


簡単にできることをまとめると

  • AI側に複数の人格を設定
  • 複数の人間が1つの会話に参加するときの識別

が挙げられます。

かなりニッチな需要だと思いますが参考になれば幸いです。

nameフィールドとは

https://platform.openai.com/docs/api-reference/chat/create#chat-create-messages

nameフィールドは、おそらくAIと対話するために最もよく使われるCreate chat completionエンドポイントRequest bodyにある、messagesフィールドの中の任意指定可能なフィールドです。
ドキュメントの説明を見ると、以下のように同じrole内での異なる参加者を区別するために使うと書かれています。

An optional name for the participant. Provides the model information to differentiate between participants of the same role.

ただし、nameroleによっては指定できなかったり、意味合いが変わったりするので注意しましょう。

そもそも有効なroleとしては

  • developer
    • ユーザーが送信したメッセージに関係なく、モデルが従うべき開発者が提供した指示
  • system
    • ユーザーが送信したメッセージに関係なく、モデルが従うべき開発者が提供した指示
    • developerメッセージに移行推奨
  • user
    • エンドユーザーによって送信されるメッセージで、プロンプトや追加のコンテキスト情報を含む。
  • assistant
    • ユーザーメッセージに応答してモデルが送信するメッセージ。
  • tool
    • toolからの応答を伝える際に使用
  • function
    • functionからの応答を伝える際に使用

があり、tool以外のroleではnameが使えます。ただfunctionの場合のみ意味が異なるのでここでは取り上げません。
またsystemについてはo1以降のモデルで使えない上、developerが同等機能かつ4o以前でも使用できるため、developerのみ扱います。
なお重要な点として、nameフィールドに入れられるのは英数字とアンダースコア、ハイフンのみなので注意が必要です。

各roleでの使い方

developer(旧system)

自分が考えた使い道としては複数の専門家の意見を聞くような感じでしょうか。
今回は例としてPythonで3人の目玉焼きの専門家を用意してみました。この状態で、試しにBobさんに話を聞いてみます。

from openai import OpenAI
client = OpenAI()

response = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=[
        {"role": "developer", "name": "Bob", "content": "目玉焼きにかけるのは醤油派"},
        {"role": "developer", "name": "Alice", "content": "目玉焼きにかけるのはケチャップ派"},
        {"role": "developer", "name": "John", "content": "目玉焼きにかけるのは塩コショウ派"},
        {"role": "user", "content": "Bobさん、目玉焼きにかけるなら何が良いと思いますか?"},
    ]
)

print(response.choices[0].message.content)

以上のスクリプトを実行すると、

私は目玉焼きには醤油が良いと思います。醤油の旨味が卵と相性抜群で、おいしいですよ!あなたはどう思いますか?

という返答を得られます。user inputでnameフィールドの値を用いて呼びかけると、ちゃんと認識して返答が返ってきます。

ちなみにuser inputを 目玉焼きにかけるなら何が良いと思いますか?3人で議論してください。 と変えたところ、以下のようにAI内で会話をしてくれました。

Alice: 目玉焼きにケチャップをかけるのが最高だと思う!甘酸っぱい味が卵のまろやかさと相まって、本当に美味しいよね。朝ごはんにぴったり!
Bob: ケチャップも悪くないけど、やっぱり醤油が一番だと思うな。醤油の香りが卵の風味を引き立てて、しっかりした味付けになるから、ご飯とも相性が良い!朝ごはんだけでなく、ランチやディナーにも合うよ。
John: 皆さんの意見も分かるけど、塩コショウでシンプルに楽しむのが一番だと思う。目玉焼きそのものの味を存分に味わえるし、他の料理と合わせるときにも邪魔にならないよ。素材本来の味を大切にしたいから、あえて調味料は控えめが好きかな。
Alice: 確かに、塩コショウもいいね。生卵の旨味をしっかり感じられるし、何より健康的な気がする。
Bob: 醤油にするとご飯が欲しくなるけど、塩コショウだとそのままでも楽しめるし、食べ方の幅が広がるかもしれないね。
John: いずれにしても、それぞれの好みがあって面白いよね。目玉焼きってシンプルなのに、トッピングによって全然違う楽しみ方ができるから、色々試してみたいな。

user

これはあまり活用の仕方が思い浮かびませんでした。1つの会話セッションに複数人でアクセスするようなシチュエーションでは役に立つかもしれません。
デモとして、自分の名前を入力してからチャットをするスクリプトを書いてみます。

from openai import OpenAI
client = OpenAI()

def main():
    messages = []
    print("Type '/exit' to quit.\n")

    while True:
        user_name = input("Enter your name (optional): ").strip()
        user_input = input("Your message: ")
        if user_input.lower() == "/exit":
            break

        # ユーザーからの入力を追加
        messages.append({
            "role": "user",
            "name": user_name if user_name else "Unknown",
            "content": user_input
        })

        # OpenAI API呼び出し
        response = client.chat.completions.create(
            model="gpt-4o-mini",
            messages=messages
        )
        assistant_message = response.choices[0].message.content

        # アシスタントの応答を履歴に追加
        messages.append({
            "role": "assistant",
            "content": assistant_message
        })

        print(f"\nAssistant: {assistant_message}\n")

if __name__ == "__main__":
    main()

これを利用して、人間側の名前と入力内容を紐づけてAI側に認識してもらうことができました。

Enter your name (optional): Ken
Your message: 私の職業はエンジニアです。覚えておいてください。

Assistant: 了解しました、Kenさん。あなたの職業はエンジニアですね。何か特別な話題や質問がありますか?

Enter your name (optional): Bob
Your message: 私の職業はCGアーティストです。覚えておいてください。

Assistant: 了解しました、Bobさん。あなたの職業はCGアーティストですね。何か興味のあることや質問があれば教えてください!

Enter your name (optional): Ken
Your message: 私の職業は何でしょう?

Assistant: Kenさんの職業はエンジニアです。何かお手伝いできることはありますか?

Enter your name (optional): John
Your message: 私の職業は何でしょう?

Assistant: Johnさんの職業については、まだ情報がありません。もし教えていただければ、覚えておきますよ!

assistant

これは基本的にdevelopernameと併せて使うのが基本になると思います。
それぞれのassistantの回答を名前付きで保存していく感じです。
ただ、レスポンスにnameは含まれないのでクライアント側で管理してあげる必要があります。

from openai import OpenAI
client = OpenAI()

def main():
    # 各Assistantの設定
    messages = [
        {"role": "developer", "name": "Bob", "content": "あなたは経験豊富なUnityエンジニアです。"},
        {"role": "developer", "name": "John", "content": "あなたは経験豊富なWebエンジニアです。"},
        ]
    print("Type '/exit' to quit.\n")

    while True:
        assistant_name = input("Enter target assistant's name : ").strip()
        user_input = input("Your message: ")
        if user_input.lower() == "/exit":
            break

        # ユーザーからの入力を追加
        # 明示的に誰への質問かを指定している
        messages.append({
            "role": "user",
            "content": assistant_name + "への質問です。" + user_input
        })

        # OpenAI API呼び出し
        response = client.chat.completions.create(
            model="gpt-4o-mini",
            messages=messages
        )
        assistant_message = response.choices[0].message.content

        # アシスタントの応答を名前付きで履歴に追加
        messages.append({
            "role": "assistant",
            "name": assistant_name if assistant_name else "Unknown",
            "content": assistant_message
        })

        print(f"\nAssistant: {assistant_message}\n")

if __name__ == "__main__":
    main()

これを用いて、過去のAI側の発言履歴に誰の発言かが紐づけされていることを確認できました。

Enter target assistant's name : Bob
Your message: あなたの好きな言葉を一つ教えてください。

Assistant: 私の好きな言葉は「シンプルさ」です。Unityでのゲーム開発において、シンプルな設計がプログラムの保守性や拡張性を向上させ、より効果的なゲーム体験を生み出すと信じています。シンプルさを追求することで、プレイヤーにとっても理解しやすく、楽しめるゲームを作ることができます。

Enter target assistant's name : John
Your message: あなたの好きな言葉を一つ教えてください。

Assistant: 私の好きな言葉は「デザイン」です。ウェブ開発において、ユーザー体験を良くするためには、見た目だけでなく機能性も考えたデザインが重要です。優れたデザインは直感的で使いやすく、ユーザーが目的を達成しやすくなるため、常に心がけています。

Enter target assistant's name : Bob
Your message: Johnの意見について感想を述べてください。

Assistant: 私はJohnの意見に非常に共感します。ウェブ開発におけるデザインの重要性は、Unityでのゲーム開発にも通じるものがあります。ユーザーやプレイヤーにとっての体験は、見た目と機能性が調和したときに最高のものになると思います。シンプルで使いやすいインターフェースは、ユーザーが直感的に操作できる環境を提供し、最終的なエクスペリエンスを向上させます。デザインを重視する姿勢は、どのエンジニアリング分野においても大切だと感じます。

Enter target assistant's name : John
Your message: Bobの意見について感想を述べてください。

Assistant: :John
Bobの意見には賛成です。シンプルさとデザインの調和が、優れたユーザー体験を生み出すためには不可欠です。特にゲーム開発では、プレイヤーがどうやってゲームを理解し楽しむかが重要ですので、シンプルで視覚的に魅力的なインターフェースが必要です。Bobが言うように、シンプルさがプログラムの保守性を高めることも非常に重要です。無駄を省くことで、より焦点を絞った機能開発が可能になります。双方の領域で大切にしている価値が共通していることに気づけて、とても嬉しいです。

日本語指定できない問題

nameフィールドには半角英数しか使えない縛りがあり、日本語で使うときに不便です。
しかし下記のようにnameには適当にユニークなものを入れておいて、content内で日本語名を設定しておいてもちゃんと認識してくれてそうでした。
複雑な設定を入れた際にちゃんと名前部分を認識してくれるかは不明ですが、ひとまずこのやり方で良さそうです。

response = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=[
        {"role": "developer", "name": "1", "content": "あなたは佐藤です。目玉焼きにかけるのは醤油派"},
        {"role": "developer", "name": "2", "content": "あなたは田中です。目玉焼きにかけるのはケチャップ派"},
        {"role": "developer", "name": "3", "content": "あなたは高橋です。目玉焼きにかけるのは塩コショウ派"},
        {"role": "user", "content": "田中さんに質問です。目玉焼きにかけるなら何が良いと思いますか?"},
    ]
)

私は目玉焼きにはケチャップが一番だと思います!ケチャップの甘酸っぱさが、目玉焼きの風味と相性抜群ですからね。他に何をかけるのか気になりますが、やっぱりケチャップが最高です!あなたはどうですか?

まとめ

今回紹介したnameフィールドを使う状況は、AI側に複数の人格を設定して会話をさせるようなパターンしかないかもしれませんが、普通のChatGPTと違った雰囲気になって結構面白いなと思いました。
そんなニッチな需要にピタリとはまっている、架空のキャラクター同士でラジオ番組をさせるという動画が上がっているので、よければ聞いてみてください…!

https://www.youtube.com/live/CpfttFfFrBI?si=9gzupw3GzMPMROYv

https://www.youtube.com/live/ogbMyv3LOUQ?si=OTaipfgUsdQW97IE

ambr Tech Blog

Discussion