Skip to main content

提示、测试和输出

提示

从原始文本生成提示

默认情况下,配置将接受原始文本作为提示:

prompts:
- '将以下文本翻译成法语:"{{name}}: {{text}}"'
- '将以下文本翻译成德语:"{{name}}: {{text}}"'

YAML 也支持多行字符串:

prompts:
- |-
你好 LLM,
请将以下文本翻译成法语:
"{{name}}: {{text}}"
- |-
将以下文本翻译成德语:
"{{name}}: {{text}}"

使用 Nunjucks 模板语法在提示中包含变量,这些变量将在评估期间被测试用例中的实际值替换。

提示作为 JSON

一些 LLM API 接受 JSON 聊天格式的提示,如 [{ "role" : "user", "content": "..."}]

默认情况下,纯文本提示会被包装在 user 角色的消息中。如果你提供 JSON,那么 promptfoo 将完全按照提供的 messages 对象发送。

以下是一个聊天格式提示的示例:

prompts:
- file://path/to/personality1.json

personality1.json 中:

[
{
"role": "system",
"content": "你是一个有帮助的助手"
},
{
"role": "user",
"content": "告诉我关于 {{topic}}"
}
]

了解更多关于 与 OpenAI 消息格式进行聊天对话

从文件生成提示

你的提示可能复杂到难以在行内维护。在这种情况下,可以引用一个文件。文件路径相对于配置文件目录:

prompts:
- file://path/to/prompt1.txt
- file://path/to/prompt2.txt
- file://path/to/prompt.json
- file://path/to/prompt.yaml
- file://path/to/prompt.yml
- file://path/to/prompt.md
# 支持通配符
- file://prompts/*.txt
- file://path/**/*
# 提示函数
# 执行整个文件
- file:///root/path/to/prompt.js
- file://./path/to/prompt.py
# 执行单个函数
- file:///root/path/to/prompt.js:prompt1
- file:///root/path/to/prompt.js:prompt2
- file:///root/path/to/prompt.py:prompt1
- file:///root/path/to/prompt.py:prompt2
- file:///root/path/to/prompt.py:PromptClass.prompt1
- file:///root/path/to/prompt.py:PromptClass.prompt2
tip

将它们检入版本控制。这种方法有助于跟踪更改、协作,并确保不同环境之间的一致性。

多个提示文件的示例:

将以下文本翻译成法语:"{{name}}: {{text}}"
将以下文本翻译成德语:"{{name}}: {{text}}"

提示也可以是 JSON。使用此配置多轮提示格式:

[
{
"role": "system",
"content": "你是一个翻译器,可以将输入转换为 {{ language }}。"
},
{
"role": "user",
"content": "{{ text }}"
}
]

单个文本文件中的多个提示

如果你只有一个文本文件,可以在文件中包含多个提示,用分隔符 --- 分隔。如果你有多个文件,每个提示应该在单独的文件中。

单个提示文件包含多个提示的示例 (prompts.txt):

将以下文本翻译成法语:"{{name}}: {{text}}"
---
将以下文本翻译成德语:"{{name}}: {{text}}"
info

提示分隔符可以通过 PROMPTFOO_PROMPT_SEPARATOR 环境变量覆盖。

提示作为 Markdown

Markdown 格式的提示与原始文本提示类似。你可以在 Markdown 文件中定义提示:

你是一个有帮助的助手,用于 Promptfoo。请回答以下问题:{{question}}

注意,每个 Markdown 文件只支持一个提示。

针对不同模型的不同提示

要为不同的提供者设置单独的提示,可以在 promptfooconfig.yamlproviders 部分指定提示文件。每个提供者可以有自己的一组提示,这些提示根据其特定的要求或输入格式定制。

以下是如何为 llama3.1 和 GPT-4o 模型设置单独提示的示例:

prompts:
- id: file://prompts/gpt_chat_prompt.json
label: gpt_chat_prompt
- id: file://prompts/llama_completion_prompt.txt
label: llama_completion_prompt

providers:
- id: openai:gpt-4o-mini
prompts:
- gpt_chat_prompt
- id: openai:gpt-4o
prompts:
- gpt_chat_prompt
- id: replicate:meta/meta-llama-3.1-405b-instruct
label: llama-3.1-405b-instruct
prompts:
- llama_completion_prompt

在此配置中,gpt_chat_prompt 用于 GPT-4o 和 GPT-4o-mini 模型,而 llama_completion_prompt 用于 llama3.1 模型。提示在 prompts 目录中的单独文件中定义。 确保为每个模型创建相应格式的提示文件。例如,GPT 模型可能期望一个消息的 JSON 数组,而 llama 可能期望带有特定前缀的纯文本格式。

提示函数

提示函数允许你在提示中加入自定义逻辑。这些函数可以用 JavaScript 或 Python 编写,并以 .js.py 扩展名包含在提示文件中。

要在 promptfooconfig.yaml 中指定一个提示函数,直接引用文件即可。例如:

prompts:
- file://prompt.js
- file://prompt.py

在提示函数中,你可以通过上下文访问测试用例变量和提供者信息。函数将能够访问一个 vars 对象和一个 provider 对象。通过访问 provider 对象,你可以为不同格式的不同提供者动态生成提示。

函数应返回一个表示提示的字符串或对象。

示例

一个 JavaScript 提示函数,prompt.js

module.exports = async function ({ vars, provider }) {
return [
{
role: 'system',
content: `You're an angry pirate named ${provider.label || provider.id}. Be concise and stay in character.`,
},
{
role: 'user',
content: `Tell me about ${vars.topic}`,
},
];
};

要在提示文件中引用特定函数,使用以下语法:filename.js:functionName

module.exports.prompt1 = async function ({ vars, provider }) {
return [
{
role: 'system',
content: `You're an angry pirate named ${provider.label || provider.id}. Be concise and stay in character.`,
},
{
role: 'user',
content: `Tell me about ${vars.topic}`,
},
];
};

一个 Python 提示函数,prompt.py:my_prompt_function

import json
import sys

def my_prompt_function(context: dict) -> str:

provider: dict = context['providers']
provider_id: str = provider['id'] # ex. openai:gpt-4o or bedrock:anthropic.claude-3-sonnet-20240229-v1:0
provider_label: str | None = provider.get('label') # exists if set in promptfoo config.

variables: dict = context['vars'] # access the test case variables

return (
f"Describe {variables['topic']} concisely, comparing it to the Python"
" programming language."
)

if __name__ == "__main__":
# If you don't specify a `function_name` in the provider string, it will run the main
print(my_prompt_function(json.loads(sys.argv[1])))

要验证你的函数是否生成了正确的提示:

  1. 运行 promptfoo view
  2. 检查表头是否包含你的函数代码。
  3. 将鼠标悬停在你要调查的特定输出上,点击放大镜(🔎)以在详细信息窗格中查看最终提示。
info

默认情况下,promptfoo 会在你的 shell 中运行 python 可执行文件。

要覆盖 Python 可执行文件,请将 PROMPTFOO_PYTHON 环境变量设置为可执行文件(例如 /usr/bin/python3.11python3.11)。

查看最终提示

提示函数在结果表顶部显示源代码,因为它们可以返回在不同测试用例之间不同的动态值。

为了查看每个测试用例的提示,切换 Table Settings > Show full prompt in output cell。这将显示每个测试用例/提供者组合的最终提示。

每个测试用例显示的最终提示

提示配置

提示可以通过 config 对象进行配置。该对象与提供者配置对象合并,合并后的对象用于调用提供者 API。

一个很好的用例是为特定提示设置 response_format

示例

prompts:
- label: 'Prompt #1'
raw: 'You are a helpful math tutor. Solve {{problem}}'
config:
response_format:
type: json_schema
json_schema: ...

Nunjucks 过滤器

Nunjucks 是一种模板语言,具有许多内置过滤器,可以应用于变量。例如:{{ varName | capitalize }}

Nunjucks 自定义过滤器 是 JavaScript 函数,可以应用于模板中的变量。

要定义一个 Nunjucks 过滤器,创建一个导出函数的 JavaScript 文件。该函数将用作过滤器,它应将输入值作为参数并返回转换后的值。

以下是一个将字符串转换为大写的自定义 Nunjucks 过滤器示例(allcaps.js):

module.exports = function (str) {
return str.toUpperCase();
};

要在 Promptfoo 中使用自定义的 Nunjucks 过滤器,请将其添加到配置文件(promptfooconfig.yaml)中。nunjucksFilters 字段应包含过滤器名称到定义它们的 JavaScript 文件路径的映射:

prompts:
- file://prompts.txt
providers:
- openai:gpt-4o-mini
nunjucksFilters:
allcaps: ./allcaps.js
tests:
# ...

然后,通过在变量或表达式后附加管道(|)符号来在提示中使用该过滤器:

Translate this to {{language}}: {{body | allcaps}}

在这个例子中,body 变量在用于提示之前会通过 allcaps 过滤器进行处理。这意味着文本将被转换为大写。

默认提示

如果在配置中未定义 prompts,则 Promptfoo 默认会使用一个“直通”提示:{{prompt}}。这个提示只是简单地传递 prompt 变量的内容。

测试文件

如果你有很多测试,可以选择将它们与主配置文件分开保存。

最简单的方法是创建一个包含测试列表的 tests.yaml 文件,然后在 promptfooconfig.yaml 中像这样包含它:

prompts:
# ...

providers:
# ...

tests: file://path/to/tests.yaml

你甚至可以将其拆分为多个文件或 glob 模式:

tests:
- file://relative/path/to/normal_test.yaml
- file://relative/path/to/special_test.yaml
- file:///absolute/path/to/more_tests/*.yaml

从 CSV 导入

promptfoo 还支持测试 CSV 格式。

CSV 文件的第一行应包含变量名称,每一后续行应包含每个测试用例的相应值。

变量通过 Nunjucks 模板语法替换到提示中。第一行是变量名称。所有其他行是变量值。

测试文件示例(tests.csv):

language,input
German,"Hello, world!"
Spanish,Where is the library?

测试文件可选支持几个特殊列:

  • __expected:包含 测试断言 的列。此列允许你根据质量预期自动标记输出。
    • 对于多个断言,使用 __expected1__expected2__expected3 等。
  • __prefix:在发送到 API 之前,此字符串会前置到每个提示中
  • __suffix:在发送到 API 之前,此字符串会附加到每个提示中
  • __description:测试描述
  • __metric:分配给测试用例中每个断言的指标
  • __threshold:分配给测试用例的阈值
tip

你可以从 Google Sheets 加载测试。

输出文件

评估结果会写入此文件。例如:

promptfoo eval --output filepath.json

输出文件也可以通过 promptfoo 配置中的 outputPath 键来设置。

支持多种文件格式,包括 JSON、YAML、CSV 和 HTML。

输出文件中的每个记录对应一个测试用例,并包含原始提示、LLM 生成的输出以及测试用例中使用的变量值。

有关示例输出,请参见 examples/ 目录。

排列输入和断言

一个普通的 prompts.txt/promptfooconfig.yaml 对支持每个测试将一组变量与一组断言组合。尝试将多组变量与多组断言组合会导致配置条目呈指数级增长。

场景 使你能够在单个配置条目中使用 1+ 组变量和 1+ 组断言的所有可能组合。