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 전면을 활용하여 템플릿과 함께 프롬프트 인라인에 대한 메타데이터를 제공합니다.
입력/출력 스키마 정의
Dotprompt에는 YAML에 최적화된 간결한 스키마 정의 형식인 스키마의 가장 중요한 속성을 쉽게 정의할 수 있는 피코스키마 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
를 지원합니다.
객체, 배열 및 enum의 경우 필드 이름 뒤에 괄호가 표시됩니다.
Picoschema로 정의된 객체에는 ?
에 의해 선택사항으로 표시되지 않는 한 필수 속성이 모두 포함되며 추가 속성은 허용되지 않습니다. 속성이 선택사항으로 표시되면 LLM이 필드를 생략하는 대신 null을 반환하도록 편의를 제공하기 위해 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 스키마입니다. 그런 다음 스키마를 활용하여 출력됩니다.
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}}
멀티턴 프롬프트 및 기록
Dotprompt는 history
옵션을
generate
메서드:
const result = await multiTurnPrompt.generate({
history: [
{ role: 'user', content: [{ text: 'Hello.' }] },
{ role: 'model', content: [{ text: 'Hi there!' }] },
],
});
기본적으로
확인할 수 있습니다 그러나 {{history}}
를 사용하여 기록을 수동으로 배치할 수 있습니다.
도우미:
{{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://
또는 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}}.'
);
코드 정의 부분은 모든 프롬프트에서 사용할 수 있습니다.
프롬프트 변형
프롬프트 파일은 텍스트일 뿐이므로 버전 제어 시스템에 커밋하면 시간 경과에 따른 변경사항을 쉽게 비교할 수 있습니다. 종종 프롬프트의 수정된 버전은 기존 버전과 나란히 비교하여 프로덕션 환경에서만 완전히 테스트할 수 있습니다. Dotprompt 변형 기능을 통해 이를 지원합니다.
변형을 만들려면 [name].[variant].prompt
파일을 만듭니다. 예를 들어 프롬프트에 Gemini 1.5 Flash를 사용하고 있었지만 Gemini 1.5 Pro가 더 잘 작동하는지 확인하려고 한다면 다음과 같은 두 개의 파일을 만들 수 있습니다.
my_prompt.prompt
: '기준' 프롬프트my_prompt.gemini15pro.prompt
: 'gemini15pro'라는 변형입니다.
프롬프트 변형을 사용하려면 로드할 때 variant
옵션을 지정합니다.
const myPrompt = promptRef('my_prompt', { variant: 'gemini15pro' });
변형 이름은 생성 trace의 메타데이터에 포함되므로 Genkit trace 검사기에서 변형 간의 실제 성능을 비교하고 대조할 수 있습니다.
커스텀 도우미 정의
커스텀 도우미를 정의하여 프롬프트 내에서 데이터를 처리하고 관리할 수 있습니다. 도우미
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}}!!!
도우미에 전달되는 인수에 관한 자세한 내용은 생성에 대한 핸들바 문서 커스텀 도우미를 제공합니다.
프롬프트를 로드하고 정의하는 다른 방법
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?`
);