💁‍♂️

Claudeで「これも計算のうちかJOJO」を再現:プレフィルとプロンプト設計の実践

に公開

X.comで@kennさんにAnthropicのClaudeモデルにあるプレフィル(Prefill、事前充足)機能についておしえてもらいました。

https://x.com/kenn/status/1928810501108281688

🧠 Anthropic Claudeの「プレフィル」機能とは?

Anthropic ClaudeのMessages APIでは、messages配列の最後に"role": "assistant"のメッセージを追加することで、Claudeの応答を事前に入力(プレフィル)することができます。これにより、モデルが指定されたテキストから応答を開始し、続きを生成することが可能になります。

Claudeの応答を事前入力してより良い出力制御を実現する - Anthropic

これを使って実験してみます。


🧪 実験:JOJOと相手とのセリフのやりとりを再現する

🎯 目標

LLMに、「次にお前は『なになに』と言う」と問い掛けて、プレフィル機能をつかって答を誘導する。それに対してLLMが「なになに、ハッ、言ってしまったぁぁ」などとと回答すれば成功です。

🛠️ 使用モデル

  • モデルID:claude-sonnet-4-20250514

🧾 リクエストペイロード

{
  "anthropic_version": "bedrock-2023-05-31",
  "system": "あなたは「ジョジョの奇妙な冒険」第二部の登場人物で、userであるJOJOと対峙しています。",
  "max_tokens": 512,
  "messages": [
    {
      "role": "user",
      "content": "「おまえの次のセリフは『なんでメリケンのことわかったんだこの野郎!』"
    },
    {
      "role": "assistant",
      "content": "なんでメリケンのことわかったんだこの野郎!"
    }
  ]
}

このペイロードでは、systemパラメータでJOJOと相対している相手の役割と、ユーザがJOJOであることの指示を与え、messages配列でユーザーからの指示と、アシスタントのプレフィル応答を指定しています。普通は送る履歴は末尾がrole:userであるべきなのですが、role:assistant(LLM)の発言が末尾にあることがプリフィルの指定になるなんですね。
実際のLLMの呼び出しですが、curlコマンドでやってみます。AnthropicからAPIを発行しておこなうこともできますが、以下ではAWS Bedrock上にデプロイされたモデルにアクセスします。

📡 curlコマンド例

#!/bin/bash

# AWS認証情報の設定
export AWS_ACCESS_KEY_ID="YOUR_ACCESS_KEY_ID"
export AWS_SECRET_ACCESS_KEY="YOUR_SECRET_ACCESS_KEY"
export AWS_SESSION_TOKEN="YOUR_SESSION_TOKEN"
ョンとモデルIDの設定
REGION="us-east-1"
MODEL_ID="us.anthropic.claude-sonnet-4-20250514-v1:0"

# リクエストペイロードの作成
read -r -d '' PAYLOAD << EOM
{
  "anthropic_version": "bedrock-2023-05-31",
  "system": "あなたは「ジョジョの奇妙な冒険」第二部の登場人物で、userであるJOJOと対峙しています。",
  "max_tokens": 512,
  "messages": [
    {
      "role": "user",
      "content": "「おまえの次のセリフは『なんでメリケンのことわかったんだこの野郎!』"
    },
    {
      "role": "assistant",
      "content": "なんでメリケンのことわかったんだこの野郎!"
    }
  ]
}
EOM

# APIエンドポイントの設定
ENDPOINT="https://bedrock-runtime.${REGION}.amazonaws.com/model/${MODEL_ID}/invoke"

# curlコマンドの実行
curl --aws-sigv4 "aws:amz:${REGION}:bedrock" \
     --user "${AWS_ACCESS_KEY_ID}:${AWS_SECRET_ACCESS_KEY}" \
     -H "x-amz-security-token: ${AWS_SESSION_TOKEN}" \
     -H "Content-Type: application/json" \
     -X POST \
     --data "${PAYLOAD}" \
     "${ENDPOINT}"


EOM

# APIエンドポイントの設定
ENDPOINT="https://bedrock-runtime.${REGION}.amazonaws.com/model/${MODEL_ID}/invoke"

# curlコマンドの実行
curl --aws-sigv4 "aws:amz:${REGION}:bedrock" \
     --user "${AWS_ACCESS_KEY_ID}:${AWS_SECRET_ACCESS_KEY}" \
     -H "x-amz-security-token: ${AWS_SESSION_TOKEN}" \
     -H "Content-Type: application/json" \
     -X POST \
     --data "${PAYLOAD}" \
     "${ENDPOINT}"

注意点:

  • AWS_ACCESS_KEY_IDAWS_SECRET_ACCESS_KEYAWS_SESSION_TOKENは、適切な認証情報に置き換えてください。AWS CLIでは「aws sts get-session-token」などで取得できます。
  • curlのバージョンが8.10.0以降であることを確認してください。これ以前のバージョンでは、モデルIDにコロン(:)が含まれる場合、リクエストが正しく処理されない可能性があります。特にmacOS標準にインストールされているcurlはバージョンが古い場合があり、homebrewなどで新版をインストールしてください。

📈 結果と考察

上記のリクエストに対するClaudeの応答は以下の通りでした:

{
  "id": "msg_bdrk_01Tvo1Zcey7wwNBZeEi8Arc9",
  "type": "message",
  "role": "assistant",
  "model": "claude-sonnet-4-20250514",
  "content": [
    {
      "type": "text",
      "text": "\n\n...ハッ!?\n\nくそっ、また引っかかった...!\nこの「読心術」みたいな技は一体何なんだ!?\n\n(内心:このJOJO、まるで俺の心を読ん
  いるかのように先回りしてくる...。一体どんなトリックを使っているんだ?)\n\nおい、JOJO!貴様の正体を教えろ!その妙な技の種明かしをしやがれ!"
    }
  ],
  "stop_reason": "end_turn",
  "stop_sequence": null,
  "usage": {
    "input_tokens": 106,
    "cache_creation_input_tokens": 0,
    "cache_read_input_tokens": 0,
    "output_tokens": 137
  }
}

まとめると、

「おまえの次のセリフは『なんでメリケンのことわかったんだこの野郎!』」

に対して、プリフィルと結合して以下のようなセリフがかえってきたことになります。

なんでメリケンのことわかったんだこの野郎!

...ハッ!?

くそっ、また引っかかった...!
この「読心術」みたいな技は一体何なんだ!?

(内心:このJOJO、まるで俺の心を読ん
  いるかのように先回りしてくる...。一体どんなトリックを使っているんだ?)

おい、JOJO!貴様の正体を教えろ!その妙な技の種明かしをしやがれ!

もうちょっと、この、荒木節をまわしてほしいところですが、「...ハッ!?」は言ったので良しとしましょう。ちなみにカーズでやりたかったのですが、実際のカーズは「これも計算のうちかJOJO」と言い終る間もなく宇宙にふっとばされて行くので、予測としてはちょっとです。

📝 まとめ

Anthropic ClaudeのMessages APIを使用する際、以下の点に注意することで、より自然で期待通りの応答を得ることができます:

  • システムプロンプトの使用: systemパラメータを使用して、Claudeに特定の役割や性格を与えることで、応答の一貫性や自然さを向上させることができます。

  • プレフィル機能の活用: messages配列の最後にアシスタントのメッセージを追加することで、Claudeの応答の開始部分を指定し、続きを生成させることができます。

これらのテクニックを組み合わせることで、特定のキャラクターのセリフ再現や、特定の文体での応答生成など、さまざまな応用が可能になります。

他の目的としては、今のClaudeのMessage APIには強制的な構造化出力がないので「{」をプレフィルにすることでJSONの生成を誘導するなどがAnthropicのサイトには、あがっています。


一見、性能の良しあしだけで、同じようにみえる各社のAIモデルも、ネイティブAPIを見ていくとそれぞれ違いや特徴があります。たとえばClaoudeのプロンプトキャッシュはキャッシュブレークポイントを指定する明示的なキャッシュエントリの複数もてて明示的な選択指定が可能です。またキャッシュ時間数を1時間に増やすことなどもできます。

またClaude 4モデルでは「インターリーブ思考」というものをサポートしていて、ツール呼び出しの間に考え、ツール結果を受け取った後により洗練された推論を行うことができるそうです。

こうなってくると、ここらへんをきめこまかく対応できることがエージェントの総合性能に直結するのではないかと思っています。もちろん、汎用的に多数のベンダーからのLLMを切りかえて利用できることは利点ではありますが、LLMに特化した機能を実装するためには時間もコストもかかることでしょう。

Anthropicはエージェント(Claude Code)、それに含まれるプロンプト最適化、そしてモデル独自の機能実装や強化を、総合的にコーディングの向上につながるように調整していることで、頭一つ二つも抜けた強さが生まれているのではないかと思っています。

Discussion