Dotprompt로 프롬프트 관리

Firebase Genkit는 작성에 도움이 되는 Dotprompt 플러그인과 텍스트 형식을 제공합니다. 정리하는 방법을 알아보겠습니다

Dotprompt는 프롬프트가 코드라는 전제를 바탕으로 설계되었습니다. 사용자는 .dotprompt 파일이라는 특수 형식의 파일에 프롬프트를 유지 관리하고, API에 사용하는 것과 동일한 버전 제어 시스템을 사용하여 생성형 AI를 호출하는 코드와 함께 배포합니다. 모델을 학습시키는 작업도 반복해야 합니다

Dotprompt를 사용하려면 먼저 프로젝트 루트에 prompts 디렉터리를 만들고 그런 다음 이 디렉터리에 .prompt 파일을 만듭니다. 간단한 예를 들면 다음과 같습니다. greeting.prompt를 호출할 수 있습니다.

---
model: vertexai/gemini-1.5-pro
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}}.

이 프롬프트를 사용하려면 다음 안내를 따르세요.

Go

dotprompt 플러그인을 설치합니다.

go get github.com/firebase/genkit/go/plugins/dotprompt

그런 다음 Open를 사용하여 프롬프트를 로드합니다.

import "github.com/firebase/genkit/go/plugins/dotprompt"
dotprompt.SetDirectory("prompts")
prompt, err := dotprompt.Open("greeting")

프롬프트의 Generate 메서드를 호출하여 템플릿을 렌더링하고 전달할 수 있습니다. 한 번에 모델 API에 추가합니다.

ctx := context.Background()

// The .prompt file specifies vertexai/gemini-1.5-pro, so make sure it's set
// up.
// Default to the project in GCLOUD_PROJECT and the location "us-central1".
vertexai.Init(ctx, nil)
vertexai.DefineModel("gemini-1.5-pro", nil)

type GreetingPromptInput struct {
  Location string `json:"location"`
  Style    string `json:"style"`
  Name     string `json:"name"`
}
response, err := prompt.Generate(
  ctx,
  &dotprompt.PromptRequest{
      Variables: GreetingPromptInput{
          Location: "the beach",
          Style:    "a fancy pirate",
          Name:     "Ed",
      },
  },
  nil,
)
if err != nil {
  return err
}

if responseText, err := response.Text(); err == nil {
  fmt.Println(responseText)
}

또는 템플릿을 문자열로 렌더링합니다.

Go

renderedPrompt, err := prompt.RenderText(map[string]any{
  "location": "a restaurant",
  "style":    "a pirate",
})

Dotprompt의 구문은 Handlebars 있습니다. if, unless, each 도우미를 사용하여 프롬프트에 조건부 부분을 추가하거나 구조화된 콘텐츠를 통해 반복합니다. 이 YAML 프런트엔드를 활용하여 프롬프트 인라인에 메타데이터를 제공하는 파일 형식 살펴보겠습니다.

Picoschema로 입력/출력 스키마 정의

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

위의 스키마는 다음 JSON 스키마와 동일합니다.

{
  "properties": {
    "metadata": {
      "properties": {
        "updatedAt": {
          "type": "string",
          "description": "ISO timestamp of last update"
        },
        "approvedBy": {
          "type": "integer",
          "description": "id of approver"
        }
      },
      "type": "object"
    },
    "title": {
      "type": "string"
    },
    "subtitle": {
      "type": "string"
    },
    "draft": {
      "type": "boolean",
      "description": "true when in draft state"
    },
    "date": {
      "type": "string",
      "description": "the date of publication e.g. '2024-04-09'"
    },
    "tags": {
      "items": {
        "type": "string"
      },
      "type": "array",
      "description": "relevant tags for article"
    },
    "authors": {
      "items": {
        "properties": {
          "name": {
            "type": "string"
          },
          "email": {
            "type": "string"
          }
        },
        "type": "object",
        "required": ["name"]
      },
      "type": "array"
    }
  },
  "type": "object",
  "required": ["title", "date", "tags", "authors"]
}

Picoschema는 스칼라 유형 string, integer, number, boolean, any를 지원합니다. 객체, 배열 및 enum의 경우 필드 이름 뒤에 괄호로 표시됩니다.

Picoschema로 정의된 객체에는 선택사항으로 표시되지 않는 한 필수 속성이 모두 포함됩니다. ?에 의해 렌더링되며 추가 속성은 허용되지 않습니다. 속성이 선택사항으로 표시되면 또한 LLM이 null을 반환하는 대신 필드를 생략할 수 있습니다.

객체 정의에서 특수 키 (*)를 사용하여 '와일드 카드'를 선언할 수 있습니다. 필드 정의입니다. 이렇게 하면 명시적 키입니다.

Picoschema는 전체 JSON 스키마의 많은 기능을 지원하지 않습니다. 만약 보다 강력한 스키마가 필요한 경우 JSON 스키마를 대신 제공할 수 있습니다.

output:
  schema:
    type: object
    properties:
      field1:
        type: number
        minimum: 20

프롬프트 메타데이터 재정의

.prompt 파일을 사용하면 모델 구성과 같은 메타데이터를 파일 자체를 재정의하면 호출별로 이러한 값을 재정의할 수도 있습니다.

Go

// Make sure you set up the model you're using.
vertexai.DefineModel("gemini-1.5-flash", nil)

response, err := prompt.Generate(
  context.Background(),
  &dotprompt.PromptRequest{
      Variables: GreetingPromptInput{
          Location: "the beach",
          Style:    "a fancy pirate",
          Name:     "Ed",
      },
      Model: "vertexai/gemini-1.5-flash",
      Config: &ai.GenerationCommonConfig{
          Temperature: 1.0,
      },
  },
  nil,
)

다중 메시지 프롬프트

기본적으로 Dotprompt는 "user" 역할을 가진 단일 메시지를 작성합니다. 다소 유용함 프롬프트는 다음과 같이 여러 메시지를 조합하여 가장 잘 표현됩니다. 시스템 프롬프트.

{{role}} 도우미를 사용하면 간단하게 멀티 메시지 프롬프트를 구성할 수 있습니다.

---
model: vertexai/gemini-1.0-pro
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}}

멀티모달 프롬프트

텍스트와 함께 이미지와 같은 멀티모달 입력을 지원하는 모델의 경우 {{media}} 도우미를 사용합니다.

---
model: vertexai/gemini-1.0-pro-vision
input:
  schema:
    photoUrl: string
---

Describe this image in a detailed paragraph:

{{media url=photoUrl}}

URL은 https:// 또는 '인라인'을 위한 base64로 인코딩된 data: URI일 수 있습니다. 이미지 사용합니다 코드에서는 다음과 같습니다.

Go

dotprompt.SetDirectory("prompts")
describeImagePrompt, err := dotprompt.Open("describe_image")
if err != nil {
  return err
}

imageBytes, err := os.ReadFile("img.jpg")
if err != nil {
  return err
}
encodedImage := base64.StdEncoding.EncodeToString(imageBytes)
dataURI := "data:image/jpeg;base64," + encodedImage

type DescribeImagePromptInput struct {
  PhotoUrl string `json:"photo_url"`
}
response, err := describeImagePrompt.Generate(
  context.Background(),
  &dotprompt.PromptRequest{Variables: DescribeImagePromptInput{
      PhotoUrl: dataURI,
  }},
  nil,
)

프롬프트 변형

프롬프트 파일은 텍스트일 뿐이므로 시간 경과에 따른 변경사항을 쉽게 비교할 수 있습니다. 종종 프롬프트의 수정된 버전은 한 환경에서만 완전히 테스트할 수 있습니다. 프로덕션 환경을 기존 버전과 나란히 비교해 보세요 Dotprompt 지원 변형 기능을 통해 이를 검증합니다.

변형을 만들려면 [name].[variant].prompt 파일을 만듭니다. 예를 들어 프롬프트에 Gemini 1.0 Pro를 사용하고 있었지만 Gemini 1.5 Pro가 Gemini 1.5 Pro인지 확인하고 싶었습니다. 더 잘 작동한다면 다음과 같은 두 개의 파일을 만들 수 있습니다.

  • my_prompt.prompt: '기준' 메시지
  • my_prompt.gemini15.prompt: 'gemini'라는 변이

프롬프트 변형을 사용하려면 로드할 때 변형을 지정합니다.

Go

describeImagePrompt, err := dotprompt.OpenVariant("describe_image", "gemini15")

프롬프트 로더는 해당 이름의 변형을 로드하려고 시도한 후 '기준점'이 될 수 있습니다 즉, TensorFlow Hub에서 선택할 수 있습니다.

Go

var myPrompt *dotprompt.Prompt
var err error
if isBetaTester(user) {
  myPrompt, err = dotprompt.OpenVariant("describe_image", "gemini15")
} else {
  myPrompt, err = dotprompt.Open("describe_image")
}

변형 이름은 생성 트레이스의 메타데이터에 포함되므로 Genkit 트레이스에서 변이 간의 실제 성능을 비교하고 대조할 수 있음 있습니다.