特别注意:本文搬运自 github 项目 anthropics/courses/prompt_evaluations ,经过中文翻译,内容可能因为转译有少数表达上的改动,但不影响主要逻辑,仅供个人阅读学习使用
Promptfoo:自定义代码评分器
注意:本课程位于包含相关代码文件的文件夹中。如果您想跟上进度并自行运行评估,请下载整个文件夹
到目前为止,我们已经看到了如何使用一些内置的 promptfoo 评分器,比如 完全匹配
和 包含所有
。这些通常是很有用的功能,但 promptfoo 还能让我们为更具体的评分任务编写自定义评分逻辑。
为了演示这一点,我们将使用一个非常简单的提示模板:
写一个关于 {{topic}} 的简短段落。确保你提到 {{topic}} 正好 {{count}} 次,不多也不少。
我们会用 {{主题}}
和 {{数量}}
来填充值,比如 "镊子"
和 7
,从而生成一个提示,如下:
写一个关于镊子的短段落。确保你提到镊子恰好7次,不多也不少。
为了评分这个输出,我们需要编写一些自定义逻辑来确保模型的输出中提到“镊子”恰好7次。
对于提示:
写一段关于绵羊的短文。确保文中提到“绵羊”恰好三次,不多也不少。
我们需要编写评分逻辑,以确保模型输出中“绵羊”这个词出现恰好三次。
初始化 promptfoo
和往常一样,第一步是使用命令初始化 promptfoo:
npx promptfoo@latest init
正如我们之前看到的,这会创建一个 promptfooconfig.yaml
文件。我们可以删除现有内容。
接下来,我们将配置我们的提供者。将以下内容添加到 promptfooconfig.yaml
:
description: Count mentions
providers:
- anthropic:messages:claude-3-haiku-20240307
- anthropic:messages:claude-3-5-sonnet-20240620
这告诉 promptfoo 我们希望使用 Claude 3 Haiku 和 Claude 3.5 Sonnet 运行我们的评估。我们将比较它们在这个特定任务上的表现!
确保您已设置 ANTHROPIC_API_KEY
环境变量。您可以通过在终端中运行此命令来设置环境变量:
export ANTHROPIC_API_KEY=your_api_key_here
准备我们的提示符¶
到目前为止,我们已经看到我们可以将提示语作为函数写在 Python 文件中。这是我们推荐的方法,但 promptfoo 还提供了其他几种指定提示语的方法。最简单的方法是直接在 YAML 文件中写文本。
让我们尝试这种内联方法。更新 promptfooconfig.yaml
文件以包含以下内容:
description: Count mentions
prompts:
- >-
Write a short paragraph about {{topic}}. Make sure you mention {{topic}} exactly {{count}} times, no more or fewer. Only use lower case letters in your output.
providers:
- anthropic:messages:claude-3-haiku-20240307
- anthropic:messages:claude-3-5-sonnet-20240620
注意 prompts
字段,其中直接包含 YAML 文件中的文本提示语。注意 {{topic}}
和 {{count}}
变量,它们使用双花括号。这些提示语使用 Nunjucks 模板语法,这很快就会很重要!
编写我们的测试用例
在之前的课程中,我们将测试用例和评分逻辑写在 CSV 文件中。正如之前讨论的,promptfoo 非常灵活,提供了多种指定测试的方法。
我们可以直接在 YAML 配置文件中编写测试用例。将 promptfooconfig.yaml
文件更新为如下所示:
description: Count mentions
prompts:
- >-
Write a short paragraph about {{topic}}. Make sure you mention {{topic}} exactly {{count}} times, no more or fewer. Only use lower case letters in your output.
providers:
- anthropic:messages:claude-3-haiku-20240307
- anthropic:messages:claude-3-5-sonnet-20240620
tests:
- vars:
topic: sheep
count: 3
- vars:
topic: fowl
count: 2
- vars:
topic: gallows
count: 4
- vars:
topic: tweezers
count: 7
- vars:
topic: jeans
count: 6
在底部,我们定义了 5 个测试用例,每个测试用例都有自己的 topic
和 count
值。Promptfoo 将自动运行每个测试,在提示模板中替换 {{topic}}
和 {{count}}
。
我们还没有评分逻辑,但仍然可以运行评估以确保我们的变量是否正确添加。
要运行评估,我们将使用之前看到的相同命令:
npx promptfoo@latest eval
这是我们得到的输出:
如果我们放大查看单行,可以看到模型输出通常看起来不错。在这个例子中,{{topic}}
被设置为“羊”,相应的模型输出是关于羊的段落!
现在我们只需要实现自定义评分逻辑来测试输出是否正确提到了主题的次数!
添加自定义评分器函数¶
Promptfoo 允许我们定义自己的 Python 评分器函数。对于这个特定的例子,我们希望定义一个函数来确保模型输出正确地提到了特定主题的次数。我们将从定义一个名为 count.py
的新 Python 文件开始。在这个文件中,我们将添加以下函数:
import re
def get_assert(output, context):
topic = context["vars"]["topic"]
goal_count = int(context["vars"]["count"])
pattern = fr'(^|\s)\b{re.escape(topic)}\b'
actual_count = len(re.findall(pattern, output.lower()))
pass_result = goal_count == actual_count
result = {
"pass": pass_result,
"score": 1 if pass_result else 0,
"reason": f"Expected {topic} to appear {goal_count} times. Actual: {actual_count}",
}
return result
让我们谈谈上面代码的作用。Promptfoo 将自动在我们的文件中查找名为 get_assert
的函数。它将向该函数传递两个参数:
- 某个模型的输出
- 包含生成输出的变量和提示的
上下文
字典
Promptfoo 期望我们的函数返回以下之一:
- 布尔值(通过/失败)
- 浮点数(分数)
- 一个评分结果字典
我们选择返回一个评分结果字典,该字典必须包含以下属性:
pass_
: 布尔值score
: 浮点数reason
: 一个字符串解释
在上述函数中,我们从 context
参数中提取主题和计数,然后使用正则表达式来计算主题在输出中出现的次数,最后返回 result
现在我们已经定义了我们的评分器,是时候告诉 promptfoo 关于它了。更新 promptfooconfig.yaml
文件:
description: Count mentions
prompts:
- >-
Write a short paragraph about {{topic}}. Make sure you mention {{topic}} exactly {{count}} times, no more or fewer. Only use lower case letters in your output.
providers:
- anthropic:messages:claude-3-haiku-20240307
- anthropic:messages:claude-3-5-sonnet-20240620
defaultTest:
assert:
- type: python
value: file://count.py
tests:
- vars:
topic: sheep
count: 3
- vars:
topic: fowl
count: 2
- vars:
topic: gallows
count: 4
- vars:
topic: tweezers
count: 7
- vars:
topic: jeans
count: 6
defaultTest
告诉 promptfoo,对于它运行的每个测试,我们都希望它使用我们在 count.py
文件中定义的 Python 评分器。
运行评估
要运行评估,我们将使用之前看到的相同命令:
npx promptfoo@latest eval
这是我们运行 eval 得到的输出:
运行此命令以启动网络界面:
npx promptfoo@latest view
我们可以看到,Claude 3.5 在这项任务中得分为 100%,而 Claude 3 Haiku 得分为 20%。要验证结果,请点击放大镜图标查看完整的输入提示和相应的输出。
这是 Claude 3 Haiku 的错误输出:
而 Claude 3.5 Sonnet 的正确输出是:
这种特定的评估有点傻,但它的目的是演示定义自定义 Python 评分逻辑的过程。通过内置的 promptfoo 断言和自定义评分函数,我们可以编写几乎任何代码评分评估。
在下一个课程中,我们将学习 promptfoo 中的模型评分评估。