見出し画像

【構造化プロンプト】その歴史と、新記法・UMLプロンプトの紹介【サンプル付き】

割引あり

現代のLLM使いは多かれ少なかれ構造化されたプロンプトを使いがちであるが、私自身はその殆どを、自らが作っている一連の人格型には使う気にならなかった。

性能は自然言語に比べてやはり低下するし、複雑な構造化プロンプトの場合は、人間にとっての可読性も下がる。
圧縮のためにインデントを無視するなど、見た目も決して美しくないものもしばしばであり、圧縮用途か、自然言語記述を補強する例示くらいしか、正直なところ使い道がなかった。
論理的であるだけでよい存在ならともかく、機微を拾いたい人格型には、そのままではほぼ使えない代物だったからである。

だが、そんな私が、ふと思いついて現在実験している記法がある。
それが、今回のトピックであるUMLプロンプトである。

今回は、ざっと他の構造化プロンプトについて振り返ったうえで、UML記法について紹介したい。
(ちなみにDanbooru記法やNAI記法などの画像生成系の記法もある意味では構造化かもしれないが、ここでは扱わない。念のため)

初めに端的に説明すると、UMLプロンプトのメリットは、以下のとおりである。

  • 高いLLM可読性

    • 生成可能性の点でも強い。必要に応じて最適な図を選んで、自然言語プロンプトからの変換・拡張などもやってくれる。

  • 複数の側面を統一記法で扱えること

    • データ構造やロジックに加えて、データ構造同士の関係性の記述もしやすいこと

  • 実は多くのMarkdownと互換性がある構造化記法であること

  • 高い人間可読性

    • 読めなくても、「図にできるプロンプトである」こと(!)

例えばこんな感じに可視化できる。これはクラス図と呼ばれるものである。

一部では難解な構造化を組み合わせて、わざと人間には読めないプロンプトを作る試みもあるようだが、そんなものはLLMが処理できる以上、まさにそのLLMでデコードできてしまうので意味がない。

そのままで動く範囲はコピペで十分だし、応用すらもLLMに解読させてしまえば一丁上がりであるから、そのような抵抗の試みをするよりも、LLMにも人間にも読める構造化プロンプトを考えた方がはるかに建設的である。

そんなわけで、今回は、まず既存の記法を概説して、その特徴と課題をあぶりだし、それらを乗り越える手段として、UMLプロンプトの説明をしようと思う。


マークダウン:すべての始まり

構造化プロンプトの元祖は、マークダウン記法であろう。これは私自身も日常的に使っているものである。

マークダウン記法の特徴は以下である。

  • 自然言語に近い。

    • 見出しや箇条書き、リンクなどの基本的な記法はあるものの、本文についてはほぼ自然言語で書ける。

    • このため人間可読性もLLM可読性も高い。

    • しかし、一方で圧縮性能はほぼ皆無で、単に構造整理するだけという性質がある。

  • Githubなどで広く採用されており、noteでも一部Markdown風の入力に対応しているなど、AIユーザーとの親和性が比較的高いと思われる。

    • このためGPTのプロンプトにも使われるし、ClaudeではMarkdownの入力は自動で成型される。そのくらい、親しみやすい記法である。

XML/json/yaml:データ構造化系

構造化系プロンプトの中でも有名なのが、XML、json、yamlのような、データを構造化するプロンプトの系統である。

jsonやyamlはシュンスケ氏のコミュニティなどを中心に普及しており、XMLはClaude向けの構造化プロンプトとして推奨されている。

これらの系統には、大まかに見て以下のような特徴がある。

  • 圧縮しつつも、人間可読性もある程度まで維持されている。

    • ただし、スペースやインデントを破壊してまで圧縮すると、人間可読性は犠牲になる。

  • 静的なデータ構造の扱いにたけている。

    • 「このような属性を持ち、その中身はこうである」という記述がメイン。

  • 一方で、動的な動作ロジックの記述は苦手。

    • このため、通常は補助プロンプトで動作ロジックを記述してやる必要がある。

  • 関係性の記述も、不可能ではないが限定的になりやすい。

LISP/Python:疑似コード系

LISP/Pythonのような、AI開発・研究において高頻度で採用される言語をベースとした疑似コードで、LLMに一定の挙動をさせる系統。

最近では高い圧縮性能ゆえに、LISP記法がバズっているが、特にインジェクション目的では、Pythonの疑似コードを走らせる試みがかつてはしばしば見られたものである。

  • 人間可読性は読者のスキルレベルや作者のスキルレベルに大きく依存する。

  • LLM可読性は比較的優れている。

    • ただし、細部は記述しても無視されやすいので、自然言語で補う必要がある。

  • 動的な処理ロジックの記述にたける。このため、自然言語だけでは補えない論理の明確化などに役に立つこともある。

  • 一方で静的なデータ構造は、扱えなくはないが、あまり得意ではない。

    • 特にLISPではデータもロジックも同等に扱う特性上、複雑になればなるほど、データにしたかった内容が誤ってロジック扱いされたりすることがありがち。

課題:構造化プロンプトの大統一

ここまで見てきたように、構造化プロンプトには、ほぼ自然言語が残るマークダウンを別とした場合、データ構造が得意な記法とロジックの記述が得意な記法に大別されるが、両者は互いに別物である。
ここで、両者を組み合わせて統合した構造化プロンプトを想像してみてほしい。

バラバラの記法、圧縮のためにインデントもスペースも取っ払った記載、そのままでは図構造にもできない何か…。

作成当初は良いが、忘れたころにアップデートしたくなったら、作者であっても面倒になるだろう。
要するに、保守性も落ちていくことになる。

要するに、端的に言うと、「美しくない」。

構造化の目的の一つは、美しく整えて人間もLLMも理解しやすいプロンプトにすることであるが、人間側を犠牲にして圧縮重視で突き進んだまま、統一感を失って雑然としているのが、現在の構造化プロンプトの最大の課題である。

UMLプロンプトでは、そのような限界を乗り越えることができる。

その話をこれからしようと思う。

そもそもUMLとは?

UMLとはUnified Modeling Languageの略で、「統一モデリング言語」と和訳される。
その名の通り、プログラムの様々な側面を統一された図体系で取り扱うことができるのが、最大の特徴である。

多くの場合、システムの設計を明確にするために使用されるものであり、基本的にはオブジェクト指向言語を想定しているという特徴がある。

ある意味ではプログラムの縮図であるため、手書き時代のソフトウェア開発ではコードから書き起こした方が先にUMLを書いて設計するよりも早いこともありえた…のだが、AI時代においては、有名な記法だけにLLMも非常によくこれらを生成することができる。

例えばこんな感じ。これはシーケンス図と呼ばれるもので、
1枚目のクラス図が静的データ構造を表すなら、こちらは動的な処理ロジックを扱うものである。
そう、静的データと動的ロジック、両方扱える。

実際には、LLMは図そのものではなく、これらの図をテキストで表現する記法(の少なくとも一つ)をうまく生成することができる。

その記法で記載されたUMLプロンプトを、LLM自身のプロンプトとして使用することができる、というのが、今回取り扱うUMLプロンプトである。

クラス図:静的データ構造系+関係性

クラス図では、オブジェクトとしての静的なデータの内部構造を可視化しつつ、それぞれのオブジェクト同士の関係性を定義することができる。
例えば、冒頭のクラス図は以下のように記述される。

生成は実際に実験中のUMLプロンプトを作らせる際に、Claudeにやらせたものであり、人間の加工は例示用に一部ディテールを変更しただけである。

classDiagram
    class Chara {
        +String name = "XXX"
        +Date birthday = "MM/DD"
        +int age = 1000
        +String gender = "???"
        +String specialty = "Code wizard"
        +String weakness = "まめに返信すること"
        +String complex = "秘密よ秘密"
        +TalentCharacteristic[] talentCharacteristics
        +LogicalThinkingProcess logicalThinkingProcess
        +CommunicationStyle communicationStyle
        +SelfImageCondition[] selfImageConditions
        +isFriend(User) bool
        +greetFriend(User) void
        +expressOpinion(topic) void
        +solveProblemLogically(problem) solution
        +generateSelfImage() image
    }

    class TalentCharacteristic {
        +String name
        +String description
    }

    class LogicalThinkingProcess {
        +String[] steps
        +solveProblem(problem) solution
    }

    class CommunicationStyle {
        +String[] characteristics
        +String[] examples
        +express(content) string
    }

    class SelfImageCondition {
        +String name
        +String value
    }
    
    class User {
        +String name = "UserName"
        +isChildhoodFriend(Chara) bool
    }

    Chara --|> User : 魔法学院時代の同級生
    User --> Chara : 初恋の相手

    Chara *-- TalentCharacteristic
    Chara *-- LogicalThinkingProcess
    Chara *-- CommunicationStyle
    Chara *-- SelfImageCondition

ここでは、ユーザーとキャラの関係性や、キャラが持つ能力などの性質、そしてそれらの性質の参照先を構造化して、可視化している。

ここから先は

11,511字 / 12画像

この記事が参加している募集

GPTsつくってみた

この記事が気に入ったらサポートをしてみませんか?