使用 Dotprompt 管理提示

Firebase Genkit 提供 Dotprompt 外掛程式和文字格式,可協助你編寫 及整理生成式 AI 提示

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());

點號的語法以處理常式為基礎 範本語言您可以使用 ifunlesseach 輔助程式新增 條件部分加進提示,或反覆修改結構化內容 檔案格式會使用 YAML 前端,為內嵌提示提供中繼資料 與範本互動

定義輸入/輸出結構定義

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 支援純量類型 stringintegernumberbooleanany。 如果是物件、陣列和列舉,欄位名稱後面會以括號表示。

Picoschema 定義的物件包含所有必要屬性,除非另有註明 ,且不允許其他屬性。?屬性標示為選用時 也能讓 LLM 傳回空值 因此可能會略過欄位

在物件定義中,您可以使用特殊鍵 (*) 宣告「萬用字元」 欄位定義。這將與 明確金鑰。

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 程式庫會自動將名稱解析為基礎 使用已註冊的可用區結構定義接著,您可以使用這個架構來強行輸入 輸出:

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());

如要確保輸出內容符合要求,您必須在 提示。根據預設,這個 ID 會附加在最後一則訊息的結尾處 。您可以使用 {{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}}

「內嵌」的網址可以是 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 否則,您可以製作兩個檔案:

  • 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}}!!!

如需進一步瞭解傳遞給輔助程式的引數,請參閱 有關建立方式的帳號代碼說明文件 自訂輔助程式

載入及定義提示的替代方式

Dotprompt 是針對提示目錄中的機構進行最佳化。不過, 以下是載入及定義提示的其他幾種方式:

  • loadPromptFile:從提示目錄的檔案載入提示。
  • loadPromptUrl:從網址載入提示。
  • 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?`
);