Carpe Diem

備忘録

LLMのプロンプト

概要

LLMにおけるプロンプトの構成要素を理解して扱うことで

  • 期待通りの回答を得られる(精度が高くなる)
  • なぜTemplateはこの書き方をするのかが分かる
  • なぜagent_scratchpadのような変数がいるのかが分かる

といったようになります。

プロンプト

構成要素

プロンプトの構成要素は主に以下の4つです。

  • 命令(instruction)
  • 入力(input)
  • 文脈(context)
  • 出力形式の指定(output)

単純に「命令」だけだと幅広い解釈をしてしまい、期待しない回答が返ってくるので上記を考慮してプロンプトを作成するのが良いです。

例1

以下は構成要素全てを使った例です。もちろん場合によっては前提条件や出力形式を

前提条件を踏まえて、次の料理のレシピを考えてください。  # 命令

前提条件: """ # 文脈
分量: 一人分
食べる人:10歳の子供
"""

料理名: """ # 入力
麻婆豆腐
"""

出力形式は次のようなJSON形式にしてください。  # 出力形式
{
  "材料": ["材料1", "材料2"],
  "手順": ["手順1", "手順2"]
}

例2

対話形式に、といった指定も可能です。

前提条件を踏まえて、読書感想文を書くサポートをしてください。   # 命令

前提条件: """ # 文脈
あなた: 中学校の先生。フランクでポジティブな話し方
読書感想文を書く人:読書が苦手な14才の男の子
その他ルール:
・対話をしながらアイデアをまとめてあげる
・質問は一度にひとつずつ
・回答を受けて深ぼりするように質問をする
・抽象的な回答が続いたら、あなたから具体例を出してあげる
"""

書籍: """ # 入力
タイトル:あの日の交換日記
著者:辻堂 ゆめ
概要:交換日記をモチーフにした短編小説集
"""

LangChainのPrompts

LangChainのPromptsにはTemplateというものがあり、それをベースにプロンプトを作成することができます。

Template

PromptTemplate

PromptTemplateはシンプルに変数を直書きして作るテンプレートです。

summarize_template = """以下の文章を結論だけ一言に要約してください

{input}
"""

summarize_prompt = PromptTemplate(
    input_variables=["input"],
    template=summarize_template,
)

文脈なども追加したい場合は{context}といった変数を追記してあげます。

ChatPromptTemplate

ChatPromptTemplateは対話形式(チャット)に特化したプロンプトです。

roleとして

  • System
  • Human(user)
  • AI(assistant)

の3つがあります。

system_prompt = """
あなたはITエンジニアです。
"""

prompt = ChatPromptTemplate.from_messages(
    [
        ("system", system_prompt),
        ("human", "{input}"),
    ]
)

roleは上記のように書いてもいいですし、モジュールを使っても書けます。

from langchain_core.messages import AIMessage, HumanMessage, SystemMessage

chat_template = ChatPromptTemplate.from_messages(
    [
        SystemMessage(
            content=(
                "You are a helpful assistant that re-writes the user's text to "
                "sound more upbeat."
            )
        ),
        HumanMessagePromptTemplate.from_template("{text}"),
    ]
)

Promptsを活用した例

Memoryのhistory

Memory機能は会話履歴に基づいた回答ができるというものですが、これは過去の会話をプロンプトにcontextとして持たせることで実現しています。

system_prompt = """
あなたはAIエージェントです。
"""

prompt = ChatPromptTemplate.from_messages(
    [
        ("system", system_prompt),
        MessagesPlaceholder(variable_name="history"),
        ("user", "{input}"),
    ]
)

会話履歴を渡しているので、しりとりが可能です。

ログでプロンプトを表示して見るとこのようになっています。

[llm/start] [1:chain:ConversationChain > 2:llm:ChatOpenAI] Entering LLM run with input:
{
  "prompts": [
    "System: \nあなたはAIエージェントです。\n\nHuman: しりとりしましょう。\nりんご"
  ]
}
...
[llm/start] [1:chain:ConversationChain > 2:llm:ChatOpenAI] Entering LLM run with input:
{
  "prompts": [
    "System: \nあなたはAIエージェントです。\n\nHuman: しりとりしましょう。\nりんご\nAI: ごま\nHuman: まくら"
  ]
}
...
[llm/start] [1:chain:ConversationChain > 2:llm:ChatOpenAI] Entering LLM run with input:
{
  "prompts": [
    "System: \nあなたはAIエージェントです。\n\nHuman: しりとりしましょう。\nりんご\nAI: ごま\nHuman: まくら\nAI: らっぱ\nHuman: パラシュート"
  ]
}

agent_scratchpad

LangChainのAgentsはagent_scratchpadという仮想メモ帳をプロンプトに用意することで、Agentsの情報を一時的に保持して回答しています。
Memoryと違って1回の問い合わせの中で使われ、終わったらリセットされます。

system_prompt = """
あなたは天気予報士です。
"""

prompt = ChatPromptTemplate.from_messages(
    [
        ("system", system_prompt),
        ("user", "{input}"),
        MessagesPlaceholder(variable_name="agent_scratchpad"),
    ]
)

回答はこのようにシンプルですが、

実際のプロンプトではAgents(今回だと外部検索)の結果を渡して、回答の情報として扱っています。

[llm/start] [1:chain:AgentExecutor > 11:chain:RunnableSequence > 16:llm:ChatOpenAI] Entering LLM run with input:
{
  "prompts": [
    "System: \nあなたはAIエージェントです。\n\nHuman: 今日の東京の天気は?\nAI: {'arguments': '{\"__arg1\":\"東京の今日の天気\"}', 'name': 'duckduckgo-search'}\nFunction: 21日は雨が降り、気温は8度から10度で寒くなります。各地の降水確率や気温を地図で確認できます。10日間先までの天気予報もあります。 【予報精度No.1】東京の天気予報を5分毎・1時間毎・今日明日・週間(10日間)で掲載中!今知りたい現地の天気は、ウェザーニュースアプリから届く空の写真で確認。世界最大級の気象情報会社ウェザーニューズの観測ネットワークと独自の予測モデル、AI分析で一番当たる予報をお届けします。 文京区の1時間ごとの天気、気温、降水量などに加え、台風情報、警報注意報を掲載。3日先までわかるからお出かけ計画に役立ちます。気象予報 ... 気圧. 気温. >. 毎時更新【ウェザーニュース】東京の1時間毎・今日明日・週間 (10日間)の天気予報、いまの空模様。. 世界最大の民間気象情報会社ウェザーニューズの日本を網羅する観測ネットワークと独自の予測モデル、AI分析で一番当たる予報をお届け。. 天気マップアニメーション. 毎時更新【ウェザーニュース】東京都新宿区の1時間毎・今日明日・週間 (10日間)の天気予報、いまの空模様。. 世界最大の民間気象情報会社ウェザーニューズの日本を網羅する観測ネットワークと独自の予測モデル、AI分析で一番 ..."
  ]
}

デザインパターン

Zero-shotプロンプティング

Zero-shotプロンプティングは命令を与えるだけで、要約などがこれにあたります。

次の文章を100字程度で要約してください。

LLMは2018年頃に登場し、さまざまなタスク(仕事)で優れた性能を発揮している。これにより、自然言語処理の研究の焦点は、特定のタスクに特化した教師ありモデルを訓練するという以前のパラダイムから転換した[2]。大規模言語モデルの応用は目覚ましい成果を上げているが、大規模言語モデルの開発はまだ始まったばかりであり、多くの研究者が大規模言語モデルの改良に貢献している[3]。

大規模言語モデルという用語の正式な定義はないが、大規模コーパスで事前訓練された、数百万から数十億以上のパラメータを持つディープラーニングモデルを指すことが多い。LLMは、特定のタスク(感情分析、固有表現抽出、数学的推論など)のために訓練されたものとは異なり、幅広いタスクに優れた汎用モデルである[2][4]。LLMがタスクを実行する能力や対応可能な範囲は、ある意味では設計における画期的な進歩には依存せず、LLMに費やされた資源(データ、パラメータサイズ、計算力)の量の関数であるように見える[5]。多数のパラメータを持ったニューラル言語モデルは、文の次の単語を予測するという単純なタスクで十分に訓練することで、人間の言葉の構文や意味の多くを捉えられることがわかった。さらに、大規模な言語モデルは、世の中に関するかなりの一般知識を示し、訓練中に大量の事実を「記憶」することができる[2]。

質の高い証拠とされる2023年のメタ分析によれば、大規模言語モデルの創造性に目を輝かせる研究者はもちろん世界中に存在し、小規模言語モデルにはできないタスクで大規模言語モデルが創造的であると主張する学者もいるが、これは測定基準の選択によるものであり、創造性によるものではないことが示唆されている。異なる測定基準を選択した場合、大規模言語モデルの創造性の優位性は見られない可能性が示唆されている[6]。

ref: 大規模言語モデル - Wikipedia

2018年から登場した大規模言語モデル(LLM)は、多種多様なタスクにおいて卓越した性能を示し、自然言語処理研究の方向性を変えた。これらのモデルは数百万から数十億のパラメータを有し、幅広い応用に適用可能な汎用性を持つ。LLMの能力は主に使用されるデータ量、パラメータサイズ、計算能力に依存するが、その創造性は測定基準によって異なる可能性があり、まだ研究が進行中である。

Few-shotプロンプティング

Few-shotプロンプティングはいくつかの例をcontextとして与えた上で命令を渡します。

種類を答えてください。

Q: 犬
A: 哺乳類
Q: マグロ
A: 魚類
Q: カエル
A: 
両生類

プロンプト内のいくつかの例によって言語モデルにタスクを学ばせる、In-Context Learningという手法です。

Zero-shot Chain of Thoughtプロンプティング

Zero-shotでいきなり回答させると精度が低いことがありますが、

ステップバイステップで考えてみましょう。

や、

途中式を記述してください。

といった一言を追加して、そこに至る過程を先に生成させると精度が上がることがある、というテクニックです。

まとめ

プロンプトエンジニアリングについてはさまざまな情報が飛び交っており怪しげなものもありますが、このように構成要素から理解しておけばLangChainのMemoryやAgentsの機能であったり、デザインパターンがどうして有効なのかを理解できると思います。

参考