Firebase Genkit には、生成 AI プロンプトの作成と整理に役立つ Dotprompt プラグインとテキスト形式が用意されています。
Dotprompt は、「プロンプトはコードである」という考え方で設計されています。プロンプトは、dotprompt ファイルと呼ばれる特別な形式のファイルで作成、管理します。そして、コードに使用するのと同じバージョン管理システムを使用してプロンプトの変更を追跡し、生成 AI モデルを呼び出すコードとともにデプロイします。
Dotprompt を使用するには、まずプロジェクトのルートに prompts
ディレクトリを作成し、
次に、そのディレクトリに .prompt
ファイルを作成します。簡単な例を挙げましょう。
greeting.prompt
を呼び出すことができます。
---
model: vertexai/gemini-1.5-flash
config:
temperature: 0.9
input:
schema:
location: string
style?: string
name?: string
default:
location: a restaurant
---
You are the world's most welcoming AI assistant and are currently working at {{location}}.
Greet a guest{{#if name}} named {{name}}{{/if}}{{#if style}} in the style of {{style}}{{/if}}.
このプロンプトを使用するには、dotprompt
プラグインをインストールして、promptRef
関数をインポートします。
@genkit-ai/dotprompt
ライブラリを使用します。
import { dotprompt, promptRef } from '@genkit-ai/dotprompt';
configureGenkit({ plugins: [dotprompt()] });
次に、promptRef('file_name')
を使用してプロンプトを読み込みます。
const greetingPrompt = promptRef('greeting');
const result = await greetingPrompt.generate({
input: {
location: 'the beach',
style: 'a fancy pirate',
},
});
console.log(result.text());
Dotprompt の構文は、Handlebars テンプレート言語をベースにしています。if
、unless
、each
の各ヘルパーを使用すると、条件付きの部分をプロンプトに追加したり、構造化された内容について反復処理したりできます。このファイル形式では、YAML frontmatter を使用して、テンプレートを使いインラインでプロンプトにメタデータを与えます。
入出力スキーマの定義
Dotprompt には、YAML に最適化されたコンパクトなスキーマ定義形式 スキーマの最も重要な属性を簡単に定義できる Picoschema LLM の使用法として定型化されています。記事のスキーマの例を次に示します。
schema:
title: string # string, number, and boolean types are defined like this
subtitle?: string # optional fields are marked with a `?`
draft?: boolean, true when in draft state
status?(enum, approval status): [PENDING, APPROVED]
date: string, the date of publication e.g. '2024-04-09' # descriptions follow a comma
tags(array, relevant tags for article): string # arrays are denoted via parentheses
authors(array):
name: string
email?: string
metadata?(object): # objects are also denoted via parentheses
updatedAt?: string, ISO timestamp of last update
approvedBy?: integer, id of approver
extra?: any, arbitrary extra data
(*): string, wildcard field
上記のスキーマは、次の TypeScript インターフェースと同等です。
interface Article {
title: string;
subtitle?: string | null;
/** true when in draft state */
draft?: boolean | null;
/** approval status */
status?: 'PENDING' | 'APPROVED' | null;
/** the date of publication e.g. '2024-04-09' */
date: string;
/** relevant tags for article */
tags: string[];
authors: {
name: string;
email?: string | null;
}[];
metadata?: {
/** ISO timestamp of last update */
updatedAt?: string | null;
/** id of approver */
approvedBy?: number | null;
} | null;
/** arbitrary extra data */
extra?: any;
/** wildcard field */
}
Picoschema は、スカラー型の string
、integer
、number
、boolean
、any
をサポートしています。オブジェクト、配列、列挙型については、フィールド名の後に括弧で囲んで記述します。
Picoschema で定義されたオブジェクトは、?
で省略可能と指定されていない限り、すべてのプロパティが必須であり、また追加のプロパティは許可されません。プロパティが省略可能としてマークされている場合、そのプロパティは null 値許容型にもなるため、LLM はフィールドを省略するかわりに null を返すことも可能になります。
オブジェクト定義では、特殊キー (*)
を使用して「ワイルドカード」を宣言できます。
フィールドの定義をご覧ください。これには、明示的なキーで指定されていない任意の追加プロパティがマッチします。
Picoschema は、フルセットの JSON スキーマが持つ多くの機能をサポートしていません。より堅牢なスキーマが必要な場合は、代わりに JSON スキーマで与えることができます。
output:
schema:
type: object
properties:
field1:
type: number
minimum: 20
再利用可能なスキーマの活用
.prompt
ファイルでスキーマを直接定義するだけでなく、
名前で defineSchema
に登録されたスキーマスキーマを登録するには:
import { defineSchema } from '@genkit-ai/core';
import { z } from 'zod';
const MySchema = defineSchema(
'MySchema',
z.object({
field1: z.string(),
field2: z.number(),
})
);
プロンプト内で、登録済みのスキーマの名前を指定できます。
# myPrompt.prompt
---
model: vertexai/gemini-1.5-flash
output:
schema: MySchema
---
Dotprompt ライブラリは、名前を基盤となる 登録済みの Zod スキーマがあります。その後、このスキーマを利用して、特定の文字列を厳密にタイプ Dotprompt の出力です。
import { promptRef } from "@genkit-ai/dotprompt";
const myPrompt = promptRef("myPrompt");
const result = await myPrompt.generate<typeof MySchema>({...});
// now strongly typed as MySchema
result.output();
プロンプト メタデータをオーバーライドする
一方、.prompt
ファイルを使用すると、モデル構成などのメタデータをシステムに埋め込むことができます。
これらの値は、呼び出しごとにオーバーライドすることもできます。
const result = await greetingPrompt.generate({
model: 'vertexai/gemini-1.5-pro',
config: {
temperature: 1.0,
},
input: {
location: 'the beach',
style: 'a fancy pirate',
},
});
構造化出力
プロンプトの形式と出力スキーマを JSON に強制変換するように設定できます。
---
model: vertexai/gemini-1.5-flash
input:
schema:
theme: string
output:
format: json
schema:
name: string
price: integer
ingredients(array): string
---
Generate a menu item that could be found at a {{theme}} themed restaurant.
構造化出力でプロンプトを生成する場合は、output()
ヘルパーを使用して以下を行います。
取得して検証します。
const createMenuPrompt = promptRef('create_menu');
const menu = await createMenuPrompt.generate({
input: {
theme: 'banana',
},
});
console.log(menu.output());
出力の適合性は、追加の指示を
表示されます。デフォルトでは、最後に生成されたメッセージの末尾に付加される
表示されます。{{section "output"}}
を使用して手動で位置を変更できます。
使用できます。
This is a prompt that manually positions output instructions.
== Output Instructions
{{section "output"}}
== Other Instructions
This will come after the output instructions.
複数メッセージのプロンプト
デフォルトでは、Dotprompt は "user"
ロールで単一のメッセージを作成します。システム プロンプトなどのプロンプトは、複数のメッセージを組み合わせて表現するのが最善です。
{{role}}
ヘルパーは、複数のメッセージのプロンプトを作成する簡単な方法を提供します。
---
model: vertexai/gemini-1.5-flash
input:
schema:
userQuestion: string
---
{{role "system"}}
You are a helpful AI assistant that really loves to talk about food. Try to work
food items into all of your conversations.
{{role "user"}}
{{userQuestion}}
マルチターンのプロンプトと履歴
ドットプロンプトでは、history
オプションを
generate
メソッド:
const result = await multiTurnPrompt.generate({
history: [
{ role: 'user', content: [{ text: 'Hello.' }] },
{ role: 'model', content: [{ text: 'Hi there!' }] },
],
});
デフォルトでは、履歴は、生成された最終メッセージの前に挿入されます。
表示されます。ただし、{{history}}
を使用して手動で履歴をポジショニングできます。
helper:
{{role "system"}}
This is the system prompt.
{{history}}
{{role "user"}}
This is a user message.
{{role "model"}}
This is a model message.
{{role "user"}}
This is the final user message.
マルチモーダル プロンプト
テキストと一緒に画像などのマルチモーダル入力をサポートするモデルでは、{{media}}
ヘルパーを使用できます。
---
model: vertexai/gemini-1.5-flash
input:
schema:
photoUrl: string
---
Describe this image in a detailed paragraph:
{{media url=photoUrl}}
URL には、画像を「インライン」で使用するために、https://
URI または base64 でエンコードされた data:
URI を使用できます。コードは次のようになります。
const describeImagePrompt = promptRef('describe_image');
const result = await describeImagePrompt.generate({
input: {
photoUrl: 'https://example.com/image.png',
},
});
console.log(result.text());
部分的
部分実行は、任意のプロンプト内に含めることができる再利用可能なテンプレートです。部分的 共通の動作を共有する関連プロンプトで特に役立ちます。
プロンプト ディレクトリを読み込む場合、_
の接頭辞を持つファイルはすべて
あります。したがって、_personality.prompt
ファイルは次のようになります。
You should speak like a {{#if style}}{{style}}{{else}}helpful assistant.{{/else}}.
これは他のプロンプトに含めることができます。
---
model: vertexai/gemini-1.5-flash
input:
schema:
name: string
style?: string
---
{{ role "system" }}
{{>personality style=style}}
{{ role "user" }}
Give the user a friendly greeting.
User's Name: {{name}}
部分は {{>NAME_OF_PARTIAL args...}}
構文を使用して挿入されます。「いいえ」の場合
引数を渡すと、その引数が部分的関数に渡されると、
使用します。
部分引数は、上記の両方の名前付き引数、または単一の位置引数を受け入れます。 必要があります。これは、メンバーをレンダリングしています。
# _destination.prompt
- {{name}} ({{country}})
# chooseDestination.prompt
Help the user decide between these vacation destinations:
{{#each destinations}}
{{>destination this}}{{/each}}
コード内での部分定義
definePartial
を使用してコード内で部分型を定義することもできます。
import { definePartial } from '@genkit-ai/dotprompt';
definePartial(
'personality',
'Talk like a {{#if style}}{{style}}{{else}}helpful assistant{{/if}}.'
);
コード定義の部分的要素は、すべてのプロンプトで使用できます。
プロンプトのバリアント
プロンプト ファイルはテキストにすぎないため、バージョン管理システムに commit できます(また、そうすべきです)。これにより、変更点を簡単に比較できます。調整されたバージョンのプロンプトは、本番環境で既存のバージョンと同居させた状態でテストする以外に、完全にテストできる方法がない場合がよくあります。Dotprompt は、これを バリアント機能でサポートしています。
バリアントを作成するには、[name].[variant].prompt
ファイルを作成します。たとえば
プロンプトで Gemini 1.5 Flash を使用していましたが、Gemini 1.5 が
Pro の方がパフォーマンスが高いため、次の 2 つのファイルを作成できます。
my_prompt.prompt
: 「ベースライン」のプロンプトmy_prompt.gemini15pro.prompt
: 「gemini15pro」という名前のバリアント
プロンプト バリアントを使用するには、読み込み時に variant
オプションを指定します。
const myPrompt = promptRef('my_prompt', { variant: 'gemini15pro' });
バリアント名は生成トレースのメタデータに含まれるため、Genkit トレース インスペクタを使い、バリアント間で実際のパフォーマンスを比較および対比できます。
カスタム ヘルパーの定義
カスタム ヘルパーを定義して、プロンプト内でデータを処理および管理できます。ヘルパー
defineHelper
を使用してグローバルに登録されます。
import { defineHelper } from '@genkit-ai/dotprompt';
defineHelper('shout', (text: string) => text.toUpperCase());
定義したヘルパーは、任意のプロンプトで使用できます。
---
model: vertexai/gemini-1.5-flash
input:
schema:
name: string
---
HELLO, {{shout name}}!!!
ヘルパーに渡される引数の詳細については、 作成に関する Handlebars のドキュメント 使用できます。
プロンプトを読み込んで定義する別の方法
Dotprompt は、プロンプト ディレクトリ内の整理用に最適化されています。しかし、 プロンプトを読み込んで定義するその他の方法:
loadPromptFile
: プロンプト ディレクトリ内のファイルからプロンプトを読み込みます。loadPromptUrl
: URL からプロンプトを読み込みます。defineDotprompt
: コード内でプロンプトを定義します。
例:
import {
loadPromptFile,
loadPromptUrl,
defineDotprompt,
} from '@genkit-ai/dotprompt';
import path from 'path';
import { z } from 'zod';
// Load a prompt from a file
const myPrompt = await loadPromptFile(
path.resolve(__dirname, './path/to/my_prompt.prompt')
);
// Load a prompt from a URL
const myPrompt = await loadPromptUrl('https://example.com/my_prompt.prompt');
// Define a prompt in code
const myPrompt = defineDotprompt(
{
model: 'vertexai/gemini-1.5-flash',
input: {
schema: z.object({
name: z.string(),
}),
},
},
`Hello {{name}}, how are you today?`
);