抄録
ラージ・ランゲージ・モデル(LLM)は、世界中で広く関心を集めており、これまでとらえどころのなかった多くのAIアプリケーションを可能にしている。LLMは、非常に表現力豊かなテキストによるプロンプトによって制御され、テキストによる回答を返す。LLMは、非常に表現力豊かなテキストによるプロンプトによって制御され、テキストによる回答を返す。しかし、このように構造化されていないテキストによる入力と出力は、LLMベースのアプリケーションを脆弱にする。このため、LLMと外界とのインタラクションを制御することを目的としたプロンプトフレームワークの台頭が加速している。しかし、既存のヒンティングフレームワークは、学習曲線が高いか、開発者が正確なヒントを制御できないかのどちらかである。このジレンマに対処するため、本稿ではプロンプティング宣言言語(PDL)を紹介する。PDLはYAMLをベースとしたシンプルな宣言型データ指向言語で、プロンプティングをその中核に置いている。例えば、チャットボット、RAG、プロキシなどの一般的なユースケースである。PDLによって、プロンプト・プログラミングがより簡単に、より堅牢に、より楽しくなることを願っています。
1.はじめに
大規模言語モデル(LLM)は大きな進歩を遂げ、様々な有用なタスクを実行する能力を示している。LLMは自然言語を手がかりに制御されるため、手がかり工学は精度を高めるためのアドホックな手法となっている(White et al.2023).文脈学習(Brown et al.2020)、複数のLLMコールチェーン(Chase et al.2022)、強化世代(RAG)(Lewis et al.2020)、道具の使用(Schick et al.2023)、手続き型補助言語モデル(PAL) (Gao et al.2023)やエージェント(Yao et al.2023)はより多くの機能をアンロックすることができる。しかし、そのパワーにもかかわらず、LLMはまだ壊れやすい。幻覚を見たり、期待された構文や型に従わないことさえある。
キューイングフレームワーク(Liu et al.2023)により、開発者はLLMと関連するヒント・パターンを、脆弱性を減らしながら、より簡単に使用することができる。フレームワークの中には、LangChain(Chase et al.2022)およびAutoGen (Wu et al.2023)、RAGやプロキシなどの一般的なパターンに特化した機能を提供する。しかし、このような機能は、基本的なプロンプトの制御をユーザから奪い、多くの複雑なフレームワークの機能を学習することを強いる。対照的に、Guidanceのような低レベルのプロンプトフレームワーク(Microsoft.2023)やLMQL (Beurer-Kellner et al.2023のような、構文や型によってより多くの制御を提供するものがある。しかし、PythonやTypeScriptのような命令型言語でプログラミングする必要がある。一方、DSPy(Khattab et al.2023)とヴィエイラ(Li et al.2024)、プロンプトを自動生成することで、手書きのプロンプトを完全に避けることができる。残念なことに、これではさらに開発者からコントロールが奪われてしまう。したがって、LLMプログラミングをより堅牢にし、シンプルさを保ちながら開発者を運転席に座らせておくにはどうすればよいかが問題となる。
この問題に対処するために、私たちは古くから使われているプログラミング言語設計の考え方を利用する。直交性の原則は、強力な機能を実現するために組み合わされる、小さくてシンプルな関数セットの使用を提唱している(van Wijngaarden et al.1977).この文脈では、直交性とは特殊なケースをできるだけ避けることを意味する。ヒンティング・フレームワークにとって、直交性は特定の機能を避けるための手段である。次に、その言語が型と役割のチェックをパスできる場合(Hugging Face, the2023構造的に強化されれば、開発者が脆弱性で苦労することは減るだろう。一方では、開発者が正確なヒントをコントロールできることを望み、他方では、シンプルな宣言型言語が必要である。このような理由から、私たちはデータ指向の言語を選び、(チェーンやツールなどの)手続きと(ヒントの)データの境界線を意図的に曖昧にした。この着想は、コード・アズ・データ(McCarthy.1960)、そしてレイヤーレス・プログラミングに関する代表的な研究(Cooper et al.2006).
本稿では、直交型で型付きのデータ指向言語であるプロンプト宣言言語(PDL)を紹介する。命令型言語に組み込まれた他のプロンプト言語とは異なり、PDLはYAML(Ben-Kiki et al.2004PDLの変数もJSON値を保持し、オプションでJSONスキーマを使用する(Pezoa et al.2016PDLは現在、動的な型チェックを行うインタープリターによって実装されている。プログラムをデータとして表現する利点の1つは、プログラムの変換が容易なことである(Mernik et al.2005など)を最適化することができる。データ表現フォーマットでプログラムをレンダリングすることで、PAL(Gao et al.2023).
PDLプログラムはブロック(YAMLオブジェクト)で構成され、各ブロックはプロンプトコンテキストにデータを追加します。この考え方は、チャットボットやエージェントのようなプロンプト技術で使うのに理想的です。プログラムの実行は、明示的なパイプラインを引くことなく、暗黙のうちにダイアログや軌跡を構築します。PDLはネイティブのLLMのほか、IBM Watsonx1上のオープンソースGraniteモデルやReplicate2(Abdelaziz et al.2024IBMのグラナイト・チーム。2024PDLは、ループや条件付き制御構造、モジュール化のための関数やファイルの導入を提供します。PDLはJinja2(Ronacher.2008)式を使って、ヒントだけでなくプログラム全体をテンプレート化することができる。
この記事では、入門的な例を通してPDLの概要を説明する(第2節)、そして言語の詳細な説明(第3節).PDLプログラムの実行と編集のためのツール (第4節)、PDLのさらなる応用を示すケーススタディを提供している(第5節).最後に、関連する研究(第6節)、そして第7節PDLはオープンソースで https://github.com/IBM/prompt-declaration-language 手に入れる全体として、PDLはシンプルだがパワフルな新しいLLMプロンプト・プログラミング言語である。
2.概要
このセクションでは、チャットボットの例を通してPDLの機能の概要を説明します。PDLプログラムは 塊各ブロックによって生成されたデータは、バックグラウンドコンテキストに寄与される。モデル呼び出し、標準入力やファイルからのデータ読み込み、さまざまなJSONデータの直接作成、コードの実行など、さまざまな方法でデータを生成できるブロックの種類があります。さらに、PDLユーザーがリッチなデータパイプラインやAIアプリケーションを表現できるように、さまざまな制御ブロック(if-then-else、for、repeat)があります。
地図 1(a)は単純なチャットボットのPDLコードである。1-4行目のread:ブロックは、ユーザーにクエリを入力するよう求めるメッセージを表示し、stdinからそれを読み取る。図 1(b) 同じプログラムの実行トレースを示す。例えば、あるユーザーが "言語サラダとは何ですか?"と尋ねたとする。.繰り返しを避けるために、"attribute: [context]"節は、ユーザーの応答を背景コンテキストに入れるが、結果(標準出力に出力されるもの)は入れない。
5行目から16行目のrepeat:until:ブロックは、入れ子になったtext:ブロックを含んでおり、そのtext:ブロックは、入れ子になった2つのブロックのシーケンスを含んでいる。text:ブロックは、入れ子になったブロックの結果を文字列に変換し、それらを連結する。7~9行目のmodel:ブロックは、現在の蓄積されたコンテキストをヒントとして使用する大規模言語モデル(LLM)を呼び出す。ループの最初の繰り返しでは、コンテキストは、"What is your query? "と "What's a language salad? "の2行だけで構成される。stop: [ \nn]' モデルパラメータは、LLM が 2 つの連続した改行を生成した後、トークンの 生成を停止するようにする。LLM インタプリタは LLM 出力を緑色で表示する。 1(b) はこの例で LLM が "A language salad is [...]" を生成したことを示しています。10行目から15行目の read: ブロックは YAML の複数行の文字列構文 (垂直線 (|) で始まる) を使ってメッセージを表示します。この例では、PDL がプロンプトを読みやすく、開発者に正確な制御を与えながら、プロンプトを最初に表示する方法を示しています。右側のインタプリタトレースは、ユーザが "Say it as a poem!"とタイプしたことを示しており、これは10行目で左側の変数questionとして定義され、12行目でコンテキストに追加されています。16行目のuntil:節は、Jinja2式の'${質問=="終了"}'
PDL は '${...}' 構文を使用します。 構文を使います。の代わりに '{{...}}' を使います。後者は YAML の特殊文字 (curly braces) と互換性がないからです。
ループの2回目の繰り返しでは、コンテキストにはループの1回目の繰り返しの効果が含まれる。したがって、model:ブロックの2回目の実行では、1回目の実行の出力を見て、それを詩のように言い換えることができる。 1(b).結局、この例の2番目のread:ブロックの実行中に、ユーザーは「quit」とタイプし、ループは終了する。さて、一般的なPDLブロック(read:、repeat:、text:、model:)の動作をいくつか見てきたところで、2番目のread:ブロックに移りましょう。 3 セクションで、残りのブロックと言語機能について説明している。
(a) コード
- 読む。
投稿: [コンテキスト]
メッセージ:
あなたのクエリは何ですか?
- repeat: | [context] message: | [context] message: | クエリーは何ですか?
テキストを入力してください。
- model: watsonx/ibm/granite-13b-chat-v2
parameters: stop: ["∕n∕n∕"]].
stop: ["\n]
- def: 質問
read: ["\n"] def: question
contribute: [コンテキスト]
message: |.
クエリを入力するか、"quit "と言って終了する。
until: ${question == "quit"}.
(b) 通訳トレース
お問い合わせとは?
言語サラダとは何ですか?
言語サラダとは、一つの会話や文章に異なる言語や方言が混在していることを表す言葉です。と捉えることができます。
問い合わせを入力するか、「quit」と言って終了してください。
詩の形で表現すること!
多くの言語が存在する世界。
言語サラダが生まれ、喜びの中で成長する。
言葉は絡み合い、調和して流れる。
色とりどりの言葉、鮮やかな花。
クエリーを入力するか、"quit "と言って終了してください。
終了
図1 PDLによるシンプルなチャットボット
3.言語
図2 PDLクイック・リファレンス
PDLはYAMLに埋め込まれた言語であり、それぞれのPDLプログラムはPDLアーキテクチャに準拠した有効なYAMLドキュメントになります。図 2 はPDLのクイック・リファレンスであり、このセクションでは構文規則を用いて説明する。プログラムはブロックまたはブロックのリストであり、ブロックには式や構造化ブロックがあります:
PDL ::= ブロック| [ブロック, . . . ブロック]
ブロック ::= 式 | 構造化ブロック
このセクションの構文ルールはすべて YAML のフロースタイルの構文を使います (たとえば、[block, ...,block]) 。...,block])。同じPDLコードをYAMLのブロックスタイルの構文としてレンダリングすることもできます:
- ブロック
... - ブロック
各ブロックは、ブロックのタイプ(モデルや読み取りなど)を示すキーワードを持つブロックボディを含む。ブロック本体には15種類ある(オプションのフィールドには疑問符が付けられている):
ブロック_ボディ ::=
model:式,input:?pdl,parameters:?
式
| read:file,メッセージ:?
文字列,メッセージ:?
ブール
| テキスト:pdl
| lastOf:pdl
| 配列:pdl
| オブジェクト:pdl
| データ:json
| インクルード:ファイル
| 関数:args,return:pdl
| call:↪Ll453↩,args:引数
| if:式,then:pdl,else:?
| for:args,repeat:ᑝ,join:?
ジョイン
| repeat:pdl,num_iterations:n,join:?
結合
| repeat:pdl,until:expression,join:?
結合
| コード:PDL,言語:文字列
model:ブロックとread:ブロックは、前のセクションですでに見た。オプションのinput: フィールドが指定されていない限り、プロンプトは現在のコンテキストから取得されます。オプションのparameters: フィールドは、モデルの推論動作を設定するために使用されます。 read: ブロックはファイルから、またはファイル名が指定されていない場合は標準入力から入力を読み込みます。オプションのmessage: フィールドは、ユーザーへのメッセージを表示するために使用されます。オプションのmultiline: フィールドは、改行で停止するかどうかを決定します。
データを作成するための5つのブロックタイプには、text:、lastOf:、array:、object:、data:がある。図 2 これらを簡単な例で示す。object:ブロックとdata:ブロックの違いは、PDLインタープリターがdata:ブロックのPDLキーワードを無視し、通常のJSONフィールドとして扱うことです。
モジュール化のために、PDLはinclude:ブロックと関数をサポートしています。include:ブロックは、指定した相対パスでPDLプログラムを開き、その出力を表示される場所に追加します。関数の引数の構文は以下の通りです:
args::={x:exp表現,...x:expresionシオン}.
各x:表現return:キーワードは、入れ子になったブロックを含むことができる関数本体を提供する。 2 簡単なJinja2式の例を示します。オプションの pdl_context: キーワードは、呼び出し中にコンテキストをリセットします。
コントロール・ブロックには、if:、for:、さまざまなrepeat:の3種類がある。ブロックのリストを含む場合、デフォルトではそのリストはlastOf:として動作します。lastOf:の動作を望まない場合は、ループ本体をtext:ブロックでカプセル化するか、join:キーワードを使ってループの反復結果をマージするのが一般的な方法です:
join::=as:?(text∣array∣lastOf),with:?文字列
上記の15個のブロックは、どのブロックにも適用される0個以上のオプションキーワードと組み合わせて使うことができる:
構造化ブロック::=
{ block_body.
description:?
文字列, def:?
def:?
x, defs:?
defs:?
x、defs:?
def:?x、defs:?defs、role:?
defs:?
defs:?
contribute、parser:?parser、parser:?
parser:?
spec:?
型 }.
def: ブロックの結果を変数に代入する。 1 PDLの10行目にすでに例がある。対照的に、defs:は複数の変数定義を作成し、それぞれにxという名前をつけ、ネストされたPDLプロシージャを通して値を代入します:
defs::={x:pdl...,x:pdl}である。
role:ブロックによって生成されたデータに'user'、'assistant'、'system'などの特定のロールを割り当てます。チャットモデルへのPDL呼び出しは、プロンプトとしてプレーンテキストではなく、シーケンスの{content:str, role:str}ペアを渡すことで、最近のチャットAPIの一般的な慣習に従っています。モデルAPIはモデル固有のチャットテンプレートを適用し、適切な制御タグを挿入することでシーケンスをフラットにします。ブロックが明示的にrole:を指定しない場合、モデルブロックのデフォルトは'assistant'となり、他のブロックのデフォルトは'user'となります。埋め込まれたブロックの役割は、外側のブロックの役割と一致する。今後の研究では、ロールを使用したパーミッションベースのセキュリティメカニズムの実装も計画している。
contribute:キーワードを使用すると、「result」または「context」の2つの宛先 に、(おそらく空の)サブセットを指定することができる。デフォルトでは、各モジュールはそれ自身の結果と、後続の大規模言語モデル(LLM)呼び出しに使われる背景コンテキストに寄与する。図 1 行目は、出力を単純化するために、モジュールの寄与をバックグラウンド・コンテキストのみに制限した例である。
spec: キーワードは型を指定します。 PDL の型は JSON Schema (Pezoa et al.) のサブタイプです。spec: キーワードは型を指定します。PDLの型はJSON Schemaのサブセットです(Pezoa et al. 2016), Fig. 2 一般的な省略記法の簡単なデモを以下に示す。例えば、'{questions: [str], answers: [str]}'という型は、質問と答えの2つのフィールドを持つオブジェクトです。最初の 5 節では、parser:とspec:がどのように連動するかを示す。今後の研究では、これらのキーワードを制約デコードにも利用する予定である(Scholak et al. 2021).
アトミック・ブロックは式である:
expression ::= bool | number | string | ${𝑗𝑖𝑛𝑗𝑒𝑥ᵅ𝑒𝑒𝑠𝑖ᵅ𝑛} | string_expression
式には、基本的な値、Jinja2 式(Ronacher. 2008Jinja2はヒントのテンプレートを指定する便利な方法で、ヒントの一部はハードコードされ、他の部分は式で埋められます。Jinja2はヒントのテンプレートを指定する便利な方法で、ヒントの一部はハードコードされ、他の部分は式で埋められます。しかし、PDLはJinja2の使用をさらに拡張し、開発者が個々のヒントだけでなく、モデル全体のコールチェーンや他のモジュールをテンプレート化できるようにします。可能な式の完全なリストについては、Jinja2ドキュメントを参照することをお勧めしますが、図 2 PDL では、Jinja2 式のみを使用します。 {% if ... %}.
もしかしたら {% for ... %}。
なぜなら、これらはすでにPDLのif:関数やfor:関数と重複しているからだ。
最後になるが、PDLにはcode:モジュールがあり、指定したプログラミング言語(本稿執筆時点ではPythonのみサポート)のコードを実行できる。次のセクションでは、任意のコードを実行するリスクを減らすサンドボックス機能を提供するインタプリタを含むPDLツールについて説明します。詳細については、PDLのGitHubリポジトリにあるチュートリアルへのリンクを参照してください。
4.ツール
PDLは、PDLプログラムを簡単に書き、実行し、理解するためのツールを提供する。
まず、PDL 通訳 は、スクリプト言語から期待されるようなコマンドラインインターフェースを持つ実行エンジンである。このインタープリターはストリーミング・モードをサポートしており、LLMの出力が生成されるたびに徐々に表示されるため、よりインタラクティブなチャット体験を提供します。このインタープリターはサンドボックスもサポートしており、コンテナ内で起動することができます。
ページ記述言語 IDEサポート VSCodeはシンタックスハイライト、オートコンプリート、PDLキーワードのツールチップ、エラーチェックによってPDLコードを書きやすくするよう強化されています。これらの機能の一部は、PDLメタモード(有効なPDLを定義するJSONスキーマ)によって駆動されています。
%%pdl
魔力単位 Jupyterノートブックで強化され、開発者はPDLで直接コードのユニットを書くことができる。このようにして、ホストされたノートブックプラットフォームは、プロンプトをインタラクティブに探索するためのシンプルな遊び場として使用することができます。同じノートブックに複数のPDLコードユニットがある場合、後のユニットでは前のユニットで定義された変数を使用することができます。さらに、後のユニットの背景コンテキストは前のユニットから引き継がれます。 %%pdl --リセットコンテキスト
を使えば、この動作をオーバーライドできる。
ページ記述言語 リアルタイム・ドキュメント・ビジュアライザー PDLプログラムの実行の具体的なトレースは、LLMのヒントに関する論文やブログ記事に見られる典型的なグラフィックに似た、色のついた入れ子のボックスの形で表示される。その後、ユーザーはボックスの1つを選択すると、対応するPDLコードが表示されます。スプレッドシートのセルにデータが表示されるのと似ていますが、ユーザーはそれらを選択して、そのデータを生成した数式を調べることができます。このリアルタイム表示により、ユーザーは特定のデータを素早く理解し、そのデータを生成したコードの理解に移ることができる。
最後に、PDLには エスディーケー(ソフトウェア開発キット)は、PythonからPDLを呼び出すための小さなPythonライブラリです。これは、エージェントのようなヒントベースの手続きを使用するために、大規模なPythonアプリケーションを拡張するのに便利です。セクション 3 セクションで説明したように、PDLファイルにはコードブロックにPythonを含めることができます。PDLを使って大規模なアプリケーションを開発する場合、関数を別のPythonファイルで定義し、PDLから呼び出すことで、このコードを数行に抑えることができます。PDLとPythonの間では、JSONオブジェクトの形式でデータを渡すのがよい方法です。オプションとして、PDLの スペック
キーワード、そしてPython側では型チェックのためにTypedDictまたはPydanticを使用する。 3 表示されている。
(a) PDLコード
1text.
2- 言語: python
3 コード: |
4 import rag_mbpp
5 PDL_SESSION.mbpp = rag_mbpp.initialise()
6 result = ""
7- defs.
8 test_query: >-
9 文字列から与えられた文字の最初と最後を削除する Python 関数を書きなさい。
12 検索される。
13 lang: python
14 spec: [{query: str, answer: str}].
15 コード: |.
16 import rag_mbpp
17 result = rag_mbpp.retrieve()
18 PDL_SESSION.mbpp, "${test_query}", 5
19 )
20 テキスト
21 "Q: "の後にテキストが与えられたら、"A: "の後にPython関数を生成する。
24 以下はいくつかの例です、最後の例を終了してください:
25- for.
26 few_shot_sample: ${retrieved}.
27 repeat: |.
28 Q: ${few_shot_sample.query}。
29 A: '''${few_shot_sample.answer}'''です。
30- |-
31 Q: ${test_query}.
32 A.
33- model: watsonx/ibm/granite-3-8b-instruct
34 パラメータ
35 stop: ["Q:", "A:"].
(b) Pythonコード
1from typing import TypedDict
2import datasets
3from sklearn.feature_extraction.text \
4 import TfidfVectorizer
5
6def initialize().
7 train_in = datasets.load_dataset(
8 "mbpp", "sanitised", split="train"
9 )
10 コーパス = [row["prompt"] for row in train_in].
11 tfidf = TfidfVectorizer().fit(corpus)
12 def embed(text).
13 sparse_result = tfidf.transform().
14 raw_documents=[text].
15 )
16 return sparse_result.toarray().flatten()
17 train_em = train_in.map(
18 lambda row: {"em": embed(row["prompt"])}.
19 )
20 vec_db = train_em.add_faiss_index("em")
21 return vec_db, embed
22
23 QA = TypedDict("QA", {"query":str, "answer":str})
24def retrieve(mbpp, query, n: int) -> list[QA].
25 vec_db, embed = mbpp
26 key = embed(query)
27 nearest = vec_db.get_nearest_examples(
28 "em", キー, n
29 )
30 queries = nearest.examples["prompt"].
31 answer = nearest.examples["コード"].
32 return [
33 {"query": q, "answer": a}.
34 for q, a in zip(queries, answers)
35 ]
図3. ラグ PDLの例
5.ケーススタディ
私たちは今、その最初の段階にいる。 2 簡単なPDLチャットボットの例をセクションで見た。このセクションでは、RAG、プロキシ、PDLからのPDL生成など、PDLの少し複雑な使用例を紹介する。
5.1 エンハンスメントの生成
検索機能付き生成、または ラグこれは、まず関連する文脈を検索し、それをモデルのプロンプトに追加して回答を生成する仕組みである(Lewis et al. 2020).図. 3(a)はコード生成タスクのためにRAGを使って少数の例を検索するPDLプログラムである。コード: 2-6行目はPythonを使い、MBPPデータセットの「ほとんどが基本的なPythonプログラム」(Austin et al., 2008)の訓練分割のベクトルデータベースを初期化している。 2021).グラフ 3(b)で定義したPython関数と、PDL_SESSION特殊変数により、後のコードブロックに状態を渡すことができる。図 3(a)の8-11行目は、変数test_queryをPythonコードを生成した自然言語リクエストに初期化する。12-19行目では、retrievedという変数を学習データから最も類似した5つの例に初期化する。
20~24行目はコンテキストに命令を追加し、25~29行目はコンテキストに一握りの例を追加し、30~32行目はコンテキストにテストクエリを追加する。25行目のfor:ループは、PDLを使ってデータを生成する一般的な方法であり、この場合はコンテキスト学習用である。最後に、33~35行目でGranite 3モデル(Granite Team, IBM 2024)、クエリーリクエストをテストするPython関数を生成させる累積コンテキストを使用する。これは単純な例ですが、PDLをCodellm-Devkit(Krishna et al. 2024)は、さまざまなプログラミング言語のソースコードを静的に解析するツールと組み合わせて使用され、LLMにコーディング作業を促す際に関連する他のコンテキストを取得する。
(a) コード
1テキスト
2- read: react_few_shot_samples.txt
3- |
4- read: react_few_shot_samples.txt
5 ハドソン川の発見者はいつ生まれましたか。
6- 繰り返す。
7 テキスト
8 - def: 思考
9 モデル:watsonx/ibm/granite-34b-code-instruct
10 パラメーター
11 stop: ["Act:"]。
12 include_stop_sequence: true
13 - def: アクション
14 モデル: watsonx/ibm/granite-34b-code-instruct
15 パラメータ
16 stop: ["\n"].
17 パーサー:json
18 spec: {name: str, arguments: {topic: str}}.
19 - def: observation
20 if: ${ action.name == "Search" }.
21 then.
22 text.
23 - "Obs: "
24 - 言語: python
25 コード: |
26 import wikipedia
27 query = "${ action.arguments.topic }"
28 result = wikipedia.summary(query)
29 until: ${ action.name != "Search" }.
(b) 通訳トレース
コロラド造山帯東部の標高範囲は?
Tho:コロラド造山帯の東部地域の標高範囲を調べるには、コロラド造山帯を検索する必要があります。
Act: {"name": "Search", "arguments": {"topic": "コロラド造山"}}。
オブザーバー:コロラドの山づくりキャンペーンはイベント [...][...
[...]
ハドソン川の発見者はいつ生まれましたか?
ト:ハドソン川の発見者がいつ生まれたか調べるには、検索する必要があります。
Act: {"name": "Search", "arguments": {"topic": "ハドソン川の発見者"}}。
オブザーバー:ハドソン川は全長315マイルの川です。
Tho:ハドソン川の発見者はヘンリー・ハドソンである ヘンリー・ハドソンを検索して、彼がいつ生まれたかを調べる必要がある。
Act: {"name": "Search", "arguments": {"topic": "ヘンリー・ハドソン"}}。
Obs: ヘンリー・ハドソン (1565年頃 - 消息不明)
行為: {"name": "終了", "arguments": {"topic": "1565"}}。
図4. リ・アクト 責任ある立場で代行する
5.2.リアクト・エージェント
大規模な言語モデルに基づく 責任ある立場で代行する 大規模な言語モデルの選択と設定が可能 ムーブメントで マトリックス これらのアクションが実行され、アクションの出力が大きな言語モデルにフィードバックされる。 鑑みる.このような薬剤には、ReAct(Yao et al. 2023)およびReWOO (Xu et al. 2023).アクションは大規模な言語モデルに基づいている ツールコール (Schick et al. 2023)、エージェントは動的で大規模な言語モデルのブートストラップ・シーケンスで複数のツールの呼び出しを連鎖させる。目標は、AIベースのアプリケーションを、より杓子定規でなく、より目標指向にすることである。さらに、エージェントは、行動がうまくいかないときに回復するためのフィードバックとして観察を使用することができる。
地図 4 ReActの中心はthink-act-observeループであり、コードではthink(8行目)、act(13行目)、observe(19行目)の変数定義として表現されている。思考はモデル生成の自然言語である。 4(b)のインタプリタ・トレースでは、「ハドソン川の発見者がいつ生まれたかを調べるために検索する必要がある」となっている。アクションは、学習データを使ってGraniteモデルのツールにマッチするようにモデルが生成したJSONである(Abdelaziz et al. 2024).左側の17行目と18行目は、大きな言語モデルの出力がJSONとしてパースされ、{name, arguments}スキーマに適合していることを確認し、右側のインタプリタトレースはモデルが実際にそのようなオブジェクトを生成していることを示しています。これにより、27行目の${ action.arguments.topic }のように、Jinja2を使ってオブジェクトのフィールドにアクセスすることが可能になります。オブザベーションは環境、この場合はWikipediaを呼び出すPythonコードによって生成されます。27行目にあるように 4 セクションで説明したように、大規模な言語モデルから(部分的に)生成されたコードを実行する場合は、PDLのサンドボックス機能を使用することをお勧めします。
地図 4(b)のインタプリタトレースは、この実行がエージェントループを2回繰り返していることを示している。これは単純な例ですが、PDLを使ったコード編集エージェントも実装しており、これはcommit4(Jimenez et al. 2024).これは、オープンソースモデルを使用した過去のどの結果よりも高く、フロンティアモデルの結果に匹敵します。
5.3.ビッグ言語モデルを用いたPDLからのPDL生成
前節では、人間の開発者がPDLを使用してさまざまなキューイングパターンをエンコードする方法を示した。このメタPDL生成は、例えばエージェントのワークフローの一部として、大規模な言語モデルが問題解決計画を作成する必要がある場合に有用である。従来、これらの計画はテキスト、JSON、またはPythonコードのみであった。PDLを使えば、これらの計画は完全に実行可能なモデルとコード呼び出しの組み合わせにすることができます。このセクションでは、GSMHardデータセット5でのPDLメタ生成の使用について検討する。
GSMHardはGSM8kのより難しいバージョンで、簡単な算数や記号的推論を必要とする学年数学の問題を含んでいる。GSMHardは入力である数学の問題文と出力である問題を解くPythonコードを含んでいる。我々はPAL(Gao et al. 2023連鎖思考はPDLのテキストブロックとして表現され、演算はPDLのコードブロックを使って実行される。
地図 6 PDLコードを生成し、それを同じプログラムで実行するPDLプログラムが示されている。変数demoには、PDLコードを生成する方法をモデルに教えるための少数の例が格納されています。32行目では、モデル呼び出しブロックがこれらの例と自由変数を持つ問題を入力として使用します。結果は問題を解くPDLプログラムです。38行目でPDLプログラムを取り出し、Pythonで実行します。このプログラムはGSMHardデータセットに適用され、問題は入力問題を入力します。
この実験では、GSMHardデータセットの10%は、グランドトゥルースが質問と矛盾していたため、実際には間違っていることがわかった。図 6 そのような不整合の例を示す。生成されたPDLコードは人間が読むことができるため、グランドトゥルースと一致しないデータポイントを簡単にチェックすることができ、いくつかのケースではグランドトゥルースが間違っていることがわかった。データセット全体をカバーするために大規模な言語モデルを使用し、矛盾していると思われる例を体系的にピックアップした。その後、手動でスクリーニングを行い、偽陽性を除去し、10%からこの問題のあるデータポイントを特定した。
1 定義。
2 例
3 データ
4 テキスト
5 テキスト
6 ...
6 ...
8 問題:ロジャーはテニスボールを5個持っている。
9 彼はテニスボールを2缶買い足した。
10 それぞれの缶には3個のテニスボールが入っている。
11 彼は今何個のテニスボールを持っていますか。
12 答え: ロジャーはテニスボールを5個持っています。
13 答え
14 ```
15 文章を書きなさい。
16 - "ロジャーは最初テニスボールを持っていました。"
17 - 定義:テニスボール
18 データ: 5
19 - "テニスボール\n"
20 - "2つの缶にそれぞれ3つのテニスボール、合計"
21 - 言語:python
22 定義:buy_balls
23 コード: result = 2 * 3
24 - "テニスボール(個)。\n"
25 - "The result is: ˶˙ᵕ˙˶"
26 - 言語: python
27 - 定義: RESULT
28 コード: result = ${ tennis_balls } + ${ bought_balls }.
29 ``
30 生成: true
31 - モデル:watson`s
32 - モデル:watsonx/meta-llama/llama-3-70b-instruct
33 定義:PDL
34 入力: true
35 テキスト
36 - ${ demos.text }.
37 - "質問: ${ 質問 }"
38 - 言語: python
39 コード: |
40 from pdl.pdl import exec_str
41 s = """${ PDL }"""
42 pdl = s.split("```")[1].
43 result = exec_str(pdl)
44 定義: RESULT
図5.
ジェームズは週に1793815スプリントを走ると決めた。
1回のスプリントは60メートルです。
彼は毎週合計何メートル走るか?
def solution():
スプリント数 = 1793815
週あたりの日数 = 3
メートル毎スプリント = 60
total_sprints = sprints_per_day * days_per_week
トータル・メーター = トータル・スプリント * メーター・パー・スプリント
結果 = トータル・メーター
トータル・メーター = トータル・スプリント * メーター・パー・スプリントの結果
図6 GSMHardサンプル問題のデータポイント
6.関連作品
最近の研究では キューフレーム LLMとユーザー、ツール、他のモデルとのインタラクションを管理、簡略化、促進するレイヤーとして定義されている(Liu et al.2023).この研究は、キューイングフレームワークの大きな欠点は、学習曲線が急であることを強調している。
おそらく現在最も人気のあるプロンプトフレームワークはLangChain(Chase et al.2022MiniChainの主な動機は、まさにこの複雑さを避けることにある(Rush.2023PDLはMiniChainと似たような動機を持っているが、より高度なアプリケーションのために組み合わせることができる、より少なくシンプルな機能を提供している。PDLはMiniChainと似たような動機を持っているが、ベースとしてPythonではなくYAMLを使うことで、さらに一歩進んでいる。
他のプロンプトフレームワークと同様に、PDLの目標はLLMをより強固なものにすることである。2023)はPythonベースのフレームワークで、より構造化された設計を提供するが、LangChainよりも低レベルである。同様に、LMQL (Beurer-Kellner et al.2023PDLは、ヒントとプログラミングの絡みにおいてLMQLからヒントを得ているが、LMQLとは異なり、命令型Pythonコードにはあまり依存していない。2024これは魅力的な試みではあるが、洗練されたキュー言語を導入しているわけではない。
ドメイン固有言語の利点のひとつは、最適化などのプログラム変換を実装できることだ(Mernik et al.2005DSPyキューイングフレームワーク(Khattab et al.2023ヒントを自動生成するため、開発者は手作業でヒントを書く必要がない。同様に、Vieira (Li et al.2024DSPyとVieiraはどちらも非常に高度なフレームワークであるが、PDLとは異なり、特定のプロンプトに対する開発者の制御を弱めている。2021DSPy、Vieira、Laleは予測性能を最適化し、その他の最適化は計算性能をターゲットにしている。2023)は、プレフィックスキャッシュをうまく利用することで、KVキャッシュでのキャッシュヒットを増やすことでこれを実現している(Kwon et al.2023).今後の研究では、PDLの宣言的な性質が、同様の計算性能の最適化を可能にするかどうかを探る。
近年、Large Language Modelling (LLM)に基づくプロンプトフレームワークが、LLMエージェントを中心に数多く登場している。2023)は、すべてのコンテンツがエージェントとダイアログで構成されるマルチエージェントフレームワークである。他のマルチエージェントフレームワークには、CrewAI(Moura.2023)とGPTSwarm(Zhuge et al.2024).PDLはプロキシもサポートしているが、よりバランスの取れたスタンスを追求しており、プロキシを数あるキューイングのテクニックの1つとして扱っている。
7.結論
PDLは宣言的なデータ指向の言語です:プログラムはYAMLブロックで構成され、それぞれのブロックはリテラルもしくは生成データです。思考モデルは、ブロックのデータを背景コンテキストに追加して実行することであり、このコンテキストは後続の言語モデル呼び出しの手がかりとして使われる。本論文では、サンプル・プログラムと、構文とツールのガイド・ツアーを使って、この言語を紹介する。PDLは現在使用可能であり、以下のURLでオープンソースとして公開されている:https://github.com/IBM/prompt-declaration-language.