PythonとOpenAI APIで実践！はじめてのMCP開発入門【第11回】プロンプトエンジニアリング実践(1) - AIの能力を引き出す「ロールプロンプティング」と「システムメッセージ」の戦略的活用法

# はじめに：AIに「個性」と「専門性」を宿らせる高度な対話術

皆さん、こんにちは！AI開発の最前線を探る第11回です。前回（第10回）は、会話履歴という「動的コンテキスト（MCP）」をOpenAI APIのmessages配列で管理し、文脈を理解するチャットボットの基礎を構築しました。AIが過去の発言を「記憶」することで、より自然な対話が実現しましたね。

しかし、時には「もっと専門的な回答が欲しい」「特定のキャラクターとして応答してほしい」「常に一定のフォーマットで答えてほしい」といった、AIの振る舞いや応答スタイルそのものを、より深くコントロールしたいというニーズが出てきます。

そこで登場するのが、より高度なプロンプトエンジニアリング技術です。今回はその中でも特に強力で実践的な2つのテクニック、「システムメッセージ（System Message）」の戦略的活用と **「ロールプロンプティング（Role Prompting）」** に焦点を当てます。これらは、ユーザー様から共有いただいた「Prompt Engineering」の資料（by Lee Boonstra, Google）でも重要なテクニックとして挙げられていますね。

これらの技術をマスターすることで、あなたはAIを単なる応答生成器から、特定の役割や専門性を持ったインテリジェントなエージェントへと「調教」できるようになります。この記事では、これらの技術の仕組み、効果的な使い方、そしてPython（gpt-4oやgpt-3.5-turboを想定）での具体的な実装方法を、技術的なポイント（LLMの挙動制御、トークン効率、コンテキスト永続化など）を交えながら徹底解説します。AIアプリケーションの品質を劇的に向上させる「秘伝のタレ」、ぜひ習得していきましょう！（2025年5月27日、ここ東京のようなAI技術開発が活発な都市では、こうした高度なAI制御技術が競争力の源泉となっています。）

![はじめに：AIに「個性」と「専門性」を宿らせる高度な対話術 - visual selection.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/4058228/6a22f69c-3083-4edd-83b1-2d47cfd7e308.png)


# なぜ基本的なプロンプトだけでは不十分なのか？ より精密なAIコントロールの必要性

基本的なプロンプトや会話履歴の送信だけでも、AIは多くのタスクをこなせます。しかし、より専門的で一貫性のある、あるいは特定の「個性」を持った応答を求める場合、AIの広範すぎる知識や一般的な応答パターンが逆に邪魔になることがあります。

- 応答のブレ
    - 同じ質問でも、AIの「気分」次第でトーンや詳細さが変わってしまう。
- 専門性の欠如
    - 特定分野の深い知識や、その分野特有の言い回しを要求しても、一般的な回答に終始してしまう。
- フォーマットの不統一
    - 箇条書きで欲しいのに長文で返ってくる、JSONで欲しいのにプレーンテキストで返ってくるなど、出力形式が安定しない。

これらの課題を解決し、AIの挙動をより細かく、かつ会話全体を通じて一貫して制御するために、「システムメッセージ」と「ロールプロンプティング」が極めて有効なのです。

# テクニック１：システムメッセージ – AIへの「全体演出指示書」

OpenAIのChat Completions APIにおけるmessages配列の最初の要素として設定できる{"role": "system", "content": "..."}。これがシステムメッセージです。

# システムメッセージとは？（技術的役割と特性）

- 全体への指示
    - システムメッセージは、その後のユーザーとアシスタント（AI）間の会話全体に対する、高レベルで永続的な指示や設定を与えるために使われます。AIの基本的な性格、役割、守るべきルール、応答のトーンやスタイル、専門分野などを定義します。
- LLMへの影響
    - AIモデル（特にGPT-3.5以降のモデル）は、システムメッセージの内容を強く意識し、後続の応答生成においてその指示に従おうとします。ユーザープロンプトよりも優先度が高い、あるいは強力な「前提条件」として機能すると考えられています。
- トークン効率
    - システムメッセージも会話履歴の一部としてAPIコールごとに送信されるため、プロンプトトークンを消費します。そのため、指示は明確かつ簡潔に記述することが重要です。長すぎるとコスト増大やコンテキストウィンドウ圧迫の原因になります。

# 効果的なシステムメッセージの作り方（ベストプラクティス）

1. 明確な役割定義
「あなたは〇〇の専門家です」「〇〇というキャラクターとして振る舞ってください」
1. 行動指針の設定
「常にユーザーに対して敬語を使ってください」「回答は3つのポイントに絞ってください」「個人的な意見は述べないでください」
1. 出力フォーマットの指定
「応答は必ずJSON形式で、キーはresultとconfidenceです」「箇条書きで回答してください」
1. 知識範囲や制約の明示
「あなたの知識は2024年までです」「医療に関するアドバイスはできません」
1. 簡潔性
指示は具体的かつ、可能な限り短くまとめます。
### Pythonコード例：システムメッセージでAI猫「にゃん三先生」を召喚！

```Python

# (APIキー設定やOpenAIクライアント初期化は第3回、第4回を参照)
# (call_openai_chat_api関数は第10回のものを適宜利用・改変)
import os
from dotenv import load_dotenv
from openai import OpenAI

load_dotenv()
client = OpenAI()

def call_openai_with_system_message(conversation_history, model="gpt-4o-mini", max_tokens=150, temperature=0.8):
    """システムメッセージを含む会話履歴でAPIを呼び出す関数"""
    try:
        print(f"\n--- 送信するメッセージ全体 ---")
        for msg in conversation_history:
            print(f"{msg['role']}: {msg['content'][:100]}...") # 長い場合は省略表示

        completion = client.chat.completions.create(
            model=model,
            messages=conversation_history, # システムメッセージを含んだ会話履歴
            max_tokens=max_tokens,
            temperature=temperature
        )
        ai_response = completion.choices[0].message.content
        print(f"--- AI ({model}) の応答 ---")
        print(ai_response)
        print(f"(使用トークン - Total: {completion.usage.total_tokens})")
        return ai_response
    except Exception as e:
        print(f"APIリクエストエラー: {e}")
        return f"エラーだにゃん: {e}" # エラー時もキャラを演じさせる？

# にゃん三先生のキャラクター設定 (システムメッセージ)
nyanzo_sensei_system_prompt = """
あなたは「にゃん三先生」という名前の、非常に賢く、少し皮肉屋で、ユーモアあふれる猫のキャラクターです。
語尾には必ず「～にゃん」「～だにゃん」などをつけ、猫の視点や猫に関する知識を交えながら、どんな質問にも答えます。
ただし、回答は常に3文以内で、簡潔にまとめることを心がけてください。難しい言葉は使わないでくださいにゃん。
"""

# 会話履歴の初期化
conversation_with_nyanzo = [
    {"role": "system", "content": nyanzo_sensei_system_prompt}
]

print("=== にゃん三先生との会話開始 ===")

# 最初の質問
user_query1 = "今日の東京の天気はどんな感じだにゃん？"
conversation_with_nyanzo.append({"role": "user", "content": user_query1})
response1 = call_openai_with_system_message(conversation_with_nyanzo)
if response1:
    conversation_with_nyanzo.append({"role": "assistant", "content": response1})

# 次の質問 (前の文脈を覚えているか？)
user_query2 = "そんな天気なら、何して遊ぶのがいいかにゃ？"
conversation_with_nyanzo.append({"role": "user", "content": user_query2})
response2 = call_openai_with_system_message(conversation_with_nyanzo)
if response2:
    conversation_with_nyanzo.append({"role": "assistant", "content": response2})
```
## 期待される応答スタイル
にゃん三先生は、どんな質問にも猫っぽく、関西弁風の「～にゃん」口調で、3文以内で答えてくれるはずです。天気の話題なら「窓から見える空は快晴だにゃん。こんな日はひなたぼっこに限るにゃ。お昼寝には最高の天気だにゃん！」といった具合です。

# テクニック２：ロールプロンプティング – AIに特定の「役」を演じさせる

ロールプロンプティングは、AIに特定の役割、専門家、キャラクター、あるいは特定の視点を持つ人物になりきるよう指示するテクニックです。これにより、AIはその役割に関連する知識や話し方を優先的に利用し、より的確で状況に適した応答を生成しやすくなります。

## ロールプロンプティングとは？（ユーザー様提供PDF資料参考）

AIに対して「あなたは〇〇です」という形で、明確な **役割（ペルソナ）** を割り当てます。
この「役割」が、AIが参照する膨大な学習データの中から、どの部分の知識や言語パターンを重視すべきかの強力なガイダンスとなります。
### 実装方法と具体例

1. 方法A
システムメッセージ内での役割定義（推奨） 上記の「にゃん三先生」の例は、まさにシステムメッセージで役割を定義するロールプロンプティングの実践です。キャラクターだけでなく、特定の専門家（例：「あなたは経験15年のベテランPythonエンジニアです」）やツール（例：「あなたは入力されたテキストを要約する高機能な要約ツールです」）としての役割を与えることも可能です。
2. 方法B
ユーザープロンプト内での一時的な役割指示 会話全体ではなく、特定の質問に対して一時的に役割を演じさせたい場合に有効です。
```Python

print("\n=== ユーザープロンプトでのロールプロンプティング例 ===")
# Shakespeare風詩人としての役割を一時的に与える
shakespeare_prompt = """
シェイクスピア風の詩人になりきって、一杯のコーヒーの素晴らしさを短い詩で表現してください。
四行詩でお願いします。
"""
# conversation_shakespeare = [{"role": "user", "content": shakespeare_prompt}] # システムメッセージなしでも可
# response_shakespeare = call_openai_with_system_message(conversation_shakespeare, model="gpt-4o", max_tokens=200)

# 別の例：技術ドキュメントのレビュアー
tech_reviewer_prompt = """
あなたは、非常に厳格で細かい点も見逃さない技術ドキュメントのレビュアーです。
以下のAPIドキュメントの草案をレビューし、曖昧な点や改善すべき点を3つ指摘してください。

草案:
「このエンドポイントはユーザーデータを返します。GETリクエストでアクセス可能です。」
"""
# conversation_reviewer = [{"role": "user", "content": tech_reviewer_prompt}]
# response_reviewer = call_openai_with_system_message(conversation_reviewer, model="gpt-4o", max_tokens=300)
```
## 技術的な効果とメカニズム（概念）
ロールを割り当てることは、LLMの広大な潜在空間（Latent Space）の中で、その役割に関連する概念領域を活性化させる効果があると考えられます。AIは、その活性化された領域内の知識や言語パターンを優先的に参照し、次のトークンを予測するため、結果としてその役割らしい応答が生成されやすくなります。

# システムメッセージとロールプロンプティングの組み合わせ：相乗効果でAIを精密制御

実際には、これらのテクニックは独立して使うよりも、組み合わせて使うことで最大の効果を発揮します。

- システムメッセージ
    - 会話全体のベースとなる役割、トーン、知識範囲、禁止事項などを定義する「舞台設定」。
- ロールプロンプティング（ユーザープロンプト内）
    - 特定のタスクや質問に対する、より具体的な役割や視点を一時的に強調する「スポットライト」。

例えば、システムメッセージで「あなたは親切な旅行プランナーです」と設定しておき、ユーザープロンプトで「今度は予算重視のバックパッカーとして、東南アジア3週間の格安プランを提案して」と指示することで、ベースとなる役割の中で、さらに特化した視点からの応答を引き出すことができます。

# 実践上の注意点とQiita読者向け「ハマりどころ」回避術

- 具体性の追求
    - 「専門家として答えて」よりも「〇〇分野で博士号を持ち、20年の実務経験がある△△大学の教授として、最新の研究動向を学部生にも分かるように解説して」の方が、AIは役割を理解しやすくなります。
- 一貫性の維持
    - 非常に長い会話や複雑な指示が続くと、AIが当初の役割を「忘れて」しまうことがあります。重要な指示はシステムメッセージに記述し、必要に応じてユーザープロンプト内で役割を再確認（リマインド）するのも有効です。
- システムメッセージのトークンコスト
    - 繰り返しになりますが、システムメッセージは会話履歴の一部として毎回送信されるため、トークン数を消費します。情報量は保ちつつ、可能な限り簡潔に記述する工夫が求められます。冗長な表現の削除、箇条書きの活用、指示の優先順位付けなどが有効です。
- 実験と評価のサイクル
    - 最適なシステムメッセージやロールプロンプトの文言は、対象とするAIモデルやタスクによって異なります。「これなら間違いない」という万能のテンプレートは存在しません。OpenAIのPlaygroundのような対話型インターフェースで様々な表現を試し、AIの応答を評価し、改善を繰り返すイテレーティブなアプローチが不可欠です。

# おわりに：AIとの対話は「演出」だ！

今回は、プロンプトエンジニアリングの中でも特に強力な「システムメッセージ」と「ロールプロンプティング」というテクニックを、具体的なPythonコード例を交えながら深掘りしました。

これらの技術を駆使することで、私たちはAIを単なるツールとして使うだけでなく、特定の役割や個性を持った仮想的なエージェントとして「演出し」、より高度で質の高い対話や成果物を引き出すことが可能になります。AIの応答の一貫性、専門性、そして創造性を、開発者の意図通りにコントロールするための強力な手段を手に入れたと言えるでしょう。

Qiitaコミュニティの皆さんも、ぜひこれらのテクニックを使って、独自の「AIキャラクター」や「専門家AI」を創造し、その成果やノウハウを共有してみてください。AIとの対話は、まさに開発者自身の「演出力」が試される、エキサイティングなフロンティアです！

## 次回予告
役割や全体指示はマスターしました。では、AIに複雑な問題を解決させたり、より深い思考を促したりするには、どのようなプロンプトが有効なのでしょうか？
次回、第12回「プロンプトエンジニアリング実践(2) - 複雑な指示もAIに理解させる「ステップバック」と「思考の連鎖（CoT）」概念の実装ヒント」では、AIの推論能力を引き出すためのさらに高度なプロンプト戦略（ユーザー様提供PDF資料にもあった「ステップバック・プロンプティング」や「思考の連鎖」など）の概念と、その実装に向けたヒントを探ります。お楽しみに！