LLM アプリ開発 #2 メッセージとパラメータを理解する

読了 6分

第1回で最初の呼び出しを行いました。そのときは messages にユーザーメッセージを一つだけ入れて先に進みましたが、今回はその messages の構造と、呼び出しに一緒に渡す主なパラメータをしっかり見ていきます。これを知ることで、Claude に文脈と指示を正確に伝えられるようになります。

会話はメッセージのリストである #

messages は名前のとおりメッセージのリストです。各メッセージは、誰が話したかを表す role と、内容である content で構成されます。role には二つあります。

  • user — ユーザーが言ったこと
  • assistant — Claude が返した答え

第1回では user を一つだけ入れました。ところが会話を続けるには、これまでに何をやり取りしたかを伝える必要があります。ここで LLM API の重要な性質が一つ出てきます。

API は以前の会話を覚えていません。

各呼び出しは独立していて、サーバーは前回何を話したかを保存しません。ですから会話を続けるには、これまでの内容を毎回まるごと送り直します。

multi_turn.py
import anthropic

client = anthropic.Anthropic()

response = client.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=1024,
    messages=[
        {"role": "user", "content": "私の名前はミンスです。"},
        {"role": "assistant", "content": "こんにちは、ミンスさん。よろしくお願いします。"},
        {"role": "user", "content": "私の名前は何だと言いましたか?"},
    ],
)

for block in response.content:
    if block.type == "text":
        print(block.text)

assistant メッセージを自分でリストに入れ、前の答えをもう一度聞かせている点に注目してください。Claude はこの messages 全体を読んで答えるので、「ミンス」という名前を正しく覚えて返します。もし最後の user メッセージだけを送っていたら、Claude は名前を知る方法がありません。

ですからチャットボットを作るときは、やり取りしたメッセージをリストに積み上げておき、呼び出すたびにその全体を送ります。会話が長くなればこのリストも長くなり、長くなった分だけトークンの費用が上がります。これをどう管理するかは #9 で扱います。

会話をコードで続ける #

上の例では messages を手で書きました。実際のチャットボットでは、会話が進むたびにこのリストへメッセージを足していきます。パターンは単純です。ユーザーが話したら user メッセージを足し、呼び出して受け取った答えを assistant メッセージとしてもう一度足します。

conversation_loop.py
import anthropic

client = anthropic.Anthropic()
messages = []

def chat(user_input: str) -> str:
    messages.append({"role": "user", "content": user_input})

    response = client.messages.create(
        model="claude-sonnet-4-6",
        max_tokens=1024,
        messages=messages,
    )
    answer = next(b.text for b in response.content if b.type == "text")

    messages.append({"role": "assistant", "content": answer})
    return answer

print(chat("私の名前はミンスです。"))
print(chat("私の名前は何だと言いましたか?"))  # 「ミンス」を覚えて答える

肝心なのは、受け取った答え(assistant)を必ず messages に足し戻す部分です。この一行を抜かすと、次の呼び出しのとき Claude は自分がさっき言ったことを知りません。ユーザーの入力だけが積み上がり、答えは積み上がらないので、会話が一方通行になってしまいます。

system プロンプトで役割とルールを決める #

systemmessages とは別のパラメータで、Claude に役割とルールをあらかじめ伝えるために使います。

system_prompt.py
response = client.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=1024,
    system="あなたは初心者にやさしい Python 講師です。回答には必ず短いサンプルコードを含めてください。",
    messages=[
        {"role": "user", "content": "リストを並べ替える方法を教えてください。"}
    ],
)

system に書いた指示は、以降のすべての答えに影響します。user メッセージが毎回変わっても、system の指示はそのまま保たれます。上の例なら、ユーザーが何を尋ねても、Claude はやさしい講師の口調で、サンプルコードを添えて答えます。

systemuser の役割を分けて考えておくとよいです。

  • system — 会話を通じて持続する役割、口調、出力ルール
  • user — 今回のターンの具体的な要望

つまり「あなたは Python 講師です」のような指示を、毎回の user メッセージで繰り返す必要はありません。一度 system に書いておけば済みます。

max_tokens — 応答の長さの上限 #

max_tokens は、応答が最大で何トークンまで生成されるかの上限です。第1回で見たとおり、この値を超えると応答が途中で切れます。

トークンは単語より小さい文字の断片だと考えてください。英語はおおよそ1単語が1〜2トークンで、日本語は文字あたりのトークンを多めに使います。正確な換算は今は気にしなくてよく、「長いほどトークンが多い」程度で十分です。

小さくしすぎると答えが切れます。とはいえ大きくして損をすることはありません。課金されるのは実際に生成された分だけで、max_tokens はどこまで許すかの上限にすぎません。ですからふつうは余裕をもって1024かそれ以上を与えます。

応答が切れたかどうかは response.stop_reason で確認します。

  • end_turn — Claude が言うべきことを終えて自然に終わりました。
  • max_tokens — 上限に達して途中で切れました。値を増やす必要があります。

temperature — 答えのばらつき #

temperature は、答えがどれだけ多様に出るかを調整します。0 に近いと毎回似た安定した答えになり、1 に近いとより多様で創造的な答えになります。値の範囲は 0 から 1 です。

temperature.py
response = client.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=1024,
    temperature=0.0,
    messages=[
        {"role": "user", "content": "バグを修正したコミットメッセージを一行で書いてください。"}
    ],
)

どの値を使うかは作業の性格で決めます。

  • 低く(0 に近く) — 事実抽出、分類、コード生成のように一貫性と正確さが大事なとき
  • 高く(1 に近く) — 広告コピーやブレインストーミングのように多様な表現が必要なとき

一つ誤解を解いておきます。temperature=0 だからといって、毎回一字一句まったく同じ答えが出るわけではありません。「より安定する」という意味であって、「まったく同じ」という意味ではありません。

注記
temperature は Sonnet と Haiku で使えます。最も強力な等級である最新の Opus モデル(claude-opus-4-8 など)は、ばらつきを内部で自動的に調整するためこのパラメータを受け取らず、渡して呼び出すとエラーになります。このシリーズの基本モデルである claude-sonnet-4-6 では正常に動作します。

よくつまずくところ #

メッセージを扱っていると、よく出会う問題です。

  • 最初のメッセージは user でなければならないmessages の最初の項目を assistant にするとエラーになります。会話は必ずユーザーの発言で始まります。
  • Claude がさっき言ったことを覚えていない — たいていは以前の会話を送っていない場合です。API は状態を保存しないので、続く会話では直前までの messages をすべて含める必要があります。
  • system の指示が効かない — 役割の指示を user メッセージの中に書いていないか確認します。指示は別の system パラメータに入れます。

まとめ #

今回は messages の構造と、呼び出しに一緒に渡す主要パラメータを整理しました。

  • 会話は role を持つメッセージのリストで、API は状態を保存しないので、マルチターンでは履歴を毎回すべて送ります。
  • system は会話を通じて持続する役割とルール、user は今回の要望です。
  • max_tokens は応答の長さの上限で、stop_reason で切れたかを確認します。
  • temperature は答えのばらつきを調整します。0 は安定、高いほど多様です。

次回の「LLM アプリ開発 #3 ストリーミングで応答をリアルタイム出力」では、応答を一度に受け取らず、生成されるそばから画面に流し込む方法を扱います。長い答えを待つ体感時間を大きく減らす手法です。

X