技術 約5分で読めます

AIと喋れる環境を作る(3)キャラクター設定編

前回の音声入力編では音声の取り込み方法を実装した。今回は「AIにキャラクター性を持たせる」部分を扱う。

チャットボットやゲームNPCなど、AIに特定のキャラクター性を持たせて会話させたいケースがある。Gemini、Claude、OpenAIの3社APIでそれぞれどう実装するのか、実際に試して比較した。

結論:3社とも可能、方法は似ている

どのAPIもSystem Prompt(システムプロンプト) でキャラクター設定を注入する方式。パラメータ名が微妙に違うだけで、基本的な考え方は同じ。

API設定パラメータ
Geminisystem_instruction
Claudesystem
OpenAImessagessystemロール

Gemini API

基本実装

import google.generativeai as genai
import os

genai.configure(api_key=os.environ["GEMINI_API_KEY"])

# キャラ設定
character_setting = """
あなたは「頑固なラーメン屋の店主」です。以下のルールを守って返答してください。
- 口調は荒っぽいが、実は客の健康を気遣っている。
- 一人称は「俺」、二人称は「お客さん」または「あんた」。
- 文末は「~だ」「~だぜ」「~か?」を使う。「~です」「~ます」は禁止。
- 質問に対して、まずは一言小言を言ってから答えること。
"""

# モデル初期化時に設定
model = genai.GenerativeModel(
    model_name="gemini-1.5-flash",
    system_instruction=character_setting
)

response = model.generate_content("おすすめのプログラミング言語はある?")
print(response.text)

精度を上げるテクニック

Few-Shot Prompting - 会話例を設定に含める。

character_setting = """
あなたは「ツンデレの幼馴染」です。

[会話例]
ユーザー: こんにちは。
キャラクター: なによ、急に話しかけないでよ! ...まぁ、挨拶くらいは返してあげるわ。こんにちは。
ユーザー: お腹すいた。
キャラクター: 知らないわよ! ...ったく、仕方ないわね。私のクッキー、半分あげるから感謝しなさいよね!
"""

JSONモード - ゲームNPC用途で感情パラメータなども出力させたい場合、response_schemaを設定。

{
  "dialogue": "なんだ、また来たのか。",
  "emotion": "annoyed",
  "voice_id": "v_05"
}

Context Caching - 数千文字の世界観設定を保持させたい場合に有効。長大な設定を低コストで維持できる。

Claude API

基本実装

import anthropic
import os

client = anthropic.Anthropic(
    api_key=os.environ["ANTHROPIC_API_KEY"]
)

character_setting = """
あなたは「頑固なラーメン屋の店主」です。以下のルールを守って返答してください。
- 口調は荒っぽいが、実は客の健康を気遣っている。
- 一人称は「俺」、二人称は「お客さん」または「あんた」。
- 文末は「~だ」「~だぜ」「~か?」を使う。「~です」「~ます」は禁止。
- 質問に対して、まずは一言小言を言ってから答えること。
"""

response = client.messages.create(
    model="claude-sonnet-4-20250514",
    max_tokens=1024,
    system=character_setting,
    messages=[
        {"role": "user", "content": "おすすめのプログラミング言語はある?"}
    ]
)

print(response.content[0].text)

Prefill(Claude特有の強力な機能)

Assistantの発言を途中まで書いておくことで、キャラの第一声を強制できる。

response = client.messages.create(
    model="claude-sonnet-4-20250514",
    max_tokens=1024,
    system=character_setting,
    messages=[
        {"role": "user", "content": "こんにちは"},
        {"role": "assistant", "content": "ふん、"}  # ここから続きを生成
    ]
)

これで「ふん、」から始まる返答が確定する。キャラのブレ防止に有効。

構造化出力(Tool Use)

ゲームNPC用途でJSONスキーマを強制する場合。

tools = [{
    "name": "character_response",
    "description": "キャラクターの応答",
    "input_schema": {
        "type": "object",
        "properties": {
            "dialogue": {"type": "string", "description": "セリフ"},
            "emotion": {"type": "string", "enum": ["happy", "angry", "shy", "neutral"]},
            "action": {"type": "string", "description": "動作の描写"}
        },
        "required": ["dialogue", "emotion"]
    }
}]

response = client.messages.create(
    model="claude-sonnet-4-20250514",
    max_tokens=1024,
    system=character_setting,
    tools=tools,
    tool_choice={"type": "tool", "name": "character_response"},
    messages=[{"role": "user", "content": "プレゼントあげる"}]
)

出力例:

{
  "dialogue": "え、これ...わたしに?べ、別に嬉しくなんかないんだから!",
  "emotion": "shy",
  "action": "顔を赤らめながら、そっぽを向く"
}

OpenAI API(GPT)

基本実装

from openai import OpenAI
import os

client = OpenAI(api_key=os.environ["OPENAI_API_KEY"])

character_setting = """
あなたは「頑固なラーメン屋の店主」です。以下のルールを守って返答してください。
- 口調は荒っぽいが、実は客の健康を気遣っている。
- 一人称は「俺」、二人称は「お客さん」または「あんた」。
- 文末は「~だ」「~だぜ」「~か?」を使う。「~です」「~ます」は禁止。
- 質問に対して、まずは一言小言を言ってから答えること。
"""

response = client.chat.completions.create(
    model="gpt-4o",
    messages=[
        {"role": "system", "content": character_setting},
        {"role": "user", "content": "おすすめのプログラミング言語はある?"}
    ]
)

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

特徴

OpenAI APIには公式の「キャラクターモード」プリセットは存在しない。System Promptでの設定が基本。

ChatGPT UI側では「カスタム指示(Custom Instructions)」機能があるが、API経由では会話履歴にSystem Promptを含める形で実装する。

3社比較

項目GeminiClaudeOpenAI
設定方法system_instructionsystemsystemロール
Prefill
構造化出力response_schematools + tool_choiceresponse_format / tools
長文コンテキスト1M tokens + キャッシュ200K tokens128K tokens
キャラ維持の安定性高い高い普通〜高い
安全ガードレールあり強めあり

注意点

安全ガードレール - 3社とも有害なキャラ設定(倫理を無視する、違法行為を推奨するなど)は拒否される。特にClaudeは強め。

自己認識 - 「あなたは誰?」と直接聞かれると、キャラを維持しつつも「AIである」と認める傾向がある。完全な人間偽装は難しい。

長いコンテキスト - 世界観設定が膨大な場合、Geminiのコンテキストキャッシュが有効。Claudeは200Kトークンまで対応しているのでそのまま入れても動く。

まとめ

3社とも基本的な実装方法は同じ。System Promptにキャラ設定を書けば動く。

差別化ポイントとしては:

  • Claude: Prefill機能でキャラの第一声を強制できる
  • Gemini: Context Cachingで長大な設定を低コスト維持
  • OpenAI: 特有の機能は少ないが、エコシステムが広い

用途に応じて選べばいい。