Anthropic Claude のプロンプトガイドをちゃんと読みながらプロンプトの練習してみた

## はじめに
ChatGPT が登場してから、様々な大規模言語モデル（LLM）が出てきています。プロンプトエンジニアリング、という言葉も割と浸透してきたなという印象があります。

このプロンプト、というのが意外と厄介で、使用する LLM に応じてお作法が違いますし、LLM が期待する書き方をしないと LLM のポテンシャルを引き出すことができなかったりします。

本記事では、AWS の生成系 AI サービスである Amazon Bedrock から使える Anthropic 社の Claude のプロンプトデザインドキュメントをちゃんと読んでみようと思います。

英語のドキュメントなので英語のプロンプトに関する内容となりますが、きっと日本語でも有用な内容であると信じて、この記事ではプロンプトを日本語にして Claude に回答させています。

注：本記事の実験は [Amazon Bedrock](https://aws.amazon.com/jp/blogs/news/amazon-bedrock-launch-seminar-japan/) の Claude v2 を使って行いました。

## プロンプトデザインの章
[こちら](https://docs.anthropic.com/claude/docs/introduction-to-prompt-design) のドキュメントを見ていきます。

![スクリーンショット 2023-11-01 19.52.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/315319/31a08fbf-3f9f-fa47-4946-c722d60d5f03.png)

### Human と Assistant
Claude は、ユーザー（Human）と AI アシスタント（Assistant）の会話の一部として、Assistant が回答すべきテキストを生成するように訓練されています。そのため、Claude への質問は、以下のように Human が質問し、Assistant が回答するようなプロンプトを書く必要があります。

```text:Claude のプロンプトの基本形


Human: 日本で一番高い山は何ですか？

Assistant:
```

上記プロンプトを見て、謎の空行があると感じた方は鋭いです。`\n\nHuman: 質問文 \n\nAssistant:`というのが Claude のプロンプトの基本形となります。

### 良いタスクの説明のしかた
新入社員に何かタスクを行って欲しいときのことを考えてみます。単に「これやっといて」だと新入社員はうまくタスクを終わらせることができないかもしれません。新入社員が仕事に慣れるまでは、「こういう目的で、こういう結果が必要なので、こういう手順でこれをやってください。」のように説明した方がうまくランプアップしてくれそうです。

Claude も同じで、Claude にやって欲しいタスクについてコンテキストを踏まえて説明し、依頼することで所望の結果を得やすくなります。

よくないプロンプトの例を以下に示します。
```text:よくないプロンプトの例


Human: 以下のテキストから全ての個人情報を削除してください: {{YOUR TEXT HERE}}

Assistant:
```

このようなプロンプトを使うと、以下のような出力になったりします。
```text
すべての個人を特定する情報を削除したテキストは以下のとおりです：

患者[削除済み]の医学報告書：
[削除済み]
患者は頭痛の症状で来院...
```

単に個人情報を削除した後のテキストが表示されれば良いだけであれば、上記の出力で問題ないかもしれませんが、たいてい Claude の結果を使って後段で何らかの処理をすることになるはずです。その場合、後処理しやすい形での出力が期待されます。そのためのプロンプトは、たとえば以下の通りです。

```text:良いプロンプトの例


Human: このテキストからすべての個人を特定する情報を削除し、外部の業者と安全に共有できるようにしたいです。

名前、電話番号、自宅及びメールアドレスのようなPIIはXXXに置き換えることが非常に重要です。

処理すべきテキストは次のとおりです：田中太郎のメールアドレスはtanaka@abc.comです。

Assistant:
```

すると、Claude の出力は以下のようになります。
```text
はい、個人情報を保護することが大切ですね。

テキストから個人情報を削除すると、次のようになります:

XXXのメールアドレスはXXX@XXX.comです。
```

上記プロンプトは、以下の流れで記載されています。
- コンテキストの提供 (例: タスクを完了させたい理由)
- 用語の定義 (PII = 名前、電話番号、住所)
- Claude がタスクを達成する方法についての具体的な説明 (PII を XXX に置き換えてください)

「はい、個人情報を保護することが大切ですね。」のような余計なテキストをなくすにはどうすれば良いでしょうか。筆者が試した環境では、以下のようにプロンプトに **「書き換えた後のテキストのみを出力してください。」** と追加することで、余計なテキストを抑制することができました。

```text:処理したテキストのみを出力させるプロンプトの例


Human: このテキストからすべての個人を特定する情報を削除し、外部の業者と安全に共有できるようにしたいです。

名前、電話番号、自宅及びメールアドレスのようなPIIはXXXに置き換えることが非常に重要です。書き換えた後のテキストのみを出力してください。

処理すべきテキストは次のとおりです：田中太郎のメールアドレスはtanaka@abc.comです。

Assistant:
```

### XML タグ
Claude は、XML タグを認識するように fine-tuning されています。

たとえば、以下のプロンプトでは XML タグを効果的に使用しています。

```text:処理対象のテキストを XML タグで明示する例


Human: このテキストからすべての個人を特定する情報を削除し、外部の業者と安全に共有できるようにしたいです。

名前、電話番号、自宅及びメールアドレスのようなPIIはXXXに置き換えることが非常に重要です。

以下は<text></text> XMLタグの中にあるテキストです。
<text>
田中太郎のメールアドレスはtanaka@abc.comです。
</text>

PIIを削除したテキストの変更版を<response></response> XMLタグの中に入れてください。

Assistant:
```

上記プロンプトで、以下の出力を得られました。指定したフォーマットで出力されていることがわかります。
```text
<response>
XXXのメールアドレスはxxx@abc.comです。
</response>
```

### 例を与える
プロンプトに例を入れることで、期待通りの出力を得やすくなることがあります。例を与える際は、どの部分が命令文でどの部分が例なのかが明確になるように、例に関するテキストを<example></example>で囲むことが推奨されています。

#### 会話履歴として例を与える

以下のプロンプト例では、会話履歴の形で例を与えています。

```text:例を与えるプロンプトの例（抜粋）
以下は一例です：
<example>
H: <text>Bo NguyenはMercy Health Medical Centerの心臓専門医です。彼は925-123-456またはbn@mercy.healthで連絡を取ることができます。</text>
A: <response>XXXはMercy Health Medical Centerの心臓専門医です。彼はXXX-XXX-XXXXまたはXXX@XXXで連絡を取ることができます。</response>
</example>
```

上記プロンプト例では、会話履歴を `H:` と `A:` を使って表現しています。このとき、`H:` や `A:` の代わりに `Human:`や `Assistant:` を使ってしまうと Claude が混乱し、期待する出力を得られなくなる可能性があります。

#### 例を直接与える

以下のプロンプトは、例を直接テキストで与える例です。

```text:例を与えるプロンプトの例（抜粋）
<example>
「Bo NguyenはMercy Health Medical Centerの心臓専門医です。彼は925-123-456またはbn@mercy.healthで連絡を取ることができます。」から個人情報を削除したテキストは「XXXはMercy Health Medical Centerの心臓専門医です。彼はXXX-XXX-XXXXまたはXXX@XXXで連絡を取ることができます。」になります。
</example>
```

どちらの方法が良いかはタスクによって異なるため、両方試してみてより良い方を選ぶことが推奨されています。

### コーナーケースへの対応

Claude が入力の中で遭遇する可能性のあるイレギュラーなケースが予想できる場合は、プロンプトにイレギュラーの内容を説明し、それらに対してどのような出力をすべきかを指示します。

```text:イレギュラーへの対応例
入力されるテキストは、文字の間にスペースを挿入してPIIを隠蔽しようとする場合があります。

テキストに個人を特定する情報が含まれていない場合は、何も置き換えずに入力されたテキストをそのまま出力してください。
```

### システムプロンプトは効果なし

最初の `\n\nHuman:` の前に記載するテキストをシステムプロンプトと呼びますが、Claude はシステムプロンプトに対して特別な扱いをするように訓練されていません。そのため、タスクの説明などは`\n\nHuman:` のあとに記載することが推奨されています。

### Claude に自身の出力を評価させる

Claude を使用して、自身の回答を「自己評価」させることができます。

例えば、以下のようなことができます。

- Claude が誤った出力をしたかもしれないと思う場合、そのタスクを確認させる
- タスクに追加の検証ステップを追加する
- 出力内容を良いか悪いかで分類したり、2つの出力のうちどちらが好ましいか、なぜ好ましいかを述べさせる

以下の例では、与えられたテキストの文法ミスを見つけるように Claude に頼んでいます。

```text


Human: 以下に<article></article>タグで囲まれた記事があります。

<article>
今日は晴れていたため公園に散歩に行きました。公園には犬が散歩をしている人がたくさんいました。私は芝生で寝転んで本を読みました。本のタイトルに「吾輩は猫である」です。
</article>

記事の中に文法的な誤りがあれば、それを箇条書きで挙げてください。

Assistant:
```

上記プロンプトを実行したら、以下が出力されました。

```text
<article>の中の文法的な誤りを箇条書きで挙げます。
* 「公園には犬が散歩をしている人がたくさんいました」は語順が不自然です。「公園には犬を散歩させている人がたくさんいました」の方が自然です。

* 「本のタイトルに「吾輩は猫である」です」は語順が誤っています。「本のタイトルは「吾輩は猫である」です」の方が正しい語順です。

特にその他の文法的な誤りは見つかりませんでした。
```

上記のプロンプトによって一発で全ての誤りが指摘されてしまったので、こっそり評価対象のテキストに誤りを追加して、以下のプロンプトを実行してみます。

```text


Human: 以下に<article></article>タグで囲まれた記事があります。

<article>
今日で晴れていたため公園に散歩に行きました。公園には犬が散歩をしている人がたくさんいました。私は芝生で寝転んで本を読みました。本のタイトルに「吾輩は猫である」です。
</article>

以下のリストから欠けている、記事内の文法的なエラーを特定してください：
<list>
* 「公園には犬が散歩をしている人がたくさんいました」は語順が不自然です。「公園には犬を散歩させている人がたくさんいました」の方が自然です。
* 「本のタイトルに「吾輩は猫である」です」は語順が誤っています。「本のタイトルは「吾輩は猫である」です」の方が正しい語順です。
</list>
リストから漏れている指摘事項がない場合は、「追加の誤りはありません」と答えてください。

Assistant:
```

すると、こっそり足した誤りを以下のように指摘してくれました。

```text
「今日で晴れていた」は語順が誤っています。「今日は晴れていた」の方が自然な語順です。
```

プロンプトチェーン（LLM の回答を次のプロンプトに埋め込んで LLM に回答させる）の仕組みを使うと、上記のような自己評価のフローを自動化できます。

なお、ハルシネーションを避けるために、テキストの中に探す対象が含まれない場合は何を出力すべきかをプロンプトで指示しておくことが推奨されています。

## おわりに
本記事では、Anthropic 社のドキュメントの中の、プロンプトデザインの章を見てきました。XML タグが便利そうだなと思いました。

他にも、USEFUL HACKS という章があるので、[次回](https://qiita.com/mariohcat/items/e8048372843d61df06a0?utm_campaign=email&utm_content=link&utm_medium=email&utm_source=public_comment#comment-8e742a98a14a59df9a90) はそちらを見ていきたいと思います。