LLM アプリ開発 #2 メッセージとパラメータを理解する
第1回で最初の呼び出しを行いました。そのときは messages にユーザーメッセージを一つだけ入れて先に進みましたが、今回はその messages の構造と、呼び出しに一緒に渡す主なパラメータをしっかり見ていきます。これを知ることで、Claude に文脈と指示を正確に伝えられるようになります。
会話はメッセージのリストである #
messages は名前のとおりメッセージのリストです。各メッセージは、誰が話したかを表す role と、内容である content で構成されます。role には二つあります。
user— ユーザーが言ったことassistant— Claude が返した答え
第1回では user を一つだけ入れました。ところが会話を続けるには、これまでに何をやり取りしたかを伝える必要があります。ここで LLM API の重要な性質が一つ出てきます。
API は以前の会話を覚えていません。
各呼び出しは独立していて、サーバーは前回何を話したかを保存しません。ですから会話を続けるには、これまでの内容を毎回まるごと送り直します。
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 メッセージとしてもう一度足します。
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 プロンプトで役割とルールを決める #
system は messages とは別のパラメータで、Claude に役割とルールをあらかじめ伝えるために使います。
response = client.messages.create(
model="claude-sonnet-4-6",
max_tokens=1024,
system="あなたは初心者にやさしい Python 講師です。回答には必ず短いサンプルコードを含めてください。",
messages=[
{"role": "user", "content": "リストを並べ替える方法を教えてください。"}
],
)system に書いた指示は、以降のすべての答えに影響します。user メッセージが毎回変わっても、system の指示はそのまま保たれます。上の例なら、ユーザーが何を尋ねても、Claude はやさしい講師の口調で、サンプルコードを添えて答えます。
system と user の役割を分けて考えておくとよいです。
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 です。
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 ストリーミングで応答をリアルタイム出力」では、応答を一度に受け取らず、生成されるそばから画面に流し込む方法を扱います。長い答えを待つ体感時間を大きく減らす手法です。